mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
1865 lines
40 KiB
C
1865 lines
40 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: obj_utils.c /main/4 1996/10/02 15:44:56 drk $
|
|
*
|
|
* @(#)obj_utils.c 3.137 01 Feb 1995
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* utils.c - general utilities
|
|
*/
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
#include <sys/times.h>
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#include <time.h>
|
|
#include "objP.h" /* put objP.h first! */
|
|
#include <ab_private/trav.h>
|
|
#include <ab_private/util.h>
|
|
#include <ab/util_types.h>
|
|
#include <ab_private/istr.h>
|
|
#include "obj_utils.h"
|
|
#include "obj_names_listP.h"
|
|
|
|
#define AB_TYPE_MODULE AB_TYPE_MODULE /* REMIND: can be taken out later */
|
|
|
|
/*
|
|
* Global variables...
|
|
*/
|
|
char *abo_empty_string = "";
|
|
char *abo_null_string = "(nil)";
|
|
|
|
static struct sigaction org_sig_segv_handler;
|
|
#ifdef SIGBUS
|
|
static struct sigaction org_sig_bus_handler;
|
|
#endif
|
|
static sigjmp_buf sigjmp_env;
|
|
|
|
static volatile BOOL sig_fault_handler_installed = FALSE;
|
|
static volatile BOOL mem_fault_occurred = FALSE;
|
|
static int sig_fault_handler_install(void);
|
|
static int sig_fault_handler_uninstall(void);
|
|
static void sig_fault_handler();
|
|
static BOOL objP_is_accessible(ABObj obj);
|
|
static int build_obj_array(
|
|
ABObj **objArrayInOut,
|
|
int *objArraySizeInOut,
|
|
ABObj root
|
|
);
|
|
static int verify_the_silly_index(
|
|
ABObj nameScopeObj,
|
|
ABObj *objArray,
|
|
int objArraySize
|
|
);
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** General (non-object) utilities **
|
|
** **
|
|
*************************************************************************/
|
|
|
|
AB_OBJECT_TYPE
|
|
ab_get_proper_subobj_type(AB_OBJECT_TYPE type)
|
|
{
|
|
AB_OBJECT_TYPE subtype = AB_TYPE_UNKNOWN;
|
|
|
|
switch (type)
|
|
{
|
|
case AB_TYPE_PROJECT:
|
|
subtype = AB_TYPE_MODULE;
|
|
break;
|
|
|
|
case AB_TYPE_CHOICE:
|
|
case AB_TYPE_LIST:
|
|
case AB_TYPE_MENU:
|
|
subtype = AB_TYPE_ITEM;
|
|
break;
|
|
}
|
|
|
|
return subtype;
|
|
}
|
|
|
|
|
|
/*
|
|
* Returns the item type this object should contain. If the object is an
|
|
* item, it returns the type of the item.
|
|
*/
|
|
AB_ITEM_TYPE
|
|
ab_get_proper_item_type(AB_OBJECT_TYPE type)
|
|
{
|
|
AB_ITEM_TYPE item_type = AB_ITEM_FOR_UNDEF;
|
|
|
|
switch (type)
|
|
{
|
|
case AB_TYPE_MENU:
|
|
item_type = AB_ITEM_FOR_MENU;
|
|
break;
|
|
|
|
case AB_TYPE_CHOICE:
|
|
item_type = AB_ITEM_FOR_CHOICE;
|
|
break;
|
|
|
|
case AB_TYPE_LIST:
|
|
item_type = AB_ITEM_FOR_LIST;
|
|
break;
|
|
}
|
|
|
|
return item_type;
|
|
}
|
|
|
|
|
|
int
|
|
ab_string_list_count(STRING * list)
|
|
{
|
|
int i = 0;
|
|
if (list != NULL)
|
|
{
|
|
while (list[i] != NULL)
|
|
{
|
|
++i;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
AB_FILE_TYPE
|
|
ab_file_type_from_path(STRING path)
|
|
{
|
|
AB_FILE_TYPE file_type = AB_FILE_UNDEF;
|
|
int pathlen = strlen(path);
|
|
|
|
if (pathlen >= 3)
|
|
{
|
|
char *ext = &(path[pathlen - 2]);
|
|
if (strcmp(ext, ".P") == 0)
|
|
{
|
|
file_type = AB_FILE_GIL_PROJECT;
|
|
}
|
|
else if (strcmp(ext, ".G") == 0)
|
|
{
|
|
file_type = AB_FILE_GIL_INTERFACE;
|
|
}
|
|
}
|
|
|
|
return file_type;
|
|
}
|
|
|
|
|
|
/*
|
|
* Only ensures that the identifier has no white space in it.
|
|
*/
|
|
BOOL
|
|
ab_ident_is_ok(STRING ident)
|
|
{
|
|
char *cp;
|
|
if (ident == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
for (cp = ident; *cp != 0; ++cp)
|
|
{
|
|
if (isspace(*cp))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ab_c_ident_is_ok(STRING ident)
|
|
{
|
|
int i;
|
|
int len = 0;
|
|
char ch;
|
|
|
|
if (ident == NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
for (i = 0, len = strlen(ident); i < len; ++i)
|
|
{
|
|
ch = ident[i];
|
|
|
|
/* The first character of a variable name must be a letter.
|
|
* The underscore character is considered a letter in C.
|
|
*/
|
|
if (i == 0)
|
|
{
|
|
if (!(isalpha(ch)) && (ch != '_'))
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!((isalnum(ch) || (ch == '_'))))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Object utilities **
|
|
** **
|
|
*************************************************************************/
|
|
|
|
STRING
|
|
obj_get_file(ABObj obj)
|
|
{
|
|
if (obj->type == AB_TYPE_FILE)
|
|
{
|
|
return obj_get_name(obj); /* stored as name */
|
|
}
|
|
while ((obj != NULL) && (obj->type != AB_TYPE_MODULE)
|
|
&& (obj->type != AB_TYPE_PROJECT))
|
|
{
|
|
obj = obj->parent;
|
|
}
|
|
if (obj != NULL)
|
|
{
|
|
if (obj->type == AB_TYPE_MODULE)
|
|
{
|
|
return istr_string(obj->info.module.file);
|
|
}
|
|
else if (obj->type == AB_TYPE_PROJECT)
|
|
{
|
|
return istr_string(obj->info.project.file);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Gets the project the object belongs to
|
|
*/
|
|
ABObj
|
|
obj_get_project(ABObj obj)
|
|
{
|
|
while ((obj != NULL) && (obj->type != AB_TYPE_PROJECT))
|
|
{
|
|
obj = obj->parent;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* Gets the module the object belongs to
|
|
*/
|
|
ABObj
|
|
obj_get_module(ABObj obj)
|
|
{
|
|
while ((obj != NULL) && (obj->type != AB_TYPE_MODULE))
|
|
{
|
|
obj = obj->parent;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* Gets the window the object belongs to
|
|
*/
|
|
ABObj
|
|
obj_get_window(ABObj obj)
|
|
{
|
|
while ((obj != NULL) && !obj_is_window(obj))
|
|
{
|
|
obj = obj->parent;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
int
|
|
obj_get_num_items(ABObj obj)
|
|
{
|
|
return trav_count(obj, AB_TRAV_ITEMS_FOR_OBJ);
|
|
}
|
|
|
|
/*
|
|
* Counts the given object! (i.e., always returns at least 1).
|
|
*/
|
|
int
|
|
obj_get_num_siblings(ABObj obj)
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
int num_sibs = 0;
|
|
for (trav_open(&trav, obj, AB_TRAV_SIBLINGS);
|
|
(obj = trav_next(&trav)) != NULL;)
|
|
{
|
|
++num_sibs;
|
|
}
|
|
return num_sibs;
|
|
}
|
|
|
|
/*
|
|
* Makes sure the object has at least the specified number of children.
|
|
*
|
|
* Any new children created are appended to the child list, and they are of the
|
|
* type returned from abo_proper_item_type.
|
|
*/
|
|
int
|
|
obj_ensure_num_children(ABObj obj, int requested_num_children)
|
|
{
|
|
AB_OBJECT_TYPE child_type = ab_get_proper_subobj_type(obj->type);
|
|
AB_ITEM_TYPE child_item_type = ab_get_proper_item_type(obj->type);
|
|
int num_children = obj_get_num_children(obj);
|
|
ABObj child = NULL;
|
|
|
|
while (num_children < requested_num_children)
|
|
{
|
|
child = obj_create(child_type, NULL);
|
|
if (child == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
if (obj_is_item(child))
|
|
{
|
|
child->info.item.type = child_item_type;
|
|
}
|
|
obj_append_child(obj, child);
|
|
++num_children;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_find_child_by_label(ABObj root, STRING label)
|
|
{
|
|
ABObj child;
|
|
|
|
for (child = root->first_child;
|
|
child != NULL; child = child->next_sibling)
|
|
{
|
|
if (istr_equalstr(child->label, label))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return child;
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_find_child_by_type(ABObj obj, AB_OBJECT_TYPE childType)
|
|
{
|
|
ABObj child;
|
|
for (child = obj->first_child;
|
|
(child != NULL); child = child->next_sibling)
|
|
{
|
|
if (child->type == childType)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return child;
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_find_by_name(ABObj root, STRING name)
|
|
{
|
|
StringList names = objP_get_names_scope_for_children(root);
|
|
ISTRING istr_name = istr_dup_existing(name);
|
|
AB_TRAVERSAL trav;
|
|
ABObj obj = NULL;
|
|
|
|
if ((name == NULL) || (istr_name == NULL))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (names != NULL)
|
|
{
|
|
obj = (ABObj)strlist_get_istr_data(names, istr_name);
|
|
}
|
|
else
|
|
{
|
|
for (trav_open(&trav, root, AB_TRAV_ALL);
|
|
(obj = trav_next(&trav)) != NULL;)
|
|
{
|
|
if (!(obj_is_project(obj) || obj_is_module(obj)))
|
|
{
|
|
if (istr_equal(obj->name, istr_name))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
istr_destroy(istr_name);
|
|
return obj;
|
|
}
|
|
|
|
ABObj
|
|
obj_find_by_name_and_type(ABObj root, STRING name, AB_OBJECT_TYPE type)
|
|
{
|
|
ABObj obj;
|
|
AB_TRAVERSAL trav;
|
|
|
|
if (name == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
for (trav_open(&trav, root, AB_TRAV_ALL);
|
|
(obj = trav_next(&trav)) != NULL;)
|
|
{
|
|
if ((obj->type == type)
|
|
&& (istr_equalstr(obj->name, name)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
trav_close(&trav);
|
|
return obj;
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_find_by_type(ABObj root, AB_OBJECT_TYPE type)
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
ABObj obj = NULL;
|
|
|
|
for (trav_open(&trav, root, AB_TRAV_UI | AB_TRAV_MOD_PARENTS_FIRST);
|
|
(obj = trav_next(&trav)) != NULL;)
|
|
{
|
|
if (obj->type == type)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
trav_close(&trav);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_find_child_by_name(ABObj obj, STRING name)
|
|
{
|
|
ABObj child;
|
|
if (name == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
for (child = obj->first_child;
|
|
child != NULL; child = child->next_sibling)
|
|
{
|
|
if (istr_equalstr(child->name, name))
|
|
{
|
|
return child;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_find_menu_by_name(ABObj root, STRING name)
|
|
{
|
|
return obj_find_by_name_and_type(root, name, AB_TYPE_MENU);
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_find_module_by_name(ABObj root, STRING name)
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
ABObj module = NULL;
|
|
|
|
for (trav_open(&trav, root, AB_TRAV_MODULES);
|
|
(module = trav_next(&trav)) != NULL;)
|
|
{
|
|
if (util_streq(obj_get_name(module), name))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
trav_close(&trav);
|
|
|
|
return module;
|
|
}
|
|
|
|
|
|
ABObj
|
|
obj_scoped_find_or_create_undef(ABObj parent,
|
|
STRING scopedName, AB_OBJECT_TYPE objType)
|
|
{
|
|
ABObj obj = obj_scoped_find_by_name(parent, scopedName);
|
|
|
|
if (obj == NULL)
|
|
{
|
|
STRING moduleName = obj_scoped_name_get_module_name(
|
|
scopedName);
|
|
STRING objName = obj_scoped_name_get_obj_name(
|
|
scopedName);
|
|
ABObj project = NULL;
|
|
ABObj module = NULL;
|
|
|
|
if (moduleName == NULL)
|
|
{
|
|
/* simple name - create as child of the "parent" object */
|
|
obj = obj_create(objType, parent);
|
|
}
|
|
else
|
|
{
|
|
/* complex name - find module to create under */
|
|
project = obj_get_project(parent);
|
|
if (project != NULL)
|
|
{
|
|
module = obj_find_module_by_name(project, moduleName);
|
|
if (module == NULL)
|
|
{
|
|
/* damn! module don't exist!! */
|
|
module = obj_create(AB_TYPE_MODULE, project);
|
|
obj_set_is_defined(module, FALSE);
|
|
obj_set_name(module, moduleName);
|
|
}
|
|
}
|
|
if (module != NULL)
|
|
{
|
|
/* actually create the object under the correct module */
|
|
obj = obj_create(objType, module);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We've (hopefully) created a new object (or more correctly, a
|
|
* reference to an undefined object). Set the attributes that we know
|
|
* about the object
|
|
*/
|
|
if (obj != NULL)
|
|
{
|
|
obj_set_is_defined(obj, FALSE);
|
|
obj_set_name(obj, objName);
|
|
}
|
|
} /* obj == NULL */
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Functions private to libgobj **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
int
|
|
abo_error(STRING message)
|
|
{
|
|
util_printf_err("%s\n", message);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
indent(int spaces)
|
|
{
|
|
int i;
|
|
for (i = 0; i < spaces; ++i)
|
|
{
|
|
util_dputs(0, " ");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Returns TRUE if the object is the target of a project connection (i.e. one
|
|
* that is written into the project .c file, and not into a module. Formerly
|
|
* known as cross-module connections).
|
|
*/
|
|
BOOL
|
|
obj_is_project_action_target(ABObj obj)
|
|
{
|
|
ABObj project = NULL;
|
|
BOOL is_project_target = FALSE;
|
|
ABObj action = NULL;
|
|
AB_TRAVERSAL trav;
|
|
|
|
project = obj_get_project(obj);
|
|
for (trav_open(&trav, project, AB_TRAV_ACTIONS_FOR_OBJ);
|
|
(action = trav_next(&trav)) != NULL;)
|
|
{
|
|
if (action->info.action.to == obj)
|
|
{
|
|
is_project_target = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
trav_close(&trav);
|
|
return is_project_target;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a valid C name given a string (normally, a label)
|
|
*/
|
|
STRING
|
|
ab_make_valid_c_ident(STRING label)
|
|
{
|
|
static char name[MAXPATHLEN];
|
|
static int ith = 0;
|
|
int lastchar = -1;
|
|
register char *oldPtr = label;
|
|
register char *newPtr = name;
|
|
|
|
if (isdigit(*oldPtr))
|
|
{
|
|
|
|
/*
|
|
* If the label starts with a number, prepend 'dtb'
|
|
*/
|
|
*newPtr++ = 'd';
|
|
*newPtr++ = 't';
|
|
*newPtr++ = 'b';
|
|
lastchar = *(newPtr-1);
|
|
}
|
|
|
|
while ((*oldPtr) != '\0')
|
|
{
|
|
if (isalnum(*oldPtr))
|
|
{
|
|
lastchar = *newPtr++ = *oldPtr++;
|
|
}
|
|
else if (isprint(*oldPtr) && (lastchar != '_'))
|
|
{
|
|
/* turn illegal printable chars into _ (e.g. / .) */
|
|
lastchar = *newPtr++ = '_';
|
|
oldPtr++;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Skip the illegal character.
|
|
*/
|
|
oldPtr++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Strip off trailing underscore (there will be no more than one).
|
|
*/
|
|
if (lastchar == '_')
|
|
{
|
|
--newPtr;
|
|
}
|
|
*newPtr = 0; /* terminate the string */
|
|
|
|
if (newPtr == name)
|
|
{
|
|
|
|
/*
|
|
* The entire label is composed of illegal characters, in that case,
|
|
* return a generated name.
|
|
*/
|
|
sprintf(name, "dtb_name_%d", ith++);
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
|
|
/*
|
|
* Given a unix file name, strip off the path and the suffix.
|
|
*/
|
|
STRING
|
|
ab_ident_from_file_name(STRING filename)
|
|
{
|
|
static char buf[MAXPATHLEN];
|
|
char *p;
|
|
|
|
if (filename != NULL)
|
|
{
|
|
if (p = (char *) strrchr(filename, '/'))
|
|
snprintf(buf, sizeof(buf), "%s", p + 1);
|
|
else
|
|
snprintf(buf, sizeof(buf), "%s", filename);
|
|
|
|
if (p = (char *) strrchr(buf, '.'))
|
|
*p = '\0';
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
|
|
/*
|
|
* Assumes: name, label not NULL.
|
|
*/
|
|
STRING
|
|
ab_ident_from_name_and_label(STRING name, STRING label)
|
|
{
|
|
static char new_name[256];
|
|
sprintf(new_name, "%s_%s", name, label);
|
|
return ab_make_valid_c_ident(new_name);
|
|
}
|
|
|
|
|
|
/*
|
|
* Gets the module and object name from a complex name (i.e., a name of the
|
|
* form module.name or module::name
|
|
*/
|
|
int
|
|
obj_scoped_name_split(
|
|
STRING complex_name,
|
|
STRING module_name_buf,
|
|
int module_name_buf_size,
|
|
STRING obj_name_buf,
|
|
int obj_name_buf_size
|
|
)
|
|
{
|
|
int return_value = 0;
|
|
char *dot_ptr = NULL;
|
|
char *module_name_ptr = NULL;
|
|
char *obj_name_ptr = complex_name;
|
|
char *module_name_end_ptr = NULL;
|
|
int moduleNameEndChar = -1;
|
|
|
|
if ((dot_ptr = strchr(complex_name, '.')) != NULL)
|
|
{
|
|
module_name_ptr = complex_name;
|
|
obj_name_ptr = dot_ptr + 1;
|
|
}
|
|
else if ((dot_ptr = strstr(complex_name, "::")) != NULL)
|
|
{
|
|
module_name_ptr = complex_name;
|
|
obj_name_ptr = dot_ptr + 2;
|
|
}
|
|
|
|
/*
|
|
* Remove white space on either side of the separator
|
|
*/
|
|
if (dot_ptr != NULL)
|
|
{
|
|
/* put a 0 at the end of the module name */
|
|
for (module_name_end_ptr = dot_ptr - 1;
|
|
((module_name_end_ptr > complex_name)
|
|
&& isspace(*module_name_end_ptr));)
|
|
{
|
|
--module_name_end_ptr;
|
|
}
|
|
if (module_name_end_ptr < dot_ptr)
|
|
{
|
|
++module_name_end_ptr; /* point one *after* last char in
|
|
* name */
|
|
}
|
|
moduleNameEndChar = *module_name_end_ptr;
|
|
*module_name_end_ptr = 0;
|
|
}
|
|
while (((*obj_name_ptr) != 0) && (isspace(*obj_name_ptr)))
|
|
{
|
|
++obj_name_ptr;
|
|
}
|
|
|
|
/*
|
|
* We now now the substrings' locations. grab them
|
|
*/
|
|
if (module_name_buf != NULL)
|
|
{
|
|
if (module_name_ptr == NULL)
|
|
{
|
|
/* no module name! */
|
|
*module_name_buf = 0;
|
|
}
|
|
else
|
|
{
|
|
strncpy(module_name_buf, complex_name, module_name_buf_size);
|
|
module_name_buf[module_name_buf_size - 1] = 0;
|
|
}
|
|
}
|
|
if (obj_name_buf != NULL)
|
|
{
|
|
strncpy(obj_name_buf, obj_name_ptr, obj_name_buf_size);
|
|
obj_name_buf[obj_name_buf_size - 1] = 0;
|
|
}
|
|
|
|
/* epilogue: */
|
|
/* replace the 0 we inserted with the char that was there */
|
|
if (module_name_end_ptr != NULL)
|
|
{
|
|
*module_name_end_ptr = moduleNameEndChar;
|
|
}
|
|
return return_value;
|
|
}
|
|
|
|
|
|
/*
|
|
* Gets the module name from the given object name, if there is one (i.e, the
|
|
* name is of the for module::name or module.name).
|
|
*/
|
|
STRING
|
|
obj_scoped_name_get_module_name(STRING complexName)
|
|
{
|
|
static char module_name[256] = "";
|
|
int rc;
|
|
rc = obj_scoped_name_split(complexName, module_name, 256, NULL, 0);
|
|
if ((rc < 0) || (*module_name == 0))
|
|
{
|
|
return NULL;
|
|
}
|
|
return module_name;
|
|
}
|
|
|
|
|
|
/*
|
|
* Gets the simple object name from the complex name (a name of the form
|
|
* module::name or module.name).
|
|
*/
|
|
STRING
|
|
obj_scoped_name_get_obj_name(STRING complexName)
|
|
{
|
|
static char simple_name[256] = "";
|
|
int rc;
|
|
rc = obj_scoped_name_split(complexName, NULL, 0, simple_name, 256);
|
|
if ((rc < 0) || (*simple_name == 0))
|
|
{
|
|
return NULL;
|
|
}
|
|
return simple_name;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Debugging functions **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
static int
|
|
obj_tree_print_indented(ABObj obj,
|
|
int spaces, int verbosity);
|
|
static int indent(int spaces);
|
|
|
|
int
|
|
obj_print(ABObj obj)
|
|
{
|
|
int spaces = 0;
|
|
int verbosity = util_get_verbosity();
|
|
return obj_print_indented(obj, spaces, verbosity);
|
|
}
|
|
|
|
int
|
|
obj_print_indented(ABObj obj, int spaces, int verbosity)
|
|
{
|
|
#define print_flag(flag, flag_str) \
|
|
(obj_has_flag(obj, flag)? \
|
|
util_dprintf(0, " %s", flag_str) \
|
|
: \
|
|
0)
|
|
|
|
char namebuf[256];
|
|
|
|
*namebuf = 0;
|
|
if (obj == NULL)
|
|
{
|
|
util_dprintf(0, "NULL Object\n");
|
|
return 0;
|
|
}
|
|
if (obj_is_action(obj))
|
|
{
|
|
switch (obj->info.action.func_type)
|
|
{
|
|
case AB_FUNC_USER_DEF:
|
|
sprintf(namebuf, "func:%s",
|
|
istr_string_safe(obj->info.action.func_value.func_name));
|
|
break;
|
|
|
|
case AB_FUNC_BUILTIN: /* builtin */
|
|
sprintf(namebuf, "builtin:%s",
|
|
util_builtin_action_to_string(
|
|
obj->info.action.func_value.builtin));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(namebuf, "name:'%s'", istr_string_safe(obj->name));
|
|
}
|
|
indent(spaces);
|
|
if ((obj != NULL) && (obj_has_impl_flags(obj, ObjFlagDestroyed)))
|
|
{
|
|
util_dprintf(1, "**DESTROYED** ");
|
|
}
|
|
if ((obj != NULL) && (!obj_is_defined(obj)))
|
|
{
|
|
util_dprintf(0, "**UNDEF** ");
|
|
}
|
|
util_dprintf(0, "0x%08lx: %s type:%s\n",
|
|
obj, namebuf,
|
|
util_object_type_to_string(obj->type));
|
|
if (verbosity >= 4)
|
|
{
|
|
indent(spaces);
|
|
util_dprintf(1, "file: '%s'\n", util_strsafe(obj_get_file(obj)));
|
|
if (obj->flags != NoFlags)
|
|
{
|
|
indent(spaces);
|
|
util_dprintf(0, "flags:");
|
|
print_flag(NoCodeGenFlag, "NoCodeGen");
|
|
print_flag(XmConfiguredFlag, "XmConfiged");
|
|
print_flag(XmCfgForCodeFlag, "CfgForCode");
|
|
print_flag(XmCfgForBuildFlag, "CfgForBuild");
|
|
print_flag(InstantiatedFlag, "Instantiated");
|
|
print_flag(BuildActionsFlag, "BuildActions");
|
|
print_flag(MappedFlag, "Mapped");
|
|
print_flag(AttrChangedFlag, "AttrChanged");
|
|
print_flag(SaveNeededFlag, "SaveNeeded");
|
|
print_flag(BeingDestroyedFlag, "BeingDestroyed");
|
|
util_dprintf(0, "\n");
|
|
}
|
|
if (obj_is_action(obj))
|
|
{
|
|
ABObj thisModule = NULL;
|
|
ABObj thatModule = NULL;
|
|
ABObj thatObj = NULL;
|
|
AB_WHEN when = AB_WHEN_UNDEF;
|
|
|
|
if (obj != NULL)
|
|
{
|
|
thisModule = obj_get_module(obj);
|
|
}
|
|
|
|
/*
|
|
* To value
|
|
*/
|
|
thatObj = obj->info.action.to;
|
|
if (thatObj != NULL)
|
|
{
|
|
thatModule = obj_get_module(thatObj);
|
|
}
|
|
indent(spaces);
|
|
util_dprintf(0, "to: ");
|
|
if ((thatModule != NULL) && (thatModule != thisModule))
|
|
{
|
|
util_dprintf(0, "%s.", obj_get_safe_name(thatModule, namebuf, 256));
|
|
}
|
|
util_dprintf(0, "(%#08lx)%s\n",
|
|
thatObj, obj_get_safe_name(thatObj, namebuf, 256));
|
|
|
|
/*
|
|
* From value
|
|
*/
|
|
thatObj = obj->info.action.from;
|
|
if (thatObj != NULL)
|
|
{
|
|
thatModule = obj_get_module(thatObj);
|
|
}
|
|
indent(spaces);
|
|
util_dprintf(0, "from: ");
|
|
if ((thatModule != NULL) && (thatModule != thisModule))
|
|
{
|
|
util_dprintf(0, "%s.", obj_get_safe_name(thatModule, namebuf, 256));
|
|
}
|
|
util_dprintf(0, "(%#08lx)%s\n",
|
|
thatObj, obj_get_safe_name(thatObj, namebuf, 256));
|
|
|
|
when = obj_get_when(obj);
|
|
indent(spaces);
|
|
util_dprintf(0,
|
|
"when: %s\n", util_strsafe(util_when_to_string(when)));
|
|
}
|
|
else
|
|
{
|
|
indent(spaces);
|
|
util_dprintf(0, "class:%s\n",
|
|
istr_string_safe(obj->class_name));
|
|
indent(spaces);
|
|
util_dprintf(0, "[parent: %s]\n",
|
|
obj_get_safe_name(obj->parent, namebuf, 256));
|
|
if (obj->ref_to != NULL)
|
|
{
|
|
indent(spaces);
|
|
util_dprintf(0, "[ref_to: %s]\n",
|
|
obj_get_safe_name(obj->ref_to, namebuf, 256));
|
|
}
|
|
if (obj->part_of != NULL)
|
|
{
|
|
indent(spaces);
|
|
util_dprintf(0, "[part_of: %s]\n",
|
|
obj_get_safe_name(obj->part_of, namebuf, 256));
|
|
}
|
|
indent(spaces);
|
|
util_dprintf(0, "x: %d\n", obj->x);
|
|
indent(spaces);
|
|
util_dprintf(0, "y: %d\n", obj->y);
|
|
indent(spaces);
|
|
util_dprintf(0, "width: %d\n", obj->width);
|
|
indent(spaces);
|
|
util_dprintf(0, "height: %d\n", obj->height);
|
|
indent(spaces);
|
|
util_dprintf(0, "label: '%s'\n",
|
|
istr_string_safe(obj->label));
|
|
} /* if is_action */
|
|
}
|
|
return 0;
|
|
#undef print_flag
|
|
} /* obj_print_indented */
|
|
|
|
|
|
int
|
|
obj_tree_print(ABObj obj)
|
|
{
|
|
int iRet = 0;
|
|
util_dprintf(0, "***** Object tree *****\n");
|
|
iRet = obj_tree_print_indented(obj, 0, util_get_verbosity());
|
|
iRet = obj_tree_verify(obj);
|
|
if (iRet < 0)
|
|
{
|
|
util_dprintf(0, "\n***\n*** TREE IS CORRUPT!\n***");
|
|
|
|
}
|
|
util_dprintf(0, "******* Tree End ******\n");
|
|
return iRet;
|
|
}
|
|
|
|
|
|
static int
|
|
obj_tree_print_indented(ABObj obj, int spaces, int verbosity)
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
ABObj child = NULL;
|
|
|
|
if (obj == NULL)
|
|
{
|
|
util_dprintf(0, "NULL Tree\n");
|
|
return 0;
|
|
}
|
|
obj_print_indented(obj, spaces, verbosity);
|
|
if (verbosity >= 4)
|
|
{
|
|
util_dprintf(0, "\n");
|
|
}
|
|
for (trav_open(&trav, obj, AB_TRAV_CHILDREN);
|
|
(child = trav_next(&trav)) != NULL;)
|
|
{
|
|
obj_tree_print_indented(child, spaces + 4, verbosity);
|
|
}
|
|
trav_close(&trav);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Perform regular checks of object integrity.
|
|
* Tries not to overuse CPU, so this may or may not actually verify anything.
|
|
*
|
|
* Note that the debug_last_verify_time field doesn't exist in non-debugging
|
|
* builds.
|
|
*/
|
|
int
|
|
objP_update_verify(ABObj obj)
|
|
{
|
|
#ifndef DEBUG
|
|
return 0;
|
|
#else
|
|
int return_value = 0;
|
|
static ABObj lastObj = NULL;
|
|
static int lastObjCount = 0;
|
|
time_t curTime = 0;
|
|
|
|
/*
|
|
* time() can be rather slow, so let multiple references to the
|
|
* same object slide...
|
|
*/
|
|
if ( (obj != NULL)
|
|
&& ( (debug_level() >= 5)
|
|
|| (( (obj != lastObj) || (++lastObjCount > 10))
|
|
&& (curTime > (obj->debug_last_verify_time+1))) )
|
|
)
|
|
{
|
|
return_value = obj_verify(obj);
|
|
lastObj = obj;
|
|
lastObjCount = 0;
|
|
}
|
|
return return_value;
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
|
|
/*
|
|
* This function does not call any functions outside of this file.
|
|
* This is because many functions call this one, and we don't want
|
|
* to recurse.
|
|
*
|
|
* This function can be EXTREMELY SLOW! Calling it, for instance,
|
|
* one million times inside a loop would not be the right thing to do.
|
|
*/
|
|
int
|
|
obj_verify(ABObj obj)
|
|
{
|
|
#define safe_data_access(_expr) \
|
|
mem_fault_occurred = FALSE; \
|
|
if (sigsetjmp(sigjmp_env, TRUE) == 0) \
|
|
{ \
|
|
(_expr); \
|
|
} \
|
|
data_access_ok = (!mem_fault_occurred);
|
|
|
|
#define field_err(_fieldName) \
|
|
(return_value = -1, \
|
|
util_dprintf(0, \
|
|
"ERROR: Obj %s, bad value in field: %s\n", \
|
|
obj_name, (_fieldName)))
|
|
|
|
#define check_str(obj, _field) \
|
|
( ((long)(last_field = #_field)), \
|
|
(istr_verify(obj->_field) >= 0)? \
|
|
(0) \
|
|
: \
|
|
(field_err(#_field)))
|
|
|
|
volatile BOOL objIsAccessible = FALSE;
|
|
volatile int return_value = 0;
|
|
volatile char obj_name[1024] = "";
|
|
volatile STRING obj_str_ptr_name = NULL;
|
|
volatile ABObj parent = NULL;
|
|
volatile ABObj next_sibling = NULL;
|
|
volatile ABObj prev_sibling = NULL;
|
|
volatile BOOL ok = FALSE;
|
|
volatile BOOL data_access_ok = TRUE;
|
|
volatile STRING last_field = NULL;
|
|
volatile ABObj tmpObj = NULL;
|
|
volatile StringList namesList = NULL;
|
|
|
|
sig_fault_handler_install();
|
|
|
|
if (obj == NULL)
|
|
{
|
|
return_value = -1;
|
|
goto epilogue;
|
|
}
|
|
|
|
/*
|
|
* See if this object even exists
|
|
*/
|
|
if (!objP_is_accessible(obj))
|
|
{
|
|
objIsAccessible = FALSE;
|
|
return_value = -1;
|
|
util_dprintf(0,
|
|
"ERROR - bad object ptr in obj_verify(): %#lx\n", obj);
|
|
goto epilogue;
|
|
}
|
|
objIsAccessible = TRUE; /* don't forget to set this!! */
|
|
|
|
/*
|
|
* Get the name of the object
|
|
*/
|
|
mem_fault_occurred = FALSE;
|
|
if (sigsetjmp(sigjmp_env, TRUE) == 0)
|
|
{
|
|
obj_str_ptr_name = NULL;
|
|
ok = (istr_verify(obj->name) >= 0);
|
|
if (ok)
|
|
{
|
|
obj_str_ptr_name = istr_string(obj->name);
|
|
sprintf((STRING)obj_name, "(ABObj %#lx", (unsigned long) obj);
|
|
if (obj_str_ptr_name != NULL)
|
|
{
|
|
strcat((STRING)obj_name, " = ");
|
|
strcat((STRING)obj_name, obj_str_ptr_name);
|
|
}
|
|
strcat((STRING)obj_name, ")");
|
|
if (!ok)
|
|
{
|
|
field_err("name");
|
|
}
|
|
} /* ok */
|
|
}
|
|
else
|
|
{
|
|
sprintf((STRING)obj_name, "(ABObj %#lx)", (unsigned long) obj);
|
|
field_err("name");
|
|
}
|
|
|
|
if (obj->impl_flags == ObjFlagAlreadyFreedValue)
|
|
{
|
|
util_dprintf(0, "\n\n");
|
|
util_dprintf(0, "\nDANGER WILL ROBINSON! COSMIC STORM APPROACHES!!!\n");
|
|
util_dprintf(0, "\n");
|
|
sleep(5);
|
|
util_dprintf(0, " (Actually, it's just a reference to a previously destroyed object)\n");
|
|
util_dprintf(0, " (Object is %s)\n", obj_name);
|
|
util_dputs(0, "\n\n");
|
|
return_value = -1;
|
|
}
|
|
|
|
/*
|
|
* next_sibling
|
|
*/
|
|
next_sibling = obj->next_sibling;
|
|
if ((next_sibling != NULL) && (!objP_is_accessible(next_sibling)))
|
|
{
|
|
next_sibling = NULL;
|
|
field_err("next_sibling");
|
|
}
|
|
if (next_sibling != NULL)
|
|
{
|
|
safe_data_access(ok = (next_sibling->prev_sibling == obj));
|
|
if ((!data_access_ok) || (!ok))
|
|
{
|
|
return_value = -1;
|
|
field_err("next_sibling");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* parent
|
|
*/
|
|
prev_sibling = obj->prev_sibling;
|
|
if ((prev_sibling != NULL) && (!objP_is_accessible(prev_sibling)))
|
|
{
|
|
prev_sibling = NULL;
|
|
field_err("prev_sibling");
|
|
}
|
|
if (prev_sibling != NULL)
|
|
{
|
|
safe_data_access(ok = (prev_sibling->next_sibling == obj));
|
|
if ((!data_access_ok) || (!ok))
|
|
{
|
|
return_value = -1;
|
|
field_err("next_sibling");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* parent
|
|
*/
|
|
parent = obj->parent;
|
|
if ((parent != NULL) && (!objP_is_accessible(parent)))
|
|
{
|
|
parent = NULL;
|
|
field_err("parent");
|
|
}
|
|
if (parent != NULL)
|
|
{
|
|
volatile ABObj child;
|
|
volatile BOOL found = FALSE;
|
|
|
|
ok = TRUE;
|
|
safe_data_access(child = parent->first_child);
|
|
if (!data_access_ok)
|
|
{
|
|
field_err("parent");
|
|
}
|
|
else
|
|
{
|
|
while ((!found) && (child != NULL))
|
|
{
|
|
if (child == obj)
|
|
{
|
|
found = TRUE;
|
|
}
|
|
safe_data_access(child = child->next_sibling);
|
|
if (!data_access_ok)
|
|
{
|
|
field_err("parent");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
return_value = -1;
|
|
field_err("parent");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* first_child
|
|
*/
|
|
|
|
/*
|
|
* Still should check: first_child, part_of
|
|
*/
|
|
|
|
/*
|
|
* Check all the ISTRING fields
|
|
*/
|
|
|
|
/* we shouldn't mem fault here, but we're going to prepare, */
|
|
/* just in case */
|
|
mem_fault_occurred = FALSE;
|
|
if (sigsetjmp(sigjmp_env, TRUE) != 0)
|
|
{
|
|
return_value = -1;
|
|
if (last_field != NULL)
|
|
{
|
|
field_err(last_field);
|
|
}
|
|
goto epilogue;
|
|
}
|
|
check_str(obj,user_data);
|
|
check_str(obj,help_volume);
|
|
check_str(obj,help_location);
|
|
check_str(obj,help_text);
|
|
check_str(obj,bg_color);
|
|
check_str(obj,fg_color);
|
|
check_str(obj,label);
|
|
check_str(obj,menu_name);
|
|
check_str(obj,class_name);
|
|
|
|
/*
|
|
* Check type-specific info
|
|
*/
|
|
switch (obj->type)
|
|
{
|
|
case AB_TYPE_ACTION:
|
|
switch (obj->info.action.func_type)
|
|
{
|
|
case AB_FUNC_CODE_FRAG:
|
|
check_str(obj,info.action.func_value.code_frag);
|
|
break;
|
|
|
|
case AB_FUNC_USER_DEF:
|
|
check_str(obj,info.action.func_value.func_name);
|
|
break;
|
|
}
|
|
switch (obj->info.action.arg_type)
|
|
{
|
|
case AB_ARG_STRING:
|
|
check_str(obj,info.action.arg_value.sval);
|
|
break;
|
|
}
|
|
check_str(obj,info.action.func_name_suffix);
|
|
break;
|
|
|
|
case AB_TYPE_FILE_CHOOSER:
|
|
check_str(obj,info.file_chooser.filter_pattern);
|
|
check_str(obj,info.file_chooser.ok_label);
|
|
check_str(obj,info.file_chooser.directory);
|
|
break;
|
|
|
|
case AB_TYPE_MESSAGE:
|
|
check_str(obj,info.message.msg_string);
|
|
check_str(obj,info.message.action1_label);
|
|
check_str(obj,info.message.action2_label);
|
|
break;
|
|
|
|
case AB_TYPE_DIALOG:
|
|
case AB_TYPE_BASE_WINDOW:
|
|
{
|
|
check_str(obj,info.window.icon);
|
|
check_str(obj,info.window.icon_label);
|
|
}
|
|
break;
|
|
|
|
case AB_TYPE_TEXT_FIELD:
|
|
case AB_TYPE_TEXT_PANE:
|
|
{
|
|
check_str(obj,info.text.initial_value_string);
|
|
}
|
|
break;
|
|
} /* switch obj->type */
|
|
if (obj->type == AB_TYPE_MODULE)
|
|
{
|
|
check_str(obj,info.module.file);
|
|
check_str(obj,info.module.stubs_file);
|
|
check_str(obj,info.module.ui_file);
|
|
}
|
|
if (obj->type == AB_TYPE_ITEM)
|
|
{
|
|
check_str(obj,info.item.accelerator);
|
|
}
|
|
if (obj->type == AB_TYPE_PROJECT)
|
|
{
|
|
check_str(obj,info.project.file);
|
|
check_str(obj,info.project.stubs_file);
|
|
}
|
|
if (obj->type == AB_TYPE_TERM_PANE)
|
|
{
|
|
check_str(obj,info.term.process_string);
|
|
}
|
|
|
|
|
|
/*
|
|
* Check names index (we know the strings are valid, now)
|
|
* project name doesn't go in an index
|
|
*/
|
|
if ((obj->type != AB_TYPE_PROJECT) && (obj->name != NULL))
|
|
{
|
|
namesList = NULL;
|
|
for (parent = obj->parent; parent != NULL; parent = parent->parent)
|
|
{
|
|
if ( (parent->type == AB_TYPE_MODULE)
|
|
|| (parent->type == AB_TYPE_PROJECT) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (parent != NULL)
|
|
{
|
|
switch (parent->type)
|
|
{
|
|
case AB_TYPE_MODULE:
|
|
namesList = parent->info.module.obj_names_list;
|
|
break;
|
|
case AB_TYPE_PROJECT:
|
|
namesList = parent->info.project.obj_names_list;
|
|
break;
|
|
}
|
|
|
|
if (namesList == NULL)
|
|
{
|
|
util_dprintf(1,
|
|
"No names index found containing %s\n", obj_name);
|
|
return_value = -1;
|
|
goto epilogue;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* A destroyed object must *not* be in the index,
|
|
* but any other object *must* be in the index.
|
|
*/
|
|
tmpObj = (ABObj)strlist_get_istr_data(namesList, obj->name);
|
|
if (obj_has_impl_flags(obj, ObjFlagDestroyed))
|
|
{
|
|
if (tmpObj != NULL)
|
|
{
|
|
util_dprintf(1,
|
|
"Destroyed object is in names index: %s\n",
|
|
obj_name);
|
|
return_value = -1;
|
|
goto epilogue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (tmpObj != obj)
|
|
{
|
|
util_dprintf(1, "Object does not exist in index: %s\n",
|
|
obj_name);
|
|
return_value = -1;
|
|
goto epilogue;
|
|
}
|
|
}
|
|
}
|
|
} /* parent != NULL */
|
|
} /* obj->name != NULL */
|
|
|
|
epilogue:
|
|
#ifdef DEBUG
|
|
if (objIsAccessible)
|
|
{
|
|
obj->debug_last_verify_time = time(NULL); /*only exists in debug build*/
|
|
}
|
|
#endif /* DEBUG */
|
|
sig_fault_handler_uninstall();
|
|
return return_value;
|
|
#undef check_str
|
|
#undef field_err
|
|
#undef safe_data_access
|
|
}
|
|
|
|
|
|
/*
|
|
* Returns whether or not we can actually examine this object without
|
|
* causing a memory fault
|
|
*
|
|
* Assumes: memory fault handler is installed
|
|
* Modifies: sigjmp_env global var
|
|
*/
|
|
static BOOL
|
|
objP_is_accessible(ABObj obj)
|
|
{
|
|
volatile BOOL isIt = TRUE;
|
|
volatile unsigned char *volatile objData = (unsigned char *)obj;
|
|
volatile int i;
|
|
volatile unsigned char oneByte = 0;
|
|
|
|
mem_fault_occurred = FALSE;
|
|
if (sigsetjmp(sigjmp_env, TRUE) != 0)
|
|
{
|
|
isIt = FALSE;
|
|
goto epilogue;
|
|
}
|
|
|
|
for (i = 0 ; i < sizeof(*obj); ++i)
|
|
{
|
|
oneByte = objData[i];
|
|
}
|
|
|
|
epilogue:
|
|
return isIt;
|
|
}
|
|
|
|
|
|
static int
|
|
sig_fault_handler_install(void)
|
|
{
|
|
struct sigaction new_action;
|
|
|
|
mem_fault_occurred = FALSE;
|
|
if (sig_fault_handler_installed)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (sigaction(SIGSEGV, NULL, &org_sig_segv_handler) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
new_action = org_sig_segv_handler;
|
|
new_action.sa_handler = sig_fault_handler;
|
|
sigemptyset(&(new_action.sa_mask));
|
|
new_action.sa_flags = 0;
|
|
if (sigaction(SIGSEGV, &new_action, NULL) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
sig_fault_handler_installed = TRUE;
|
|
|
|
#ifdef SIGBUS
|
|
if (sigaction(SIGBUS, NULL, &org_sig_bus_handler) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
new_action = org_sig_bus_handler;
|
|
new_action.sa_handler = sig_fault_handler;
|
|
sigemptyset(&(new_action.sa_mask));
|
|
new_action.sa_flags = 0;
|
|
if (sigaction(SIGBUS, &new_action, NULL) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif /* SIGBUS */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
sig_fault_handler_uninstall(void)
|
|
{
|
|
mem_fault_occurred = FALSE;
|
|
if (!sig_fault_handler_installed)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (sigaction(SIGSEGV, &org_sig_segv_handler, NULL) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
sig_fault_handler_installed = FALSE;
|
|
|
|
#ifdef SIGBUS
|
|
if (sigaction(SIGBUS, &org_sig_bus_handler, NULL) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif /* SIGBUS */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
sig_fault_handler()
|
|
{
|
|
if (mem_fault_occurred)
|
|
{
|
|
/* We should have cleared this to prepare for a mem fault */
|
|
/* If not, then something has gone haywire */
|
|
static STRING msg = NULL;
|
|
msg = "MEMORY ACCESS VIOLATION OCCURED. ABORTING.\n";
|
|
write(2, msg, strlen(msg));
|
|
abort();
|
|
}
|
|
mem_fault_occurred = TRUE;
|
|
siglongjmp(sigjmp_env, 1);
|
|
}
|
|
|
|
|
|
int
|
|
obj_tree_verify(ABObj root)
|
|
{
|
|
int return_value = 0;
|
|
int rc = 0; /* return code */
|
|
ABObj *objArray = NULL;
|
|
int objArraySize = 0;
|
|
ABObj module = NULL;
|
|
AB_TRAVERSAL moduleTrav;
|
|
int i = 0;
|
|
|
|
if (root == NULL)
|
|
{
|
|
/* empty tree is valid (I guess) */
|
|
return 0;
|
|
}
|
|
|
|
rc = build_obj_array(&objArray, &objArraySize, root);
|
|
if (rc < 0)
|
|
{
|
|
return_value = rc;
|
|
goto epilogue;
|
|
}
|
|
|
|
for (i = 0; i < objArraySize; ++i)
|
|
{
|
|
rc = obj_verify(objArray[i]);
|
|
if (rc < 0)
|
|
{
|
|
return_value = rc;
|
|
goto epilogue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check the project names list
|
|
*/
|
|
if (obj_is_project(root))
|
|
{
|
|
rc = verify_the_silly_index(root, objArray, objArraySize);
|
|
if (rc < 0)
|
|
{
|
|
return_value = rc;
|
|
goto epilogue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* check the modules' name lists
|
|
*/
|
|
for (trav_open(&moduleTrav, root, AB_TRAV_MODULES);
|
|
(module = trav_next(&moduleTrav)) != NULL; )
|
|
{
|
|
rc = verify_the_silly_index(module, objArray, objArraySize);
|
|
if (rc < 0)
|
|
{
|
|
return_value = rc;
|
|
break;
|
|
}
|
|
}
|
|
trav_close(&moduleTrav);
|
|
|
|
epilogue:
|
|
util_free(objArray);
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static int
|
|
verify_the_silly_index(
|
|
ABObj nameScopeObj,
|
|
ABObj *objArray,
|
|
int objArraySize
|
|
)
|
|
{
|
|
int return_value = 0;
|
|
StringList names = NULL;
|
|
int numNames = 0;
|
|
int nameCount = 0;
|
|
int objCount = 0;
|
|
ABObj namedObj = NULL;
|
|
ABObj namesObj = NULL;
|
|
ISTRING curName = NULL;
|
|
ABObj curObj = NULL;
|
|
ABObj curScopeObj = NULL;
|
|
StringList curNames = NULL;
|
|
BOOL namedObjFound = FALSE;
|
|
char nameBuf1[1024];
|
|
char nameBuf2[1024];
|
|
char nameBuf3[1024];
|
|
*nameBuf1 = 0;
|
|
*nameBuf2 = 0;
|
|
*nameBuf3 = 0;
|
|
|
|
|
|
names = objP_get_names_list(nameScopeObj);
|
|
if (names == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
numNames = strlist_get_num_strs(names);
|
|
|
|
for (nameCount = 0; nameCount < numNames; ++nameCount)
|
|
{
|
|
namedObjFound = FALSE;
|
|
curName = strlist_get_istr(names, nameCount, (void **)&namedObj);
|
|
for (objCount = 0;
|
|
(!namedObjFound) && (objCount < objArraySize); ++objCount)
|
|
{
|
|
/*
|
|
* See if we've found the object
|
|
*/
|
|
curObj = objArray[objCount];
|
|
if ((curObj != namedObj) || obj_is_project(curObj))
|
|
{
|
|
/* projects don't go in list, anywhere */
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* We've found the object that goes with this name. Check
|
|
* to see if it is in the right scope.
|
|
*/
|
|
curNames = NULL;
|
|
curScopeObj = objP_get_names_scope_obj(curObj);
|
|
if (curScopeObj != NULL)
|
|
{
|
|
curNames = objP_get_names_list(curScopeObj);
|
|
}
|
|
if (curNames == NULL)
|
|
{
|
|
util_dprintf(1,
|
|
"No names list found for object %s in module %s!\n",
|
|
obj_get_safe_name(curObj, nameBuf1, 1024),
|
|
obj_get_safe_name(obj_get_module(curObj), nameBuf2, 1024));
|
|
return_value = ERR_INTERNAL;
|
|
goto epilogue;
|
|
}
|
|
else if (curNames != names)
|
|
{
|
|
util_dprintf(1,
|
|
"Object %s should be in scope for %s, but is in scope for %s\n",
|
|
obj_get_safe_name(curObj, nameBuf1, 1024),
|
|
obj_get_safe_name(curScopeObj, nameBuf2, 1024),
|
|
obj_get_safe_name(nameScopeObj, nameBuf3, 1024));
|
|
return_value = ERR_INTERNAL;
|
|
goto epilogue;
|
|
}
|
|
else if (!istr_equal(curName, curObj->name))
|
|
{
|
|
util_dprintf(1,
|
|
"Object %s has incorrect reference in index!\n",
|
|
obj_get_safe_name(curObj, nameBuf1, 1024));
|
|
}
|
|
else
|
|
{
|
|
namedObjFound = TRUE;
|
|
}
|
|
} /* for objCount */
|
|
|
|
if (!namedObjFound)
|
|
{
|
|
#ifdef DEBUG
|
|
util_dprintf(1,
|
|
"Name is in index '%s', but no such object exists!\n",
|
|
istr_string_safe(curName));
|
|
#endif /* DEBUG */
|
|
return_value = ERR_INTERNAL;
|
|
goto epilogue;
|
|
}
|
|
} /* for nameCount */
|
|
|
|
epilogue:
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static int
|
|
build_obj_array(ABObj **objArrayPtr, int *objArraySizePtr, ABObj root)
|
|
{
|
|
#define objArray (*objArrayPtr)
|
|
#define objArraySize (*objArraySizePtr)
|
|
int rc = 0; /* return code */
|
|
ABObj *newObjArray = NULL;
|
|
ABObj child = NULL;
|
|
|
|
/*
|
|
* If this object is already in the list, we've detected some sort
|
|
* of cycle.
|
|
*/
|
|
{
|
|
int i = 0;
|
|
char name[1024];
|
|
*name = 0;
|
|
for (i = 0; i < objArraySize; ++i)
|
|
{
|
|
if (objArray[i] == root)
|
|
{
|
|
util_dprintf(1,
|
|
"INTERNAL ERROR: some sort of cycle detected involving %s\n",
|
|
obj_get_safe_name(root, name, 1024));
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add root obj to list
|
|
*/
|
|
++objArraySize;
|
|
newObjArray = (ABObj*)realloc(objArray, objArraySize*sizeof(ABObj*));
|
|
if (newObjArray == NULL)
|
|
{
|
|
util_dprintf(1, "Out of memory in build_obj_array\n");
|
|
return ERR_NO_MEMORY;
|
|
}
|
|
objArray = newObjArray;
|
|
objArray[objArraySize-1] = root;
|
|
|
|
/*
|
|
* Add the children to the list
|
|
*/
|
|
for (child = root->first_child; child != NULL; child = child->next_sibling)
|
|
{
|
|
if ((rc = build_obj_array(&objArray, &objArraySize, child)) < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
#undef objArrayPtr
|
|
#undef objArray
|
|
}
|
|
|
|
ABObj
|
|
obj_get_parent_of_type(ABObj obj, AB_OBJECT_TYPE type)
|
|
{
|
|
ABObj ancestor = obj->parent;
|
|
while ((ancestor != NULL) && (obj_get_type(ancestor) != type))
|
|
{
|
|
ancestor = ancestor->parent;
|
|
}
|
|
return ancestor;
|
|
}
|