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].
24 #include <simgear/compiler.h>
25 #include <simgear/debug/logstream.hxx>
34 ////////////////////////////////////////////////////////////////////////
36 ////////////////////////////////////////////////////////////////////////
39 * Comparator class for sorting by index.
44 int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
45 return (n1->getIndex() < n2->getIndex());
51 ////////////////////////////////////////////////////////////////////////
52 // Convenience macros for value access.
53 ////////////////////////////////////////////////////////////////////////
55 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
56 #define TEST_WRITE if (!getAttribute(WRITE)) return false
60 ////////////////////////////////////////////////////////////////////////
61 // Default values for every type.
62 ////////////////////////////////////////////////////////////////////////
64 const bool SGRawValue<bool>::DefaultValue = false;
65 const int SGRawValue<int>::DefaultValue = 0;
66 const long SGRawValue<long>::DefaultValue = 0L;
67 const float SGRawValue<float>::DefaultValue = 0.0;
68 const double SGRawValue<double>::DefaultValue = 0.0L;
69 const char * const SGRawValue<const char *>::DefaultValue = "";
73 ////////////////////////////////////////////////////////////////////////
74 // Local path normalization code.
75 ////////////////////////////////////////////////////////////////////////
78 * A component in a path.
87 * Parse the name for a path component.
89 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
91 static inline const string
92 parse_name (const string &path, int &i)
95 int max = path.size();
99 if (i < max && path[i] == '.') {
105 if (i < max && path[i] != '/')
106 throw string(string("Illegal character after ") + name);
109 else if (isalpha(path[i]) || path[i] == '_') {
113 // The rules inside a name are a little
116 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
117 path[i] == '-' || path[i] == '.') {
119 } else if (path[i] == '[' || path[i] == '/') {
122 throw string("name may contain only ._- and alphanumeric characters");
129 if (name.size() == 0)
130 throw string("name must begin with alpha or '_'");
138 * Parse the optional integer index for a path component.
140 * Index: "[" [0-9]+ "]"
143 parse_index (const string &path, int &i)
152 for (int max = path.size(); i < max; i++) {
153 if (isdigit(path[i])) {
154 index = (index * 10) + (path[i] - '0');
155 } else if (path[i] == ']') {
163 throw string("unterminated index (looking for ']')");
168 * Parse a single path component.
170 * Component: Name Index?
172 static inline PathComponent
173 parse_component (const string &path, int &i)
175 PathComponent component;
176 component.name = parse_name(path, i);
177 if (component.name[0] != '.')
178 component.index = parse_index(path, i);
180 component.index = -1;
186 * Parse a path into its components.
189 parse_path (const string &path, vector<PathComponent> &components)
192 int max = path.size();
194 // Check for initial '/'
195 if (path[pos] == '/') {
199 components.push_back(root);
201 while (pos < max && path[pos] == '/')
206 components.push_back(parse_component(path, pos));
207 while (pos < max && path[pos] == '/')
214 ////////////////////////////////////////////////////////////////////////
215 // Other static utility functions.
216 ////////////////////////////////////////////////////////////////////////
220 copy_string (const char * s)
222 // FIXME: potential buffer overflow.
223 // For some reason, strnlen and
224 // strncpy cause all kinds of crashes.
226 size_t len = strlen(s);
227 char * copy = new char[str.size() + 1];
228 strcpy(copy, str.c_str());
233 compare_strings (const char * s1, const char * s2)
235 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
239 * Locate a child node by name and index.
242 find_child (const char * name, int index, vector<SGPropertyNode *> nodes)
244 int nNodes = nodes.size();
245 for (int i = 0; i < nNodes; i++) {
246 SGPropertyNode * node = nodes[i];
247 if (compare_strings(node->getName(), name) && node->getIndex() == index)
255 * Locate another node, given a relative path.
257 static SGPropertyNode *
258 find_node (SGPropertyNode * current,
259 const vector<PathComponent> &components,
263 // Run off the end of the list
268 // Success! This is the one we want.
269 else if (position >= (int)components.size()) {
273 // Empty component means root.
274 else if (components[position].name == "") {
275 return find_node(current->getRootNode(), components, position + 1, create);
278 // . means current directory
279 else if (components[position].name == ".") {
280 return find_node(current, components, position + 1, create);
283 // .. means parent directory
284 else if (components[position].name == "..") {
285 SGPropertyNode * parent = current->getParent();
287 throw string("Attempt to move past root with '..'");
289 return find_node(parent, components, position + 1, create);
292 // Otherwise, a child name
294 SGPropertyNode * child =
295 current->getChild(components[position].name.c_str(),
296 components[position].index,
298 return find_node(child, components, position + 1, create);
304 ////////////////////////////////////////////////////////////////////////
305 // Private methods from SGPropertyNode (may be inlined for speed).
306 ////////////////////////////////////////////////////////////////////////
309 SGPropertyNode::get_bool () const
312 return _value.bool_val->getValue();
314 return _local_val.bool_val;
318 SGPropertyNode::get_int () const
321 return _value.int_val->getValue();
323 return _local_val.int_val;
327 SGPropertyNode::get_long () const
330 return _value.long_val->getValue();
332 return _local_val.long_val;
336 SGPropertyNode::get_float () const
339 return _value.float_val->getValue();
341 return _local_val.float_val;
345 SGPropertyNode::get_double () const
348 return _value.double_val->getValue();
350 return _local_val.double_val;
354 SGPropertyNode::get_string () const
357 return _value.string_val->getValue();
359 return _local_val.string_val;
363 SGPropertyNode::set_bool (bool val)
366 return _value.bool_val->setValue(val);
368 _local_val.bool_val = val;
374 SGPropertyNode::set_int (int val)
377 return _value.int_val->setValue(val);
379 _local_val.int_val = val;
385 SGPropertyNode::set_long (long val)
388 return _value.long_val->setValue(val);
390 _local_val.long_val = val;
396 SGPropertyNode::set_float (float val)
399 return _value.float_val->setValue(val);
401 _local_val.float_val = val;
407 SGPropertyNode::set_double (double val)
410 return _value.double_val->setValue(val);
412 _local_val.double_val = val;
418 SGPropertyNode::set_string (const char * val)
421 return _value.string_val->setValue(val);
423 delete _local_val.string_val;
424 _local_val.string_val = copy_string(val);
430 SGPropertyNode::clear_value ()
438 delete _value.bool_val;
440 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
443 delete _value.int_val;
445 _local_val.int_val = SGRawValue<int>::DefaultValue;
448 delete _value.long_val;
449 _value.long_val = 0L;
450 _local_val.long_val = SGRawValue<long>::DefaultValue;
453 delete _value.float_val;
454 _value.float_val = 0;
455 _local_val.float_val = SGRawValue<float>::DefaultValue;
458 delete _value.double_val;
459 _value.double_val = 0;
460 _local_val.double_val = SGRawValue<double>::DefaultValue;
464 delete _value.string_val;
465 _value.string_val = 0;
466 delete _local_val.string_val;
467 _local_val.string_val = 0;
476 * Get the value as a string.
479 SGPropertyNode::make_string () const
481 if (!getAttribute(READ))
486 return _value.alias->getStringValue();
493 sprintf(_buffer, "%d", get_int());
496 sprintf(_buffer, "%ld", get_long());
499 sprintf(_buffer, "%f", get_float());
502 sprintf(_buffer, "%f", get_double());
514 * Trace a write access for a property.
517 SGPropertyNode::trace_write () const
520 cerr << "TRACE: Write node " << getPath () << ", value\""
521 << make_string() << '"' << endl;
523 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
524 << ", value\"" << make_string() << '"');
529 * Trace a read access for a property.
532 SGPropertyNode::trace_read () const
535 cerr << "TRACE: Write node " << getPath () << ", value \""
536 << make_string() << '"' << endl;
538 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
539 << ", value \"" << make_string() << '"');
545 ////////////////////////////////////////////////////////////////////////
546 // Public methods from SGPropertyNode.
547 ////////////////////////////////////////////////////////////////////////
550 * Default constructor: always creates a root node.
552 SGPropertyNode::SGPropertyNode ()
553 : _name(copy_string("")),
561 _local_val.string_val = 0;
568 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
569 : _index(node._index),
570 _parent(0), // don't copy the parent
576 _name = copy_string(node._name);
577 _local_val.string_val = 0;
582 _value.alias = node._value.alias;
588 _value.bool_val = node._value.bool_val->clone();
591 set_bool(node.get_bool());
597 _value.int_val = node._value.int_val->clone();
600 set_int(node.get_int());
606 _value.long_val = node._value.long_val->clone();
609 set_long(node.get_long());
615 _value.float_val = node._value.float_val->clone();
618 set_float(node.get_float());
624 _value.double_val = node._value.double_val->clone();
627 set_double(node.get_double());
634 _value.string_val = node._value.string_val->clone();
637 set_string(node.get_string());
645 * Convenience constructor.
647 SGPropertyNode::SGPropertyNode (const char * name,
649 SGPropertyNode * parent)
657 _name = copy_string(name);
658 _local_val.string_val = 0;
665 SGPropertyNode::~SGPropertyNode ()
668 for (int i = 0; i < (int)_children.size(); i++) {
671 // delete _path_cache;
677 * Alias to another node.
680 SGPropertyNode::alias (SGPropertyNode * target)
682 if (target == 0 || _type == ALIAS || _tied)
685 _value.alias = target;
692 * Alias to another node by path.
695 SGPropertyNode::alias (const char * path)
697 return alias(getNode(path, true));
705 SGPropertyNode::unalias ()
716 * Get the target of an alias.
719 SGPropertyNode::getAliasTarget ()
721 return (_type == ALIAS ? _value.alias : 0);
725 const SGPropertyNode *
726 SGPropertyNode::getAliasTarget () const
728 return (_type == ALIAS ? _value.alias : 0);
733 * Get a non-const child by index.
736 SGPropertyNode::getChild (int position)
738 if (position >= 0 && position < nChildren())
739 return _children[position];
746 * Get a const child by index.
748 const SGPropertyNode *
749 SGPropertyNode::getChild (int position) const
751 if (position >= 0 && position < nChildren())
752 return _children[position];
759 * Get a non-const child by name and index, creating if necessary.
762 SGPropertyNode::getChild (const char * name, int index, bool create)
764 int pos = find_child(name, index, _children);
766 return _children[pos];
768 _children.push_back(new SGPropertyNode(name, index, this));
769 return _children[_children.size()-1];
777 * Get a const child by name and index.
779 const SGPropertyNode *
780 SGPropertyNode::getChild (const char * name, int index) const
782 int pos = find_child(name, index, _children);
784 return _children[pos];
791 * Get all children with the same name (but different indices).
793 vector<SGPropertyNode *>
794 SGPropertyNode::getChildren (const char * name)
796 vector<SGPropertyNode *> children;
797 int max = _children.size();
799 for (int i = 0; i < max; i++)
800 if (compare_strings(_children[i]->getName(), name))
801 children.push_back(_children[i]);
803 sort(children.begin(), children.end(), CompareIndices());
809 * Get all children const with the same name (but different indices).
811 vector<const SGPropertyNode *>
812 SGPropertyNode::getChildren (const char * name) const
814 vector<const SGPropertyNode *> children;
815 int max = _children.size();
817 for (int i = 0; i < max; i++)
818 if (compare_strings(_children[i]->getName(), name))
819 children.push_back(_children[i]);
821 sort(children.begin(), children.end(), CompareIndices());
827 SGPropertyNode::getPath (bool simplify) const
832 string path = _parent->getPath(simplify);
835 if (_index != 0 || !simplify) {
837 sprintf(buffer, "[%d]", _index);
844 SGPropertyNode::getType () const
847 return _value.alias->getType();
854 SGPropertyNode::getBoolValue () const
856 // Shortcut for common case
857 if (_attr == (READ|WRITE) && _type == BOOL)
860 if (getAttribute(TRACE_READ))
862 if (!getAttribute(READ))
863 return SGRawValue<bool>::DefaultValue;
866 return _value.alias->getBoolValue();
870 return get_int() == 0 ? false : true;
872 return get_long() == 0L ? false : true;
874 return get_float() == 0.0 ? false : true;
876 return get_double() == 0.0L ? false : true;
879 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
882 return SGRawValue<bool>::DefaultValue;
887 SGPropertyNode::getIntValue () const
889 // Shortcut for common case
890 if (_attr == (READ|WRITE) && _type == INT)
893 if (getAttribute(TRACE_READ))
895 if (!getAttribute(READ))
896 return SGRawValue<int>::DefaultValue;
899 return _value.alias->getIntValue();
901 return int(get_bool());
905 return int(get_long());
907 return int(get_float());
909 return int(get_double());
912 return atoi(get_string());
915 return SGRawValue<int>::DefaultValue;
920 SGPropertyNode::getLongValue () const
922 // Shortcut for common case
923 if (_attr == (READ|WRITE) && _type == LONG)
926 if (getAttribute(TRACE_READ))
928 if (!getAttribute(READ))
929 return SGRawValue<long>::DefaultValue;
932 return _value.alias->getLongValue();
934 return long(get_bool());
936 return long(get_int());
940 return long(get_float());
942 return long(get_double());
945 return strtol(get_string(), 0, 0);
948 return SGRawValue<long>::DefaultValue;
953 SGPropertyNode::getFloatValue () const
955 // Shortcut for common case
956 if (_attr == (READ|WRITE) && _type == FLOAT)
959 if (getAttribute(TRACE_READ))
961 if (!getAttribute(READ))
962 return SGRawValue<float>::DefaultValue;
965 return _value.alias->getFloatValue();
967 return float(get_bool());
969 return float(get_int());
971 return float(get_long());
975 return float(get_double());
978 return atof(get_string());
981 return SGRawValue<float>::DefaultValue;
986 SGPropertyNode::getDoubleValue () const
988 // Shortcut for common case
989 if (_attr == (READ|WRITE) && _type == DOUBLE)
992 if (getAttribute(TRACE_READ))
994 if (!getAttribute(READ))
995 return SGRawValue<double>::DefaultValue;
999 return _value.alias->getDoubleValue();
1001 return double(get_bool());
1003 return double(get_int());
1005 return double(get_long());
1007 return double(get_float());
1009 return get_double();
1012 return strtod(get_string(), 0);
1015 return SGRawValue<double>::DefaultValue;
1020 SGPropertyNode::getStringValue () const
1022 // Shortcut for common case
1023 if (_attr == (READ|WRITE) && _type == STRING)
1024 return get_string();
1026 if (getAttribute(TRACE_READ))
1028 if (!getAttribute(READ))
1029 return SGRawValue<const char *>::DefaultValue;
1030 return make_string();
1034 SGPropertyNode::setBoolValue (bool value)
1036 // Shortcut for common case
1037 if (_attr == (READ|WRITE) && _type == BOOL)
1038 return set_bool(value);
1040 bool result = false;
1042 if (_type == NONE || _type == UNSPECIFIED) {
1050 result = _value.alias->setBoolValue(value);
1053 result = set_bool(value);
1056 result = set_int(int(value));
1059 result = set_long(long(value));
1062 result = set_float(float(value));
1065 result = set_double(double(value));
1069 result = set_string(value ? "true" : "false");
1076 if (getAttribute(TRACE_WRITE))
1082 SGPropertyNode::setIntValue (int value)
1084 // Shortcut for common case
1085 if (_attr == (READ|WRITE) && _type == INT)
1086 return set_int(value);
1088 bool result = false;
1090 if (_type == NONE || _type == UNSPECIFIED) {
1093 _local_val.int_val = 0;
1098 result = _value.alias->setIntValue(value);
1101 result = set_bool(value == 0 ? false : true);
1104 result = set_int(value);
1107 result = set_long(long(value));
1110 result = set_float(float(value));
1113 result = set_double(double(value));
1118 sprintf(buf, "%d", value);
1119 result = set_string(buf);
1127 if (getAttribute(TRACE_WRITE))
1133 SGPropertyNode::setLongValue (long value)
1135 // Shortcut for common case
1136 if (_attr == (READ|WRITE) && _type == LONG)
1137 return set_long(value);
1139 bool result = false;
1141 if (_type == NONE || _type == UNSPECIFIED) {
1144 _local_val.long_val = 0L;
1149 result = _value.alias->setLongValue(value);
1152 result = set_bool(value == 0L ? false : true);
1155 result = set_int(int(value));
1158 result = set_long(value);
1161 result = set_float(float(value));
1164 result = set_double(double(value));
1169 sprintf(buf, "%ld", value);
1170 result = set_string(buf);
1178 if (getAttribute(TRACE_WRITE))
1184 SGPropertyNode::setFloatValue (float value)
1186 // Shortcut for common case
1187 if (_attr == (READ|WRITE) && _type == FLOAT)
1188 return set_float(value);
1190 bool result = false;
1192 if (_type == NONE || _type == UNSPECIFIED) {
1195 _local_val.float_val = 0;
1200 result = _value.alias->setFloatValue(value);
1203 result = set_bool(value == 0.0 ? false : true);
1206 result = set_int(int(value));
1209 result = set_long(long(value));
1212 result = set_float(value);
1215 result = set_double(double(value));
1220 sprintf(buf, "%f", value);
1221 result = set_string(buf);
1229 if (getAttribute(TRACE_WRITE))
1235 SGPropertyNode::setDoubleValue (double value)
1237 // Shortcut for common case
1238 if (_attr == (READ|WRITE) && _type == DOUBLE)
1239 return set_double(value);
1241 bool result = false;
1243 if (_type == NONE || _type == UNSPECIFIED) {
1245 _local_val.double_val = value;
1251 result = _value.alias->setDoubleValue(value);
1254 result = set_bool(value == 0.0L ? false : true);
1257 result = set_int(int(value));
1260 result = set_long(long(value));
1263 result = set_float(float(value));
1266 result = set_double(value);
1271 sprintf(buf, "%f", value);
1272 result = set_string(buf);
1280 if (getAttribute(TRACE_WRITE))
1286 SGPropertyNode::setStringValue (const char * value)
1288 // Shortcut for common case
1289 if (_attr == (READ|WRITE) && _type == STRING)
1290 return set_string(value);
1292 bool result = false;
1294 if (_type == NONE || _type == UNSPECIFIED) {
1301 result = _value.alias->setStringValue(value);
1304 result = set_bool((compare_strings(value, "true")
1305 || atoi(value)) ? true : false);
1308 result = set_int(atoi(value));
1311 result = set_long(strtol(value, 0, 0));
1314 result = set_float(atof(value));
1317 result = set_double(strtod(value, 0));
1321 result = set_string(value);
1328 if (getAttribute(TRACE_WRITE))
1334 SGPropertyNode::setUnspecifiedValue (const char * value)
1336 bool result = false;
1338 if (_type == NONE) {
1340 _type = UNSPECIFIED;
1345 result = _value.alias->setUnspecifiedValue(value);
1348 result = set_bool((compare_strings(value, "true")
1349 || atoi(value)) ? true : false);
1352 result = set_int(atoi(value));
1355 result = set_long(strtol(value, 0, 0));
1358 result = set_float(atof(value));
1361 result = set_double(strtod(value, 0));
1365 result = set_string(value);
1372 if (getAttribute(TRACE_WRITE))
1378 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1380 if (_type == ALIAS || _tied)
1383 useDefault = useDefault && hasValue();
1384 bool old_val = false;
1386 old_val = getBoolValue();
1391 _value.bool_val = rawValue.clone();
1394 setBoolValue(old_val);
1400 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1402 if (_type == ALIAS || _tied)
1405 useDefault = useDefault && hasValue();
1408 old_val = getIntValue();
1413 _value.int_val = rawValue.clone();
1416 setIntValue(old_val);
1422 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1424 if (_type == ALIAS || _tied)
1427 useDefault = useDefault && hasValue();
1430 old_val = getLongValue();
1435 _value.long_val = rawValue.clone();
1438 setLongValue(old_val);
1444 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1446 if (_type == ALIAS || _tied)
1449 useDefault = useDefault && hasValue();
1450 float old_val = 0.0;
1452 old_val = getFloatValue();
1457 _value.float_val = rawValue.clone();
1460 setFloatValue(old_val);
1466 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1468 if (_type == ALIAS || _tied)
1471 useDefault = useDefault && hasValue();
1472 double old_val = 0.0;
1474 old_val = getDoubleValue();
1479 _value.double_val = rawValue.clone();
1482 setDoubleValue(old_val);
1489 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1491 if (_type == ALIAS || _tied)
1494 useDefault = useDefault && hasValue();
1497 old_val = getStringValue();
1502 _value.string_val = rawValue.clone();
1505 setStringValue(old_val.c_str());
1511 SGPropertyNode::untie ()
1518 bool val = getBoolValue();
1521 _local_val.bool_val = val;
1525 int val = getIntValue();
1528 _local_val.int_val = val;
1532 long val = getLongValue();
1535 _local_val.long_val = val;
1539 float val = getFloatValue();
1542 _local_val.float_val = val;
1546 double val = getDoubleValue();
1549 _local_val.double_val = val;
1554 string val = getStringValue();
1557 _local_val.string_val = copy_string(val.c_str());
1570 SGPropertyNode::getRootNode ()
1575 return _parent->getRootNode();
1578 const SGPropertyNode *
1579 SGPropertyNode::getRootNode () const
1584 return _parent->getRootNode();
1588 SGPropertyNode::getNode (const char * relative_path, bool create)
1590 // if (_path_cache == 0)
1591 // _path_cache = new cache_map;
1593 // SGPropertyNode * result = (*_path_cache)[relative_path];
1594 // if (result == 0) {
1595 // vector<PathComponent> components;
1596 // parse_path(relative_path, components);
1597 // result = find_node(this, components, 0, create);
1599 // (*_path_cache)[relative_path] = result;
1603 vector<PathComponent> components;
1604 parse_path(relative_path, components);
1605 return find_node(this, components, 0, create);
1609 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1611 vector<PathComponent> components;
1612 parse_path(relative_path, components);
1613 if (components.size() > 0)
1614 components[components.size()-1].index = index;
1615 return find_node(this, components, 0, create);
1618 const SGPropertyNode *
1619 SGPropertyNode::getNode (const char * relative_path) const
1621 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1624 const SGPropertyNode *
1625 SGPropertyNode::getNode (const char * relative_path, int index) const
1627 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1631 ////////////////////////////////////////////////////////////////////////
1632 // Convenience methods using relative paths.
1633 ////////////////////////////////////////////////////////////////////////
1637 * Test whether another node has a value attached.
1640 SGPropertyNode::hasValue (const char * relative_path) const
1642 const SGPropertyNode * node = getNode(relative_path);
1643 return (node == 0 ? false : node->hasValue());
1648 * Get the value type for another node.
1650 SGPropertyNode::Type
1651 SGPropertyNode::getType (const char * relative_path) const
1653 const SGPropertyNode * node = getNode(relative_path);
1654 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1659 * Get a bool value for another node.
1662 SGPropertyNode::getBoolValue (const char * relative_path,
1663 bool defaultValue) const
1665 const SGPropertyNode * node = getNode(relative_path);
1666 return (node == 0 ? defaultValue : node->getBoolValue());
1671 * Get an int value for another node.
1674 SGPropertyNode::getIntValue (const char * relative_path,
1675 int defaultValue) const
1677 const SGPropertyNode * node = getNode(relative_path);
1678 return (node == 0 ? defaultValue : node->getIntValue());
1683 * Get a long value for another node.
1686 SGPropertyNode::getLongValue (const char * relative_path,
1687 long defaultValue) const
1689 const SGPropertyNode * node = getNode(relative_path);
1690 return (node == 0 ? defaultValue : node->getLongValue());
1695 * Get a float value for another node.
1698 SGPropertyNode::getFloatValue (const char * relative_path,
1699 float defaultValue) const
1701 const SGPropertyNode * node = getNode(relative_path);
1702 return (node == 0 ? defaultValue : node->getFloatValue());
1707 * Get a double value for another node.
1710 SGPropertyNode::getDoubleValue (const char * relative_path,
1711 double defaultValue) const
1713 const SGPropertyNode * node = getNode(relative_path);
1714 return (node == 0 ? defaultValue : node->getDoubleValue());
1719 * Get a string value for another node.
1722 SGPropertyNode::getStringValue (const char * relative_path,
1723 const char * defaultValue) const
1725 const SGPropertyNode * node = getNode(relative_path);
1726 return (node == 0 ? defaultValue : node->getStringValue());
1731 * Set a bool value for another node.
1734 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1736 return getNode(relative_path, true)->setBoolValue(value);
1741 * Set an int value for another node.
1744 SGPropertyNode::setIntValue (const char * relative_path, int value)
1746 return getNode(relative_path, true)->setIntValue(value);
1751 * Set a long value for another node.
1754 SGPropertyNode::setLongValue (const char * relative_path, long value)
1756 return getNode(relative_path, true)->setLongValue(value);
1761 * Set a float value for another node.
1764 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1766 return getNode(relative_path, true)->setFloatValue(value);
1771 * Set a double value for another node.
1774 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1776 return getNode(relative_path, true)->setDoubleValue(value);
1781 * Set a string value for another node.
1784 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1786 return getNode(relative_path, true)->setStringValue(value);
1791 * Set an unknown value for another node.
1794 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1797 return getNode(relative_path, true)->setUnspecifiedValue(value);
1802 * Test whether another node is tied.
1805 SGPropertyNode::isTied (const char * relative_path) const
1807 const SGPropertyNode * node = getNode(relative_path);
1808 return (node == 0 ? false : node->isTied());
1813 * Tie a node reached by a relative path, creating it if necessary.
1816 SGPropertyNode::tie (const char * relative_path,
1817 const SGRawValue<bool> &rawValue,
1820 return getNode(relative_path, true)->tie(rawValue, useDefault);
1825 * Tie a node reached by a relative path, creating it if necessary.
1828 SGPropertyNode::tie (const char * relative_path,
1829 const SGRawValue<int> &rawValue,
1832 return getNode(relative_path, true)->tie(rawValue, useDefault);
1837 * Tie a node reached by a relative path, creating it if necessary.
1840 SGPropertyNode::tie (const char * relative_path,
1841 const SGRawValue<long> &rawValue,
1844 return getNode(relative_path, true)->tie(rawValue, useDefault);
1849 * Tie a node reached by a relative path, creating it if necessary.
1852 SGPropertyNode::tie (const char * relative_path,
1853 const SGRawValue<float> &rawValue,
1856 return getNode(relative_path, true)->tie(rawValue, useDefault);
1861 * Tie a node reached by a relative path, creating it if necessary.
1864 SGPropertyNode::tie (const char * relative_path,
1865 const SGRawValue<double> &rawValue,
1868 return getNode(relative_path, true)->tie(rawValue, useDefault);
1873 * Tie a node reached by a relative path, creating it if necessary.
1876 SGPropertyNode::tie (const char * relative_path,
1877 const SGRawValue<const char *> &rawValue,
1880 return getNode(relative_path, true)->tie(rawValue, useDefault);
1885 * Attempt to untie another node reached by a relative path.
1888 SGPropertyNode::untie (const char * relative_path)
1890 SGPropertyNode * node = getNode(relative_path);
1891 return (node == 0 ? false : node->untie());