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