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