Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / UAS / MMDB / MMDB_Factory.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 // $TOG: MMDB_Factory.C /main/15 1998/04/17 11:42:43 mgreess $
24 # include <stream.h>
25 # include "UAS_Exceptions.hh"
26 # include "MMDB_Factory.hh"
27 # include "UAS_Exceptions.hh"
28 # include "MMDB_EmbeddedObject.hh"
29 # include "MMDB_Library.hh"
30 # include "MMDB_BookCase.hh"
31 # include "MMDB_Section.hh"
32 # include "UAS_Collection.hh"
33
34 #include "Managers/CatMgr.hh"
35 #include "Registration.hh"
36
37 OLIAS_DB *MMDB_Factory::fOLIASDB = 0;
38
39 static MMDB_Factory  the_mmdb_factory; // instantiation
40
41 MMDB_Factory::MMDB_Factory ()
42 {
43     UAS_Factory::register_factory("mmdb", this);
44 }
45
46 MMDB_Factory::~MMDB_Factory ()
47 {
48     finalizeFactory ();
49     UAS_Factory::unregister_factory("mmdb");
50 }
51
52 OLIAS_DB &
53 MMDB_Factory::olias_db () {
54     if (fOLIASDB == 0) {
55         fOLIASDB = new OLIAS_DB ();
56     }
57     return *fOLIASDB;
58 }
59
60 MMDB *
61 MMDB_Factory::createMMDB (const UAS_String &infoLibPath) {
62     MMDB *rval = 0;
63     //
64     //  The MMDB leaks memory if we try to create an infolib
65     //  with a bogus path. This routine is called often with
66     //  infoLibPath == "", so we'll trap that case now
67     //
68     if (infoLibPath.length()) {
69         if (!olias_db().validInfoLibPath(infoLibPath)) {
70             UAS_ErrorMsg badPath;
71             char buf[BUFSIZ];
72             (void) sprintf (buf, CATGETS(Set_UAS_MMDB, 2,
73                                         "Invalid Infolib path: %s"),
74                                         (char *) infoLibPath);
75             badPath.fErrorMsg = buf;
76             UAS_Common::send_message (badPath);
77             return rval;
78         }
79         try {
80             rval = new MMDB (infoLibPath);
81             fMMDBList.append (rval);
82         } catch_any() {
83 #if 0
84             char buf[BUFSIZ];
85             (void) sprintf (buf, CATGETS(Set_UAS_MMDB, 3,
86                                         "Ignoring invalid Infolib path: %s"),
87                                         (char *) infoLibPath);
88             UAS_ErrorMsg theError;
89             theError.fErrorMsg = buf;
90             UAS_Common::send_message (theError);
91 #endif
92             rval = 0;
93         } end_try;
94     }
95     return rval;
96 }
97
98 // check to make sure duplicate infolibs are not added.
99 // for a duplicate infolib, just return a pointer to
100 // the already-existing infolib.
101 // (Duplicate infolib means infolibs with the same lid (uid))
102 MMDB *
103 MMDB_Factory::getMMDB (const UAS_String &infoLibPath) {
104     int i;
105     UAS_String uid(fOLIASDB->getInfoLibUid((char*)infoLibPath));
106     for (i = 0; i < fMMDBList.numItems(); i ++) {
107         if (uid == fMMDBList[i]->infoLibUid())
108             return fMMDBList[i];
109     }
110     for (i  = 0; i < fDeadMMDBList.numItems(); i ++) {
111         if (uid == fDeadMMDBList[i]->infoLibUid())
112             return fDeadMMDBList[i];
113     }
114     return createMMDB (infoLibPath);
115 }
116
117 void
118 MMDB_Factory::resolveLocator (const UAS_String &loc,
119                               MMDB *&returnMMDB,
120                               info_base *&returnInfoBase) {
121     returnMMDB = 0;
122     returnInfoBase = 0;
123     for (int i = 0; i < fMMDBList.numItems(); i ++) {
124         if (returnInfoBase = fMMDBList[i]->infolib()->
125                 getInfobaseByComponent(loc, info_lib::LOC)) {
126             returnMMDB = fMMDBList[i];
127             return;
128         }
129     }
130 }
131
132 MMDB *
133 MMDB_Factory::getMMDBFromObject (UAS_Pointer<UAS_Common> theDoc) {
134     if (theDoc->implementation_type() != "mmdb")
135         return 0;
136     switch (theDoc->type()) {
137         case UAS_LIBRARY: {
138             MMDB_Library *l = (MMDB_Library *) ((UAS_Common *) theDoc);
139             return &(l->mmdb());
140         }
141         case UAS_BOOKCASE: {
142             MMDB_BookCase *c = (MMDB_BookCase *) ((UAS_Common *) theDoc);
143             return &(c->mmdb());
144         }
145         case UAS_BOOK:
146         case UAS_SECTION: {
147             MMDB_Section *s =  (MMDB_Section *) ((UAS_Common *) theDoc);
148             return &(s->mmdb());
149         }
150         default:
151             return 0;
152     }
153 }
154
155 UAS_Pointer<UAS_Common>
156 MMDB_Factory::create_object (const UAS_String &locator) {
157     MMDB_URL curURL;
158     curURL.locator (locator);
159     MMDB *theMMDB = getMMDB (curURL.fInfoLib);
160     info_base *theInfoBase = 0;
161     if (theMMDB == 0) {
162         if (curURL.fLocator != "") {
163             resolveLocator (curURL.fLocator, theMMDB, theInfoBase);
164             if (theMMDB == 0) {
165                 throw (CASTEXCEPT Exception());
166             } else {
167                 UAS_Pointer<UAS_Common> rval =
168                     new MMDB_Section (*theMMDB, curURL.fLocator);
169                 if (curURL.fType == "collection")
170                     return new UAS_Collection (rval);
171                 return rval;
172             }
173         }
174     }
175
176     if (theMMDB && curURL.fLocator != "") {
177         UAS_Pointer<UAS_Common> rval =
178                 new MMDB_Section (*theMMDB, curURL.fLocator);
179         if (curURL.fType == "collection")
180             return new UAS_Collection (rval);
181         return rval;
182     } else if (theMMDB && curURL.fInfoBase != "") {
183         return new UAS_Collection(new MMDB_BookCase(*theMMDB,curURL.fInfoBase));
184     } else if (theMMDB && curURL.fInfoLib != "") {
185         return new UAS_Collection (new MMDB_Library(*theMMDB));
186     } else {
187         throw (CASTEXCEPT Exception());
188     }
189 }
190
191 UAS_Pointer<UAS_Common>
192 MMDB_Factory::create_relative_object (const UAS_String &locator,
193                                UAS_Pointer<UAS_Common> theDoc) {
194
195     //
196     //  First, try to get the object by using the current
197     //  MMDB information library.
198     //
199     MMDB *theMMDB = getMMDBFromObject (theDoc);
200     if (theMMDB) {
201         info_base *ib = theMMDB->infolib()->
202             getInfobaseByComponent(locator, info_lib::LOC);
203         if (ib) {
204             // need to pass precise id to the constructor
205             return new MMDB_Section (*theMMDB, locator);
206         }
207     }
208
209     //
210     //  Couldn't find it in theDoc's infolib. Try all the infolibs
211     //  we know about.
212     //
213     for (int i = 0; i < fMMDBList.numItems(); i ++) {
214         info_base *ib = fMMDBList[i]->infolib()->
215                 getInfobaseByComponent(locator, info_lib::LOC);
216         if (ib) {
217             // need to pass precise id to the constructor
218             return new MMDB_Section(*(fMMDBList[i]), locator);
219         }
220     }
221
222     return UAS_Pointer<UAS_Common>(NULL);
223 }
224
225 UAS_Pointer<UAS_EmbeddedObject>
226 MMDB_Factory::create_embedded_object (const UAS_String &locator) {
227     for (int i = 0; i < fMMDBList.numItems(); i ++) {
228         info_base *ib = fMMDBList[i]->infolib()->
229                 getInfobaseByComponent(locator, info_lib::GRA);
230         if (ib) {
231             return new MMDB_EmbeddedObject (*fMMDBList[i], ib, locator);
232         }
233     }
234     throw (CASTEXCEPT Exception());
235 }
236
237 UAS_Pointer<UAS_EmbeddedObject>
238 MMDB_Factory::create_relative_embedded_object (const UAS_String &locator,
239                                UAS_Pointer<UAS_Common> theDoc) {
240     //
241     //  First try resolving to theDoc's infolib
242     //
243     MMDB *theMMDB = getMMDBFromObject (theDoc);
244     if (theMMDB) {
245         info_base *ib = theMMDB->infolib()->
246                 getInfobaseByComponent(locator, info_lib::GRA);
247         if (ib) {
248             return new MMDB_EmbeddedObject (*theMMDB, ib, locator);
249         }
250     }
251
252     //
253     //  Cross-infolib link. Iterate through the list of infolibs.
254     //
255     for (int i = 0; i < fMMDBList.numItems(); i ++) {
256         info_base *ib = fMMDBList[i]->infolib()->
257                 getInfobaseByComponent(locator, info_lib::GRA);
258         if (ib) {
259             return new MMDB_EmbeddedObject (*(fMMDBList[i]), ib, locator);
260         }
261     }
262     throw (CASTEXCEPT Exception());
263 }
264
265 void
266 MMDB_Factory::initializeFactory (UAS_List<UAS_String>& libs) {
267     //
268     //  Take DTINFO_INFOLIB_PATH and split out the colon-separated
269     //  paths. Create an MMDB object for each path and, if creation
270     //  was successful, add it to our list of infolibs. Send messages
271     //  for each invalid 
272     //
273     //char *libenv = getenv ("DTINFO_INFOLIB_PATH");
274     //if (!libenv) {
275         //return;
276     //}
277     //UAS_String libstr (libenv);
278     //UAS_List<UAS_String> fields = libstr.splitFields (':');
279     //for (int i = 0; i < fields.length(); i ++) {
280         //(void) getMMDB (*(UAS_String*)fields[i]);
281     //}
282     for (int i = 0; i < libs.length(); i ++) {
283         //  If this call doesn't create a new MMDB, it sends
284         //  an error message to the application.
285         (void) getMMDB (*(UAS_String*)libs[i]);
286     }
287 }
288
289 void
290 MMDB_Factory::finalizeFactory () {
291     while (fMMDBList.numItems() > 0) {
292         MMDB *dead = fMMDBList[0];
293         fMMDBList.remove(dead);
294         delete dead;
295     }
296     while (fDeadMMDBList.numItems() > 0) {
297         MMDB *deaddead = fDeadMMDBList[0];
298         fDeadMMDBList.remove(deaddead);
299         delete deaddead;
300     }
301     delete fOLIASDB;
302     fOLIASDB = 0;
303 }
304
305 UAS_List<UAS_String>
306 MMDB_Factory::rootLocators () {
307     //
308     // CHANGE THIS TO BE UAS_ObjList...
309     //
310     UAS_List<UAS_String> rval;
311     for (int i = 0; i < fMMDBList.numItems(); i ++) {
312         MMDB_URL cur;
313         cur.fType = "collection";
314         cur.fInfoLib = fMMDBList[i]->infoLibPath();
315         rval.insert_item (new UAS_String (cur.locator()));
316     }
317     return rval;
318 }
319
320 void
321 MMDB_Factory::destroy_root_object (UAS_Pointer<UAS_Common> theRoot) {
322     if (theRoot->implementation_type() != "mmdb" ||
323         theRoot->type() != UAS_LIBRARY)
324         throw(CASTEXCEPT Exception());
325     MMDB_Library *theLib = (MMDB_Library *) (UAS_Common *) theRoot;
326     MMDB *deadMMDB = &(theLib->mmdb());
327     int i;
328     for (i = 0; i < fMMDBList.numItems(); i ++)
329         if (fMMDBList[i] == deadMMDB)
330             break;
331     if (i >= fMMDBList.numItems())
332         throw(CASTEXCEPT Exception());
333
334     // remove deadMMDB before sending msg because the user
335     // can possibly inquire mmdb list on the thread.
336     fMMDBList.remove (deadMMDB);
337
338     //  Give the user a chance to blow away all objects associated
339     //  with this library.
340     //
341     UAS_LibraryDestroyedMsg theMsg (theRoot);
342     UAS_Common::send_message (theMsg);
343
344     //  Do the final damage.
345     delete deadMMDB;
346 }
347
348 UAS_String
349 MMDB_Factory::genInfolibName () {
350     static int counter = 0;
351     char buf[BUFSIZ];
352     (void) sprintf (buf, CATGETS(Set_UAS_MMDB, 4, "DtMmdb Library %d"), ++counter);
353     return UAS_String (buf);
354 }
355
356 ///////////////////////////////////////////////////////////////////////////////
357 ///////////////////////////////////////////////////////////////////////////////
358 //
359 //  MMDB_URL
360 //
361 ///////////////////////////////////////////////////////////////////////////////
362 ///////////////////////////////////////////////////////////////////////////////
363
364 MMDB_URL::MMDB_URL () {
365 }
366
367 UAS_String
368 MMDB_URL::locator () {
369     UAS_String rval = "mmdb:";
370     int hasStuff = 0;
371     if (fInfoLib != "") {
372         rval = rval + "INFOLIB=" + fInfoLib;
373         hasStuff ++;
374     }
375     if (fInfoBase != "") {
376         if (hasStuff)
377             rval = rval + "&";
378         rval = rval + "BOOKCASE=" + fInfoBase;
379         hasStuff ++;
380     }
381     if (fLocator != "") {
382         if (hasStuff)
383             rval = rval + "&";
384         rval = rval + "LOCATOR=" + fLocator;
385         hasStuff ++;
386     }
387     if (fType == "") {
388         fType = "collection"; // default value
389     }
390     if (hasStuff)
391         rval = rval + "&";
392     rval = rval + "TYPE=" + fType;
393     hasStuff ++;
394
395     return rval;
396 }
397
398 void
399 MMDB_URL::installPair (const UAS_String &key, const UAS_String &value) {
400     if (key == "INFOLIB") {
401         fInfoLib = value;
402     } else if (key == "BOOKCASE") {
403         fInfoBase = value;
404     } else if (key == "TYPE") {
405         fType = value;
406     } else if (key == "LOCATOR") {
407         fLocator = value;
408     }
409 }
410
411 void
412 MMDB_URL::locator (const UAS_String &in) {
413     UAS_String access, rest;
414     in.split (':', access, rest);
415     UAS_List<UAS_String> pairs = rest.splitFields ('&');
416     for (int i = 0; i < pairs.length(); i ++) {
417         UAS_String key, value;
418         pairs[i]->split ('=', key, value);
419         installPair (key, value);
420     }
421 }
422