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