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].
20 #include <simgear/compiler.h>
21 #include <simgear/debug/logstream.hxx>
30 ////////////////////////////////////////////////////////////////////////
32 ////////////////////////////////////////////////////////////////////////
35 * Comparator class for sorting by index.
40 int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
41 return (n1->getIndex() < n2->getIndex());
47 ////////////////////////////////////////////////////////////////////////
48 // Convenience macros for value access.
49 ////////////////////////////////////////////////////////////////////////
51 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
52 #define TEST_WRITE if (!getAttribute(WRITE)) return false
56 ////////////////////////////////////////////////////////////////////////
57 // Default values for every type.
58 ////////////////////////////////////////////////////////////////////////
60 const bool SGRawValue<bool>::DefaultValue = false;
61 const int SGRawValue<int>::DefaultValue = 0;
62 const long SGRawValue<long>::DefaultValue = 0L;
63 const float SGRawValue<float>::DefaultValue = 0.0;
64 const double SGRawValue<double>::DefaultValue = 0.0L;
65 const char * const SGRawValue<const char *>::DefaultValue = "";
69 ////////////////////////////////////////////////////////////////////////
70 // Local path normalization code.
71 ////////////////////////////////////////////////////////////////////////
74 * A component in a path.
83 * Parse the name for a path component.
85 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
87 static inline const string
88 parse_name (const string &path, int &i)
91 int max = path.size();
95 if (i < max && path[i] == '.') {
101 if (i < max && path[i] != '/')
102 throw string(string("Illegal character after ") + name);
105 else if (isalpha(path[i]) || path[i] == '_') {
109 // The rules inside a name are a little
112 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
113 path[i] == '-' || path[i] == '.') {
115 } else if (path[i] == '[' || path[i] == '/') {
118 throw string("name may contain only ._- and alphanumeric characters");
125 if (name.size() == 0)
126 throw string("name must begin with alpha or '_'");
134 * Parse the optional integer index for a path component.
136 * Index: "[" [0-9]+ "]"
139 parse_index (const string &path, int &i)
148 for (int max = path.size(); i < max; i++) {
149 if (isdigit(path[i])) {
150 index = (index * 10) + (path[i] - '0');
151 } else if (path[i] == ']') {
159 throw string("unterminated index (looking for ']')");
164 * Parse a single path component.
166 * Component: Name Index?
168 static inline PathComponent
169 parse_component (const string &path, int &i)
171 PathComponent component;
172 component.name = parse_name(path, i);
173 if (component.name[0] != '.')
174 component.index = parse_index(path, i);
176 component.index = -1;
182 * Parse a path into its components.
185 parse_path (const string &path, vector<PathComponent> &components)
188 int max = path.size();
190 // Check for initial '/'
191 if (path[pos] == '/') {
195 components.push_back(root);
197 while (pos < max && path[pos] == '/')
202 components.push_back(parse_component(path, pos));
203 while (pos < max && path[pos] == '/')
210 ////////////////////////////////////////////////////////////////////////
211 // Other static utility functions.
212 ////////////////////////////////////////////////////////////////////////
216 copy_string (const char * s)
218 // FIXME: potential buffer overflow.
219 // For some reason, strnlen and
220 // strncpy cause all kinds of crashes.
222 size_t len = strlen(s);
223 char * copy = new char[str.size() + 1];
224 strcpy(copy, str.c_str());
229 compare_strings (const char * s1, const char * s2)
231 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
235 * Locate a child node by name and index.
238 find_child (const char * name, int index, vector<SGPropertyNode *> nodes)
240 int nNodes = nodes.size();
241 for (int i = 0; i < nNodes; i++) {
242 SGPropertyNode * node = nodes[i];
243 if (compare_strings(node->getName(), name) && node->getIndex() == index)
251 * Locate another node, given a relative path.
253 static SGPropertyNode *
254 find_node (SGPropertyNode * current,
255 const vector<PathComponent> &components,
259 // Run off the end of the list
264 // Success! This is the one we want.
265 else if (position >= (int)components.size()) {
269 // Empty component means root.
270 else if (components[position].name == "") {
271 return find_node(current->getRootNode(), components, position + 1, create);
274 // . means current directory
275 else if (components[position].name == ".") {
276 return find_node(current, components, position + 1, create);
279 // .. means parent directory
280 else if (components[position].name == "..") {
281 SGPropertyNode * parent = current->getParent();
283 throw string("Attempt to move past root with '..'");
285 return find_node(parent, components, position + 1, create);
288 // Otherwise, a child name
290 SGPropertyNode * child =
291 current->getChild(components[position].name.c_str(),
292 components[position].index,
294 return find_node(child, components, position + 1, create);
300 ////////////////////////////////////////////////////////////////////////
301 // Private methods from SGPropertyNode (may be inlined for speed).
302 ////////////////////////////////////////////////////////////////////////
305 SGPropertyNode::get_bool () const
308 return _value.bool_val->getValue();
310 return _local_val.bool_val;
314 SGPropertyNode::get_int () const
317 return _value.int_val->getValue();
319 return _local_val.int_val;
323 SGPropertyNode::get_long () const
326 return _value.long_val->getValue();
328 return _local_val.long_val;
332 SGPropertyNode::get_float () const
335 return _value.float_val->getValue();
337 return _local_val.float_val;
341 SGPropertyNode::get_double () const
344 return _value.double_val->getValue();
346 return _local_val.double_val;
350 SGPropertyNode::get_string () const
353 return _value.string_val->getValue();
355 return _local_val.string_val;
359 SGPropertyNode::set_bool (bool val)
362 return _value.bool_val->setValue(val);
364 _local_val.bool_val = val;
370 SGPropertyNode::set_int (int val)
373 return _value.int_val->setValue(val);
375 _local_val.int_val = val;
381 SGPropertyNode::set_long (long val)
384 return _value.long_val->setValue(val);
386 _local_val.long_val = val;
392 SGPropertyNode::set_float (float val)
395 return _value.float_val->setValue(val);
397 _local_val.float_val = val;
403 SGPropertyNode::set_double (double val)
406 return _value.double_val->setValue(val);
408 _local_val.double_val = val;
414 SGPropertyNode::set_string (const char * val)
417 return _value.string_val->setValue(val);
419 delete _local_val.string_val;
420 _local_val.string_val = copy_string(val);
426 SGPropertyNode::clear_value ()
434 delete _value.bool_val;
436 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
439 delete _value.int_val;
441 _local_val.int_val = SGRawValue<int>::DefaultValue;
444 delete _value.long_val;
445 _value.long_val = 0L;
446 _local_val.long_val = SGRawValue<long>::DefaultValue;
449 delete _value.float_val;
450 _value.float_val = 0;
451 _local_val.float_val = SGRawValue<float>::DefaultValue;
454 delete _value.double_val;
455 _value.double_val = 0;
456 _local_val.double_val = SGRawValue<double>::DefaultValue;
460 delete _value.string_val;
461 _value.string_val = 0;
462 delete _local_val.string_val;
463 _local_val.string_val = 0;
472 * Get the value as a string.
475 SGPropertyNode::make_string () const
477 if (!getAttribute(READ))
482 return _value.alias->getStringValue();
489 sprintf(_buffer, "%d", get_int());
492 sprintf(_buffer, "%ld", get_long());
495 sprintf(_buffer, "%f", get_float());
498 sprintf(_buffer, "%f", get_double());
510 * Trace a write access for a property.
513 SGPropertyNode::trace_write () const
516 cerr << "TRACE: Write node " << getPath () << ", value\""
517 << make_string() << '"' << endl;
519 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
520 << ", value\"" << make_string() << '"');
525 * Trace a read access for a property.
528 SGPropertyNode::trace_read () const
531 cerr << "TRACE: Write node " << getPath () << ", value \""
532 << make_string() << '"' << endl;
534 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
535 << ", value \"" << make_string() << '"');
541 ////////////////////////////////////////////////////////////////////////
542 // Public methods from SGPropertyNode.
543 ////////////////////////////////////////////////////////////////////////
546 * Default constructor: always creates a root node.
548 SGPropertyNode::SGPropertyNode ()
549 : _name(copy_string("")),
557 _local_val.string_val = 0;
564 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
565 : _index(node._index),
566 _parent(0), // don't copy the parent
572 _name = copy_string(node._name);
573 _local_val.string_val = 0;
578 _value.alias = node._value.alias;
584 _value.bool_val = node._value.bool_val->clone();
587 set_bool(node.get_bool());
593 _value.int_val = node._value.int_val->clone();
596 set_int(node.get_int());
602 _value.long_val = node._value.long_val->clone();
605 set_long(node.get_long());
611 _value.float_val = node._value.float_val->clone();
614 set_float(node.get_float());
620 _value.double_val = node._value.double_val->clone();
623 set_double(node.get_double());
630 _value.string_val = node._value.string_val->clone();
633 set_string(node.get_string());
641 * Convenience constructor.
643 SGPropertyNode::SGPropertyNode (const char * name,
645 SGPropertyNode * parent)
653 _name = copy_string(name);
654 _local_val.string_val = 0;
661 SGPropertyNode::~SGPropertyNode ()
664 for (int i = 0; i < (int)_children.size(); i++) {
667 // delete _path_cache;
673 * Alias to another node.
676 SGPropertyNode::alias (SGPropertyNode * target)
678 if (target == 0 || _type == ALIAS || _tied)
681 _value.alias = target;
688 * Alias to another node by path.
691 SGPropertyNode::alias (const char * path)
693 return alias(getNode(path, true));
701 SGPropertyNode::unalias ()
712 * Get the target of an alias.
715 SGPropertyNode::getAliasTarget ()
717 return (_type == ALIAS ? _value.alias : 0);
721 const SGPropertyNode *
722 SGPropertyNode::getAliasTarget () const
724 return (_type == ALIAS ? _value.alias : 0);
729 * Get a non-const child by index.
732 SGPropertyNode::getChild (int position)
734 if (position >= 0 && position < nChildren())
735 return _children[position];
742 * Get a const child by index.
744 const SGPropertyNode *
745 SGPropertyNode::getChild (int position) const
747 if (position >= 0 && position < nChildren())
748 return _children[position];
755 * Get a non-const child by name and index, creating if necessary.
758 SGPropertyNode::getChild (const char * name, int index, bool create)
760 int pos = find_child(name, index, _children);
762 return _children[pos];
764 _children.push_back(new SGPropertyNode(name, index, this));
765 return _children[_children.size()-1];
773 * Get a const child by name and index.
775 const SGPropertyNode *
776 SGPropertyNode::getChild (const char * name, int index) const
778 int pos = find_child(name, index, _children);
780 return _children[pos];
787 * Get all children with the same name (but different indices).
789 vector<SGPropertyNode *>
790 SGPropertyNode::getChildren (const char * name)
792 vector<SGPropertyNode *> children;
793 int max = _children.size();
795 for (int i = 0; i < max; i++)
796 if (compare_strings(_children[i]->getName(), name))
797 children.push_back(_children[i]);
799 sort(children.begin(), children.end(), CompareIndices());
805 * Get all children const with the same name (but different indices).
807 vector<const SGPropertyNode *>
808 SGPropertyNode::getChildren (const char * name) const
810 vector<const SGPropertyNode *> children;
811 int max = _children.size();
813 for (int i = 0; i < max; i++)
814 if (compare_strings(_children[i]->getName(), name))
815 children.push_back(_children[i]);
817 sort(children.begin(), children.end(), CompareIndices());
823 SGPropertyNode::getPath (bool simplify) const
828 string path = _parent->getPath(simplify);
831 if (_index != 0 || !simplify) {
833 sprintf(buffer, "[%d]", _index);
840 SGPropertyNode::getType () const
843 return _value.alias->getType();
850 SGPropertyNode::getBoolValue () const
852 // Shortcut for common case
853 if (_attr == (READ|WRITE) && _type == BOOL)
856 if (getAttribute(TRACE_READ))
858 if (!getAttribute(READ))
859 return SGRawValue<bool>::DefaultValue;
862 return _value.alias->getBoolValue();
866 return get_int() == 0 ? false : true;
868 return get_long() == 0L ? false : true;
870 return get_float() == 0.0 ? false : true;
872 return get_double() == 0.0L ? false : true;
875 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
878 return SGRawValue<bool>::DefaultValue;
883 SGPropertyNode::getIntValue () const
885 // Shortcut for common case
886 if (_attr == (READ|WRITE) && _type == INT)
889 if (getAttribute(TRACE_READ))
891 if (!getAttribute(READ))
892 return SGRawValue<int>::DefaultValue;
895 return _value.alias->getIntValue();
897 return int(get_bool());
901 return int(get_long());
903 return int(get_float());
905 return int(get_double());
908 return atoi(get_string());
911 return SGRawValue<int>::DefaultValue;
916 SGPropertyNode::getLongValue () const
918 // Shortcut for common case
919 if (_attr == (READ|WRITE) && _type == LONG)
922 if (getAttribute(TRACE_READ))
924 if (!getAttribute(READ))
925 return SGRawValue<long>::DefaultValue;
928 return _value.alias->getLongValue();
930 return long(get_bool());
932 return long(get_int());
936 return long(get_float());
938 return long(get_double());
941 return strtol(get_string(), 0, 0);
944 return SGRawValue<long>::DefaultValue;
949 SGPropertyNode::getFloatValue () const
951 // Shortcut for common case
952 if (_attr == (READ|WRITE) && _type == FLOAT)
955 if (getAttribute(TRACE_READ))
957 if (!getAttribute(READ))
958 return SGRawValue<float>::DefaultValue;
961 return _value.alias->getFloatValue();
963 return float(get_bool());
965 return float(get_int());
967 return float(get_long());
971 return float(get_double());
974 return atof(get_string());
977 return SGRawValue<float>::DefaultValue;
982 SGPropertyNode::getDoubleValue () const
984 // Shortcut for common case
985 if (_attr == (READ|WRITE) && _type == DOUBLE)
988 if (getAttribute(TRACE_READ))
990 if (!getAttribute(READ))
991 return SGRawValue<double>::DefaultValue;
995 return _value.alias->getDoubleValue();
997 return double(get_bool());
999 return double(get_int());
1001 return double(get_long());
1003 return double(get_float());
1005 return get_double();
1008 return strtod(get_string(), 0);
1011 return SGRawValue<double>::DefaultValue;
1016 SGPropertyNode::getStringValue () const
1018 // Shortcut for common case
1019 if (_attr == (READ|WRITE) && _type == STRING)
1020 return get_string();
1022 if (getAttribute(TRACE_READ))
1024 if (!getAttribute(READ))
1025 return SGRawValue<const char *>::DefaultValue;
1026 return make_string();
1030 SGPropertyNode::setBoolValue (bool value)
1032 // Shortcut for common case
1033 if (_attr == (READ|WRITE) && _type == BOOL)
1034 return set_bool(value);
1036 bool result = false;
1038 if (_type == NONE || _type == UNSPECIFIED) {
1046 result = _value.alias->setBoolValue(value);
1049 result = set_bool(value);
1052 result = set_int(int(value));
1055 result = set_long(long(value));
1058 result = set_float(float(value));
1061 result = set_double(double(value));
1065 result = set_string(value ? "true" : "false");
1072 if (getAttribute(TRACE_WRITE))
1078 SGPropertyNode::setIntValue (int value)
1080 // Shortcut for common case
1081 if (_attr == (READ|WRITE) && _type == INT)
1082 return set_int(value);
1084 bool result = false;
1086 if (_type == NONE || _type == UNSPECIFIED) {
1089 _local_val.int_val = 0;
1094 result = _value.alias->setIntValue(value);
1097 result = set_bool(value == 0 ? false : true);
1100 result = set_int(value);
1103 result = set_long(long(value));
1106 result = set_float(float(value));
1109 result = set_double(double(value));
1114 sprintf(buf, "%d", value);
1115 result = set_string(buf);
1123 if (getAttribute(TRACE_WRITE))
1129 SGPropertyNode::setLongValue (long value)
1131 // Shortcut for common case
1132 if (_attr == (READ|WRITE) && _type == LONG)
1133 return set_long(value);
1135 bool result = false;
1137 if (_type == NONE || _type == UNSPECIFIED) {
1140 _local_val.long_val = 0L;
1145 result = _value.alias->setLongValue(value);
1148 result = set_bool(value == 0L ? false : true);
1151 result = set_int(int(value));
1154 result = set_long(value);
1157 result = set_float(float(value));
1160 result = set_double(double(value));
1165 sprintf(buf, "%ld", value);
1166 result = set_string(buf);
1174 if (getAttribute(TRACE_WRITE))
1180 SGPropertyNode::setFloatValue (float value)
1182 // Shortcut for common case
1183 if (_attr == (READ|WRITE) && _type == FLOAT)
1184 return set_float(value);
1186 bool result = false;
1188 if (_type == NONE || _type == UNSPECIFIED) {
1191 _local_val.float_val = 0;
1196 result = _value.alias->setFloatValue(value);
1199 result = set_bool(value == 0.0 ? false : true);
1202 result = set_int(int(value));
1205 result = set_long(long(value));
1208 result = set_float(value);
1211 result = set_double(double(value));
1216 sprintf(buf, "%f", value);
1217 result = set_string(buf);
1225 if (getAttribute(TRACE_WRITE))
1231 SGPropertyNode::setDoubleValue (double value)
1233 // Shortcut for common case
1234 if (_attr == (READ|WRITE) && _type == DOUBLE)
1235 return set_double(value);
1237 bool result = false;
1239 if (_type == NONE || _type == UNSPECIFIED) {
1241 _local_val.double_val = value;
1247 result = _value.alias->setDoubleValue(value);
1250 result = set_bool(value == 0.0L ? false : true);
1253 result = set_int(int(value));
1256 result = set_long(long(value));
1259 result = set_float(float(value));
1262 result = set_double(value);
1267 sprintf(buf, "%f", value);
1268 result = set_string(buf);
1276 if (getAttribute(TRACE_WRITE))
1282 SGPropertyNode::setStringValue (const char * value)
1284 // Shortcut for common case
1285 if (_attr == (READ|WRITE) && _type == STRING)
1286 return set_string(value);
1288 bool result = false;
1290 if (_type == NONE || _type == UNSPECIFIED) {
1297 result = _value.alias->setStringValue(value);
1300 result = set_bool((compare_strings(value, "true")
1301 || atoi(value)) ? true : false);
1304 result = set_int(atoi(value));
1307 result = set_long(strtol(value, 0, 0));
1310 result = set_float(atof(value));
1313 result = set_double(strtod(value, 0));
1317 result = set_string(value);
1324 if (getAttribute(TRACE_WRITE))
1330 SGPropertyNode::setUnspecifiedValue (const char * value)
1332 bool result = false;
1334 if (_type == NONE) {
1336 _type = UNSPECIFIED;
1341 result = _value.alias->setUnspecifiedValue(value);
1344 result = set_bool((compare_strings(value, "true")
1345 || atoi(value)) ? true : false);
1348 result = set_int(atoi(value));
1351 result = set_long(strtol(value, 0, 0));
1354 result = set_float(atof(value));
1357 result = set_double(strtod(value, 0));
1361 result = set_string(value);
1368 if (getAttribute(TRACE_WRITE))
1374 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1376 if (_type == ALIAS || _tied)
1379 useDefault = useDefault && hasValue();
1380 bool old_val = false;
1382 old_val = getBoolValue();
1387 _value.bool_val = rawValue.clone();
1390 setBoolValue(old_val);
1396 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1398 if (_type == ALIAS || _tied)
1401 useDefault = useDefault && hasValue();
1404 old_val = getIntValue();
1409 _value.int_val = rawValue.clone();
1412 setIntValue(old_val);
1418 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1420 if (_type == ALIAS || _tied)
1423 useDefault = useDefault && hasValue();
1426 old_val = getLongValue();
1431 _value.long_val = rawValue.clone();
1434 setLongValue(old_val);
1440 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1442 if (_type == ALIAS || _tied)
1445 useDefault = useDefault && hasValue();
1446 float old_val = 0.0;
1448 old_val = getFloatValue();
1453 _value.float_val = rawValue.clone();
1456 setFloatValue(old_val);
1462 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1464 if (_type == ALIAS || _tied)
1467 useDefault = useDefault && hasValue();
1468 double old_val = 0.0;
1470 old_val = getDoubleValue();
1475 _value.double_val = rawValue.clone();
1478 setDoubleValue(old_val);
1485 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1487 if (_type == ALIAS || _tied)
1490 useDefault = useDefault && hasValue();
1493 old_val = getStringValue();
1498 _value.string_val = rawValue.clone();
1501 setStringValue(old_val.c_str());
1507 SGPropertyNode::untie ()
1514 bool val = getBoolValue();
1517 _local_val.bool_val = val;
1521 int val = getIntValue();
1524 _local_val.int_val = val;
1528 long val = getLongValue();
1531 _local_val.long_val = val;
1535 float val = getFloatValue();
1538 _local_val.float_val = val;
1542 double val = getDoubleValue();
1545 _local_val.double_val = val;
1550 string val = getStringValue();
1553 _local_val.string_val = copy_string(val.c_str());
1566 SGPropertyNode::getRootNode ()
1571 return _parent->getRootNode();
1574 const SGPropertyNode *
1575 SGPropertyNode::getRootNode () const
1580 return _parent->getRootNode();
1584 SGPropertyNode::getNode (const char * relative_path, bool create)
1586 // if (_path_cache == 0)
1587 // _path_cache = new cache_map;
1589 // SGPropertyNode * result = (*_path_cache)[relative_path];
1590 // if (result == 0) {
1591 // vector<PathComponent> components;
1592 // parse_path(relative_path, components);
1593 // result = find_node(this, components, 0, create);
1595 // (*_path_cache)[relative_path] = result;
1599 vector<PathComponent> components;
1600 parse_path(relative_path, components);
1601 return find_node(this, components, 0, create);
1605 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1607 vector<PathComponent> components;
1608 parse_path(relative_path, components);
1609 if (components.size() > 0)
1610 components[components.size()-1].index = index;
1611 return find_node(this, components, 0, create);
1614 const SGPropertyNode *
1615 SGPropertyNode::getNode (const char * relative_path) const
1617 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1620 const SGPropertyNode *
1621 SGPropertyNode::getNode (const char * relative_path, int index) const
1623 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1627 ////////////////////////////////////////////////////////////////////////
1628 // Convenience methods using relative paths.
1629 ////////////////////////////////////////////////////////////////////////
1633 * Test whether another node has a value attached.
1636 SGPropertyNode::hasValue (const char * relative_path) const
1638 const SGPropertyNode * node = getNode(relative_path);
1639 return (node == 0 ? false : node->hasValue());
1644 * Get the value type for another node.
1646 SGPropertyNode::Type
1647 SGPropertyNode::getType (const char * relative_path) const
1649 const SGPropertyNode * node = getNode(relative_path);
1650 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1655 * Get a bool value for another node.
1658 SGPropertyNode::getBoolValue (const char * relative_path,
1659 bool defaultValue) const
1661 const SGPropertyNode * node = getNode(relative_path);
1662 return (node == 0 ? defaultValue : node->getBoolValue());
1667 * Get an int value for another node.
1670 SGPropertyNode::getIntValue (const char * relative_path,
1671 int defaultValue) const
1673 const SGPropertyNode * node = getNode(relative_path);
1674 return (node == 0 ? defaultValue : node->getIntValue());
1679 * Get a long value for another node.
1682 SGPropertyNode::getLongValue (const char * relative_path,
1683 long defaultValue) const
1685 const SGPropertyNode * node = getNode(relative_path);
1686 return (node == 0 ? defaultValue : node->getLongValue());
1691 * Get a float value for another node.
1694 SGPropertyNode::getFloatValue (const char * relative_path,
1695 float defaultValue) const
1697 const SGPropertyNode * node = getNode(relative_path);
1698 return (node == 0 ? defaultValue : node->getFloatValue());
1703 * Get a double value for another node.
1706 SGPropertyNode::getDoubleValue (const char * relative_path,
1707 double defaultValue) const
1709 const SGPropertyNode * node = getNode(relative_path);
1710 return (node == 0 ? defaultValue : node->getDoubleValue());
1715 * Get a string value for another node.
1718 SGPropertyNode::getStringValue (const char * relative_path,
1719 const char * defaultValue) const
1721 const SGPropertyNode * node = getNode(relative_path);
1722 return (node == 0 ? defaultValue : node->getStringValue());
1727 * Set a bool value for another node.
1730 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1732 return getNode(relative_path, true)->setBoolValue(value);
1737 * Set an int value for another node.
1740 SGPropertyNode::setIntValue (const char * relative_path, int value)
1742 return getNode(relative_path, true)->setIntValue(value);
1747 * Set a long value for another node.
1750 SGPropertyNode::setLongValue (const char * relative_path, long value)
1752 return getNode(relative_path, true)->setLongValue(value);
1757 * Set a float value for another node.
1760 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1762 return getNode(relative_path, true)->setFloatValue(value);
1767 * Set a double value for another node.
1770 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1772 return getNode(relative_path, true)->setDoubleValue(value);
1777 * Set a string value for another node.
1780 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1782 return getNode(relative_path, true)->setStringValue(value);
1787 * Set an unknown value for another node.
1790 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1793 return getNode(relative_path, true)->setUnspecifiedValue(value);
1798 * Test whether another node is tied.
1801 SGPropertyNode::isTied (const char * relative_path) const
1803 const SGPropertyNode * node = getNode(relative_path);
1804 return (node == 0 ? false : node->isTied());
1809 * Tie a node reached by a relative path, creating it if necessary.
1812 SGPropertyNode::tie (const char * relative_path,
1813 const SGRawValue<bool> &rawValue,
1816 return getNode(relative_path, true)->tie(rawValue, useDefault);
1821 * Tie a node reached by a relative path, creating it if necessary.
1824 SGPropertyNode::tie (const char * relative_path,
1825 const SGRawValue<int> &rawValue,
1828 return getNode(relative_path, true)->tie(rawValue, useDefault);
1833 * Tie a node reached by a relative path, creating it if necessary.
1836 SGPropertyNode::tie (const char * relative_path,
1837 const SGRawValue<long> &rawValue,
1840 return getNode(relative_path, true)->tie(rawValue, useDefault);
1845 * Tie a node reached by a relative path, creating it if necessary.
1848 SGPropertyNode::tie (const char * relative_path,
1849 const SGRawValue<float> &rawValue,
1852 return getNode(relative_path, true)->tie(rawValue, useDefault);
1857 * Tie a node reached by a relative path, creating it if necessary.
1860 SGPropertyNode::tie (const char * relative_path,
1861 const SGRawValue<double> &rawValue,
1864 return getNode(relative_path, true)->tie(rawValue, useDefault);
1869 * Tie a node reached by a relative path, creating it if necessary.
1872 SGPropertyNode::tie (const char * relative_path,
1873 const SGRawValue<const char *> &rawValue,
1876 return getNode(relative_path, true)->tie(rawValue, useDefault);
1881 * Attempt to untie another node reached by a relative path.
1884 SGPropertyNode::untie (const char * relative_path)
1886 SGPropertyNode * node = getNode(relative_path);
1887 return (node == 0 ? false : node->untie());