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