root/juggler/tags/1.0.7/Config/vjConfigChunkDB.cpp

Revision 8789, 15.7 kB (checked in by patrickh, 7 years ago)

Copyright update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
2  *
3  * VR Juggler is (C) Copyright 1998, 1999, 2000, 2001, 2002
4  *   by Iowa State University
5  *
6  * Original Authors:
7  *   Allen Bierbaum, Christopher Just,
8  *   Patrick Hartling, Kevin Meinert,
9  *   Carolina Cruz-Neira, Albert Baker
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public
22  * License along with this library; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  *
26  * -----------------------------------------------------------------
27  * File:          $RCSfile$
28  * Date modified: $Date$
29  * Version:       $Revision$
30  * -----------------------------------------------------------------
31  *
32  *************** <auto-copyright.pl END do not edit this line> ***************/
33
34
35 // Implementation of vjConfigChunk DB
36 //
37 // Author: Christopher Just
38
39
40 #include <Config/vjConfigChunkDB.h>
41 #include <Config/vjChunkFactory.h>
42 #include <Config/vjParseUtil.h>
43 #include <Kernel/vjDebug.h>
44 #include <Config/vjConfigTokens.h>
45
46 #include <sys/types.h>
47
48
49 vjConfigChunkDB::vjConfigChunkDB (): chunks() {
50     ;
51 }
52
53
54
55 vjConfigChunkDB::~vjConfigChunkDB () {
56     // if ConfigChunkDBs ever start doing memory management of their
57     // ConfigChunks, do it here.
58 }
59
60
61
62 //: copy constructor
63 vjConfigChunkDB::vjConfigChunkDB (vjConfigChunkDB& db): chunks() {
64     *this = db;
65 }
66
67
68
69 vjConfigChunkDB& vjConfigChunkDB::operator = (vjConfigChunkDB& db) {
70     unsigned int i;
71     //for (i = 0; i < chunks.size(); i++)
72     //    delete chunks[i];
73     chunks.clear();
74     for (i = 0; i < db.chunks.size(); i++) {
75         chunks.push_back (new vjConfigChunk(*(db.chunks[i])));
76     }
77     return *this;
78 }
79
80
81
82 vjConfigChunk* vjConfigChunkDB::getChunk (const std::string& name) {
83     /* returns a chunk with the given name, if such exists, or NULL.
84      */
85     for (unsigned int i = 0; i < chunks.size(); i++) {
86         if (!vjstrcasecmp (name, chunks[i]->getProperty("name")))
87             return chunks[i];
88     }
89     return NULL;
90 }
91
92
93
94 // Return a copy of the chunks vector
95 std::vector<vjConfigChunk*> vjConfigChunkDB::getChunks() {
96     return chunks;
97 }
98
99
100
101 // Add the given chunks to the end of the chunk list
102 void vjConfigChunkDB::addChunks(std::vector<vjConfigChunk*> new_chunks) {
103     // no! must make copies of all chunks. sigh...
104     //chunks.insert(chunks.end(), new_chunks.begin(), new_chunks.end());
105     for (unsigned int i = 0; i < new_chunks.size(); i++)
106         addChunk (new vjConfigChunk (*new_chunks[i]));
107 }
108
109
110
111 void vjConfigChunkDB::addChunks(vjConfigChunkDB *db) {
112     addChunks (db->chunks);
113 }
114
115
116
117 void vjConfigChunkDB::addChunk(vjConfigChunk* new_chunk) {
118     removeNamed (new_chunk->getProperty("Name"));
119     chunks.push_back (new_chunk);
120 }
121
122
123
124
125 // GetMatching: These functions return a vector of all chunks with a
126 // property named by the first argument, and a value defined by the
127 // second argument.  The returned vector may be empty.
128 // NOTE:  The caller is responsible for delete()ing the vector, but not
129 // its contents.
130 std::vector<vjConfigChunk*>* vjConfigChunkDB::getMatching (const std::string& property, const std::string value) {
131     std::vector<vjConfigChunk*>* v = new std::vector<vjConfigChunk*>;
132
133     for (unsigned int i = 0; i < chunks.size(); i++) {
134         if (!vjstrcasecmp (value, chunks[i]->getProperty(property)))
135             v->push_back(chunks[i]);
136     }
137     return v;
138 }
139
140 std::vector<vjConfigChunk*>* vjConfigChunkDB::getMatching (const std::string& property, int value) {
141     int c;
142     std::vector<vjConfigChunk*>* v = new std::vector<vjConfigChunk*>;
143     for (unsigned int i = 0; i < chunks.size(); i++) {
144         c = chunks[i]->getProperty(property);
145         if (c == value)
146             v->push_back(chunks[i]);
147     }
148     return v;
149 }
150
151
152 std::vector<vjConfigChunk*>* vjConfigChunkDB::getMatching (const std::string& property, float value) {
153     float c;
154     std::vector<vjConfigChunk*>* v = new std::vector<vjConfigChunk*>;
155     for (unsigned int i = 0; i < chunks.size(); i++) {
156         c = chunks[i]->getProperty(property);
157         if (c == value)
158             v->push_back(chunks[i]);
159     }
160     return v;
161 }
162
163
164
165 bool vjConfigChunkDB::erase () {
166     /* removes all chunks from self (and frees them)
167      */
168     //for (unsigned int i = 0; i < chunks.size(); i++)
169     //delete (chunks[i]);
170     chunks.clear();
171     return true;
172 }
173
174
175
176 // Removes (and frees all memory associated with) all chunks with a property
177 // named by the first argument with a value defined by the second argument.
178 int vjConfigChunkDB::removeMatching (const std::string& property, int value) {
179     int i = 0;
180     int c;
181     std::vector<vjConfigChunk*>::iterator cur_chunk = chunks.begin();
182     while (cur_chunk != chunks.end()) {
183         c = (*cur_chunk)->getProperty(property);
184         if (c == value) {
185             //delete (*next);
186             cur_chunk = chunks.erase(cur_chunk);
187             i++;
188         }
189         else
190             cur_chunk++;
191     }
192     return i;
193 }
194
195 int vjConfigChunkDB::removeMatching (const std::string& property, float value) {
196     int i = 0;
197     float c;
198
199     std::vector<vjConfigChunk*>::iterator cur_chunk = chunks.begin();
200     while (cur_chunk != chunks.end()) {
201         c = (*cur_chunk)->getProperty(property);
202         if (c == value) {
203             //delete (*cur_chunk);
204             cur_chunk = chunks.erase(cur_chunk);
205             i++;
206         }
207         else
208             cur_chunk++;
209     }
210     return i;
211 }
212
213 int vjConfigChunkDB::removeMatching (const std::string& property, const std::string& value) {
214
215     int i = 0;
216     std::vector<vjConfigChunk*>::iterator cur_chunk = chunks.begin();
217     while (cur_chunk != chunks.end()) {
218         vjVarValue v = ((*cur_chunk)->getProperty(property));
219         if (((v.getType() == T_STRING) || (v.getType() == T_STRING))
220             &&  (!vjstrcasecmp (value, (std::string)v))) {
221             //delete (*begin);
222             cur_chunk = chunks.erase(cur_chunk);
223             i++;
224         }
225         else
226             cur_chunk++;
227     }
228
229     return i;
230 }
231
232
233
234 //: Sorts the chunks based on dependancies of chunk ptrs
235 //! PRE: we need a "good object"
236 //! MODIFIES: self.  We move the objects around so they are sorted
237 //! ARGS: auxChunks - Auxilary chunks that have been loaded already
238 //! POST: Topologically sorted
239 // Copy the chunks over to a new list.  Repetatively try to
240 // find an item in the source list that already has it's dependencies
241 // copied into the dst list.  Do this iteratively until done or
242 // until fail.
243 int vjConfigChunkDB::dependencySort(vjConfigChunkDB* auxChunks)
244 {
245     // Print out dependancies
246 #ifdef VJ_DEBUG
247     vjDEBUG_BEGIN(vjDBG_CONFIG,4) << "---- Dependencies -----------\n" << vjDEBUG_FLUSH;
248     for (unsigned int i=0;i<chunks.size();i++) {
249         vjDEBUG(vjDBG_CONFIG,4) << "Chunk:" << chunks[i]->getProperty("name")
250                                 << std::endl << "\tDepends on:\n"
251                                 << vjDEBUG_FLUSH;
252         std::vector<std::string> deps = chunks[i]->getChunkPtrDependencies();
253         if (deps.size() > 0) {
254             for (unsigned int j=0;j<deps.size();j++)
255                 vjDEBUG(vjDBG_CONFIG,4) << "   " << j << ": "
256                                         << deps[j].c_str() << std::endl
257                                         << vjDEBUG_FLUSH;
258         } else {
259             vjDEBUG(vjDBG_CONFIG,4) << "   Nothing.\n" << vjDEBUG_FLUSH;
260         }
261     }
262     vjDEBUG_END(vjDBG_CONFIG,4) << "-----------------------------\n" << vjDEBUG_FLUSH;
263 #endif
264
265
266     // --- THE SORT --- //
267     // Create new src list to work from
268     // Targetting the local data
269     // So basically, we take an element from the src list one at a time
270     // If it's dependencies are already in the local list, add it to the local list
271     // else go on to the next one
272     // Kinda like an insertion sort
273     std::vector<vjConfigChunk*> src_chunks = chunks;
274     chunks = std::vector<vjConfigChunk*>(0);        // Chunks is the local data - Zero it out to start
275
276     bool dep_pass(true);             // Flag for Pass dependency check
277     std::vector<std::string> deps;   // Dependencies of current item
278     std::vector<vjConfigChunk*>::iterator cur_item = src_chunks.begin();          // The current src item to look at
279
280     while (cur_item != src_chunks.end()) {          // While not at end of src list
281         vjDEBUG(vjDBG_CONFIG,4) << "Checking depencies for: " << (*cur_item)->getProperty("name") << "\n" << vjDEBUG_FLUSH;
282
283         deps = (*cur_item)->getChunkPtrDependencies();             // Get src dependencies
284         for (unsigned int dep_num=0;dep_num<deps.size();dep_num++) {  // For each dependency
285             bool dep_not_found = (getChunk(deps[dep_num]) == NULL);
286             bool aux_dep_not_found = ((auxChunks == NULL) ||
287                                       (auxChunks->getChunk(deps[dep_num]) == NULL));
288
289             // If dependency not in list yet or in aux buffer
290             // If (not in src && (!aux exists || not in aux))
291             if ( dep_not_found && aux_dep_not_found )
292                 dep_pass = false;                                   // Failed check (we don't pass)
293         }
294
295         if (dep_pass) {        // If all dependencies are accounted for
296             addChunk(*cur_item);        // Copy src to dst
297             src_chunks.erase(cur_item);         // Erase it from source
298             cur_item = src_chunks.begin();      // Goto first item
299         } else
300             cur_item++;             // Try next item
301
302         dep_pass = true;           // Reset to passing
303     }
304
305     // ASSERT: (Done with sort)
306     //   Either, all depencies have been accounted for and the src list is empty
307     //   OR we went all the way through list without finding an item that passes
308
309     if (src_chunks.size() > 0) {     // Items left, so we failed to get all dependencies
310         // ouput error
311         for (unsigned int i=0;i<src_chunks.size();i++) {
312             vjDEBUG(vjDBG_ERROR,0) << clrOutNORM(clrRED, "ERROR:") << " Dependency error:  Chunk:" << src_chunks[i]->getProperty("name")
313                                    << "\tDepends on: \n" << vjDEBUG_FLUSH;
314             std::vector<std::string> deps = src_chunks[i]->getChunkPtrDependencies();
315             if (deps.size() > 0) {
316                 for (unsigned int j=0;j<deps.size();j++)
317                     vjDEBUG(vjDBG_ERROR,0) << "\tdep " << j << ": "
318                                            << deps[j].c_str() << std::endl
319                                            << vjDEBUG_FLUSH;
320             } else {
321                 vjDEBUG(vjDBG_ERROR,0) << "Nothing.\n" << vjDEBUG_FLUSH;
322             }
323             vjDEBUG(vjDBG_ERROR,0) << "Check for undefined devices that others depend upon.\n" << vjDEBUG_FLUSH;
324         }
325         chunks.insert(chunks.end(), src_chunks.begin(), src_chunks.end());   // Copy over the rest anyway
326
327         return -1;
328     } else {
329         // Print out sorted dependancies
330 #ifdef VJ_DEBUG
331
332         vjDEBUG_BEGIN(vjDBG_CONFIG,4) << "---- After sort ----" << std::endl << vjDEBUG_FLUSH;
333         for (unsigned int i=0;i<chunks.size();i++) {
334             vjDEBUG(vjDBG_CONFIG,4) << "Chunk:" << chunks[i]->getProperty("name") << std::endl
335                                     << "\tDepends on:\n" << vjDEBUG_FLUSH;
336             std::vector<std::string> deps = chunks[i]->getChunkPtrDependencies();
337             if (deps.size() > 0) {
338                 for (unsigned int j=0;j<deps.size();j++)
339                     vjDEBUG(vjDBG_CONFIG,4) << "   " << j << ": " << deps[j].c_str() << std::endl << vjDEBUG_FLUSH;
340             } else {
341                 vjDEBUG(vjDBG_CONFIG,4) << "   Nothing.\n" << vjDEBUG_FLUSH;
342             }
343         }
344         vjDEBUG_END(vjDBG_CONFIG,4) << "-----------------\n" << vjDEBUG_FLUSH;
345 #endif
346
347         return 0;      // Success
348     }
349 }
350
351
352
353 /* IO functions: */
354
355 std::ostream& operator << (std::ostream& out, vjConfigChunkDB& self) {
356     for (unsigned int i = 0; i < self.chunks.size(); i++) {
357         out << *(self.chunks[i]) << std::endl;
358     }
359     out << "End" << std::endl;
360     return out;
361 }
362
363
364
365 std::istream& operator >> (std::istream& in, vjConfigChunkDB& self) {
366
367     const int bufsize = 512;
368     char str[bufsize];
369     vjConfigChunk *ch;
370
371     do {
372         if (!readString (in, str, bufsize))
373             break; /* eof */
374         if (!strcasecmp (str, end_TOKEN))
375             break;
376
377         std::string newstr = str;
378         ch = vjChunkFactory::instance()->createChunk (newstr);
379         if (ch == NULL) {
380             vjDEBUG(vjDBG_ERROR,0) << clrOutNORM(clrRED, "ERROR:") << " Unknown Chunk type: " << str << std::endl
381                                    << vjDEBUG_FLUSH;
382             // skip to end of chunk
383             while (strcasecmp (str, end_TOKEN)) {
384                 if (0 == readString (in, str, bufsize))
385                     break;
386                 //std::cerr << "read " << str << std::endl;
387             }
388         }
389         else {
390             in >> *ch;
391
392             //std::cerr << "read chunk: " << *ch << std::endl;
393
394             if (!vjstrcasecmp (ch->getType(), "vjIncludeFile")) {
395                 // this is another one of those bits of code where we need to make some
396                 // real decisions about memory management of ConfigChunks
397                 std::string s = ch->getProperty ("Name");
398                 vjConfigChunkDB newdb;
399                 newdb.load (s, self.file_name);
400                 self.addChunks(&newdb);
401             }
402             else if (!vjstrcasecmp (ch->getType(), "vjIncludeDescFile")) {
403                 // the descs could be needed by everybody else in this file,
404                 // so load 'em now...
405                 std::string s = ch->getProperty ("Name");
406                 vjChunkDescDB newdb;
407                 newdb.load (s, self.file_name);
408                 vjChunkFactory::instance()->addDescs (&newdb);
409             }
410             else {
411                 // just a plain old chunk to add in...
412                 self.addChunk(ch);
413             }
414         }
415     } while (!in.eof());
416
417     vjDEBUG(vjDBG_CONFIG,3) << "vjConfigChunkDB::>> : Finished - "
418                             << self.chunks.size() << " chunks read."
419                             << std::endl << vjDEBUG_FLUSH;
420
421     return in;
422 }
423
424
425
426
427
428
429 bool vjConfigChunkDB::load (const std::string& filename, const std::string& parentfile) {
430     file_name = demangleFileName (filename, parentfile);
431
432     std::ifstream in(file_name.c_str());
433
434     vjDEBUG(vjDBG_CONFIG,3) << "vjConfigChunkDB::load(): opening file " << file_name.c_str() << " -- " << vjDEBUG_FLUSH;
435
436
437     if (!in) {
438         vjDEBUG(vjDBG_ALL,0) << "\nvjConfigChunkDB::load(): Unable to open file '"
439                              << file_name.c_str() << "'" << std::endl << vjDEBUG_FLUSH;
440         return false;
441     }
442     vjDEBUG(vjDBG_CONFIG,5) << " succeeded.\n" << vjDEBUG_FLUSH;
443     in >> *this;
444     vjDEBUG(vjDBG_CONFIG,3) << " finished.. read " << chunks.size() << " chunks\n"
445                             << vjDEBUG_FLUSH;
446     return true;
447 }
448
449
450
451 bool vjConfigChunkDB::save (const std::string& fname) {
452
453     std::ofstream out(fname.c_str());
454     if (!out) {
455         vjDEBUG(vjDBG_ERROR,1) << clrOutNORM(clrRED, "ERROR:") << " vjConfigChunkDB::save() - Unable to open file '"
456                                << fname.c_str() << "'\n" << vjDEBUG_FLUSH;
457         return false;
458     }
459     out << *this;
460     return true;
461 }
462
463
464
465 bool vjConfigChunkDB::isEmpty() {
466     return (chunks.size() == 0);
467 }
468
469
470
471 void vjConfigChunkDB::removeAll() {
472     // just an alias
473     erase();
474 }
475
476
477
478 int vjConfigChunkDB::removeNamed (const std::string& name) {
479     return removeMatching ("Name", name);
480 }
481
Note: See TracBrowser for help on using the browser.