Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Basic / FolioObject.C
1 /*
2  * $XConsortium: FolioObject.C /main/5 1996/10/04 11:23:44 drk $
3  *
4  * Copyright (c) 1992 HaL Computer Systems, Inc.  All rights reserved.
5  * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
6  * States.  Use of a copyright notice is precautionary only and does not
7  * imply publication or disclosure.
8  * 
9  * This software contains confidential information and trade secrets of HaL
10  * Computer Systems, Inc.  Use, disclosure, or reproduction is prohibited
11  * without the prior express written permission of HaL Computer Systems, Inc.
12  * 
13  *                         RESTRICTED RIGHTS LEGEND
14  * Use, duplication, or disclosure by the Government is subject to
15  * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
16  * Technical Data and Computer Software clause at DFARS 252.227-7013.
17  *                        HaL Computer Systems, Inc.
18  *                  1315 Dell Avenue, Campbell, CA  95008
19  * 
20  */
21
22 #define C_FolioObject
23 #define L_Basic
24 #include "Prelude.h"
25
26 INIT_CLASS (FolioObject);
27
28 // private class to hold dependent data
29 // NOTE: To avoid overhead there should be a class below FolioObject
30 // to hold the dependency type stuff called "??"
31 // Need to fix this up later.
32 // BaseObject -> Object -> Hasbable -> etc.
33 // This may not be a problem once we have templates, because then we can
34 // stick anything in our list. 
35
36 class Dependent
37 {
38 public:
39   Dependent (Dependent **pre_next, Dependent *next,
40              FolioObject *dependent, FolioObject *folio_object,
41              notify_handler_t handler,
42              u_int notify_type, void *dependent_data)
43   : f_pre_next (pre_next), f_next (next),
44     f_dependent (dependent), f_folio_object (folio_object),
45     f_handler (handler),
46     f_notify_type (notify_type), f_dependent_data (dependent_data)
47     { if (next) next->f_pre_next = &f_next; }
48   FolioObject       *f_dependent;
49   FolioObject       *f_folio_object;
50   notify_handler_t   f_handler;
51   u_int              f_notify_type;
52   void              *f_dependent_data;
53   Dependent        **f_pre_next;
54   Dependent         *f_next;
55   void release();
56   void call (FolioObject *obj, void *notify_data);
57 };
58
59 inline void
60 Dependent::release()
61 {
62   ON_DEBUG(printf ("@** assigning: f_dependent = %p\n", f_next));
63   *f_pre_next = f_next;
64   if (f_next) f_next->f_pre_next = f_pre_next;
65   delete this;
66 }
67
68 inline void
69 Dependent::call (FolioObject *obj, void *notify_data)
70 {
71   (f_dependent->*f_handler)(obj, f_notify_type, notify_data, f_dependent_data);
72 }
73
74
75 class DependOnList
76 {
77 public:
78   DependOnList (DependOnList *next, Dependent *d)
79     : f_next (next), f_dependent_obj (d)
80   { }
81   void delete_dependent();
82   Dependent *f_dependent_obj;
83   DependOnList *f_next;
84 };
85
86 inline void
87 DependOnList::delete_dependent()
88 {
89   f_dependent_obj->release();
90 }
91
92
93 // /////////////////////////////////////////////////////////////////
94 // class constructor
95 // /////////////////////////////////////////////////////////////////
96
97 FolioObject::FolioObject()
98 : f_dependents (NULL), f_depend_on_list (NULL)
99 {
100   // Initialize status to reasonable value.
101   // Subclasses only need to change on creation if an error occurs.
102   setStatus (eSuccess);
103   f_initialized = FALSE;
104 }
105
106
107 // /////////////////////////////////////////////////////////////////
108 // class destructor
109 // /////////////////////////////////////////////////////////////////
110
111 FolioObject::~FolioObject()
112 {
113   notify (DESTROYED);
114   release_dependents();
115   release_depend_on_list();
116 }
117
118
119 // /////////////////////////////////////////////////////////////////
120 // notify - this object changed
121 // /////////////////////////////////////////////////////////////////
122
123 void
124 FolioObject::notify (u_int notify_type, void *notify_data)
125 {
126   Dependent *d, *next;
127
128   // NOTE: This function is temporarily hacked up to get the next
129   // entry in the list before calling the function because it
130   // might be a destroy message which causes the object notified
131   // to destroy itself and delete the current Dependent object,
132   // leaving d pointing into freed memory.  next could also point
133   // into freed memory, so for now we need to make sure that any
134   // notification that deletes the target object is at the end
135   // of the list of dependents.  This is done by adding first, since
136   // Dependent records are added to the start of the list.
137   // The Right fix for this is probably to pull items from the "to check"
138   // list and move them to a "called" list as they are called.  After
139   // each call, d should start at the beginning of the "to check" list
140   // since it will be the only memory guaranteed to be around.
141   // DJB 11/10/92 
142   for (d = f_dependents; d != NULL;)
143     {
144       next = d->f_next;
145       if (d->f_notify_type == notify_type)
146         d->call (this, notify_data);
147       d = next;
148     }
149 }
150
151
152 // /////////////////////////////////////////////////////////////////
153 // add_dependent - add a new dependent
154 // /////////////////////////////////////////////////////////////////
155
156 void
157 #if defined(SC3) || defined(__osf__) || defined(USL)
158 FolioObject::add_dependent (FolioObject *dependent, notify_handler_t handler,
159 #else
160 FolioObject::add_dependent (void *dependent, notify_handler_t handler,
161 #endif
162                             u_int notify_type, void *dependent_data)
163 {
164   // Adds to begining because that's easiest.
165 #if defined(SC3) || defined(__osf__) || defined(USL)
166   f_dependents = new Dependent (&f_dependents, f_dependents,
167                                 dependent, NULL, handler,
168                                 notify_type, dependent_data);
169 #else
170   f_dependents = new Dependent (&f_dependents, f_dependents,
171                                 (FolioObject*)dependent, NULL, handler,
172                                 notify_type, dependent_data);
173 #endif
174   ON_DEBUG(printf ("@@@2 adding dependent %p to object %p\n",
175                    f_dependents, this));
176   // Also remember it in the dependent for easy removal if it is deleted.
177   // The code below failed in a big way because the "dependent" variable
178   // was the real this pointer of the original object, not the offset
179   // this pointer for a FolioObject (in a multiply inherited object).
180   // The net result was the the code mucked up the object because dependent
181   // really wasn't a FolioObject.
182   // NOTE: need to change all code in which we're doing semi-bogus stuff
183   // with a FolioObject to be a void * so that functions can't be called
184   // by mistake like this.  We'll just have to cast it to a FolioObject
185   // when the call through it is made and hope the compiler doesn't
186   // expect it to point to an actual FolioObject (or whatever, eg: WWL). 
187 #if defined(SC3) || defined(__osf__) || defined(USL)
188   ON_DEBUG(printf ("@@@ adding to depend_on_list of %p\n", dependent));
189   dependent->f_depend_on_list =
190     new DependOnList (dependent->f_depend_on_list, f_dependents);
191 #endif
192 }
193
194
195 // /////////////////////////////////////////////////////////////////
196 // remove_depend_on
197 // /////////////////////////////////////////////////////////////////
198
199 void
200 FolioObject::remove_depend_on (FolioObject *target, Dependent *d)
201 {
202   ON_DEBUG(printf ("Calling remove_depend_on for object %p, entry %p\n",
203                    target, d));
204   DependOnList **l;
205   for (l = &(target->f_depend_on_list); *l != NULL; l = &((*l)->f_next))
206     {
207       ON_DEBUG(printf ("   checking against entry %p\n", *l));
208       if ((*l)->f_dependent_obj == d)
209         {
210           ON_DEBUG(printf ("removing DependOnList %p\n", *l));
211           DependOnList *dead_meat = *l;
212           *l = (*l)->f_next;
213           delete dead_meat;
214           break;
215         }
216     }
217 }
218
219
220 // /////////////////////////////////////////////////////////////////
221 // remove_dependent - remove first matching dependent
222 // /////////////////////////////////////////////////////////////////
223
224 void
225 #if defined(SC3) || defined(__osf__) || defined(USL)
226 FolioObject::remove_dependent (FolioObject *dependent,
227 #else
228 FolioObject::remove_dependent (void *dependent,
229 #endif
230                                notify_handler_t handler,
231                                u_int notify_type, void *dependent_data)
232 {
233   Dependent **d;
234
235   // This only removes the first matching handler!
236   // That means that each handler added must be removed!
237   for (d = &f_dependents; *d != NULL; d = &((*d)->f_next))
238     {
239 #if defined(SC3) || defined(__osf__) || defined(USL)
240       if ((*d)->f_dependent      == dependent   &&
241 #else
242       if ((*d)->f_dependent      == (FolioObject*)dependent   &&
243 #endif
244           (*d)->f_handler        == handler     &&
245           (*d)->f_notify_type    == notify_type &&
246           (*d)->f_dependent_data == dependent_data)
247         {
248           // Following line is BOGUS because dependent is "real this"
249           // not necessarily a FolioObject!
250           // f_folio_object will be NULL if the Dependent object was
251           // created in add_dependent!  DJB 11/10/92 
252           assert ((*d)->f_folio_object != NULL);
253 #if defined(SC3) || defined(__osf__) || defined(USL)
254           remove_depend_on (dependent, *d);
255 #else
256           remove_depend_on ((FolioObject*)dependent, *d);
257 #endif
258           Dependent *dead_meat = *d;
259           *d = (*d)->f_next;
260           delete dead_meat;
261           break;
262         }
263     }
264 }
265
266
267 // /////////////////////////////////////////////////////////////////
268 // release_dependents - free all dependents
269 // /////////////////////////////////////////////////////////////////
270
271 void
272 FolioObject::release_dependents()
273 {
274   Dependent *d = f_dependents, *next;
275
276   while (d != NULL)
277     {
278       // NOTE: Quick fix below.  Improve with doubly-linked lists and
279       // cross pointers in Dependent and DependOnList objects.
280       // f_folio_object member is part of the quick fix.  DJB 11/10/92 
281       if (d->f_folio_object != NULL)
282         remove_depend_on (d->f_folio_object, d);
283       else
284         ON_DEBUG(printf ("WARNING: NULL f_folio_object member in release_dependents\n"));
285       next = d->f_next;
286       delete d;
287       d = next;
288     }
289   f_dependents = NULL;
290 }
291
292
293 // /////////////////////////////////////////////////////////////////
294 // release_depend_on_list
295 // /////////////////////////////////////////////////////////////////
296
297 void
298 FolioObject::release_depend_on_list()
299 {
300   DependOnList *l = f_depend_on_list, *next;
301
302   while (l != NULL)
303     {
304       next = l->f_next;
305       l->delete_dependent();
306       delete l;
307       l = next;
308     }
309
310   f_depend_on_list = NULL;
311 }
312
313
314 // /////////////////////////////////////////////////////////////////
315 // select_on - alternative add_dependent interface
316 // /////////////////////////////////////////////////////////////////
317
318 // NOTE: it would be useful to have this call return a handle to
319 // the thing we're observing so that we can stop observing just
320 // by deleting that handle!!! 
321
322 void
323 #if defined(SC3) || defined(__osf__) || defined(USL)
324 FolioObject::observe (FolioObject *real_this, FolioObject *target,
325 #else
326 FolioObject::observe (void *real_this, FolioObject *target,
327 #endif
328                       notify_handler_t handler, u_int notify_type,
329                       void *dependent_data)
330 {
331   // This routine will not work, because if target multiply inherits
332   // from FolioObject (like Agent) and FolioObject is not first inherited
333   // class, the this pointer in this routine will be offset from the
334   // real object this pointer, which will cause big problems when
335   // we try to call the callback which expects the real this pointer.
336   // ---
337   // OK, instead we will have to pass in the "real" this pointer which
338   // may be different from the this pointer visible in this routine. 
339 #if defined(SC3) || defined(__osf__) || defined(USL)
340   target->f_dependents =
341     new Dependent (&target->f_dependents, target->f_dependents,
342                    real_this, this,
343                    handler, notify_type, dependent_data);
344   assert( real_this == this );
345 #else
346   target->f_dependents =
347     new Dependent (&target->f_dependents, target->f_dependents,
348                    (FolioObject *) real_this, this,
349                    handler, notify_type, dependent_data);
350 #endif
351   ON_DEBUG(printf ("@@@ adding dependent %p to object %p for object %p\n",
352                    target->f_dependents, target, this));
353   f_depend_on_list =
354     new DependOnList (f_depend_on_list, target->f_dependents);
355 }
356
357 const char *
358 FolioObject::display_as()
359 {
360   return "Generic Folio Object"; 
361 }
362