1 // props.cxx -- implementation of SimGear Property Manager.
3 // Written by David Megginson - david@megginson.com
5 // This module is in the PUBLIC DOMAIN.
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.
11 // See props.html for documentation [replace with URL when available].
19 #include <simgear/debug/logstream.hxx>
29 FGPropertyList current_properties;
31 static string empty_string;
35 ////////////////////////////////////////////////////////////////////////
36 // Implementation of FGValue.
37 ////////////////////////////////////////////////////////////////////////
41 * Construct a new value.
44 : _type(UNKNOWN), _tied(false)
58 * Return a raw boolean value (no type coercion).
61 FGValue::getRawBool () const
64 if (_value.bool_func.getter != 0)
65 return (*(_value.bool_func.getter))();
69 return _value.bool_val;
75 * Return a raw integer value (no type coercion).
78 FGValue::getRawInt () const
81 if (_value.int_func.getter != 0)
82 return (*(_value.int_func.getter))();
86 return _value.int_val;
92 * Return a raw floating-point value (no type coercion).
95 FGValue::getRawFloat () const
98 if (_value.float_func.getter != 0)
99 return (*(_value.float_func.getter))();
103 return _value.float_val;
109 * Return a raw double-precision floating-point value (no type coercion).
112 FGValue::getRawDouble () const
115 if (_value.double_func.getter != 0)
116 return (*(_value.double_func.getter))();
120 return _value.double_val;
126 * Return a raw string value (no type coercion).
129 FGValue::getRawString () const
131 if (_tied && _value.string_func.getter != 0)
132 return (*(_value.string_func.getter))();
139 * Set a raw boolean value (no type coercion).
141 * Return false if the value could not be set, true otherwise.
144 FGValue::setRawBool (bool value)
147 if (_value.bool_func.setter != 0) {
148 (*_value.bool_func.setter)(value);
154 _value.bool_val = value;
161 * Set a raw integer value (no type coercion).
163 * Return false if the value could not be set, true otherwise.
166 FGValue::setRawInt (int value)
169 if (_value.int_func.setter != 0) {
170 (*_value.int_func.setter)(value);
176 _value.int_val = value;
183 * Set a raw floating-point value (no type coercion).
185 * Return false if the value could not be set, true otherwise.
188 FGValue::setRawFloat (float value)
191 if (_value.float_func.setter != 0) {
192 (*_value.float_func.setter)(value);
198 _value.float_val = value;
205 * Set a raw double-precision floating-point value (no type coercion).
207 * Return false if the value could not be set, true otherwise.
210 FGValue::setRawDouble (double value)
213 if (_value.double_func.setter != 0) {
214 (*_value.double_func.setter)(value);
220 _value.double_val = value;
227 * Set a raw string value (no type coercion).
229 * Return false if the value could not be set, true otherwise.
232 FGValue::setRawString (const string &value)
235 if (_value.string_func.setter != 0) {
236 (*_value.string_func.setter)(value);
249 * Get the boolean value of a property.
251 * If the native type is not boolean, attempt to coerce it.
254 FGValue::getBoolValue () const
260 return (getRawInt() == 0 ? false : true);
262 return (getRawFloat() == 0.0 ? false : true);
264 return (getRawDouble() == 0.0 ? false : true);
267 return ((getRawString() == "false" || getIntValue() == 0) ? false : true);
274 * Get the integer value of a property.
276 * If the native type is not integer, attempt to coerce it.
279 FGValue::getIntValue () const
287 return (int)(getRawFloat());
289 return (int)(getRawDouble());
292 return atoi(getRawString().c_str());
299 * Get the floating-point value of a property.
301 * If the native type is not float, attempt to coerce it.
304 FGValue::getFloatValue () const
310 return (float)(getRawBool());
312 return (float)(getRawInt());
314 return getRawFloat();
316 return (float)(getRawDouble());
318 return (float)atof(getRawString().c_str());
325 * Get the double-precision floating-point value of a property.
327 * If the native type is not double, attempt to coerce it.
330 FGValue::getDoubleValue () const
336 return (double)(getRawBool());
338 return (double)(getRawInt());
340 return (double)(getRawFloat());
342 return getRawDouble();
344 return atof(getRawString().c_str());
351 * Get the string value of a property.
353 * If the native type is not string, attempt to coerce it.
356 FGValue::getStringValue () const
361 return getRawString();
366 string_val = "false";
369 sprintf(buf, "%d", getRawInt());
373 sprintf(buf, "%f", getRawFloat());
377 sprintf(buf, "%lf", getRawDouble());
381 return getRawString();
388 * Set the boolean value and change the type if unknown.
390 * Returns true on success.
393 FGValue::setBoolValue (bool value)
395 if (_type == UNKNOWN || _type == BOOL) {
397 return setRawBool(value);
405 * Set the integer value and change the type if unknown.
407 * Returns true on success.
410 FGValue::setIntValue (int value)
412 if (_type == UNKNOWN || _type == INT) {
414 return setRawInt(value);
422 * Set the floating-point value and change the type if unknown.
424 * Returns true on success.
427 FGValue::setFloatValue (float value)
429 if (_type == UNKNOWN || _type == FLOAT) {
431 return setRawFloat(value);
439 * Set the double-precision value and change the type if unknown.
441 * Returns true on success.
444 FGValue::setDoubleValue (double value)
446 if (_type == UNKNOWN || _type == DOUBLE) {
448 return setRawDouble(value);
456 * Set the string value and change the type if unknown.
458 * Returns true on success.
461 FGValue::setStringValue (const string &value)
463 if (_type == UNKNOWN || _type == STRING) {
465 return setRawString(value);
473 * Set a string value and don't modify the type.
475 * Returns true on success.
478 FGValue::setUnknownValue (const string &value)
480 if (_type == UNKNOWN || _type == STRING) {
481 return setRawString(value);
489 * Tie a boolean value to external functions.
491 * If useDefault is true, attempt the assign the current value
492 * (if any) after tying the functions.
494 * Returns true on success (i.e. the value is not currently tied).
497 FGValue::tieBool (bool_getter getter, bool_setter setter = 0,
498 bool useDefault = true)
503 if (useDefault && setter && _type != UNKNOWN)
504 (*setter)(getBoolValue());
507 _value.bool_func.getter = getter;
508 _value.bool_func.setter = setter;
515 * Tie an integer value to external functions.
517 * If useDefault is true, attempt the assign the current value
518 * (if any) after tying the functions.
520 * Returns true on success (i.e. the value is not currently tied).
523 FGValue::tieInt (int_getter getter, int_setter setter = 0,
524 bool useDefault = true)
529 if (useDefault && setter && _type != UNKNOWN)
530 (*setter)(getIntValue());
533 _value.int_func.getter = getter;
534 _value.int_func.setter = setter;
541 * Tie a floating-point value to external functions.
543 * If useDefault is true, attempt the assign the current value
544 * (if any) after tying the functions.
546 * Returns true on success (i.e. the value is not currently tied).
549 FGValue::tieFloat (float_getter getter, float_setter setter = 0,
550 bool useDefault = true)
555 if (useDefault && setter && _type != UNKNOWN)
556 (*setter)(getFloatValue());
559 _value.float_func.getter = getter;
560 _value.float_func.setter = setter;
567 * Tie a double-precision floating-point value to external functions.
569 * If useDefault is true, attempt the assign the current value
570 * (if any) after tying the functions.
572 * Returns true on success (i.e. the value is not currently tied).
575 FGValue::tieDouble (double_getter getter, double_setter setter = 0,
576 bool useDefault = true)
581 if (useDefault && setter && _type != UNKNOWN)
582 (*setter)(getDoubleValue());
585 _value.double_func.getter = getter;
586 _value.double_func.setter = setter;
593 * Tie a string value to external functions.
595 * If useDefault is true, attempt the assign the current value
596 * (if any) after tying the functions.
598 * Returns true on success (i.e. the value is not currently tied).
601 FGValue::tieString (string_getter getter, string_setter setter = 0,
602 bool useDefault = true)
607 if (useDefault && setter && _type != UNKNOWN)
608 (*setter)(getStringValue());
611 _value.string_func.getter = getter;
612 _value.string_func.setter = setter;
619 * Untie a value from external functions.
621 * Will always attempt to intialize the internal value from
622 * the getter before untying.
624 * Returns true on success (i.e. the value had been tied).
634 bool value = getRawBool();
640 int value = getRawInt();
646 float value = getRawFloat();
652 double value = getRawDouble();
658 string value = getRawString();
670 ////////////////////////////////////////////////////////////////////////
671 // Implementation of FGPropertyList.
672 ////////////////////////////////////////////////////////////////////////
678 FGPropertyList::FGPropertyList ()
686 FGPropertyList::~FGPropertyList ()
692 * Look up the FGValue structure associated with a property.
694 * Run some basic validity checks on the property name: it must
695 * not be empty, must begin with '/', must never have two '//' in a row,
696 * and must not end with '/'.
699 FGPropertyList::getValue (const string &name, bool create = false)
701 const_iterator el = _props.find(name);
702 if (el == _props.end()) {
706 FG_LOG(FG_GENERAL, FG_INFO, "Creating new property '" << name << '\'');
707 if (name.size() == 0 ||
709 name[name.size()-1] == '/' ||
710 name.find("//") != string::npos) {
711 FG_LOG(FG_GENERAL, FG_ALERT, "Illegal property name: '"
717 return &(_props[name]);
722 * Look up a const value (never created).
725 FGPropertyList::getValue (const string &name) const
727 value_map::const_iterator el = _props.find(name);
728 if (el == _props.end())
731 return &(el->second);
736 * Extract a boolean from the value.
738 * Note that this is inefficient for use in a tight loop: it is
739 * better to get the FGValue and query it repeatedly.
742 FGPropertyList::getBoolValue (const string &name) const
744 const FGValue * val = getValue(name);
748 return val->getBoolValue();
753 * Extract an integer from the value.
755 * Note that this is inefficient for use in a tight loop: it is
756 * better to get the FGValue and query it repeatedly.
759 FGPropertyList::getIntValue (const string &name) const
761 const FGValue * val = getValue(name);
765 return val->getIntValue();
770 * Extract a float from the value.
772 * Note that this is inefficient for use in a tight loop: it is
773 * better to get the FGValue and query it repeatedly.
776 FGPropertyList::getFloatValue (const string &name) const
778 const FGValue * val = getValue(name);
782 return val->getFloatValue();
787 * Extract a double from the value.
789 * Note that this is inefficient for use in a tight loop: it is
790 * better to get the FGValue and query it repeatedly.
793 FGPropertyList::getDoubleValue (const string &name) const
795 const FGValue * val = getValue(name);
799 return val->getDoubleValue();
804 * Extract a string from the value.
806 * Note that this is inefficient for use in a tight loop: it is
807 * better to save the FGValue and query it repeatedly.
810 FGPropertyList::getStringValue (const string &name) const
812 const FGValue * val = getValue(name);
816 return val->getStringValue();
821 * Assign a bool to the value and change the type if unknown.
823 * Note that this is inefficient for use in a tight loop: it is
824 * better to save the FGValue and modify it repeatedly.
826 * Returns true on success.
829 FGPropertyList::setBoolValue (const string &name, bool value)
831 return getValue(name, true)->setBoolValue(value);
836 * Assign an integer to the value and change the type if unknown.
838 * Note that this is inefficient for use in a tight loop: it is
839 * better to save the FGValue and modify it repeatedly.
841 * Returns true on success.
844 FGPropertyList::setIntValue (const string &name, int value)
846 return getValue(name, true)->setIntValue(value);
851 * Assign a float to the value and change the type if unknown.
853 * Note that this is inefficient for use in a tight loop: it is
854 * better to save the FGValue and modify it repeatedly.
856 * Returns true on success.
859 FGPropertyList::setFloatValue (const string &name, float value)
861 return getValue(name, true)->setFloatValue(value);
866 * Assign a double to the value and change the type if unknown.
868 * Note that this is inefficient for use in a tight loop: it is
869 * better to save the FGValue and modify it repeatedly.
871 * Returns true on success.
874 FGPropertyList::setDoubleValue (const string &name, double value)
876 return getValue(name, true)->setDoubleValue(value);
881 * Assign a string to the value and change the type if unknown.
883 * Note that this is inefficient for use in a tight loop: it is
884 * better to save the FGValue and modify it repeatedly.
886 * Returns true on success.
889 FGPropertyList::setStringValue (const string &name, const string &value)
891 return getValue(name, true)->setStringValue(value);
896 * Assign a string to the value, but don't change the type.
898 * Note that this is inefficient for use in a tight loop: it is
899 * better to save the FGValue and modify it repeatedly.
901 * Returns true on success.
904 FGPropertyList::setUnknownValue (const string &name, const string &value)
906 return getValue(name, true)->setUnknownValue(value);
911 * Tie a boolean value to external functions.
913 * Invokes FGValue::tieBool
916 FGPropertyList::tieBool (const string &name,
919 bool useDefault = true)
921 FG_LOG(FG_GENERAL, FG_INFO, "Tying bool property '" << name << '\'');
922 return getValue(name, true)->tieBool(getter, setter, useDefault);
927 * Tie an integer value to external functions.
929 * Invokes FGValue::tieInt
932 FGPropertyList::tieInt (const string &name,
935 bool useDefault = true)
937 FG_LOG(FG_GENERAL, FG_INFO, "Tying int property '" << name << '\'');
938 return getValue(name, true)->tieInt(getter, setter, useDefault);
943 * Tie a float value to external functions.
945 * Invokes FGValue::tieFloat
948 FGPropertyList::tieFloat (const string &name,
951 bool useDefault = true)
953 FG_LOG(FG_GENERAL, FG_INFO, "Tying float property '" << name << '\'');
954 return getValue(name, true)->tieFloat(getter, setter, useDefault);
959 * Tie a double value to external functions.
961 * Invokes FGValue::tieDouble
964 FGPropertyList::tieDouble (const string &name,
965 double_getter getter,
966 double_setter setter,
967 bool useDefault = true)
969 FG_LOG(FG_GENERAL, FG_INFO, "Tying double property '" << name << '\'');
970 return getValue(name, true)->tieDouble(getter, setter, useDefault);
975 * Tie a string value to external functions.
977 * Invokes FGValue::tieString
980 FGPropertyList::tieString (const string &name,
981 string_getter getter,
982 string_setter setter,
983 bool useDefault = true)
985 FG_LOG(FG_GENERAL, FG_INFO, "Tying string property '" << name << '\'');
986 return getValue(name, true)->tieString(getter, setter, useDefault);
991 * Untie a value from external functions.
993 * Invokes FGValue::untie
996 FGPropertyList::untie (const string &name)
998 FG_LOG(FG_GENERAL, FG_INFO, "Untying property '" << name << '\'');
999 return getValue(name, true)->untie();
1004 ////////////////////////////////////////////////////////////////////////
1005 // Implementation of FGPropertyNode.
1006 ////////////////////////////////////////////////////////////////////////
1010 * Extract the base name of the next level down from the parent.
1012 * The parent must have a '/' appended. Note that basename may
1013 * be modified even if the test fails.
1016 get_base (const string &parent, const string &child,
1019 // First, check that the parent name
1020 // is a prefix of the child name, and
1021 // extract the remainder
1022 if (child.find(parent) != 0)
1025 basename = child.substr(parent.size());
1027 int pos = basename.find('/');
1028 if (pos != string::npos) {
1029 basename.resize(pos);
1032 if (basename.size() == 0)
1042 FGPropertyNode::FGPropertyNode (const string &path = "",
1043 FGPropertyList * props = 0)
1053 FGPropertyNode::~FGPropertyNode ()
1061 * Strip the trailing '/', if any.
1064 FGPropertyNode::setPath (const string &path)
1068 // Chop the final '/', if present.
1069 if (_path.size() > 0 && _path[_path.size()-1] == '/')
1070 _path.resize(_path.size()-1);
1075 * Return the local name of the property.
1077 * The local name is just everything after the last slash.
1080 FGPropertyNode::getName () const
1082 int pos = _path.rfind('/');
1083 if (pos != string::npos) {
1084 _name = _path.substr(pos+1);
1087 return empty_string;
1093 * Return the value of the current node.
1095 * Currently, this does a lookup each time, but we could cache the
1096 * value safely as long as it's non-zero.
1098 * Note that this will not create the value if it doesn't already exist.
1101 FGPropertyNode::getValue ()
1103 if (_props == 0 || _path.size() == 0)
1106 return _props->getValue(_path);
1111 * Return the number of children for the current node.
1114 FGPropertyNode::size () const
1123 string pattern = _path;
1126 FGPropertyList::const_iterator it = _props->begin();
1127 FGPropertyList::const_iterator end = _props->end();
1129 if (get_base(pattern, it->first, base) && base != lastBase) {
1141 * Initialize a node to represent this node's parent.
1143 * A return value of true means success; otherwise, the node supplied
1147 FGPropertyNode::getParent (FGPropertyNode &parent) const
1149 int pos = _path.rfind('/');
1150 if (pos != string::npos) {
1151 parent.setPath(_path.substr(0, pos-1));
1152 parent.setPropertyList(_props);
1161 * Initialize a node to represent this node's nth child.
1163 * A return value of true means success; otherwise, the node supplied
1167 FGPropertyNode::getChild (FGPropertyNode &child, int n) const
1175 string pattern = _path;
1178 FGPropertyList::const_iterator it = _props->begin();
1179 FGPropertyList::const_iterator end = _props->end();
1181 if (get_base(pattern, it->first, base) && base != lastBase) {
1183 string path = _path;
1186 child.setPath(path);
1187 child.setPropertyList(_props);