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