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