]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
Major property-manager rewrite, using const char * throughout
[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 "props.hxx"
10
11 #if PROPS_STANDALONE
12
13 #include <iostream>
14 using std::cerr;
15 using std::endl;
16 using std::sort;
17
18 #else
19
20 #include <simgear/compiler.h>
21 #include <simgear/debug/logstream.hxx>
22 SG_USING_STD(sort);
23
24 #endif
25
26 #include <string.h>
27
28
29 \f
30 ////////////////////////////////////////////////////////////////////////
31 // Local classes.
32 ////////////////////////////////////////////////////////////////////////
33
34 /**
35  * Comparator class for sorting by index.
36  */
37 class CompareIndices
38 {
39 public:
40   int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
41     return (n1->getIndex() < n2->getIndex());
42   }
43 };
44
45
46 \f
47 ////////////////////////////////////////////////////////////////////////
48 // Convenience macros for value access.
49 ////////////////////////////////////////////////////////////////////////
50
51 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
52 #define TEST_WRITE if (!getAttribute(WRITE)) return false
53
54
55 \f
56 ////////////////////////////////////////////////////////////////////////
57 // Default values for every type.
58 ////////////////////////////////////////////////////////////////////////
59
60 const bool SGRawValue<bool>::DefaultValue = false;
61 const int SGRawValue<int>::DefaultValue = 0;
62 const long SGRawValue<long>::DefaultValue = 0L;
63 const float SGRawValue<float>::DefaultValue = 0.0;
64 const double SGRawValue<double>::DefaultValue = 0.0L;
65 const char * const SGRawValue<const char *>::DefaultValue = "";
66
67
68 \f
69 ////////////////////////////////////////////////////////////////////////
70 // Local path normalization code.
71 ////////////////////////////////////////////////////////////////////////
72
73 /**
74  * A component in a path.
75  */
76 struct PathComponent
77 {
78   string name;
79   int index;
80 };
81
82 /**
83  * Parse the name for a path component.
84  *
85  * Name: [_a-zA-Z][-._a-zA-Z0-9]*
86  */
87 static inline const string
88 parse_name (const string &path, int &i)
89 {
90   string name = "";
91   int max = path.size();
92
93   if (path[i] == '.') {
94     i++;
95     if (i < max && path[i] == '.') {
96       i++;
97       name = "..";
98     } else {
99       name = ".";
100     }
101     if (i < max && path[i] != '/')
102       throw string(string("Illegal character after ") + name);
103   }
104
105   else if (isalpha(path[i]) || path[i] == '_') {
106     name += path[i];
107     i++;
108
109                                 // The rules inside a name are a little
110                                 // less restrictive.
111     while (i < max) {
112       if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
113           path[i] == '-' || path[i] == '.') {
114         name += path[i];
115       } else if (path[i] == '[' || path[i] == '/') {
116         break;
117       } else {
118         throw string("name may contain only ._- and alphanumeric characters");
119       }
120       i++;
121     }
122   }
123
124   else {
125     if (name.size() == 0)
126       throw string("name must begin with alpha or '_'");
127   }
128
129   return name;
130 }
131
132
133 /**
134  * Parse the optional integer index for a path component.
135  *
136  * Index: "[" [0-9]+ "]"
137  */
138 static inline int
139 parse_index (const string &path, int &i)
140 {
141   int index = 0;
142
143   if (path[i] != '[')
144     return 0;
145   else
146     i++;
147
148   for (int max = path.size(); i < max; i++) {
149     if (isdigit(path[i])) {
150       index = (index * 10) + (path[i] - '0');
151     } else if (path[i] == ']') {
152       i++;
153       return index;
154     } else {
155       break;
156     }
157   }
158
159   throw string("unterminated index (looking for ']')");
160 }
161
162
163 /**
164  * Parse a single path component.
165  *
166  * Component: Name Index?
167  */
168 static inline PathComponent
169 parse_component (const string &path, int &i)
170 {
171   PathComponent component;
172   component.name = parse_name(path, i);
173   if (component.name[0] != '.')
174     component.index = parse_index(path, i);
175   else
176     component.index = -1;
177   return component;
178 }
179
180
181 /**
182  * Parse a path into its components.
183  */
184 static void
185 parse_path (const string &path, vector<PathComponent> &components)
186 {
187   int pos = 0;
188   int max = path.size();
189
190                                 // Check for initial '/'
191   if (path[pos] == '/') {
192     PathComponent root;
193     root.name = "";
194     root.index = -1;
195     components.push_back(root);
196     pos++;
197     while (pos < max && path[pos] == '/')
198       pos++;
199   }
200
201   while (pos < max) {
202     components.push_back(parse_component(path, pos));
203     while (pos < max && path[pos] == '/')
204       pos++;
205   }
206 }
207
208
209 \f
210 ////////////////////////////////////////////////////////////////////////
211 // Other static utility functions.
212 ////////////////////////////////////////////////////////////////////////
213
214
215 static const char *
216 copy_string (const char * s)
217 {
218                                 // FIXME: potential buffer overflow.
219                                 // For some reason, strnlen and
220                                 // strncpy cause all kinds of crashes.
221   string str = s;
222   size_t len = strlen(s);
223   char * copy = new char[str.size() + 1];
224   strcpy(copy, str.c_str());
225   return copy;
226 }
227
228 static bool
229 compare_strings (const char * s1, const char * s2)
230 {
231   return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
232 }
233
234 /**
235  * Locate a child node by name and index.
236  */
237 static int
238 find_child (const char * name, int index, vector<SGPropertyNode *> nodes)
239 {
240   int nNodes = nodes.size();
241   for (int i = 0; i < nNodes; i++) {
242     SGPropertyNode * node = nodes[i];
243     if (compare_strings(node->getName(), name) && node->getIndex() == index)
244       return i;
245   }
246   return -1;
247 }
248
249
250 /**
251  * Locate another node, given a relative path.
252  */
253 static SGPropertyNode *
254 find_node (SGPropertyNode * current,
255            const vector<PathComponent> &components,
256            int position,
257            bool create)
258 {
259                                 // Run off the end of the list
260   if (current == 0) {
261     return 0;
262   }
263
264                                 // Success! This is the one we want.
265   else if (position >= (int)components.size()) {
266     return current;
267   }
268
269                                 // Empty component means root.
270   else if (components[position].name == "") {
271     return find_node(current->getRootNode(), components, position + 1, create);
272   }
273
274                                 // . means current directory
275   else if (components[position].name == ".") {
276     return find_node(current, components, position + 1, create);
277   }
278
279                                 // .. means parent directory
280   else if (components[position].name == "..") {
281     SGPropertyNode * parent = current->getParent();
282     if (parent == 0)
283       throw string("Attempt to move past root with '..'");
284     else
285       return find_node(parent, components, position + 1, create);
286   }
287
288                                 // Otherwise, a child name
289   else {
290     SGPropertyNode * child =
291       current->getChild(components[position].name.c_str(),
292                         components[position].index,
293                         create);
294     return find_node(child, components, position + 1, create);
295   }
296 }
297
298
299 \f
300 ////////////////////////////////////////////////////////////////////////
301 // Private methods from SGPropertyNode (may be inlined for speed).
302 ////////////////////////////////////////////////////////////////////////
303
304 inline bool
305 SGPropertyNode::get_bool () const
306 {
307   if (_tied)
308     return _value.bool_val->getValue();
309   else
310     return _local_val.bool_val;
311 }
312
313 inline int
314 SGPropertyNode::get_int () const
315 {
316   if (_tied)
317     return _value.int_val->getValue();
318   else
319     return _local_val.int_val;
320 }
321
322 inline long
323 SGPropertyNode::get_long () const
324 {
325   if (_tied)
326     return _value.long_val->getValue();
327   else
328     return _local_val.long_val;
329 }
330
331 inline float
332 SGPropertyNode::get_float () const
333 {
334   if (_tied)
335     return _value.float_val->getValue();
336   else
337     return _local_val.float_val;
338 }
339
340 inline double
341 SGPropertyNode::get_double () const
342 {
343   if (_tied)
344     return _value.double_val->getValue();
345   else
346     return _local_val.double_val;
347 }
348
349 inline const char *
350 SGPropertyNode::get_string () const
351 {
352   if (_tied)
353     return _value.string_val->getValue();
354   else
355     return _local_val.string_val;
356 }
357
358 inline bool
359 SGPropertyNode::set_bool (bool val)
360 {
361   if (_tied) {
362     return _value.bool_val->setValue(val);
363   } else {
364     _local_val.bool_val = val;
365     return true;
366   }
367 }
368
369 inline bool
370 SGPropertyNode::set_int (int val)
371 {
372   if (_tied) {
373     return _value.int_val->setValue(val);
374   } else {
375     _local_val.int_val = val;
376     return true;
377   }
378 }
379
380 inline bool
381 SGPropertyNode::set_long (long val)
382 {
383   if (_tied) {
384     return _value.long_val->setValue(val);
385   } else {
386     _local_val.long_val = val;
387     return true;
388   }
389 }
390
391 inline bool
392 SGPropertyNode::set_float (float val)
393 {
394   if (_tied) {
395     return _value.float_val->setValue(val);
396   } else {
397     _local_val.float_val = val;
398     return true;
399   }
400 }
401
402 inline bool
403 SGPropertyNode::set_double (double val)
404 {
405   if (_tied) {
406     return _value.double_val->setValue(val);
407   } else {
408     _local_val.double_val = val;
409     return true;
410   }
411 }
412
413 inline bool
414 SGPropertyNode::set_string (const char * val)
415 {
416   if (_tied) {
417     return _value.string_val->setValue(val);
418   } else {
419     delete _local_val.string_val;
420     _local_val.string_val = copy_string(val);
421     return true;
422   }
423 }
424
425 void
426 SGPropertyNode::clear_value ()
427 {
428   switch (_type) {
429   case NONE:
430   case ALIAS:
431     _value.alias = 0;
432     break;
433   case BOOL:
434     delete _value.bool_val;
435     _value.bool_val = 0;
436     _local_val.bool_val = SGRawValue<bool>::DefaultValue;
437     break;
438   case INT:
439     delete _value.int_val;
440     _value.int_val = 0;
441     _local_val.int_val = SGRawValue<int>::DefaultValue;
442     break;
443   case LONG:
444     delete _value.long_val;
445     _value.long_val = 0L;
446     _local_val.long_val = SGRawValue<long>::DefaultValue;
447     break;
448   case FLOAT:
449     delete _value.float_val;
450     _value.float_val = 0;
451     _local_val.float_val = SGRawValue<float>::DefaultValue;
452     break;
453   case DOUBLE:
454     delete _value.double_val;
455     _value.double_val = 0;
456     _local_val.double_val = SGRawValue<double>::DefaultValue;
457     break;
458   case STRING:
459   case UNSPECIFIED:
460     delete _value.string_val;
461     _value.string_val = 0;
462     delete _local_val.string_val;
463     _local_val.string_val = 0;
464     break;
465   }
466   _tied = false;
467   _type = NONE;
468 }
469
470
471 /**
472  * Get the value as a string.
473  */
474 const char *
475 SGPropertyNode::make_string () const
476 {
477   if (!getAttribute(READ))
478     return "";
479
480   switch (_type) {
481   case ALIAS:
482     return _value.alias->getStringValue();
483   case BOOL:
484     if (get_bool())
485       return "true";
486     else
487       return "false";
488   case INT:
489     sprintf(_buffer, "%d", get_int());
490     return _buffer;
491   case LONG:
492     sprintf(_buffer, "%ld", get_long());
493     return _buffer;
494   case FLOAT:
495     sprintf(_buffer, "%f", get_float());
496     return _buffer;
497   case DOUBLE:
498     sprintf(_buffer, "%f", get_double());
499     return _buffer;
500   case STRING:
501   case UNSPECIFIED:
502     return get_string();
503   case NONE:
504   default:
505     return "";
506   }
507 }
508
509 /**
510  * Trace a write access for a property.
511  */
512 void
513 SGPropertyNode::trace_write () const
514 {
515 #if PROPS_STANDALONE
516   cerr << "TRACE: Write node " << getPath () << ", value\""
517        << make_string() << '"' << endl;
518 #else
519   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
520          << ", value\"" << make_string() << '"');
521 #endif
522 }
523
524 /**
525  * Trace a read access for a property.
526  */
527 void
528 SGPropertyNode::trace_read () const
529 {
530 #if PROPS_STANDALONE
531   cerr << "TRACE: Write node " << getPath () << ", value \""
532        << make_string() << '"' << endl;
533 #else
534   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
535          << ", value \"" << make_string() << '"');
536 #endif
537 }
538
539
540 \f
541 ////////////////////////////////////////////////////////////////////////
542 // Public methods from SGPropertyNode.
543 ////////////////////////////////////////////////////////////////////////
544
545 /**
546  * Default constructor: always creates a root node.
547  */
548 SGPropertyNode::SGPropertyNode ()
549   : _name(copy_string("")),
550     _index(0),
551     _parent(0),
552     _path_cache(0),
553     _type(NONE),
554     _tied(false),
555     _attr(READ|WRITE)
556 {
557   _local_val.string_val = 0;
558 }
559
560
561 /**
562  * Copy constructor.
563  */
564 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
565   : _index(node._index),
566     _parent(0),                 // don't copy the parent
567     _path_cache(0),
568     _type(node._type),
569     _tied(node._tied),
570     _attr(node._attr)
571 {
572   _name = copy_string(node._name);
573   _local_val.string_val = 0;
574   switch (_type) {
575   case NONE:
576     break;
577   case ALIAS:
578     _value.alias = node._value.alias;
579     _tied = false;
580     break;
581   case BOOL:
582     if (_tied) {
583       _tied = true;
584       _value.bool_val = node._value.bool_val->clone();
585     } else {
586       _tied = false;
587       set_bool(node.get_bool());
588     }
589     break;
590   case INT:
591     if (_tied) {
592       _tied = true;
593       _value.int_val = node._value.int_val->clone();
594     } else {
595       _tied = false;
596       set_int(node.get_int());
597     }
598     break;
599   case LONG:
600     if (_tied) {
601       _tied = true;
602       _value.long_val = node._value.long_val->clone();
603     } else {
604       _tied = false;
605       set_long(node.get_long());
606     }
607     break;
608   case FLOAT:
609     if (_tied) {
610       _tied = true;
611       _value.float_val = node._value.float_val->clone();
612     } else {
613       _tied = false;
614       set_float(node.get_float());
615     }
616     break;
617   case DOUBLE:
618     if (_tied) {
619       _tied = true;
620       _value.double_val = node._value.double_val->clone();
621     } else {
622       _tied = false;
623       set_double(node.get_double());
624     }
625     break;
626   case STRING:
627   case UNSPECIFIED:
628     if (_tied) {
629       _tied = true;
630       _value.string_val = node._value.string_val->clone();
631     } else {
632       _tied = false;
633       set_string(node.get_string());
634     }
635     break;
636   }
637 }
638
639
640 /**
641  * Convenience constructor.
642  */
643 SGPropertyNode::SGPropertyNode (const char * name,
644                                 int index,
645                                 SGPropertyNode * parent)
646   : _index(index),
647     _parent(parent),
648     _path_cache(0),
649     _type(NONE),
650     _tied(false),
651     _attr(READ|WRITE)
652 {
653   _name = copy_string(name);
654   _local_val.string_val = 0;
655 }
656
657
658 /**
659  * Destructor.
660  */
661 SGPropertyNode::~SGPropertyNode ()
662 {
663   delete _name;
664   for (int i = 0; i < (int)_children.size(); i++) {
665     delete _children[i];
666   }
667 //   delete _path_cache;
668   clear_value();
669 }
670
671
672 /**
673  * Alias to another node.
674  */
675 bool
676 SGPropertyNode::alias (SGPropertyNode * target)
677 {
678   if (target == 0 || _type == ALIAS || _tied)
679     return false;
680   clear_value();
681   _value.alias = target;
682   _type = ALIAS;
683   return true;
684 }
685
686
687 /**
688  * Alias to another node by path.
689  */
690 bool
691 SGPropertyNode::alias (const char * path)
692 {
693   return alias(getNode(path, true));
694 }
695
696
697 /**
698  * Remove an alias.
699  */
700 bool
701 SGPropertyNode::unalias ()
702 {
703   if (_type != ALIAS)
704     return false;
705   _type = NONE;
706   _value.alias = 0;
707   return true;
708 }
709
710
711 /**
712  * Get the target of an alias.
713  */
714 SGPropertyNode *
715 SGPropertyNode::getAliasTarget ()
716 {
717   return (_type == ALIAS ? _value.alias : 0);
718 }
719
720
721 const SGPropertyNode *
722 SGPropertyNode::getAliasTarget () const
723 {
724   return (_type == ALIAS ? _value.alias : 0);
725 }
726
727
728 /**
729  * Get a non-const child by index.
730  */
731 SGPropertyNode *
732 SGPropertyNode::getChild (int position)
733 {
734   if (position >= 0 && position < nChildren())
735     return _children[position];
736   else
737     return 0;
738 }
739
740
741 /**
742  * Get a const child by index.
743  */
744 const SGPropertyNode *
745 SGPropertyNode::getChild (int position) const
746 {
747   if (position >= 0 && position < nChildren())
748     return _children[position];
749   else
750     return 0;
751 }
752
753
754 /**
755  * Get a non-const child by name and index, creating if necessary.
756  */
757 SGPropertyNode *
758 SGPropertyNode::getChild (const char * name, int index, bool create)
759 {
760   int pos = find_child(name, index, _children);
761   if (pos >= 0) {
762     return _children[pos];
763   } else if (create) {
764     _children.push_back(new SGPropertyNode(name, index, this));
765     return _children[_children.size()-1];
766   } else {
767     return 0;
768   }
769 }
770
771
772 /**
773  * Get a const child by name and index.
774  */
775 const SGPropertyNode *
776 SGPropertyNode::getChild (const char * name, int index) const
777 {
778   int pos = find_child(name, index, _children);
779   if (pos >= 0)
780     return _children[pos];
781   else
782     return 0;
783 }
784
785
786 /**
787  * Get all children with the same name (but different indices).
788  */
789 vector<SGPropertyNode *>
790 SGPropertyNode::getChildren (const char * name)
791 {
792   vector<SGPropertyNode *> children;
793   int max = _children.size();
794
795   for (int i = 0; i < max; i++)
796     if (compare_strings(_children[i]->getName(), name))
797       children.push_back(_children[i]);
798
799   sort(children.begin(), children.end(), CompareIndices());
800   return children;
801 }
802
803
804 /**
805  * Get all children const with the same name (but different indices).
806  */
807 vector<const SGPropertyNode *>
808 SGPropertyNode::getChildren (const char * name) const
809 {
810   vector<const SGPropertyNode *> children;
811   int max = _children.size();
812
813   for (int i = 0; i < max; i++)
814     if (compare_strings(_children[i]->getName(), name))
815       children.push_back(_children[i]);
816
817   sort(children.begin(), children.end(), CompareIndices());
818   return children;
819 }
820
821
822 const char *
823 SGPropertyNode::getPath (bool simplify) const
824 {
825   if (_parent == 0)
826     return "";
827
828   string path = _parent->getPath(simplify);
829   path += '/';
830   path += _name;
831   if (_index != 0 || !simplify) {
832     char buffer[128];
833     sprintf(buffer, "[%d]", _index);
834     path += buffer;
835   }
836   return path.c_str();
837 }
838
839 SGPropertyNode::Type
840 SGPropertyNode::getType () const
841 {
842   if (_type == ALIAS)
843     return _value.alias->getType();
844   else
845     return _type;
846 }
847
848
849 bool 
850 SGPropertyNode::getBoolValue () const
851 {
852                                 // Shortcut for common case
853   if (_attr == (READ|WRITE) && _type == BOOL)
854     return get_bool();
855
856   if (getAttribute(TRACE_READ))
857     trace_read();
858   if (!getAttribute(READ))
859     return SGRawValue<bool>::DefaultValue;
860   switch (_type) {
861   case ALIAS:
862     return _value.alias->getBoolValue();
863   case BOOL:
864     return get_bool();
865   case INT:
866     return get_int() == 0 ? false : true;
867   case LONG:
868     return get_long() == 0L ? false : true;
869   case FLOAT:
870     return get_float() == 0.0 ? false : true;
871   case DOUBLE:
872     return get_double() == 0.0L ? false : true;
873   case STRING:
874   case UNSPECIFIED:
875     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
876   case NONE:
877   default:
878     return SGRawValue<bool>::DefaultValue;
879   }
880 }
881
882 int 
883 SGPropertyNode::getIntValue () const
884 {
885                                 // Shortcut for common case
886   if (_attr == (READ|WRITE) && _type == INT)
887     return get_int();
888
889   if (getAttribute(TRACE_READ))
890     trace_read();
891   if (!getAttribute(READ))
892     return SGRawValue<int>::DefaultValue;
893   switch (_type) {
894   case ALIAS:
895     return _value.alias->getIntValue();
896   case BOOL:
897     return int(get_bool());
898   case INT:
899     return get_int();
900   case LONG:
901     return int(get_long());
902   case FLOAT:
903     return int(get_float());
904   case DOUBLE:
905     return int(get_double());
906   case STRING:
907   case UNSPECIFIED:
908     return atoi(get_string());
909   case NONE:
910   default:
911     return SGRawValue<int>::DefaultValue;
912   }
913 }
914
915 long 
916 SGPropertyNode::getLongValue () const
917 {
918                                 // Shortcut for common case
919   if (_attr == (READ|WRITE) && _type == LONG)
920     return get_long();
921
922   if (getAttribute(TRACE_READ))
923     trace_read();
924   if (!getAttribute(READ))
925     return SGRawValue<long>::DefaultValue;
926   switch (_type) {
927   case ALIAS:
928     return _value.alias->getLongValue();
929   case BOOL:
930     return long(get_bool());
931   case INT:
932     return long(get_int());
933   case LONG:
934     return get_long();
935   case FLOAT:
936     return long(get_float());
937   case DOUBLE:
938     return long(get_double());
939   case STRING:
940   case UNSPECIFIED:
941     return strtol(get_string(), 0, 0);
942   case NONE:
943   default:
944     return SGRawValue<long>::DefaultValue;
945   }
946 }
947
948 float 
949 SGPropertyNode::getFloatValue () const
950 {
951                                 // Shortcut for common case
952   if (_attr == (READ|WRITE) && _type == FLOAT)
953     return get_float();
954
955   if (getAttribute(TRACE_READ))
956     trace_read();
957   if (!getAttribute(READ))
958     return SGRawValue<float>::DefaultValue;
959   switch (_type) {
960   case ALIAS:
961     return _value.alias->getFloatValue();
962   case BOOL:
963     return float(get_bool());
964   case INT:
965     return float(get_int());
966   case LONG:
967     return float(get_long());
968   case FLOAT:
969     return get_float();
970   case DOUBLE:
971     return float(get_double());
972   case STRING:
973   case UNSPECIFIED:
974     return atof(get_string());
975   case NONE:
976   default:
977     return SGRawValue<float>::DefaultValue;
978   }
979 }
980
981 double 
982 SGPropertyNode::getDoubleValue () const
983 {
984                                 // Shortcut for common case
985   if (_attr == (READ|WRITE) && _type == DOUBLE)
986     return get_double();
987
988   if (getAttribute(TRACE_READ))
989     trace_read();
990   if (!getAttribute(READ))
991     return SGRawValue<double>::DefaultValue;
992
993   switch (_type) {
994   case ALIAS:
995     return _value.alias->getDoubleValue();
996   case BOOL:
997     return double(get_bool());
998   case INT:
999     return double(get_int());
1000   case LONG:
1001     return double(get_long());
1002   case FLOAT:
1003     return double(get_float());
1004   case DOUBLE:
1005     return get_double();
1006   case STRING:
1007   case UNSPECIFIED:
1008     return strtod(get_string(), 0);
1009   case NONE:
1010   default:
1011     return SGRawValue<double>::DefaultValue;
1012   }
1013 }
1014
1015 const char *
1016 SGPropertyNode::getStringValue () const
1017 {
1018                                 // Shortcut for common case
1019   if (_attr == (READ|WRITE) && _type == STRING)
1020     return get_string();
1021
1022   if (getAttribute(TRACE_READ))
1023     trace_read();
1024   if (!getAttribute(READ))
1025     return SGRawValue<const char *>::DefaultValue;
1026   return make_string();
1027 }
1028
1029 bool
1030 SGPropertyNode::setBoolValue (bool value)
1031 {
1032                                 // Shortcut for common case
1033   if (_attr == (READ|WRITE) && _type == BOOL)
1034     return set_bool(value);
1035
1036   bool result = false;
1037   TEST_WRITE;
1038   if (_type == NONE || _type == UNSPECIFIED) {
1039     clear_value();
1040     _tied = false;
1041     _type = BOOL;
1042   }
1043
1044   switch (_type) {
1045   case ALIAS:
1046     result = _value.alias->setBoolValue(value);
1047     break;
1048   case BOOL:
1049     result = set_bool(value);
1050     break;
1051   case INT:
1052     result = set_int(int(value));
1053     break;
1054   case LONG:
1055     result = set_long(long(value));
1056     break;
1057   case FLOAT:
1058     result = set_float(float(value));
1059     break;
1060   case DOUBLE:
1061     result = set_double(double(value));
1062     break;
1063   case STRING:
1064   case UNSPECIFIED:
1065     result = set_string(value ? "true" : "false");
1066     break;
1067   case NONE:
1068   default:
1069     break;
1070   }
1071
1072   if (getAttribute(TRACE_WRITE))
1073     trace_write();
1074   return result;
1075 }
1076
1077 bool
1078 SGPropertyNode::setIntValue (int value)
1079 {
1080                                 // Shortcut for common case
1081   if (_attr == (READ|WRITE) && _type == INT)
1082     return set_int(value);
1083
1084   bool result = false;
1085   TEST_WRITE;
1086   if (_type == NONE || _type == UNSPECIFIED) {
1087     clear_value();
1088     _type = INT;
1089     _local_val.int_val = 0;
1090   }
1091
1092   switch (_type) {
1093   case ALIAS:
1094     result = _value.alias->setIntValue(value);
1095     break;
1096   case BOOL:
1097     result = set_bool(value == 0 ? false : true);
1098     break;
1099   case INT:
1100     result = set_int(value);
1101     break;
1102   case LONG:
1103     result = set_long(long(value));
1104     break;
1105   case FLOAT:
1106     result = set_float(float(value));
1107     break;
1108   case DOUBLE:
1109     result = set_double(double(value));
1110     break;
1111   case STRING:
1112   case UNSPECIFIED: {
1113     char buf[128];
1114     sprintf(buf, "%d", value);
1115     result = set_string(buf);
1116     break;
1117   }
1118   case NONE:
1119   default:
1120     break;
1121   }
1122
1123   if (getAttribute(TRACE_WRITE))
1124     trace_write();
1125   return result;
1126 }
1127
1128 bool
1129 SGPropertyNode::setLongValue (long value)
1130 {
1131                                 // Shortcut for common case
1132   if (_attr == (READ|WRITE) && _type == LONG)
1133     return set_long(value);
1134
1135   bool result = false;
1136   TEST_WRITE;
1137   if (_type == NONE || _type == UNSPECIFIED) {
1138     clear_value();
1139     _type = LONG;
1140     _local_val.long_val = 0L;
1141   }
1142
1143   switch (_type) {
1144   case ALIAS:
1145     result = _value.alias->setLongValue(value);
1146     break;
1147   case BOOL:
1148     result = set_bool(value == 0L ? false : true);
1149     break;
1150   case INT:
1151     result = set_int(int(value));
1152     break;
1153   case LONG:
1154     result = set_long(value);
1155     break;
1156   case FLOAT:
1157     result = set_float(float(value));
1158     break;
1159   case DOUBLE:
1160     result = set_double(double(value));
1161     break;
1162   case STRING:
1163   case UNSPECIFIED: {
1164     char buf[128];
1165     sprintf(buf, "%ld", value);
1166     result = set_string(buf);
1167     break;
1168   }
1169   case NONE:
1170   default:
1171     break;
1172   }
1173
1174   if (getAttribute(TRACE_WRITE))
1175     trace_write();
1176   return result;
1177 }
1178
1179 bool
1180 SGPropertyNode::setFloatValue (float value)
1181 {
1182                                 // Shortcut for common case
1183   if (_attr == (READ|WRITE) && _type == FLOAT)
1184     return set_float(value);
1185
1186   bool result = false;
1187   TEST_WRITE;
1188   if (_type == NONE || _type == UNSPECIFIED) {
1189     clear_value();
1190     _type = FLOAT;
1191     _local_val.float_val = 0;
1192   }
1193
1194   switch (_type) {
1195   case ALIAS:
1196     result = _value.alias->setFloatValue(value);
1197     break;
1198   case BOOL:
1199     result = set_bool(value == 0.0 ? false : true);
1200     break;
1201   case INT:
1202     result = set_int(int(value));
1203     break;
1204   case LONG:
1205     result = set_long(long(value));
1206     break;
1207   case FLOAT:
1208     result = set_float(value);
1209     break;
1210   case DOUBLE:
1211     result = set_double(double(value));
1212     break;
1213   case STRING:
1214   case UNSPECIFIED: {
1215     char buf[128];
1216     sprintf(buf, "%f", value);
1217     result = set_string(buf);
1218     break;
1219   }
1220   case NONE:
1221   default:
1222     break;
1223   }
1224
1225   if (getAttribute(TRACE_WRITE))
1226     trace_write();
1227   return result;
1228 }
1229
1230 bool
1231 SGPropertyNode::setDoubleValue (double value)
1232 {
1233                                 // Shortcut for common case
1234   if (_attr == (READ|WRITE) && _type == DOUBLE)
1235     return set_double(value);
1236
1237   bool result = false;
1238   TEST_WRITE;
1239   if (_type == NONE || _type == UNSPECIFIED) {
1240     clear_value();
1241     _local_val.double_val = value;
1242     _type = DOUBLE;
1243   }
1244
1245   switch (_type) {
1246   case ALIAS:
1247     result = _value.alias->setDoubleValue(value);
1248     break;
1249   case BOOL:
1250     result = set_bool(value == 0.0L ? false : true);
1251     break;
1252   case INT:
1253     result = set_int(int(value));
1254     break;
1255   case LONG:
1256     result = set_long(long(value));
1257     break;
1258   case FLOAT:
1259     result = set_float(float(value));
1260     break;
1261   case DOUBLE:
1262     result = set_double(value);
1263     break;
1264   case STRING:
1265   case UNSPECIFIED: {
1266     char buf[128];
1267     sprintf(buf, "%f", value);
1268     result = set_string(buf);
1269     break;
1270   }
1271   case NONE:
1272   default:
1273     break;
1274   }
1275
1276   if (getAttribute(TRACE_WRITE))
1277     trace_write();
1278   return result;
1279 }
1280
1281 bool
1282 SGPropertyNode::setStringValue (const char * value)
1283 {
1284                                 // Shortcut for common case
1285   if (_attr == (READ|WRITE) && _type == STRING)
1286     return set_string(value);
1287
1288   bool result = false;
1289   TEST_WRITE;
1290   if (_type == NONE || _type == UNSPECIFIED) {
1291     clear_value();
1292     _type = STRING;
1293   }
1294
1295   switch (_type) {
1296   case ALIAS:
1297     result = _value.alias->setStringValue(value);
1298     break;
1299   case BOOL:
1300     result = set_bool((compare_strings(value, "true")
1301                        || atoi(value)) ? true : false);
1302     break;
1303   case INT:
1304     result = set_int(atoi(value));
1305     break;
1306   case LONG:
1307     result = set_long(strtol(value, 0, 0));
1308     break;
1309   case FLOAT:
1310     result = set_float(atof(value));
1311     break;
1312   case DOUBLE:
1313     result = set_double(strtod(value, 0));
1314     break;
1315   case STRING:
1316   case UNSPECIFIED:
1317     result = set_string(value);
1318     break;
1319   case NONE:
1320   default:
1321     break;
1322   }
1323
1324   if (getAttribute(TRACE_WRITE))
1325     trace_write();
1326   return result;
1327 }
1328
1329 bool
1330 SGPropertyNode::setUnspecifiedValue (const char * value)
1331 {
1332   bool result = false;
1333   TEST_WRITE;
1334   if (_type == NONE) {
1335     clear_value();
1336     _type = UNSPECIFIED;
1337   }
1338
1339   switch (_type) {
1340   case ALIAS:
1341     result = _value.alias->setUnspecifiedValue(value);
1342     break;
1343   case BOOL:
1344     result = set_bool((compare_strings(value, "true")
1345                        || atoi(value)) ? true : false);
1346     break;
1347   case INT:
1348     result = set_int(atoi(value));
1349     break;
1350   case LONG:
1351     result = set_long(strtol(value, 0, 0));
1352     break;
1353   case FLOAT:
1354     result = set_float(atof(value));
1355     break;
1356   case DOUBLE:
1357     result = set_double(strtod(value, 0));
1358     break;
1359   case STRING:
1360   case UNSPECIFIED:
1361     result = set_string(value);
1362     break;
1363   case NONE:
1364   default:
1365     break;
1366   }
1367
1368   if (getAttribute(TRACE_WRITE))
1369     trace_write();
1370   return result;
1371 }
1372
1373 bool
1374 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1375 {
1376   if (_type == ALIAS || _tied)
1377     return false;
1378
1379   useDefault = useDefault && hasValue();
1380   bool old_val = false;
1381   if (useDefault)
1382     old_val = getBoolValue();
1383
1384   clear_value();
1385   _type = BOOL;
1386   _tied = true;
1387   _value.bool_val = rawValue.clone();
1388
1389   if (useDefault)
1390     setBoolValue(old_val);
1391
1392   return true;
1393 }
1394
1395 bool
1396 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1397 {
1398   if (_type == ALIAS || _tied)
1399     return false;
1400
1401   useDefault = useDefault && hasValue();
1402   int old_val = 0;
1403   if (useDefault)
1404     old_val = getIntValue();
1405
1406   clear_value();
1407   _type = INT;
1408   _tied = true;
1409   _value.int_val = rawValue.clone();
1410
1411   if (useDefault)
1412     setIntValue(old_val);
1413
1414   return true;
1415 }
1416
1417 bool
1418 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1419 {
1420   if (_type == ALIAS || _tied)
1421     return false;
1422
1423   useDefault = useDefault && hasValue();
1424   long old_val = 0;
1425   if (useDefault)
1426     old_val = getLongValue();
1427
1428   clear_value();
1429   _type = LONG;
1430   _tied = true;
1431   _value.long_val = rawValue.clone();
1432
1433   if (useDefault)
1434     setLongValue(old_val);
1435
1436   return true;
1437 }
1438
1439 bool
1440 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1441 {
1442   if (_type == ALIAS || _tied)
1443     return false;
1444
1445   useDefault = useDefault && hasValue();
1446   float old_val = 0.0;
1447   if (useDefault)
1448     old_val = getFloatValue();
1449
1450   clear_value();
1451   _type = FLOAT;
1452   _tied = true;
1453   _value.float_val = rawValue.clone();
1454
1455   if (useDefault)
1456     setFloatValue(old_val);
1457
1458   return true;
1459 }
1460
1461 bool
1462 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1463 {
1464   if (_type == ALIAS || _tied)
1465     return false;
1466
1467   useDefault = useDefault && hasValue();
1468   double old_val = 0.0;
1469   if (useDefault)
1470     old_val = getDoubleValue();
1471
1472   clear_value();
1473   _type = DOUBLE;
1474   _tied = true;
1475   _value.double_val = rawValue.clone();
1476
1477   if (useDefault)
1478     setDoubleValue(old_val);
1479
1480   return true;
1481
1482 }
1483
1484 bool
1485 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1486 {
1487   if (_type == ALIAS || _tied)
1488     return false;
1489
1490   useDefault = useDefault && hasValue();
1491   string old_val;
1492   if (useDefault)
1493     old_val = getStringValue();
1494
1495   clear_value();
1496   _type = STRING;
1497   _tied = true;
1498   _value.string_val = rawValue.clone();
1499
1500   if (useDefault)
1501     setStringValue(old_val.c_str());
1502
1503   return true;
1504 }
1505
1506 bool
1507 SGPropertyNode::untie ()
1508 {
1509   if (!_tied)
1510     return false;
1511
1512   switch (_type) {
1513   case BOOL: {
1514     bool val = getBoolValue();
1515     clear_value();
1516     _type = BOOL;
1517     _local_val.bool_val = val;
1518     break;
1519   }
1520   case INT: {
1521     int val = getIntValue();
1522     clear_value();
1523     _type = INT;
1524     _local_val.int_val = val;
1525     break;
1526   }
1527   case LONG: {
1528     long val = getLongValue();
1529     clear_value();
1530     _type = LONG;
1531     _local_val.long_val = val;
1532     break;
1533   }
1534   case FLOAT: {
1535     float val = getFloatValue();
1536     clear_value();
1537     _type = FLOAT;
1538     _local_val.float_val = val;
1539     break;
1540   }
1541   case DOUBLE: {
1542     double val = getDoubleValue();
1543     clear_value();
1544     _type = DOUBLE;
1545     _local_val.double_val = val;
1546     break;
1547   }
1548   case STRING:
1549   case UNSPECIFIED: {
1550     string val = getStringValue();
1551     clear_value();
1552     _type = STRING;
1553     _local_val.string_val = copy_string(val.c_str());
1554     break;
1555   }
1556   case NONE:
1557   default:
1558     break;
1559   }
1560
1561   _tied = false;
1562   return true;
1563 }
1564
1565 SGPropertyNode *
1566 SGPropertyNode::getRootNode ()
1567 {
1568   if (_parent == 0)
1569     return this;
1570   else
1571     return _parent->getRootNode();
1572 }
1573
1574 const SGPropertyNode *
1575 SGPropertyNode::getRootNode () const
1576 {
1577   if (_parent == 0)
1578     return this;
1579   else
1580     return _parent->getRootNode();
1581 }
1582
1583 SGPropertyNode *
1584 SGPropertyNode::getNode (const char * relative_path, bool create)
1585 {
1586 //   if (_path_cache == 0)
1587 //     _path_cache = new cache_map;
1588
1589 //   SGPropertyNode * result = (*_path_cache)[relative_path];
1590 //   if (result == 0) {
1591 //     vector<PathComponent> components;
1592 //     parse_path(relative_path, components);
1593 //     result = find_node(this, components, 0, create);
1594 //     if (result != 0)
1595 //       (*_path_cache)[relative_path] = result;
1596 //   }
1597   
1598 //   return result;
1599   vector<PathComponent> components;
1600   parse_path(relative_path, components);
1601   return find_node(this, components, 0, create);
1602 }
1603
1604 SGPropertyNode *
1605 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1606 {
1607   vector<PathComponent> components;
1608   parse_path(relative_path, components);
1609   if (components.size() > 0)
1610     components[components.size()-1].index = index;
1611   return find_node(this, components, 0, create);
1612 }
1613
1614 const SGPropertyNode *
1615 SGPropertyNode::getNode (const char * relative_path) const
1616 {
1617   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1618 }
1619
1620 const SGPropertyNode *
1621 SGPropertyNode::getNode (const char * relative_path, int index) const
1622 {
1623   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1624 }
1625
1626 \f
1627 ////////////////////////////////////////////////////////////////////////
1628 // Convenience methods using relative paths.
1629 ////////////////////////////////////////////////////////////////////////
1630
1631
1632 /**
1633  * Test whether another node has a value attached.
1634  */
1635 bool
1636 SGPropertyNode::hasValue (const char * relative_path) const
1637 {
1638   const SGPropertyNode * node = getNode(relative_path);
1639   return (node == 0 ? false : node->hasValue());
1640 }
1641
1642
1643 /**
1644  * Get the value type for another node.
1645  */
1646 SGPropertyNode::Type
1647 SGPropertyNode::getType (const char * relative_path) const
1648 {
1649   const SGPropertyNode * node = getNode(relative_path);
1650   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1651 }
1652
1653
1654 /**
1655  * Get a bool value for another node.
1656  */
1657 bool
1658 SGPropertyNode::getBoolValue (const char * relative_path,
1659                               bool defaultValue) const
1660 {
1661   const SGPropertyNode * node = getNode(relative_path);
1662   return (node == 0 ? defaultValue : node->getBoolValue());
1663 }
1664
1665
1666 /**
1667  * Get an int value for another node.
1668  */
1669 int
1670 SGPropertyNode::getIntValue (const char * relative_path,
1671                              int defaultValue) const
1672 {
1673   const SGPropertyNode * node = getNode(relative_path);
1674   return (node == 0 ? defaultValue : node->getIntValue());
1675 }
1676
1677
1678 /**
1679  * Get a long value for another node.
1680  */
1681 long
1682 SGPropertyNode::getLongValue (const char * relative_path,
1683                               long defaultValue) const
1684 {
1685   const SGPropertyNode * node = getNode(relative_path);
1686   return (node == 0 ? defaultValue : node->getLongValue());
1687 }
1688
1689
1690 /**
1691  * Get a float value for another node.
1692  */
1693 float
1694 SGPropertyNode::getFloatValue (const char * relative_path,
1695                                float defaultValue) const
1696 {
1697   const SGPropertyNode * node = getNode(relative_path);
1698   return (node == 0 ? defaultValue : node->getFloatValue());
1699 }
1700
1701
1702 /**
1703  * Get a double value for another node.
1704  */
1705 double
1706 SGPropertyNode::getDoubleValue (const char * relative_path,
1707                                 double defaultValue) const
1708 {
1709   const SGPropertyNode * node = getNode(relative_path);
1710   return (node == 0 ? defaultValue : node->getDoubleValue());
1711 }
1712
1713
1714 /**
1715  * Get a string value for another node.
1716  */
1717 const char *
1718 SGPropertyNode::getStringValue (const char * relative_path,
1719                                 const char * defaultValue) const
1720 {
1721   const SGPropertyNode * node = getNode(relative_path);
1722   return (node == 0 ? defaultValue : node->getStringValue());
1723 }
1724
1725
1726 /**
1727  * Set a bool value for another node.
1728  */
1729 bool
1730 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1731 {
1732   return getNode(relative_path, true)->setBoolValue(value);
1733 }
1734
1735
1736 /**
1737  * Set an int value for another node.
1738  */
1739 bool
1740 SGPropertyNode::setIntValue (const char * relative_path, int value)
1741 {
1742   return getNode(relative_path, true)->setIntValue(value);
1743 }
1744
1745
1746 /**
1747  * Set a long value for another node.
1748  */
1749 bool
1750 SGPropertyNode::setLongValue (const char * relative_path, long value)
1751 {
1752   return getNode(relative_path, true)->setLongValue(value);
1753 }
1754
1755
1756 /**
1757  * Set a float value for another node.
1758  */
1759 bool
1760 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1761 {
1762   return getNode(relative_path, true)->setFloatValue(value);
1763 }
1764
1765
1766 /**
1767  * Set a double value for another node.
1768  */
1769 bool
1770 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1771 {
1772   return getNode(relative_path, true)->setDoubleValue(value);
1773 }
1774
1775
1776 /**
1777  * Set a string value for another node.
1778  */
1779 bool
1780 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1781 {
1782   return getNode(relative_path, true)->setStringValue(value);
1783 }
1784
1785
1786 /**
1787  * Set an unknown value for another node.
1788  */
1789 bool
1790 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1791                                      const char * value)
1792 {
1793   return getNode(relative_path, true)->setUnspecifiedValue(value);
1794 }
1795
1796
1797 /**
1798  * Test whether another node is tied.
1799  */
1800 bool
1801 SGPropertyNode::isTied (const char * relative_path) const
1802 {
1803   const SGPropertyNode * node = getNode(relative_path);
1804   return (node == 0 ? false : node->isTied());
1805 }
1806
1807
1808 /**
1809  * Tie a node reached by a relative path, creating it if necessary.
1810  */
1811 bool
1812 SGPropertyNode::tie (const char * relative_path,
1813                      const SGRawValue<bool> &rawValue,
1814                      bool useDefault)
1815 {
1816   return getNode(relative_path, true)->tie(rawValue, useDefault);
1817 }
1818
1819
1820 /**
1821  * Tie a node reached by a relative path, creating it if necessary.
1822  */
1823 bool
1824 SGPropertyNode::tie (const char * relative_path,
1825                      const SGRawValue<int> &rawValue,
1826                      bool useDefault)
1827 {
1828   return getNode(relative_path, true)->tie(rawValue, useDefault);
1829 }
1830
1831
1832 /**
1833  * Tie a node reached by a relative path, creating it if necessary.
1834  */
1835 bool
1836 SGPropertyNode::tie (const char * relative_path,
1837                      const SGRawValue<long> &rawValue,
1838                      bool useDefault)
1839 {
1840   return getNode(relative_path, true)->tie(rawValue, useDefault);
1841 }
1842
1843
1844 /**
1845  * Tie a node reached by a relative path, creating it if necessary.
1846  */
1847 bool
1848 SGPropertyNode::tie (const char * relative_path,
1849                      const SGRawValue<float> &rawValue,
1850                      bool useDefault)
1851 {
1852   return getNode(relative_path, true)->tie(rawValue, useDefault);
1853 }
1854
1855
1856 /**
1857  * Tie a node reached by a relative path, creating it if necessary.
1858  */
1859 bool
1860 SGPropertyNode::tie (const char * relative_path,
1861                      const SGRawValue<double> &rawValue,
1862                      bool useDefault)
1863 {
1864   return getNode(relative_path, true)->tie(rawValue, useDefault);
1865 }
1866
1867
1868 /**
1869  * Tie a node reached by a relative path, creating it if necessary.
1870  */
1871 bool
1872 SGPropertyNode::tie (const char * relative_path,
1873                      const SGRawValue<const char *> &rawValue,
1874                      bool useDefault)
1875 {
1876   return getNode(relative_path, true)->tie(rawValue, useDefault);
1877 }
1878
1879
1880 /**
1881  * Attempt to untie another node reached by a relative path.
1882  */
1883 bool
1884 SGPropertyNode::untie (const char * relative_path)
1885 {
1886   SGPropertyNode * node = getNode(relative_path);
1887   return (node == 0 ? false : node->untie());
1888 }
1889
1890 // end of props.cxx