]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
Patch from Tony Peden to remove unused variable and eliminate compiler
[simgear.git] / simgear / misc / props.cxx
1 // props.cxx - implementation of a property list.
2 // Started Fall 2000 by David Megginson, david@megginson.com
3 // This code is released into the Public Domain.
4 //
5 // See props.html for documentation [replace with URL when available].
6 //
7 // $Id$
8
9 #include "props.hxx"
10
11 #if PROPS_STANDALONE
12
13 #include <iostream>
14 using std::cerr;
15 using std::endl;
16 using std::sort;
17
18 #else
19
20 #include <simgear/compiler.h>
21 #include <simgear/debug/logstream.hxx>
22
23 SG_USING_STD(sort);
24
25 #endif
26
27 #include <algorithm>
28 #include <stdio.h>
29 #include <string.h>
30
31
32 \f
33 ////////////////////////////////////////////////////////////////////////
34 // Local classes.
35 ////////////////////////////////////////////////////////////////////////
36
37 /**
38  * Comparator class for sorting by index.
39  */
40 class CompareIndices
41 {
42 public:
43   int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
44     return (n1->getIndex() < n2->getIndex());
45   }
46 };
47
48
49 \f
50 ////////////////////////////////////////////////////////////////////////
51 // Convenience macros for value access.
52 ////////////////////////////////////////////////////////////////////////
53
54 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
55 #define TEST_WRITE if (!getAttribute(WRITE)) return false
56
57
58 \f
59 ////////////////////////////////////////////////////////////////////////
60 // Default values for every type.
61 ////////////////////////////////////////////////////////////////////////
62
63 const bool SGRawValue<bool>::DefaultValue = false;
64 const int SGRawValue<int>::DefaultValue = 0;
65 const long SGRawValue<long>::DefaultValue = 0L;
66 const float SGRawValue<float>::DefaultValue = 0.0;
67 const double SGRawValue<double>::DefaultValue = 0.0L;
68 const char * const SGRawValue<const char *>::DefaultValue = "";
69
70
71 \f
72 ////////////////////////////////////////////////////////////////////////
73 // Local path normalization code.
74 ////////////////////////////////////////////////////////////////////////
75
76 /**
77  * A component in a path.
78  */
79 struct PathComponent
80 {
81   string name;
82   int index;
83 };
84
85 /**
86  * Parse the name for a path component.
87  *
88  * Name: [_a-zA-Z][-._a-zA-Z0-9]*
89  */
90 static inline const string
91 parse_name (const string &path, int &i)
92 {
93   string name = "";
94   int max = path.size();
95
96   if (path[i] == '.') {
97     i++;
98     if (i < max && path[i] == '.') {
99       i++;
100       name = "..";
101     } else {
102       name = ".";
103     }
104     if (i < max && path[i] != '/')
105       throw string(string("Illegal character after ") + name);
106   }
107
108   else if (isalpha(path[i]) || path[i] == '_') {
109     name += path[i];
110     i++;
111
112                                 // The rules inside a name are a little
113                                 // less restrictive.
114     while (i < max) {
115       if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
116           path[i] == '-' || path[i] == '.') {
117         name += path[i];
118       } else if (path[i] == '[' || path[i] == '/') {
119         break;
120       } else {
121         throw string("name may contain only ._- and alphanumeric characters");
122       }
123       i++;
124     }
125   }
126
127   else {
128     if (name.size() == 0)
129       throw string("name must begin with alpha or '_'");
130   }
131
132   return name;
133 }
134
135
136 /**
137  * Parse the optional integer index for a path component.
138  *
139  * Index: "[" [0-9]+ "]"
140  */
141 static inline int
142 parse_index (const string &path, int &i)
143 {
144   int index = 0;
145
146   if (path[i] != '[')
147     return 0;
148   else
149     i++;
150
151   for (int max = path.size(); i < max; i++) {
152     if (isdigit(path[i])) {
153       index = (index * 10) + (path[i] - '0');
154     } else if (path[i] == ']') {
155       i++;
156       return index;
157     } else {
158       break;
159     }
160   }
161
162   throw string("unterminated index (looking for ']')");
163 }
164
165
166 /**
167  * Parse a single path component.
168  *
169  * Component: Name Index?
170  */
171 static inline PathComponent
172 parse_component (const string &path, int &i)
173 {
174   PathComponent component;
175   component.name = parse_name(path, i);
176   if (component.name[0] != '.')
177     component.index = parse_index(path, i);
178   else
179     component.index = -1;
180   return component;
181 }
182
183
184 /**
185  * Parse a path into its components.
186  */
187 static void
188 parse_path (const string &path, vector<PathComponent> &components)
189 {
190   int pos = 0;
191   int max = path.size();
192
193                                 // Check for initial '/'
194   if (path[pos] == '/') {
195     PathComponent root;
196     root.name = "";
197     root.index = -1;
198     components.push_back(root);
199     pos++;
200     while (pos < max && path[pos] == '/')
201       pos++;
202   }
203
204   while (pos < max) {
205     components.push_back(parse_component(path, pos));
206     while (pos < max && path[pos] == '/')
207       pos++;
208   }
209 }
210
211
212 \f
213 ////////////////////////////////////////////////////////////////////////
214 // Other static utility functions.
215 ////////////////////////////////////////////////////////////////////////
216
217
218 static const char *
219 copy_string (const char * s)
220 {
221                                 // FIXME: potential buffer overflow.
222                                 // For some reason, strnlen and
223                                 // strncpy cause all kinds of crashes.
224   string str = s;
225   char * copy = new char[str.size() + 1];
226   strcpy(copy, str.c_str());
227   return copy;
228 }
229
230 static bool
231 compare_strings (const char * s1, const char * s2)
232 {
233   return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
234 }
235
236 /**
237  * Locate a child node by name and index.
238  */
239 static int
240 find_child (const char * name, int index, vector<SGPropertyNode *> nodes)
241 {
242   int nNodes = nodes.size();
243   for (int i = 0; i < nNodes; i++) {
244     SGPropertyNode * node = nodes[i];
245     if (compare_strings(node->getName(), name) && node->getIndex() == index)
246       return i;
247   }
248   return -1;
249 }
250
251
252 /**
253  * Locate another node, given a relative path.
254  */
255 static SGPropertyNode *
256 find_node (SGPropertyNode * current,
257            const vector<PathComponent> &components,
258            int position,
259            bool create)
260 {
261                                 // Run off the end of the list
262   if (current == 0) {
263     return 0;
264   }
265
266                                 // Success! This is the one we want.
267   else if (position >= (int)components.size()) {
268     return current;
269   }
270
271                                 // Empty component means root.
272   else if (components[position].name == "") {
273     return find_node(current->getRootNode(), components, position + 1, create);
274   }
275
276                                 // . means current directory
277   else if (components[position].name == ".") {
278     return find_node(current, components, position + 1, create);
279   }
280
281                                 // .. means parent directory
282   else if (components[position].name == "..") {
283     SGPropertyNode * parent = current->getParent();
284     if (parent == 0)
285       throw string("Attempt to move past root with '..'");
286     else
287       return find_node(parent, components, position + 1, create);
288   }
289
290                                 // Otherwise, a child name
291   else {
292     SGPropertyNode * child =
293       current->getChild(components[position].name.c_str(),
294                         components[position].index,
295                         create);
296     return find_node(child, components, position + 1, create);
297   }
298 }
299
300
301 \f
302 ////////////////////////////////////////////////////////////////////////
303 // Private methods from SGPropertyNode (may be inlined for speed).
304 ////////////////////////////////////////////////////////////////////////
305
306 inline bool
307 SGPropertyNode::get_bool () const
308 {
309   if (_tied)
310     return _value.bool_val->getValue();
311   else
312     return _local_val.bool_val;
313 }
314
315 inline int
316 SGPropertyNode::get_int () const
317 {
318   if (_tied)
319     return _value.int_val->getValue();
320   else
321     return _local_val.int_val;
322 }
323
324 inline long
325 SGPropertyNode::get_long () const
326 {
327   if (_tied)
328     return _value.long_val->getValue();
329   else
330     return _local_val.long_val;
331 }
332
333 inline float
334 SGPropertyNode::get_float () const
335 {
336   if (_tied)
337     return _value.float_val->getValue();
338   else
339     return _local_val.float_val;
340 }
341
342 inline double
343 SGPropertyNode::get_double () const
344 {
345   if (_tied)
346     return _value.double_val->getValue();
347   else
348     return _local_val.double_val;
349 }
350
351 inline const char *
352 SGPropertyNode::get_string () const
353 {
354   if (_tied)
355     return _value.string_val->getValue();
356   else
357     return _local_val.string_val;
358 }
359
360 inline bool
361 SGPropertyNode::set_bool (bool val)
362 {
363   if (_tied) {
364     return _value.bool_val->setValue(val);
365   } else {
366     _local_val.bool_val = val;
367     return true;
368   }
369 }
370
371 inline bool
372 SGPropertyNode::set_int (int val)
373 {
374   if (_tied) {
375     return _value.int_val->setValue(val);
376   } else {
377     _local_val.int_val = val;
378     return true;
379   }
380 }
381
382 inline bool
383 SGPropertyNode::set_long (long val)
384 {
385   if (_tied) {
386     return _value.long_val->setValue(val);
387   } else {
388     _local_val.long_val = val;
389     return true;
390   }
391 }
392
393 inline bool
394 SGPropertyNode::set_float (float val)
395 {
396   if (_tied) {
397     return _value.float_val->setValue(val);
398   } else {
399     _local_val.float_val = val;
400     return true;
401   }
402 }
403
404 inline bool
405 SGPropertyNode::set_double (double val)
406 {
407   if (_tied) {
408     return _value.double_val->setValue(val);
409   } else {
410     _local_val.double_val = val;
411     return true;
412   }
413 }
414
415 inline bool
416 SGPropertyNode::set_string (const char * val)
417 {
418   if (_tied) {
419     return _value.string_val->setValue(val);
420   } else {
421     delete _local_val.string_val;
422     _local_val.string_val = copy_string(val);
423     return true;
424   }
425 }
426
427 void
428 SGPropertyNode::clear_value ()
429 {
430   switch (_type) {
431   case NONE:
432   case ALIAS:
433     _value.alias = 0;
434     break;
435   case BOOL:
436     delete _value.bool_val;
437     _value.bool_val = 0;
438     _local_val.bool_val = SGRawValue<bool>::DefaultValue;
439     break;
440   case INT:
441     delete _value.int_val;
442     _value.int_val = 0;
443     _local_val.int_val = SGRawValue<int>::DefaultValue;
444     break;
445   case LONG:
446     delete _value.long_val;
447     _value.long_val = 0L;
448     _local_val.long_val = SGRawValue<long>::DefaultValue;
449     break;
450   case FLOAT:
451     delete _value.float_val;
452     _value.float_val = 0;
453     _local_val.float_val = SGRawValue<float>::DefaultValue;
454     break;
455   case DOUBLE:
456     delete _value.double_val;
457     _value.double_val = 0;
458     _local_val.double_val = SGRawValue<double>::DefaultValue;
459     break;
460   case STRING:
461   case UNSPECIFIED:
462     delete _value.string_val;
463     _value.string_val = 0;
464     delete _local_val.string_val;
465     _local_val.string_val = 0;
466     break;
467   }
468   _tied = false;
469   _type = NONE;
470 }
471
472
473 /**
474  * Get the value as a string.
475  */
476 const char *
477 SGPropertyNode::make_string () const
478 {
479   if (!getAttribute(READ))
480     return "";
481
482   switch (_type) {
483   case ALIAS:
484     return _value.alias->getStringValue();
485   case BOOL:
486     if (get_bool())
487       return "true";
488     else
489       return "false";
490   case INT:
491     sprintf(_buffer, "%d", get_int());
492     return _buffer;
493   case LONG:
494     sprintf(_buffer, "%ld", get_long());
495     return _buffer;
496   case FLOAT:
497     sprintf(_buffer, "%f", get_float());
498     return _buffer;
499   case DOUBLE:
500     sprintf(_buffer, "%f", get_double());
501     return _buffer;
502   case STRING:
503   case UNSPECIFIED:
504     return get_string();
505   case NONE:
506   default:
507     return "";
508   }
509 }
510
511 /**
512  * Trace a write access for a property.
513  */
514 void
515 SGPropertyNode::trace_write () const
516 {
517 #if PROPS_STANDALONE
518   cerr << "TRACE: Write node " << getPath () << ", value\""
519        << make_string() << '"' << endl;
520 #else
521   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
522          << ", value\"" << make_string() << '"');
523 #endif
524 }
525
526 /**
527  * Trace a read access for a property.
528  */
529 void
530 SGPropertyNode::trace_read () const
531 {
532 #if PROPS_STANDALONE
533   cerr << "TRACE: Write node " << getPath () << ", value \""
534        << make_string() << '"' << endl;
535 #else
536   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
537          << ", value \"" << make_string() << '"');
538 #endif
539 }
540
541
542 \f
543 ////////////////////////////////////////////////////////////////////////
544 // Public methods from SGPropertyNode.
545 ////////////////////////////////////////////////////////////////////////
546
547 /**
548  * Default constructor: always creates a root node.
549  */
550 SGPropertyNode::SGPropertyNode ()
551   : _name(copy_string("")),
552     _index(0),
553     _parent(0),
554     _path_cache(0),
555     _type(NONE),
556     _tied(false),
557     _attr(READ|WRITE)
558 {
559   _local_val.string_val = 0;
560 }
561
562
563 /**
564  * Copy constructor.
565  */
566 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
567   : _index(node._index),
568     _parent(0),                 // don't copy the parent
569     _path_cache(0),
570     _type(node._type),
571     _tied(node._tied),
572     _attr(node._attr)
573 {
574   _name = copy_string(node._name);
575   _local_val.string_val = 0;
576   switch (_type) {
577   case NONE:
578     break;
579   case ALIAS:
580     _value.alias = node._value.alias;
581     _tied = false;
582     break;
583   case BOOL:
584     if (_tied) {
585       _tied = true;
586       _value.bool_val = node._value.bool_val->clone();
587     } else {
588       _tied = false;
589       set_bool(node.get_bool());
590     }
591     break;
592   case INT:
593     if (_tied) {
594       _tied = true;
595       _value.int_val = node._value.int_val->clone();
596     } else {
597       _tied = false;
598       set_int(node.get_int());
599     }
600     break;
601   case LONG:
602     if (_tied) {
603       _tied = true;
604       _value.long_val = node._value.long_val->clone();
605     } else {
606       _tied = false;
607       set_long(node.get_long());
608     }
609     break;
610   case FLOAT:
611     if (_tied) {
612       _tied = true;
613       _value.float_val = node._value.float_val->clone();
614     } else {
615       _tied = false;
616       set_float(node.get_float());
617     }
618     break;
619   case DOUBLE:
620     if (_tied) {
621       _tied = true;
622       _value.double_val = node._value.double_val->clone();
623     } else {
624       _tied = false;
625       set_double(node.get_double());
626     }
627     break;
628   case STRING:
629   case UNSPECIFIED:
630     if (_tied) {
631       _tied = true;
632       _value.string_val = node._value.string_val->clone();
633     } else {
634       _tied = false;
635       set_string(node.get_string());
636     }
637     break;
638   }
639 }
640
641
642 /**
643  * Convenience constructor.
644  */
645 SGPropertyNode::SGPropertyNode (const char * name,
646                                 int index,
647                                 SGPropertyNode * parent)
648   : _index(index),
649     _parent(parent),
650     _path_cache(0),
651     _type(NONE),
652     _tied(false),
653     _attr(READ|WRITE)
654 {
655   _name = copy_string(name);
656   _local_val.string_val = 0;
657 }
658
659
660 /**
661  * Destructor.
662  */
663 SGPropertyNode::~SGPropertyNode ()
664 {
665   delete _name;
666   for (int i = 0; i < (int)_children.size(); i++) {
667     delete _children[i];
668   }
669 //   delete _path_cache;
670   clear_value();
671 }
672
673
674 /**
675  * Alias to another node.
676  */
677 bool
678 SGPropertyNode::alias (SGPropertyNode * target)
679 {
680   if (target == 0 || _type == ALIAS || _tied)
681     return false;
682   clear_value();
683   _value.alias = target;
684   _type = ALIAS;
685   return true;
686 }
687
688
689 /**
690  * Alias to another node by path.
691  */
692 bool
693 SGPropertyNode::alias (const char * path)
694 {
695   return alias(getNode(path, true));
696 }
697
698
699 /**
700  * Remove an alias.
701  */
702 bool
703 SGPropertyNode::unalias ()
704 {
705   if (_type != ALIAS)
706     return false;
707   _type = NONE;
708   _value.alias = 0;
709   return true;
710 }
711
712
713 /**
714  * Get the target of an alias.
715  */
716 SGPropertyNode *
717 SGPropertyNode::getAliasTarget ()
718 {
719   return (_type == ALIAS ? _value.alias : 0);
720 }
721
722
723 const SGPropertyNode *
724 SGPropertyNode::getAliasTarget () const
725 {
726   return (_type == ALIAS ? _value.alias : 0);
727 }
728
729
730 /**
731  * Get a non-const child by index.
732  */
733 SGPropertyNode *
734 SGPropertyNode::getChild (int position)
735 {
736   if (position >= 0 && position < nChildren())
737     return _children[position];
738   else
739     return 0;
740 }
741
742
743 /**
744  * Get a const child by index.
745  */
746 const SGPropertyNode *
747 SGPropertyNode::getChild (int position) const
748 {
749   if (position >= 0 && position < nChildren())
750     return _children[position];
751   else
752     return 0;
753 }
754
755
756 /**
757  * Get a non-const child by name and index, creating if necessary.
758  */
759 SGPropertyNode *
760 SGPropertyNode::getChild (const char * name, int index, bool create)
761 {
762   int pos = find_child(name, index, _children);
763   if (pos >= 0) {
764     return _children[pos];
765   } else if (create) {
766     _children.push_back(new SGPropertyNode(name, index, this));
767     return _children[_children.size()-1];
768   } else {
769     return 0;
770   }
771 }
772
773
774 /**
775  * Get a const child by name and index.
776  */
777 const SGPropertyNode *
778 SGPropertyNode::getChild (const char * name, int index) const
779 {
780   int pos = find_child(name, index, _children);
781   if (pos >= 0)
782     return _children[pos];
783   else
784     return 0;
785 }
786
787
788 /**
789  * Get all children with the same name (but different indices).
790  */
791 vector<SGPropertyNode *>
792 SGPropertyNode::getChildren (const char * name)
793 {
794   vector<SGPropertyNode *> children;
795   int max = _children.size();
796
797   for (int i = 0; i < max; i++)
798     if (compare_strings(_children[i]->getName(), name))
799       children.push_back(_children[i]);
800
801   sort(children.begin(), children.end(), CompareIndices());
802   return children;
803 }
804
805
806 /**
807  * Get all children const with the same name (but different indices).
808  */
809 vector<const SGPropertyNode *>
810 SGPropertyNode::getChildren (const char * name) const
811 {
812   vector<const SGPropertyNode *> children;
813   int max = _children.size();
814
815   for (int i = 0; i < max; i++)
816     if (compare_strings(_children[i]->getName(), name))
817       children.push_back(_children[i]);
818
819   sort(children.begin(), children.end(), CompareIndices());
820   return children;
821 }
822
823
824 const char *
825 SGPropertyNode::getPath (bool simplify) const
826 {
827   if (_parent == 0)
828     return "";
829
830   string path = _parent->getPath(simplify);
831   path += '/';
832   path += _name;
833   if (_index != 0 || !simplify) {
834     char buffer[128];
835     sprintf(buffer, "[%d]", _index);
836     path += buffer;
837   }
838   return path.c_str();
839 }
840
841 SGPropertyNode::Type
842 SGPropertyNode::getType () const
843 {
844   if (_type == ALIAS)
845     return _value.alias->getType();
846   else
847     return _type;
848 }
849
850
851 bool 
852 SGPropertyNode::getBoolValue () const
853 {
854                                 // Shortcut for common case
855   if (_attr == (READ|WRITE) && _type == BOOL)
856     return get_bool();
857
858   if (getAttribute(TRACE_READ))
859     trace_read();
860   if (!getAttribute(READ))
861     return SGRawValue<bool>::DefaultValue;
862   switch (_type) {
863   case ALIAS:
864     return _value.alias->getBoolValue();
865   case BOOL:
866     return get_bool();
867   case INT:
868     return get_int() == 0 ? false : true;
869   case LONG:
870     return get_long() == 0L ? false : true;
871   case FLOAT:
872     return get_float() == 0.0 ? false : true;
873   case DOUBLE:
874     return get_double() == 0.0L ? false : true;
875   case STRING:
876   case UNSPECIFIED:
877     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
878   case NONE:
879   default:
880     return SGRawValue<bool>::DefaultValue;
881   }
882 }
883
884 int 
885 SGPropertyNode::getIntValue () const
886 {
887                                 // Shortcut for common case
888   if (_attr == (READ|WRITE) && _type == INT)
889     return get_int();
890
891   if (getAttribute(TRACE_READ))
892     trace_read();
893   if (!getAttribute(READ))
894     return SGRawValue<int>::DefaultValue;
895   switch (_type) {
896   case ALIAS:
897     return _value.alias->getIntValue();
898   case BOOL:
899     return int(get_bool());
900   case INT:
901     return get_int();
902   case LONG:
903     return int(get_long());
904   case FLOAT:
905     return int(get_float());
906   case DOUBLE:
907     return int(get_double());
908   case STRING:
909   case UNSPECIFIED:
910     return atoi(get_string());
911   case NONE:
912   default:
913     return SGRawValue<int>::DefaultValue;
914   }
915 }
916
917 long 
918 SGPropertyNode::getLongValue () const
919 {
920                                 // Shortcut for common case
921   if (_attr == (READ|WRITE) && _type == LONG)
922     return get_long();
923
924   if (getAttribute(TRACE_READ))
925     trace_read();
926   if (!getAttribute(READ))
927     return SGRawValue<long>::DefaultValue;
928   switch (_type) {
929   case ALIAS:
930     return _value.alias->getLongValue();
931   case BOOL:
932     return long(get_bool());
933   case INT:
934     return long(get_int());
935   case LONG:
936     return get_long();
937   case FLOAT:
938     return long(get_float());
939   case DOUBLE:
940     return long(get_double());
941   case STRING:
942   case UNSPECIFIED:
943     return strtol(get_string(), 0, 0);
944   case NONE:
945   default:
946     return SGRawValue<long>::DefaultValue;
947   }
948 }
949
950 float 
951 SGPropertyNode::getFloatValue () const
952 {
953                                 // Shortcut for common case
954   if (_attr == (READ|WRITE) && _type == FLOAT)
955     return get_float();
956
957   if (getAttribute(TRACE_READ))
958     trace_read();
959   if (!getAttribute(READ))
960     return SGRawValue<float>::DefaultValue;
961   switch (_type) {
962   case ALIAS:
963     return _value.alias->getFloatValue();
964   case BOOL:
965     return float(get_bool());
966   case INT:
967     return float(get_int());
968   case LONG:
969     return float(get_long());
970   case FLOAT:
971     return get_float();
972   case DOUBLE:
973     return float(get_double());
974   case STRING:
975   case UNSPECIFIED:
976     return atof(get_string());
977   case NONE:
978   default:
979     return SGRawValue<float>::DefaultValue;
980   }
981 }
982
983 double 
984 SGPropertyNode::getDoubleValue () const
985 {
986                                 // Shortcut for common case
987   if (_attr == (READ|WRITE) && _type == DOUBLE)
988     return get_double();
989
990   if (getAttribute(TRACE_READ))
991     trace_read();
992   if (!getAttribute(READ))
993     return SGRawValue<double>::DefaultValue;
994
995   switch (_type) {
996   case ALIAS:
997     return _value.alias->getDoubleValue();
998   case BOOL:
999     return double(get_bool());
1000   case INT:
1001     return double(get_int());
1002   case LONG:
1003     return double(get_long());
1004   case FLOAT:
1005     return double(get_float());
1006   case DOUBLE:
1007     return get_double();
1008   case STRING:
1009   case UNSPECIFIED:
1010     return strtod(get_string(), 0);
1011   case NONE:
1012   default:
1013     return SGRawValue<double>::DefaultValue;
1014   }
1015 }
1016
1017 const char *
1018 SGPropertyNode::getStringValue () const
1019 {
1020                                 // Shortcut for common case
1021   if (_attr == (READ|WRITE) && _type == STRING)
1022     return get_string();
1023
1024   if (getAttribute(TRACE_READ))
1025     trace_read();
1026   if (!getAttribute(READ))
1027     return SGRawValue<const char *>::DefaultValue;
1028   return make_string();
1029 }
1030
1031 bool
1032 SGPropertyNode::setBoolValue (bool value)
1033 {
1034                                 // Shortcut for common case
1035   if (_attr == (READ|WRITE) && _type == BOOL)
1036     return set_bool(value);
1037
1038   bool result = false;
1039   TEST_WRITE;
1040   if (_type == NONE || _type == UNSPECIFIED) {
1041     clear_value();
1042     _tied = false;
1043     _type = BOOL;
1044   }
1045
1046   switch (_type) {
1047   case ALIAS:
1048     result = _value.alias->setBoolValue(value);
1049     break;
1050   case BOOL:
1051     result = set_bool(value);
1052     break;
1053   case INT:
1054     result = set_int(int(value));
1055     break;
1056   case LONG:
1057     result = set_long(long(value));
1058     break;
1059   case FLOAT:
1060     result = set_float(float(value));
1061     break;
1062   case DOUBLE:
1063     result = set_double(double(value));
1064     break;
1065   case STRING:
1066   case UNSPECIFIED:
1067     result = set_string(value ? "true" : "false");
1068     break;
1069   case NONE:
1070   default:
1071     break;
1072   }
1073
1074   if (getAttribute(TRACE_WRITE))
1075     trace_write();
1076   return result;
1077 }
1078
1079 bool
1080 SGPropertyNode::setIntValue (int value)
1081 {
1082                                 // Shortcut for common case
1083   if (_attr == (READ|WRITE) && _type == INT)
1084     return set_int(value);
1085
1086   bool result = false;
1087   TEST_WRITE;
1088   if (_type == NONE || _type == UNSPECIFIED) {
1089     clear_value();
1090     _type = INT;
1091     _local_val.int_val = 0;
1092   }
1093
1094   switch (_type) {
1095   case ALIAS:
1096     result = _value.alias->setIntValue(value);
1097     break;
1098   case BOOL:
1099     result = set_bool(value == 0 ? false : true);
1100     break;
1101   case INT:
1102     result = set_int(value);
1103     break;
1104   case LONG:
1105     result = set_long(long(value));
1106     break;
1107   case FLOAT:
1108     result = set_float(float(value));
1109     break;
1110   case DOUBLE:
1111     result = set_double(double(value));
1112     break;
1113   case STRING:
1114   case UNSPECIFIED: {
1115     char buf[128];
1116     sprintf(buf, "%d", value);
1117     result = set_string(buf);
1118     break;
1119   }
1120   case NONE:
1121   default:
1122     break;
1123   }
1124
1125   if (getAttribute(TRACE_WRITE))
1126     trace_write();
1127   return result;
1128 }
1129
1130 bool
1131 SGPropertyNode::setLongValue (long value)
1132 {
1133                                 // Shortcut for common case
1134   if (_attr == (READ|WRITE) && _type == LONG)
1135     return set_long(value);
1136
1137   bool result = false;
1138   TEST_WRITE;
1139   if (_type == NONE || _type == UNSPECIFIED) {
1140     clear_value();
1141     _type = LONG;
1142     _local_val.long_val = 0L;
1143   }
1144
1145   switch (_type) {
1146   case ALIAS:
1147     result = _value.alias->setLongValue(value);
1148     break;
1149   case BOOL:
1150     result = set_bool(value == 0L ? false : true);
1151     break;
1152   case INT:
1153     result = set_int(int(value));
1154     break;
1155   case LONG:
1156     result = set_long(value);
1157     break;
1158   case FLOAT:
1159     result = set_float(float(value));
1160     break;
1161   case DOUBLE:
1162     result = set_double(double(value));
1163     break;
1164   case STRING:
1165   case UNSPECIFIED: {
1166     char buf[128];
1167     sprintf(buf, "%ld", value);
1168     result = set_string(buf);
1169     break;
1170   }
1171   case NONE:
1172   default:
1173     break;
1174   }
1175
1176   if (getAttribute(TRACE_WRITE))
1177     trace_write();
1178   return result;
1179 }
1180
1181 bool
1182 SGPropertyNode::setFloatValue (float value)
1183 {
1184                                 // Shortcut for common case
1185   if (_attr == (READ|WRITE) && _type == FLOAT)
1186     return set_float(value);
1187
1188   bool result = false;
1189   TEST_WRITE;
1190   if (_type == NONE || _type == UNSPECIFIED) {
1191     clear_value();
1192     _type = FLOAT;
1193     _local_val.float_val = 0;
1194   }
1195
1196   switch (_type) {
1197   case ALIAS:
1198     result = _value.alias->setFloatValue(value);
1199     break;
1200   case BOOL:
1201     result = set_bool(value == 0.0 ? false : true);
1202     break;
1203   case INT:
1204     result = set_int(int(value));
1205     break;
1206   case LONG:
1207     result = set_long(long(value));
1208     break;
1209   case FLOAT:
1210     result = set_float(value);
1211     break;
1212   case DOUBLE:
1213     result = set_double(double(value));
1214     break;
1215   case STRING:
1216   case UNSPECIFIED: {
1217     char buf[128];
1218     sprintf(buf, "%f", value);
1219     result = set_string(buf);
1220     break;
1221   }
1222   case NONE:
1223   default:
1224     break;
1225   }
1226
1227   if (getAttribute(TRACE_WRITE))
1228     trace_write();
1229   return result;
1230 }
1231
1232 bool
1233 SGPropertyNode::setDoubleValue (double value)
1234 {
1235                                 // Shortcut for common case
1236   if (_attr == (READ|WRITE) && _type == DOUBLE)
1237     return set_double(value);
1238
1239   bool result = false;
1240   TEST_WRITE;
1241   if (_type == NONE || _type == UNSPECIFIED) {
1242     clear_value();
1243     _local_val.double_val = value;
1244     _type = DOUBLE;
1245   }
1246
1247   switch (_type) {
1248   case ALIAS:
1249     result = _value.alias->setDoubleValue(value);
1250     break;
1251   case BOOL:
1252     result = set_bool(value == 0.0L ? false : true);
1253     break;
1254   case INT:
1255     result = set_int(int(value));
1256     break;
1257   case LONG:
1258     result = set_long(long(value));
1259     break;
1260   case FLOAT:
1261     result = set_float(float(value));
1262     break;
1263   case DOUBLE:
1264     result = set_double(value);
1265     break;
1266   case STRING:
1267   case UNSPECIFIED: {
1268     char buf[128];
1269     sprintf(buf, "%f", value);
1270     result = set_string(buf);
1271     break;
1272   }
1273   case NONE:
1274   default:
1275     break;
1276   }
1277
1278   if (getAttribute(TRACE_WRITE))
1279     trace_write();
1280   return result;
1281 }
1282
1283 bool
1284 SGPropertyNode::setStringValue (const char * value)
1285 {
1286                                 // Shortcut for common case
1287   if (_attr == (READ|WRITE) && _type == STRING)
1288     return set_string(value);
1289
1290   bool result = false;
1291   TEST_WRITE;
1292   if (_type == NONE || _type == UNSPECIFIED) {
1293     clear_value();
1294     _type = STRING;
1295   }
1296
1297   switch (_type) {
1298   case ALIAS:
1299     result = _value.alias->setStringValue(value);
1300     break;
1301   case BOOL:
1302     result = set_bool((compare_strings(value, "true")
1303                        || atoi(value)) ? true : false);
1304     break;
1305   case INT:
1306     result = set_int(atoi(value));
1307     break;
1308   case LONG:
1309     result = set_long(strtol(value, 0, 0));
1310     break;
1311   case FLOAT:
1312     result = set_float(atof(value));
1313     break;
1314   case DOUBLE:
1315     result = set_double(strtod(value, 0));
1316     break;
1317   case STRING:
1318   case UNSPECIFIED:
1319     result = set_string(value);
1320     break;
1321   case NONE:
1322   default:
1323     break;
1324   }
1325
1326   if (getAttribute(TRACE_WRITE))
1327     trace_write();
1328   return result;
1329 }
1330
1331 bool
1332 SGPropertyNode::setUnspecifiedValue (const char * value)
1333 {
1334   bool result = false;
1335   TEST_WRITE;
1336   if (_type == NONE) {
1337     clear_value();
1338     _type = UNSPECIFIED;
1339   }
1340
1341   switch (_type) {
1342   case ALIAS:
1343     result = _value.alias->setUnspecifiedValue(value);
1344     break;
1345   case BOOL:
1346     result = set_bool((compare_strings(value, "true")
1347                        || atoi(value)) ? true : false);
1348     break;
1349   case INT:
1350     result = set_int(atoi(value));
1351     break;
1352   case LONG:
1353     result = set_long(strtol(value, 0, 0));
1354     break;
1355   case FLOAT:
1356     result = set_float(atof(value));
1357     break;
1358   case DOUBLE:
1359     result = set_double(strtod(value, 0));
1360     break;
1361   case STRING:
1362   case UNSPECIFIED:
1363     result = set_string(value);
1364     break;
1365   case NONE:
1366   default:
1367     break;
1368   }
1369
1370   if (getAttribute(TRACE_WRITE))
1371     trace_write();
1372   return result;
1373 }
1374
1375 bool
1376 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1377 {
1378   if (_type == ALIAS || _tied)
1379     return false;
1380
1381   useDefault = useDefault && hasValue();
1382   bool old_val = false;
1383   if (useDefault)
1384     old_val = getBoolValue();
1385
1386   clear_value();
1387   _type = BOOL;
1388   _tied = true;
1389   _value.bool_val = rawValue.clone();
1390
1391   if (useDefault)
1392     setBoolValue(old_val);
1393
1394   return true;
1395 }
1396
1397 bool
1398 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1399 {
1400   if (_type == ALIAS || _tied)
1401     return false;
1402
1403   useDefault = useDefault && hasValue();
1404   int old_val = 0;
1405   if (useDefault)
1406     old_val = getIntValue();
1407
1408   clear_value();
1409   _type = INT;
1410   _tied = true;
1411   _value.int_val = rawValue.clone();
1412
1413   if (useDefault)
1414     setIntValue(old_val);
1415
1416   return true;
1417 }
1418
1419 bool
1420 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1421 {
1422   if (_type == ALIAS || _tied)
1423     return false;
1424
1425   useDefault = useDefault && hasValue();
1426   long old_val = 0;
1427   if (useDefault)
1428     old_val = getLongValue();
1429
1430   clear_value();
1431   _type = LONG;
1432   _tied = true;
1433   _value.long_val = rawValue.clone();
1434
1435   if (useDefault)
1436     setLongValue(old_val);
1437
1438   return true;
1439 }
1440
1441 bool
1442 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1443 {
1444   if (_type == ALIAS || _tied)
1445     return false;
1446
1447   useDefault = useDefault && hasValue();
1448   float old_val = 0.0;
1449   if (useDefault)
1450     old_val = getFloatValue();
1451
1452   clear_value();
1453   _type = FLOAT;
1454   _tied = true;
1455   _value.float_val = rawValue.clone();
1456
1457   if (useDefault)
1458     setFloatValue(old_val);
1459
1460   return true;
1461 }
1462
1463 bool
1464 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1465 {
1466   if (_type == ALIAS || _tied)
1467     return false;
1468
1469   useDefault = useDefault && hasValue();
1470   double old_val = 0.0;
1471   if (useDefault)
1472     old_val = getDoubleValue();
1473
1474   clear_value();
1475   _type = DOUBLE;
1476   _tied = true;
1477   _value.double_val = rawValue.clone();
1478
1479   if (useDefault)
1480     setDoubleValue(old_val);
1481
1482   return true;
1483
1484 }
1485
1486 bool
1487 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1488 {
1489   if (_type == ALIAS || _tied)
1490     return false;
1491
1492   useDefault = useDefault && hasValue();
1493   string old_val;
1494   if (useDefault)
1495     old_val = getStringValue();
1496
1497   clear_value();
1498   _type = STRING;
1499   _tied = true;
1500   _value.string_val = rawValue.clone();
1501
1502   if (useDefault)
1503     setStringValue(old_val.c_str());
1504
1505   return true;
1506 }
1507
1508 bool
1509 SGPropertyNode::untie ()
1510 {
1511   if (!_tied)
1512     return false;
1513
1514   switch (_type) {
1515   case BOOL: {
1516     bool val = getBoolValue();
1517     clear_value();
1518     _type = BOOL;
1519     _local_val.bool_val = val;
1520     break;
1521   }
1522   case INT: {
1523     int val = getIntValue();
1524     clear_value();
1525     _type = INT;
1526     _local_val.int_val = val;
1527     break;
1528   }
1529   case LONG: {
1530     long val = getLongValue();
1531     clear_value();
1532     _type = LONG;
1533     _local_val.long_val = val;
1534     break;
1535   }
1536   case FLOAT: {
1537     float val = getFloatValue();
1538     clear_value();
1539     _type = FLOAT;
1540     _local_val.float_val = val;
1541     break;
1542   }
1543   case DOUBLE: {
1544     double val = getDoubleValue();
1545     clear_value();
1546     _type = DOUBLE;
1547     _local_val.double_val = val;
1548     break;
1549   }
1550   case STRING:
1551   case UNSPECIFIED: {
1552     string val = getStringValue();
1553     clear_value();
1554     _type = STRING;
1555     _local_val.string_val = copy_string(val.c_str());
1556     break;
1557   }
1558   case NONE:
1559   default:
1560     break;
1561   }
1562
1563   _tied = false;
1564   return true;
1565 }
1566
1567 SGPropertyNode *
1568 SGPropertyNode::getRootNode ()
1569 {
1570   if (_parent == 0)
1571     return this;
1572   else
1573     return _parent->getRootNode();
1574 }
1575
1576 const SGPropertyNode *
1577 SGPropertyNode::getRootNode () const
1578 {
1579   if (_parent == 0)
1580     return this;
1581   else
1582     return _parent->getRootNode();
1583 }
1584
1585 SGPropertyNode *
1586 SGPropertyNode::getNode (const char * relative_path, bool create)
1587 {
1588 //   if (_path_cache == 0)
1589 //     _path_cache = new cache_map;
1590
1591 //   SGPropertyNode * result = (*_path_cache)[relative_path];
1592 //   if (result == 0) {
1593 //     vector<PathComponent> components;
1594 //     parse_path(relative_path, components);
1595 //     result = find_node(this, components, 0, create);
1596 //     if (result != 0)
1597 //       (*_path_cache)[relative_path] = result;
1598 //   }
1599   
1600 //   return result;
1601   vector<PathComponent> components;
1602   parse_path(relative_path, components);
1603   return find_node(this, components, 0, create);
1604 }
1605
1606 SGPropertyNode *
1607 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1608 {
1609   vector<PathComponent> components;
1610   parse_path(relative_path, components);
1611   if (components.size() > 0)
1612     components[components.size()-1].index = index;
1613   return find_node(this, components, 0, create);
1614 }
1615
1616 const SGPropertyNode *
1617 SGPropertyNode::getNode (const char * relative_path) const
1618 {
1619   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1620 }
1621
1622 const SGPropertyNode *
1623 SGPropertyNode::getNode (const char * relative_path, int index) const
1624 {
1625   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1626 }
1627
1628 \f
1629 ////////////////////////////////////////////////////////////////////////
1630 // Convenience methods using relative paths.
1631 ////////////////////////////////////////////////////////////////////////
1632
1633
1634 /**
1635  * Test whether another node has a value attached.
1636  */
1637 bool
1638 SGPropertyNode::hasValue (const char * relative_path) const
1639 {
1640   const SGPropertyNode * node = getNode(relative_path);
1641   return (node == 0 ? false : node->hasValue());
1642 }
1643
1644
1645 /**
1646  * Get the value type for another node.
1647  */
1648 SGPropertyNode::Type
1649 SGPropertyNode::getType (const char * relative_path) const
1650 {
1651   const SGPropertyNode * node = getNode(relative_path);
1652   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1653 }
1654
1655
1656 /**
1657  * Get a bool value for another node.
1658  */
1659 bool
1660 SGPropertyNode::getBoolValue (const char * relative_path,
1661                               bool defaultValue) const
1662 {
1663   const SGPropertyNode * node = getNode(relative_path);
1664   return (node == 0 ? defaultValue : node->getBoolValue());
1665 }
1666
1667
1668 /**
1669  * Get an int value for another node.
1670  */
1671 int
1672 SGPropertyNode::getIntValue (const char * relative_path,
1673                              int defaultValue) const
1674 {
1675   const SGPropertyNode * node = getNode(relative_path);
1676   return (node == 0 ? defaultValue : node->getIntValue());
1677 }
1678
1679
1680 /**
1681  * Get a long value for another node.
1682  */
1683 long
1684 SGPropertyNode::getLongValue (const char * relative_path,
1685                               long defaultValue) const
1686 {
1687   const SGPropertyNode * node = getNode(relative_path);
1688   return (node == 0 ? defaultValue : node->getLongValue());
1689 }
1690
1691
1692 /**
1693  * Get a float value for another node.
1694  */
1695 float
1696 SGPropertyNode::getFloatValue (const char * relative_path,
1697                                float defaultValue) const
1698 {
1699   const SGPropertyNode * node = getNode(relative_path);
1700   return (node == 0 ? defaultValue : node->getFloatValue());
1701 }
1702
1703
1704 /**
1705  * Get a double value for another node.
1706  */
1707 double
1708 SGPropertyNode::getDoubleValue (const char * relative_path,
1709                                 double defaultValue) const
1710 {
1711   const SGPropertyNode * node = getNode(relative_path);
1712   return (node == 0 ? defaultValue : node->getDoubleValue());
1713 }
1714
1715
1716 /**
1717  * Get a string value for another node.
1718  */
1719 const char *
1720 SGPropertyNode::getStringValue (const char * relative_path,
1721                                 const char * defaultValue) const
1722 {
1723   const SGPropertyNode * node = getNode(relative_path);
1724   return (node == 0 ? defaultValue : node->getStringValue());
1725 }
1726
1727
1728 /**
1729  * Set a bool value for another node.
1730  */
1731 bool
1732 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1733 {
1734   return getNode(relative_path, true)->setBoolValue(value);
1735 }
1736
1737
1738 /**
1739  * Set an int value for another node.
1740  */
1741 bool
1742 SGPropertyNode::setIntValue (const char * relative_path, int value)
1743 {
1744   return getNode(relative_path, true)->setIntValue(value);
1745 }
1746
1747
1748 /**
1749  * Set a long value for another node.
1750  */
1751 bool
1752 SGPropertyNode::setLongValue (const char * relative_path, long value)
1753 {
1754   return getNode(relative_path, true)->setLongValue(value);
1755 }
1756
1757
1758 /**
1759  * Set a float value for another node.
1760  */
1761 bool
1762 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1763 {
1764   return getNode(relative_path, true)->setFloatValue(value);
1765 }
1766
1767
1768 /**
1769  * Set a double value for another node.
1770  */
1771 bool
1772 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1773 {
1774   return getNode(relative_path, true)->setDoubleValue(value);
1775 }
1776
1777
1778 /**
1779  * Set a string value for another node.
1780  */
1781 bool
1782 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1783 {
1784   return getNode(relative_path, true)->setStringValue(value);
1785 }
1786
1787
1788 /**
1789  * Set an unknown value for another node.
1790  */
1791 bool
1792 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1793                                      const char * value)
1794 {
1795   return getNode(relative_path, true)->setUnspecifiedValue(value);
1796 }
1797
1798
1799 /**
1800  * Test whether another node is tied.
1801  */
1802 bool
1803 SGPropertyNode::isTied (const char * relative_path) const
1804 {
1805   const SGPropertyNode * node = getNode(relative_path);
1806   return (node == 0 ? false : node->isTied());
1807 }
1808
1809
1810 /**
1811  * Tie a node reached by a relative path, creating it if necessary.
1812  */
1813 bool
1814 SGPropertyNode::tie (const char * relative_path,
1815                      const SGRawValue<bool> &rawValue,
1816                      bool useDefault)
1817 {
1818   return getNode(relative_path, true)->tie(rawValue, useDefault);
1819 }
1820
1821
1822 /**
1823  * Tie a node reached by a relative path, creating it if necessary.
1824  */
1825 bool
1826 SGPropertyNode::tie (const char * relative_path,
1827                      const SGRawValue<int> &rawValue,
1828                      bool useDefault)
1829 {
1830   return getNode(relative_path, true)->tie(rawValue, useDefault);
1831 }
1832
1833
1834 /**
1835  * Tie a node reached by a relative path, creating it if necessary.
1836  */
1837 bool
1838 SGPropertyNode::tie (const char * relative_path,
1839                      const SGRawValue<long> &rawValue,
1840                      bool useDefault)
1841 {
1842   return getNode(relative_path, true)->tie(rawValue, useDefault);
1843 }
1844
1845
1846 /**
1847  * Tie a node reached by a relative path, creating it if necessary.
1848  */
1849 bool
1850 SGPropertyNode::tie (const char * relative_path,
1851                      const SGRawValue<float> &rawValue,
1852                      bool useDefault)
1853 {
1854   return getNode(relative_path, true)->tie(rawValue, useDefault);
1855 }
1856
1857
1858 /**
1859  * Tie a node reached by a relative path, creating it if necessary.
1860  */
1861 bool
1862 SGPropertyNode::tie (const char * relative_path,
1863                      const SGRawValue<double> &rawValue,
1864                      bool useDefault)
1865 {
1866   return getNode(relative_path, true)->tie(rawValue, useDefault);
1867 }
1868
1869
1870 /**
1871  * Tie a node reached by a relative path, creating it if necessary.
1872  */
1873 bool
1874 SGPropertyNode::tie (const char * relative_path,
1875                      const SGRawValue<const char *> &rawValue,
1876                      bool useDefault)
1877 {
1878   return getNode(relative_path, true)->tie(rawValue, useDefault);
1879 }
1880
1881
1882 /**
1883  * Attempt to untie another node reached by a relative path.
1884  */
1885 bool
1886 SGPropertyNode::untie (const char * relative_path)
1887 {
1888   SGPropertyNode * node = getNode(relative_path);
1889   return (node == 0 ? false : node->untie());
1890 }
1891
1892 // end of props.cxx