]> git.mxchange.org Git - simgear.git/blob - simgear/props/props.cxx
Merge branch 'ehofman/particles'
[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 string
1040 SGPropertyNode::getPath (bool simplify) const
1041 {
1042   typedef std::vector<SGConstPropertyNode_ptr> PList;
1043   PList pathList;
1044   for (const SGPropertyNode* node = this; node->_parent; node = node->_parent)
1045     pathList.push_back(node);
1046   string result;
1047   for (PList::reverse_iterator itr = pathList.rbegin(),
1048          rend = pathList.rend();
1049        itr != rend;
1050        ++itr) {
1051     result += '/';
1052     result += (*itr)->getDisplayName(simplify);
1053   }
1054   return result;
1055 }
1056
1057 props::Type
1058 SGPropertyNode::getType () const
1059 {
1060   if (_type == props::ALIAS)
1061     return _value.alias->getType();
1062   else if (_type == props::EXTENDED)
1063       return _value.val->getType();
1064   else
1065     return _type;
1066 }
1067
1068
1069 bool 
1070 SGPropertyNode::getBoolValue () const
1071 {
1072                                 // Shortcut for common case
1073   if (_attr == (READ|WRITE) && _type == props::BOOL)
1074     return get_bool();
1075
1076   if (getAttribute(TRACE_READ))
1077     trace_read();
1078   if (!getAttribute(READ))
1079     return SGRawValue<bool>::DefaultValue();
1080   switch (_type) {
1081   case props::ALIAS:
1082     return _value.alias->getBoolValue();
1083   case props::BOOL:
1084     return get_bool();
1085   case props::INT:
1086     return get_int() == 0 ? false : true;
1087   case props::LONG:
1088     return get_long() == 0L ? false : true;
1089   case props::FLOAT:
1090     return get_float() == 0.0 ? false : true;
1091   case props::DOUBLE:
1092     return get_double() == 0.0L ? false : true;
1093   case props::STRING:
1094   case props::UNSPECIFIED:
1095     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1096   case props::NONE:
1097   default:
1098     return SGRawValue<bool>::DefaultValue();
1099   }
1100 }
1101
1102 int 
1103 SGPropertyNode::getIntValue () const
1104 {
1105                                 // Shortcut for common case
1106   if (_attr == (READ|WRITE) && _type == props::INT)
1107     return get_int();
1108
1109   if (getAttribute(TRACE_READ))
1110     trace_read();
1111   if (!getAttribute(READ))
1112     return SGRawValue<int>::DefaultValue();
1113   switch (_type) {
1114   case props::ALIAS:
1115     return _value.alias->getIntValue();
1116   case props::BOOL:
1117     return int(get_bool());
1118   case props::INT:
1119     return get_int();
1120   case props::LONG:
1121     return int(get_long());
1122   case props::FLOAT:
1123     return int(get_float());
1124   case props::DOUBLE:
1125     return int(get_double());
1126   case props::STRING:
1127   case props::UNSPECIFIED:
1128     return atoi(get_string());
1129   case props::NONE:
1130   default:
1131     return SGRawValue<int>::DefaultValue();
1132   }
1133 }
1134
1135 long 
1136 SGPropertyNode::getLongValue () const
1137 {
1138                                 // Shortcut for common case
1139   if (_attr == (READ|WRITE) && _type == props::LONG)
1140     return get_long();
1141
1142   if (getAttribute(TRACE_READ))
1143     trace_read();
1144   if (!getAttribute(READ))
1145     return SGRawValue<long>::DefaultValue();
1146   switch (_type) {
1147   case props::ALIAS:
1148     return _value.alias->getLongValue();
1149   case props::BOOL:
1150     return long(get_bool());
1151   case props::INT:
1152     return long(get_int());
1153   case props::LONG:
1154     return get_long();
1155   case props::FLOAT:
1156     return long(get_float());
1157   case props::DOUBLE:
1158     return long(get_double());
1159   case props::STRING:
1160   case props::UNSPECIFIED:
1161     return strtol(get_string(), 0, 0);
1162   case props::NONE:
1163   default:
1164     return SGRawValue<long>::DefaultValue();
1165   }
1166 }
1167
1168 float 
1169 SGPropertyNode::getFloatValue () const
1170 {
1171                                 // Shortcut for common case
1172   if (_attr == (READ|WRITE) && _type == props::FLOAT)
1173     return get_float();
1174
1175   if (getAttribute(TRACE_READ))
1176     trace_read();
1177   if (!getAttribute(READ))
1178     return SGRawValue<float>::DefaultValue();
1179   switch (_type) {
1180   case props::ALIAS:
1181     return _value.alias->getFloatValue();
1182   case props::BOOL:
1183     return float(get_bool());
1184   case props::INT:
1185     return float(get_int());
1186   case props::LONG:
1187     return float(get_long());
1188   case props::FLOAT:
1189     return get_float();
1190   case props::DOUBLE:
1191     return float(get_double());
1192   case props::STRING:
1193   case props::UNSPECIFIED:
1194     return atof(get_string());
1195   case props::NONE:
1196   default:
1197     return SGRawValue<float>::DefaultValue();
1198   }
1199 }
1200
1201 double 
1202 SGPropertyNode::getDoubleValue () const
1203 {
1204                                 // Shortcut for common case
1205   if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1206     return get_double();
1207
1208   if (getAttribute(TRACE_READ))
1209     trace_read();
1210   if (!getAttribute(READ))
1211     return SGRawValue<double>::DefaultValue();
1212
1213   switch (_type) {
1214   case props::ALIAS:
1215     return _value.alias->getDoubleValue();
1216   case props::BOOL:
1217     return double(get_bool());
1218   case props::INT:
1219     return double(get_int());
1220   case props::LONG:
1221     return double(get_long());
1222   case props::FLOAT:
1223     return double(get_float());
1224   case props::DOUBLE:
1225     return get_double();
1226   case props::STRING:
1227   case props::UNSPECIFIED:
1228     return strtod(get_string(), 0);
1229   case props::NONE:
1230   default:
1231     return SGRawValue<double>::DefaultValue();
1232   }
1233 }
1234
1235 const char *
1236 SGPropertyNode::getStringValue () const
1237 {
1238                                 // Shortcut for common case
1239   if (_attr == (READ|WRITE) && _type == props::STRING)
1240     return get_string();
1241
1242   if (getAttribute(TRACE_READ))
1243     trace_read();
1244   if (!getAttribute(READ))
1245     return SGRawValue<const char *>::DefaultValue();
1246   return make_string();
1247 }
1248
1249 bool
1250 SGPropertyNode::setBoolValue (bool value)
1251 {
1252                                 // Shortcut for common case
1253   if (_attr == (READ|WRITE) && _type == props::BOOL)
1254     return set_bool(value);
1255
1256   bool result = false;
1257   TEST_WRITE;
1258   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1259     clearValue();
1260     _tied = false;
1261     _type = props::BOOL;
1262   }
1263
1264   switch (_type) {
1265   case props::ALIAS:
1266     result = _value.alias->setBoolValue(value);
1267     break;
1268   case props::BOOL:
1269     result = set_bool(value);
1270     break;
1271   case props::INT:
1272     result = set_int(int(value));
1273     break;
1274   case props::LONG:
1275     result = set_long(long(value));
1276     break;
1277   case props::FLOAT:
1278     result = set_float(float(value));
1279     break;
1280   case props::DOUBLE:
1281     result = set_double(double(value));
1282     break;
1283   case props::STRING:
1284   case props::UNSPECIFIED:
1285     result = set_string(value ? "true" : "false");
1286     break;
1287   case props::NONE:
1288   default:
1289     break;
1290   }
1291
1292   if (getAttribute(TRACE_WRITE))
1293     trace_write();
1294   return result;
1295 }
1296
1297 bool
1298 SGPropertyNode::setIntValue (int value)
1299 {
1300                                 // Shortcut for common case
1301   if (_attr == (READ|WRITE) && _type == props::INT)
1302     return set_int(value);
1303
1304   bool result = false;
1305   TEST_WRITE;
1306   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1307     clearValue();
1308     _type = props::INT;
1309     _local_val.int_val = 0;
1310   }
1311
1312   switch (_type) {
1313   case props::ALIAS:
1314     result = _value.alias->setIntValue(value);
1315     break;
1316   case props::BOOL:
1317     result = set_bool(value == 0 ? false : true);
1318     break;
1319   case props::INT:
1320     result = set_int(value);
1321     break;
1322   case props::LONG:
1323     result = set_long(long(value));
1324     break;
1325   case props::FLOAT:
1326     result = set_float(float(value));
1327     break;
1328   case props::DOUBLE:
1329     result = set_double(double(value));
1330     break;
1331   case props::STRING:
1332   case props::UNSPECIFIED: {
1333     char buf[128];
1334     sprintf(buf, "%d", value);
1335     result = set_string(buf);
1336     break;
1337   }
1338   case props::NONE:
1339   default:
1340     break;
1341   }
1342
1343   if (getAttribute(TRACE_WRITE))
1344     trace_write();
1345   return result;
1346 }
1347
1348 bool
1349 SGPropertyNode::setLongValue (long value)
1350 {
1351                                 // Shortcut for common case
1352   if (_attr == (READ|WRITE) && _type == props::LONG)
1353     return set_long(value);
1354
1355   bool result = false;
1356   TEST_WRITE;
1357   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1358     clearValue();
1359     _type = props::LONG;
1360     _local_val.long_val = 0L;
1361   }
1362
1363   switch (_type) {
1364   case props::ALIAS:
1365     result = _value.alias->setLongValue(value);
1366     break;
1367   case props::BOOL:
1368     result = set_bool(value == 0L ? false : true);
1369     break;
1370   case props::INT:
1371     result = set_int(int(value));
1372     break;
1373   case props::LONG:
1374     result = set_long(value);
1375     break;
1376   case props::FLOAT:
1377     result = set_float(float(value));
1378     break;
1379   case props::DOUBLE:
1380     result = set_double(double(value));
1381     break;
1382   case props::STRING:
1383   case props::UNSPECIFIED: {
1384     char buf[128];
1385     sprintf(buf, "%ld", value);
1386     result = set_string(buf);
1387     break;
1388   }
1389   case props::NONE:
1390   default:
1391     break;
1392   }
1393
1394   if (getAttribute(TRACE_WRITE))
1395     trace_write();
1396   return result;
1397 }
1398
1399 bool
1400 SGPropertyNode::setFloatValue (float value)
1401 {
1402                                 // Shortcut for common case
1403   if (_attr == (READ|WRITE) && _type == props::FLOAT)
1404     return set_float(value);
1405
1406   bool result = false;
1407   TEST_WRITE;
1408   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1409     clearValue();
1410     _type = props::FLOAT;
1411     _local_val.float_val = 0;
1412   }
1413
1414   switch (_type) {
1415   case props::ALIAS:
1416     result = _value.alias->setFloatValue(value);
1417     break;
1418   case props::BOOL:
1419     result = set_bool(value == 0.0 ? false : true);
1420     break;
1421   case props::INT:
1422     result = set_int(int(value));
1423     break;
1424   case props::LONG:
1425     result = set_long(long(value));
1426     break;
1427   case props::FLOAT:
1428     result = set_float(value);
1429     break;
1430   case props::DOUBLE:
1431     result = set_double(double(value));
1432     break;
1433   case props::STRING:
1434   case props::UNSPECIFIED: {
1435     char buf[128];
1436     sprintf(buf, "%f", value);
1437     result = set_string(buf);
1438     break;
1439   }
1440   case props::NONE:
1441   default:
1442     break;
1443   }
1444
1445   if (getAttribute(TRACE_WRITE))
1446     trace_write();
1447   return result;
1448 }
1449
1450 bool
1451 SGPropertyNode::setDoubleValue (double value)
1452 {
1453                                 // Shortcut for common case
1454   if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1455     return set_double(value);
1456
1457   bool result = false;
1458   TEST_WRITE;
1459   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1460     clearValue();
1461     _local_val.double_val = value;
1462     _type = props::DOUBLE;
1463   }
1464
1465   switch (_type) {
1466   case props::ALIAS:
1467     result = _value.alias->setDoubleValue(value);
1468     break;
1469   case props::BOOL:
1470     result = set_bool(value == 0.0L ? false : true);
1471     break;
1472   case props::INT:
1473     result = set_int(int(value));
1474     break;
1475   case props::LONG:
1476     result = set_long(long(value));
1477     break;
1478   case props::FLOAT:
1479     result = set_float(float(value));
1480     break;
1481   case props::DOUBLE:
1482     result = set_double(value);
1483     break;
1484   case props::STRING:
1485   case props::UNSPECIFIED: {
1486     char buf[128];
1487     sprintf(buf, "%f", value);
1488     result = set_string(buf);
1489     break;
1490   }
1491   case props::NONE:
1492   default:
1493     break;
1494   }
1495
1496   if (getAttribute(TRACE_WRITE))
1497     trace_write();
1498   return result;
1499 }
1500
1501 bool
1502 SGPropertyNode::setStringValue (const char * value)
1503 {
1504                                 // Shortcut for common case
1505   if (_attr == (READ|WRITE) && _type == props::STRING)
1506     return set_string(value);
1507
1508   bool result = false;
1509   TEST_WRITE;
1510   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1511     clearValue();
1512     _type = props::STRING;
1513   }
1514
1515   switch (_type) {
1516   case props::ALIAS:
1517     result = _value.alias->setStringValue(value);
1518     break;
1519   case props::BOOL:
1520     result = set_bool((compare_strings(value, "true")
1521                        || atoi(value)) ? true : false);
1522     break;
1523   case props::INT:
1524     result = set_int(atoi(value));
1525     break;
1526   case props::LONG:
1527     result = set_long(strtol(value, 0, 0));
1528     break;
1529   case props::FLOAT:
1530     result = set_float(atof(value));
1531     break;
1532   case props::DOUBLE:
1533     result = set_double(strtod(value, 0));
1534     break;
1535   case props::STRING:
1536   case props::UNSPECIFIED:
1537     result = set_string(value);
1538     break;
1539   case props::EXTENDED:
1540   {
1541     stringstream sstr(value);
1542     static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1543   }
1544   break;
1545   case props::NONE:
1546   default:
1547     break;
1548   }
1549
1550   if (getAttribute(TRACE_WRITE))
1551     trace_write();
1552   return result;
1553 }
1554
1555 bool
1556 SGPropertyNode::setUnspecifiedValue (const char * value)
1557 {
1558   bool result = false;
1559   TEST_WRITE;
1560   if (_type == props::NONE) {
1561     clearValue();
1562     _type = props::UNSPECIFIED;
1563   }
1564   props::Type type = _type;
1565   if (type == props::EXTENDED)
1566       type = _value.val->getType();
1567   switch (type) {
1568   case props::ALIAS:
1569     result = _value.alias->setUnspecifiedValue(value);
1570     break;
1571   case props::BOOL:
1572     result = set_bool((compare_strings(value, "true")
1573                        || atoi(value)) ? true : false);
1574     break;
1575   case props::INT:
1576     result = set_int(atoi(value));
1577     break;
1578   case props::LONG:
1579     result = set_long(strtol(value, 0, 0));
1580     break;
1581   case props::FLOAT:
1582     result = set_float(atof(value));
1583     break;
1584   case props::DOUBLE:
1585     result = set_double(strtod(value, 0));
1586     break;
1587   case props::STRING:
1588   case props::UNSPECIFIED:
1589     result = set_string(value);
1590     break;
1591   case props::VEC3D:
1592       result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1593       break;
1594   case props::VEC4D:
1595       result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1596       break;
1597   case props::NONE:
1598   default:
1599     break;
1600   }
1601
1602   if (getAttribute(TRACE_WRITE))
1603     trace_write();
1604   return result;
1605 }
1606
1607 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1608 {
1609     if (!getAttribute(READ))
1610         return stream;
1611     switch (_type) {
1612     case props::ALIAS:
1613         return _value.alias->printOn(stream);
1614     case props::BOOL:
1615         stream << (get_bool() ? "true" : "false");
1616         break;
1617     case props::INT:
1618         stream << get_int();
1619         break;
1620     case props::LONG:
1621         stream << get_long();
1622         break;
1623     case props::FLOAT:
1624         stream << get_float();
1625         break;
1626     case props::DOUBLE:
1627         stream << get_double();
1628         break;
1629     case props::STRING:
1630     case props::UNSPECIFIED:
1631         stream << get_string();
1632         break;
1633     case props::EXTENDED:
1634         static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1635         break;
1636     case props::NONE:
1637         break;
1638     default: // avoid compiler warning
1639         break;
1640     }
1641     return stream;
1642 }
1643
1644 template<>
1645 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1646                           bool useDefault)
1647 {
1648     if (_type == props::ALIAS || _tied)
1649         return false;
1650
1651     useDefault = useDefault && hasValue();
1652     std::string old_val;
1653     if (useDefault)
1654         old_val = getStringValue();
1655     clearValue();
1656     _type = props::STRING;
1657     _tied = true;
1658     _value.val = rawValue.clone();
1659
1660     if (useDefault)
1661         setStringValue(old_val.c_str());
1662
1663     return true;
1664 }
1665 bool
1666 SGPropertyNode::untie ()
1667 {
1668   if (!_tied)
1669     return false;
1670
1671   switch (_type) {
1672   case props::BOOL: {
1673     bool val = getBoolValue();
1674     clearValue();
1675     _type = props::BOOL;
1676     _local_val.bool_val = val;
1677     break;
1678   }
1679   case props::INT: {
1680     int val = getIntValue();
1681     clearValue();
1682     _type = props::INT;
1683     _local_val.int_val = val;
1684     break;
1685   }
1686   case props::LONG: {
1687     long val = getLongValue();
1688     clearValue();
1689     _type = props::LONG;
1690     _local_val.long_val = val;
1691     break;
1692   }
1693   case props::FLOAT: {
1694     float val = getFloatValue();
1695     clearValue();
1696     _type = props::FLOAT;
1697     _local_val.float_val = val;
1698     break;
1699   }
1700   case props::DOUBLE: {
1701     double val = getDoubleValue();
1702     clearValue();
1703     _type = props::DOUBLE;
1704     _local_val.double_val = val;
1705     break;
1706   }
1707   case props::STRING:
1708   case props::UNSPECIFIED: {
1709     string val = getStringValue();
1710     clearValue();
1711     _type = props::STRING;
1712     _local_val.string_val = copy_string(val.c_str());
1713     break;
1714   }
1715   case props::EXTENDED: {
1716     SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1717     _value.val = 0;             // Prevent clearValue() from deleting
1718     clearValue();
1719     _type = props::EXTENDED;
1720     _value.val = val->makeContainer();
1721     delete val;
1722     break;
1723   }
1724   case props::NONE:
1725   default:
1726     break;
1727   }
1728
1729   _tied = false;
1730   return true;
1731 }
1732
1733 SGPropertyNode *
1734 SGPropertyNode::getRootNode ()
1735 {
1736   if (_parent == 0)
1737     return this;
1738   else
1739     return _parent->getRootNode();
1740 }
1741
1742 const SGPropertyNode *
1743 SGPropertyNode::getRootNode () const
1744 {
1745   if (_parent == 0)
1746     return this;
1747   else
1748     return _parent->getRootNode();
1749 }
1750
1751 SGPropertyNode *
1752 SGPropertyNode::getNode (const char * relative_path, bool create)
1753 {
1754   using namespace boost;
1755   if (_path_cache == 0)
1756     _path_cache = new hash_table;
1757
1758   SGPropertyNode * result = _path_cache->get(relative_path);
1759   if (result == 0) {
1760     result = find_node(this,
1761                        make_iterator_range(relative_path, relative_path
1762                                            + strlen(relative_path)),
1763                        create);
1764     if (result != 0)
1765       _path_cache->put(relative_path, result);
1766   }
1767
1768   return result;
1769 }
1770
1771 SGPropertyNode *
1772 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1773 {
1774   using namespace boost;
1775   return find_node(this, make_iterator_range(relative_path, relative_path
1776                                              + strlen(relative_path)),
1777                    create, index);
1778 }
1779
1780 const SGPropertyNode *
1781 SGPropertyNode::getNode (const char * relative_path) const
1782 {
1783   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1784 }
1785
1786 const SGPropertyNode *
1787 SGPropertyNode::getNode (const char * relative_path, int index) const
1788 {
1789   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1790 }
1791
1792 \f
1793 ////////////////////////////////////////////////////////////////////////
1794 // Convenience methods using relative paths.
1795 ////////////////////////////////////////////////////////////////////////
1796
1797
1798 /**
1799  * Test whether another node has a value attached.
1800  */
1801 bool
1802 SGPropertyNode::hasValue (const char * relative_path) const
1803 {
1804   const SGPropertyNode * node = getNode(relative_path);
1805   return (node == 0 ? false : node->hasValue());
1806 }
1807
1808
1809 /**
1810  * Get the value type for another node.
1811  */
1812 props::Type
1813 SGPropertyNode::getType (const char * relative_path) const
1814 {
1815   const SGPropertyNode * node = getNode(relative_path);
1816   return (node == 0 ? props::UNSPECIFIED : node->getType());
1817 }
1818
1819
1820 /**
1821  * Get a bool value for another node.
1822  */
1823 bool
1824 SGPropertyNode::getBoolValue (const char * relative_path,
1825                               bool defaultValue) const
1826 {
1827   const SGPropertyNode * node = getNode(relative_path);
1828   return (node == 0 ? defaultValue : node->getBoolValue());
1829 }
1830
1831
1832 /**
1833  * Get an int value for another node.
1834  */
1835 int
1836 SGPropertyNode::getIntValue (const char * relative_path,
1837                              int defaultValue) const
1838 {
1839   const SGPropertyNode * node = getNode(relative_path);
1840   return (node == 0 ? defaultValue : node->getIntValue());
1841 }
1842
1843
1844 /**
1845  * Get a long value for another node.
1846  */
1847 long
1848 SGPropertyNode::getLongValue (const char * relative_path,
1849                               long defaultValue) const
1850 {
1851   const SGPropertyNode * node = getNode(relative_path);
1852   return (node == 0 ? defaultValue : node->getLongValue());
1853 }
1854
1855
1856 /**
1857  * Get a float value for another node.
1858  */
1859 float
1860 SGPropertyNode::getFloatValue (const char * relative_path,
1861                                float defaultValue) const
1862 {
1863   const SGPropertyNode * node = getNode(relative_path);
1864   return (node == 0 ? defaultValue : node->getFloatValue());
1865 }
1866
1867
1868 /**
1869  * Get a double value for another node.
1870  */
1871 double
1872 SGPropertyNode::getDoubleValue (const char * relative_path,
1873                                 double defaultValue) const
1874 {
1875   const SGPropertyNode * node = getNode(relative_path);
1876   return (node == 0 ? defaultValue : node->getDoubleValue());
1877 }
1878
1879
1880 /**
1881  * Get a string value for another node.
1882  */
1883 const char *
1884 SGPropertyNode::getStringValue (const char * relative_path,
1885                                 const char * defaultValue) const
1886 {
1887   const SGPropertyNode * node = getNode(relative_path);
1888   return (node == 0 ? defaultValue : node->getStringValue());
1889 }
1890
1891
1892 /**
1893  * Set a bool value for another node.
1894  */
1895 bool
1896 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1897 {
1898   return getNode(relative_path, true)->setBoolValue(value);
1899 }
1900
1901
1902 /**
1903  * Set an int value for another node.
1904  */
1905 bool
1906 SGPropertyNode::setIntValue (const char * relative_path, int value)
1907 {
1908   return getNode(relative_path, true)->setIntValue(value);
1909 }
1910
1911
1912 /**
1913  * Set a long value for another node.
1914  */
1915 bool
1916 SGPropertyNode::setLongValue (const char * relative_path, long value)
1917 {
1918   return getNode(relative_path, true)->setLongValue(value);
1919 }
1920
1921
1922 /**
1923  * Set a float value for another node.
1924  */
1925 bool
1926 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1927 {
1928   return getNode(relative_path, true)->setFloatValue(value);
1929 }
1930
1931
1932 /**
1933  * Set a double value for another node.
1934  */
1935 bool
1936 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1937 {
1938   return getNode(relative_path, true)->setDoubleValue(value);
1939 }
1940
1941
1942 /**
1943  * Set a string value for another node.
1944  */
1945 bool
1946 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1947 {
1948   return getNode(relative_path, true)->setStringValue(value);
1949 }
1950
1951
1952 /**
1953  * Set an unknown value for another node.
1954  */
1955 bool
1956 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1957                                      const char * value)
1958 {
1959   return getNode(relative_path, true)->setUnspecifiedValue(value);
1960 }
1961
1962
1963 /**
1964  * Test whether another node is tied.
1965  */
1966 bool
1967 SGPropertyNode::isTied (const char * relative_path) const
1968 {
1969   const SGPropertyNode * node = getNode(relative_path);
1970   return (node == 0 ? false : node->isTied());
1971 }
1972
1973
1974 /**
1975  * Tie a node reached by a relative path, creating it if necessary.
1976  */
1977 bool
1978 SGPropertyNode::tie (const char * relative_path,
1979                      const SGRawValue<bool> &rawValue,
1980                      bool useDefault)
1981 {
1982   return getNode(relative_path, true)->tie(rawValue, useDefault);
1983 }
1984
1985
1986 /**
1987  * Tie a node reached by a relative path, creating it if necessary.
1988  */
1989 bool
1990 SGPropertyNode::tie (const char * relative_path,
1991                      const SGRawValue<int> &rawValue,
1992                      bool useDefault)
1993 {
1994   return getNode(relative_path, true)->tie(rawValue, useDefault);
1995 }
1996
1997
1998 /**
1999  * Tie a node reached by a relative path, creating it if necessary.
2000  */
2001 bool
2002 SGPropertyNode::tie (const char * relative_path,
2003                      const SGRawValue<long> &rawValue,
2004                      bool useDefault)
2005 {
2006   return getNode(relative_path, true)->tie(rawValue, useDefault);
2007 }
2008
2009
2010 /**
2011  * Tie a node reached by a relative path, creating it if necessary.
2012  */
2013 bool
2014 SGPropertyNode::tie (const char * relative_path,
2015                      const SGRawValue<float> &rawValue,
2016                      bool useDefault)
2017 {
2018   return getNode(relative_path, true)->tie(rawValue, useDefault);
2019 }
2020
2021
2022 /**
2023  * Tie a node reached by a relative path, creating it if necessary.
2024  */
2025 bool
2026 SGPropertyNode::tie (const char * relative_path,
2027                      const SGRawValue<double> &rawValue,
2028                      bool useDefault)
2029 {
2030   return getNode(relative_path, true)->tie(rawValue, useDefault);
2031 }
2032
2033
2034 /**
2035  * Tie a node reached by a relative path, creating it if necessary.
2036  */
2037 bool
2038 SGPropertyNode::tie (const char * relative_path,
2039                      const SGRawValue<const char *> &rawValue,
2040                      bool useDefault)
2041 {
2042   return getNode(relative_path, true)->tie(rawValue, useDefault);
2043 }
2044
2045
2046 /**
2047  * Attempt to untie another node reached by a relative path.
2048  */
2049 bool
2050 SGPropertyNode::untie (const char * relative_path)
2051 {
2052   SGPropertyNode * node = getNode(relative_path);
2053   return (node == 0 ? false : node->untie());
2054 }
2055
2056 void
2057 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2058                                    bool initial)
2059 {
2060   if (_listeners == 0)
2061     _listeners = new vector<SGPropertyChangeListener*>;
2062   _listeners->push_back(listener);
2063   listener->register_property(this);
2064   if (initial)
2065     listener->valueChanged(this);
2066 }
2067
2068 void
2069 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2070 {
2071   vector<SGPropertyChangeListener*>::iterator it =
2072     find(_listeners->begin(), _listeners->end(), listener);
2073   if (it != _listeners->end()) {
2074     _listeners->erase(it);
2075     listener->unregister_property(this);
2076     if (_listeners->empty()) {
2077       vector<SGPropertyChangeListener*>* tmp = _listeners;
2078       _listeners = 0;
2079       delete tmp;
2080     }
2081   }
2082 }
2083
2084 void
2085 SGPropertyNode::fireValueChanged ()
2086 {
2087   fireValueChanged(this);
2088 }
2089
2090 void
2091 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2092 {
2093   fireChildAdded(this, child);
2094 }
2095
2096 void
2097 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2098 {
2099   fireChildRemoved(this, child);
2100 }
2101
2102 void
2103 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2104 {
2105   if (_listeners != 0) {
2106     for (unsigned int i = 0; i < _listeners->size(); i++) {
2107       (*_listeners)[i]->valueChanged(node);
2108     }
2109   }
2110   if (_parent != 0)
2111     _parent->fireValueChanged(node);
2112 }
2113
2114 void
2115 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2116                                 SGPropertyNode * child)
2117 {
2118   if (_listeners != 0) {
2119     for (unsigned int i = 0; i < _listeners->size(); i++) {
2120       (*_listeners)[i]->childAdded(parent, child);
2121     }
2122   }
2123   if (_parent != 0)
2124     _parent->fireChildAdded(parent, child);
2125 }
2126
2127 void
2128 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2129                                   SGPropertyNode * child)
2130 {
2131   if (_listeners != 0) {
2132     for (unsigned int i = 0; i < _listeners->size(); i++) {
2133       (*_listeners)[i]->childRemoved(parent, child);
2134     }
2135   }
2136   if (_parent != 0)
2137     _parent->fireChildRemoved(parent, child);
2138 }
2139
2140
2141 \f
2142 ////////////////////////////////////////////////////////////////////////
2143 // Simplified hash table for caching paths.
2144 ////////////////////////////////////////////////////////////////////////
2145
2146 #define HASH_TABLE_SIZE 199
2147
2148 SGPropertyNode::hash_table::entry::entry ()
2149   : _value(0)
2150 {
2151 }
2152
2153 SGPropertyNode::hash_table::entry::~entry ()
2154 {
2155                                 // Don't delete the value; we don't own
2156                                 // the pointer.
2157 }
2158
2159 void
2160 SGPropertyNode::hash_table::entry::set_key (const char * key)
2161 {
2162   _key = key;
2163 }
2164
2165 void
2166 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2167 {
2168   _value = value;
2169 }
2170
2171 SGPropertyNode::hash_table::bucket::bucket ()
2172   : _length(0),
2173     _entries(0)
2174 {
2175 }
2176
2177 SGPropertyNode::hash_table::bucket::~bucket ()
2178 {
2179   for (int i = 0; i < _length; i++)
2180     delete _entries[i];
2181   delete [] _entries;
2182 }
2183
2184 SGPropertyNode::hash_table::entry *
2185 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2186 {
2187   int i;
2188   for (i = 0; i < _length; i++) {
2189     if (!strcmp(_entries[i]->get_key(), key))
2190       return _entries[i];
2191   }
2192   if (create) {
2193     entry ** new_entries = new entry*[_length+1];
2194     for (i = 0; i < _length; i++) {
2195       new_entries[i] = _entries[i];
2196     }
2197     delete [] _entries;
2198     _entries = new_entries;
2199     _entries[_length] = new entry;
2200     _entries[_length]->set_key(key);
2201     _length++;
2202     return _entries[_length - 1];
2203   } else {
2204     return 0;
2205   }
2206 }
2207
2208 bool
2209 SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
2210 {
2211   for (int i = 0; i < _length; i++) {
2212     if (_entries[i]->get_value() == node) {
2213       delete _entries[i];
2214       for (++i; i < _length; i++) {
2215         _entries[i-1] = _entries[i];
2216       }
2217       _length--;
2218       return true;
2219     }
2220   }
2221   return false;
2222 }
2223
2224 void
2225 SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
2226 {
2227   for (int i = 0; i < _length; i++) {
2228     SGPropertyNode * node = _entries[i]->get_value();
2229     if (node)
2230       node->remove_linked_node(owner);
2231   }
2232 }
2233
2234 SGPropertyNode::hash_table::hash_table ()
2235   : _data_length(0),
2236     _data(0)
2237 {
2238 }
2239
2240 SGPropertyNode::hash_table::~hash_table ()
2241 {
2242   for (unsigned int i = 0; i < _data_length; i++) {
2243     if (_data[i]) {
2244       _data[i]->clear(this);
2245       delete _data[i];
2246     }
2247   }
2248   delete [] _data;
2249 }
2250
2251 SGPropertyNode *
2252 SGPropertyNode::hash_table::get (const char * key)
2253 {
2254   if (_data_length == 0)
2255     return 0;
2256   unsigned int index = hashcode(key) % _data_length;
2257   if (_data[index] == 0)
2258     return 0;
2259   entry * e = _data[index]->get_entry(key);
2260   if (e == 0)
2261     return 0;
2262   else
2263     return e->get_value();
2264 }
2265
2266 void
2267 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2268 {
2269   if (_data_length == 0) {
2270     _data = new bucket*[HASH_TABLE_SIZE];
2271     _data_length = HASH_TABLE_SIZE;
2272     for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2273       _data[i] = 0;
2274   }
2275   unsigned int index = hashcode(key) % _data_length;
2276   if (_data[index] == 0) {
2277     _data[index] = new bucket;
2278   }
2279   entry * e = _data[index]->get_entry(key, true);
2280   e->set_value(value);
2281   value->add_linked_node(this);
2282 }
2283
2284 bool
2285 SGPropertyNode::hash_table::erase (SGPropertyNode * node)
2286 {
2287   for (unsigned int i = 0; i < _data_length; i++)
2288     if (_data[i] && _data[i]->erase(node))
2289       return true;
2290
2291   return false;
2292 }
2293
2294 unsigned int
2295 SGPropertyNode::hash_table::hashcode (const char * key)
2296 {
2297   unsigned int hash = 0;
2298   while (*key != 0) {
2299     hash = 31 * hash + *key;
2300     key++;
2301   }
2302   return hash;
2303 }
2304
2305
2306 \f
2307 ////////////////////////////////////////////////////////////////////////
2308 // Implementation of SGPropertyChangeListener.
2309 ////////////////////////////////////////////////////////////////////////
2310
2311 SGPropertyChangeListener::~SGPropertyChangeListener ()
2312 {
2313   for (int i = _properties.size() - 1; i >= 0; i--)
2314     _properties[i]->removeChangeListener(this);
2315 }
2316
2317 void
2318 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2319 {
2320   // NO-OP
2321 }
2322
2323 void
2324 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2325                                       SGPropertyNode * child)
2326 {
2327   // NO-OP
2328 }
2329
2330 void
2331 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2332                                         SGPropertyNode * child)
2333 {
2334   // NO-OP
2335 }
2336
2337 void
2338 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2339 {
2340   _properties.push_back(node);
2341 }
2342
2343 void
2344 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2345 {
2346   vector<SGPropertyNode *>::iterator it =
2347     find(_properties.begin(), _properties.end(), node);
2348   if (it != _properties.end())
2349     _properties.erase(it);
2350 }
2351
2352 template<>
2353 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2354 {
2355     const SGVec3d vec
2356         = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2357     for (int i = 0; i < 3; ++i) {
2358         stream << vec[i];
2359         if (i < 2)
2360             stream << ' ';
2361     }
2362     return stream;
2363 }
2364
2365 namespace simgear
2366 {
2367 template<>
2368 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2369 {
2370     for (int i = 0; i < 3; ++i) {
2371         stream >> result[i];
2372     }
2373     return stream;
2374 }
2375 }
2376 template<>
2377 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2378 {
2379     const SGVec4d vec
2380         = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();    
2381     for (int i = 0; i < 4; ++i) {
2382         stream << vec[i];
2383         if (i < 3)
2384             stream << ' ';
2385     }
2386     return stream;
2387 }
2388
2389 namespace simgear
2390 {
2391 template<>
2392 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2393 {
2394     for (int i = 0; i < 4; ++i) {
2395         stream >> result[i];
2396     }
2397     return stream;
2398 }
2399
2400 namespace
2401 {
2402 bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
2403 {
2404     props::Type ltype = lhs.getType();
2405     props::Type rtype = rhs.getType();
2406     if (ltype != rtype)
2407         return false;
2408     switch (ltype) {
2409     case props::NONE:
2410         return true;
2411     case props::ALIAS:
2412         return false;           // XXX Should we look in aliases?
2413     case props::BOOL:
2414         return lhs.getValue<bool>() == rhs.getValue<bool>();
2415     case props::INT:
2416         return lhs.getValue<int>() == rhs.getValue<int>();
2417     case props::LONG:
2418         return lhs.getValue<long>() == rhs.getValue<long>();
2419     case props::FLOAT:
2420         return lhs.getValue<float>() == rhs.getValue<float>();
2421     case props::DOUBLE:
2422         return lhs.getValue<double>() == rhs.getValue<double>();
2423     case props::STRING:
2424     case props::UNSPECIFIED:
2425         return !strcmp(lhs.getStringValue(), rhs.getStringValue());
2426     case props::VEC3D:
2427         return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
2428     case props::VEC4D:
2429         return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
2430     default:
2431         return false;
2432     }
2433 }
2434 }
2435 }
2436
2437 bool SGPropertyNode::compare(const SGPropertyNode& lhs,
2438                              const SGPropertyNode& rhs)
2439 {
2440     if (&lhs == &rhs)
2441         return true;
2442     int lhsChildren = lhs.nChildren();
2443     int rhsChildren = rhs.nChildren();
2444     if (lhsChildren != rhsChildren)
2445         return false;
2446     if (lhsChildren == 0)
2447         return compareNodeValue(lhs, rhs);
2448     for (size_t i = 0; i < lhs._children.size(); ++i) {
2449         const SGPropertyNode* lchild = lhs._children[i];
2450         const SGPropertyNode* rchild = rhs._children[i];
2451         // I'm guessing that the nodes will usually be in the same
2452         // order.
2453         if (lchild->getIndex() != rchild->getIndex()
2454             || lchild->getNameString() != rchild->getNameString()) {
2455             rchild = 0;
2456             for (PropertyList::const_iterator itr = rhs._children.begin(),
2457                      end = rhs._children.end();
2458                  itr != end;
2459                 ++itr)
2460                 if (lchild->getIndex() == (*itr)->getIndex()
2461                     && lchild->getNameString() == (*itr)->getNameString()) {
2462                     rchild = *itr;
2463                     break;
2464                 }
2465             if (!rchild)
2466                 return false;
2467         }
2468         if (!compare(*lchild, *rchild))
2469             return false;
2470     }
2471     return true;
2472 }
2473
2474 struct PropertyPlaceLess {
2475     typedef bool result_type;
2476     bool operator()(SGPropertyNode_ptr lhs, SGPropertyNode_ptr rhs) const
2477     {
2478         int comp = lhs->getNameString().compare(rhs->getNameString());
2479         if (comp == 0)
2480             return lhs->getIndex() < rhs->getIndex();
2481         else
2482             return comp < 0;
2483     }
2484 };
2485
2486 size_t hash_value(const SGPropertyNode& node)
2487 {
2488     using namespace boost;
2489
2490     if (node.nChildren() == 0) {
2491         switch (node.getType()) {
2492         case props::NONE:
2493             return 0;
2494
2495         case props::BOOL:
2496             return hash_value(node.getValue<bool>());
2497         case props::INT:
2498             return hash_value(node.getValue<int>());
2499         case props::LONG:
2500             return hash_value(node.getValue<long>());
2501         case props::FLOAT:
2502             return hash_value(node.getValue<float>());
2503         case props::DOUBLE:
2504             return hash_value(node.getValue<double>());
2505         case props::STRING:
2506         case props::UNSPECIFIED:
2507         {
2508             const char *val = node.getStringValue();
2509             return hash_range(val, val + strlen(val));
2510         }
2511         case props::VEC3D:
2512         {
2513             const SGVec3d val = node.getValue<SGVec3d>();
2514             return hash_range(&val[0], &val[3]);
2515         }
2516         case props::VEC4D:
2517         {
2518             const SGVec4d val = node.getValue<SGVec4d>();
2519             return hash_range(&val[0], &val[4]);
2520         }
2521         case props::ALIAS:      // XXX Should we look in aliases?
2522         default:
2523             return 0;
2524         }
2525     } else {
2526         size_t seed = 0;
2527         PropertyList children(node._children.begin(), node._children.end());
2528         sort(children.begin(), children.end(), PropertyPlaceLess());
2529         for (PropertyList::const_iterator itr  = children.begin(),
2530                  end = children.end();
2531              itr != end;
2532              ++itr) {
2533             hash_combine(seed, (*itr)->_name);
2534             hash_combine(seed, (*itr)->_index);
2535             hash_combine(seed, hash_value(**itr));
2536         }
2537         return seed;
2538     }
2539 }
2540
2541 // end of props.cxx