root/juggler/branches/1.0/Config/vjConfigChunk.cpp

Revision 8789, 16.0 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 #include <vjConfig.h>
36 #include <Config/vjConfigChunk.h>
37 #include <Config/vjParseUtil.h>
38 #include <Kernel/vjDebug.h>
39 #include <Config/vjChunkFactory.h>
40 #include <Config/vjChunkDesc.h>
41 #include <Config/vjConfigTokens.h>
42
43 #include <stdlib.h>
44 #include <ctype.h>
45
46
47
48 vjConfigChunk::vjConfigChunk (): props(), type_as_varvalue(T_STRING) {
49     desc = 0;
50     validation = 1;
51 }
52
53
54
55 vjConfigChunk::vjConfigChunk (vjChunkDesc *d) :props(), type_as_varvalue(T_STRING) {
56     validation = 1;
57     associateDesc (d);
58 }
59
60
61
62 vjConfigChunk::~vjConfigChunk () {
63     assertValid();
64
65     validation = 0;
66     /* XXX
67     for (unsigned int i = 0; i < props.size(); i++)
68         delete (props[i]);
69         */
70 }
71
72
73
74 vjConfigChunk::vjConfigChunk (const vjConfigChunk& c):props(), type_as_varvalue(T_STRING) {
75     validation = 1;
76     *this = c;
77 }
78
79
80
81 #ifdef VJ_DEBUG
82 void vjConfigChunk::assertValid () const {
83     assert (validation == 1 && "Trying to use deleted config chunk");
84     for (unsigned int i = 0; i < props.size(); i++)
85         props[i]->assertValid();
86 }
87 #endif
88
89
90
91 void vjConfigChunk::associateDesc (vjChunkDesc* d) {
92     assertValid();
93
94     unsigned int i;
95
96     desc = d;
97     type_as_varvalue = desc->getToken();
98
99     /* XXX:
100     for (i = 0; i < props.size(); i++)
101         delete (props[i]);
102     */
103     props.clear();
104
105     for (i = 0; i < desc->plist.size(); i++) {
106         vjPropertyDesc* pd = desc->plist[i];
107         vjProperty* pr = new vjProperty (pd);
108         props.push_back (pr);
109     }
110 }
111
112
113
114 vjConfigChunk& vjConfigChunk::operator = (const vjConfigChunk& c) {
115     assertValid();
116     c.assertValid();
117
118     unsigned int i;
119     if (this == &c)     // ack! same object!
120         return *this;
121
122     desc = c.desc;
123     type_as_varvalue = c.type_as_varvalue;
124
125     /* XXX:
126     for (i = 0; i < props.size(); i++)
127         delete (props[i]);
128         */
129     props.clear();
130
131     for (i = 0; i < c.props.size(); i++) {
132         props.push_back (new vjProperty(*(c.props[i])));
133     }
134     return *this;
135 }
136
137
138
139 //: tests for equality of two vjConfigChunks
140 bool vjConfigChunk::operator== (const vjConfigChunk& c) const {
141     assertValid();
142     c.assertValid();
143
144     // equality operator - this makes a couple of assumptions:
145     // 1. the descs must be the _same_object_, not just equal.
146     // 2. the properties will be in the _same_order_.  This is
147     //    reasonable if 1. is true.
148
149     if (desc != c.desc)
150         return false;
151     if (props.size() != c.props.size()) // probably redundant
152         return false;
153     for (unsigned int i = 0; i < props.size(); i++) {
154         if (*(props[i]) != *(c.props[i]))
155             return false;
156     }
157     return true;
158 }
159
160
161
162 //: Compares two vjConfigChunks based on their instance names
163 bool vjConfigChunk::operator< (const vjConfigChunk& c) const {
164     assertValid();
165
166     std::string s1 = getProperty ("name");
167     std::string s2 = c.getProperty ("name");
168     return s1 < s2;
169 }
170
171
172
173 //: Return a list of chunk names dependant upon this one
174 // This is used to sort a db by dependancy.
175 std::vector<std::string> vjConfigChunk::getChunkPtrDependencies() const
176 {
177     assertValid();
178
179    std::string chunkname;
180    std::vector<std::string> dep_list;     // Create return vector
181    unsigned int i;
182    int j;
183
184    //cout << "Dependency test for " << getProperty ("name") << endl;
185    for (i=0;i<props.size();i++)                       // For each property
186    {
187       if (props[i]->getType() == T_CHUNK)             // If it is a chunk ptr
188       {
189          for (j=0;j<props[i]->getNum();j++)           // For each property
190          {
191             vjVarValue prop_var_val = props[i]->getValue(j);
192             chunkname = static_cast<std::string>(prop_var_val);
193             if (!(chunkname == ""))
194             {
195                dep_list.push_back(chunkname);
196             }
197          }
198       }
199       else if (props[i]->getType() == T_EMBEDDEDCHUNK)
200       {
201          std::vector<std::string> child_deps;
202          for (j = 0; j < props[i]->getNum(); j++)
203          {
204             // XXX: if we ever have cyclic dependencies, we're in trouble
205             child_deps = ((vjConfigChunk*)props[i]->getValue(j))->getChunkPtrDependencies();
206             dep_list.insert (dep_list.end(), child_deps.begin(), child_deps.end());
207          }
208       }
209    }
210    return dep_list;      // Return the list
211 }
212
213
214
215 vjProperty* vjConfigChunk::getPropertyPtrFromName (const std::string& property) const {
216     assertValid();
217
218     for (unsigned int i = 0; i < props.size(); i++) {
219         if (!vjstrcasecmp (props[i]->getName(), property))
220             return props[i];
221     }
222     return NULL;
223 }
224
225
226
227 vjProperty* vjConfigChunk::getPropertyPtrFromToken (const std::string& token) const {
228     assertValid();
229
230     for (unsigned int i = 0; i < props.size(); i++) {
231         if (!vjstrcasecmp(props[i]->getToken(), token))
232             return props[i];
233     }
234     return NULL;
235 }
236
237
238
239 //: Return all the values for a given property
240 // This is just a simple helper function
241 //! NOTE: The vector has COPIES of the var values.
242 // cj - this is bad implementation... bad...
243 std::vector<vjVarValue*> vjConfigChunk::getAllProperties(const std::string& property)
244 {
245     assertValid();
246
247     int num_properties = getNum(property);
248     std::vector<vjVarValue*> ret_val;
249     for(int i=0;i<num_properties;i++) {
250         vjVarValue* new_var_val = new vjVarValue(getProperty(property,i));
251         ret_val.push_back(new_var_val);
252     }
253
254     return ret_val;
255 }
256
257
258
259 std::ostream& operator << (std::ostream& out, vjConfigChunk& self) {
260     self.assertValid();
261
262     // outputting an uninitialized chunk would be a mistake...
263     if (self.desc) {
264         out << self.desc->token.c_str() << std::endl;
265         for (unsigned int i =0; i < self.props.size(); i++) {
266             out << "  " << *(self.props[i]) << std::endl;
267         }
268         out << "  End" << std::endl;
269     }
270     return out;
271 }
272
273
274
275 bool vjConfigChunk::tryassign (vjProperty *p, int index, const char* val) {
276     assertValid();
277
278     /* This does some type-checking and translating before just
279      * doing an assign into the right value entry of p. Some of
280      * this functionality ought to just be subsumed by vjVarValue
281      * itself, but this way we get back some feedback about
282      * wether a type mismatch occurred (ie we return false if
283      * a type mismatch occurs ).
284      *
285      * Incidentally, this is also where string values get
286      * mangled into enumeration entries when assigning strings
287      * to T_INTs.
288      */
289     char* endval;
290     int i;
291     float f;
292     bool b;
293
294     if(p->getType() != T_CHUNK) {          // T_CHUNKS have enumeration, but they are really strings (or something)
295         vjEnumEntry* e = p->getEnumEntry (val);
296         if (e) {
297             p->setValue (e->getValue());
298             return true;
299         }
300     }
301
302     switch (p->getType()) {
303     case T_INT:
304         i = strtol (val, &endval, 0);
305         if (*endval != '\0')
306             vjDEBUG (vjDBG_CONFIG, 0) << clrOutNORM(clrYELLOW, "WARNING:") << " Parser expected int, got '"
307                   << val << "'\n" << vjDEBUG_FLUSH;
308         p->setValue (i, index);
309         return true;
310     case T_FLOAT:
311         f = (float)strtod (val, &endval);
312         if (*endval != '\0')
313             vjDEBUG (vjDBG_CONFIG, 0) << clrOutNORM(clrYELLOW, "WARNING:") << " Parser expected float, got '"
314                                       << val << "'\n" << vjDEBUG_FLUSH;
315         p->setValue (f, index);
316         return true;
317     case T_BOOL:
318         b = false;
319         if (!strcasecmp (val, true_TOKEN))
320             b = true;
321         else if (!strcasecmp (val, false_TOKEN))
322             b = false;
323         else { // we'll try to accept a numeric value
324             b = strtol (val, &endval, 0);
325             if (endval != '\0') {
326                 b = false;
327                 vjDEBUG (vjDBG_CONFIG,0) << clrOutNORM(clrYELLOW, "WARNING:") << " Parser expected bool, got '"
328                                          << val << "'\n" << vjDEBUG_FLUSH;
329             }
330         }
331         p->setValue (b, index);
332         return true;
333     case T_STRING:
334     case T_CHUNK:
335         p->setValue (val, index);
336         return true;
337     case T_EMBEDDEDCHUNK:
338         std::cout << "NOT HANDLED HERE!" << std::endl;
339         return false;
340     default:
341         return false;
342     }
343 }
344
345
346
347
348 std::istream& operator >> (std::istream& in, vjConfigChunk& self) {
349     self.assertValid();
350
351     /* can't really use property >> because we don't know what
352      * property to assign into.
353      */
354     const int buflen = 1024;
355     char buf[buflen];
356     vjProperty *p;
357     int i;
358     bool quoted;
359
360     // if this chunk hasn't been assigned a description yet, something's wrong
361     if (!self.desc)
362         return in;
363
364     while (readString (in, buf, buflen, NULL)) {
365
366         if (!strcasecmp (buf, end_TOKEN))
367             break;
368
369         // We have a string token; assumably a property name.
370         if (!(p = self.getPropertyPtrFromToken (buf))) {
371             vjDEBUG(vjDBG_ERROR,0) << clrOutNORM(clrRED, "ERROR:") << " Property '" << buf << "' is not found in"
372                                    << " Chunk " << self.desc->name.c_str() << std::endl << vjDEBUG_FLUSH;
373             continue;
374         }
375
376         // We're reading a line of input for a valid Property.
377         readString (in, buf, buflen, &quoted);
378
379         if (!quoted && (buf[0] == '{')) {
380             // We're reading values until we get a close bracket.
381             i = 0;
382             for (;;) {
383                 readString (in, buf, buflen, &quoted);
384                 if (!quoted && (buf[0] == '}'))
385                     break;
386
387                 // this works because the chunk >> expects the typename to have
388                 // already been read (which we did when looking for '}')
389                 if (p->getType() == T_EMBEDDEDCHUNK) {
390                     vjConfigChunk *ch = vjChunkFactory::instance()->createChunk (p->embeddesc);
391                     in >> *ch;
392                     p->setValue (ch, i++);
393                 }
394                 //       else if (tok.type == TK_Unit) {
395                 //           p->applyUnits (tok.unitval);
396                 //       }
397                 else {
398                     if (!self.tryassign (p, i++, buf))
399                         vjDEBUG(vjDBG_ERROR,2) << clrOutNORM(clrRED, "ERROR:") << " Assigning to property "
400                                                << p->getName().c_str() << std::endl << vjDEBUG_FLUSH;
401                 }
402             }
403
404             if (p->hasFixedNumberOfValues() && (p->num != i))
405                 vjDEBUG(vjDBG_ERROR,1) << clrOutNORM(clrRED, "ERROR:") << " vjProperty " << p->getName().c_str() << " should have "
406                                        << p->num << " values; " << i << " found" << std::endl << vjDEBUG_FLUSH;
407         }
408         else {
409             // we're just doing one value.
410             if (!self.tryassign (p, 0, buf))
411                 vjDEBUG(vjDBG_ERROR,1) << clrOutNORM(clrRED, "ERROR:") << " Assigning to property "
412                                        << p->getName().c_str() << std::endl << vjDEBUG_FLUSH;
413             //        self.getVJCFGToken (in,tok);
414             //        if (tok.type == TK_Unit) {
415             //       p->applyUnits (tok.unitval);
416             //       self.getVJCFGToken (in, tok);
417             //        }
418             if (p->num > 1) {
419                 vjDEBUG(vjDBG_ERROR,3) << clrOutNORM(clrRED, "ERROR:") << " Property " << p->getName().c_str()
420                                        << " expects " << p->num << " values." << std::endl << vjDEBUG_FLUSH;
421             }
422         }
423     }
424
425     return in;
426 }
427
428
429
430 int vjConfigChunk::getNum (const std::string& property_token) const {
431     assertValid();
432
433     vjProperty* p = getPropertyPtrFromToken (property_token);
434     if (p)
435         return p->getNum();
436     else
437         return 0;
438 }
439
440
441
442 const vjVarValue& vjConfigChunk::getType () const {
443     assertValid();
444
445     return type_as_varvalue;
446 }
447
448
449
450 const vjVarValue& vjConfigChunk::getProperty (const std::string& property_token, int ind) const {
451     assertValid();
452
453     if (!vjstrcasecmp(property_token,type_TOKEN)) {
454         return type_as_varvalue;
455     }
456
457     vjProperty *p = getPropertyPtrFromToken (property_token);
458     if (!p) {
459         vjDEBUG(vjDBG_CONFIG,2) << "getProperty(\"" << property_token.c_str() << "\") in chunk \""
460                                 << getProperty("Name") << "\" - no such property; returning T_INVALID\n" << vjDEBUG_FLUSH;
461         return vjVarValue::getInvalidInstance();
462     }
463     return p->getValue (ind);
464 }
465
466
467 /* we're probably gonna need to overload set for each kind of
468  * value.  That gets passed on to the vjVarValue assign...
469  */
470
471 bool vjConfigChunk::setProperty (const std::string& property, int val, int ind) {
472     assertValid();
473
474     vjProperty *p;
475     p = getPropertyPtrFromToken (property);
476     if (!p)
477         return false;
478     return p->setValue (val, ind);
479 }
480
481 bool vjConfigChunk::setProperty (const std::string& property, float val, int ind) {
482     assertValid();
483
484     vjProperty *p;
485     p = getPropertyPtrFromToken (property);
486     if (!p)
487         return false;
488     return p->setValue (val, ind);
489 }
490
491 bool vjConfigChunk::setProperty (const std::string& property, const std::string& val, int ind) {
492     assertValid();
493
494     vjProperty *p;
495     p = getPropertyPtrFromToken (property);
496     if (!p)
497         return false;
498     return p->setValue (val, ind);
499 }
500
501 bool vjConfigChunk::setProperty (const std::string& property, vjConfigChunk* val, int ind) {
502     assertValid();
503
504     vjProperty *p;
505     p = getPropertyPtrFromToken (property);
506     if (!p) {
507         vjDEBUG (vjDBG_ERROR, 1) << "ConfigChunk.setProperty: no such property " << property.c_str()
508                                  << "\n" << vjDEBUG_FLUSH;
509         return false;
510     }
511     return p->setValue (val, ind);
512 }
513
514
515 bool vjConfigChunk::addValue (const std::string& property, int val) {
516     assertValid();
517
518     vjProperty *p;
519     p = getPropertyPtrFromToken (property);
520     if (p == NULL)
521         return false;
522     if (p->hasFixedNumberOfValues())
523         return false;
524     return setProperty (property, val, p->value.size());
525 }
526
527 bool vjConfigChunk::addValue (const std::string& property, float val) {
528     assertValid();
529
530     vjProperty *p;
531     p = getPropertyPtrFromToken (property);
532     if (p == NULL)
533         return false;
534     if (p->hasFixedNumberOfValues())
535         return false;
536     return setProperty (property, val, p->value.size());
537 }
538
539 bool vjConfigChunk::addValue (const std::string& property, const std::string& val) {
540     assertValid();
541
542     vjProperty *p;
543     p = getPropertyPtrFromToken (property);
544     if (p == NULL)
545         return false;
546     if (p->hasFixedNumberOfValues())
547         return false;
548     return setProperty (property, val, p->value.size());
549 }
550
551 bool vjConfigChunk::addValue (const std::string& property, vjConfigChunk* val) {
552     assertValid();
553
554     vjProperty *p;
555     p = getPropertyPtrFromToken (property);
556     if (p == NULL)
557         return false;
558     if (p->hasFixedNumberOfValues())
559         return false;
560     return setProperty (property, val, p->value.size());
561 }
562
563
Note: See TracBrowser for help on using the browser.