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