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 SGPropertyList current_properties;
31 static string empty_string;
35 ////////////////////////////////////////////////////////////////////////
36 // Implementation of SGValue.
37 ////////////////////////////////////////////////////////////////////////
41 * Construct a new value.
44 : _type(UNKNOWN), _tied(false)
58 * Return a raw boolean value (no type coercion).
61 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::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 SGValue::getFloatValue () const
308 return (float)(getRawBool());
310 return (float)(getRawInt());
312 return getRawFloat();
314 return (float)(getRawDouble());
317 return (float)atof(getRawString().c_str());
324 * Get the double-precision floating-point value of a property.
326 * If the native type is not double, attempt to coerce it.
329 SGValue::getDoubleValue () const
333 return (double)(getRawBool());
335 return (double)(getRawInt());
337 return (double)(getRawFloat());
339 return getRawDouble();
342 return atof(getRawString().c_str());
349 * Get the string value of a property.
351 * If the native type is not string, attempt to coerce it.
354 SGValue::getStringValue () const
362 string_val = "false";
365 sprintf(buf, "%d", getRawInt());
369 sprintf(buf, "%f", getRawFloat());
373 sprintf(buf, "%f", getRawDouble());
378 return getRawString();
385 * Set the boolean value and change the type if unknown.
387 * Returns true on success.
390 SGValue::setBoolValue (bool value)
392 if (_type == UNKNOWN || _type == BOOL) {
394 return setRawBool(value);
402 * Set the integer value and change the type if unknown.
404 * Returns true on success.
407 SGValue::setIntValue (int value)
409 if (_type == UNKNOWN || _type == INT) {
411 return setRawInt(value);
419 * Set the floating-point value and change the type if unknown.
421 * Returns true on success.
424 SGValue::setFloatValue (float value)
426 if (_type == UNKNOWN || _type == FLOAT) {
428 return setRawFloat(value);
436 * Set the double-precision value and change the type if unknown.
438 * Returns true on success.
441 SGValue::setDoubleValue (double value)
443 if (_type == UNKNOWN || _type == DOUBLE) {
445 return setRawDouble(value);
453 * Set the string value and change the type if unknown.
455 * Returns true on success.
458 SGValue::setStringValue (const string &value)
460 if (_type == UNKNOWN || _type == STRING) {
462 return setRawString(value);
470 * Set a string value and don't modify the type.
472 * Returns true on success.
475 SGValue::setUnknownValue (const string &value)
477 if (_type == UNKNOWN || _type == STRING) {
478 return setRawString(value);
486 * Tie a boolean value to external functions.
488 * If useDefault is true, attempt the assign the current value
489 * (if any) after tying the functions.
491 * Returns true on success (i.e. the value is not currently tied).
494 SGValue::tieBool (bool_getter getter, bool_setter setter,
500 if (useDefault && setter && _type != UNKNOWN)
501 (*setter)(getBoolValue());
504 _value.bool_func.getter = getter;
505 _value.bool_func.setter = setter;
512 * Tie an integer value to external functions.
514 * If useDefault is true, attempt the assign the current value
515 * (if any) after tying the functions.
517 * Returns true on success (i.e. the value is not currently tied).
520 SGValue::tieInt (int_getter getter, int_setter setter,
526 if (useDefault && setter && _type != UNKNOWN)
527 (*setter)(getIntValue());
530 _value.int_func.getter = getter;
531 _value.int_func.setter = setter;
538 * Tie a floating-point value to external functions.
540 * If useDefault is true, attempt the assign the current value
541 * (if any) after tying the functions.
543 * Returns true on success (i.e. the value is not currently tied).
546 SGValue::tieFloat (float_getter getter, float_setter setter,
552 if (useDefault && setter && _type != UNKNOWN)
553 (*setter)(getFloatValue());
556 _value.float_func.getter = getter;
557 _value.float_func.setter = setter;
564 * Tie a double-precision floating-point value to external functions.
566 * If useDefault is true, attempt the assign the current value
567 * (if any) after tying the functions.
569 * Returns true on success (i.e. the value is not currently tied).
572 SGValue::tieDouble (double_getter getter, double_setter setter,
578 if (useDefault && setter && _type != UNKNOWN)
579 (*setter)(getDoubleValue());
582 _value.double_func.getter = getter;
583 _value.double_func.setter = setter;
590 * Tie a string value to external functions.
592 * If useDefault is true, attempt the assign the current value
593 * (if any) after tying the functions.
595 * Returns true on success (i.e. the value is not currently tied).
598 SGValue::tieString (string_getter getter, string_setter setter,
604 if (useDefault && setter && _type != UNKNOWN)
605 (*setter)(getStringValue());
608 _value.string_func.getter = getter;
609 _value.string_func.setter = setter;
616 * Untie a value from external functions.
618 * Will always attempt to intialize the internal value from
619 * the getter before untying.
621 * Returns true on success (i.e. the value had been tied).
631 bool value = getRawBool();
637 int value = getRawInt();
643 float value = getRawFloat();
649 double value = getRawDouble();
655 string value = getRawString();
667 ////////////////////////////////////////////////////////////////////////
668 // Implementation of SGPropertyList.
669 ////////////////////////////////////////////////////////////////////////
675 SGPropertyList::SGPropertyList ()
683 SGPropertyList::~SGPropertyList ()
689 * Look up the SGValue structure associated with a property.
691 * Run some basic validity checks on the property name: it must
692 * not be empty, must begin with '/', must never have two '//' in a row,
693 * and must not end with '/'.
696 SGPropertyList::getValue (const string &name, bool create)
698 const_iterator el = _props.find(name);
699 if (el == _props.end()) {
703 FG_LOG(FG_GENERAL, FG_INFO, "Creating new property '" << name << '\'');
704 if (name.size() == 0 ||
706 name[name.size()-1] == '/' ||
707 name.find("//") != string::npos) {
708 FG_LOG(FG_GENERAL, FG_ALERT, "Illegal property name: '"
714 return &(_props[name]);
719 * Look up a const value (never created).
722 SGPropertyList::getValue (const string &name) const
724 value_map::const_iterator el = _props.find(name);
725 if (el == _props.end())
728 return &(el->second);
733 * Extract a boolean from the value.
735 * Note that this is inefficient for use in a tight loop: it is
736 * better to get the SGValue and query it repeatedly.
739 SGPropertyList::getBoolValue (const string &name, bool defaultValue) const
741 const SGValue * val = getValue(name);
745 return val->getBoolValue();
750 * Extract an integer from the value.
752 * Note that this is inefficient for use in a tight loop: it is
753 * better to get the SGValue and query it repeatedly.
756 SGPropertyList::getIntValue (const string &name, int defaultValue) const
758 const SGValue * val = getValue(name);
762 return val->getIntValue();
767 * Extract a float from the value.
769 * Note that this is inefficient for use in a tight loop: it is
770 * better to get the SGValue and query it repeatedly.
773 SGPropertyList::getFloatValue (const string &name, float defaultValue) const
775 const SGValue * val = getValue(name);
779 return val->getFloatValue();
784 * Extract a double from the value.
786 * Note that this is inefficient for use in a tight loop: it is
787 * better to get the SGValue and query it repeatedly.
790 SGPropertyList::getDoubleValue (const string &name, double defaultValue) const
792 const SGValue * val = getValue(name);
796 return val->getDoubleValue();
801 * Extract a string from the value.
803 * Note that this is inefficient for use in a tight loop: it is
804 * better to save the SGValue and query it repeatedly.
807 SGPropertyList::getStringValue (const string &name,
808 const string &defaultValue) const
810 const SGValue * val = getValue(name);
814 return val->getStringValue();
819 * Assign a bool to the value and change the type if unknown.
821 * Note that this is inefficient for use in a tight loop: it is
822 * better to save the SGValue and modify it repeatedly.
824 * Returns true on success.
827 SGPropertyList::setBoolValue (const string &name, bool value)
829 return getValue(name, true)->setBoolValue(value);
834 * Assign an integer to the value and change the type if unknown.
836 * Note that this is inefficient for use in a tight loop: it is
837 * better to save the SGValue and modify it repeatedly.
839 * Returns true on success.
842 SGPropertyList::setIntValue (const string &name, int value)
844 return getValue(name, true)->setIntValue(value);
849 * Assign a float to the value and change the type if unknown.
851 * Note that this is inefficient for use in a tight loop: it is
852 * better to save the SGValue and modify it repeatedly.
854 * Returns true on success.
857 SGPropertyList::setFloatValue (const string &name, float value)
859 return getValue(name, true)->setFloatValue(value);
864 * Assign a double to the value and change the type if unknown.
866 * Note that this is inefficient for use in a tight loop: it is
867 * better to save the SGValue and modify it repeatedly.
869 * Returns true on success.
872 SGPropertyList::setDoubleValue (const string &name, double value)
874 return getValue(name, true)->setDoubleValue(value);
879 * Assign a string to the value and change the type if unknown.
881 * Note that this is inefficient for use in a tight loop: it is
882 * better to save the SGValue and modify it repeatedly.
884 * Returns true on success.
887 SGPropertyList::setStringValue (const string &name, const string &value)
889 return getValue(name, true)->setStringValue(value);
894 * Assign a string to the value, but don't change the type.
896 * Note that this is inefficient for use in a tight loop: it is
897 * better to save the SGValue and modify it repeatedly.
899 * Returns true on success.
902 SGPropertyList::setUnknownValue (const string &name, const string &value)
904 return getValue(name, true)->setUnknownValue(value);
909 * Tie a boolean value to external functions.
911 * Invokes SGValue::tieBool
914 SGPropertyList::tieBool (const string &name,
919 FG_LOG(FG_GENERAL, FG_INFO, "Tying bool property '" << name << '\'');
920 return getValue(name, true)->tieBool(getter, setter, useDefault);
925 * Tie an integer value to external functions.
927 * Invokes SGValue::tieInt
930 SGPropertyList::tieInt (const string &name,
935 FG_LOG(FG_GENERAL, FG_INFO, "Tying int property '" << name << '\'');
936 return getValue(name, true)->tieInt(getter, setter, useDefault);
941 * Tie a float value to external functions.
943 * Invokes SGValue::tieFloat
946 SGPropertyList::tieFloat (const string &name,
951 FG_LOG(FG_GENERAL, FG_INFO, "Tying float property '" << name << '\'');
952 return getValue(name, true)->tieFloat(getter, setter, useDefault);
957 * Tie a double value to external functions.
959 * Invokes SGValue::tieDouble
962 SGPropertyList::tieDouble (const string &name,
963 double_getter getter,
964 double_setter setter,
967 FG_LOG(FG_GENERAL, FG_INFO, "Tying double property '" << name << '\'');
968 return getValue(name, true)->tieDouble(getter, setter, useDefault);
973 * Tie a string value to external functions.
975 * Invokes SGValue::tieString
978 SGPropertyList::tieString (const string &name,
979 string_getter getter,
980 string_setter setter,
983 FG_LOG(FG_GENERAL, FG_INFO, "Tying string property '" << name << '\'');
984 return getValue(name, true)->tieString(getter, setter, useDefault);
989 * Untie a value from external functions.
991 * Invokes SGValue::untie
994 SGPropertyList::untie (const string &name)
996 FG_LOG(FG_GENERAL, FG_INFO, "Untying property '" << name << '\'');
997 return getValue(name, true)->untie();
1002 ////////////////////////////////////////////////////////////////////////
1003 // Implementation of SGPropertyNode.
1004 ////////////////////////////////////////////////////////////////////////
1008 * Extract the base name of the next level down from the parent.
1010 * The parent must have a '/' appended. Note that basename may
1011 * be modified even if the test fails.
1014 get_base (const string &parent, const string &child,
1017 // First, check that the parent name
1018 // is a prefix of the child name, and
1019 // extract the remainder
1020 if (child.find(parent) != 0)
1023 basename = child.substr(parent.size());
1025 string::size_type pos = basename.find('/');
1026 if (pos != string::npos) {
1027 basename.resize(pos);
1030 if (basename.size() == 0)
1040 SGPropertyNode::SGPropertyNode (const string &path,
1041 SGPropertyList * props)
1042 : _props(props), _node(0)
1051 SGPropertyNode::~SGPropertyNode ()
1061 * Strip the trailing '/', if any.
1064 SGPropertyNode::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 SGPropertyNode::getName () const
1082 string::size_type pos = _path.rfind('/');
1083 if (pos != string::npos) {
1084 _name = _path.substr(pos+1);
1087 return empty_string;
1093 * Return the number of children for the current node.
1096 SGPropertyNode::size () const
1105 string pattern = _path;
1108 SGPropertyList::const_iterator it = _props->begin();
1109 SGPropertyList::const_iterator end = _props->end();
1111 if (get_base(pattern, it->first, base) && base != lastBase) {
1123 * Initialize a node to represent this node's parent.
1125 * A return value of true means success; otherwise, the node supplied
1129 SGPropertyNode::getParent () const
1132 _node = new SGPropertyNode();
1134 string::size_type pos = _path.rfind('/');
1135 if (pos != string::npos) {
1136 _node->setPropertyList(_props);
1137 _node->setPath(_path.substr(0, pos-1));
1144 * Initialize a node to represent this node's nth child.
1146 * A return value of true means success; otherwise, the node supplied
1150 SGPropertyNode::getChild (int n) const
1153 _node = new SGPropertyNode();
1161 string pattern = _path;
1164 SGPropertyList::const_iterator it = _props->begin();
1165 SGPropertyList::const_iterator end = _props->end();
1167 if (get_base(pattern, it->first, base) && base != lastBase) {
1169 _node->setPropertyList(_props);
1170 _node->setPath(_path + string("/") + base);
1185 * Return a node for an arbitrary subpath.
1190 SGPropertyNode::getSubNode (const string &subpath) const
1193 _node = new SGPropertyNode();
1195 _node->setPropertyList(_props);
1196 _node->setPath(_path + string("/") + subpath);
1202 * Return the value of the current node.
1204 * Currently, this does a lookup each time, but we could cache the
1205 * value safely as long as it's non-zero.
1207 * Note that this will not create the value if it doesn't already exist.
1210 SGPropertyNode::getValue (const string &subpath)
1215 if (subpath.size() == 0)
1216 return _props->getValue(_path);
1218 return _props->getValue(_path + string("/") + subpath);
1223 * Return a bool value.
1226 SGPropertyNode::getBoolValue (const string &subpath, bool defaultValue) const
1229 return defaultValue;
1232 return _props->getBoolValue(_path, defaultValue);
1234 return _props->getBoolValue(_path + string("/") + subpath,
1240 * Return an int value.
1243 SGPropertyNode::getIntValue (const string &subpath, int defaultValue) const
1246 return defaultValue;
1249 return _props->getIntValue(_path, defaultValue);
1251 return _props->getIntValue(_path + string("/") + subpath,
1257 * Return a float value.
1260 SGPropertyNode::getFloatValue (const string &subpath, float defaultValue) const
1263 return defaultValue;
1266 return _props->getFloatValue(_path, defaultValue);
1268 return _props->getFloatValue(_path + string("/") + subpath,
1274 * Return a double value.
1277 SGPropertyNode::getDoubleValue (const string &subpath,
1278 double defaultValue) const
1281 return defaultValue;
1284 return _props->getDoubleValue(_path, defaultValue);
1286 return _props->getDoubleValue(_path + string("/") + subpath,
1292 * Return a string value.
1295 SGPropertyNode::getStringValue (const string &subpath,
1296 const string &defaultValue) const
1299 return defaultValue;
1302 return _props->getStringValue(_path, defaultValue);
1304 return _props->getStringValue(_path + string("/") + subpath,