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