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