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() == "true" || getIntValue() != 0) ? true : false);
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)
396 return setRawBool(value);
398 return setRawInt((int)value);
400 return setRawFloat((float)value);
402 return setRawDouble((double)value);
405 return setRawString("true");
407 return setRawString("false");
414 * Set the integer value and change the type if unknown.
416 * Returns true on success.
419 SGValue::setIntValue (int value)
421 if (_type == UNKNOWN)
426 return setRawBool(false);
428 return setRawBool(true);
430 return setRawInt(value);
432 return setRawFloat((float)value);
434 return setRawDouble((double)value);
437 sprintf(buf, "%d", value);
438 return setRawString(buf);
445 * Set the floating-point value and change the type if unknown.
447 * Returns true on success.
450 SGValue::setFloatValue (float value)
452 if (_type == UNKNOWN)
457 return setRawBool(false);
459 return setRawBool(true);
461 return setRawInt((int)value);
463 return setRawFloat(value);
465 return setRawDouble((double)value);
468 sprintf(buf, "%f", value);
469 return setRawString(buf);
476 * Set the double-precision value and change the type if unknown.
478 * Returns true on success.
481 SGValue::setDoubleValue (double value)
483 if (_type == UNKNOWN)
488 return setRawBool(false);
490 return setRawBool(true);
492 return setRawInt((int)value);
494 return setRawFloat((float)value);
496 return setRawDouble(value);
499 sprintf(buf, "%lf", value);
500 return setRawString(buf);
507 * Set the string value and change the type if unknown.
509 * Returns true on success.
512 SGValue::setStringValue (const string &value)
514 if (_type == UNKNOWN)
519 if (value == "true" || atoi(value.c_str()) != 0)
520 return setRawBool(true);
522 return setRawBool(false);
524 return setRawInt(atoi(value.c_str()));
526 return setRawFloat(atof(value.c_str()));
528 return setRawDouble(atof(value.c_str()));
530 return setRawString(value);
537 * Set a string value and don't modify the type.
539 * Returns true on success.
542 SGValue::setUnknownValue (const string &value)
546 if (value == "true" || atoi(value.c_str()) != 0)
547 return setRawBool(true);
549 return setRawBool(false);
551 return setRawInt(atoi(value.c_str()));
553 return setRawFloat(atof(value.c_str()));
555 return setRawDouble(atof(value.c_str()));
558 return setRawString(value);
565 * Tie a boolean value to external functions.
567 * If useDefault is true, attempt the assign the current value
568 * (if any) after tying the functions.
570 * Returns true on success (i.e. the value is not currently tied).
573 SGValue::tieBool (bool_getter getter, bool_setter setter,
579 if (useDefault && setter)
580 (*setter)(getBoolValue());
583 _value.bool_func.getter = getter;
584 _value.bool_func.setter = setter;
591 * Tie an integer value to external functions.
593 * If useDefault is true, attempt the assign the current value
594 * (if any) after tying the functions.
596 * Returns true on success (i.e. the value is not currently tied).
599 SGValue::tieInt (int_getter getter, int_setter setter,
605 if (useDefault && setter)
606 (*setter)(getIntValue());
609 _value.int_func.getter = getter;
610 _value.int_func.setter = setter;
617 * Tie a floating-point value to external functions.
619 * If useDefault is true, attempt the assign the current value
620 * (if any) after tying the functions.
622 * Returns true on success (i.e. the value is not currently tied).
625 SGValue::tieFloat (float_getter getter, float_setter setter,
631 if (useDefault && setter)
632 (*setter)(getFloatValue());
635 _value.float_func.getter = getter;
636 _value.float_func.setter = setter;
643 * Tie a double-precision floating-point value to external functions.
645 * If useDefault is true, attempt the assign the current value
646 * (if any) after tying the functions.
648 * Returns true on success (i.e. the value is not currently tied).
651 SGValue::tieDouble (double_getter getter, double_setter setter,
657 if (useDefault && setter)
658 (*setter)(getDoubleValue());
661 _value.double_func.getter = getter;
662 _value.double_func.setter = setter;
669 * Tie a string value to external functions.
671 * If useDefault is true, attempt the assign the current value
672 * (if any) after tying the functions.
674 * Returns true on success (i.e. the value is not currently tied).
677 SGValue::tieString (string_getter getter, string_setter setter,
683 if (useDefault && setter)
684 (*setter)(getStringValue());
687 _value.string_func.getter = getter;
688 _value.string_func.setter = setter;
695 * Untie a value from external functions.
697 * Will always attempt to intialize the internal value from
698 * the getter before untying.
700 * Returns true on success (i.e. the value had been tied).
710 bool value = getRawBool();
716 int value = getRawInt();
722 float value = getRawFloat();
728 double value = getRawDouble();
734 string value = getRawString();
746 ////////////////////////////////////////////////////////////////////////
747 // Implementation of SGPropertyList.
748 ////////////////////////////////////////////////////////////////////////
754 SGPropertyList::SGPropertyList ()
762 SGPropertyList::~SGPropertyList ()
768 * Return true if a value is present.
771 SGPropertyList::hasValue (const string &name) const
773 const_iterator el = _props.find(name);
774 if (el == _props.end())
782 * Look up the SGValue structure associated with a property.
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 '/'.
789 SGPropertyList::getValue (const string &name, bool create)
791 const_iterator el = _props.find(name);
792 if (el == _props.end()) {
796 FG_LOG(FG_GENERAL, FG_DEBUG, "Creating new property '" << name << '\'');
797 if (name.size() == 0 ||
799 name[name.size()-1] == '/' ||
800 name.find("//") != string::npos) {
801 FG_LOG(FG_GENERAL, FG_ALERT, "Illegal property name: '"
807 return &(_props[name]);
812 * Look up a const value (never created).
815 SGPropertyList::getValue (const string &name) const
817 value_map::const_iterator el = _props.find(name);
818 if (el == _props.end())
821 return &(el->second);
826 * Extract a boolean from the value.
828 * Note that this is inefficient for use in a tight loop: it is
829 * better to get the SGValue and query it repeatedly.
832 SGPropertyList::getBoolValue (const string &name, bool defaultValue) const
834 const SGValue * val = getValue(name);
838 return val->getBoolValue();
843 * Extract an integer from the value.
845 * Note that this is inefficient for use in a tight loop: it is
846 * better to get the SGValue and query it repeatedly.
849 SGPropertyList::getIntValue (const string &name, int defaultValue) const
851 const SGValue * val = getValue(name);
855 return val->getIntValue();
860 * Extract a float from the value.
862 * Note that this is inefficient for use in a tight loop: it is
863 * better to get the SGValue and query it repeatedly.
866 SGPropertyList::getFloatValue (const string &name, float defaultValue) const
868 const SGValue * val = getValue(name);
872 return val->getFloatValue();
877 * Extract a double from the value.
879 * Note that this is inefficient for use in a tight loop: it is
880 * better to get the SGValue and query it repeatedly.
883 SGPropertyList::getDoubleValue (const string &name, double defaultValue) const
885 const SGValue * val = getValue(name);
889 return val->getDoubleValue();
894 * Extract a string from the value.
896 * Note that this is inefficient for use in a tight loop: it is
897 * better to save the SGValue and query it repeatedly.
900 SGPropertyList::getStringValue (const string &name,
901 const string &defaultValue) const
903 const SGValue * val = getValue(name);
907 return val->getStringValue();
912 * Assign a bool to the value and change the type if unknown.
914 * Note that this is inefficient for use in a tight loop: it is
915 * better to save the SGValue and modify it repeatedly.
917 * Returns true on success.
920 SGPropertyList::setBoolValue (const string &name, bool value)
922 return getValue(name, true)->setBoolValue(value);
927 * Assign an integer to the value and change the type if unknown.
929 * Note that this is inefficient for use in a tight loop: it is
930 * better to save the SGValue and modify it repeatedly.
932 * Returns true on success.
935 SGPropertyList::setIntValue (const string &name, int value)
937 return getValue(name, true)->setIntValue(value);
942 * Assign a float to the value and change the type if unknown.
944 * Note that this is inefficient for use in a tight loop: it is
945 * better to save the SGValue and modify it repeatedly.
947 * Returns true on success.
950 SGPropertyList::setFloatValue (const string &name, float value)
952 return getValue(name, true)->setFloatValue(value);
957 * Assign a double to the value and change the type if unknown.
959 * Note that this is inefficient for use in a tight loop: it is
960 * better to save the SGValue and modify it repeatedly.
962 * Returns true on success.
965 SGPropertyList::setDoubleValue (const string &name, double value)
967 return getValue(name, true)->setDoubleValue(value);
972 * Assign a string to the value and change the type if unknown.
974 * Note that this is inefficient for use in a tight loop: it is
975 * better to save the SGValue and modify it repeatedly.
977 * Returns true on success.
980 SGPropertyList::setStringValue (const string &name, const string &value)
982 return getValue(name, true)->setStringValue(value);
987 * Assign a string to the value, but don't change the type.
989 * Note that this is inefficient for use in a tight loop: it is
990 * better to save the SGValue and modify it repeatedly.
992 * Returns true on success.
995 SGPropertyList::setUnknownValue (const string &name, const string &value)
997 return getValue(name, true)->setUnknownValue(value);
1002 * Tie a boolean value to external functions.
1004 * Invokes SGValue::tieBool
1007 SGPropertyList::tieBool (const string &name,
1012 FG_LOG(FG_GENERAL, FG_DEBUG, "Tying bool property '" << name << '\'');
1013 useDefault = useDefault && hasValue(name);
1014 return getValue(name, true)->tieBool(getter, setter, useDefault);
1019 * Tie an integer value to external functions.
1021 * Invokes SGValue::tieInt
1024 SGPropertyList::tieInt (const string &name,
1029 FG_LOG(FG_GENERAL, FG_DEBUG, "Tying int property '" << name << '\'');
1030 useDefault = useDefault && hasValue(name);
1031 return getValue(name, true)->tieInt(getter, setter, useDefault);
1036 * Tie a float value to external functions.
1038 * Invokes SGValue::tieFloat
1041 SGPropertyList::tieFloat (const string &name,
1042 float_getter getter,
1043 float_setter setter,
1046 FG_LOG(FG_GENERAL, FG_DEBUG, "Tying float property '" << name << '\'');
1047 useDefault = useDefault && hasValue(name);
1048 return getValue(name, true)->tieFloat(getter, setter, useDefault);
1053 * Tie a double value to external functions.
1055 * Invokes SGValue::tieDouble
1058 SGPropertyList::tieDouble (const string &name,
1059 double_getter getter,
1060 double_setter setter,
1063 FG_LOG(FG_GENERAL, FG_DEBUG, "Tying double property '" << name << '\'');
1064 useDefault = useDefault && hasValue(name);
1065 return getValue(name, true)->tieDouble(getter, setter, useDefault);
1070 * Tie a string value to external functions.
1072 * Invokes SGValue::tieString
1075 SGPropertyList::tieString (const string &name,
1076 string_getter getter,
1077 string_setter setter,
1080 FG_LOG(FG_GENERAL, FG_DEBUG, "Tying string property '" << name << '\'');
1081 useDefault = useDefault && hasValue(name);
1082 return getValue(name, true)->tieString(getter, setter, useDefault);
1087 * Untie a value from external functions.
1089 * Invokes SGValue::untie
1092 SGPropertyList::untie (const string &name)
1094 FG_LOG(FG_GENERAL, FG_DEBUG, "Untying property '" << name << '\'');
1095 return getValue(name, true)->untie();
1100 ////////////////////////////////////////////////////////////////////////
1101 // Implementation of SGPropertyNode.
1102 ////////////////////////////////////////////////////////////////////////
1106 * Extract the base name of the next level down from the parent.
1108 * The parent must have a '/' appended. Note that basename may
1109 * be modified even if the test fails.
1112 get_base (const string &parent, const string &child,
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)
1121 basename = child.substr(parent.size());
1123 string::size_type pos = basename.find('/');
1124 if (pos != string::npos) {
1125 basename.resize(pos);
1128 if (basename.size() == 0)
1138 SGPropertyNode::SGPropertyNode (const string &path,
1139 SGPropertyList * props)
1140 : _props(props), _node(0)
1149 SGPropertyNode::~SGPropertyNode ()
1159 * Strip the trailing '/', if any.
1162 SGPropertyNode::setPath (const string &path)
1166 // Chop the final '/', if present.
1167 if (_path.size() > 0 && _path[_path.size()-1] == '/')
1168 _path.resize(_path.size()-1);
1173 * Return the local name of the property.
1175 * The local name is just everything after the last slash.
1178 SGPropertyNode::getName () const
1180 string::size_type pos = _path.rfind('/');
1181 if (pos != string::npos) {
1182 _name = _path.substr(pos+1);
1185 return empty_string;
1191 * Return the number of children for the current node.
1194 SGPropertyNode::size () const
1203 string pattern = _path;
1206 SGPropertyList::const_iterator it = _props->begin();
1207 SGPropertyList::const_iterator end = _props->end();
1209 if (get_base(pattern, it->first, base) && base != lastBase) {
1221 * Initialize a node to represent this node's parent.
1223 * A return value of true means success; otherwise, the node supplied
1227 SGPropertyNode::getParent () const
1230 _node = new SGPropertyNode();
1232 string::size_type pos = _path.rfind('/');
1233 if (pos != string::npos) {
1234 _node->setPropertyList(_props);
1235 _node->setPath(_path.substr(0, pos-1));
1242 * Initialize a node to represent this node's nth child.
1244 * A return value of true means success; otherwise, the node supplied
1248 SGPropertyNode::getChild (int n) const
1251 _node = new SGPropertyNode();
1259 string pattern = _path;
1262 SGPropertyList::const_iterator it = _props->begin();
1263 SGPropertyList::const_iterator end = _props->end();
1265 if (get_base(pattern, it->first, base) && base != lastBase) {
1267 _node->setPropertyList(_props);
1268 _node->setPath(_path + string("/") + base);
1283 * Return a node for an arbitrary subpath.
1288 SGPropertyNode::getSubNode (const string &subpath) const
1291 _node = new SGPropertyNode();
1293 _node->setPropertyList(_props);
1294 _node->setPath(_path + string("/") + subpath);
1300 * Test whether the specified subpath has a value.
1303 SGPropertyNode::hasValue (const string &subpath) const
1308 if (subpath.size() == 0)
1309 return _props->hasValue(_path);
1311 return _props->hasValue(_path + string("/") + subpath);
1316 * Return the value of the current node.
1318 * Currently, this does a lookup each time, but we could cache the
1319 * value safely as long as it's non-zero.
1321 * Note that this will not create the value if it doesn't already exist.
1324 SGPropertyNode::getValue (const string &subpath)
1329 if (subpath.size() == 0)
1330 return _props->getValue(_path);
1332 return _props->getValue(_path + string("/") + subpath);
1337 * Return a bool value.
1340 SGPropertyNode::getBoolValue (const string &subpath, bool defaultValue) const
1343 return defaultValue;
1346 return _props->getBoolValue(_path, defaultValue);
1348 return _props->getBoolValue(_path + string("/") + subpath,
1354 * Return an int value.
1357 SGPropertyNode::getIntValue (const string &subpath, int defaultValue) const
1360 return defaultValue;
1363 return _props->getIntValue(_path, defaultValue);
1365 return _props->getIntValue(_path + string("/") + subpath,
1371 * Return a float value.
1374 SGPropertyNode::getFloatValue (const string &subpath, float defaultValue) const
1377 return defaultValue;
1380 return _props->getFloatValue(_path, defaultValue);
1382 return _props->getFloatValue(_path + string("/") + subpath,
1388 * Return a double value.
1391 SGPropertyNode::getDoubleValue (const string &subpath,
1392 double defaultValue) const
1395 return defaultValue;
1398 return _props->getDoubleValue(_path, defaultValue);
1400 return _props->getDoubleValue(_path + string("/") + subpath,
1406 * Return a string value.
1409 SGPropertyNode::getStringValue (const string &subpath,
1410 const string &defaultValue) const
1413 return defaultValue;
1416 return _props->getStringValue(_path, defaultValue);
1418 return _props->getStringValue(_path + string("/") + subpath,