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