1 // props.cxx - implementation of a property list.
2 // Started Fall 2000 by David Megginson, david@megginson.com
3 // This code is released into the Public Domain.
5 // See props.html for documentation [replace with URL when available].
9 #include <simgear/compiler.h>
10 #include <simgear/debug/logstream.hxx>
22 ////////////////////////////////////////////////////////////////////////
24 ////////////////////////////////////////////////////////////////////////
27 * Comparator class for sorting by index.
32 int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
33 return (n1->getIndex() < n2->getIndex());
39 ////////////////////////////////////////////////////////////////////////
40 // Convenience macros for value access.
41 ////////////////////////////////////////////////////////////////////////
43 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
44 #define TEST_WRITE if (!getAttribute(WRITE)) return false
48 ////////////////////////////////////////////////////////////////////////
49 // Default values for every type.
50 ////////////////////////////////////////////////////////////////////////
52 const bool SGRawValue<bool>::DefaultValue = false;
53 const int SGRawValue<int>::DefaultValue = 0;
54 const long SGRawValue<long>::DefaultValue = 0L;
55 const float SGRawValue<float>::DefaultValue = 0.0;
56 const double SGRawValue<double>::DefaultValue = 0.0L;
57 const string SGRawValue<string>::DefaultValue = "";
61 ////////////////////////////////////////////////////////////////////////
62 // Local path normalization code.
63 ////////////////////////////////////////////////////////////////////////
66 * A component in a path.
75 * Parse the name for a path component.
77 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
80 parse_name (const string &path, int &i)
83 int max = path.size();
87 if (i < max && path[i] == '.') {
93 if (i < max && path[i] != '/')
94 throw string(string("Illegal character after ") + name);
97 else if (isalpha(path[i]) || path[i] == '_') {
101 // The rules inside a name are a little
104 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
105 path[i] == '-' || path[i] == '.') {
107 } else if (path[i] == '[' || path[i] == '/') {
110 throw string("name may contain only ._- and alphanumeric characters");
117 if (name.size() == 0)
118 throw string("name must begin with alpha or '_'");
126 * Parse the optional integer index for a path component.
128 * Index: "[" [0-9]+ "]"
131 parse_index (const string &path, int &i)
140 for (int max = path.size(); i < max; i++) {
141 if (isdigit(path[i])) {
142 index = (index * 10) + (path[i] - '0');
143 } else if (path[i] == ']') {
151 throw string("unterminated index (looking for ']')");
156 * Parse a single path component.
158 * Component: Name Index?
160 static inline PathComponent
161 parse_component (const string &path, int &i)
163 PathComponent component;
164 component.name = parse_name(path, i);
165 if (component.name[0] != '.')
166 component.index = parse_index(path, i);
168 component.index = -1;
174 * Parse a path into its components.
177 parse_path (const string &path, vector<PathComponent> &components)
180 int max = path.size();
182 // Check for initial '/'
183 if (path[pos] == '/') {
187 components.push_back(root);
189 while (pos < max && path[pos] == '/')
194 components.push_back(parse_component(path, pos));
195 while (pos < max && path[pos] == '/')
202 ////////////////////////////////////////////////////////////////////////
203 // Other static utility functions.
204 ////////////////////////////////////////////////////////////////////////
208 * Locate a child node by name and index.
211 find_child (const string &name, int index, vector<SGPropertyNode *> nodes)
213 int nNodes = nodes.size();
214 for (int i = 0; i < nNodes; i++) {
215 SGPropertyNode * node = nodes[i];
216 if (node->getName() == name && node->getIndex() == index)
224 * Locate another node, given a relative path.
226 static SGPropertyNode *
227 find_node (SGPropertyNode * current,
228 const vector<PathComponent> &components,
232 // Run off the end of the list
237 // Success! This is the one we want.
238 else if (position >= (int)components.size()) {
242 // Empty component means root.
243 else if (components[position].name == "") {
244 return find_node(current->getRootNode(), components, position + 1, create);
247 // . means current directory
248 else if (components[position].name == ".") {
249 return find_node(current, components, position + 1, create);
252 // .. means parent directory
253 else if (components[position].name == "..") {
254 SGPropertyNode * parent = current->getParent();
256 throw string("Attempt to move past root with '..'");
258 return find_node(parent, components, position + 1, create);
261 // Otherwise, a child name
263 SGPropertyNode * child =
264 current->getChild(components[position].name,
265 components[position].index,
267 return find_node(child, components, position + 1, create);
273 ////////////////////////////////////////////////////////////////////////
274 // Private methods from SGPropertyNode (may be inlined for speed).
275 ////////////////////////////////////////////////////////////////////////
278 SGPropertyNode::get_bool () const
281 return _value.bool_val->getValue();
283 return _local_val.bool_val;
287 SGPropertyNode::get_int () const
290 return _value.int_val->getValue();
292 return _local_val.int_val;
296 SGPropertyNode::get_long () const
299 return _value.long_val->getValue();
301 return _local_val.long_val;
305 SGPropertyNode::get_float () const
308 return _value.float_val->getValue();
310 return _local_val.float_val;
314 SGPropertyNode::get_double () const
317 return _value.double_val->getValue();
319 return _local_val.double_val;
323 SGPropertyNode::get_string () const
326 return _value.string_val->getValue();
328 return *(_local_val.string_val);
332 SGPropertyNode::set_bool (bool val)
335 return _value.bool_val->setValue(val);
337 _local_val.bool_val = val;
343 SGPropertyNode::set_int (int val)
346 return _value.int_val->setValue(val);
348 _local_val.int_val = val;
354 SGPropertyNode::set_long (long val)
357 return _value.long_val->setValue(val);
359 _local_val.long_val = val;
365 SGPropertyNode::set_float (float val)
368 return _value.float_val->setValue(val);
370 _local_val.float_val = val;
376 SGPropertyNode::set_double (double val)
379 return _value.double_val->setValue(val);
381 _local_val.double_val = val;
387 SGPropertyNode::set_string (const string &val)
390 return _value.string_val->setValue(val);
392 (*_local_val.string_val) = val;
398 SGPropertyNode::clear_value ()
406 delete _value.bool_val;
408 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
411 delete _value.int_val;
413 _local_val.int_val = SGRawValue<int>::DefaultValue;
416 delete _value.long_val;
417 _value.long_val = 0L;
418 _local_val.long_val = SGRawValue<long>::DefaultValue;
421 delete _value.float_val;
422 _value.float_val = 0;
423 _local_val.float_val = SGRawValue<float>::DefaultValue;
426 delete _value.double_val;
427 _value.double_val = 0;
428 _local_val.double_val = SGRawValue<double>::DefaultValue;
432 delete _value.string_val;
433 _value.string_val = 0;
434 delete _local_val.string_val;
435 _local_val.string_val = 0;
444 * Get the value as a string.
447 SGPropertyNode::make_string () const
449 if (!getAttribute(READ))
455 return _value.alias->getStringValue();
462 sprintf(buf, "%d", get_int());
465 sprintf(buf, "%ld", get_long());
468 sprintf(buf, "%f", get_float());
471 sprintf(buf, "%f", get_double());
483 * Trace a write access for a property.
486 SGPropertyNode::trace_write () const
488 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
489 << ", value\"" << make_string() << '"');
493 * Trace a read access for a property.
496 SGPropertyNode::trace_read () const
498 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
499 << ", value \"" << make_string() << '"');
504 ////////////////////////////////////////////////////////////////////////
505 // Public methods from SGPropertyNode.
506 ////////////////////////////////////////////////////////////////////////
509 * Default constructor: always creates a root node.
511 SGPropertyNode::SGPropertyNode ()
526 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
529 _parent(0), // don't copy the parent
539 _value.alias = node._value.alias;
545 _value.bool_val = node._value.bool_val->clone();
548 set_bool(node.get_bool());
554 _value.int_val = node._value.int_val->clone();
557 set_int(node.get_int());
563 _value.long_val = node._value.long_val->clone();
566 set_long(node.get_long());
572 _value.float_val = node._value.float_val->clone();
575 set_float(node.get_float());
581 _value.double_val = node._value.double_val->clone();
584 set_double(node.get_double());
591 _value.string_val = node._value.string_val->clone();
594 _local_val.string_val = new string;
595 set_string(node.get_string());
603 * Convenience constructor.
605 SGPropertyNode::SGPropertyNode (const string &name,
606 int index, SGPropertyNode * parent)
621 SGPropertyNode::~SGPropertyNode ()
623 for (int i = 0; i < (int)_children.size(); i++) {
632 * Alias to another node.
635 SGPropertyNode::alias (SGPropertyNode * target)
637 if (target == 0 || _type == ALIAS || _tied)
640 _value.alias = target;
647 * Alias to another node by path.
650 SGPropertyNode::alias (const string &path)
652 return alias(getNode(path, true));
660 SGPropertyNode::unalias ()
671 * Get the target of an alias.
674 SGPropertyNode::getAliasTarget ()
676 return (_type == ALIAS ? _value.alias : 0);
680 const SGPropertyNode *
681 SGPropertyNode::getAliasTarget () const
683 return (_type == ALIAS ? _value.alias : 0);
688 * Get a non-const child by index.
691 SGPropertyNode::getChild (int position)
693 if (position >= 0 && position < nChildren())
694 return _children[position];
701 * Get a const child by index.
703 const SGPropertyNode *
704 SGPropertyNode::getChild (int position) const
706 if (position >= 0 && position < nChildren())
707 return _children[position];
714 * Get a non-const child by name and index, creating if necessary.
717 SGPropertyNode::getChild (const string &name, int index, bool create)
719 int pos = find_child(name, index, _children);
721 return _children[pos];
723 _children.push_back(new SGPropertyNode(name, index, this));
724 return _children[_children.size()-1];
732 * Get a const child by name and index.
734 const SGPropertyNode *
735 SGPropertyNode::getChild (const string &name, int index) const
737 int pos = find_child(name, index, _children);
739 return _children[pos];
746 * Get all children with the same name (but different indices).
748 vector<SGPropertyNode *>
749 SGPropertyNode::getChildren (const string &name)
751 vector<SGPropertyNode *> children;
752 int max = _children.size();
754 for (int i = 0; i < max; i++)
755 if (_children[i]->getName() == name)
756 children.push_back(_children[i]);
758 sort(children.begin(), children.end(), CompareIndices());
764 * Get all children const with the same name (but different indices).
766 vector<const SGPropertyNode *>
767 SGPropertyNode::getChildren (const string &name) const
769 vector<const SGPropertyNode *> children;
770 int max = _children.size();
772 for (int i = 0; i < max; i++)
773 if (_children[i]->getName() == name)
774 children.push_back(_children[i]);
776 sort(children.begin(), children.end(), CompareIndices());
782 SGPropertyNode::getPath (bool simplify) const
787 string path = _parent->getPath(simplify);
790 if (_index != 0 || !simplify) {
792 sprintf(buffer, "[%d]", _index);
799 SGPropertyNode::getType () const
802 return _value.alias->getType();
809 SGPropertyNode::getBoolValue () const
811 // Shortcut for common case
812 if (_attr == (READ|WRITE) && _type == BOOL)
815 if (getAttribute(TRACE_READ))
817 if (!getAttribute(READ))
818 return SGRawValue<bool>::DefaultValue;
821 return _value.alias->getBoolValue();
825 return get_int() == 0 ? false : true;
827 return get_long() == 0L ? false : true;
829 return get_float() == 0.0 ? false : true;
831 return get_double() == 0.0L ? false : true;
834 return (get_string() == "true" || getDoubleValue() != 0.0L);
837 return SGRawValue<bool>::DefaultValue;
842 SGPropertyNode::getIntValue () const
844 // Shortcut for common case
845 if (_attr == (READ|WRITE) && _type == INT)
848 if (getAttribute(TRACE_READ))
850 if (!getAttribute(READ))
851 return SGRawValue<int>::DefaultValue;
854 return _value.alias->getIntValue();
856 return int(get_bool());
860 return int(get_long());
862 return int(get_float());
864 return int(get_double());
867 return atoi(get_string().c_str());
870 return SGRawValue<int>::DefaultValue;
875 SGPropertyNode::getLongValue () const
877 // Shortcut for common case
878 if (_attr == (READ|WRITE) && _type == LONG)
881 if (getAttribute(TRACE_READ))
883 if (!getAttribute(READ))
884 return SGRawValue<long>::DefaultValue;
887 return _value.alias->getLongValue();
889 return long(get_bool());
891 return long(get_int());
895 return long(get_float());
897 return long(get_double());
900 return strtol(get_string().c_str(), 0, 0);
903 return SGRawValue<long>::DefaultValue;
908 SGPropertyNode::getFloatValue () const
910 // Shortcut for common case
911 if (_attr == (READ|WRITE) && _type == FLOAT)
914 if (getAttribute(TRACE_READ))
916 if (!getAttribute(READ))
917 return SGRawValue<float>::DefaultValue;
920 return _value.alias->getFloatValue();
922 return float(get_bool());
924 return float(get_int());
926 return float(get_long());
930 return float(get_double());
933 return atof(get_string().c_str());
936 return SGRawValue<float>::DefaultValue;
941 SGPropertyNode::getDoubleValue () const
943 // Shortcut for common case
944 if (_attr == (READ|WRITE) && _type == DOUBLE)
947 if (getAttribute(TRACE_READ))
949 if (!getAttribute(READ))
950 return SGRawValue<double>::DefaultValue;
954 return _value.alias->getDoubleValue();
956 return double(get_bool());
958 return double(get_int());
960 return double(get_long());
962 return double(get_float());
967 return strtod(get_string().c_str(), 0);
970 return SGRawValue<double>::DefaultValue;
975 SGPropertyNode::getStringValue () const
977 // Shortcut for common case
978 if (_attr == (READ|WRITE) && _type == STRING)
981 if (getAttribute(TRACE_READ))
983 if (!getAttribute(READ))
984 return SGRawValue<string>::DefaultValue;
985 return make_string();
989 SGPropertyNode::setBoolValue (bool value)
991 // Shortcut for common case
992 if (_attr == (READ|WRITE) && _type == BOOL)
993 return set_bool(value);
997 if (_type == NONE || _type == UNSPECIFIED) {
1005 result = _value.alias->setBoolValue(value);
1008 result = set_bool(value);
1011 result = set_int(int(value));
1014 result = set_long(long(value));
1017 result = set_float(float(value));
1020 result = set_double(double(value));
1024 result = set_string(value ? "true" : "false");
1031 if (getAttribute(TRACE_WRITE))
1037 SGPropertyNode::setIntValue (int value)
1039 // Shortcut for common case
1040 if (_attr == (READ|WRITE) && _type == INT)
1041 return set_int(value);
1043 bool result = false;
1045 if (_type == NONE || _type == UNSPECIFIED) {
1047 _value.int_val = new SGRawValueInternal<int>;
1053 result = _value.alias->setIntValue(value);
1056 result = set_bool(value == 0 ? false : true);
1059 result = set_int(value);
1062 result = set_long(long(value));
1065 result = set_float(float(value));
1068 result = set_double(double(value));
1073 sprintf(buf, "%d", value);
1074 result = set_string(buf);
1082 if (getAttribute(TRACE_WRITE))
1088 SGPropertyNode::setLongValue (long value)
1090 // Shortcut for common case
1091 if (_attr == (READ|WRITE) && _type == LONG)
1092 return set_long(value);
1094 bool result = false;
1096 if (_type == NONE || _type == UNSPECIFIED) {
1098 _value.long_val = new SGRawValueInternal<long>;
1104 result = _value.alias->setLongValue(value);
1107 result = set_bool(value == 0L ? false : true);
1110 result = set_int(int(value));
1113 result = set_long(value);
1116 result = set_float(float(value));
1119 result = set_double(double(value));
1124 sprintf(buf, "%ld", value);
1125 result = set_string(buf);
1133 if (getAttribute(TRACE_WRITE))
1139 SGPropertyNode::setFloatValue (float value)
1141 // Shortcut for common case
1142 if (_attr == (READ|WRITE) && _type == FLOAT)
1143 return set_float(value);
1145 bool result = false;
1147 if (_type == NONE || _type == UNSPECIFIED) {
1149 _value.float_val = new SGRawValueInternal<float>;
1155 result = _value.alias->setFloatValue(value);
1158 result = set_bool(value == 0.0 ? false : true);
1161 result = set_int(int(value));
1164 result = set_long(long(value));
1167 result = set_float(value);
1170 result = set_double(double(value));
1175 sprintf(buf, "%f", value);
1176 result = set_string(buf);
1184 if (getAttribute(TRACE_WRITE))
1190 SGPropertyNode::setDoubleValue (double value)
1192 // Shortcut for common case
1193 if (_attr == (READ|WRITE) && _type == DOUBLE)
1194 return set_double(value);
1196 bool result = false;
1198 if (_type == NONE || _type == UNSPECIFIED) {
1200 _local_val.double_val = value;
1206 result = _value.alias->setDoubleValue(value);
1209 result = set_bool(value == 0.0L ? false : true);
1212 result = set_int(int(value));
1215 result = set_long(long(value));
1218 result = set_float(float(value));
1221 result = set_double(value);
1226 sprintf(buf, "%f", value);
1227 result = set_string(buf);
1235 if (getAttribute(TRACE_WRITE))
1241 SGPropertyNode::setStringValue (string value)
1243 // Shortcut for common case
1244 if (_attr == (READ|WRITE) && _type == STRING)
1245 return set_string(value);
1247 bool result = false;
1249 if (_type == NONE || _type == UNSPECIFIED) {
1251 _local_val.string_val = new string;
1257 result = _value.alias->setStringValue(value);
1260 result = set_bool((value == "true" || atoi(value.c_str())) ? true : false);
1263 result = set_int(atoi(value.c_str()));
1266 result = set_long(strtol(value.c_str(), 0, 0));
1269 result = set_float(atof(value.c_str()));
1272 result = set_double(strtod(value.c_str(), 0));
1276 result = set_string(value);
1283 if (getAttribute(TRACE_WRITE))
1289 SGPropertyNode::setUnspecifiedValue (string value)
1291 bool result = false;
1293 if (_type == NONE) {
1295 _local_val.string_val = new string;
1296 _type = UNSPECIFIED;
1301 result = _value.alias->setUnspecifiedValue(value);
1304 result = set_bool((value == "true" || atoi(value.c_str())) ? true : false);
1307 result = set_int(atoi(value.c_str()));
1310 result = set_long(strtol(value.c_str(), 0, 0));
1313 result = set_float(atof(value.c_str()));
1316 result = set_double(strtod(value.c_str(), 0));
1320 result = set_string(value);
1327 if (getAttribute(TRACE_WRITE))
1333 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1335 if (_type == ALIAS || _tied)
1338 useDefault = useDefault && hasValue();
1339 bool old_val = false;
1341 old_val = getBoolValue();
1346 _value.bool_val = rawValue.clone();
1349 setBoolValue(old_val);
1355 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1357 if (_type == ALIAS || _tied)
1360 useDefault = useDefault && hasValue();
1363 old_val = getIntValue();
1368 _value.int_val = rawValue.clone();
1371 setIntValue(old_val);
1377 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1379 if (_type == ALIAS || _tied)
1382 useDefault = useDefault && hasValue();
1385 old_val = getLongValue();
1390 _value.long_val = rawValue.clone();
1393 setLongValue(old_val);
1399 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1401 if (_type == ALIAS || _tied)
1404 useDefault = useDefault && hasValue();
1405 float old_val = 0.0;
1407 old_val = getFloatValue();
1412 _value.float_val = rawValue.clone();
1415 setFloatValue(old_val);
1421 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1423 if (_type == ALIAS || _tied)
1426 useDefault = useDefault && hasValue();
1427 double old_val = 0.0;
1429 old_val = getDoubleValue();
1434 _value.double_val = rawValue.clone();
1437 setDoubleValue(old_val);
1444 SGPropertyNode::tie (const SGRawValue<string> &rawValue, bool useDefault)
1446 if (_type == ALIAS || _tied)
1449 useDefault = useDefault && hasValue();
1452 old_val = getStringValue();
1457 _value.string_val = rawValue.clone();
1460 setStringValue(old_val);
1466 SGPropertyNode::untie ()
1473 bool val = getBoolValue();
1476 _value.bool_val = new SGRawValueInternal<bool>;
1481 int val = getIntValue();
1484 _value.int_val = new SGRawValueInternal<int>;
1489 long val = getLongValue();
1492 _value.long_val = new SGRawValueInternal<long>;
1497 float val = getFloatValue();
1500 _value.float_val = new SGRawValueInternal<float>;
1505 double val = getDoubleValue();
1508 _value.double_val = new SGRawValueInternal<double>;
1514 string val = getStringValue();
1517 _value.string_val = new SGRawValueInternal<string>;
1531 SGPropertyNode::getRootNode ()
1536 return _parent->getRootNode();
1539 const SGPropertyNode *
1540 SGPropertyNode::getRootNode () const
1545 return _parent->getRootNode();
1549 SGPropertyNode::getNode (const string &relative_path, bool create)
1551 if (_path_cache == 0)
1552 _path_cache = new cache_map;
1554 SGPropertyNode * result = (*_path_cache)[relative_path];
1556 vector<PathComponent> components;
1557 parse_path(relative_path, components);
1558 result = find_node(this, components, 0, create);
1560 (*_path_cache)[relative_path] = result;
1567 SGPropertyNode::getNode (const string &relative_path, int index, bool create)
1569 vector<PathComponent> components;
1570 parse_path(relative_path, components);
1571 if (components.size() > 0)
1572 components[components.size()-1].index = index;
1573 return find_node(this, components, 0, create);
1576 const SGPropertyNode *
1577 SGPropertyNode::getNode (const string &relative_path) const
1579 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1582 const SGPropertyNode *
1583 SGPropertyNode::getNode (const string &relative_path, int index) const
1585 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1589 ////////////////////////////////////////////////////////////////////////
1590 // Convenience methods using relative paths.
1591 ////////////////////////////////////////////////////////////////////////
1595 * Test whether another node has a value attached.
1598 SGPropertyNode::hasValue (const string &relative_path) const
1600 const SGPropertyNode * node = getNode(relative_path);
1601 return (node == 0 ? false : node->hasValue());
1606 * Get the value type for another node.
1608 SGPropertyNode::Type
1609 SGPropertyNode::getType (const string &relative_path) const
1611 const SGPropertyNode * node = getNode(relative_path);
1612 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1617 * Get a bool value for another node.
1620 SGPropertyNode::getBoolValue (const string &relative_path,
1621 bool defaultValue) const
1623 const SGPropertyNode * node = getNode(relative_path);
1624 return (node == 0 ? defaultValue : node->getBoolValue());
1629 * Get an int value for another node.
1632 SGPropertyNode::getIntValue (const string &relative_path,
1633 int defaultValue) const
1635 const SGPropertyNode * node = getNode(relative_path);
1636 return (node == 0 ? defaultValue : node->getIntValue());
1641 * Get a long value for another node.
1644 SGPropertyNode::getLongValue (const string &relative_path,
1645 long defaultValue) const
1647 const SGPropertyNode * node = getNode(relative_path);
1648 return (node == 0 ? defaultValue : node->getLongValue());
1653 * Get a float value for another node.
1656 SGPropertyNode::getFloatValue (const string &relative_path,
1657 float defaultValue) const
1659 const SGPropertyNode * node = getNode(relative_path);
1660 return (node == 0 ? defaultValue : node->getFloatValue());
1665 * Get a double value for another node.
1668 SGPropertyNode::getDoubleValue (const string &relative_path,
1669 double defaultValue) const
1671 const SGPropertyNode * node = getNode(relative_path);
1672 return (node == 0 ? defaultValue : node->getDoubleValue());
1677 * Get a string value for another node.
1680 SGPropertyNode::getStringValue (const string &relative_path,
1681 string defaultValue) const
1683 const SGPropertyNode * node = getNode(relative_path);
1684 return (node == 0 ? defaultValue : node->getStringValue());
1689 * Set a bool value for another node.
1692 SGPropertyNode::setBoolValue (const string &relative_path, bool value)
1694 return getNode(relative_path, true)->setBoolValue(value);
1699 * Set an int value for another node.
1702 SGPropertyNode::setIntValue (const string &relative_path, int value)
1704 return getNode(relative_path, true)->setIntValue(value);
1709 * Set a long value for another node.
1712 SGPropertyNode::setLongValue (const string &relative_path, long value)
1714 return getNode(relative_path, true)->setLongValue(value);
1719 * Set a float value for another node.
1722 SGPropertyNode::setFloatValue (const string &relative_path, float value)
1724 return getNode(relative_path, true)->setFloatValue(value);
1729 * Set a double value for another node.
1732 SGPropertyNode::setDoubleValue (const string &relative_path, double value)
1734 return getNode(relative_path, true)->setDoubleValue(value);
1739 * Set a string value for another node.
1742 SGPropertyNode::setStringValue (const string &relative_path, string value)
1744 return getNode(relative_path, true)->setStringValue(value);
1749 * Set an unknown value for another node.
1752 SGPropertyNode::setUnspecifiedValue (const string &relative_path, string value)
1754 return getNode(relative_path, true)->setUnspecifiedValue(value);
1759 * Test whether another node is tied.
1762 SGPropertyNode::isTied (const string &relative_path) const
1764 const SGPropertyNode * node = getNode(relative_path);
1765 return (node == 0 ? false : node->isTied());
1770 * Tie a node reached by a relative path, creating it if necessary.
1773 SGPropertyNode::tie (const string &relative_path,
1774 const SGRawValue<bool> &rawValue,
1777 return getNode(relative_path, true)->tie(rawValue, useDefault);
1782 * Tie a node reached by a relative path, creating it if necessary.
1785 SGPropertyNode::tie (const string &relative_path,
1786 const SGRawValue<int> &rawValue,
1789 return getNode(relative_path, true)->tie(rawValue, useDefault);
1794 * Tie a node reached by a relative path, creating it if necessary.
1797 SGPropertyNode::tie (const string &relative_path,
1798 const SGRawValue<long> &rawValue,
1801 return getNode(relative_path, true)->tie(rawValue, useDefault);
1806 * Tie a node reached by a relative path, creating it if necessary.
1809 SGPropertyNode::tie (const string &relative_path,
1810 const SGRawValue<float> &rawValue,
1813 return getNode(relative_path, true)->tie(rawValue, useDefault);
1818 * Tie a node reached by a relative path, creating it if necessary.
1821 SGPropertyNode::tie (const string &relative_path,
1822 const SGRawValue<double> &rawValue,
1825 return getNode(relative_path, true)->tie(rawValue, useDefault);
1830 * Tie a node reached by a relative path, creating it if necessary.
1833 SGPropertyNode::tie (const string &relative_path,
1834 const SGRawValue<string> &rawValue,
1837 return getNode(relative_path, true)->tie(rawValue, useDefault);
1842 * Attempt to untie another node reached by a relative path.
1845 SGPropertyNode::untie (const string &relative_path)
1847 SGPropertyNode * node = getNode(relative_path);
1848 return (node == 0 ? false : node->untie());