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