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