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