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