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