]> git.mxchange.org Git - simgear.git/blob - simgear/props/props.cxx
673cde4cbf0aaa468b6064b83419df16eae1c18c
[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, 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 << get_double();
578       _buffer = sstr.str();
579       return _buffer.c_str();
580     }
581   case STRING:
582   case UNSPECIFIED:
583     return get_string();
584   case NONE:
585   default:
586     return "";
587   }
588 }
589
590 /**
591  * Trace a write access for a property.
592  */
593 void
594 SGPropertyNode::trace_write () const
595 {
596 #if PROPS_STANDALONE
597   cerr << "TRACE: Write node " << getPath () << ", value\""
598        << make_string() << '"' << endl;
599 #else
600   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
601          << ", value\"" << make_string() << '"');
602 #endif
603 }
604
605 /**
606  * Trace a read access for a property.
607  */
608 void
609 SGPropertyNode::trace_read () const
610 {
611 #if PROPS_STANDALONE
612   cerr << "TRACE: Write node " << getPath () << ", value \""
613        << make_string() << '"' << endl;
614 #else
615   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
616          << ", value \"" << make_string() << '"');
617 #endif
618 }
619
620 \f
621 ////////////////////////////////////////////////////////////////////////
622 // Public methods from SGPropertyNode.
623 ////////////////////////////////////////////////////////////////////////
624
625 /**
626  * Last used attribute
627  * Update as needed when enum Attribute is changed
628  */
629 const int SGPropertyNode::LAST_USED_ATTRIBUTE = TRACE_WRITE;
630
631 /**
632  * Default constructor: always creates a root node.
633  */
634 SGPropertyNode::SGPropertyNode ()
635   : _index(0),
636     _parent(0),
637     _path_cache(0),
638     _type(NONE),
639     _tied(false),
640     _attr(READ|WRITE),
641     _listeners(0)
642 {
643   _local_val.string_val = 0;
644 }
645
646
647 /**
648  * Copy constructor.
649  */
650 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
651   : _index(node._index),
652     _name(node._name),
653     _parent(0),                 // don't copy the parent
654     _path_cache(0),
655     _type(node._type),
656     _tied(node._tied),
657     _attr(node._attr),
658     _listeners(0)               // CHECK!!
659 {
660   _local_val.string_val = 0;
661   switch (_type) {
662   case NONE:
663     break;
664   case ALIAS:
665     _value.alias = node._value.alias;
666     _tied = false;
667     break;
668   case BOOL:
669     if (_tied) {
670       _tied = true;
671       _value.bool_val = node._value.bool_val->clone();
672     } else {
673       _tied = false;
674       set_bool(node.get_bool());
675     }
676     break;
677   case INT:
678     if (_tied) {
679       _tied = true;
680       _value.int_val = node._value.int_val->clone();
681     } else {
682       _tied = false;
683       set_int(node.get_int());
684     }
685     break;
686   case LONG:
687     if (_tied) {
688       _tied = true;
689       _value.long_val = node._value.long_val->clone();
690     } else {
691       _tied = false;
692       set_long(node.get_long());
693     }
694     break;
695   case FLOAT:
696     if (_tied) {
697       _tied = true;
698       _value.float_val = node._value.float_val->clone();
699     } else {
700       _tied = false;
701       set_float(node.get_float());
702     }
703     break;
704   case DOUBLE:
705     if (_tied) {
706       _tied = true;
707       _value.double_val = node._value.double_val->clone();
708     } else {
709       _tied = false;
710       set_double(node.get_double());
711     }
712     break;
713   case STRING:
714   case UNSPECIFIED:
715     if (_tied) {
716       _tied = true;
717       _value.string_val = node._value.string_val->clone();
718     } else {
719       _tied = false;
720       set_string(node.get_string());
721     }
722     break;
723   }
724 }
725
726
727 /**
728  * Convenience constructor.
729  */
730 SGPropertyNode::SGPropertyNode (const char * name,
731                                 int index,
732                                 SGPropertyNode * parent)
733   : _index(index),
734     _parent(parent),
735     _path_cache(0),
736     _type(NONE),
737     _tied(false),
738     _attr(READ|WRITE),
739     _listeners(0)
740 {
741   _name = name;
742   _local_val.string_val = 0;
743 }
744
745
746 /**
747  * Destructor.
748  */
749 SGPropertyNode::~SGPropertyNode ()
750 {
751   delete _path_cache;
752   clearValue();
753   delete _listeners;
754 }
755
756
757 /**
758  * Alias to another node.
759  */
760 bool
761 SGPropertyNode::alias (SGPropertyNode * target)
762 {
763   if (target == 0 || _type == ALIAS || _tied)
764     return false;
765   clearValue();
766   _value.alias = target;
767   _type = ALIAS;
768   return true;
769 }
770
771
772 /**
773  * Alias to another node by path.
774  */
775 bool
776 SGPropertyNode::alias (const char * path)
777 {
778   return alias(getNode(path, true));
779 }
780
781
782 /**
783  * Remove an alias.
784  */
785 bool
786 SGPropertyNode::unalias ()
787 {
788   if (_type != ALIAS)
789     return false;
790   _type = NONE;
791   _value.alias = 0;
792   return true;
793 }
794
795
796 /**
797  * Get the target of an alias.
798  */
799 SGPropertyNode *
800 SGPropertyNode::getAliasTarget ()
801 {
802   return (_type == ALIAS ? _value.alias : 0);
803 }
804
805
806 const SGPropertyNode *
807 SGPropertyNode::getAliasTarget () const
808 {
809   return (_type == ALIAS ? _value.alias : 0);
810 }
811
812
813 /**
814  * Get a non-const child by index.
815  */
816 SGPropertyNode *
817 SGPropertyNode::getChild (int position)
818 {
819   if (position >= 0 && position < nChildren())
820     return _children[position];
821   else
822     return 0;
823 }
824
825
826 /**
827  * Get a const child by index.
828  */
829 const SGPropertyNode *
830 SGPropertyNode::getChild (int position) const
831 {
832   if (position >= 0 && position < nChildren())
833     return _children[position];
834   else
835     return 0;
836 }
837
838
839 /**
840  * Get a non-const child by name and index, creating if necessary.
841  */
842 SGPropertyNode *
843 SGPropertyNode::getChild (const char * name, int index, bool create)
844 {
845   int pos = find_child(name, index, _children);
846   if (pos >= 0) {
847     return _children[pos];
848   } else if (create) {
849     SGPropertyNode_ptr node;
850     pos = find_child(name, index, _removedChildren);
851     if (pos >= 0) {
852       vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
853       it += pos;
854       node = _removedChildren[pos];
855       _removedChildren.erase(it);
856       node->setAttribute(REMOVED, false);
857     } else {
858       node = new SGPropertyNode(name, index, this);
859     }
860     _children.push_back(node);
861     fireChildAdded(node);
862     return node;
863   } else {
864     return 0;
865   }
866 }
867
868
869 /**
870  * Get a const child by name and index.
871  */
872 const SGPropertyNode *
873 SGPropertyNode::getChild (const char * name, int index) const
874 {
875   int pos = find_child(name, index, _children);
876   if (pos >= 0)
877     return _children[pos];
878   else
879     return 0;
880 }
881
882
883 /**
884  * Get all children with the same name (but different indices).
885  */
886 vector<SGPropertyNode_ptr>
887 SGPropertyNode::getChildren (const char * name) const
888 {
889   vector<SGPropertyNode_ptr> children;
890   int max = _children.size();
891
892   for (int i = 0; i < max; i++)
893     if (compare_strings(_children[i]->getName(), name))
894       children.push_back(_children[i]);
895
896   sort(children.begin(), children.end(), CompareIndices());
897   return children;
898 }
899
900
901 /**
902  * Remove child by position.
903  */
904 SGPropertyNode_ptr
905 SGPropertyNode::removeChild (int pos, bool keep)
906 {
907   SGPropertyNode_ptr node;
908   if (pos < 0 || pos >= _children.size())
909     return node;
910
911   vector<SGPropertyNode_ptr>::iterator it = _children.begin();
912   it += pos;
913   node = _children[pos];
914   _children.erase(it);
915   if (keep) {
916     _removedChildren.push_back(node);
917   }
918   if (_path_cache)
919      _path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
920   node->setAttribute(REMOVED, true);
921   node->clearValue();
922   fireChildRemoved(node);
923   return node;
924 }
925
926
927 /**
928  * Remove a child node
929  */
930 SGPropertyNode_ptr 
931 SGPropertyNode::removeChild (const char * name, int index, bool keep)
932 {
933   SGPropertyNode_ptr ret;
934   int pos = find_child(name, index, _children);
935   if (pos >= 0)
936     ret = removeChild(pos, keep);
937   return ret;
938 }
939
940
941 /**
942   * Remove all children with the specified name.
943   */
944 vector<SGPropertyNode_ptr>
945 SGPropertyNode::removeChildren (const char * name, bool keep)
946 {
947   vector<SGPropertyNode_ptr> children;
948
949   for (int pos = _children.size() - 1; pos >= 0; pos--)
950     if (compare_strings(_children[pos]->getName(), name))
951       children.push_back(removeChild(pos, keep));
952
953   sort(children.begin(), children.end(), CompareIndices());
954   return children;
955 }
956
957
958 const char *
959 SGPropertyNode::getDisplayName (bool simplify) const
960 {
961   _display_name = _name;
962   if (_index != 0 || !simplify) {
963     stringstream sstr;
964     sstr << '[' << _index << ']';
965     _display_name += sstr.str();
966   }
967   return _display_name.c_str();
968 }
969
970
971 const char *
972 SGPropertyNode::getPath (bool simplify) const
973 {
974   // Calculate the complete path only once.
975   if (_parent != 0 && _path.empty()) {
976     _path = _parent->getPath(simplify);
977     _path += '/';
978     _path += getDisplayName(simplify);
979   }
980
981   return _path.c_str();
982 }
983
984 SGPropertyNode::Type
985 SGPropertyNode::getType () const
986 {
987   if (_type == ALIAS)
988     return _value.alias->getType();
989   else
990     return _type;
991 }
992
993
994 bool 
995 SGPropertyNode::getBoolValue () const
996 {
997                                 // Shortcut for common case
998   if (_attr == (READ|WRITE) && _type == BOOL)
999     return get_bool();
1000
1001   if (getAttribute(TRACE_READ))
1002     trace_read();
1003   if (!getAttribute(READ))
1004     return SGRawValue<bool>::DefaultValue;
1005   switch (_type) {
1006   case ALIAS:
1007     return _value.alias->getBoolValue();
1008   case BOOL:
1009     return get_bool();
1010   case INT:
1011     return get_int() == 0 ? false : true;
1012   case LONG:
1013     return get_long() == 0L ? false : true;
1014   case FLOAT:
1015     return get_float() == 0.0 ? false : true;
1016   case DOUBLE:
1017     return get_double() == 0.0L ? false : true;
1018   case STRING:
1019   case UNSPECIFIED:
1020     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1021   case NONE:
1022   default:
1023     return SGRawValue<bool>::DefaultValue;
1024   }
1025 }
1026
1027 int 
1028 SGPropertyNode::getIntValue () const
1029 {
1030                                 // Shortcut for common case
1031   if (_attr == (READ|WRITE) && _type == INT)
1032     return get_int();
1033
1034   if (getAttribute(TRACE_READ))
1035     trace_read();
1036   if (!getAttribute(READ))
1037     return SGRawValue<int>::DefaultValue;
1038   switch (_type) {
1039   case ALIAS:
1040     return _value.alias->getIntValue();
1041   case BOOL:
1042     return int(get_bool());
1043   case INT:
1044     return get_int();
1045   case LONG:
1046     return int(get_long());
1047   case FLOAT:
1048     return int(get_float());
1049   case DOUBLE:
1050     return int(get_double());
1051   case STRING:
1052   case UNSPECIFIED:
1053     return atoi(get_string());
1054   case NONE:
1055   default:
1056     return SGRawValue<int>::DefaultValue;
1057   }
1058 }
1059
1060 long 
1061 SGPropertyNode::getLongValue () const
1062 {
1063                                 // Shortcut for common case
1064   if (_attr == (READ|WRITE) && _type == LONG)
1065     return get_long();
1066
1067   if (getAttribute(TRACE_READ))
1068     trace_read();
1069   if (!getAttribute(READ))
1070     return SGRawValue<long>::DefaultValue;
1071   switch (_type) {
1072   case ALIAS:
1073     return _value.alias->getLongValue();
1074   case BOOL:
1075     return long(get_bool());
1076   case INT:
1077     return long(get_int());
1078   case LONG:
1079     return get_long();
1080   case FLOAT:
1081     return long(get_float());
1082   case DOUBLE:
1083     return long(get_double());
1084   case STRING:
1085   case UNSPECIFIED:
1086     return strtol(get_string(), 0, 0);
1087   case NONE:
1088   default:
1089     return SGRawValue<long>::DefaultValue;
1090   }
1091 }
1092
1093 float 
1094 SGPropertyNode::getFloatValue () const
1095 {
1096                                 // Shortcut for common case
1097   if (_attr == (READ|WRITE) && _type == FLOAT)
1098     return get_float();
1099
1100   if (getAttribute(TRACE_READ))
1101     trace_read();
1102   if (!getAttribute(READ))
1103     return SGRawValue<float>::DefaultValue;
1104   switch (_type) {
1105   case ALIAS:
1106     return _value.alias->getFloatValue();
1107   case BOOL:
1108     return float(get_bool());
1109   case INT:
1110     return float(get_int());
1111   case LONG:
1112     return float(get_long());
1113   case FLOAT:
1114     return get_float();
1115   case DOUBLE:
1116     return float(get_double());
1117   case STRING:
1118   case UNSPECIFIED:
1119     return atof(get_string());
1120   case NONE:
1121   default:
1122     return SGRawValue<float>::DefaultValue;
1123   }
1124 }
1125
1126 double 
1127 SGPropertyNode::getDoubleValue () const
1128 {
1129                                 // Shortcut for common case
1130   if (_attr == (READ|WRITE) && _type == DOUBLE)
1131     return get_double();
1132
1133   if (getAttribute(TRACE_READ))
1134     trace_read();
1135   if (!getAttribute(READ))
1136     return SGRawValue<double>::DefaultValue;
1137
1138   switch (_type) {
1139   case ALIAS:
1140     return _value.alias->getDoubleValue();
1141   case BOOL:
1142     return double(get_bool());
1143   case INT:
1144     return double(get_int());
1145   case LONG:
1146     return double(get_long());
1147   case FLOAT:
1148     return double(get_float());
1149   case DOUBLE:
1150     return get_double();
1151   case STRING:
1152   case UNSPECIFIED:
1153     return strtod(get_string(), 0);
1154   case NONE:
1155   default:
1156     return SGRawValue<double>::DefaultValue;
1157   }
1158 }
1159
1160 const char *
1161 SGPropertyNode::getStringValue () const
1162 {
1163                                 // Shortcut for common case
1164   if (_attr == (READ|WRITE) && _type == STRING)
1165     return get_string();
1166
1167   if (getAttribute(TRACE_READ))
1168     trace_read();
1169   if (!getAttribute(READ))
1170     return SGRawValue<const char *>::DefaultValue;
1171   return make_string();
1172 }
1173
1174 bool
1175 SGPropertyNode::setBoolValue (bool value)
1176 {
1177                                 // Shortcut for common case
1178   if (_attr == (READ|WRITE) && _type == BOOL)
1179     return set_bool(value);
1180
1181   bool result = false;
1182   TEST_WRITE;
1183   if (_type == NONE || _type == UNSPECIFIED) {
1184     clearValue();
1185     _tied = false;
1186     _type = BOOL;
1187   }
1188
1189   switch (_type) {
1190   case ALIAS:
1191     result = _value.alias->setBoolValue(value);
1192     break;
1193   case BOOL:
1194     result = set_bool(value);
1195     break;
1196   case INT:
1197     result = set_int(int(value));
1198     break;
1199   case LONG:
1200     result = set_long(long(value));
1201     break;
1202   case FLOAT:
1203     result = set_float(float(value));
1204     break;
1205   case DOUBLE:
1206     result = set_double(double(value));
1207     break;
1208   case STRING:
1209   case UNSPECIFIED:
1210     result = set_string(value ? "true" : "false");
1211     break;
1212   case NONE:
1213   default:
1214     break;
1215   }
1216
1217   if (getAttribute(TRACE_WRITE))
1218     trace_write();
1219   return result;
1220 }
1221
1222 bool
1223 SGPropertyNode::setIntValue (int value)
1224 {
1225                                 // Shortcut for common case
1226   if (_attr == (READ|WRITE) && _type == INT)
1227     return set_int(value);
1228
1229   bool result = false;
1230   TEST_WRITE;
1231   if (_type == NONE || _type == UNSPECIFIED) {
1232     clearValue();
1233     _type = INT;
1234     _local_val.int_val = 0;
1235   }
1236
1237   switch (_type) {
1238   case ALIAS:
1239     result = _value.alias->setIntValue(value);
1240     break;
1241   case BOOL:
1242     result = set_bool(value == 0 ? false : true);
1243     break;
1244   case INT:
1245     result = set_int(value);
1246     break;
1247   case LONG:
1248     result = set_long(long(value));
1249     break;
1250   case FLOAT:
1251     result = set_float(float(value));
1252     break;
1253   case DOUBLE:
1254     result = set_double(double(value));
1255     break;
1256   case STRING:
1257   case UNSPECIFIED: {
1258     char buf[128];
1259     sprintf(buf, "%d", value);
1260     result = set_string(buf);
1261     break;
1262   }
1263   case NONE:
1264   default:
1265     break;
1266   }
1267
1268   if (getAttribute(TRACE_WRITE))
1269     trace_write();
1270   return result;
1271 }
1272
1273 bool
1274 SGPropertyNode::setLongValue (long value)
1275 {
1276                                 // Shortcut for common case
1277   if (_attr == (READ|WRITE) && _type == LONG)
1278     return set_long(value);
1279
1280   bool result = false;
1281   TEST_WRITE;
1282   if (_type == NONE || _type == UNSPECIFIED) {
1283     clearValue();
1284     _type = LONG;
1285     _local_val.long_val = 0L;
1286   }
1287
1288   switch (_type) {
1289   case ALIAS:
1290     result = _value.alias->setLongValue(value);
1291     break;
1292   case BOOL:
1293     result = set_bool(value == 0L ? false : true);
1294     break;
1295   case INT:
1296     result = set_int(int(value));
1297     break;
1298   case LONG:
1299     result = set_long(value);
1300     break;
1301   case FLOAT:
1302     result = set_float(float(value));
1303     break;
1304   case DOUBLE:
1305     result = set_double(double(value));
1306     break;
1307   case STRING:
1308   case UNSPECIFIED: {
1309     char buf[128];
1310     sprintf(buf, "%ld", value);
1311     result = set_string(buf);
1312     break;
1313   }
1314   case NONE:
1315   default:
1316     break;
1317   }
1318
1319   if (getAttribute(TRACE_WRITE))
1320     trace_write();
1321   return result;
1322 }
1323
1324 bool
1325 SGPropertyNode::setFloatValue (float value)
1326 {
1327                                 // Shortcut for common case
1328   if (_attr == (READ|WRITE) && _type == FLOAT)
1329     return set_float(value);
1330
1331   bool result = false;
1332   TEST_WRITE;
1333   if (_type == NONE || _type == UNSPECIFIED) {
1334     clearValue();
1335     _type = FLOAT;
1336     _local_val.float_val = 0;
1337   }
1338
1339   switch (_type) {
1340   case ALIAS:
1341     result = _value.alias->setFloatValue(value);
1342     break;
1343   case BOOL:
1344     result = set_bool(value == 0.0 ? false : true);
1345     break;
1346   case INT:
1347     result = set_int(int(value));
1348     break;
1349   case LONG:
1350     result = set_long(long(value));
1351     break;
1352   case FLOAT:
1353     result = set_float(value);
1354     break;
1355   case DOUBLE:
1356     result = set_double(double(value));
1357     break;
1358   case STRING:
1359   case UNSPECIFIED: {
1360     char buf[128];
1361     sprintf(buf, "%f", value);
1362     result = set_string(buf);
1363     break;
1364   }
1365   case NONE:
1366   default:
1367     break;
1368   }
1369
1370   if (getAttribute(TRACE_WRITE))
1371     trace_write();
1372   return result;
1373 }
1374
1375 bool
1376 SGPropertyNode::setDoubleValue (double value)
1377 {
1378                                 // Shortcut for common case
1379   if (_attr == (READ|WRITE) && _type == DOUBLE)
1380     return set_double(value);
1381
1382   bool result = false;
1383   TEST_WRITE;
1384   if (_type == NONE || _type == UNSPECIFIED) {
1385     clearValue();
1386     _local_val.double_val = value;
1387     _type = DOUBLE;
1388   }
1389
1390   switch (_type) {
1391   case ALIAS:
1392     result = _value.alias->setDoubleValue(value);
1393     break;
1394   case BOOL:
1395     result = set_bool(value == 0.0L ? false : true);
1396     break;
1397   case INT:
1398     result = set_int(int(value));
1399     break;
1400   case LONG:
1401     result = set_long(long(value));
1402     break;
1403   case FLOAT:
1404     result = set_float(float(value));
1405     break;
1406   case DOUBLE:
1407     result = set_double(value);
1408     break;
1409   case STRING:
1410   case UNSPECIFIED: {
1411     char buf[128];
1412     sprintf(buf, "%f", value);
1413     result = set_string(buf);
1414     break;
1415   }
1416   case NONE:
1417   default:
1418     break;
1419   }
1420
1421   if (getAttribute(TRACE_WRITE))
1422     trace_write();
1423   return result;
1424 }
1425
1426 bool
1427 SGPropertyNode::setStringValue (const char * value)
1428 {
1429                                 // Shortcut for common case
1430   if (_attr == (READ|WRITE) && _type == STRING)
1431     return set_string(value);
1432
1433   bool result = false;
1434   TEST_WRITE;
1435   if (_type == NONE || _type == UNSPECIFIED) {
1436     clearValue();
1437     _type = STRING;
1438   }
1439
1440   switch (_type) {
1441   case ALIAS:
1442     result = _value.alias->setStringValue(value);
1443     break;
1444   case BOOL:
1445     result = set_bool((compare_strings(value, "true")
1446                        || atoi(value)) ? true : false);
1447     break;
1448   case INT:
1449     result = set_int(atoi(value));
1450     break;
1451   case LONG:
1452     result = set_long(strtol(value, 0, 0));
1453     break;
1454   case FLOAT:
1455     result = set_float(atof(value));
1456     break;
1457   case DOUBLE:
1458     result = set_double(strtod(value, 0));
1459     break;
1460   case STRING:
1461   case UNSPECIFIED:
1462     result = set_string(value);
1463     break;
1464   case NONE:
1465   default:
1466     break;
1467   }
1468
1469   if (getAttribute(TRACE_WRITE))
1470     trace_write();
1471   return result;
1472 }
1473
1474 bool
1475 SGPropertyNode::setUnspecifiedValue (const char * value)
1476 {
1477   bool result = false;
1478   TEST_WRITE;
1479   if (_type == NONE) {
1480     clearValue();
1481     _type = UNSPECIFIED;
1482   }
1483
1484   switch (_type) {
1485   case ALIAS:
1486     result = _value.alias->setUnspecifiedValue(value);
1487     break;
1488   case BOOL:
1489     result = set_bool((compare_strings(value, "true")
1490                        || atoi(value)) ? true : false);
1491     break;
1492   case INT:
1493     result = set_int(atoi(value));
1494     break;
1495   case LONG:
1496     result = set_long(strtol(value, 0, 0));
1497     break;
1498   case FLOAT:
1499     result = set_float(atof(value));
1500     break;
1501   case DOUBLE:
1502     result = set_double(strtod(value, 0));
1503     break;
1504   case STRING:
1505   case UNSPECIFIED:
1506     result = set_string(value);
1507     break;
1508   case NONE:
1509   default:
1510     break;
1511   }
1512
1513   if (getAttribute(TRACE_WRITE))
1514     trace_write();
1515   return result;
1516 }
1517
1518 bool
1519 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1520 {
1521   if (_type == ALIAS || _tied)
1522     return false;
1523
1524   useDefault = useDefault && hasValue();
1525   bool old_val = false;
1526   if (useDefault)
1527     old_val = getBoolValue();
1528
1529   clearValue();
1530   _type = BOOL;
1531   _tied = true;
1532   _value.bool_val = rawValue.clone();
1533
1534   if (useDefault)
1535     setBoolValue(old_val);
1536
1537   return true;
1538 }
1539
1540 bool
1541 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1542 {
1543   if (_type == ALIAS || _tied)
1544     return false;
1545
1546   useDefault = useDefault && hasValue();
1547   int old_val = 0;
1548   if (useDefault)
1549     old_val = getIntValue();
1550
1551   clearValue();
1552   _type = INT;
1553   _tied = true;
1554   _value.int_val = rawValue.clone();
1555
1556   if (useDefault)
1557     setIntValue(old_val);
1558
1559   return true;
1560 }
1561
1562 bool
1563 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1564 {
1565   if (_type == ALIAS || _tied)
1566     return false;
1567
1568   useDefault = useDefault && hasValue();
1569   long old_val = 0;
1570   if (useDefault)
1571     old_val = getLongValue();
1572
1573   clearValue();
1574   _type = LONG;
1575   _tied = true;
1576   _value.long_val = rawValue.clone();
1577
1578   if (useDefault)
1579     setLongValue(old_val);
1580
1581   return true;
1582 }
1583
1584 bool
1585 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1586 {
1587   if (_type == ALIAS || _tied)
1588     return false;
1589
1590   useDefault = useDefault && hasValue();
1591   float old_val = 0.0;
1592   if (useDefault)
1593     old_val = getFloatValue();
1594
1595   clearValue();
1596   _type = FLOAT;
1597   _tied = true;
1598   _value.float_val = rawValue.clone();
1599
1600   if (useDefault)
1601     setFloatValue(old_val);
1602
1603   return true;
1604 }
1605
1606 bool
1607 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1608 {
1609   if (_type == ALIAS || _tied)
1610     return false;
1611
1612   useDefault = useDefault && hasValue();
1613   double old_val = 0.0;
1614   if (useDefault)
1615     old_val = getDoubleValue();
1616
1617   clearValue();
1618   _type = DOUBLE;
1619   _tied = true;
1620   _value.double_val = rawValue.clone();
1621
1622   if (useDefault)
1623     setDoubleValue(old_val);
1624
1625   return true;
1626
1627 }
1628
1629 bool
1630 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1631 {
1632   if (_type == ALIAS || _tied)
1633     return false;
1634
1635   useDefault = useDefault && hasValue();
1636   string old_val;
1637   if (useDefault)
1638     old_val = getStringValue();
1639
1640   clearValue();
1641   _type = STRING;
1642   _tied = true;
1643   _value.string_val = rawValue.clone();
1644
1645   if (useDefault)
1646     setStringValue(old_val.c_str());
1647
1648   return true;
1649 }
1650
1651 bool
1652 SGPropertyNode::untie ()
1653 {
1654   if (!_tied)
1655     return false;
1656
1657   switch (_type) {
1658   case BOOL: {
1659     bool val = getBoolValue();
1660     clearValue();
1661     _type = BOOL;
1662     _local_val.bool_val = val;
1663     break;
1664   }
1665   case INT: {
1666     int val = getIntValue();
1667     clearValue();
1668     _type = INT;
1669     _local_val.int_val = val;
1670     break;
1671   }
1672   case LONG: {
1673     long val = getLongValue();
1674     clearValue();
1675     _type = LONG;
1676     _local_val.long_val = val;
1677     break;
1678   }
1679   case FLOAT: {
1680     float val = getFloatValue();
1681     clearValue();
1682     _type = FLOAT;
1683     _local_val.float_val = val;
1684     break;
1685   }
1686   case DOUBLE: {
1687     double val = getDoubleValue();
1688     clearValue();
1689     _type = DOUBLE;
1690     _local_val.double_val = val;
1691     break;
1692   }
1693   case STRING:
1694   case UNSPECIFIED: {
1695     string val = getStringValue();
1696     clearValue();
1697     _type = STRING;
1698     _local_val.string_val = copy_string(val.c_str());
1699     break;
1700   }
1701   case NONE:
1702   default:
1703     break;
1704   }
1705
1706   _tied = false;
1707   return true;
1708 }
1709
1710 SGPropertyNode *
1711 SGPropertyNode::getRootNode ()
1712 {
1713   if (_parent == 0)
1714     return this;
1715   else
1716     return _parent->getRootNode();
1717 }
1718
1719 const SGPropertyNode *
1720 SGPropertyNode::getRootNode () const
1721 {
1722   if (_parent == 0)
1723     return this;
1724   else
1725     return _parent->getRootNode();
1726 }
1727
1728 SGPropertyNode *
1729 SGPropertyNode::getNode (const char * relative_path, bool create)
1730 {
1731   if (_path_cache == 0)
1732     _path_cache = new hash_table;
1733
1734   SGPropertyNode * result = _path_cache->get(relative_path);
1735   if (result == 0) {
1736     vector<PathComponent> components;
1737     parse_path(relative_path, components);
1738     result = find_node(this, components, 0, create);
1739     if (result != 0)
1740       _path_cache->put(relative_path, result);
1741   }
1742
1743   return result;
1744 }
1745
1746 SGPropertyNode *
1747 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1748 {
1749   vector<PathComponent> components;
1750   parse_path(relative_path, components);
1751   if (components.size() > 0)
1752     components.back().index = index;
1753   return find_node(this, components, 0, create);
1754 }
1755
1756 const SGPropertyNode *
1757 SGPropertyNode::getNode (const char * relative_path) const
1758 {
1759   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1760 }
1761
1762 const SGPropertyNode *
1763 SGPropertyNode::getNode (const char * relative_path, int index) const
1764 {
1765   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1766 }
1767
1768 \f
1769 ////////////////////////////////////////////////////////////////////////
1770 // Convenience methods using relative paths.
1771 ////////////////////////////////////////////////////////////////////////
1772
1773
1774 /**
1775  * Test whether another node has a value attached.
1776  */
1777 bool
1778 SGPropertyNode::hasValue (const char * relative_path) const
1779 {
1780   const SGPropertyNode * node = getNode(relative_path);
1781   return (node == 0 ? false : node->hasValue());
1782 }
1783
1784
1785 /**
1786  * Get the value type for another node.
1787  */
1788 SGPropertyNode::Type
1789 SGPropertyNode::getType (const char * relative_path) const
1790 {
1791   const SGPropertyNode * node = getNode(relative_path);
1792   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1793 }
1794
1795
1796 /**
1797  * Get a bool value for another node.
1798  */
1799 bool
1800 SGPropertyNode::getBoolValue (const char * relative_path,
1801                               bool defaultValue) const
1802 {
1803   const SGPropertyNode * node = getNode(relative_path);
1804   return (node == 0 ? defaultValue : node->getBoolValue());
1805 }
1806
1807
1808 /**
1809  * Get an int value for another node.
1810  */
1811 int
1812 SGPropertyNode::getIntValue (const char * relative_path,
1813                              int defaultValue) const
1814 {
1815   const SGPropertyNode * node = getNode(relative_path);
1816   return (node == 0 ? defaultValue : node->getIntValue());
1817 }
1818
1819
1820 /**
1821  * Get a long value for another node.
1822  */
1823 long
1824 SGPropertyNode::getLongValue (const char * relative_path,
1825                               long defaultValue) const
1826 {
1827   const SGPropertyNode * node = getNode(relative_path);
1828   return (node == 0 ? defaultValue : node->getLongValue());
1829 }
1830
1831
1832 /**
1833  * Get a float value for another node.
1834  */
1835 float
1836 SGPropertyNode::getFloatValue (const char * relative_path,
1837                                float defaultValue) const
1838 {
1839   const SGPropertyNode * node = getNode(relative_path);
1840   return (node == 0 ? defaultValue : node->getFloatValue());
1841 }
1842
1843
1844 /**
1845  * Get a double value for another node.
1846  */
1847 double
1848 SGPropertyNode::getDoubleValue (const char * relative_path,
1849                                 double defaultValue) const
1850 {
1851   const SGPropertyNode * node = getNode(relative_path);
1852   return (node == 0 ? defaultValue : node->getDoubleValue());
1853 }
1854
1855
1856 /**
1857  * Get a string value for another node.
1858  */
1859 const char *
1860 SGPropertyNode::getStringValue (const char * relative_path,
1861                                 const char * defaultValue) const
1862 {
1863   const SGPropertyNode * node = getNode(relative_path);
1864   return (node == 0 ? defaultValue : node->getStringValue());
1865 }
1866
1867
1868 /**
1869  * Set a bool value for another node.
1870  */
1871 bool
1872 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1873 {
1874   return getNode(relative_path, true)->setBoolValue(value);
1875 }
1876
1877
1878 /**
1879  * Set an int value for another node.
1880  */
1881 bool
1882 SGPropertyNode::setIntValue (const char * relative_path, int value)
1883 {
1884   return getNode(relative_path, true)->setIntValue(value);
1885 }
1886
1887
1888 /**
1889  * Set a long value for another node.
1890  */
1891 bool
1892 SGPropertyNode::setLongValue (const char * relative_path, long value)
1893 {
1894   return getNode(relative_path, true)->setLongValue(value);
1895 }
1896
1897
1898 /**
1899  * Set a float value for another node.
1900  */
1901 bool
1902 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1903 {
1904   return getNode(relative_path, true)->setFloatValue(value);
1905 }
1906
1907
1908 /**
1909  * Set a double value for another node.
1910  */
1911 bool
1912 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1913 {
1914   return getNode(relative_path, true)->setDoubleValue(value);
1915 }
1916
1917
1918 /**
1919  * Set a string value for another node.
1920  */
1921 bool
1922 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1923 {
1924   return getNode(relative_path, true)->setStringValue(value);
1925 }
1926
1927
1928 /**
1929  * Set an unknown value for another node.
1930  */
1931 bool
1932 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1933                                      const char * value)
1934 {
1935   return getNode(relative_path, true)->setUnspecifiedValue(value);
1936 }
1937
1938
1939 /**
1940  * Test whether another node is tied.
1941  */
1942 bool
1943 SGPropertyNode::isTied (const char * relative_path) const
1944 {
1945   const SGPropertyNode * node = getNode(relative_path);
1946   return (node == 0 ? false : node->isTied());
1947 }
1948
1949
1950 /**
1951  * Tie a node reached by a relative path, creating it if necessary.
1952  */
1953 bool
1954 SGPropertyNode::tie (const char * relative_path,
1955                      const SGRawValue<bool> &rawValue,
1956                      bool useDefault)
1957 {
1958   return getNode(relative_path, true)->tie(rawValue, useDefault);
1959 }
1960
1961
1962 /**
1963  * Tie a node reached by a relative path, creating it if necessary.
1964  */
1965 bool
1966 SGPropertyNode::tie (const char * relative_path,
1967                      const SGRawValue<int> &rawValue,
1968                      bool useDefault)
1969 {
1970   return getNode(relative_path, true)->tie(rawValue, useDefault);
1971 }
1972
1973
1974 /**
1975  * Tie a node reached by a relative path, creating it if necessary.
1976  */
1977 bool
1978 SGPropertyNode::tie (const char * relative_path,
1979                      const SGRawValue<long> &rawValue,
1980                      bool useDefault)
1981 {
1982   return getNode(relative_path, true)->tie(rawValue, useDefault);
1983 }
1984
1985
1986 /**
1987  * Tie a node reached by a relative path, creating it if necessary.
1988  */
1989 bool
1990 SGPropertyNode::tie (const char * relative_path,
1991                      const SGRawValue<float> &rawValue,
1992                      bool useDefault)
1993 {
1994   return getNode(relative_path, true)->tie(rawValue, useDefault);
1995 }
1996
1997
1998 /**
1999  * Tie a node reached by a relative path, creating it if necessary.
2000  */
2001 bool
2002 SGPropertyNode::tie (const char * relative_path,
2003                      const SGRawValue<double> &rawValue,
2004                      bool useDefault)
2005 {
2006   return getNode(relative_path, true)->tie(rawValue, useDefault);
2007 }
2008
2009
2010 /**
2011  * Tie a node reached by a relative path, creating it if necessary.
2012  */
2013 bool
2014 SGPropertyNode::tie (const char * relative_path,
2015                      const SGRawValue<const char *> &rawValue,
2016                      bool useDefault)
2017 {
2018   return getNode(relative_path, true)->tie(rawValue, useDefault);
2019 }
2020
2021
2022 /**
2023  * Attempt to untie another node reached by a relative path.
2024  */
2025 bool
2026 SGPropertyNode::untie (const char * relative_path)
2027 {
2028   SGPropertyNode * node = getNode(relative_path);
2029   return (node == 0 ? false : node->untie());
2030 }
2031
2032 void
2033 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener)
2034 {
2035   if (_listeners == 0)
2036     _listeners = new vector<SGPropertyChangeListener*>;
2037   _listeners->push_back(listener);
2038   listener->register_property(this);
2039 }
2040
2041 void
2042 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2043 {
2044   vector<SGPropertyChangeListener*>::iterator it =
2045     find(_listeners->begin(), _listeners->end(), listener);
2046   if (it != _listeners->end()) {
2047     _listeners->erase(it);
2048     listener->unregister_property(this);
2049     if (_listeners->empty()) {
2050       vector<SGPropertyChangeListener*>* tmp = _listeners;
2051       _listeners = 0;
2052       delete tmp;
2053     }
2054   }
2055 }
2056
2057 void
2058 SGPropertyNode::fireValueChanged ()
2059 {
2060   fireValueChanged(this);
2061 }
2062
2063 void
2064 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2065 {
2066   fireChildAdded(this, child);
2067 }
2068
2069 void
2070 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2071 {
2072   fireChildRemoved(this, child);
2073 }
2074
2075 void
2076 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2077 {
2078   if (_listeners != 0) {
2079     for (unsigned int i = 0; i < _listeners->size(); i++) {
2080       (*_listeners)[i]->valueChanged(node);
2081     }
2082   }
2083   if (_parent != 0)
2084     _parent->fireValueChanged(node);
2085 }
2086
2087 void
2088 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2089                                 SGPropertyNode * child)
2090 {
2091   if (_listeners != 0) {
2092     for (unsigned int i = 0; i < _listeners->size(); i++) {
2093       (*_listeners)[i]->childAdded(parent, child);
2094     }
2095   }
2096   if (_parent != 0)
2097     _parent->fireChildAdded(parent, child);
2098 }
2099
2100 void
2101 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2102                                   SGPropertyNode * child)
2103 {
2104   if (_listeners != 0) {
2105     for (unsigned int i = 0; i < _listeners->size(); i++) {
2106       (*_listeners)[i]->childRemoved(parent, child);
2107     }
2108   }
2109   if (_parent != 0)
2110     _parent->fireChildRemoved(parent, child);
2111 }
2112
2113
2114 \f
2115 ////////////////////////////////////////////////////////////////////////
2116 // Simplified hash table for caching paths.
2117 ////////////////////////////////////////////////////////////////////////
2118
2119 #define HASH_TABLE_SIZE 199
2120
2121 SGPropertyNode::hash_table::entry::entry ()
2122   : _value(0)
2123 {
2124 }
2125
2126 SGPropertyNode::hash_table::entry::~entry ()
2127 {
2128                                 // Don't delete the value; we don't own
2129                                 // the pointer.
2130 }
2131
2132 void
2133 SGPropertyNode::hash_table::entry::set_key (const char * key)
2134 {
2135   _key = key;
2136 }
2137
2138 void
2139 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2140 {
2141   _value = value;
2142 }
2143
2144 SGPropertyNode::hash_table::bucket::bucket ()
2145   : _length(0),
2146     _entries(0)
2147 {
2148 }
2149
2150 SGPropertyNode::hash_table::bucket::~bucket ()
2151 {
2152   for (int i = 0; i < _length; i++)
2153     delete _entries[i];
2154   delete [] _entries;
2155 }
2156
2157 SGPropertyNode::hash_table::entry *
2158 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2159 {
2160   int i;
2161   for (i = 0; i < _length; i++) {
2162     if (!strcmp(_entries[i]->get_key(), key))
2163       return _entries[i];
2164   }
2165   if (create) {
2166     entry ** new_entries = new entry*[_length+1];
2167     for (i = 0; i < _length; i++) {
2168       new_entries[i] = _entries[i];
2169     }
2170     delete [] _entries;
2171     _entries = new_entries;
2172     _entries[_length] = new entry;
2173     _entries[_length]->set_key(key);
2174     _length++;
2175     return _entries[_length - 1];
2176   } else {
2177     return 0;
2178   }
2179 }
2180
2181 void
2182 SGPropertyNode::hash_table::bucket::erase (const char * key)
2183 {
2184   int i;
2185   for (i = 0; i < _length; i++) {
2186     if (!strcmp(_entries[i]->get_key(), key))
2187        break;
2188   }
2189
2190   if (i < _length) {
2191     for (++i; i < _length; i++) {
2192       _entries[i-1] = _entries[i];
2193     }
2194      _length--;
2195   }
2196 }
2197
2198
2199 SGPropertyNode::hash_table::hash_table ()
2200   : _data_length(0),
2201     _data(0)
2202 {
2203 }
2204
2205 SGPropertyNode::hash_table::~hash_table ()
2206 {
2207   for (unsigned int i = 0; i < _data_length; i++)
2208     delete _data[i];
2209   delete [] _data;
2210 }
2211
2212 SGPropertyNode *
2213 SGPropertyNode::hash_table::get (const char * key)
2214 {
2215   if (_data_length == 0)
2216     return 0;
2217   unsigned int index = hashcode(key) % _data_length;
2218   if (_data[index] == 0)
2219     return 0;
2220   entry * e = _data[index]->get_entry(key);
2221   if (e == 0)
2222     return 0;
2223   else
2224     return e->get_value();
2225 }
2226
2227 void
2228 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2229 {
2230   if (_data_length == 0) {
2231     _data = new bucket*[HASH_TABLE_SIZE];
2232     _data_length = HASH_TABLE_SIZE;
2233     for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2234       _data[i] = 0;
2235   }
2236   unsigned int index = hashcode(key) % _data_length;
2237   if (_data[index] == 0) {
2238     _data[index] = new bucket;
2239   }
2240   entry * e = _data[index]->get_entry(key, true);
2241   e->set_value(value);
2242 }
2243
2244 void
2245 SGPropertyNode::hash_table::erase (const char * key)
2246 {
2247    if (_data_length == 0)
2248     return;
2249   unsigned int index = hashcode(key) % _data_length;
2250   if (_data[index] == 0)
2251     return;
2252   _data[index]->erase(key);
2253 }
2254
2255 unsigned int
2256 SGPropertyNode::hash_table::hashcode (const char * key)
2257 {
2258   unsigned int hash = 0;
2259   while (*key != 0) {
2260     hash = 31 * hash + *key;
2261     key++;
2262   }
2263   return hash;
2264 }
2265
2266
2267 \f
2268 ////////////////////////////////////////////////////////////////////////
2269 // Implementation of SGPropertyChangeListener.
2270 ////////////////////////////////////////////////////////////////////////
2271
2272 SGPropertyChangeListener::~SGPropertyChangeListener ()
2273 {
2274                                 // This will come back and remove
2275                                 // the current item each time.  Is
2276                                 // that OK?
2277   vector<SGPropertyNode *>::iterator it;
2278   for (it = _properties.begin(); it != _properties.end(); it++)
2279     (*it)->removeChangeListener(this);
2280 }
2281
2282 void
2283 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2284 {
2285   // NO-OP
2286 }
2287
2288 void
2289 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2290                                       SGPropertyNode * child)
2291 {
2292   // NO-OP
2293 }
2294
2295 void
2296 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2297                                         SGPropertyNode * child)
2298 {
2299   // NO-OP
2300 }
2301
2302 void
2303 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2304 {
2305   _properties.push_back(node);
2306 }
2307
2308 void
2309 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2310 {
2311   vector<SGPropertyNode *>::iterator it =
2312     find(_properties.begin(), _properties.end(), node);
2313   if (it != _properties.end())
2314     _properties.erase(it);
2315 }
2316
2317
2318 // end of props.cxx