]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
Updates from David Megginson:
[simgear.git] / simgear / misc / props.cxx
1 // props.cxx -- implementation of SimGear Property Manager.
2 //
3 // Written by David Megginson - david@megginson.com
4 //
5 // This module is in the PUBLIC DOMAIN.
6 //
7 // This program is distributed in the hope that it will be useful, but
8 // WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 //
11 // See props.html for documentation [replace with URL when available].
12 //
13 // $Id$
14
15 #ifdef HAVE_CONFIG_H
16 #  include <config.h>
17 #endif
18
19 #include <simgear/debug/logstream.hxx>
20
21 #include "props.hxx"
22
23 #include <stdlib.h>
24
25 #include <string>
26
27 using std::string;
28
29 SGPropertyList current_properties;
30
31 static string empty_string;
32
33
34 \f
35 ////////////////////////////////////////////////////////////////////////
36 // Implementation of SGValue.
37 ////////////////////////////////////////////////////////////////////////
38
39
40 /**
41  * Construct a new value.
42  */
43 SGValue::SGValue ()
44   : _type(UNKNOWN), _tied(false)
45 {
46 }
47
48
49 /**
50  * Destroy a value.
51  */
52 SGValue::~SGValue ()
53 {
54 }
55
56
57 /**
58  * Return a raw boolean value (no type coercion).
59  */
60 bool
61 SGValue::getRawBool () const
62 {
63   if (_tied) {
64     if (_value.bool_func.getter != 0)
65       return (*(_value.bool_func.getter))();
66     else
67       return false;
68   } else {
69     return _value.bool_val;
70   }
71 }
72
73
74 /**
75  * Return a raw integer value (no type coercion).
76  */
77 int
78 SGValue::getRawInt () const
79 {
80   if (_tied) {
81     if (_value.int_func.getter != 0)
82       return (*(_value.int_func.getter))();
83     else
84       return 0;
85   } else {
86     return _value.int_val;
87   }
88 }
89
90
91 /**
92  * Return a raw floating-point value (no type coercion).
93  */
94 float
95 SGValue::getRawFloat () const
96 {
97   if (_tied) {
98     if (_value.float_func.getter != 0)
99       return (*(_value.float_func.getter))();
100     else
101       return 0.0;
102   } else {
103     return _value.float_val;
104   }
105 }
106
107
108 /**
109  * Return a raw double-precision floating-point value (no type coercion).
110  */
111 double
112 SGValue::getRawDouble () const
113 {
114   if (_tied) {
115     if (_value.double_func.getter != 0)
116       return (*(_value.double_func.getter))();
117     else
118       return 0.0L;
119   } else {
120     return _value.double_val;
121   }
122 }
123
124
125 /**
126  * Return a raw string value (no type coercion).
127  */
128 const string &
129 SGValue::getRawString () const
130 {
131   if (_tied && _value.string_func.getter != 0)
132     return (*(_value.string_func.getter))();
133   else
134     return string_val;
135 }
136
137
138 /**
139  * Set a raw boolean value (no type coercion).
140  *
141  * Return false if the value could not be set, true otherwise.
142  */
143 bool
144 SGValue::setRawBool (bool value)
145 {
146   if (_tied) {
147     if (_value.bool_func.setter != 0) {
148       (*_value.bool_func.setter)(value);
149       return true;
150     } else {
151       return false;
152     }
153   } else {
154     _value.bool_val = value;
155     return true;
156   }
157 }
158
159
160 /**
161  * Set a raw integer value (no type coercion).
162  *
163  * Return false if the value could not be set, true otherwise.
164  */
165 bool
166 SGValue::setRawInt (int value)
167 {
168   if (_tied) {
169     if (_value.int_func.setter != 0) {
170       (*_value.int_func.setter)(value);
171       return true;
172     } else {
173       return false;
174     }
175   } else {
176     _value.int_val = value;
177     return true;
178   }
179 }
180
181
182 /**
183  * Set a raw floating-point value (no type coercion).
184  *
185  * Return false if the value could not be set, true otherwise.
186  */
187 bool
188 SGValue::setRawFloat (float value)
189 {
190   if (_tied) {
191     if (_value.float_func.setter != 0) {
192       (*_value.float_func.setter)(value);
193       return true;
194     } else {
195       return false;
196     }
197   } else {
198     _value.float_val = value;
199     return true;
200   }
201 }
202
203
204 /**
205  * Set a raw double-precision floating-point value (no type coercion).
206  *
207  * Return false if the value could not be set, true otherwise.
208  */
209 bool
210 SGValue::setRawDouble (double value)
211 {
212   if (_tied) {
213     if (_value.double_func.setter != 0) {
214       (*_value.double_func.setter)(value);
215       return true;
216     } else {
217       return false;
218     }
219   } else {
220     _value.double_val = value;
221     return true;
222   }
223 }
224
225
226 /**
227  * Set a raw string value (no type coercion).
228  *
229  * Return false if the value could not be set, true otherwise.
230  */
231 bool
232 SGValue::setRawString (const string &value)
233 {
234   if (_tied) {
235     if (_value.string_func.setter != 0) {
236       (*_value.string_func.setter)(value);
237       return true;
238     } else {
239       return false;
240     }
241   } else {
242     string_val = value;
243     return true;
244   }
245 }
246
247
248 /**
249  * Get the boolean value of a property.
250  *
251  * If the native type is not boolean, attempt to coerce it.
252  */
253 bool
254 SGValue::getBoolValue () const
255 {
256   switch (_type) {
257   case BOOL:
258     return getRawBool();
259   case INT:
260     return (getRawInt() == 0 ? false : true);
261   case FLOAT:
262     return (getRawFloat() == 0.0 ? false : true);
263   case DOUBLE:
264     return (getRawDouble() == 0.0 ? false : true);
265   case UNKNOWN:
266   case STRING:
267     return ((getRawString() == "true" || getIntValue() != 0) ? true : false);
268   }
269   return false;
270 }
271
272
273 /**
274  * Get the integer value of a property.
275  *
276  * If the native type is not integer, attempt to coerce it.
277  */
278 int
279 SGValue::getIntValue () const
280 {
281   switch (_type) {
282   case BOOL:
283     return getRawBool();
284   case INT:
285     return getRawInt();
286   case FLOAT:
287     return (int)(getRawFloat());
288   case DOUBLE:
289     return (int)(getRawDouble());
290   case UNKNOWN:
291   case STRING:
292     return atoi(getRawString().c_str());
293   }
294   return false;
295 }
296
297
298 /**
299  * Get the floating-point value of a property.
300  *
301  * If the native type is not float, attempt to coerce it.
302  */
303 float
304 SGValue::getFloatValue () const
305 {
306   switch (_type) {
307   case BOOL:
308     return (float)(getRawBool());
309   case INT:
310     return (float)(getRawInt());
311   case FLOAT:
312     return getRawFloat();
313   case DOUBLE:
314     return (float)(getRawDouble());
315   case UNKNOWN:
316   case STRING:
317     return (float)atof(getRawString().c_str());
318   }
319   return false;
320 }
321
322
323 /**
324  * Get the double-precision floating-point value of a property.
325  *
326  * If the native type is not double, attempt to coerce it.
327  */
328 double
329 SGValue::getDoubleValue () const
330 {
331   switch (_type) {
332   case BOOL:
333     return (double)(getRawBool());
334   case INT:
335     return (double)(getRawInt());
336   case FLOAT:
337     return (double)(getRawFloat());
338   case DOUBLE:
339     return getRawDouble();
340   case UNKNOWN:
341   case STRING:
342     return atof(getRawString().c_str());
343   }
344   return false;
345 }
346
347
348 /**
349  * Get the string value of a property.
350  *
351  * If the native type is not string, attempt to coerce it.
352  */
353 const string &
354 SGValue::getStringValue () const
355 {
356   char buf[512];
357   switch (_type) {
358   case BOOL:
359     if (getRawBool())
360       string_val = "true";
361     else
362       string_val = "false";
363     return string_val;
364   case INT:
365     sprintf(buf, "%d", getRawInt());
366     string_val = buf;
367     return string_val;
368   case FLOAT:
369     sprintf(buf, "%f", getRawFloat());
370     string_val = buf;
371     return string_val;
372   case DOUBLE:
373     sprintf(buf, "%f", getRawDouble());
374     string_val = buf;
375     return string_val;
376   case UNKNOWN:
377   case STRING:
378     return getRawString();
379   }
380   return empty_string;
381 }
382
383
384 /**
385  * Set the boolean value and change the type if unknown.
386  *
387  * Returns true on success.
388  */
389 bool
390 SGValue::setBoolValue (bool value)
391 {
392   if (_type == UNKNOWN)
393     _type = INT;
394   switch (_type) {
395   case BOOL:
396     return setRawBool(value);
397   case INT:
398     return setRawInt((int)value);
399   case FLOAT:
400     return setRawFloat((float)value);
401   case DOUBLE:
402     return setRawDouble((double)value);
403   case STRING:
404     if (value)
405       return setRawString("true");
406     else
407       return setRawString("false");
408   }
409   return false;
410 }
411
412
413 /**
414  * Set the integer value and change the type if unknown.
415  *
416  * Returns true on success.
417  */
418 bool
419 SGValue::setIntValue (int value)
420 {
421   if (_type == UNKNOWN)
422     _type = INT;
423   switch (_type) {
424   case BOOL:
425     if (value == 0)
426       return setRawBool(false);
427     else
428       return setRawBool(true);
429   case INT:
430     return setRawInt(value);
431   case FLOAT:
432     return setRawFloat((float)value);
433   case DOUBLE:
434     return setRawDouble((double)value);
435   case STRING:
436     char buf[128];
437     sprintf(buf, "%d", value);
438     return setRawString(buf);
439   }
440   return false;
441 }
442
443
444 /**
445  * Set the floating-point value and change the type if unknown.
446  *
447  * Returns true on success.
448  */
449 bool
450 SGValue::setFloatValue (float value)
451 {
452   if (_type == UNKNOWN)
453     _type = FLOAT;
454   switch (_type) {
455   case BOOL:
456     if (value == 0.0)
457       return setRawBool(false);
458     else
459       return setRawBool(true);
460   case INT:
461     return setRawInt((int)value);
462   case FLOAT:
463     return setRawFloat(value);
464   case DOUBLE:
465     return setRawDouble((double)value);
466   case STRING:
467     char buf[128];
468     sprintf(buf, "%f", value);
469     return setRawString(buf);
470   }
471   return false;
472 }
473
474
475 /**
476  * Set the double-precision value and change the type if unknown.
477  *
478  * Returns true on success.
479  */
480 bool
481 SGValue::setDoubleValue (double value)
482 {
483   if (_type == UNKNOWN)
484     _type = DOUBLE;
485   switch (_type) {
486   case BOOL:
487     if (value == 0.0L)
488       return setRawBool(false);
489     else
490       return setRawBool(true);
491   case INT:
492     return setRawInt((int)value);
493   case FLOAT:
494     return setRawFloat((float)value);
495   case DOUBLE:
496     return setRawDouble(value);
497   case STRING:
498     char buf[128];
499     sprintf(buf, "%lf", value);
500     return setRawString(buf);
501   }
502   return false;
503 }
504
505
506 /**
507  * Set the string value and change the type if unknown.
508  *
509  * Returns true on success.
510  */
511 bool
512 SGValue::setStringValue (const string &value)
513 {
514   if (_type == UNKNOWN)
515     _type = STRING;
516
517   switch (_type) {
518   case BOOL:
519     if (value == "true" || atoi(value.c_str()) != 0)
520       return setRawBool(true);
521     else
522       return setRawBool(false);
523   case INT:
524     return setRawInt(atoi(value.c_str()));
525   case FLOAT:
526     return setRawFloat(atof(value.c_str()));
527   case DOUBLE:
528     return setRawDouble(atof(value.c_str()));
529   case STRING:
530     return setRawString(value);
531   }
532   return false;
533 }
534
535
536 /**
537  * Set a string value and don't modify the type.
538  *
539  * Returns true on success.
540  */
541 bool
542 SGValue::setUnknownValue (const string &value)
543 {
544   switch (_type) {
545   case BOOL:
546     if (value == "true" || atoi(value.c_str()) != 0)
547       return setRawBool(true);
548     else
549       return setRawBool(false);
550   case INT:
551     return setRawInt(atoi(value.c_str()));
552   case FLOAT:
553     return setRawFloat(atof(value.c_str()));
554   case DOUBLE:
555     return setRawDouble(atof(value.c_str()));
556   case STRING:
557   case UNKNOWN:
558     return setRawString(value);
559   }
560   return false;
561 }
562
563
564 /**
565  * Tie a boolean value to external functions.
566  *
567  * If useDefault is true, attempt the assign the current value
568  * (if any) after tying the functions.
569  *
570  * Returns true on success (i.e. the value is not currently tied).
571  */
572 bool
573 SGValue::tieBool (bool_getter getter, bool_setter setter,
574                   bool useDefault)
575 {
576   if (_tied) {
577     return false;
578   } else {
579     if (useDefault && setter)
580       (*setter)(getBoolValue());
581     _tied = true;
582     _type = BOOL;
583     _value.bool_func.getter = getter;
584     _value.bool_func.setter = setter;
585     return true;
586   }
587 }
588
589
590 /**
591  * Tie an integer value to external functions.
592  *
593  * If useDefault is true, attempt the assign the current value
594  * (if any) after tying the functions.
595  *
596  * Returns true on success (i.e. the value is not currently tied).
597  */
598 bool
599 SGValue::tieInt (int_getter getter, int_setter setter,
600                  bool useDefault)
601 {
602   if (_tied) {
603     return false;
604   } else {
605     if (useDefault && setter)
606       (*setter)(getIntValue());
607     _tied = true;
608     _type = INT;
609     _value.int_func.getter = getter;
610     _value.int_func.setter = setter;
611     return true;
612   }
613 }
614
615
616 /**
617  * Tie a floating-point value to external functions.
618  *
619  * If useDefault is true, attempt the assign the current value
620  * (if any) after tying the functions.
621  *
622  * Returns true on success (i.e. the value is not currently tied).
623  */
624 bool
625 SGValue::tieFloat (float_getter getter, float_setter setter,
626                    bool useDefault)
627 {
628   if (_tied) {
629     return false;
630   } else {
631     if (useDefault && setter)
632       (*setter)(getFloatValue());
633     _tied = true;
634     _type = FLOAT;
635     _value.float_func.getter = getter;
636     _value.float_func.setter = setter;
637     return true;
638   }
639 }
640
641
642 /**
643  * Tie a double-precision floating-point value to external functions.
644  *
645  * If useDefault is true, attempt the assign the current value
646  * (if any) after tying the functions.
647  *
648  * Returns true on success (i.e. the value is not currently tied).
649  */
650 bool
651 SGValue::tieDouble (double_getter getter, double_setter setter,
652                     bool useDefault)
653 {
654   if (_tied) {
655     return false;
656   } else {
657     if (useDefault && setter)
658       (*setter)(getDoubleValue());
659     _tied = true;
660     _type = DOUBLE;
661     _value.double_func.getter = getter;
662     _value.double_func.setter = setter;
663     return true;
664   }
665 }
666
667
668 /**
669  * Tie a string value to external functions.
670  *
671  * If useDefault is true, attempt the assign the current value
672  * (if any) after tying the functions.
673  *
674  * Returns true on success (i.e. the value is not currently tied).
675  */
676 bool
677 SGValue::tieString (string_getter getter, string_setter setter,
678                     bool useDefault)
679 {
680   if (_tied) {
681     return false;
682   } else {
683     if (useDefault && setter)
684       (*setter)(getStringValue());
685     _tied = true;
686     _type = STRING;
687     _value.string_func.getter = getter;
688     _value.string_func.setter = setter;
689     return true;
690   }
691 }
692
693
694 /**
695  * Untie a value from external functions.
696  *
697  * Will always attempt to intialize the internal value from
698  * the getter before untying.
699  *
700  * Returns true on success (i.e. the value had been tied).
701  */
702 bool
703 SGValue::untie ()
704 {
705   if (!_tied)
706     return false;
707
708   switch (_type) {
709   case BOOL: {
710     bool value = getRawBool();
711     _tied = false;
712     setRawBool(value);
713     break;
714   }
715   case INT: {
716     int value = getRawInt();
717     _tied = false;
718     setRawInt(value);
719     break;
720   }
721   case FLOAT: {
722     float value = getRawFloat();
723     _tied = false;
724     setRawFloat(value);
725     break;
726   }
727   case DOUBLE: {
728     double value = getRawDouble();
729     _tied = false;
730     setRawDouble(value);
731     break;
732   }
733   case STRING: {
734     string value = getRawString();
735     _tied = false;
736     setRawString(value);
737     break;
738   }
739   }
740
741   return true;
742 }
743
744
745 \f
746 ////////////////////////////////////////////////////////////////////////
747 // Implementation of SGPropertyList.
748 ////////////////////////////////////////////////////////////////////////
749
750
751 /**
752  * Constructor.
753  */
754 SGPropertyList::SGPropertyList ()
755 {
756 }
757
758
759 /**
760  * Destructor.
761  */
762 SGPropertyList::~SGPropertyList ()
763 {
764 }
765
766
767 /**
768  * Return true if a value is present.
769  */
770 bool
771 SGPropertyList::hasValue (const string &name) const
772 {
773   const_iterator el = _props.find(name);
774   if (el == _props.end())
775     return false;
776   else
777     return true;
778 }
779
780
781 /**
782  * Look up the SGValue structure associated with a property.
783  *
784  * Run some basic validity checks on the property name: it must
785  * not be empty, must begin with '/', must never have two '//' in a row,
786  * and must not end with '/'.
787  */
788 SGValue *
789 SGPropertyList::getValue (const string &name, bool create)
790 {
791   const_iterator el = _props.find(name);
792   if (el == _props.end()) {
793     if (!create)
794       return 0;
795     else {
796       FG_LOG(FG_GENERAL, FG_INFO, "Creating new property '" << name << '\'');
797       if (name.size() == 0 ||
798           name[0] != '/' ||
799           name[name.size()-1] == '/' ||
800           name.find("//") != string::npos) {
801         FG_LOG(FG_GENERAL, FG_ALERT, "Illegal property name: '"
802                << name << '\'');
803         return 0;
804       }
805     }
806   }
807   return &(_props[name]);
808 }
809
810
811 /**
812  * Look up a const value (never created).
813  */
814 const SGValue *
815 SGPropertyList::getValue (const string &name) const
816 {
817   value_map::const_iterator el = _props.find(name);
818   if (el == _props.end())
819     return 0;
820   else
821     return &(el->second);
822 }
823
824
825 /**
826  * Extract a boolean from the value.
827  *
828  * Note that this is inefficient for use in a tight loop: it is
829  * better to get the SGValue and query it repeatedly.
830  */
831 bool
832 SGPropertyList::getBoolValue (const string &name, bool defaultValue) const
833 {
834   const SGValue * val = getValue(name);
835   if (val == 0)
836     return defaultValue;
837   else
838     return val->getBoolValue();
839 }
840
841
842 /**
843  * Extract an integer from the value.
844  *
845  * Note that this is inefficient for use in a tight loop: it is
846  * better to get the SGValue and query it repeatedly.
847  */
848 int
849 SGPropertyList::getIntValue (const string &name, int defaultValue) const
850 {
851   const SGValue * val = getValue(name);
852   if (val == 0)
853     return defaultValue;
854   else
855     return val->getIntValue();
856 }
857
858
859 /**
860  * Extract a float from the value.
861  *
862  * Note that this is inefficient for use in a tight loop: it is
863  * better to get the SGValue and query it repeatedly.
864  */
865 float
866 SGPropertyList::getFloatValue (const string &name, float defaultValue) const
867 {
868   const SGValue * val = getValue(name);
869   if (val == 0)
870     return defaultValue;
871   else
872     return val->getFloatValue();
873 }
874
875
876 /**
877  * Extract a double from the value.
878  *
879  * Note that this is inefficient for use in a tight loop: it is
880  * better to get the SGValue and query it repeatedly.
881  */
882 double
883 SGPropertyList::getDoubleValue (const string &name, double defaultValue) const
884 {
885   const SGValue * val = getValue(name);
886   if (val == 0)
887     return defaultValue;
888   else
889     return val->getDoubleValue();
890 }
891
892
893 /**
894  * Extract a string from the value.
895  *
896  * Note that this is inefficient for use in a tight loop: it is
897  * better to save the SGValue and query it repeatedly.
898  */
899 const string &
900 SGPropertyList::getStringValue (const string &name,
901                                 const string &defaultValue) const
902 {
903   const SGValue * val = getValue(name);
904   if (val == 0)
905     return defaultValue;
906   else
907     return val->getStringValue();
908 }
909
910
911 /**
912  * Assign a bool to the value and change the type if unknown.
913  *
914  * Note that this is inefficient for use in a tight loop: it is
915  * better to save the SGValue and modify it repeatedly.
916  *
917  * Returns true on success.
918  */
919 bool
920 SGPropertyList::setBoolValue (const string &name, bool value)
921 {
922   return getValue(name, true)->setBoolValue(value);
923 }
924
925
926 /**
927  * Assign an integer to the value and change the type if unknown.
928  *
929  * Note that this is inefficient for use in a tight loop: it is
930  * better to save the SGValue and modify it repeatedly.
931  *
932  * Returns true on success.
933  */
934 bool
935 SGPropertyList::setIntValue (const string &name, int value)
936 {
937   return getValue(name, true)->setIntValue(value);
938 }
939
940
941 /**
942  * Assign a float to the value and change the type if unknown.
943  *
944  * Note that this is inefficient for use in a tight loop: it is
945  * better to save the SGValue and modify it repeatedly.
946  *
947  * Returns true on success.
948  */
949 bool
950 SGPropertyList::setFloatValue (const string &name, float value)
951 {
952   return getValue(name, true)->setFloatValue(value);
953 }
954
955
956 /**
957  * Assign a double to the value and change the type if unknown.
958  *
959  * Note that this is inefficient for use in a tight loop: it is
960  * better to save the SGValue and modify it repeatedly.
961  *
962  * Returns true on success.
963  */
964 bool
965 SGPropertyList::setDoubleValue (const string &name, double value)
966 {
967   return getValue(name, true)->setDoubleValue(value);
968 }
969
970
971 /**
972  * Assign a string to the value and change the type if unknown.
973  *
974  * Note that this is inefficient for use in a tight loop: it is
975  * better to save the SGValue and modify it repeatedly.
976  *
977  * Returns true on success.
978  */
979 bool
980 SGPropertyList::setStringValue (const string &name, const string &value)
981 {
982   return getValue(name, true)->setStringValue(value);
983 }
984
985
986 /**
987  * Assign a string to the value, but don't change the type.
988  *
989  * Note that this is inefficient for use in a tight loop: it is
990  * better to save the SGValue and modify it repeatedly.
991  *
992  * Returns true on success.
993  */
994 bool
995 SGPropertyList::setUnknownValue (const string &name, const string &value)
996 {
997   return getValue(name, true)->setUnknownValue(value);
998 }
999
1000
1001 /**
1002  * Tie a boolean value to external functions.
1003  *
1004  * Invokes SGValue::tieBool
1005  */
1006 bool
1007 SGPropertyList::tieBool (const string &name, 
1008                          bool_getter getter,
1009                          bool_setter setter,
1010                          bool useDefault)
1011 {
1012   FG_LOG(FG_GENERAL, FG_INFO, "Tying bool property '" << name << '\'');
1013   useDefault = useDefault && hasValue(name);
1014   return getValue(name, true)->tieBool(getter, setter, useDefault);
1015 }
1016
1017
1018 /**
1019  * Tie an integer value to external functions.
1020  *
1021  * Invokes SGValue::tieInt
1022  */
1023 bool
1024 SGPropertyList::tieInt (const string &name, 
1025                         int_getter getter,
1026                         int_setter setter,
1027                         bool useDefault)
1028 {
1029   FG_LOG(FG_GENERAL, FG_INFO, "Tying int property '" << name << '\'');
1030   useDefault = useDefault && hasValue(name);
1031   return getValue(name, true)->tieInt(getter, setter, useDefault);
1032 }
1033
1034
1035 /**
1036  * Tie a float value to external functions.
1037  *
1038  * Invokes SGValue::tieFloat
1039  */
1040 bool
1041 SGPropertyList::tieFloat (const string &name, 
1042                           float_getter getter,
1043                           float_setter setter,
1044                           bool useDefault)
1045 {
1046   FG_LOG(FG_GENERAL, FG_INFO, "Tying float property '" << name << '\'');
1047   useDefault = useDefault && hasValue(name);
1048   return getValue(name, true)->tieFloat(getter, setter, useDefault);
1049 }
1050
1051
1052 /**
1053  * Tie a double value to external functions.
1054  *
1055  * Invokes SGValue::tieDouble
1056  */
1057 bool
1058 SGPropertyList::tieDouble (const string &name, 
1059                            double_getter getter,
1060                            double_setter setter,
1061                            bool useDefault)
1062 {
1063   FG_LOG(FG_GENERAL, FG_INFO, "Tying double property '" << name << '\'');
1064   useDefault = useDefault && hasValue(name);
1065   return getValue(name, true)->tieDouble(getter, setter, useDefault);
1066 }
1067
1068
1069 /**
1070  * Tie a string value to external functions.
1071  *
1072  * Invokes SGValue::tieString
1073  */
1074 bool
1075 SGPropertyList::tieString (const string &name, 
1076                            string_getter getter,
1077                            string_setter setter,
1078                            bool useDefault)
1079 {
1080   FG_LOG(FG_GENERAL, FG_INFO, "Tying string property '" << name << '\'');
1081   useDefault = useDefault && hasValue(name);
1082   return getValue(name, true)->tieString(getter, setter, useDefault);
1083 }
1084
1085
1086 /**
1087  * Untie a value from external functions.
1088  *
1089  * Invokes SGValue::untie
1090  */
1091 bool
1092 SGPropertyList::untie (const string &name)
1093 {
1094   FG_LOG(FG_GENERAL, FG_INFO, "Untying property '" << name << '\'');
1095   return getValue(name, true)->untie();
1096 }
1097
1098
1099 \f
1100 ////////////////////////////////////////////////////////////////////////
1101 // Implementation of SGPropertyNode.
1102 ////////////////////////////////////////////////////////////////////////
1103
1104
1105 /**
1106  * Extract the base name of the next level down from the parent.
1107  *
1108  * The parent must have a '/' appended.  Note that basename may
1109  * be modified even if the test fails.
1110  */
1111 static bool
1112 get_base (const string &parent, const string &child,
1113              string &basename)
1114 {
1115                                 // First, check that the parent name
1116                                 // is a prefix of the child name, and
1117                                 // extract the remainder
1118   if (child.find(parent) != 0)
1119     return false;
1120
1121   basename = child.substr(parent.size());
1122
1123   string::size_type pos = basename.find('/');
1124   if (pos != string::npos) {
1125     basename.resize(pos);
1126   }
1127
1128   if (basename.size() == 0)
1129     return false;
1130   else
1131     return true;
1132 }
1133
1134
1135 /**
1136  * Constructor.
1137  */
1138 SGPropertyNode::SGPropertyNode (const string &path,
1139                                 SGPropertyList * props)
1140   : _props(props), _node(0)
1141 {
1142   setPath(path);
1143 }
1144
1145
1146 /**
1147  * Destructor.
1148  */
1149 SGPropertyNode::~SGPropertyNode ()
1150 {
1151   delete _node;
1152   _node = 0;
1153 }
1154
1155
1156 /**
1157  * Set the path.
1158  *
1159  * Strip the trailing '/', if any.
1160  */
1161 void
1162 SGPropertyNode::setPath (const string &path)
1163 {
1164   _path = path;
1165
1166                                 // Chop the final '/', if present.
1167   if (_path.size() > 0 && _path[_path.size()-1] == '/')
1168     _path.resize(_path.size()-1);
1169 }
1170
1171
1172 /**
1173  * Return the local name of the property.
1174  *
1175  * The local name is just everything after the last slash.
1176  */
1177 const string &
1178 SGPropertyNode::getName () const
1179 {
1180   string::size_type pos = _path.rfind('/');
1181   if (pos != string::npos) {
1182     _name = _path.substr(pos+1);
1183     return _name;
1184   } else {
1185     return empty_string;
1186   }
1187 }
1188
1189
1190 /**
1191  * Return the number of children for the current node.
1192  */
1193 int
1194 SGPropertyNode::size () const
1195 {
1196   if (_props == 0)
1197     return 0;
1198
1199   int s = 0;
1200
1201   string base;
1202   string lastBase;
1203   string pattern = _path;
1204   pattern += '/';
1205
1206   SGPropertyList::const_iterator it = _props->begin();
1207   SGPropertyList::const_iterator end = _props->end();
1208   while (it != end) {
1209     if (get_base(pattern, it->first, base) && base != lastBase) {
1210       s++;
1211       lastBase = base;
1212     }
1213     it++;
1214   }
1215
1216   return s;
1217 }
1218
1219
1220 /**
1221  * Initialize a node to represent this node's parent.
1222  *
1223  * A return value of true means success; otherwise, the node supplied
1224  * is unmodified.
1225  */
1226 SGPropertyNode &
1227 SGPropertyNode::getParent () const
1228 {
1229   if (_node == 0)
1230     _node = new SGPropertyNode();
1231
1232   string::size_type pos = _path.rfind('/');
1233   if (pos != string::npos) {
1234     _node->setPropertyList(_props);
1235     _node->setPath(_path.substr(0, pos-1));
1236   }
1237   return *_node;
1238 }
1239
1240
1241 /**
1242  * Initialize a node to represent this node's nth child.
1243  *
1244  * A return value of true means success; otherwise, the node supplied
1245  * is unmodified.
1246  */
1247 SGPropertyNode &
1248 SGPropertyNode::getChild (int n) const
1249 {
1250   if (_node == 0)
1251     _node = new SGPropertyNode();
1252
1253   if (_props == 0)
1254     return *_node;
1255
1256   int s = 0;
1257   string base;
1258   string lastBase;
1259   string pattern = _path;
1260   pattern += '/';
1261
1262   SGPropertyList::const_iterator it = _props->begin();
1263   SGPropertyList::const_iterator end = _props->end();
1264   while (it != end) {
1265     if (get_base(pattern, it->first, base) && base != lastBase) {
1266       if (s == n) {
1267         _node->setPropertyList(_props);
1268         _node->setPath(_path + string("/") + base);
1269         return *_node;
1270       } else {
1271         s++;
1272         lastBase = base;
1273       }
1274     }
1275     it++;
1276   }
1277
1278   return *_node;
1279 }
1280
1281
1282 /**
1283  * Return a node for an arbitrary subpath.
1284  *
1285  * Never returns 0.
1286  */
1287 SGPropertyNode &
1288 SGPropertyNode::getSubNode (const string &subpath) const
1289 {
1290   if (_node == 0)
1291     _node = new SGPropertyNode();
1292
1293   _node->setPropertyList(_props);
1294   _node->setPath(_path + string("/") + subpath);
1295   return *_node;
1296 }
1297
1298
1299 /**
1300  * Test whether the specified subpath has a value.
1301  */
1302 bool
1303 SGPropertyNode::hasValue (const string &subpath) const
1304 {
1305   if (_props == 0)
1306     return false;
1307
1308   if (subpath.size() == 0)
1309     return _props->hasValue(_path);
1310   else
1311     return _props->hasValue(_path + string("/") + subpath);
1312 }
1313
1314
1315 /**
1316  * Return the value of the current node.
1317  *
1318  * Currently, this does a lookup each time, but we could cache the
1319  * value safely as long as it's non-zero.
1320  *
1321  * Note that this will not create the value if it doesn't already exist.
1322  */
1323 SGValue *
1324 SGPropertyNode::getValue (const string &subpath)
1325 {
1326   if (_props == 0)
1327     return 0;
1328
1329   if (subpath.size() == 0)
1330     return _props->getValue(_path);
1331   else
1332     return _props->getValue(_path + string("/") + subpath);
1333 }
1334
1335
1336 /**
1337  * Return a bool value.
1338  */
1339 bool
1340 SGPropertyNode::getBoolValue (const string &subpath, bool defaultValue) const
1341 {
1342   if (_props == 0)
1343     return defaultValue;
1344
1345   if (subpath == "")
1346     return _props->getBoolValue(_path, defaultValue);
1347   else
1348     return _props->getBoolValue(_path + string("/") + subpath,
1349                                 defaultValue);
1350 }
1351
1352
1353 /**
1354  * Return an int value.
1355  */
1356 int
1357 SGPropertyNode::getIntValue (const string &subpath, int defaultValue) const
1358 {
1359   if (_props == 0)
1360     return defaultValue;
1361
1362   if (subpath == "")
1363     return _props->getIntValue(_path, defaultValue);
1364   else
1365     return _props->getIntValue(_path + string("/") + subpath,
1366                                defaultValue);
1367 }
1368
1369
1370 /**
1371  * Return a float value.
1372  */
1373 float
1374 SGPropertyNode::getFloatValue (const string &subpath, float defaultValue) const
1375 {
1376   if (_props == 0)
1377     return defaultValue;
1378
1379   if (subpath == "")
1380     return _props->getFloatValue(_path, defaultValue);
1381   else
1382     return _props->getFloatValue(_path + string("/") + subpath,
1383                                  defaultValue);
1384 }
1385
1386
1387 /**
1388  * Return a double value.
1389  */
1390 double
1391 SGPropertyNode::getDoubleValue (const string &subpath,
1392                                 double defaultValue) const
1393 {
1394   if (_props == 0)
1395     return defaultValue;
1396
1397   if (subpath == "")
1398     return _props->getDoubleValue(_path, defaultValue);
1399   else
1400     return _props->getDoubleValue(_path + string("/") + subpath,
1401                                   defaultValue);
1402 }
1403
1404
1405 /**
1406  * Return a string value.
1407  */
1408 const string &
1409 SGPropertyNode::getStringValue (const string &subpath,
1410                                 const string &defaultValue) const
1411 {
1412   if (_props == 0)
1413     return defaultValue;
1414
1415   if (subpath == "")
1416     return _props->getStringValue(_path, defaultValue);
1417   else
1418     return _props->getStringValue(_path + string("/") + subpath,
1419                                   defaultValue);
1420 }
1421
1422
1423 // end of props.cxx