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