656 lines
13 KiB
C
656 lines
13 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*
|
|
* $XConsortium: trav.c /main/3 1995/11/06 18:41:30 rswiston $
|
|
*
|
|
* @(#)trav.c 3.41 14 Feb 1994 cde_app_builder/src/libABobj
|
|
*
|
|
* RESTRICTED CONFIDENTIAL INFORMATION:
|
|
*
|
|
* The information in this document is subject to special
|
|
* restrictions in a confidential disclosure agreement between
|
|
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
|
|
* document outside HP, IBM, Sun, USL, SCO, or Univel without
|
|
* Sun's specific written approval. This document and all copies
|
|
* and derivative works thereof must be returned or destroyed at
|
|
* Sun's request.
|
|
*
|
|
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* traversal.c - traversals of object trees
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "objP.h"
|
|
#include "travP.h"
|
|
|
|
static int travP_find_first(ABTraversal trav);
|
|
static int travP_find_next(ABTraversal trav);
|
|
static int travP_find_next_parents_first(ABTraversal trav);
|
|
static int travP_find_first_for_parents(ABTraversal trav);
|
|
static int travP_find_next_for_parents(ABTraversal trav);
|
|
static BOOL travP_qualifies(ABTraversal trav);
|
|
static int travP_verify_type(ABTraversal travType, BOOL warn);
|
|
static ABObj find_first_item(ABObj obj);
|
|
static ABObj find_first_child_of_type(ABObj obj,
|
|
ABTraversal trav, AB_OBJECT_TYPE type);
|
|
static ABObj find_first_action(ABObj, ABTraversal);
|
|
static ABObj find_first_sibling_child(ABObj obj, ABTraversal trav);
|
|
static ABObj find_next_sibling_child(ABObj obj, ABTraversal trav);
|
|
static ABObj find_first_ancestor_sibling_child(ABObj obj, ABTraversal trav);
|
|
|
|
|
|
int
|
|
travP_open(
|
|
ABTraversal trav, ABObj root, unsigned travType,
|
|
ABObjTestFunc testFunc)
|
|
{
|
|
travP_clean(trav);
|
|
trav->travType= travType;
|
|
trav->rootObj= root;
|
|
trav->testFunc= testFunc;
|
|
travP_reset(trav);
|
|
travP_verify_type(trav, TRUE);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
travP_close(ABTraversal trav)
|
|
{
|
|
trav->rootObj= NULL;
|
|
trav->travType= AB_TRAV_UNDEF;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Restarts the traversal from the beginning. With a safe traversal,
|
|
* the list of objects is not recalculated.
|
|
*/
|
|
int
|
|
travP_reset(ABTraversal trav)
|
|
{
|
|
trav->curObj= NULL;
|
|
trav->done= FALSE;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Hint: travP_goto(trav, -1) is equivalent to travP_reset(trav).
|
|
*/
|
|
ABObj
|
|
travP_goto(ABTraversal trav, int node_num)
|
|
{
|
|
int i;
|
|
|
|
travP_reset(trav);
|
|
for (i= 0; i <= node_num; ++i)
|
|
{
|
|
travP_next(trav);
|
|
}
|
|
|
|
return trav->curObj;
|
|
}
|
|
|
|
|
|
/*
|
|
* Effects: gets the next object in the traversal
|
|
* Modifies: checks/sets done flag
|
|
*/
|
|
ABObj
|
|
travP_next(ABTraversal trav)
|
|
{
|
|
BOOL found_next= FALSE;
|
|
|
|
if (trav->done)
|
|
{
|
|
return NULL;
|
|
}
|
|
else if (trav->curObj == NULL)
|
|
{
|
|
/* starting a new traversal */
|
|
travP_find_first(trav);
|
|
found_next= ((trav->curObj == NULL) || travP_qualifies(trav));
|
|
}
|
|
|
|
while (!found_next)
|
|
{
|
|
travP_find_next(trav);
|
|
if ( (trav->curObj == NULL)
|
|
|| (travP_qualifies(trav)) )
|
|
{
|
|
found_next= TRUE;
|
|
}
|
|
} /* while !found_next */
|
|
|
|
if (trav->curObj == NULL)
|
|
{
|
|
trav->done= TRUE;
|
|
}
|
|
|
|
return trav->curObj;
|
|
} /* travP_next */
|
|
|
|
|
|
/*
|
|
* ASSUMES: rootObj is not NULL
|
|
* - done is FALSE
|
|
*/
|
|
static int
|
|
travP_find_first(ABTraversal trav)
|
|
{
|
|
#define rootObj (trav->rootObj)
|
|
#define curObj (trav->curObj)
|
|
curObj = NULL;
|
|
|
|
switch (travP_get_qualifier(trav))
|
|
{
|
|
case AB_TRAV_ACTIONS_FOR_OBJ:
|
|
curObj= find_first_action(rootObj, trav);
|
|
break;
|
|
|
|
case AB_TRAV_CHILDREN:
|
|
case AB_TRAV_SALIENT_CHILDREN:
|
|
case AB_TRAV_SALIENT_UI_CHILDREN:
|
|
curObj= travP_obj_first_child(rootObj, trav);
|
|
break;
|
|
|
|
case AB_TRAV_COMP_SUBOBJS:
|
|
if (obj_is_root(rootObj))
|
|
{
|
|
curObj = rootObj;
|
|
}
|
|
break;
|
|
|
|
case AB_TRAV_ITEMS_FOR_OBJ:
|
|
curObj= find_first_item(rootObj);
|
|
break;
|
|
|
|
case AB_TRAV_MODULES:
|
|
curObj= obj_is_module(rootObj)?
|
|
rootObj
|
|
:
|
|
find_first_child_of_type(rootObj, trav, AB_TYPE_MODULE);
|
|
break;
|
|
|
|
case AB_TRAV_PARENTS:
|
|
travP_find_first_for_parents(trav);
|
|
break;
|
|
|
|
case AB_TRAV_SIBLINGS:
|
|
{
|
|
ABObj prevSibling= NULL;
|
|
curObj= rootObj;
|
|
while ((prevSibling= travP_obj_prev_sibling(curObj, trav)) != NULL)
|
|
{
|
|
curObj= prevSibling;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
curObj= rootObj;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
#undef rootObj
|
|
#undef curObj
|
|
}
|
|
|
|
|
|
/*
|
|
* Assumes: - traversal is not "done"
|
|
* - curObj is not NULL
|
|
*/
|
|
static int
|
|
travP_find_next(ABTraversal trav)
|
|
{
|
|
#define curObj (trav->curObj)
|
|
switch (travP_get_qualifier(trav))
|
|
{
|
|
/*
|
|
* Types that return only a set of siblings
|
|
*/
|
|
case AB_TRAV_ACTIONS_FOR_OBJ:
|
|
case AB_TRAV_CHILDREN:
|
|
case AB_TRAV_ITEMS_FOR_OBJ:
|
|
case AB_TRAV_MODULES:
|
|
case AB_TRAV_SALIENT_CHILDREN:
|
|
case AB_TRAV_SALIENT_UI_CHILDREN:
|
|
case AB_TRAV_SIBLINGS:
|
|
curObj= travP_obj_next_sibling(curObj, trav);
|
|
break;
|
|
|
|
/*
|
|
* Types that return parents
|
|
*/
|
|
case AB_TRAV_PARENTS:
|
|
travP_find_next_for_parents(trav);
|
|
break;
|
|
|
|
/*
|
|
* Traversals that return an entire tree
|
|
*/
|
|
default:
|
|
travP_find_next_parents_first(trav);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
#undef curObj
|
|
} /* travP_find_next */
|
|
|
|
|
|
static int
|
|
travP_find_first_for_parents(ABTraversal trav)
|
|
{
|
|
#define curObj (trav->curObj)
|
|
ABObj parent= NULL;
|
|
|
|
if (travP_is_parents_first(trav))
|
|
{
|
|
curObj= travP_obj_parent(trav->rootObj, trav);
|
|
if (curObj != NULL)
|
|
{
|
|
while ((parent= travP_obj_parent(curObj, trav)) != NULL)
|
|
{
|
|
curObj= parent;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curObj= travP_obj_parent(trav->rootObj, trav);
|
|
}
|
|
|
|
return 0;
|
|
#undef curObj
|
|
}
|
|
|
|
|
|
static int
|
|
travP_find_next_for_parents(ABTraversal trav)
|
|
{
|
|
#define curObj (trav->curObj)
|
|
|
|
if (travP_is_parents_first(trav))
|
|
{
|
|
curObj= travP_obj_first_child(curObj, trav);
|
|
if (curObj == trav->rootObj)
|
|
{
|
|
curObj= NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curObj= travP_obj_parent(curObj, trav);
|
|
}
|
|
|
|
return 0;
|
|
#undef curObj
|
|
}
|
|
|
|
/*****************************************************************
|
|
** **
|
|
** PARENTS_FIRST TRAVERSAL **
|
|
** **
|
|
******************************************************************/
|
|
|
|
|
|
/*
|
|
* Assumes: traversal is open and not done
|
|
*/
|
|
static int
|
|
travP_find_next_parents_first(ABTraversal trav)
|
|
{
|
|
ABObj curObj= trav->curObj;
|
|
ABObj tmpObj= NULL;
|
|
|
|
if (curObj == trav->rootObj)
|
|
{
|
|
curObj= travP_obj_first_child(curObj, trav);
|
|
}
|
|
else
|
|
{
|
|
if ((tmpObj= travP_obj_next_sibling(curObj, trav)) != NULL)
|
|
{
|
|
curObj= tmpObj;
|
|
}
|
|
else
|
|
{
|
|
tmpObj= find_first_sibling_child(curObj, trav);
|
|
if (tmpObj == NULL)
|
|
{
|
|
tmpObj= find_first_ancestor_sibling_child(curObj, trav);
|
|
}
|
|
curObj= tmpObj;
|
|
}
|
|
}
|
|
|
|
trav->curObj= curObj;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static ABObj
|
|
find_first_item(ABObj obj)
|
|
{
|
|
ABObj compRoot= obj_get_root(obj);
|
|
ABObj child= NULL;
|
|
ABObj item= NULL;
|
|
|
|
for (child= obj->first_child; child != NULL; child= child->next_sibling)
|
|
{
|
|
if (obj_get_root(child) == compRoot)
|
|
{
|
|
/* it's a subobj - look at its children */
|
|
item= find_first_item(child);
|
|
if (item != NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (obj_is_item(child))
|
|
{
|
|
item= child;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
|
|
/*
|
|
* Finds the first sibling (from "left" to "right") of the object
|
|
* that has a child. Returns the first child of that sibling.
|
|
*/
|
|
static ABObj
|
|
find_first_sibling_child(ABObj obj, ABTraversal trav)
|
|
{
|
|
ABObj sibling= obj;
|
|
ABObj child= NULL;
|
|
ABObj prevSibling= NULL;
|
|
ABObj firstChild= NULL;
|
|
|
|
while ((prevSibling= travP_obj_prev_sibling(sibling, trav)) != NULL)
|
|
{
|
|
sibling= prevSibling;
|
|
}
|
|
|
|
if ((firstChild= travP_obj_first_child(sibling, trav)) != NULL)
|
|
{
|
|
child= firstChild;
|
|
}
|
|
else
|
|
{
|
|
child= find_next_sibling_child(sibling, trav);
|
|
}
|
|
return child;
|
|
}
|
|
|
|
|
|
/*
|
|
* Finds the next sibling of the object that has a child.
|
|
* Returns the first child of that sibling.
|
|
*/
|
|
static ABObj
|
|
find_next_sibling_child(ABObj obj, ABTraversal trav)
|
|
{
|
|
ABObj sibling= travP_obj_next_sibling(obj, trav);
|
|
ABObj child= NULL;
|
|
ABObj firstChild= NULL;
|
|
|
|
while ( (sibling != NULL)
|
|
&& ((firstChild= travP_obj_first_child(sibling, trav)) == NULL) )
|
|
{
|
|
sibling= travP_obj_next_sibling(sibling, trav);
|
|
}
|
|
|
|
if (sibling != NULL)
|
|
{
|
|
child= firstChild;
|
|
}
|
|
return child;
|
|
}
|
|
|
|
|
|
/*
|
|
* Finds the first ancestor that has a sibling to its "right"
|
|
* that has a child. Returns the child.
|
|
*/
|
|
static ABObj
|
|
find_first_ancestor_sibling_child(ABObj obj, ABTraversal trav)
|
|
{
|
|
ABObj ancestor= travP_obj_parent(obj, trav);
|
|
ABObj child= NULL;
|
|
|
|
for (; ((ancestor != NULL) && (ancestor != trav->rootObj));
|
|
ancestor= travP_obj_parent(ancestor, trav))
|
|
{
|
|
child= find_next_sibling_child(ancestor, trav);
|
|
if (child != NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return child;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check the new current object to see if it qualifies for the traversal.
|
|
*
|
|
* Assumes: trav->curObj is not null
|
|
*/
|
|
static BOOL
|
|
travP_qualifies(ABTraversal trav)
|
|
{
|
|
register ABObj curObj = trav->curObj;
|
|
register BOOL qualifies= TRUE;
|
|
|
|
if (obj_has_impl_flags(curObj, ObjFlagDestroyed))
|
|
{
|
|
qualifies= FALSE;
|
|
goto epilogue;
|
|
}
|
|
|
|
switch (travP_get_qualifier(trav))
|
|
{
|
|
case AB_TRAV_ACTIONS:
|
|
case AB_TRAV_ACTIONS_FOR_OBJ:
|
|
qualifies= obj_is_action(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_COMP_SUBOBJS:
|
|
qualifies = (obj_get_root(curObj) == trav->rootObj);
|
|
break;
|
|
|
|
case AB_TRAV_FILES:
|
|
qualifies= (curObj->type == AB_TYPE_FILE);
|
|
break;
|
|
|
|
case AB_TRAV_GROUPS:
|
|
qualifies= obj_is_group(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_ITEMS:
|
|
case AB_TRAV_ITEMS_FOR_OBJ:
|
|
qualifies= obj_is_item(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_MENUS:
|
|
qualifies= obj_is_menu(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_MODULES:
|
|
qualifies= obj_is_module(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_SALIENT:
|
|
case AB_TRAV_SALIENT_CHILDREN:
|
|
qualifies= obj_is_salient(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_SALIENT_UI:
|
|
case AB_TRAV_SALIENT_UI_CHILDREN:
|
|
qualifies= obj_is_salient_ui(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_UI:
|
|
qualifies= obj_is_ui(curObj);
|
|
break;
|
|
|
|
case AB_TRAV_WINDOWS:
|
|
qualifies= obj_is_window(curObj);
|
|
break;
|
|
}
|
|
|
|
if ((qualifies) && (trav->testFunc != NULL))
|
|
{
|
|
qualifies = trav->testFunc(curObj);
|
|
}
|
|
|
|
epilogue:
|
|
return qualifies;
|
|
} /* travP_qualifies */
|
|
|
|
|
|
/*
|
|
* Verifies that the traversal type is valid, and changes
|
|
* it, if necessary.
|
|
*/
|
|
static int
|
|
travP_verify_type(ABTraversal trav, BOOL warn)
|
|
{
|
|
int iRet= 0;
|
|
unsigned travQualifier= travP_get_qualifier(trav);
|
|
char errMsg[256];
|
|
errMsg[0]= 0;
|
|
|
|
switch (travQualifier)
|
|
{
|
|
case AB_TRAV_ACTIONS:
|
|
case AB_TRAV_ACTIONS_FOR_OBJ:
|
|
case AB_TRAV_ALL:
|
|
case AB_TRAV_CHILDREN:
|
|
case AB_TRAV_COMP_SUBOBJS:
|
|
case AB_TRAV_FILES:
|
|
case AB_TRAV_GROUPS:
|
|
case AB_TRAV_ITEMS:
|
|
case AB_TRAV_ITEMS_FOR_OBJ:
|
|
case AB_TRAV_MODULES:
|
|
case AB_TRAV_MENUS:
|
|
case AB_TRAV_SALIENT:
|
|
case AB_TRAV_SALIENT_CHILDREN:
|
|
case AB_TRAV_SALIENT_UI:
|
|
case AB_TRAV_SALIENT_UI_CHILDREN:
|
|
case AB_TRAV_SIBLINGS:
|
|
case AB_TRAV_UI:
|
|
case AB_TRAV_WINDOWS:
|
|
/*
|
|
* All supported
|
|
*/
|
|
break;
|
|
|
|
case AB_TRAV_PARENTS:
|
|
if (travP_is_parents_first(trav) && debugging())
|
|
{
|
|
sprintf(errMsg,
|
|
"WARNING: "
|
|
"AB_TRAV_PARENTS - Ignoring unsupported modifier "
|
|
"AB_TRAV_MOD_PARENTS_FIRST.");
|
|
trav->travType &= ~AB_TRAV_MOD_PARENTS_FIRST;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (debugging())
|
|
{
|
|
sprintf(errMsg, "WARNING: travType %d unknown - "
|
|
"Using AB_TRAV_ALL.",
|
|
travQualifier);
|
|
}
|
|
travQualifier= AB_TRAV_ALL;
|
|
trav->travType &= TRAV_MODIFIER_MASK;
|
|
trav->travType |= travQualifier;
|
|
break;
|
|
}
|
|
|
|
if (warn && ((*errMsg) != 0))
|
|
{
|
|
fprintf(stderr, "%s\n", errMsg);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
/*
|
|
* If parent is NULL, returns NULL.
|
|
*/
|
|
static ABObj
|
|
find_first_child_of_type(ABObj parent, ABTraversal trav, AB_OBJECT_TYPE type)
|
|
{
|
|
ABObj child= NULL;
|
|
|
|
if (parent == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
for (child= travP_obj_first_child(parent, trav);
|
|
child != NULL; child= travP_obj_next_sibling(child, trav))
|
|
{
|
|
if (child->type == type)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return child;
|
|
}
|
|
|
|
|
|
static ABObj
|
|
find_first_action(ABObj obj, ABTraversal trav)
|
|
{
|
|
obj= find_first_child_of_type(obj, trav, AB_TYPE_ACTION_LIST);
|
|
if (obj != NULL)
|
|
{
|
|
obj= find_first_child_of_type(obj, trav, AB_TYPE_ACTION);
|
|
}
|
|
return obj;
|
|
}
|
|
|