]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
Minor fixes from Cameron Moore.
[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   bool old_val = false;
1121   if (useDefault)
1122     old_val = getBoolValue();
1123
1124   clear_value();
1125   _type = BOOL;
1126   _tied = true;
1127   _value.bool_val = rawValue.clone();
1128
1129   if (useDefault)
1130     setBoolValue(old_val);
1131
1132   return true;
1133 }
1134
1135 bool
1136 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1137 {
1138   if (_type == ALIAS || _tied)
1139     return false;
1140
1141   int old_val = 0;
1142   if (useDefault)
1143     old_val = getIntValue();
1144
1145   clear_value();
1146   _type = INT;
1147   _tied = true;
1148   _value.int_val = rawValue.clone();
1149
1150   if (useDefault)
1151     setIntValue(old_val);
1152
1153   return true;
1154 }
1155
1156 bool
1157 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1158 {
1159   if (_type == ALIAS || _tied)
1160     return false;
1161
1162   long old_val;
1163   if (useDefault)
1164     old_val = getLongValue();
1165
1166   clear_value();
1167   _type = LONG;
1168   _tied = true;
1169   _value.long_val = rawValue.clone();
1170
1171   if (useDefault)
1172     setLongValue(old_val);
1173
1174   return true;
1175 }
1176
1177 bool
1178 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1179 {
1180   if (_type == ALIAS || _tied)
1181     return false;
1182
1183   float old_val = 0.0;
1184   if (useDefault)
1185     old_val = getFloatValue();
1186
1187   clear_value();
1188   _type = FLOAT;
1189   _tied = true;
1190   _value.float_val = rawValue.clone();
1191
1192   if (useDefault)
1193     setFloatValue(old_val);
1194
1195   return true;
1196 }
1197
1198 bool
1199 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1200 {
1201   if (_type == ALIAS || _tied)
1202     return false;
1203
1204   double old_val = 0.0;
1205   if (useDefault)
1206     old_val = getDoubleValue();
1207
1208   clear_value();
1209   _type = DOUBLE;
1210   _tied = true;
1211   _value.double_val = rawValue.clone();
1212
1213   if (useDefault)
1214     setDoubleValue(old_val);
1215
1216   return true;
1217
1218 }
1219
1220 bool
1221 SGPropertyNode::tie (const SGRawValue<string> &rawValue, bool useDefault)
1222 {
1223   if (_type == ALIAS || _tied)
1224     return false;
1225
1226   string old_val;
1227   if (useDefault)
1228     old_val = getStringValue();
1229
1230   clear_value();
1231   _type = STRING;
1232   _tied = true;
1233   _value.string_val = rawValue.clone();
1234
1235   if (useDefault)
1236     setStringValue(old_val);
1237
1238   return true;
1239 }
1240
1241 bool
1242 SGPropertyNode::untie ()
1243 {
1244   if (!_tied)
1245     return false;
1246
1247   switch (_type) {
1248   case BOOL: {
1249     bool val = getBoolValue();
1250     clear_value();
1251     _type = BOOL;
1252     _value.bool_val = new SGRawValueInternal<bool>;
1253     SET_BOOL(val);
1254     break;
1255   }
1256   case INT: {
1257     int val = getIntValue();
1258     clear_value();
1259     _type = INT;
1260     _value.int_val = new SGRawValueInternal<int>;
1261     SET_INT(val);
1262     break;
1263   }
1264   case LONG: {
1265     long val = getLongValue();
1266     clear_value();
1267     _type = LONG;
1268     _value.long_val = new SGRawValueInternal<long>;
1269     SET_LONG(val);
1270     break;
1271   }
1272   case FLOAT: {
1273     float val = getFloatValue();
1274     clear_value();
1275     _type = FLOAT;
1276     _value.float_val = new SGRawValueInternal<float>;
1277     SET_FLOAT(val);
1278     break;
1279   }
1280   case DOUBLE: {
1281     double val = getDoubleValue();
1282     clear_value();
1283     _type = DOUBLE;
1284     _value.double_val = new SGRawValueInternal<double>;
1285     SET_DOUBLE(val);
1286     break;
1287   }
1288   case STRING:
1289   case UNSPECIFIED: {
1290     string val = getStringValue();
1291     clear_value();
1292     _type = STRING;
1293     _value.string_val = new SGRawValueInternal<string>;
1294     SET_STRING(val);
1295     break;
1296   }
1297   case NONE:
1298   default:
1299     break;
1300   }
1301
1302   _tied = false;
1303   return true;
1304 }
1305
1306 SGPropertyNode *
1307 SGPropertyNode::getRootNode ()
1308 {
1309   if (_parent == 0)
1310     return this;
1311   else
1312     return _parent->getRootNode();
1313 }
1314
1315 const SGPropertyNode *
1316 SGPropertyNode::getRootNode () const
1317 {
1318   if (_parent == 0)
1319     return this;
1320   else
1321     return _parent->getRootNode();
1322 }
1323
1324 SGPropertyNode *
1325 SGPropertyNode::getNode (const string &relative_path, bool create)
1326 {
1327   if (_path_cache == 0)
1328     _path_cache = new cache_map;
1329
1330   SGPropertyNode * result = (*_path_cache)[relative_path];
1331   if (result == 0) {
1332     vector<PathComponent> components;
1333     parse_path(relative_path, components);
1334     result = find_node(this, components, 0, create);
1335     (*_path_cache)[relative_path] = result;
1336   }
1337   
1338   return result;
1339 }
1340
1341 SGPropertyNode *
1342 SGPropertyNode::getNode (const string &relative_path, int index, bool create)
1343 {
1344   vector<PathComponent> components;
1345   parse_path(relative_path, components);
1346   if (components.size() > 0)
1347     components[components.size()-1].index = index;
1348   return find_node(this, components, 0, create);
1349 }
1350
1351 const SGPropertyNode *
1352 SGPropertyNode::getNode (const string &relative_path) const
1353 {
1354   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1355 }
1356
1357 const SGPropertyNode *
1358 SGPropertyNode::getNode (const string &relative_path, int index) const
1359 {
1360   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1361 }
1362
1363 \f
1364 ////////////////////////////////////////////////////////////////////////
1365 // Convenience methods using relative paths.
1366 ////////////////////////////////////////////////////////////////////////
1367
1368
1369 /**
1370  * Test whether another node has a value attached.
1371  */
1372 bool
1373 SGPropertyNode::hasValue (const string &relative_path) const
1374 {
1375   const SGPropertyNode * node = getNode(relative_path);
1376   return (node == 0 ? false : node->hasValue());
1377 }
1378
1379
1380 /**
1381  * Get the value type for another node.
1382  */
1383 SGPropertyNode::Type
1384 SGPropertyNode::getType (const string &relative_path) const
1385 {
1386   const SGPropertyNode * node = getNode(relative_path);
1387   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1388 }
1389
1390
1391 /**
1392  * Get a bool value for another node.
1393  */
1394 bool
1395 SGPropertyNode::getBoolValue (const string &relative_path,
1396                               bool defaultValue) const
1397 {
1398   const SGPropertyNode * node = getNode(relative_path);
1399   return (node == 0 ? defaultValue : node->getBoolValue());
1400 }
1401
1402
1403 /**
1404  * Get an int value for another node.
1405  */
1406 int
1407 SGPropertyNode::getIntValue (const string &relative_path,
1408                              int defaultValue) const
1409 {
1410   const SGPropertyNode * node = getNode(relative_path);
1411   return (node == 0 ? defaultValue : node->getIntValue());
1412 }
1413
1414
1415 /**
1416  * Get a long value for another node.
1417  */
1418 long
1419 SGPropertyNode::getLongValue (const string &relative_path,
1420                               long defaultValue) const
1421 {
1422   const SGPropertyNode * node = getNode(relative_path);
1423   return (node == 0 ? defaultValue : node->getLongValue());
1424 }
1425
1426
1427 /**
1428  * Get a float value for another node.
1429  */
1430 float
1431 SGPropertyNode::getFloatValue (const string &relative_path,
1432                                float defaultValue) const
1433 {
1434   const SGPropertyNode * node = getNode(relative_path);
1435   return (node == 0 ? defaultValue : node->getFloatValue());
1436 }
1437
1438
1439 /**
1440  * Get a double value for another node.
1441  */
1442 double
1443 SGPropertyNode::getDoubleValue (const string &relative_path,
1444                                 double defaultValue) const
1445 {
1446   const SGPropertyNode * node = getNode(relative_path);
1447   return (node == 0 ? defaultValue : node->getDoubleValue());
1448 }
1449
1450
1451 /**
1452  * Get a string value for another node.
1453  */
1454 string
1455 SGPropertyNode::getStringValue (const string &relative_path,
1456                                 string defaultValue) const
1457 {
1458   const SGPropertyNode * node = getNode(relative_path);
1459   return (node == 0 ? defaultValue : node->getStringValue());
1460 }
1461
1462
1463 /**
1464  * Set a bool value for another node.
1465  */
1466 bool
1467 SGPropertyNode::setBoolValue (const string &relative_path, bool value)
1468 {
1469   return getNode(relative_path, true)->setBoolValue(value);
1470 }
1471
1472
1473 /**
1474  * Set an int value for another node.
1475  */
1476 bool
1477 SGPropertyNode::setIntValue (const string &relative_path, int value)
1478 {
1479   return getNode(relative_path, true)->setIntValue(value);
1480 }
1481
1482
1483 /**
1484  * Set a long value for another node.
1485  */
1486 bool
1487 SGPropertyNode::setLongValue (const string &relative_path, long value)
1488 {
1489   return getNode(relative_path, true)->setLongValue(value);
1490 }
1491
1492
1493 /**
1494  * Set a float value for another node.
1495  */
1496 bool
1497 SGPropertyNode::setFloatValue (const string &relative_path, float value)
1498 {
1499   return getNode(relative_path, true)->setFloatValue(value);
1500 }
1501
1502
1503 /**
1504  * Set a double value for another node.
1505  */
1506 bool
1507 SGPropertyNode::setDoubleValue (const string &relative_path, double value)
1508 {
1509   return getNode(relative_path, true)->setDoubleValue(value);
1510 }
1511
1512
1513 /**
1514  * Set a string value for another node.
1515  */
1516 bool
1517 SGPropertyNode::setStringValue (const string &relative_path, string value)
1518 {
1519   return getNode(relative_path, true)->setStringValue(value);
1520 }
1521
1522
1523 /**
1524  * Set an unknown value for another node.
1525  */
1526 bool
1527 SGPropertyNode::setUnspecifiedValue (const string &relative_path, string value)
1528 {
1529   return getNode(relative_path, true)->setUnspecifiedValue(value);
1530 }
1531
1532
1533 /**
1534  * Test whether another node is tied.
1535  */
1536 bool
1537 SGPropertyNode::isTied (const string &relative_path) const
1538 {
1539   const SGPropertyNode * node = getNode(relative_path);
1540   return (node == 0 ? false : node->isTied());
1541 }
1542
1543
1544 /**
1545  * Tie a node reached by a relative path, creating it if necessary.
1546  */
1547 bool
1548 SGPropertyNode::tie (const string &relative_path,
1549                      const SGRawValue<bool> &rawValue,
1550                      bool useDefault)
1551 {
1552   return getNode(relative_path, true)->tie(rawValue, useDefault);
1553 }
1554
1555
1556 /**
1557  * Tie a node reached by a relative path, creating it if necessary.
1558  */
1559 bool
1560 SGPropertyNode::tie (const string &relative_path,
1561                      const SGRawValue<int> &rawValue,
1562                      bool useDefault)
1563 {
1564   return getNode(relative_path, true)->tie(rawValue, useDefault);
1565 }
1566
1567
1568 /**
1569  * Tie a node reached by a relative path, creating it if necessary.
1570  */
1571 bool
1572 SGPropertyNode::tie (const string &relative_path,
1573                      const SGRawValue<long> &rawValue,
1574                      bool useDefault)
1575 {
1576   return getNode(relative_path, true)->tie(rawValue, useDefault);
1577 }
1578
1579
1580 /**
1581  * Tie a node reached by a relative path, creating it if necessary.
1582  */
1583 bool
1584 SGPropertyNode::tie (const string &relative_path,
1585                      const SGRawValue<float> &rawValue,
1586                      bool useDefault)
1587 {
1588   return getNode(relative_path, true)->tie(rawValue, useDefault);
1589 }
1590
1591
1592 /**
1593  * Tie a node reached by a relative path, creating it if necessary.
1594  */
1595 bool
1596 SGPropertyNode::tie (const string &relative_path,
1597                      const SGRawValue<double> &rawValue,
1598                      bool useDefault)
1599 {
1600   return getNode(relative_path, true)->tie(rawValue, useDefault);
1601 }
1602
1603
1604 /**
1605  * Tie a node reached by a relative path, creating it if necessary.
1606  */
1607 bool
1608 SGPropertyNode::tie (const string &relative_path,
1609                      const SGRawValue<string> &rawValue,
1610                      bool useDefault)
1611 {
1612   return getNode(relative_path, true)->tie(rawValue, useDefault);
1613 }
1614
1615
1616 /**
1617  * Attempt to untie another node reached by a relative path.
1618  */
1619 bool
1620 SGPropertyNode::untie (const string &relative_path)
1621 {
1622   SGPropertyNode * node = getNode(relative_path);
1623   return (node == 0 ? false : node->untie());
1624 }
1625
1626 // end of props.cxx