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