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