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