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