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