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