Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / libABobj / obj.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.c /main/4 1996/10/02 16:11:56 drk $
26  * 
27  * @(#)obj.c    3.46 11 Feb 1994        cde_app_builder/src/libABobj
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  * ABObj.c - manipulations of one gobj structure
45  */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <ctype.h>
50 #include <values.h>
51 #include <stdlib.h>
52 #include <sys/param.h>
53 #include <string.h>
54 #include "objP.h"               /* include first! */
55 #include <ab_private/trav.h>
56 #include <ab_private/util.h>
57 #include "obj_names_listP.h"
58 #include "obj_notifyP.h"
59
60 static int 
61 objP_or_tree_update_clients_with_data(
62                                       ABObj obj,
63                                       BOOL update_subtree,
64                                       int update_code,
65                                       void *update_data,
66                                       UpdateDataFreeFunc free_func
67 );
68
69 /*
70  * Gets the item for this object with index which_item
71  */
72 ABObj
73 obj_get_item(ABObj obj, int which_item)
74 {
75     AB_TRAVERSAL        trav;
76     ABObj               item = NULL;
77     int                 item_num = -1;  /* must be -1 */
78
79     for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
80          (item = trav_next(&trav)) != NULL;)
81     {
82         ++item_num;
83         if (item_num == which_item)
84         {
85             break;
86         }
87     }
88     trav_close(&trav);
89     return item;
90 }
91
92 /*
93  * Return the Help Item for a given menubar
94  */
95 ABObj
96 obj_get_menubar_help_item(
97                           ABObj obj
98 )
99 {
100     AB_TRAVERSAL        trav;
101     ABObj               help_item = NULL;
102     ABObj               item;
103
104     if (!obj_is_menubar(obj))
105         return NULL;
106
107     for (trav_open(&trav, obj, AB_TRAV_ITEMS_FOR_OBJ);
108          (item = trav_next(&trav)) != NULL;)
109     {
110         if (obj_is_help_item(item) == TRUE)
111         {
112             help_item = item;
113             break;
114         }
115     }
116     trav_close(&trav);
117     return help_item;
118
119 }
120
121 /*
122  * Returns the number of this object, as a child of it's parent.
123  */
124 int
125 obj_get_child_num(ABObj obj)
126 {
127     int                 child_num = -1;
128     ABObj               child;
129
130     if (obj->parent == NULL)
131     {
132         goto epilogue;
133     }
134
135     for (child = obj->parent->first_child;
136          child != NULL; child = child->next_sibling)
137     {
138         ++child_num;
139         if (obj == child)
140         {
141             break;
142         }
143     }
144
145 epilogue:
146     return child_num;
147 }
148
149
150 ABObj
151 obj_get_container_child(ABObj obj)
152 {
153     ABObj               child;
154     for (child = obj->first_child; child != NULL;
155          child = child->next_sibling)
156     {
157         if (obj_is_container(child))
158         {
159             break;
160         }
161     }
162     return child;
163 }
164
165
166 /*
167  * Returns the item number of this object, with reference to it's parent
168  */
169 int
170 obj_get_item_num(ABObj obj)
171 {
172     int                 item_num = -1;
173     ABObj               item;
174     for (item = obj->parent->first_child;
175          item != NULL; item = item->next_sibling)
176     {
177         if (!obj_is_item(item))
178         {
179             continue;
180         }
181         ++item_num;
182         if (item == obj)
183         {
184             break;
185         }
186     }
187     return item_num;
188 }
189
190
191 ABObj
192 obj_get_menu(ABObj obj)
193 {
194     ABObj               child = NULL;
195     for (child = obj->first_child; child != NULL; child = child->next_sibling)
196     {
197         if (obj_is_menu(child))
198         {
199             break;
200         }
201     }
202     return child;
203 }
204
205
206 ABObj
207 obj_get_pane_child(ABObj obj)
208 {
209     ABObj               child;
210     for (child = obj->first_child; child != NULL;
211          child = child->next_sibling)
212     {
213         if (obj_is_pane(child))
214         {
215             break;
216         }
217     }
218     return child;
219 }
220
221
222 BOOL
223 obj_has_menu(ABObj obj)
224 {
225     if (!util_strempty(obj_get_menu_name(obj)))
226         return TRUE;
227     else
228         return FALSE;
229
230 }
231
232 /*
233  * Moves the children only if *all* the children can be moved.
234  */
235 int
236 obj_move_children(ABObj to, ABObj from)
237 {
238     int                 iReturn = 0;
239     int                 iRC = 0;/* return code */
240     ABObj               child = NULL;
241
242     /*
243      * Get permission for all children
244      */
245     for (child = from->first_child;
246          child != NULL; child = child->next_sibling)
247     {
248         if ((iRC = objP_notify_send_allow_reparent(child, to)) < 0)
249         {
250             iReturn = iRC;
251             goto epilogue;
252         }
253     }
254
255     while ((child = from->first_child) != NULL)
256     {
257
258         /*
259          * Don't send reparent to NULL
260          */
261
262         objP_notify_push_mode();
263         objP_notify_clear_mode(OBJEV_MODE_SEND_NOTIFY_EVS);
264         obj_unparent(child);
265         obj_append_child(to, child);
266         objP_notify_pop_mode();
267
268         objP_notify_send_reparent(child, from);
269     }
270
271 epilogue:
272     return iReturn;
273 }
274
275 /*
276  * maxlen < 1 means no max.
277  */
278 int
279 obj_ensure_unique_name(ABObj obj, ABObj root, int maxlen)
280 {
281     BOOL                unique = FALSE;
282     BOOL                error = FALSE;
283     BOOL                name_changed = FALSE;
284     char                mod_name[256];
285     char                obj_name[2048];
286     int                 oldlen;
287     int                 modlen;
288     int                 newlen;
289     AB_TRAVERSAL        trav;
290     ABObj               other_obj = NULL;
291     int                 modifier = 0;
292     unsigned            trav_type;
293
294     if (obj->name == NULL)
295     {
296         return -1;
297     }
298     if (maxlen < 1)
299     {
300         maxlen = 2048;
301     }
302     strncpy(obj_name, istr_string(obj->name), maxlen);
303     obj_name[2047] = 0;
304     modifier = 0;
305     unique = FALSE;
306     if (obj_is_module(obj))
307     {
308         trav_type = AB_TRAV_MODULES;
309     }
310     else
311     {
312         trav_type = AB_TRAV_UI;
313     }
314     while ((!unique) && (!error))
315     {
316         unique = TRUE;
317         for (trav_open(&trav, root, trav_type);
318              (other_obj = trav_next(&trav)) != NULL;)
319         {
320             if ((other_obj != obj)
321                 && (other_obj->name != NULL)
322                 && (strncmp(istr_string(other_obj->name), obj_name, maxlen)
323                     == 0))
324             {
325                 unique = FALSE;
326                 name_changed = TRUE;
327                 sprintf(mod_name, "%d", ++modifier);
328                 if ((strlen(mod_name) + 1) > (unsigned) maxlen)
329                 {
330                     error = TRUE;
331                     break;
332                 }
333                 oldlen = istr_len(obj->name);
334                 modlen = strlen(mod_name);
335                 newlen = oldlen + modlen;
336                 if (newlen > maxlen)
337                 {
338                     newlen = maxlen;
339                     oldlen = newlen - modlen;
340                 }
341                 strncpy(obj_name, istr_string(obj->name),
342                         oldlen);
343                 obj_name[oldlen] = 0;
344                 strcat(obj_name, mod_name);
345             }
346         }
347         trav_close(&trav);
348     }
349     if (name_changed && (!error))
350     {
351         /* printf("CHANGED %s -> %s\n", obj->name, obj_name); */
352
353         /*
354          * REMIND: CHANGE ALL BY-NAME REFS TO THIS OBJECT!
355          */
356         obj_set_name(obj, obj_name);
357     }
358
359     return error ? -1 : 0;
360 }
361
362
363 /*
364  * Munges name, as necessary to get uniqueness
365  */
366 int
367 obj_set_unique_name_istr(ABObj obj, ISTRING name)
368 {
369     int         rc = 0;         /* return code */
370     ISTRING     newName = obj_alloc_unique_name_istr(obj, name, -1);
371     rc = obj_set_name_istr(obj, newName);
372     istr_destroy(newName);
373     return rc;
374 }
375
376
377 int
378 obj_set_unique_name(ABObj obj, STRING strName)
379 {
380     int         return_value = 0;
381     ISTRING     name = istr_create(strName);
382
383     return_value = obj_set_unique_name_istr(obj, name);
384
385     istr_destroy(name);
386     return return_value;
387 }
388
389
390 STRING          
391 obj_alloc_unique_name(
392                         ABObj   obj, 
393                         STRING  name, 
394                         int     maxNameLen
395 )
396 {
397     ABObj       parent = obj->parent;
398     if (   (parent == NULL)
399         || (obj_find_by_name(parent, name) == obj) )
400     {
401         return strdup(name);
402     }
403     return obj_alloc_unique_name_for_child(parent, name, maxNameLen);
404 }
405
406
407 ISTRING         
408 obj_alloc_unique_name_istr(
409                         ABObj   obj, 
410                         ISTRING name, 
411                         int     maxNameLen
412 )
413 {
414     ABObj       parent = obj->parent;
415     if (   (parent == NULL)
416         || (obj_find_by_name(parent, istr_string(name)) == obj) )
417     {
418         return istr_dup(name);
419     }
420     return obj_alloc_unique_name_istr_for_child(parent, name, maxNameLen);
421 }
422
423
424 STRING          
425 obj_get_unique_name(
426                         ABObj   obj, 
427                         STRING  name, 
428                         int     maxNameLen,
429                         STRING  nameOutBuf
430 )
431 {
432     ABObj       parent = obj->parent;
433     if (   (parent == NULL)
434         || (obj_find_by_name(parent, name) == obj) )
435     {
436         return name;
437     }
438     return obj_get_unique_name_for_child(parent, name, maxNameLen-1, nameOutBuf);
439 }
440
441
442 /*
443  * maxlen < 1 means no max.
444  */
445 STRING
446 obj_alloc_unique_name_for_child(
447                       ABObj     obj,
448                       STRING    name,
449                       int       maxlen
450 )
451 {
452     char        nameBuf[8192];
453     STRING      unique_name = NULL;
454     *nameBuf = 0;
455
456     if (maxlen < 0)
457     {
458         maxlen = 8192;
459     }
460 #if defined (USL) || defined(__uxp__)
461         /*
462          * The USL specific changes were added ifdef due to time constraints
463          * They should be removed in the next release
464          */
465     maxlen = util_min(8191,maxlen);     /* don't overrun buf */
466 #else
467     maxlen = util_min(8192,maxlen);     /* don't overrun buf */
468 #endif
469
470     /*
471      * Alloc space and copy-in the unique name
472      */
473     unique_name = strdup(
474                 obj_get_unique_name_for_child(obj, name, maxlen-1, nameBuf));
475      
476     return unique_name;
477 }
478
479
480 ISTRING
481 obj_alloc_unique_name_istr_for_child(
482                       ABObj     obj,
483                       ISTRING   name,
484                       int       maxlen
485 )
486 {
487     char        nameBuf[8192];
488     ISTRING     unique_name = NULL;
489     *nameBuf = 0;
490
491     if (maxlen < 0)
492     {
493         maxlen = 8192;
494     }
495 #if defined (USL) || defined(__uxp__)
496     maxlen = util_min(8191,maxlen);
497 #else
498     maxlen = util_min(8192,maxlen);
499 #endif
500     unique_name = istr_create(
501         obj_get_unique_name_for_child(obj, istr_string(name), maxlen-1, nameBuf));
502
503     return unique_name;
504 }
505
506
507 STRING
508 obj_get_unique_name_for_child(
509     ABObj       obj,
510     STRING      name,
511     int         maxlen,
512     STRING      nameOutBuf
513 )
514 {
515     STRING      returnName = NULL;
516     int         nameOutBufSize = maxlen+1;      
517     StringList  namesList = NULL;
518     BOOL        done = FALSE;
519     BOOL        unique = FALSE;
520     int         nameLen = 0;
521     int         i = 0;
522     int         objNumberStart = 0;
523     int         objNumber = 0;
524
525     namesList = objP_get_names_scope_for_children(obj);
526     if (namesList == NULL)
527     {
528         returnName = name;
529         goto epilogue;
530     }
531
532     unique = !strlist_str_exists(namesList, name);
533     if (unique)
534     {
535         returnName = name;
536         goto epilogue;
537     }
538
539     /*
540      * Determine trailing number
541      */
542     util_strncpy(nameOutBuf, name, nameOutBufSize);
543     nameLen = strlen(nameOutBuf);
544     for (i = nameLen-1; i >= 0; --i)
545     {
546         if (!isdigit(nameOutBuf[i]))
547         {
548             break;
549         }
550     }
551     objNumberStart = i + 1;
552     objNumber = atoi(&(nameOutBuf[objNumberStart]));
553
554     /*
555      * Search for a unique name by incrementing trailing #
556      */
557     unique = FALSE;
558     done = FALSE;
559     while (!done)
560     {
561         if (++objNumber == 1)
562         {
563             /* skip 1 - name w/no # is implied 1 */
564             objNumber = 2;
565         }
566         sprintf(&(nameOutBuf[objNumberStart]), "%d", objNumber);
567         unique = !strlist_str_exists(namesList, nameOutBuf);
568         done = unique;
569     }
570     if (unique)
571     {
572         returnName = nameOutBuf;
573     }
574
575 epilogue:
576     return returnName;
577 }
578
579
580 /*
581  * Don't run this on a project!!! It's a severe dog, and can take many
582  * seconds to complete.
583  * 
584  * Run it on each module (root = an module) instead.
585  */
586 int
587 obj_tree_ensure_unique_names(ABObj root, int maxnamelen)
588 {
589     AB_TRAVERSAL        trav;
590     ABObj               obj;
591
592     for (trav_open(&trav, root, AB_TRAV_UI);
593          (obj = trav_next(&trav)) != NULL;)
594     {
595         obj_ensure_unique_name(obj, root, maxnamelen);
596     }
597     trav_close(&trav);
598     return 0;
599 }
600
601
602 /*
603  * Calls obj_tree_ensure_unique_names on each module in the given tree.
604  */
605 int
606 obj_tree_ensure_unique_names_in_modules(ABObj root, int maxnamelen)
607 {
608     AB_TRAVERSAL        trav;
609     ABObj               module;
610
611     for (trav_open(&trav, root, AB_TRAV_MODULES);
612          (module = trav_next(&trav)) != NULL;)
613     {
614         obj_tree_ensure_unique_names(module, maxnamelen);
615     }
616     trav_close(&trav);
617     return 0;
618 }
619
620 /*
621  * Gives an object a name by munging it's parent's name with it's own label.
622  * Used for item children, which aren't given names directly.
623  * 
624  * actual_parent overrides the parent of the object.  If actual_parent is NULL,
625  * the "normal" parent of the object is used.
626  */
627 int
628 obj_set_name_from_label(ABObj obj, STRING parent_name_in)
629 {
630     STRING              parent_name = NULL;
631     STRING              item_label = NULL;
632     STRING              new_name = NULL;
633
634     parent_name =
635         (parent_name_in == NULL ?
636          (obj->parent == NULL ?
637           NULL
638           :
639           istr_string(obj->parent->name)
640           )
641          :
642          parent_name
643         );
644     if (parent_name == NULL)
645     {
646         return -1;
647     }
648
649     if (istr_len(obj->label) > 0)
650     {
651         item_label = istr_string(obj->label);
652     }
653     else
654     {
655         item_label = "item";
656     }
657
658     obj_set_unique_name(obj,
659                  ab_ident_from_name_and_label(parent_name, item_label));
660
661     return 0;
662 }
663
664 int
665 obj_set_name_from_parent(ABObj obj, STRING suffix)
666 {
667     STRING              parent_name;
668     STRING              new_name = NULL;
669
670     parent_name = (obj->parent == NULL ?
671                    NULL
672                    :
673                    istr_string(obj->parent->name)
674         );
675
676     if (parent_name == NULL)
677     {
678         return -1;
679     }
680
681     obj_set_unique_name(obj,
682                  ab_ident_from_name_and_label(parent_name,
683                                               suffix));
684
685     return 0;
686
687 }
688
689 /*
690  * Gets a name for an object. Object may be NULL, or have a NULL name
691  * 
692  * Copies name into passed-in buffer name, guarantees 0 termination. returns
693  * parameter string
694  */
695 STRING
696 obj_get_safe_name(ABObj obj, STRING name, int name_size)
697 {
698     if (name_size < 1)
699     {
700         return name;
701     }
702
703     if (obj == NULL)
704     {
705         strncpy(name, "(nil ABObj)", name_size);
706     }
707     else if (obj_get_name(obj) == NULL)
708     {
709         char                buf[256];
710         sprintf(buf, "(ABObj:0x%08lx)", obj);
711         strncpy(name, buf, name_size);
712     }
713     else
714     {
715         strncpy(name, obj_get_name(obj), name_size);
716     }
717
718     name[name_size - 1] = 0;
719
720     return name;
721 }
722
723 /*************************************************************************
724 **                                                                      **
725 **              UPDATE_CLIENTS METHODS                                  **
726 **                                                                      **
727 *************************************************************************/
728
729 int
730 obj_update_clients(ABObj obj)
731 {
732     return objP_notify_send_update(obj, FALSE);
733 }
734
735
736 int
737 obj_tree_update_clients(ABObj tree)
738
739 {
740     return objP_notify_send_update(tree, TRUE);
741 }
742
743
744 int
745 obj_update_clients_with_data(
746                              ABObj obj,
747                              int update_code,
748                              void *update_data,
749                              UpdateDataFreeFunc free_func)
750 {
751     return objP_or_tree_update_clients_with_data(
752                            obj, FALSE, update_code, update_data, free_func);
753 }
754
755
756 int
757 obj_tree_update_clients_with_data(ABObj obj,
758                                   int update_code,
759                                   void *update_data,
760                                   UpdateDataFreeFunc free_func)
761 {
762     return objP_or_tree_update_clients_with_data(
763                             obj, TRUE, update_code, update_data, free_func);
764 }
765
766
767 static int
768 objP_or_tree_update_clients_with_data(
769                                       ABObj obj,
770                                       BOOL update_subtree,
771                                       int update_code,
772                                       void *update_data,
773                                       UpdateDataFreeFunc free_func
774 )
775 {
776     int                 iReturn = 0;
777
778     /*
779      * event notification will only free the data if the notify events are
780      * batched.  It's pretty smart about it, so we're going to go to batch
781      * mode and let it handle it.
782      */
783     objP_notify_push_mode();
784     objP_notify_set_mode(OBJEV_MODE_BATCH_NOTIFY_EVS);
785
786     iReturn = objP_notify_send_update_with_data(
787                   obj, update_subtree, update_code, update_data, free_func);
788
789     objP_notify_pop_mode();
790     return iReturn;
791 }