]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
fc0e549affe34c7d5a89d8fc821c245619b2f956
[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 #include <algorithm>
12 #include <stdio.h>
13 #include <string.h>
14
15 #if PROPS_STANDALONE
16
17 #include <iostream>
18 using std::cerr;
19 using std::endl;
20 using std::sort;
21
22 #else
23
24 #include <simgear/compiler.h>
25 #include <simgear/debug/logstream.hxx>
26
27 SG_USING_STD(sort);
28
29 #endif
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 [] (char *)_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     break;
433   case ALIAS:
434     _value.alias = 0;
435     break;
436   case BOOL:
437     if (_tied) {
438       delete _value.bool_val;
439       _value.bool_val = 0;
440     }
441     _local_val.bool_val = SGRawValue<bool>::DefaultValue;
442     break;
443   case INT:
444     if (_tied) {
445       delete _value.int_val;
446       _value.int_val = 0;
447     }
448     _local_val.int_val = SGRawValue<int>::DefaultValue;
449     break;
450   case LONG:
451     if (_tied) {
452       delete _value.long_val;
453       _value.long_val = 0L;
454     }
455     _local_val.long_val = SGRawValue<long>::DefaultValue;
456     break;
457   case FLOAT:
458     if (_tied) {
459       delete _value.float_val;
460       _value.float_val = 0;
461     }
462     _local_val.float_val = SGRawValue<float>::DefaultValue;
463     break;
464   case DOUBLE:
465     if (_tied) {
466       delete _value.double_val;
467       _value.double_val = 0;
468     }
469     _local_val.double_val = SGRawValue<double>::DefaultValue;
470     break;
471   case STRING:
472   case UNSPECIFIED:
473     if (_tied) {
474       delete _value.string_val;
475       _value.string_val = 0;
476     } else {
477       delete [] (char *)_local_val.string_val;
478     }
479     _local_val.string_val = 0;
480     break;
481   }
482   _tied = false;
483   _type = NONE;
484 }
485
486
487 /**
488  * Get the value as a string.
489  */
490 const char *
491 SGPropertyNode::make_string () const
492 {
493   if (!getAttribute(READ))
494     return "";
495
496   switch (_type) {
497   case ALIAS:
498     return _value.alias->getStringValue();
499   case BOOL:
500     if (get_bool())
501       return "true";
502     else
503       return "false";
504   case INT:
505     sprintf(_buffer, "%d", get_int());
506     return _buffer;
507   case LONG:
508     sprintf(_buffer, "%ld", get_long());
509     return _buffer;
510   case FLOAT:
511     sprintf(_buffer, "%f", get_float());
512     return _buffer;
513   case DOUBLE:
514     sprintf(_buffer, "%f", get_double());
515     return _buffer;
516   case STRING:
517   case UNSPECIFIED:
518     return get_string();
519   case NONE:
520   default:
521     return "";
522   }
523 }
524
525 /**
526  * Trace a write access for a property.
527  */
528 void
529 SGPropertyNode::trace_write () const
530 {
531 #if PROPS_STANDALONE
532   cerr << "TRACE: Write node " << getPath () << ", value\""
533        << make_string() << '"' << endl;
534 #else
535   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
536          << ", value\"" << make_string() << '"');
537 #endif
538 }
539
540 /**
541  * Trace a read access for a property.
542  */
543 void
544 SGPropertyNode::trace_read () const
545 {
546 #if PROPS_STANDALONE
547   cerr << "TRACE: Write node " << getPath () << ", value \""
548        << make_string() << '"' << endl;
549 #else
550   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
551          << ", value \"" << make_string() << '"');
552 #endif
553 }
554
555
556 \f
557 ////////////////////////////////////////////////////////////////////////
558 // Public methods from SGPropertyNode.
559 ////////////////////////////////////////////////////////////////////////
560
561 /**
562  * Default constructor: always creates a root node.
563  */
564 SGPropertyNode::SGPropertyNode ()
565   : _name(copy_string("")),
566     _index(0),
567     _parent(0),
568     _path_cache(0),
569     _type(NONE),
570     _tied(false),
571     _attr(READ|WRITE)
572 {
573   _local_val.string_val = 0;
574 }
575
576
577 /**
578  * Copy constructor.
579  */
580 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
581   : _index(node._index),
582     _parent(0),                 // don't copy the parent
583     _path_cache(0),
584     _type(node._type),
585     _tied(node._tied),
586     _attr(node._attr)
587 {
588   _name = copy_string(node._name);
589   _local_val.string_val = 0;
590   switch (_type) {
591   case NONE:
592     break;
593   case ALIAS:
594     _value.alias = node._value.alias;
595     _tied = false;
596     break;
597   case BOOL:
598     if (_tied) {
599       _tied = true;
600       _value.bool_val = node._value.bool_val->clone();
601     } else {
602       _tied = false;
603       set_bool(node.get_bool());
604     }
605     break;
606   case INT:
607     if (_tied) {
608       _tied = true;
609       _value.int_val = node._value.int_val->clone();
610     } else {
611       _tied = false;
612       set_int(node.get_int());
613     }
614     break;
615   case LONG:
616     if (_tied) {
617       _tied = true;
618       _value.long_val = node._value.long_val->clone();
619     } else {
620       _tied = false;
621       set_long(node.get_long());
622     }
623     break;
624   case FLOAT:
625     if (_tied) {
626       _tied = true;
627       _value.float_val = node._value.float_val->clone();
628     } else {
629       _tied = false;
630       set_float(node.get_float());
631     }
632     break;
633   case DOUBLE:
634     if (_tied) {
635       _tied = true;
636       _value.double_val = node._value.double_val->clone();
637     } else {
638       _tied = false;
639       set_double(node.get_double());
640     }
641     break;
642   case STRING:
643   case UNSPECIFIED:
644     if (_tied) {
645       _tied = true;
646       _value.string_val = node._value.string_val->clone();
647     } else {
648       _tied = false;
649       set_string(node.get_string());
650     }
651     break;
652   }
653 }
654
655
656 /**
657  * Convenience constructor.
658  */
659 SGPropertyNode::SGPropertyNode (const char * name,
660                                 int index,
661                                 SGPropertyNode * parent)
662   : _index(index),
663     _parent(parent),
664     _path_cache(0),
665     _type(NONE),
666     _tied(false),
667     _attr(READ|WRITE)
668 {
669   _name = copy_string(name);
670   _local_val.string_val = 0;
671 }
672
673
674 /**
675  * Destructor.
676  */
677 SGPropertyNode::~SGPropertyNode ()
678 {
679   delete [] (char *)_name;
680   for (int i = 0; i < (int)_children.size(); i++) {
681     delete _children[i];
682   }
683 //   delete _path_cache;
684   clear_value();
685 }
686
687
688 /**
689  * Alias to another node.
690  */
691 bool
692 SGPropertyNode::alias (SGPropertyNode * target)
693 {
694   if (target == 0 || _type == ALIAS || _tied)
695     return false;
696   clear_value();
697   _value.alias = target;
698   _type = ALIAS;
699   return true;
700 }
701
702
703 /**
704  * Alias to another node by path.
705  */
706 bool
707 SGPropertyNode::alias (const char * path)
708 {
709   return alias(getNode(path, true));
710 }
711
712
713 /**
714  * Remove an alias.
715  */
716 bool
717 SGPropertyNode::unalias ()
718 {
719   if (_type != ALIAS)
720     return false;
721   _type = NONE;
722   _value.alias = 0;
723   return true;
724 }
725
726
727 /**
728  * Get the target of an alias.
729  */
730 SGPropertyNode *
731 SGPropertyNode::getAliasTarget ()
732 {
733   return (_type == ALIAS ? _value.alias : 0);
734 }
735
736
737 const SGPropertyNode *
738 SGPropertyNode::getAliasTarget () const
739 {
740   return (_type == ALIAS ? _value.alias : 0);
741 }
742
743
744 /**
745  * Get a non-const child by index.
746  */
747 SGPropertyNode *
748 SGPropertyNode::getChild (int position)
749 {
750   if (position >= 0 && position < nChildren())
751     return _children[position];
752   else
753     return 0;
754 }
755
756
757 /**
758  * Get a const child by index.
759  */
760 const SGPropertyNode *
761 SGPropertyNode::getChild (int position) const
762 {
763   if (position >= 0 && position < nChildren())
764     return _children[position];
765   else
766     return 0;
767 }
768
769
770 /**
771  * Get a non-const child by name and index, creating if necessary.
772  */
773 SGPropertyNode *
774 SGPropertyNode::getChild (const char * name, int index, bool create)
775 {
776   int pos = find_child(name, index, _children);
777   if (pos >= 0) {
778     return _children[pos];
779   } else if (create) {
780     _children.push_back(new SGPropertyNode(name, index, this));
781     return _children[_children.size()-1];
782   } else {
783     return 0;
784   }
785 }
786
787
788 /**
789  * Get a const child by name and index.
790  */
791 const SGPropertyNode *
792 SGPropertyNode::getChild (const char * name, int index) const
793 {
794   int pos = find_child(name, index, _children);
795   if (pos >= 0)
796     return _children[pos];
797   else
798     return 0;
799 }
800
801
802 /**
803  * Get all children with the same name (but different indices).
804  */
805 vector<SGPropertyNode *>
806 SGPropertyNode::getChildren (const char * name)
807 {
808   vector<SGPropertyNode *> children;
809   int max = _children.size();
810
811   for (int i = 0; i < max; i++)
812     if (compare_strings(_children[i]->getName(), name))
813       children.push_back(_children[i]);
814
815   sort(children.begin(), children.end(), CompareIndices());
816   return children;
817 }
818
819
820 /**
821  * Get all children const with the same name (but different indices).
822  */
823 vector<const SGPropertyNode *>
824 SGPropertyNode::getChildren (const char * name) const
825 {
826   vector<const SGPropertyNode *> children;
827   int max = _children.size();
828
829   for (int i = 0; i < max; i++)
830     if (compare_strings(_children[i]->getName(), name))
831       children.push_back(_children[i]);
832
833   sort(children.begin(), children.end(), CompareIndices());
834   return children;
835 }
836
837
838 const char *
839 SGPropertyNode::getPath (bool simplify) const
840 {
841   if (_parent == 0)
842     return "";
843
844   string path = _parent->getPath(simplify);
845   path += '/';
846   path += _name;
847   if (_index != 0 || !simplify) {
848     char buffer[128];
849     sprintf(buffer, "[%d]", _index);
850     path += buffer;
851   }
852   return path.c_str();
853 }
854
855 SGPropertyNode::Type
856 SGPropertyNode::getType () const
857 {
858   if (_type == ALIAS)
859     return _value.alias->getType();
860   else
861     return _type;
862 }
863
864
865 bool 
866 SGPropertyNode::getBoolValue () const
867 {
868                                 // Shortcut for common case
869   if (_attr == (READ|WRITE) && _type == BOOL)
870     return get_bool();
871
872   if (getAttribute(TRACE_READ))
873     trace_read();
874   if (!getAttribute(READ))
875     return SGRawValue<bool>::DefaultValue;
876   switch (_type) {
877   case ALIAS:
878     return _value.alias->getBoolValue();
879   case BOOL:
880     return get_bool();
881   case INT:
882     return get_int() == 0 ? false : true;
883   case LONG:
884     return get_long() == 0L ? false : true;
885   case FLOAT:
886     return get_float() == 0.0 ? false : true;
887   case DOUBLE:
888     return get_double() == 0.0L ? false : true;
889   case STRING:
890   case UNSPECIFIED:
891     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
892   case NONE:
893   default:
894     return SGRawValue<bool>::DefaultValue;
895   }
896 }
897
898 int 
899 SGPropertyNode::getIntValue () const
900 {
901                                 // Shortcut for common case
902   if (_attr == (READ|WRITE) && _type == INT)
903     return get_int();
904
905   if (getAttribute(TRACE_READ))
906     trace_read();
907   if (!getAttribute(READ))
908     return SGRawValue<int>::DefaultValue;
909   switch (_type) {
910   case ALIAS:
911     return _value.alias->getIntValue();
912   case BOOL:
913     return int(get_bool());
914   case INT:
915     return get_int();
916   case LONG:
917     return int(get_long());
918   case FLOAT:
919     return int(get_float());
920   case DOUBLE:
921     return int(get_double());
922   case STRING:
923   case UNSPECIFIED:
924     return atoi(get_string());
925   case NONE:
926   default:
927     return SGRawValue<int>::DefaultValue;
928   }
929 }
930
931 long 
932 SGPropertyNode::getLongValue () const
933 {
934                                 // Shortcut for common case
935   if (_attr == (READ|WRITE) && _type == LONG)
936     return get_long();
937
938   if (getAttribute(TRACE_READ))
939     trace_read();
940   if (!getAttribute(READ))
941     return SGRawValue<long>::DefaultValue;
942   switch (_type) {
943   case ALIAS:
944     return _value.alias->getLongValue();
945   case BOOL:
946     return long(get_bool());
947   case INT:
948     return long(get_int());
949   case LONG:
950     return get_long();
951   case FLOAT:
952     return long(get_float());
953   case DOUBLE:
954     return long(get_double());
955   case STRING:
956   case UNSPECIFIED:
957     return strtol(get_string(), 0, 0);
958   case NONE:
959   default:
960     return SGRawValue<long>::DefaultValue;
961   }
962 }
963
964 float 
965 SGPropertyNode::getFloatValue () const
966 {
967                                 // Shortcut for common case
968   if (_attr == (READ|WRITE) && _type == FLOAT)
969     return get_float();
970
971   if (getAttribute(TRACE_READ))
972     trace_read();
973   if (!getAttribute(READ))
974     return SGRawValue<float>::DefaultValue;
975   switch (_type) {
976   case ALIAS:
977     return _value.alias->getFloatValue();
978   case BOOL:
979     return float(get_bool());
980   case INT:
981     return float(get_int());
982   case LONG:
983     return float(get_long());
984   case FLOAT:
985     return get_float();
986   case DOUBLE:
987     return float(get_double());
988   case STRING:
989   case UNSPECIFIED:
990     return atof(get_string());
991   case NONE:
992   default:
993     return SGRawValue<float>::DefaultValue;
994   }
995 }
996
997 double 
998 SGPropertyNode::getDoubleValue () const
999 {
1000                                 // Shortcut for common case
1001   if (_attr == (READ|WRITE) && _type == DOUBLE)
1002     return get_double();
1003
1004   if (getAttribute(TRACE_READ))
1005     trace_read();
1006   if (!getAttribute(READ))
1007     return SGRawValue<double>::DefaultValue;
1008
1009   switch (_type) {
1010   case ALIAS:
1011     return _value.alias->getDoubleValue();
1012   case BOOL:
1013     return double(get_bool());
1014   case INT:
1015     return double(get_int());
1016   case LONG:
1017     return double(get_long());
1018   case FLOAT:
1019     return double(get_float());
1020   case DOUBLE:
1021     return get_double();
1022   case STRING:
1023   case UNSPECIFIED:
1024     return strtod(get_string(), 0);
1025   case NONE:
1026   default:
1027     return SGRawValue<double>::DefaultValue;
1028   }
1029 }
1030
1031 const char *
1032 SGPropertyNode::getStringValue () const
1033 {
1034                                 // Shortcut for common case
1035   if (_attr == (READ|WRITE) && _type == STRING)
1036     return get_string();
1037
1038   if (getAttribute(TRACE_READ))
1039     trace_read();
1040   if (!getAttribute(READ))
1041     return SGRawValue<const char *>::DefaultValue;
1042   return make_string();
1043 }
1044
1045 bool
1046 SGPropertyNode::setBoolValue (bool value)
1047 {
1048                                 // Shortcut for common case
1049   if (_attr == (READ|WRITE) && _type == BOOL)
1050     return set_bool(value);
1051
1052   bool result = false;
1053   TEST_WRITE;
1054   if (_type == NONE || _type == UNSPECIFIED) {
1055     clear_value();
1056     _tied = false;
1057     _type = BOOL;
1058   }
1059
1060   switch (_type) {
1061   case ALIAS:
1062     result = _value.alias->setBoolValue(value);
1063     break;
1064   case BOOL:
1065     result = set_bool(value);
1066     break;
1067   case INT:
1068     result = set_int(int(value));
1069     break;
1070   case LONG:
1071     result = set_long(long(value));
1072     break;
1073   case FLOAT:
1074     result = set_float(float(value));
1075     break;
1076   case DOUBLE:
1077     result = set_double(double(value));
1078     break;
1079   case STRING:
1080   case UNSPECIFIED:
1081     result = set_string(value ? "true" : "false");
1082     break;
1083   case NONE:
1084   default:
1085     break;
1086   }
1087
1088   if (getAttribute(TRACE_WRITE))
1089     trace_write();
1090   return result;
1091 }
1092
1093 bool
1094 SGPropertyNode::setIntValue (int value)
1095 {
1096                                 // Shortcut for common case
1097   if (_attr == (READ|WRITE) && _type == INT)
1098     return set_int(value);
1099
1100   bool result = false;
1101   TEST_WRITE;
1102   if (_type == NONE || _type == UNSPECIFIED) {
1103     clear_value();
1104     _type = INT;
1105     _local_val.int_val = 0;
1106   }
1107
1108   switch (_type) {
1109   case ALIAS:
1110     result = _value.alias->setIntValue(value);
1111     break;
1112   case BOOL:
1113     result = set_bool(value == 0 ? false : true);
1114     break;
1115   case INT:
1116     result = set_int(value);
1117     break;
1118   case LONG:
1119     result = set_long(long(value));
1120     break;
1121   case FLOAT:
1122     result = set_float(float(value));
1123     break;
1124   case DOUBLE:
1125     result = set_double(double(value));
1126     break;
1127   case STRING:
1128   case UNSPECIFIED: {
1129     char buf[128];
1130     sprintf(buf, "%d", value);
1131     result = set_string(buf);
1132     break;
1133   }
1134   case NONE:
1135   default:
1136     break;
1137   }
1138
1139   if (getAttribute(TRACE_WRITE))
1140     trace_write();
1141   return result;
1142 }
1143
1144 bool
1145 SGPropertyNode::setLongValue (long value)
1146 {
1147                                 // Shortcut for common case
1148   if (_attr == (READ|WRITE) && _type == LONG)
1149     return set_long(value);
1150
1151   bool result = false;
1152   TEST_WRITE;
1153   if (_type == NONE || _type == UNSPECIFIED) {
1154     clear_value();
1155     _type = LONG;
1156     _local_val.long_val = 0L;
1157   }
1158
1159   switch (_type) {
1160   case ALIAS:
1161     result = _value.alias->setLongValue(value);
1162     break;
1163   case BOOL:
1164     result = set_bool(value == 0L ? false : true);
1165     break;
1166   case INT:
1167     result = set_int(int(value));
1168     break;
1169   case LONG:
1170     result = set_long(value);
1171     break;
1172   case FLOAT:
1173     result = set_float(float(value));
1174     break;
1175   case DOUBLE:
1176     result = set_double(double(value));
1177     break;
1178   case STRING:
1179   case UNSPECIFIED: {
1180     char buf[128];
1181     sprintf(buf, "%ld", value);
1182     result = set_string(buf);
1183     break;
1184   }
1185   case NONE:
1186   default:
1187     break;
1188   }
1189
1190   if (getAttribute(TRACE_WRITE))
1191     trace_write();
1192   return result;
1193 }
1194
1195 bool
1196 SGPropertyNode::setFloatValue (float value)
1197 {
1198                                 // Shortcut for common case
1199   if (_attr == (READ|WRITE) && _type == FLOAT)
1200     return set_float(value);
1201
1202   bool result = false;
1203   TEST_WRITE;
1204   if (_type == NONE || _type == UNSPECIFIED) {
1205     clear_value();
1206     _type = FLOAT;
1207     _local_val.float_val = 0;
1208   }
1209
1210   switch (_type) {
1211   case ALIAS:
1212     result = _value.alias->setFloatValue(value);
1213     break;
1214   case BOOL:
1215     result = set_bool(value == 0.0 ? false : true);
1216     break;
1217   case INT:
1218     result = set_int(int(value));
1219     break;
1220   case LONG:
1221     result = set_long(long(value));
1222     break;
1223   case FLOAT:
1224     result = set_float(value);
1225     break;
1226   case DOUBLE:
1227     result = set_double(double(value));
1228     break;
1229   case STRING:
1230   case UNSPECIFIED: {
1231     char buf[128];
1232     sprintf(buf, "%f", value);
1233     result = set_string(buf);
1234     break;
1235   }
1236   case NONE:
1237   default:
1238     break;
1239   }
1240
1241   if (getAttribute(TRACE_WRITE))
1242     trace_write();
1243   return result;
1244 }
1245
1246 bool
1247 SGPropertyNode::setDoubleValue (double value)
1248 {
1249                                 // Shortcut for common case
1250   if (_attr == (READ|WRITE) && _type == DOUBLE)
1251     return set_double(value);
1252
1253   bool result = false;
1254   TEST_WRITE;
1255   if (_type == NONE || _type == UNSPECIFIED) {
1256     clear_value();
1257     _local_val.double_val = value;
1258     _type = DOUBLE;
1259   }
1260
1261   switch (_type) {
1262   case ALIAS:
1263     result = _value.alias->setDoubleValue(value);
1264     break;
1265   case BOOL:
1266     result = set_bool(value == 0.0L ? false : true);
1267     break;
1268   case INT:
1269     result = set_int(int(value));
1270     break;
1271   case LONG:
1272     result = set_long(long(value));
1273     break;
1274   case FLOAT:
1275     result = set_float(float(value));
1276     break;
1277   case DOUBLE:
1278     result = set_double(value);
1279     break;
1280   case STRING:
1281   case UNSPECIFIED: {
1282     char buf[128];
1283     sprintf(buf, "%f", value);
1284     result = set_string(buf);
1285     break;
1286   }
1287   case NONE:
1288   default:
1289     break;
1290   }
1291
1292   if (getAttribute(TRACE_WRITE))
1293     trace_write();
1294   return result;
1295 }
1296
1297 bool
1298 SGPropertyNode::setStringValue (const char * value)
1299 {
1300                                 // Shortcut for common case
1301   if (_attr == (READ|WRITE) && _type == STRING)
1302     return set_string(value);
1303
1304   bool result = false;
1305   TEST_WRITE;
1306   if (_type == NONE || _type == UNSPECIFIED) {
1307     clear_value();
1308     _type = STRING;
1309   }
1310
1311   switch (_type) {
1312   case ALIAS:
1313     result = _value.alias->setStringValue(value);
1314     break;
1315   case BOOL:
1316     result = set_bool((compare_strings(value, "true")
1317                        || atoi(value)) ? true : false);
1318     break;
1319   case INT:
1320     result = set_int(atoi(value));
1321     break;
1322   case LONG:
1323     result = set_long(strtol(value, 0, 0));
1324     break;
1325   case FLOAT:
1326     result = set_float(atof(value));
1327     break;
1328   case DOUBLE:
1329     result = set_double(strtod(value, 0));
1330     break;
1331   case STRING:
1332   case UNSPECIFIED:
1333     result = set_string(value);
1334     break;
1335   case NONE:
1336   default:
1337     break;
1338   }
1339
1340   if (getAttribute(TRACE_WRITE))
1341     trace_write();
1342   return result;
1343 }
1344
1345 bool
1346 SGPropertyNode::setUnspecifiedValue (const char * value)
1347 {
1348   bool result = false;
1349   TEST_WRITE;
1350   if (_type == NONE) {
1351     clear_value();
1352     _type = UNSPECIFIED;
1353   }
1354
1355   switch (_type) {
1356   case ALIAS:
1357     result = _value.alias->setUnspecifiedValue(value);
1358     break;
1359   case BOOL:
1360     result = set_bool((compare_strings(value, "true")
1361                        || atoi(value)) ? true : false);
1362     break;
1363   case INT:
1364     result = set_int(atoi(value));
1365     break;
1366   case LONG:
1367     result = set_long(strtol(value, 0, 0));
1368     break;
1369   case FLOAT:
1370     result = set_float(atof(value));
1371     break;
1372   case DOUBLE:
1373     result = set_double(strtod(value, 0));
1374     break;
1375   case STRING:
1376   case UNSPECIFIED:
1377     result = set_string(value);
1378     break;
1379   case NONE:
1380   default:
1381     break;
1382   }
1383
1384   if (getAttribute(TRACE_WRITE))
1385     trace_write();
1386   return result;
1387 }
1388
1389 bool
1390 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1391 {
1392   if (_type == ALIAS || _tied)
1393     return false;
1394
1395   useDefault = useDefault && hasValue();
1396   bool old_val = false;
1397   if (useDefault)
1398     old_val = getBoolValue();
1399
1400   clear_value();
1401   _type = BOOL;
1402   _tied = true;
1403   _value.bool_val = rawValue.clone();
1404
1405   if (useDefault)
1406     setBoolValue(old_val);
1407
1408   return true;
1409 }
1410
1411 bool
1412 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1413 {
1414   if (_type == ALIAS || _tied)
1415     return false;
1416
1417   useDefault = useDefault && hasValue();
1418   int old_val = 0;
1419   if (useDefault)
1420     old_val = getIntValue();
1421
1422   clear_value();
1423   _type = INT;
1424   _tied = true;
1425   _value.int_val = rawValue.clone();
1426
1427   if (useDefault)
1428     setIntValue(old_val);
1429
1430   return true;
1431 }
1432
1433 bool
1434 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1435 {
1436   if (_type == ALIAS || _tied)
1437     return false;
1438
1439   useDefault = useDefault && hasValue();
1440   long old_val = 0;
1441   if (useDefault)
1442     old_val = getLongValue();
1443
1444   clear_value();
1445   _type = LONG;
1446   _tied = true;
1447   _value.long_val = rawValue.clone();
1448
1449   if (useDefault)
1450     setLongValue(old_val);
1451
1452   return true;
1453 }
1454
1455 bool
1456 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1457 {
1458   if (_type == ALIAS || _tied)
1459     return false;
1460
1461   useDefault = useDefault && hasValue();
1462   float old_val = 0.0;
1463   if (useDefault)
1464     old_val = getFloatValue();
1465
1466   clear_value();
1467   _type = FLOAT;
1468   _tied = true;
1469   _value.float_val = rawValue.clone();
1470
1471   if (useDefault)
1472     setFloatValue(old_val);
1473
1474   return true;
1475 }
1476
1477 bool
1478 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1479 {
1480   if (_type == ALIAS || _tied)
1481     return false;
1482
1483   useDefault = useDefault && hasValue();
1484   double old_val = 0.0;
1485   if (useDefault)
1486     old_val = getDoubleValue();
1487
1488   clear_value();
1489   _type = DOUBLE;
1490   _tied = true;
1491   _value.double_val = rawValue.clone();
1492
1493   if (useDefault)
1494     setDoubleValue(old_val);
1495
1496   return true;
1497
1498 }
1499
1500 bool
1501 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1502 {
1503   if (_type == ALIAS || _tied)
1504     return false;
1505
1506   useDefault = useDefault && hasValue();
1507   string old_val;
1508   if (useDefault)
1509     old_val = getStringValue();
1510
1511   clear_value();
1512   _type = STRING;
1513   _tied = true;
1514   _value.string_val = rawValue.clone();
1515
1516   if (useDefault)
1517     setStringValue(old_val.c_str());
1518
1519   return true;
1520 }
1521
1522 bool
1523 SGPropertyNode::untie ()
1524 {
1525   if (!_tied)
1526     return false;
1527
1528   switch (_type) {
1529   case BOOL: {
1530     bool val = getBoolValue();
1531     clear_value();
1532     _type = BOOL;
1533     _local_val.bool_val = val;
1534     break;
1535   }
1536   case INT: {
1537     int val = getIntValue();
1538     clear_value();
1539     _type = INT;
1540     _local_val.int_val = val;
1541     break;
1542   }
1543   case LONG: {
1544     long val = getLongValue();
1545     clear_value();
1546     _type = LONG;
1547     _local_val.long_val = val;
1548     break;
1549   }
1550   case FLOAT: {
1551     float val = getFloatValue();
1552     clear_value();
1553     _type = FLOAT;
1554     _local_val.float_val = val;
1555     break;
1556   }
1557   case DOUBLE: {
1558     double val = getDoubleValue();
1559     clear_value();
1560     _type = DOUBLE;
1561     _local_val.double_val = val;
1562     break;
1563   }
1564   case STRING:
1565   case UNSPECIFIED: {
1566     string val = getStringValue();
1567     clear_value();
1568     _type = STRING;
1569     _local_val.string_val = copy_string(val.c_str());
1570     break;
1571   }
1572   case NONE:
1573   default:
1574     break;
1575   }
1576
1577   _tied = false;
1578   return true;
1579 }
1580
1581 SGPropertyNode *
1582 SGPropertyNode::getRootNode ()
1583 {
1584   if (_parent == 0)
1585     return this;
1586   else
1587     return _parent->getRootNode();
1588 }
1589
1590 const SGPropertyNode *
1591 SGPropertyNode::getRootNode () const
1592 {
1593   if (_parent == 0)
1594     return this;
1595   else
1596     return _parent->getRootNode();
1597 }
1598
1599 SGPropertyNode *
1600 SGPropertyNode::getNode (const char * relative_path, bool create)
1601 {
1602 //   if (_path_cache == 0)
1603 //     _path_cache = new cache_map;
1604
1605 //   SGPropertyNode * result = (*_path_cache)[relative_path];
1606 //   if (result == 0) {
1607 //     vector<PathComponent> components;
1608 //     parse_path(relative_path, components);
1609 //     result = find_node(this, components, 0, create);
1610 //     if (result != 0)
1611 //       (*_path_cache)[relative_path] = result;
1612 //   }
1613   
1614 //   return result;
1615   vector<PathComponent> components;
1616   parse_path(relative_path, components);
1617   return find_node(this, components, 0, create);
1618 }
1619
1620 SGPropertyNode *
1621 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1622 {
1623   vector<PathComponent> components;
1624   parse_path(relative_path, components);
1625   if (components.size() > 0)
1626     components[components.size()-1].index = index;
1627   return find_node(this, components, 0, create);
1628 }
1629
1630 const SGPropertyNode *
1631 SGPropertyNode::getNode (const char * relative_path) const
1632 {
1633   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1634 }
1635
1636 const SGPropertyNode *
1637 SGPropertyNode::getNode (const char * relative_path, int index) const
1638 {
1639   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1640 }
1641
1642 \f
1643 ////////////////////////////////////////////////////////////////////////
1644 // Convenience methods using relative paths.
1645 ////////////////////////////////////////////////////////////////////////
1646
1647
1648 /**
1649  * Test whether another node has a value attached.
1650  */
1651 bool
1652 SGPropertyNode::hasValue (const char * relative_path) const
1653 {
1654   const SGPropertyNode * node = getNode(relative_path);
1655   return (node == 0 ? false : node->hasValue());
1656 }
1657
1658
1659 /**
1660  * Get the value type for another node.
1661  */
1662 SGPropertyNode::Type
1663 SGPropertyNode::getType (const char * relative_path) const
1664 {
1665   const SGPropertyNode * node = getNode(relative_path);
1666   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1667 }
1668
1669
1670 /**
1671  * Get a bool value for another node.
1672  */
1673 bool
1674 SGPropertyNode::getBoolValue (const char * relative_path,
1675                               bool defaultValue) const
1676 {
1677   const SGPropertyNode * node = getNode(relative_path);
1678   return (node == 0 ? defaultValue : node->getBoolValue());
1679 }
1680
1681
1682 /**
1683  * Get an int value for another node.
1684  */
1685 int
1686 SGPropertyNode::getIntValue (const char * relative_path,
1687                              int defaultValue) const
1688 {
1689   const SGPropertyNode * node = getNode(relative_path);
1690   return (node == 0 ? defaultValue : node->getIntValue());
1691 }
1692
1693
1694 /**
1695  * Get a long value for another node.
1696  */
1697 long
1698 SGPropertyNode::getLongValue (const char * relative_path,
1699                               long defaultValue) const
1700 {
1701   const SGPropertyNode * node = getNode(relative_path);
1702   return (node == 0 ? defaultValue : node->getLongValue());
1703 }
1704
1705
1706 /**
1707  * Get a float value for another node.
1708  */
1709 float
1710 SGPropertyNode::getFloatValue (const char * relative_path,
1711                                float defaultValue) const
1712 {
1713   const SGPropertyNode * node = getNode(relative_path);
1714   return (node == 0 ? defaultValue : node->getFloatValue());
1715 }
1716
1717
1718 /**
1719  * Get a double value for another node.
1720  */
1721 double
1722 SGPropertyNode::getDoubleValue (const char * relative_path,
1723                                 double defaultValue) const
1724 {
1725   const SGPropertyNode * node = getNode(relative_path);
1726   return (node == 0 ? defaultValue : node->getDoubleValue());
1727 }
1728
1729
1730 /**
1731  * Get a string value for another node.
1732  */
1733 const char *
1734 SGPropertyNode::getStringValue (const char * relative_path,
1735                                 const char * defaultValue) const
1736 {
1737   const SGPropertyNode * node = getNode(relative_path);
1738   return (node == 0 ? defaultValue : node->getStringValue());
1739 }
1740
1741
1742 /**
1743  * Set a bool value for another node.
1744  */
1745 bool
1746 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1747 {
1748   return getNode(relative_path, true)->setBoolValue(value);
1749 }
1750
1751
1752 /**
1753  * Set an int value for another node.
1754  */
1755 bool
1756 SGPropertyNode::setIntValue (const char * relative_path, int value)
1757 {
1758   return getNode(relative_path, true)->setIntValue(value);
1759 }
1760
1761
1762 /**
1763  * Set a long value for another node.
1764  */
1765 bool
1766 SGPropertyNode::setLongValue (const char * relative_path, long value)
1767 {
1768   return getNode(relative_path, true)->setLongValue(value);
1769 }
1770
1771
1772 /**
1773  * Set a float value for another node.
1774  */
1775 bool
1776 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1777 {
1778   return getNode(relative_path, true)->setFloatValue(value);
1779 }
1780
1781
1782 /**
1783  * Set a double value for another node.
1784  */
1785 bool
1786 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1787 {
1788   return getNode(relative_path, true)->setDoubleValue(value);
1789 }
1790
1791
1792 /**
1793  * Set a string value for another node.
1794  */
1795 bool
1796 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1797 {
1798   return getNode(relative_path, true)->setStringValue(value);
1799 }
1800
1801
1802 /**
1803  * Set an unknown value for another node.
1804  */
1805 bool
1806 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1807                                      const char * value)
1808 {
1809   return getNode(relative_path, true)->setUnspecifiedValue(value);
1810 }
1811
1812
1813 /**
1814  * Test whether another node is tied.
1815  */
1816 bool
1817 SGPropertyNode::isTied (const char * relative_path) const
1818 {
1819   const SGPropertyNode * node = getNode(relative_path);
1820   return (node == 0 ? false : node->isTied());
1821 }
1822
1823
1824 /**
1825  * Tie a node reached by a relative path, creating it if necessary.
1826  */
1827 bool
1828 SGPropertyNode::tie (const char * relative_path,
1829                      const SGRawValue<bool> &rawValue,
1830                      bool useDefault)
1831 {
1832   return getNode(relative_path, true)->tie(rawValue, useDefault);
1833 }
1834
1835
1836 /**
1837  * Tie a node reached by a relative path, creating it if necessary.
1838  */
1839 bool
1840 SGPropertyNode::tie (const char * relative_path,
1841                      const SGRawValue<int> &rawValue,
1842                      bool useDefault)
1843 {
1844   return getNode(relative_path, true)->tie(rawValue, useDefault);
1845 }
1846
1847
1848 /**
1849  * Tie a node reached by a relative path, creating it if necessary.
1850  */
1851 bool
1852 SGPropertyNode::tie (const char * relative_path,
1853                      const SGRawValue<long> &rawValue,
1854                      bool useDefault)
1855 {
1856   return getNode(relative_path, true)->tie(rawValue, useDefault);
1857 }
1858
1859
1860 /**
1861  * Tie a node reached by a relative path, creating it if necessary.
1862  */
1863 bool
1864 SGPropertyNode::tie (const char * relative_path,
1865                      const SGRawValue<float> &rawValue,
1866                      bool useDefault)
1867 {
1868   return getNode(relative_path, true)->tie(rawValue, useDefault);
1869 }
1870
1871
1872 /**
1873  * Tie a node reached by a relative path, creating it if necessary.
1874  */
1875 bool
1876 SGPropertyNode::tie (const char * relative_path,
1877                      const SGRawValue<double> &rawValue,
1878                      bool useDefault)
1879 {
1880   return getNode(relative_path, true)->tie(rawValue, useDefault);
1881 }
1882
1883
1884 /**
1885  * Tie a node reached by a relative path, creating it if necessary.
1886  */
1887 bool
1888 SGPropertyNode::tie (const char * relative_path,
1889                      const SGRawValue<const char *> &rawValue,
1890                      bool useDefault)
1891 {
1892   return getNode(relative_path, true)->tie(rawValue, useDefault);
1893 }
1894
1895
1896 /**
1897  * Attempt to untie another node reached by a relative path.
1898  */
1899 bool
1900 SGPropertyNode::untie (const char * relative_path)
1901 {
1902   SGPropertyNode * node = getNode(relative_path);
1903   return (node == 0 ? false : node->untie());
1904 }
1905
1906 // end of props.cxx