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