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