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