]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
Fixes to make telnet interface work more than 1x.
[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     _path_cache(0),
303     _type(NONE),
304     _tied(false),
305     _attr(READ|WRITE)
306 {
307 }
308
309
310 /**
311  * Copy constructor.
312  */
313 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
314   : _name(node._name),
315     _index(node._index),
316     _parent(0),                 // don't copy the parent
317     _path_cache(0),
318     _type(node._type),
319     _tied(node._tied),
320     _attr(node._attr)
321 {
322   switch (_type) {
323   case NONE:
324     break;
325   case ALIAS:
326     _value.alias = node._value.alias;
327     break;
328   case BOOL:
329     _value.bool_val = node._value.bool_val->clone();
330     break;
331   case INT:
332     _value.int_val = node._value.int_val->clone();
333     break;
334   case LONG:
335     _value.long_val = node._value.long_val->clone();
336     break;
337   case FLOAT:
338     _value.float_val = node._value.float_val->clone();
339     break;
340   case DOUBLE:
341     _value.double_val = node._value.double_val->clone();
342     break;
343   case STRING:
344   case UNSPECIFIED:
345     _value.string_val = node._value.string_val->clone();
346     break;
347   }
348 }
349
350
351 /**
352  * Convenience constructor.
353  */
354 SGPropertyNode::SGPropertyNode (const string &name,
355                                 int index, SGPropertyNode * parent)
356   : _name(name),
357     _index(index),
358     _parent(parent),
359     _path_cache(0),
360     _type(NONE),
361     _tied(false),
362     _attr(READ|WRITE)
363 {
364 }
365
366
367 /**
368  * Destructor.
369  */
370 SGPropertyNode::~SGPropertyNode ()
371 {
372   for (int i = 0; i < (int)_children.size(); i++) {
373     delete _children[i];
374   }
375   delete _path_cache;
376   clear_value();
377 }
378
379
380 /**
381  * Delete and clear the current value.
382  */
383 void
384 SGPropertyNode::clear_value ()
385 {
386   switch (_type) {
387   case NONE:
388   case ALIAS:
389     _value.alias = 0;
390     break;
391   case BOOL:
392     delete _value.bool_val;
393     _value.bool_val = 0;
394     break;
395   case INT:
396     delete _value.int_val;
397     _value.int_val = 0;
398     break;
399   case LONG:
400     delete _value.long_val;
401     _value.long_val = 0L;
402     break;
403   case FLOAT:
404     delete _value.float_val;
405     _value.float_val = 0;
406     break;
407   case DOUBLE:
408     delete _value.double_val;
409     _value.double_val = 0;
410     break;
411   case STRING:
412   case UNSPECIFIED:
413     delete _value.string_val;
414     _value.string_val = 0;
415     break;
416   }
417   _type = NONE;
418 }
419
420
421 /**
422  * Get the value as a string.
423  */
424 string
425 SGPropertyNode::get_string () const
426 {
427   TEST_READ("");
428   char buf[128];
429
430   switch (_type) {
431   case ALIAS:
432     return _value.alias->getStringValue();
433   case BOOL:
434     if (GET_BOOL)
435       return "true";
436     else
437       return "false";
438   case INT:
439     sprintf(buf, "%d", GET_INT);
440     return buf;
441   case LONG:
442     sprintf(buf, "%ld", GET_LONG);
443     return buf;
444   case FLOAT:
445     sprintf(buf, "%f", GET_FLOAT);
446     return buf;
447   case DOUBLE:
448     sprintf(buf, "%f", GET_DOUBLE);
449     return buf;
450   case STRING:
451   case UNSPECIFIED:
452     return GET_STRING;
453   }
454
455   return "";                    // if NONE
456 }
457
458
459 /**
460  * Trace a read access for a property.
461  */
462 void
463 SGPropertyNode::trace_read (SGPropertyNode::Type accessType) const
464 {
465   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
466          << ", value \"" << get_string() << '"');
467 }
468
469
470 /**
471  * Trace a write access for a property.
472  */
473 void
474 SGPropertyNode::trace_write (SGPropertyNode::Type accessType) const
475 {
476   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
477          << ", value\"" << get_string() << '"');
478 }
479
480
481 /**
482  * Alias to another node.
483  */
484 bool
485 SGPropertyNode::alias (SGPropertyNode * target)
486 {
487   if (target == 0 || _type == ALIAS || _tied)
488     return false;
489   clear_value();
490   _value.alias = target;
491   _type = ALIAS;
492   return true;
493 }
494
495
496 /**
497  * Alias to another node by path.
498  */
499 bool
500 SGPropertyNode::alias (const string &path)
501 {
502   return alias(getNode(path, true));
503 }
504
505
506 /**
507  * Remove an alias.
508  */
509 bool
510 SGPropertyNode::unalias ()
511 {
512   if (_type != ALIAS)
513     return false;
514   _type = NONE;
515   _value.alias = 0;
516   return true;
517 }
518
519
520 /**
521  * Get the target of an alias.
522  */
523 SGPropertyNode *
524 SGPropertyNode::getAliasTarget ()
525 {
526   return (_type == ALIAS ? _value.alias : 0);
527 }
528
529
530 const SGPropertyNode *
531 SGPropertyNode::getAliasTarget () const
532 {
533   return (_type == ALIAS ? _value.alias : 0);
534 }
535
536
537 /**
538  * Get a non-const child by index.
539  */
540 SGPropertyNode *
541 SGPropertyNode::getChild (int position)
542 {
543   if (position >= 0 && position < nChildren())
544     return _children[position];
545   else
546     return 0;
547 }
548
549
550 /**
551  * Get a const child by index.
552  */
553 const SGPropertyNode *
554 SGPropertyNode::getChild (int position) const
555 {
556   if (position >= 0 && position < nChildren())
557     return _children[position];
558   else
559     return 0;
560 }
561
562
563 /**
564  * Get a non-const child by name and index, creating if necessary.
565  */
566 SGPropertyNode *
567 SGPropertyNode::getChild (const string &name, int index, bool create)
568 {
569   int pos = find_child(name, index, _children);
570   if (pos >= 0) {
571     return _children[pos];
572   } else if (create) {
573     _children.push_back(new SGPropertyNode(name, index, this));
574     return _children[_children.size()-1];
575   } else {
576     return 0;
577   }
578 }
579
580
581 /**
582  * Get a const child by name and index.
583  */
584 const SGPropertyNode *
585 SGPropertyNode::getChild (const string &name, int index) const
586 {
587   int pos = find_child(name, index, _children);
588   if (pos >= 0)
589     return _children[pos];
590   else
591     return 0;
592 }
593
594
595 /**
596  * Get all children with the same name (but different indices).
597  */
598 vector<SGPropertyNode *>
599 SGPropertyNode::getChildren (const string &name)
600 {
601   vector<SGPropertyNode *> children;
602   int max = _children.size();
603
604   for (int i = 0; i < max; i++)
605     if (_children[i]->getName() == name)
606       children.push_back(_children[i]);
607
608   sort(children.begin(), children.end(), CompareIndices());
609   return children;
610 }
611
612
613 /**
614  * Get all children const with the same name (but different indices).
615  */
616 vector<const SGPropertyNode *>
617 SGPropertyNode::getChildren (const string &name) const
618 {
619   vector<const SGPropertyNode *> children;
620   int max = _children.size();
621
622   for (int i = 0; i < max; i++)
623     if (_children[i]->getName() == name)
624       children.push_back(_children[i]);
625
626   sort(children.begin(), children.end(), CompareIndices());
627   return children;
628 }
629
630
631 string
632 SGPropertyNode::getPath (bool simplify) const
633 {
634   if (_parent == 0)
635     return "";
636
637   string path = _parent->getPath(simplify);
638   path += '/';
639   path += _name;
640   if (_index != 0 || !simplify) {
641     char buffer[128];
642     sprintf(buffer, "[%d]", _index);
643     path += buffer;
644   }
645   return path;
646 }
647
648 SGPropertyNode::Type
649 SGPropertyNode::getType () const
650 {
651   if (_type == ALIAS)
652     return _value.alias->getType();
653   else
654     return _type;
655 }
656
657
658 bool 
659 SGPropertyNode::getBoolValue () const
660 {
661   DO_TRACE_READ(BOOL);
662   TEST_READ(false);
663   switch (_type) {
664   case ALIAS:
665     return _value.alias->getBoolValue();
666   case BOOL:
667     return GET_BOOL;
668   case INT:
669     return GET_INT == 0 ? false : true;
670   case LONG:
671     return GET_LONG == 0L ? false : true;
672   case FLOAT:
673     return GET_FLOAT == 0.0 ? false : true;
674   case DOUBLE:
675     return GET_DOUBLE == 0.0L ? false : true;
676   case STRING:
677   case UNSPECIFIED:
678     return (GET_STRING == "true" || getDoubleValue() != 0.0L);
679   }
680
681   return false;                 // if NONE
682 }
683
684 int 
685 SGPropertyNode::getIntValue () const
686 {
687   DO_TRACE_READ(INT);
688   TEST_READ(0);
689   switch (_type) {
690   case ALIAS:
691     return _value.alias->getIntValue();
692   case BOOL:
693     return int(GET_BOOL);
694   case INT:
695     return GET_INT;
696   case LONG:
697     return int(GET_LONG);
698   case FLOAT:
699     return int(GET_FLOAT);
700   case DOUBLE:
701     return int(GET_DOUBLE);
702   case STRING:
703   case UNSPECIFIED:
704     return atoi(GET_STRING.c_str());
705   }
706
707   return 0;                     // if NONE
708 }
709
710 long 
711 SGPropertyNode::getLongValue () const
712 {
713   DO_TRACE_READ(LONG);
714   TEST_READ(0L);
715   switch (_type) {
716   case ALIAS:
717     return _value.alias->getLongValue();
718   case BOOL:
719     return long(GET_BOOL);
720   case INT:
721     return long(GET_INT);
722   case LONG:
723     return GET_LONG;
724   case FLOAT:
725     return long(GET_FLOAT);
726   case DOUBLE:
727     return long(GET_DOUBLE);
728   case STRING:
729   case UNSPECIFIED:
730     return strtol(GET_STRING.c_str(), 0, 0);
731   }
732
733   return 0L;                    // if NONE
734 }
735
736 float 
737 SGPropertyNode::getFloatValue () const
738 {
739   DO_TRACE_READ(FLOAT);
740   TEST_READ(0.0);
741   switch (_type) {
742   case ALIAS:
743     return _value.alias->getFloatValue();
744   case BOOL:
745     return float(GET_BOOL);
746   case INT:
747     return float(GET_INT);
748   case LONG:
749     return float(GET_LONG);
750   case FLOAT:
751     return GET_FLOAT;
752   case DOUBLE:
753     return float(GET_DOUBLE);
754   case STRING:
755   case UNSPECIFIED:
756     return atof(GET_STRING.c_str());
757   }
758
759   return 0.0;                   // if NONE
760 }
761
762 double 
763 SGPropertyNode::getDoubleValue () const
764 {
765   DO_TRACE_READ(DOUBLE);
766   TEST_READ(0.0L);
767   switch (_type) {
768   case ALIAS:
769     return _value.alias->getDoubleValue();
770   case BOOL:
771     return double(GET_BOOL);
772   case INT:
773     return double(GET_INT);
774   case LONG:
775     return double(GET_LONG);
776   case FLOAT:
777     return double(GET_FLOAT);
778   case DOUBLE:
779     return GET_DOUBLE;
780   case STRING:
781   case UNSPECIFIED:
782     return strtod(GET_STRING.c_str(), 0);
783   }
784
785   return 0.0L;                  // if NONE
786 }
787
788 string
789 SGPropertyNode::getStringValue () const
790 {
791   DO_TRACE_READ(STRING);
792   return get_string();
793 }
794
795 bool
796 SGPropertyNode::setBoolValue (bool value)
797 {
798   bool result = false;
799   TEST_WRITE;
800   if (_type == NONE || _type == UNSPECIFIED) {
801     clear_value();
802     _value.bool_val = new SGRawValueInternal<bool>;
803     _type = BOOL;
804   }
805
806   switch (_type) {
807   case ALIAS:
808     result = _value.alias->setBoolValue(value);
809     break;
810   case BOOL:
811     result = SET_BOOL(value);
812     break;
813   case INT:
814     result = SET_INT(int(value));
815     break;
816   case LONG:
817     result = SET_LONG(long(value));
818     break;
819   case FLOAT:
820     result = SET_FLOAT(float(value));
821     break;
822   case DOUBLE:
823     result = SET_DOUBLE(double(value));
824     break;
825   case STRING:
826     result = SET_STRING(value ? "true" : "false");
827     break;
828   }
829
830   DO_TRACE_WRITE(BOOL);
831   return result;
832 }
833
834 bool
835 SGPropertyNode::setIntValue (int value)
836 {
837   bool result = false;
838   TEST_WRITE;
839   if (_type == NONE || _type == UNSPECIFIED) {
840     clear_value();
841     _value.int_val = new SGRawValueInternal<int>;
842     _type = INT;
843   }
844
845   switch (_type) {
846   case ALIAS:
847     result = _value.alias->setIntValue(value);
848     break;
849   case BOOL:
850     result = SET_BOOL(value == 0 ? false : true);
851     break;
852   case INT:
853     result = SET_INT(value);
854     break;
855   case LONG:
856     result = SET_LONG(long(value));
857     break;
858   case FLOAT:
859     result = SET_FLOAT(float(value));
860     break;
861   case DOUBLE:
862     result = SET_DOUBLE(double(value));
863     break;
864   case STRING: {
865     char buf[128];
866     sprintf(buf, "%d", value);
867     result = SET_STRING(buf);
868     break;
869   }
870   }
871
872   DO_TRACE_WRITE(INT);
873   return result;
874 }
875
876 bool
877 SGPropertyNode::setLongValue (long value)
878 {
879   bool result = false;
880   TEST_WRITE;
881   if (_type == NONE || _type == UNSPECIFIED) {
882     clear_value();
883     _value.long_val = new SGRawValueInternal<long>;
884     _type = LONG;
885   }
886
887   switch (_type) {
888   case ALIAS:
889     result = _value.alias->setLongValue(value);
890     break;
891   case BOOL:
892     result = SET_BOOL(value == 0L ? false : true);
893     break;
894   case INT:
895     result = SET_INT(int(value));
896     break;
897   case LONG:
898     result = SET_LONG(value);
899     break;
900   case FLOAT:
901     result = SET_FLOAT(float(value));
902     break;
903   case DOUBLE:
904     result = SET_DOUBLE(double(value));
905     break;
906   case STRING: {
907     char buf[128];
908     sprintf(buf, "%d", value);
909     result = SET_STRING(buf);
910     break;
911   }
912   }
913
914   DO_TRACE_WRITE(LONG);
915   return result;
916 }
917
918 bool
919 SGPropertyNode::setFloatValue (float value)
920 {
921   bool result = false;
922   TEST_WRITE;
923   if (_type == NONE || _type == UNSPECIFIED) {
924     clear_value();
925     _value.float_val = new SGRawValueInternal<float>;
926     _type = FLOAT;
927   }
928
929   switch (_type) {
930   case ALIAS:
931     result = _value.alias->setFloatValue(value);
932     break;
933   case BOOL:
934     result = SET_BOOL(value == 0.0 ? false : true);
935     break;
936   case INT:
937     result = SET_INT(int(value));
938     break;
939   case LONG:
940     result = SET_LONG(long(value));
941     break;
942   case FLOAT:
943     result = SET_FLOAT(value);
944     break;
945   case DOUBLE:
946     result = SET_DOUBLE(double(value));
947     break;
948   case STRING: {
949     char buf[128];
950     sprintf(buf, "%f", value);
951     result = SET_STRING(buf);
952     break;
953   }
954   }
955
956   DO_TRACE_WRITE(FLOAT);
957   return result;
958 }
959
960 bool
961 SGPropertyNode::setDoubleValue (double value)
962 {
963   bool result = false;
964   TEST_WRITE;
965   if (_type == NONE || _type == UNSPECIFIED) {
966     clear_value();
967     _value.double_val = new SGRawValueInternal<double>;
968     _type = DOUBLE;
969   }
970
971   switch (_type) {
972   case ALIAS:
973     result = _value.alias->setDoubleValue(value);
974     break;
975   case BOOL:
976     result = SET_BOOL(value == 0.0L ? false : true);
977     break;
978   case INT:
979     result = SET_INT(int(value));
980     break;
981   case LONG:
982     result = SET_LONG(long(value));
983     break;
984   case FLOAT:
985     result = SET_FLOAT(float(value));
986     break;
987   case DOUBLE:
988     result = SET_DOUBLE(value);
989     break;
990   case STRING: {
991     char buf[128];
992     sprintf(buf, "%lf", value);
993     result = SET_STRING(buf);
994     break;
995   }
996   }
997
998   DO_TRACE_WRITE(DOUBLE);
999   return result;
1000 }
1001
1002 bool
1003 SGPropertyNode::setStringValue (string value)
1004 {
1005   bool result = false;
1006   TEST_WRITE;
1007   if (_type == NONE || _type == UNSPECIFIED) {
1008     clear_value();
1009     _value.string_val = new SGRawValueInternal<string>;
1010     _type = STRING;
1011   }
1012
1013   switch (_type) {
1014   case ALIAS:
1015     result = _value.alias->setStringValue(value);
1016     break;
1017   case BOOL:
1018     result = SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
1019     break;
1020   case INT:
1021     result = SET_INT(atoi(value.c_str()));
1022     break;
1023   case LONG:
1024     result = SET_LONG(strtol(value.c_str(), 0, 0));
1025     break;
1026   case FLOAT:
1027     result = SET_FLOAT(atof(value.c_str()));
1028     break;
1029   case DOUBLE:
1030     result = SET_DOUBLE(strtod(value.c_str(), 0));
1031     break;
1032   case STRING:
1033     result = SET_STRING(value);
1034     break;
1035   }
1036
1037   DO_TRACE_WRITE(STRING);
1038   return result;
1039 }
1040
1041 bool
1042 SGPropertyNode::setUnspecifiedValue (string value)
1043 {
1044   bool result = false;
1045   TEST_WRITE;
1046   if (_type == NONE) {
1047     clear_value();
1048     _value.string_val = new SGRawValueInternal<string>;
1049     _type = UNSPECIFIED;
1050   }
1051
1052   switch (_type) {
1053   case ALIAS:
1054     result = _value.alias->setUnspecifiedValue(value);
1055     break;
1056   case BOOL:
1057     result = SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
1058     break;
1059   case INT:
1060     result = SET_INT(atoi(value.c_str()));
1061     break;
1062   case LONG:
1063     result = SET_LONG(strtol(value.c_str(), 0, 0));
1064     break;
1065   case FLOAT:
1066     result = SET_FLOAT(atof(value.c_str()));
1067     break;
1068   case DOUBLE:
1069     result = SET_DOUBLE(strtod(value.c_str(), 0));
1070     break;
1071   case STRING:
1072   case UNSPECIFIED:
1073     result = SET_STRING(value);
1074     break;
1075   }
1076
1077   DO_TRACE_WRITE(UNSPECIFIED);
1078   return result;
1079 }
1080
1081 bool
1082 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1083 {
1084   if (_type == ALIAS || _tied)
1085     return false;
1086
1087   bool old_val = false;
1088   if (useDefault)
1089     old_val = getBoolValue();
1090
1091   clear_value();
1092   _type = BOOL;
1093   _tied = true;
1094   _value.bool_val = rawValue.clone();
1095
1096   if (useDefault)
1097     setBoolValue(old_val);
1098
1099   return true;
1100 }
1101
1102 bool
1103 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1104 {
1105   if (_type == ALIAS || _tied)
1106     return false;
1107
1108   int old_val = 0;
1109   if (useDefault)
1110     old_val = getIntValue();
1111
1112   clear_value();
1113   _type = INT;
1114   _tied = true;
1115   _value.int_val = rawValue.clone();
1116
1117   if (useDefault)
1118     setIntValue(old_val);
1119
1120   return true;
1121 }
1122
1123 bool
1124 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1125 {
1126   if (_type == ALIAS || _tied)
1127     return false;
1128
1129   long old_val;
1130   if (useDefault)
1131     old_val = getLongValue();
1132
1133   clear_value();
1134   _type = LONG;
1135   _tied = true;
1136   _value.long_val = rawValue.clone();
1137
1138   if (useDefault)
1139     setLongValue(old_val);
1140
1141   return true;
1142 }
1143
1144 bool
1145 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1146 {
1147   if (_type == ALIAS || _tied)
1148     return false;
1149
1150   float old_val = 0.0;
1151   if (useDefault)
1152     old_val = getFloatValue();
1153
1154   clear_value();
1155   _type = FLOAT;
1156   _tied = true;
1157   _value.float_val = rawValue.clone();
1158
1159   if (useDefault)
1160     setFloatValue(old_val);
1161
1162   return true;
1163 }
1164
1165 bool
1166 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1167 {
1168   if (_type == ALIAS || _tied)
1169     return false;
1170
1171   double old_val = 0.0;
1172   if (useDefault)
1173     old_val = getDoubleValue();
1174
1175   clear_value();
1176   _type = DOUBLE;
1177   _tied = true;
1178   _value.double_val = rawValue.clone();
1179
1180   if (useDefault)
1181     setDoubleValue(old_val);
1182
1183   return true;
1184
1185 }
1186
1187 bool
1188 SGPropertyNode::tie (const SGRawValue<string> &rawValue, bool useDefault)
1189 {
1190   if (_type == ALIAS || _tied)
1191     return false;
1192
1193   string old_val;
1194   if (useDefault)
1195     old_val = getStringValue();
1196
1197   clear_value();
1198   _type = STRING;
1199   _tied = true;
1200   _value.string_val = rawValue.clone();
1201
1202   if (useDefault)
1203     setStringValue(old_val);
1204
1205   return true;
1206 }
1207
1208 bool
1209 SGPropertyNode::untie ()
1210 {
1211   if (!_tied)
1212     return false;
1213
1214   switch (_type) {
1215   case BOOL: {
1216     bool val = getBoolValue();
1217     clear_value();
1218     _type = BOOL;
1219     _value.bool_val = new SGRawValueInternal<bool>;
1220     SET_BOOL(val);
1221     break;
1222   }
1223   case INT: {
1224     int val = getIntValue();
1225     clear_value();
1226     _type = INT;
1227     _value.int_val = new SGRawValueInternal<int>;
1228     SET_INT(val);
1229     break;
1230   }
1231   case LONG: {
1232     long val = getLongValue();
1233     clear_value();
1234     _type = LONG;
1235     _value.long_val = new SGRawValueInternal<long>;
1236     SET_LONG(val);
1237     break;
1238   }
1239   case FLOAT: {
1240     float val = getFloatValue();
1241     clear_value();
1242     _type = FLOAT;
1243     _value.float_val = new SGRawValueInternal<float>;
1244     SET_FLOAT(val);
1245     break;
1246   }
1247   case DOUBLE: {
1248     double val = getDoubleValue();
1249     clear_value();
1250     _type = DOUBLE;
1251     _value.double_val = new SGRawValueInternal<double>;
1252     SET_DOUBLE(val);
1253     break;
1254   }
1255   case STRING: {
1256     string val = getStringValue();
1257     clear_value();
1258     _type = STRING;
1259     _value.string_val = new SGRawValueInternal<string>;
1260     SET_STRING(val);
1261     break;
1262   }
1263   }
1264
1265   _tied = false;
1266   return true;
1267 }
1268
1269 SGPropertyNode *
1270 SGPropertyNode::getRootNode ()
1271 {
1272   if (_parent == 0)
1273     return this;
1274   else
1275     return _parent->getRootNode();
1276 }
1277
1278 const SGPropertyNode *
1279 SGPropertyNode::getRootNode () const
1280 {
1281   if (_parent == 0)
1282     return this;
1283   else
1284     return _parent->getRootNode();
1285 }
1286
1287 SGPropertyNode *
1288 SGPropertyNode::getNode (const string &relative_path, bool create)
1289 {
1290   if (_path_cache == 0)
1291     _path_cache = new cache_map;
1292
1293   SGPropertyNode * result = (*_path_cache)[relative_path];
1294   if (result == 0) {
1295     vector<PathComponent> components;
1296     parse_path(relative_path, components);
1297     result = find_node(this, components, 0, create);
1298     (*_path_cache)[relative_path] = result;
1299   }
1300   
1301   return result;
1302 }
1303
1304 SGPropertyNode *
1305 SGPropertyNode::getNode (const string &relative_path, int index, bool create)
1306 {
1307   vector<PathComponent> components;
1308   parse_path(relative_path, components);
1309   if (components.size() > 0)
1310     components[components.size()-1].index = index;
1311   return find_node(this, components, 0, create);
1312 }
1313
1314 const SGPropertyNode *
1315 SGPropertyNode::getNode (const string &relative_path) const
1316 {
1317   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1318 }
1319
1320 const SGPropertyNode *
1321 SGPropertyNode::getNode (const string &relative_path, int index) const
1322 {
1323   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1324 }
1325
1326 \f
1327 ////////////////////////////////////////////////////////////////////////
1328 // Convenience methods using relative paths.
1329 ////////////////////////////////////////////////////////////////////////
1330
1331
1332 /**
1333  * Test whether another node has a value attached.
1334  */
1335 bool
1336 SGPropertyNode::hasValue (const string &relative_path) const
1337 {
1338   const SGPropertyNode * node = getNode(relative_path);
1339   return (node == 0 ? false : node->hasValue());
1340 }
1341
1342
1343 /**
1344  * Get the value type for another node.
1345  */
1346 SGPropertyNode::Type
1347 SGPropertyNode::getType (const string &relative_path) const
1348 {
1349   const SGPropertyNode * node = getNode(relative_path);
1350   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1351 }
1352
1353
1354 /**
1355  * Get a bool value for another node.
1356  */
1357 bool
1358 SGPropertyNode::getBoolValue (const string &relative_path,
1359                               bool defaultValue) const
1360 {
1361   const SGPropertyNode * node = getNode(relative_path);
1362   return (node == 0 ? defaultValue : node->getBoolValue());
1363 }
1364
1365
1366 /**
1367  * Get an int value for another node.
1368  */
1369 int
1370 SGPropertyNode::getIntValue (const string &relative_path,
1371                              int defaultValue) const
1372 {
1373   const SGPropertyNode * node = getNode(relative_path);
1374   return (node == 0 ? defaultValue : node->getIntValue());
1375 }
1376
1377
1378 /**
1379  * Get a long value for another node.
1380  */
1381 long
1382 SGPropertyNode::getLongValue (const string &relative_path,
1383                               long defaultValue) const
1384 {
1385   const SGPropertyNode * node = getNode(relative_path);
1386   return (node == 0 ? defaultValue : node->getLongValue());
1387 }
1388
1389
1390 /**
1391  * Get a float value for another node.
1392  */
1393 float
1394 SGPropertyNode::getFloatValue (const string &relative_path,
1395                                float defaultValue) const
1396 {
1397   const SGPropertyNode * node = getNode(relative_path);
1398   return (node == 0 ? defaultValue : node->getFloatValue());
1399 }
1400
1401
1402 /**
1403  * Get a double value for another node.
1404  */
1405 double
1406 SGPropertyNode::getDoubleValue (const string &relative_path,
1407                                 double defaultValue) const
1408 {
1409   const SGPropertyNode * node = getNode(relative_path);
1410   return (node == 0 ? defaultValue : node->getDoubleValue());
1411 }
1412
1413
1414 /**
1415  * Get a string value for another node.
1416  */
1417 string
1418 SGPropertyNode::getStringValue (const string &relative_path,
1419                                 string defaultValue) const
1420 {
1421   const SGPropertyNode * node = getNode(relative_path);
1422   return (node == 0 ? defaultValue : node->getStringValue());
1423 }
1424
1425
1426 /**
1427  * Set a bool value for another node.
1428  */
1429 bool
1430 SGPropertyNode::setBoolValue (const string &relative_path, bool value)
1431 {
1432   return getNode(relative_path, true)->setBoolValue(value);
1433 }
1434
1435
1436 /**
1437  * Set an int value for another node.
1438  */
1439 bool
1440 SGPropertyNode::setIntValue (const string &relative_path, int value)
1441 {
1442   return getNode(relative_path, true)->setIntValue(value);
1443 }
1444
1445
1446 /**
1447  * Set a long value for another node.
1448  */
1449 bool
1450 SGPropertyNode::setLongValue (const string &relative_path, long value)
1451 {
1452   return getNode(relative_path, true)->setLongValue(value);
1453 }
1454
1455
1456 /**
1457  * Set a float value for another node.
1458  */
1459 bool
1460 SGPropertyNode::setFloatValue (const string &relative_path, float value)
1461 {
1462   return getNode(relative_path, true)->setFloatValue(value);
1463 }
1464
1465
1466 /**
1467  * Set a double value for another node.
1468  */
1469 bool
1470 SGPropertyNode::setDoubleValue (const string &relative_path, double value)
1471 {
1472   return getNode(relative_path, true)->setDoubleValue(value);
1473 }
1474
1475
1476 /**
1477  * Set a string value for another node.
1478  */
1479 bool
1480 SGPropertyNode::setStringValue (const string &relative_path, string value)
1481 {
1482   return getNode(relative_path, true)->setStringValue(value);
1483 }
1484
1485
1486 /**
1487  * Set an unknown value for another node.
1488  */
1489 bool
1490 SGPropertyNode::setUnspecifiedValue (const string &relative_path, string value)
1491 {
1492   return getNode(relative_path, true)->setUnspecifiedValue(value);
1493 }
1494
1495
1496 /**
1497  * Test whether another node is tied.
1498  */
1499 bool
1500 SGPropertyNode::isTied (const string &relative_path) const
1501 {
1502   const SGPropertyNode * node = getNode(relative_path);
1503   return (node == 0 ? false : node->isTied());
1504 }
1505
1506
1507 /**
1508  * Tie a node reached by a relative path, creating it if necessary.
1509  */
1510 bool
1511 SGPropertyNode::tie (const string &relative_path,
1512                      const SGRawValue<bool> &rawValue,
1513                      bool useDefault)
1514 {
1515   return getNode(relative_path, true)->tie(rawValue, useDefault);
1516 }
1517
1518
1519 /**
1520  * Tie a node reached by a relative path, creating it if necessary.
1521  */
1522 bool
1523 SGPropertyNode::tie (const string &relative_path,
1524                      const SGRawValue<int> &rawValue,
1525                      bool useDefault)
1526 {
1527   return getNode(relative_path, true)->tie(rawValue, useDefault);
1528 }
1529
1530
1531 /**
1532  * Tie a node reached by a relative path, creating it if necessary.
1533  */
1534 bool
1535 SGPropertyNode::tie (const string &relative_path,
1536                      const SGRawValue<long> &rawValue,
1537                      bool useDefault)
1538 {
1539   return getNode(relative_path, true)->tie(rawValue, useDefault);
1540 }
1541
1542
1543 /**
1544  * Tie a node reached by a relative path, creating it if necessary.
1545  */
1546 bool
1547 SGPropertyNode::tie (const string &relative_path,
1548                      const SGRawValue<float> &rawValue,
1549                      bool useDefault)
1550 {
1551   return getNode(relative_path, true)->tie(rawValue, useDefault);
1552 }
1553
1554
1555 /**
1556  * Tie a node reached by a relative path, creating it if necessary.
1557  */
1558 bool
1559 SGPropertyNode::tie (const string &relative_path,
1560                      const SGRawValue<double> &rawValue,
1561                      bool useDefault)
1562 {
1563   return getNode(relative_path, true)->tie(rawValue, useDefault);
1564 }
1565
1566
1567 /**
1568  * Tie a node reached by a relative path, creating it if necessary.
1569  */
1570 bool
1571 SGPropertyNode::tie (const string &relative_path,
1572                      const SGRawValue<string> &rawValue,
1573                      bool useDefault)
1574 {
1575   return getNode(relative_path, true)->tie(rawValue, useDefault);
1576 }
1577
1578
1579 /**
1580  * Attempt to untie another node reached by a relative path.
1581  */
1582 bool
1583 SGPropertyNode::untie (const string &relative_path)
1584 {
1585   SGPropertyNode * node = getNode(relative_path);
1586   return (node == 0 ? false : node->untie());
1587 }
1588
1589 // end of props.cxx