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