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