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