Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / libABobj / obj_utils.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23
24 /*
25  * $XConsortium: obj_utils.c /main/4 1996/10/02 15:44:56 drk $
26  * 
27  *      @(#)obj_utils.c 3.137 01 Feb 1995
28  * 
29  * RESTRICTED CONFIDENTIAL INFORMATION:
30  * 
31  * The information in this document is subject to special restrictions in a
32  * confidential disclosure agreement between HP, IBM, Sun, USL, SCO and
33  * Univel.  Do not distribute this document outside HP, IBM, Sun, USL, SCO,
34  * or Univel without Sun's specific written approval.  This document and all
35  * copies and derivative works thereof must be returned or destroyed at Sun's
36  * request.
37  * 
38  * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
39  * 
40  */
41
42
43 /*
44  * utils.c - general utilities
45  */
46 #include <ctype.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/param.h>
50 #include <sys/times.h>
51 #include <signal.h>
52 #include <setjmp.h>
53 #include <time.h>
54 #include "objP.h"               /* put objP.h first! */
55 #include <ab_private/trav.h>
56 #include <ab_private/util.h>
57 #include <ab/util_types.h>
58 #include <ab_private/istr.h>
59 #include "obj_utils.h"
60 #include "obj_names_listP.h"
61
62 #define AB_TYPE_MODULE  AB_TYPE_MODULE  /* REMIND: can be taken out later */
63
64 /*
65  * Global variables...
66  */
67 char               *abo_empty_string = "";
68 char               *abo_null_string = "(nil)";
69
70 static struct sigaction org_sig_segv_handler;
71 #ifdef SIGBUS
72 static struct sigaction org_sig_bus_handler;
73 #endif
74 static sigjmp_buf       sigjmp_env;
75
76 static volatile BOOL    sig_fault_handler_installed = FALSE;
77 static volatile BOOL    mem_fault_occurred = FALSE;
78 static int      sig_fault_handler_install(void);
79 static int      sig_fault_handler_uninstall(void);
80 static void     sig_fault_handler();
81 static BOOL     objP_is_accessible(ABObj obj);
82 static int      build_obj_array(
83                         ABObj **objArrayInOut, 
84                         int *objArraySizeInOut, 
85                         ABObj root
86                 );
87 static int      verify_the_silly_index(
88                         ABObj           nameScopeObj,
89                         ABObj           *objArray, 
90                         int             objArraySize
91                 );
92
93
94 /*************************************************************************
95 **                                                                      **
96 **              General (non-object) utilities                          **
97 **                                                                      **
98 *************************************************************************/
99
100 AB_OBJECT_TYPE
101 ab_get_proper_subobj_type(AB_OBJECT_TYPE type)
102 {
103     AB_OBJECT_TYPE      subtype = AB_TYPE_UNKNOWN;
104
105     switch (type)
106     {
107     case AB_TYPE_PROJECT:
108         subtype = AB_TYPE_MODULE;
109         break;
110
111     case AB_TYPE_CHOICE:
112     case AB_TYPE_LIST:
113     case AB_TYPE_MENU:
114         subtype = AB_TYPE_ITEM;
115         break;
116     }
117
118     return subtype;
119 }
120
121
122 /*
123  * Returns the item type this object should contain.  If the object is an
124  * item, it returns the type of the item.
125  */
126 AB_ITEM_TYPE
127 ab_get_proper_item_type(AB_OBJECT_TYPE type)
128 {
129     AB_ITEM_TYPE        item_type = AB_ITEM_FOR_UNDEF;
130
131     switch (type)
132     {
133     case AB_TYPE_MENU:
134         item_type = AB_ITEM_FOR_MENU;
135         break;
136
137     case AB_TYPE_CHOICE:
138         item_type = AB_ITEM_FOR_CHOICE;
139         break;
140
141     case AB_TYPE_LIST:
142         item_type = AB_ITEM_FOR_LIST;
143         break;
144     }
145
146     return item_type;
147 }
148
149
150 int
151 ab_string_list_count(STRING * list)
152 {
153     int                 i = 0;
154     if (list != NULL)
155     {
156         while (list[i] != NULL)
157         {
158             ++i;
159         }
160     }
161     return i;
162 }
163
164
165 AB_FILE_TYPE
166 ab_file_type_from_path(STRING path)
167 {
168     AB_FILE_TYPE        file_type = AB_FILE_UNDEF;
169     int                 pathlen = strlen(path);
170
171     if (pathlen >= 3)
172     {
173         char               *ext = &(path[pathlen - 2]);
174         if (strcmp(ext, ".P") == 0)
175         {
176             file_type = AB_FILE_GIL_PROJECT;
177         }
178         else if (strcmp(ext, ".G") == 0)
179         {
180             file_type = AB_FILE_GIL_INTERFACE;
181         }
182     }
183
184     return file_type;
185 }
186
187
188 /*
189  * Only ensures that the identifier has no white space in it.
190  */
191 BOOL
192 ab_ident_is_ok(STRING ident)
193 {
194     char               *cp;
195     if (ident == NULL)
196     {
197         return FALSE;
198     }
199     for (cp = ident; *cp != NULL; ++cp)
200     {
201         if (isspace(*cp))
202         {
203             return FALSE;
204         }
205     }
206     return TRUE;
207 }
208
209
210 BOOL
211 ab_c_ident_is_ok(STRING ident)
212 {
213     int                 i;
214     int                 len = 0;
215     char                ch;
216
217     if (ident == NULL)
218     {
219         return TRUE;
220     }
221     for (i = 0, len = strlen(ident); i < len; ++i)
222     {
223         ch = ident[i];
224
225         /* The first character of a variable name must be a letter.
226          * The underscore character is considered a letter in C. 
227          */
228         if (i == 0)
229         {
230             if (!(isalpha(ch)) && (ch != '_'))
231                 return FALSE;
232         }
233         else
234         {
235             if (!((isalnum(ch) || (ch == '_'))))
236                 return FALSE;
237         }
238     }
239
240     return TRUE;
241 }
242
243
244 /*************************************************************************
245 **                                                                      **
246 **              Object utilities                                        **
247 **                                                                      **
248 *************************************************************************/
249
250 STRING
251 obj_get_file(ABObj obj)
252 {
253     if (obj->type == AB_TYPE_FILE)
254     {
255         return obj_get_name(obj);       /* stored as name */
256     }
257     while ((obj != NULL) && (obj->type != AB_TYPE_MODULE)
258            && (obj->type != AB_TYPE_PROJECT))
259     {
260         obj = obj->parent;
261     }
262     if (obj != NULL)
263     {
264         if (obj->type == AB_TYPE_MODULE)
265         {
266             return istr_string(obj->info.module.file);
267         }
268         else if (obj->type == AB_TYPE_PROJECT)
269         {
270             return istr_string(obj->info.project.file);
271         }
272     }
273     return NULL;
274 }
275
276 /*
277  * Gets the project the object belongs to
278  */
279 ABObj
280 obj_get_project(ABObj obj)
281 {
282     while ((obj != NULL) && (obj->type != AB_TYPE_PROJECT))
283     {
284         obj = obj->parent;
285     }
286     return obj;
287 }
288
289 /*
290  * Gets the module the object belongs to
291  */
292 ABObj
293 obj_get_module(ABObj obj)
294 {
295     while ((obj != NULL) && (obj->type != AB_TYPE_MODULE))
296     {
297         obj = obj->parent;
298     }
299     return obj;
300 }
301
302 /*
303  * Gets the window the object belongs to
304  */
305 ABObj
306 obj_get_window(ABObj obj)
307 {
308     while ((obj != NULL) && !obj_is_window(obj))
309     {
310         obj = obj->parent;
311     }
312     return obj;
313 }
314
315 int
316 obj_get_num_items(ABObj obj)
317 {
318     return trav_count(obj, AB_TRAV_ITEMS_FOR_OBJ);
319 }
320
321 /*
322  * Counts the given object! (i.e., always returns at least 1).
323  */
324 int
325 obj_get_num_siblings(ABObj obj)
326 {
327     AB_TRAVERSAL        trav;
328     int                 num_sibs = 0;
329     for (trav_open(&trav, obj, AB_TRAV_SIBLINGS);
330          (obj = trav_next(&trav)) != NULL;)
331     {
332         ++num_sibs;
333     }
334     return num_sibs;
335 }
336
337 /*
338  * Makes sure the object has at least the specified number of children.
339  * 
340  * Any new children created are appended to the child list, and they are of the
341  * type returned from abo_proper_item_type.
342  */
343 int
344 obj_ensure_num_children(ABObj obj, int requested_num_children)
345 {
346     AB_OBJECT_TYPE      child_type = ab_get_proper_subobj_type(obj->type);
347     AB_ITEM_TYPE        child_item_type = ab_get_proper_item_type(obj->type);
348     int                 num_children = obj_get_num_children(obj);
349     ABObj               child = NULL;
350
351     while (num_children < requested_num_children)
352     {
353         child = obj_create(child_type, NULL);
354         if (child == NULL)
355         {
356             return -1;
357         }
358         if (obj_is_item(child))
359         {
360             child->info.item.type = child_item_type;
361         }
362         obj_append_child(obj, child);
363         ++num_children;
364     }
365     return 0;
366 }
367
368
369 ABObj
370 obj_find_child_by_label(ABObj root, STRING label)
371 {
372     ABObj               child;
373
374     for (child = root->first_child;
375          child != NULL; child = child->next_sibling)
376     {
377         if (istr_equalstr(child->label, label))
378         {
379             break;
380         }
381     }
382     return child;
383 }
384
385
386 ABObj
387 obj_find_child_by_type(ABObj obj, AB_OBJECT_TYPE childType)
388 {
389     ABObj       child;
390     for (child = obj->first_child; 
391         (child != NULL); child = child->next_sibling)
392     {
393         if (child->type == childType)
394         {
395             break;
396         }
397     }
398
399     return child;
400 }
401
402
403 ABObj
404 obj_find_by_name(ABObj root, STRING name)
405 {
406     StringList          names = objP_get_names_scope_for_children(root);
407     ISTRING             istr_name = istr_dup_existing(name);
408     AB_TRAVERSAL        trav;
409     ABObj               obj = NULL;
410
411     if ((name == NULL) || (istr_name == NULL))
412     {
413         return NULL;
414     }
415
416     if (names != NULL)
417     {
418         obj = (ABObj)strlist_get_istr_data(names, istr_name);
419     }
420     else
421     {
422         for (trav_open(&trav, root, AB_TRAV_ALL);
423              (obj = trav_next(&trav)) != NULL;)
424         {
425             if (!(obj_is_project(obj) || obj_is_module(obj)))
426             {
427                 if (istr_equal(obj->name, istr_name))
428                     break;
429             }
430         }
431     }
432
433     istr_destroy(istr_name);
434     return obj;
435 }
436
437 ABObj
438 obj_find_by_name_and_type(ABObj root, STRING name, AB_OBJECT_TYPE type)
439 {
440     ABObj               obj;
441     AB_TRAVERSAL        trav;
442
443     if (name == NULL)
444     {
445         return NULL;
446     }
447     for (trav_open(&trav, root, AB_TRAV_ALL);
448          (obj = trav_next(&trav)) != NULL;)
449     {
450         if ((obj->type == type)
451             && (istr_equalstr(obj->name, name)))
452         {
453             break;
454         }
455     }
456     trav_close(&trav);
457     return obj;
458 }
459
460
461 ABObj
462 obj_find_by_type(ABObj root, AB_OBJECT_TYPE type)
463 {
464     AB_TRAVERSAL        trav;
465     ABObj               obj = NULL;
466
467     for (trav_open(&trav, root, AB_TRAV_UI | AB_TRAV_MOD_PARENTS_FIRST);
468          (obj = trav_next(&trav)) != NULL;)
469     {
470         if (obj->type == type)
471         {
472             break;
473         }
474     }
475     trav_close(&trav);
476
477     return NULL;
478 }
479
480
481 ABObj
482 obj_find_child_by_name(ABObj obj, STRING name)
483 {
484     ABObj               child;
485     if (name == NULL)
486     {
487         return NULL;
488     }
489     for (child = obj->first_child;
490          child != NULL; child = child->next_sibling)
491     {
492         if (istr_equalstr(child->name, name))
493         {
494             return child;
495         }
496     }
497     return NULL;
498 }
499
500
501 ABObj
502 obj_find_menu_by_name(ABObj root, STRING name)
503 {
504     return obj_find_by_name_and_type(root, name, AB_TYPE_MENU);
505 }
506
507
508 ABObj
509 obj_find_module_by_name(ABObj root, STRING name)
510 {
511     AB_TRAVERSAL        trav;
512     ABObj               module = NULL;
513
514     for (trav_open(&trav, root, AB_TRAV_MODULES);
515          (module = trav_next(&trav)) != NULL;)
516     {
517         if (util_streq(obj_get_name(module), name))
518         {
519             break;
520         }
521     }
522     trav_close(&trav);
523
524     return module;
525 }
526
527
528 ABObj
529 obj_scoped_find_or_create_undef(ABObj parent,
530                                 STRING scopedName, AB_OBJECT_TYPE objType)
531 {
532     ABObj               obj = obj_scoped_find_by_name(parent, scopedName);
533
534     if (obj == NULL)
535     {
536         STRING              moduleName = obj_scoped_name_get_module_name(
537                                                                 scopedName);
538         STRING              objName = obj_scoped_name_get_obj_name(
539                                                                 scopedName);
540         ABObj               project = NULL;
541         ABObj               module = NULL;
542
543         if (moduleName == NULL)
544         {
545             /* simple name - create as child of the "parent" object */
546             obj = obj_create(objType, parent);
547         }
548         else
549         {
550             /* complex name - find module to create under */
551             project = obj_get_project(parent);
552             if (project != NULL)
553             {
554                 module = obj_find_module_by_name(project, moduleName);
555                 if (module == NULL)
556                 {
557                     /* damn! module don't exist!! */
558                     module = obj_create(AB_TYPE_MODULE, project);
559                     obj_set_is_defined(module, FALSE);
560                     obj_set_name(module, moduleName);
561                 }
562             }
563             if (module != NULL)
564             {
565                 /* actually create the object under the correct module */
566                 obj = obj_create(objType, module);
567             }
568         }
569
570         /*
571          * We've (hopefully) created a new object (or more correctly, a
572          * reference to an undefined object). Set the attributes that we know
573          * about the object
574          */
575         if (obj != NULL)
576         {
577             obj_set_is_defined(obj, FALSE);
578             obj_set_name(obj, objName);
579         }
580     }                           /* obj == NULL */
581
582     return obj;
583 }
584
585
586 /*************************************************************************
587 **                                                                      **
588 **              Functions private to libgobj                            **
589 **                                                                      **
590 **************************************************************************/
591
592 int
593 abo_error(STRING message)
594 {
595     util_printf_err("%s\n", message);
596     return 0;
597 }
598
599 static int
600 indent(int spaces)
601 {
602     int                 i;
603     for (i = 0; i < spaces; ++i)
604     {
605         util_dputs(0, " ");
606     }
607     return 0;
608 }
609
610 /*
611  * Returns TRUE if the object is the target of a project connection (i.e. one
612  * that is written into the project .c file, and not into a module.  Formerly
613  * known as cross-module connections).
614  */
615 BOOL
616 obj_is_project_action_target(ABObj obj)
617 {
618     ABObj               project = NULL;
619     BOOL                is_project_target = FALSE;
620     ABObj               action = NULL;
621     AB_TRAVERSAL        trav;
622
623     project = obj_get_project(obj);
624     for (trav_open(&trav, project, AB_TRAV_ACTIONS_FOR_OBJ);
625          (action = trav_next(&trav)) != NULL;)
626     {
627         if (action->info.action.to == obj)
628         {
629             is_project_target = TRUE;
630             break;
631         }
632     }
633     trav_close(&trav);
634     return is_project_target;
635 }
636
637
638 /*
639  * Return a valid C name given a string (normally, a label)
640  */
641 STRING
642 ab_make_valid_c_ident(STRING label)
643 {
644     static char         name[MAXPATHLEN];
645     static int          ith = 0;
646     int                 lastchar = -1;
647     register char      *oldPtr = label;
648     register char      *newPtr = name;
649
650     if (isdigit(*oldPtr))
651     {
652
653         /*
654          * If the label starts with a number, prepend 'dtb'
655          */
656         *newPtr++ = 'd';
657         *newPtr++ = 't';
658         *newPtr++ = 'b';
659         lastchar = *(newPtr-1);
660     }
661
662     while ((*oldPtr) != '\0')
663     {
664         if (isalnum(*oldPtr))
665         {
666             lastchar = *newPtr++ = *oldPtr++;
667         }
668         else if (isprint(*oldPtr) && (lastchar != '_'))
669         {
670             /* turn illegal printable chars into _ (e.g. / .) */
671             lastchar = *newPtr++ = '_';
672             oldPtr++;
673         }
674         else
675         {
676             /*
677              * Skip the illegal character.
678              */
679             oldPtr++;
680         }
681     }
682
683     /*
684      * Strip off trailing underscore (there will be no more than one).
685      */
686     if (lastchar == '_')
687     {
688         --newPtr;
689     }
690     *newPtr = 0;        /* terminate the string */
691
692     if (newPtr == name)
693     {
694
695         /*
696          * The entire label is composed of illegal characters, in that case,
697          * return a generated name.
698          */
699         sprintf(name, "dtb_name_%d", ith++);
700     }
701
702     return name;
703 }
704
705
706 /*
707  * Given a unix file name, strip off the path and the suffix.
708  */
709 STRING
710 ab_ident_from_file_name(STRING filename)
711 {
712     static char         buf[MAXPATHLEN];
713     char               *p;
714
715     if (filename != NULL)
716     {
717         if (p = (char *) strrchr(filename, '/'))
718             strcpy(buf, p + 1);
719         else
720             strcpy(buf, filename);
721
722         if (p = (char *) strrchr(buf, '.'))
723             *p = '\0';
724     }
725     return buf;
726 }
727
728
729 /*
730  * Assumes: name, label not NULL.
731  */
732 STRING
733 ab_ident_from_name_and_label(STRING name, STRING label)
734 {
735     static char         new_name[256];
736     sprintf(new_name, "%s_%s", name, label);
737     return ab_make_valid_c_ident(new_name);
738 }
739
740
741 /*
742  * Gets the module and object name from a complex name (i.e., a name of the
743  * form module.name or module::name
744  */
745 int
746 obj_scoped_name_split(
747                       STRING complex_name,
748                       STRING module_name_buf,
749                       int module_name_buf_size,
750                       STRING obj_name_buf,
751                       int obj_name_buf_size
752 )
753 {
754     int                 return_value = 0;
755     char               *dot_ptr = NULL;
756     char               *module_name_ptr = NULL;
757     char               *obj_name_ptr = complex_name;
758     char               *module_name_end_ptr = NULL;
759     int                 moduleNameEndChar = -1;
760
761     if ((dot_ptr = strchr(complex_name, '.')) != NULL)
762     {
763         module_name_ptr = complex_name;
764         obj_name_ptr = dot_ptr + 1;
765     }
766     else if ((dot_ptr = strstr(complex_name, "::")) != NULL)
767     {
768         module_name_ptr = complex_name;
769         obj_name_ptr = dot_ptr + 2;
770     }
771
772     /*
773      * Remove white space on either side of the separator
774      */
775     if (dot_ptr != NULL)
776     {
777         /* put a 0 at the end of the module name */
778         for (module_name_end_ptr = dot_ptr - 1;
779              ((module_name_end_ptr > complex_name)
780               && isspace(*module_name_end_ptr));)
781         {
782             --module_name_end_ptr;
783         }
784         if (module_name_end_ptr < dot_ptr)
785         {
786             ++module_name_end_ptr;      /* point one *after* last char in
787                                          * name */
788         }
789         moduleNameEndChar = *module_name_end_ptr;
790         *module_name_end_ptr = 0;
791     }
792     while (((*obj_name_ptr) != NULL) && (isspace(*obj_name_ptr)))
793     {
794         ++obj_name_ptr;
795     }
796
797     /*
798      * We now now the substrings' locations. grab them
799      */
800     if (module_name_buf != NULL)
801     {
802         if (module_name_ptr == NULL)
803         {
804             /* no module name! */
805             *module_name_buf = 0;
806         }
807         else
808         {
809             strncpy(module_name_buf, complex_name, module_name_buf_size);
810             module_name_buf[module_name_buf_size - 1] = 0;
811         }
812     }
813     if (obj_name_buf != NULL)
814     {
815         strncpy(obj_name_buf, obj_name_ptr, obj_name_buf_size);
816         obj_name_buf[obj_name_buf_size - 1] = 0;
817     }
818
819 /* epilogue: */
820     /* replace the 0 we inserted with the char that was there */
821     if (module_name_end_ptr != NULL)
822     {
823         *module_name_end_ptr = moduleNameEndChar;
824     }
825     return return_value;
826 }
827
828
829 /*
830  * Gets the module name from the given object name, if there is one (i.e, the
831  * name is of the for module::name or module.name).
832  */
833 STRING
834 obj_scoped_name_get_module_name(STRING complexName)
835 {
836     static char         module_name[256] = "";
837     int                 rc;
838     rc = obj_scoped_name_split(complexName, module_name, 256, NULL, 0);
839     if ((rc < 0) || (*module_name == 0))
840     {
841         return NULL;
842     }
843     return module_name;
844 }
845
846
847 /*
848  * Gets the simple object name from the complex name (a name of the form
849  * module::name or module.name).
850  */
851 STRING
852 obj_scoped_name_get_obj_name(STRING complexName)
853 {
854     static char         simple_name[256] = "";
855     int                 rc;
856     rc = obj_scoped_name_split(complexName, NULL, 0, simple_name, 256);
857     if ((rc < 0) || (*simple_name == 0))
858     {
859         return NULL;
860     }
861     return simple_name;
862 }
863
864
865 /*************************************************************************
866 **                                                                      **
867 **              Debugging functions                                     **
868 **                                                                      **
869 **************************************************************************/
870
871 static int
872 obj_tree_print_indented(ABObj obj,
873                         int spaces, int verbosity);
874 static int          indent(int spaces);
875
876 int
877 obj_print(ABObj obj)
878 {
879     int                 spaces = 0;
880     int                 verbosity = util_get_verbosity();
881     return obj_print_indented(obj, spaces, verbosity);
882 }
883
884 int
885 obj_print_indented(ABObj obj, int spaces, int verbosity)
886 {
887 #define print_flag(flag, flag_str) \
888         (obj_has_flag(obj, flag)? \
889             util_dprintf(0, " %s", flag_str) \
890         : \
891             0)
892
893     char                namebuf[256];
894
895     *namebuf = 0;
896     if (obj == NULL)
897     {
898         util_dprintf(0, "NULL Object\n");
899         return 0;
900     }
901     if (obj_is_action(obj))
902     {
903         switch (obj->info.action.func_type)
904         {
905         case AB_FUNC_USER_DEF:
906             sprintf(namebuf, "func:%s",
907                     istr_string_safe(obj->info.action.func_value.func_name));
908             break;
909
910         case AB_FUNC_BUILTIN:   /* builtin */
911             sprintf(namebuf, "builtin:%s",
912                     util_builtin_action_to_string(
913                                       obj->info.action.func_value.builtin));
914             break;
915         }
916     }
917     else
918     {
919         sprintf(namebuf, "name:'%s'", istr_string_safe(obj->name));
920     }
921     indent(spaces);
922     if ((obj != NULL) && (obj_has_impl_flags(obj, ObjFlagDestroyed)))
923     {
924         util_dprintf(1, "**DESTROYED** ");
925     }
926     if ((obj != NULL) && (!obj_is_defined(obj)))
927     {
928         util_dprintf(0, "**UNDEF** ");
929     }
930     util_dprintf(0, "0x%08lx: %s  type:%s\n",
931                  obj, namebuf,
932                  util_object_type_to_string(obj->type));
933     if (verbosity >= 4)
934     {
935         indent(spaces);
936         util_dprintf(1, "file: '%s'\n", util_strsafe(obj_get_file(obj)));
937         if (obj->flags != NoFlags)
938         {
939             indent(spaces);
940             util_dprintf(0, "flags:");
941             print_flag(NoCodeGenFlag, "NoCodeGen");
942             print_flag(XmConfiguredFlag, "XmConfiged");
943             print_flag(XmCfgForCodeFlag, "CfgForCode");
944             print_flag(XmCfgForBuildFlag, "CfgForBuild");
945             print_flag(InstantiatedFlag, "Instantiated");
946             print_flag(BuildActionsFlag, "BuildActions");
947             print_flag(MappedFlag, "Mapped");
948             print_flag(AttrChangedFlag, "AttrChanged");
949             print_flag(SaveNeededFlag, "SaveNeeded");
950             print_flag(BeingDestroyedFlag, "BeingDestroyed");
951             util_dprintf(0, "\n");
952         }
953         if (obj_is_action(obj))
954         {
955             ABObj               thisModule = NULL;
956             ABObj               thatModule = NULL;
957             ABObj               thatObj = NULL;
958             AB_WHEN             when = AB_WHEN_UNDEF;
959
960             if (obj != NULL)
961             {
962                 thisModule = obj_get_module(obj);
963             }
964
965             /*
966              * To value
967              */
968             thatObj = obj->info.action.to;
969             if (thatObj != NULL)
970             {
971                 thatModule = obj_get_module(thatObj);
972             }
973             indent(spaces);
974             util_dprintf(0, "to: ");
975             if ((thatModule != NULL) && (thatModule != thisModule))
976             {
977                 util_dprintf(0, "%s.", obj_get_safe_name(thatModule, namebuf, 256));
978             }
979             util_dprintf(0, "(%#08lx)%s\n",
980                          thatObj, obj_get_safe_name(thatObj, namebuf, 256));
981
982             /*
983              * From value
984              */
985             thatObj = obj->info.action.from;
986             if (thatObj != NULL)
987             {
988                 thatModule = obj_get_module(thatObj);
989             }
990             indent(spaces);
991             util_dprintf(0, "from: ");
992             if ((thatModule != NULL) && (thatModule != thisModule))
993             {
994                 util_dprintf(0, "%s.", obj_get_safe_name(thatModule, namebuf, 256));
995             }
996             util_dprintf(0, "(%#08lx)%s\n",
997                          thatObj, obj_get_safe_name(thatObj, namebuf, 256));
998
999             when = obj_get_when(obj);
1000             indent(spaces);
1001             util_dprintf(0, 
1002                 "when: %s\n", util_strsafe(util_when_to_string(when)));
1003         }
1004         else
1005         {
1006             indent(spaces);
1007             util_dprintf(0, "class:%s\n",
1008                          istr_string_safe(obj->class_name));
1009             indent(spaces);
1010             util_dprintf(0, "[parent: %s]\n",
1011                          obj_get_safe_name(obj->parent, namebuf, 256));
1012             if (obj->ref_to != NULL)
1013             {
1014                 indent(spaces);
1015                 util_dprintf(0, "[ref_to: %s]\n",
1016                          obj_get_safe_name(obj->ref_to, namebuf, 256));
1017             }
1018             if (obj->part_of != NULL)
1019             {
1020                 indent(spaces);
1021                 util_dprintf(0, "[part_of: %s]\n",
1022                          obj_get_safe_name(obj->part_of, namebuf, 256));
1023             }
1024             indent(spaces);
1025             util_dprintf(0, "x: %d\n", obj->x);
1026             indent(spaces);
1027             util_dprintf(0, "y: %d\n", obj->y);
1028             indent(spaces);
1029             util_dprintf(0, "width: %d\n", obj->width);
1030             indent(spaces);
1031             util_dprintf(0, "height: %d\n", obj->height);
1032             indent(spaces);
1033             util_dprintf(0, "label: '%s'\n",
1034                          istr_string_safe(obj->label));
1035         }                       /* if is_action */
1036     }
1037     return 0;
1038 #undef print_flag
1039 }                               /* obj_print_indented */
1040
1041
1042 int
1043 obj_tree_print(ABObj obj)
1044 {
1045     int                 iRet = 0;
1046     util_dprintf(0, "***** Object tree *****\n");
1047     iRet = obj_tree_print_indented(obj, 0, util_get_verbosity());
1048     iRet = obj_tree_verify(obj);
1049     if (iRet < 0)
1050     {
1051         util_dprintf(0, "\n***\n***  TREE IS CORRUPT!\n***");
1052
1053     }
1054     util_dprintf(0, "******* Tree End ******\n");
1055     return iRet;
1056 }
1057
1058
1059 static int
1060 obj_tree_print_indented(ABObj obj, int spaces, int verbosity)
1061 {
1062     AB_TRAVERSAL        trav;
1063     ABObj               child = NULL;
1064
1065     if (obj == NULL)
1066     {
1067         util_dprintf(0, "NULL Tree\n");
1068         return 0;
1069     }
1070     obj_print_indented(obj, spaces, verbosity);
1071     if (verbosity >= 4)
1072     {
1073         util_dprintf(0, "\n");
1074     }
1075     for (trav_open(&trav, obj, AB_TRAV_CHILDREN);
1076          (child = trav_next(&trav)) != NULL;)
1077     {
1078         obj_tree_print_indented(child, spaces + 4, verbosity);
1079     }
1080     trav_close(&trav);
1081
1082     return 0;
1083 }
1084
1085
1086 /*
1087  * Perform regular checks of object integrity.
1088  * Tries not to overuse CPU, so this may or may not actually verify anything.
1089  *
1090  * Note that the debug_last_verify_time field doesn't exist in non-debugging
1091  * builds.
1092  */
1093 int
1094 objP_update_verify(ABObj obj)
1095 {
1096 #ifndef DEBUG
1097     return 0;
1098 #else
1099     int                 return_value = 0;
1100     static ABObj        lastObj = NULL;
1101     static int          lastObjCount = 0;
1102     time_t              curTime = 0;
1103
1104     /*
1105      * time() can be rather slow, so let multiple references to the 
1106      * same object slide...
1107      */
1108     if (   (obj != NULL)
1109         && (   (debug_level() >= 5)
1110             || ((   (obj != lastObj) || (++lastObjCount > 10))
1111                  && (curTime > (obj->debug_last_verify_time+1))) )
1112        )
1113     {
1114         return_value = obj_verify(obj);
1115         lastObj = obj;
1116         lastObjCount = 0;
1117     }
1118     return return_value;
1119 #endif /* DEBUG */
1120 }
1121
1122
1123 /*
1124  * This function does not call any functions outside of this file.
1125  * This is because many functions call this one, and we don't want
1126  * to recurse.
1127  *
1128  * This function can be EXTREMELY SLOW! Calling it, for instance,
1129  * one million times inside a loop would not be the right thing to do.
1130  */
1131 int
1132 obj_verify(ABObj obj)
1133 {
1134 #define safe_data_access(_expr) \
1135     mem_fault_occurred = FALSE; \
1136     if (sigsetjmp(sigjmp_env, TRUE) == 0) \
1137     { \
1138         (_expr); \
1139     } \
1140     data_access_ok = (!mem_fault_occurred);
1141
1142 #define field_err(_fieldName) \
1143         (return_value = -1, \
1144         util_dprintf(0, \
1145             "ERROR: Obj %s, bad value in field: %s\n", \
1146                 obj_name, (_fieldName)))
1147
1148 #define check_str(obj, _field) \
1149     ( ((int)(last_field = #_field)), \
1150       (istr_verify(obj->_field) >= 0)? \
1151         (0) \
1152     : \
1153         (field_err(#_field)))
1154
1155     volatile BOOL       objIsAccessible = FALSE;
1156     volatile int        return_value = 0;
1157     volatile char       obj_name[1024] = "";
1158     volatile STRING     obj_str_ptr_name = NULL;
1159     volatile ABObj      parent = NULL;
1160     volatile ABObj      next_sibling = NULL;
1161     volatile ABObj      prev_sibling = NULL;
1162     volatile BOOL       ok = FALSE;
1163     volatile BOOL       data_access_ok = TRUE;
1164     volatile STRING     last_field = NULL;
1165     volatile ABObj      tmpObj = NULL;
1166     volatile StringList namesList = NULL;
1167
1168     sig_fault_handler_install();
1169
1170     if (obj == NULL)
1171     {
1172         return_value = -1;
1173         goto epilogue;
1174     }
1175
1176     /*
1177      * See if this object even exists
1178      */
1179     if (!objP_is_accessible(obj))
1180     {
1181         objIsAccessible = FALSE;
1182         return_value = -1;
1183         util_dprintf(0,
1184             "ERROR - bad object ptr in obj_verify(): %#lx\n", obj);
1185         goto epilogue;
1186     }
1187     objIsAccessible = TRUE;     /* don't forget to set this!! */
1188
1189     /*
1190      * Get the name of the object
1191      */
1192     mem_fault_occurred = FALSE;
1193     if (sigsetjmp(sigjmp_env, TRUE) == 0)
1194     {
1195         obj_str_ptr_name = NULL;
1196         ok = (istr_verify(obj->name) >= 0);
1197         if (ok)
1198         {
1199             obj_str_ptr_name = istr_string(obj->name);
1200             sprintf((STRING)obj_name, "(ABObj %#lx", obj);
1201             if (obj_str_ptr_name != NULL)
1202             {
1203                 strcat((STRING)obj_name, " = ");
1204                 strcat((STRING)obj_name, obj_str_ptr_name);
1205             }
1206             strcat((STRING)obj_name, ")");
1207             if (!ok)
1208             {
1209                 field_err("name");
1210             }
1211         } /* ok */
1212     }
1213     else
1214     {
1215         sprintf((STRING)obj_name, "(ABObj %#lx)", obj);
1216         field_err("name");
1217     }
1218
1219     if (obj->impl_flags == ObjFlagAlreadyFreedValue)
1220     {
1221         util_dprintf(0, "\n\n");
1222         util_dprintf(0, "\nDANGER WILL ROBINSON! COSMIC STORM APPROACHES!!!\n");
1223         util_dprintf(0, "\n");
1224         sleep(5);
1225         util_dprintf(0, "        (Actually, it's just a reference to a previously destroyed object)\n");
1226         util_dprintf(0, "        (Object is %s)\n", obj_name);
1227         util_dputs(0, "\n\n");
1228         return_value = -1;
1229     }
1230
1231     /*
1232      * next_sibling
1233      */
1234     next_sibling = obj->next_sibling;
1235     if ((next_sibling != NULL) && (!objP_is_accessible(next_sibling)))
1236     {
1237         next_sibling = NULL;
1238         field_err("next_sibling");
1239     }
1240     if (next_sibling != NULL)
1241     {
1242         safe_data_access(ok = (next_sibling->prev_sibling == obj));
1243         if ((!data_access_ok) || (!ok))
1244         {
1245             return_value = -1;
1246             field_err("next_sibling");
1247         }
1248     }
1249
1250     /*
1251      * parent
1252      */
1253     prev_sibling = obj->prev_sibling;
1254     if ((prev_sibling != NULL) && (!objP_is_accessible(prev_sibling)))
1255     {
1256         prev_sibling = NULL;
1257         field_err("prev_sibling");
1258     }
1259     if (prev_sibling != NULL)
1260     {
1261         safe_data_access(ok = (prev_sibling->next_sibling == obj));
1262         if ((!data_access_ok) || (!ok))
1263         {
1264             return_value = -1;
1265             field_err("next_sibling");
1266         }
1267     }
1268
1269     /*
1270      * parent
1271      */
1272     parent = obj->parent;
1273     if ((parent != NULL) && (!objP_is_accessible(parent)))
1274     {
1275         parent = NULL;
1276         field_err("parent");
1277     }
1278     if (parent != NULL)
1279     {
1280         volatile ABObj  child;
1281         volatile BOOL   found = FALSE;
1282
1283         ok = TRUE;
1284         safe_data_access(child = parent->first_child);
1285         if (!data_access_ok)
1286         {
1287            field_err("parent");
1288         }
1289         else
1290         {
1291             while ((!found) && (child != NULL))
1292             {
1293                 if (child == obj)
1294                 {
1295                     found = TRUE;
1296                 }
1297                 safe_data_access(child = child->next_sibling);
1298                 if (!data_access_ok)
1299                 {
1300                     field_err("parent");
1301                     break;
1302                 }
1303             }
1304         }
1305         if (!found)
1306         {
1307             return_value = -1;
1308             field_err("parent");
1309         }
1310     }
1311
1312     /*
1313      * first_child
1314      */
1315     
1316     /*
1317      * Still should check: first_child, part_of
1318      */
1319
1320     /*
1321      * Check all the ISTRING fields
1322      */
1323
1324     /* we shouldn't mem fault here, but we're going to prepare, */
1325     /* just in case */
1326     mem_fault_occurred = FALSE;
1327     if (sigsetjmp(sigjmp_env, TRUE) != 0)
1328     {
1329         return_value = -1;
1330         if (last_field != NULL)
1331         {
1332             field_err(last_field);
1333         }
1334         goto epilogue;
1335     }
1336     check_str(obj,user_data);
1337     check_str(obj,help_volume);
1338     check_str(obj,help_location);
1339     check_str(obj,help_text);
1340     check_str(obj,bg_color);
1341     check_str(obj,fg_color);
1342     check_str(obj,label);
1343     check_str(obj,menu_name);
1344     check_str(obj,class_name);
1345
1346     /*
1347      * Check type-specific info
1348      */
1349     switch (obj->type)
1350     {
1351         case AB_TYPE_ACTION:
1352             switch (obj->info.action.func_type)
1353             {
1354                 case AB_FUNC_CODE_FRAG:
1355                     check_str(obj,info.action.func_value.code_frag);
1356                 break;
1357     
1358                 case AB_FUNC_USER_DEF:
1359                     check_str(obj,info.action.func_value.func_name);
1360                 break;
1361             }
1362             switch (obj->info.action.arg_type)
1363             {
1364                 case AB_ARG_STRING:
1365                     check_str(obj,info.action.arg_value.sval);
1366                 break;
1367             }
1368             check_str(obj,info.action.func_name_suffix);
1369         break;
1370
1371         case AB_TYPE_FILE_CHOOSER:
1372             check_str(obj,info.file_chooser.filter_pattern);
1373             check_str(obj,info.file_chooser.ok_label);
1374             check_str(obj,info.file_chooser.directory);
1375         break;
1376
1377         case AB_TYPE_MESSAGE:
1378             check_str(obj,info.message.msg_string);
1379             check_str(obj,info.message.action1_label);
1380             check_str(obj,info.message.action2_label);
1381         break;
1382
1383         case AB_TYPE_DIALOG:
1384         case AB_TYPE_BASE_WINDOW:
1385         {
1386             check_str(obj,info.window.icon);
1387             check_str(obj,info.window.icon_label);
1388         }
1389         break;
1390
1391         case AB_TYPE_TEXT_FIELD:
1392         case AB_TYPE_TEXT_PANE:
1393         {
1394             check_str(obj,info.text.initial_value_string);
1395         }
1396         break;
1397     } /* switch obj->type */
1398     if (obj->type == AB_TYPE_MODULE)
1399     {
1400         check_str(obj,info.module.file);
1401         check_str(obj,info.module.stubs_file);
1402         check_str(obj,info.module.ui_file);
1403     }
1404     if (obj->type == AB_TYPE_ITEM)
1405     {
1406         check_str(obj,info.item.accelerator);
1407     }
1408     if (obj->type == AB_TYPE_PROJECT)
1409     {
1410         check_str(obj,info.project.file);
1411         check_str(obj,info.project.stubs_file);
1412     }
1413     if (obj->type == AB_TYPE_TERM_PANE)
1414     {
1415         check_str(obj,info.term.process_string);
1416     }
1417
1418
1419     /*
1420      * Check names index (we know the strings are valid, now)
1421      * project name doesn't go in an index
1422      */
1423     if ((obj->type != AB_TYPE_PROJECT) && (obj->name != NULL))
1424     {
1425         namesList = NULL;
1426         for (parent = obj->parent; parent != NULL; parent = parent->parent)
1427         {
1428             if (   (parent->type == AB_TYPE_MODULE)
1429                 || (parent->type == AB_TYPE_PROJECT) )
1430             {
1431                 break;
1432             }
1433         }
1434         if (parent != NULL)
1435         {
1436             switch (parent->type)
1437             {
1438                 case AB_TYPE_MODULE: 
1439                     namesList = parent->info.module.obj_names_list;
1440                 break;
1441                 case AB_TYPE_PROJECT: 
1442                     namesList = parent->info.project.obj_names_list;
1443                 break;
1444             }
1445
1446             if (namesList == NULL)
1447             {
1448                 util_dprintf(1, 
1449                     "No names index found containing %s\n", obj_name);
1450                 return_value = -1;
1451                 goto epilogue;
1452             }
1453             else
1454             {
1455                 /*
1456                  * A destroyed object must *not* be in the index,
1457                  * but any other object *must* be in the index.
1458                  */
1459                 tmpObj = (ABObj)strlist_get_istr_data(namesList, obj->name);
1460                 if (obj_has_impl_flags(obj, ObjFlagDestroyed))
1461                 {
1462                     if (tmpObj != NULL)
1463                     {
1464                         util_dprintf(1, 
1465                             "Destroyed object is in names index: %s\n",
1466                             obj_name);
1467                         return_value = -1;
1468                         goto epilogue;
1469                     }
1470                 }
1471                 else
1472                 {
1473                     if (tmpObj != obj)
1474                     {
1475                         util_dprintf(1, "Object does not exist in index: %s\n",
1476                             obj_name);
1477                         return_value = -1;
1478                         goto epilogue;
1479                     }
1480                 }
1481             }
1482         } /* parent != NULL */
1483     } /* obj->name != NULL */
1484
1485 epilogue:
1486 #ifdef DEBUG
1487     if (objIsAccessible)
1488     {
1489         obj->debug_last_verify_time = time(NULL); /*only exists in debug build*/
1490     }
1491 #endif /* DEBUG */
1492     sig_fault_handler_uninstall();
1493     return return_value;
1494 #undef check_str
1495 #undef field_err
1496 #undef safe_data_access
1497 }
1498
1499
1500 /*
1501  * Returns whether or not we can actually examine this object without
1502  * causing a memory fault
1503  *
1504  * Assumes: memory fault handler is installed
1505  * Modifies: sigjmp_env global var
1506  */
1507 static BOOL 
1508 objP_is_accessible(ABObj obj)
1509 {
1510     volatile BOOL               isIt = TRUE;
1511     volatile unsigned char      *volatile objData = (unsigned char *)obj;
1512     volatile int                i;
1513     volatile unsigned char      oneByte = 0;
1514
1515     mem_fault_occurred = FALSE;
1516     if (sigsetjmp(sigjmp_env, TRUE) != 0)
1517     {
1518         isIt = FALSE;
1519         goto epilogue;
1520     }
1521
1522     for (i = 0 ; i < sizeof(*obj); ++i)
1523     {
1524         oneByte = objData[i];
1525     }
1526
1527 epilogue:
1528     return isIt;
1529 }
1530
1531
1532 static int
1533 sig_fault_handler_install(void)
1534 {
1535     struct sigaction    new_action;
1536
1537     mem_fault_occurred = FALSE;
1538     if (sig_fault_handler_installed)
1539     {
1540         return 0;
1541     }
1542
1543     if (sigaction(SIGSEGV, NULL, &org_sig_segv_handler) < 0)
1544     {
1545         return -1;
1546     }
1547     new_action = org_sig_segv_handler;
1548     new_action.sa_handler = sig_fault_handler;
1549     sigemptyset(&(new_action.sa_mask));
1550     new_action.sa_flags = 0;
1551     if (sigaction(SIGSEGV, &new_action, NULL) < 0)
1552     {
1553         return -1;
1554     }
1555
1556     sig_fault_handler_installed = TRUE;
1557
1558 #ifdef SIGBUS
1559     if (sigaction(SIGBUS, NULL, &org_sig_bus_handler) < 0)
1560     {
1561         return -1;
1562     }
1563     new_action = org_sig_bus_handler;
1564     new_action.sa_handler = sig_fault_handler;
1565     sigemptyset(&(new_action.sa_mask));
1566     new_action.sa_flags = 0;
1567     if (sigaction(SIGBUS, &new_action, NULL) < 0)
1568     {
1569         return -1;
1570     }
1571 #endif /* SIGBUS */
1572
1573     return 0;
1574 }
1575
1576
1577 static int
1578 sig_fault_handler_uninstall(void)
1579 {
1580     mem_fault_occurred = FALSE;
1581     if (!sig_fault_handler_installed)
1582     {
1583         return 0;
1584     }
1585
1586     if (sigaction(SIGSEGV, &org_sig_segv_handler, NULL) < 0)
1587     {
1588         return -1;
1589     }
1590     sig_fault_handler_installed = FALSE;
1591
1592 #ifdef SIGBUS
1593     if (sigaction(SIGBUS, &org_sig_bus_handler, NULL) < 0)
1594     {
1595         return -1;
1596     }
1597 #endif /* SIGBUS */
1598
1599     return 0;
1600 }
1601
1602
1603 static void
1604 sig_fault_handler()
1605 {
1606     if (mem_fault_occurred)
1607     {
1608         /* We should have cleared this to prepare for a mem fault */
1609         /* If not, then something has gone haywire */
1610         static STRING msg = NULL;
1611         msg = "MEMORY ACCESS VIOLATION OCCURED. ABORTING.\n";
1612         write(2, msg, strlen(msg));
1613         abort();
1614     }
1615     mem_fault_occurred = TRUE;
1616     siglongjmp(sigjmp_env, 1);
1617 }
1618
1619
1620 int
1621 obj_tree_verify(ABObj root)
1622 {
1623     int                 return_value = 0;
1624     int                 rc = 0;         /* return code */
1625     ABObj               *objArray = NULL;
1626     int                 objArraySize = 0;
1627     ABObj               module = NULL;
1628     AB_TRAVERSAL        moduleTrav;
1629     int                 i = 0;
1630
1631     if (root == NULL)
1632     {
1633         /* empty tree is valid (I guess) */
1634         return 0;
1635     }
1636
1637     rc = build_obj_array(&objArray, &objArraySize, root);
1638     if (rc < 0)
1639     {
1640         return_value = rc;
1641         goto epilogue;
1642     }
1643
1644     for (i = 0; i < objArraySize; ++i)
1645     {
1646         rc = obj_verify(objArray[i]);
1647         if (rc < 0)
1648         {
1649             return_value = rc;
1650             goto epilogue;
1651         }
1652     }
1653
1654     /* 
1655      * Check the project names list
1656      */
1657     if (obj_is_project(root))
1658     {
1659         rc = verify_the_silly_index(root, objArray, objArraySize);
1660         if (rc < 0)
1661         {
1662             return_value = rc;
1663             goto epilogue;
1664         }
1665     }
1666
1667     /* 
1668      * check the modules' name lists
1669      */
1670     for (trav_open(&moduleTrav, root, AB_TRAV_MODULES);
1671         (module = trav_next(&moduleTrav)) != NULL; )
1672     {
1673         rc = verify_the_silly_index(module, objArray, objArraySize);
1674         if (rc < 0)
1675         {
1676             return_value = rc;
1677             break;
1678         }
1679     }
1680     trav_close(&moduleTrav);
1681
1682 epilogue:
1683     util_free(objArray);
1684     return return_value;
1685 }
1686
1687
1688 static int      
1689 verify_the_silly_index(
1690                         ABObj           nameScopeObj,
1691                         ABObj           *objArray, 
1692                         int             objArraySize
1693 )
1694 {
1695     int         return_value = 0;
1696     StringList  names = NULL;
1697     int         numNames = 0;
1698     int         nameCount = 0;
1699     int         objCount = 0;
1700     ABObj       namedObj = NULL;
1701     ABObj       namesObj = NULL;
1702     ISTRING     curName = NULL;
1703     ABObj       curObj = NULL;
1704     ABObj       curScopeObj = NULL;
1705     StringList  curNames = NULL;
1706     BOOL        namedObjFound = FALSE;
1707     char        nameBuf1[1024];
1708     char        nameBuf2[1024];
1709     char        nameBuf3[1024];
1710     *nameBuf1 = 0;
1711     *nameBuf2 = 0;
1712     *nameBuf3 = 0;
1713
1714
1715     names = objP_get_names_list(nameScopeObj);
1716     if (names == NULL)
1717     {
1718         return 0;
1719     }
1720     numNames = strlist_get_num_strs(names);
1721
1722     for (nameCount = 0; nameCount < numNames; ++nameCount)
1723     {
1724         namedObjFound = FALSE;
1725         curName = strlist_get_istr(names, nameCount, (void **)&namedObj);
1726         for (objCount = 0; 
1727              (!namedObjFound) && (objCount < objArraySize); ++objCount)
1728         {
1729             /*
1730              * See if we've found the object
1731              */
1732             curObj = objArray[objCount];
1733             if ((curObj != namedObj) || obj_is_project(curObj))
1734             {
1735                 /* projects don't go in list, anywhere */
1736                 continue;
1737             }
1738
1739             /*
1740              * We've found the object that goes with this name. Check
1741              * to see if it is in the right scope.
1742              */
1743             curNames = NULL;
1744             curScopeObj = objP_get_names_scope_obj(curObj);
1745             if (curScopeObj != NULL)
1746             {
1747                 curNames = objP_get_names_list(curScopeObj);
1748             }
1749             if (curNames == NULL)
1750             {
1751                 util_dprintf(1, 
1752                     "No names list found for object %s in module %s!\n",
1753                     obj_get_safe_name(curObj, nameBuf1, 1024),
1754                     obj_get_safe_name(obj_get_module(curObj), nameBuf2, 1024));
1755                 return_value = ERR_INTERNAL;
1756                 goto epilogue;
1757             }
1758             else if (curNames != names)
1759             {
1760                 util_dprintf(1,
1761              "Object %s should be in scope for %s, but is in scope for %s\n",
1762                     obj_get_safe_name(curObj, nameBuf1, 1024),
1763                     obj_get_safe_name(curScopeObj, nameBuf2, 1024),
1764                     obj_get_safe_name(nameScopeObj, nameBuf3, 1024));
1765                 return_value = ERR_INTERNAL;
1766                 goto epilogue;
1767             }
1768             else if (!istr_equal(curName, curObj->name))
1769             {
1770                 util_dprintf(1,
1771                     "Object %s has incorrect reference in index!\n",
1772                         obj_get_safe_name(curObj, nameBuf1, 1024));
1773             }
1774             else
1775             {
1776                 namedObjFound = TRUE;
1777             }
1778         } /* for objCount */
1779
1780         if (!namedObjFound)
1781         {
1782 #ifdef DEBUG
1783             util_dprintf(1,
1784                 "Name is in index '%s', but no such object exists!\n",
1785                 istr_string_safe(curName));
1786 #endif /* DEBUG */
1787             return_value = ERR_INTERNAL;
1788             goto epilogue;
1789         }
1790     } /* for nameCount */
1791
1792 epilogue:
1793     return return_value;
1794 }
1795
1796
1797 static int
1798 build_obj_array(ABObj **objArrayPtr, int *objArraySizePtr, ABObj root)
1799 {
1800 #define objArray (*objArrayPtr)
1801 #define objArraySize (*objArraySizePtr)
1802     int         rc = 0;                 /* return code */
1803     ABObj       *newObjArray = NULL;
1804     ABObj       child = NULL;
1805
1806     /*
1807      * If this object is already in the list, we've detected some sort
1808      * of cycle.
1809      */
1810     {
1811         int     i = 0;
1812         char    name[1024];
1813         *name = 0;
1814         for (i = 0; i < objArraySize; ++i)
1815         {
1816             if (objArray[i] == root)
1817             {
1818                 util_dprintf(1, 
1819                  "INTERNAL ERROR: some sort of cycle detected involving %s\n",
1820                  obj_get_safe_name(root, name, 1024));
1821                 return -1;
1822             }
1823         }
1824     }
1825
1826     /*
1827      * Add root obj to list
1828      */
1829     ++objArraySize;
1830     newObjArray = (ABObj*)realloc(objArray, objArraySize*sizeof(ABObj*));
1831     if (newObjArray == NULL)
1832     {
1833         util_dprintf(1, "Out of memory in build_obj_array\n");
1834         return ERR_NO_MEMORY;
1835     }
1836     objArray = newObjArray;
1837     objArray[objArraySize-1] = root;
1838
1839     /*
1840      * Add the children to the list
1841      */
1842     for (child = root->first_child; child != NULL; child = child->next_sibling)
1843     {
1844         if ((rc = build_obj_array(&objArray, &objArraySize, child)) < 0)
1845         {
1846             return rc;
1847         }
1848     }
1849
1850     return 0;
1851
1852 #undef objArrayPtr
1853 #undef objArray
1854 }
1855
1856 ABObj
1857 obj_get_parent_of_type(ABObj obj, AB_OBJECT_TYPE type)
1858 {
1859     ABObj               ancestor = obj->parent;
1860     while ((ancestor != NULL) && (obj_get_type(ancestor) != type))
1861     {
1862         ancestor = ancestor->parent;
1863     }
1864     return ancestor;
1865 }