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