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