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