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>
33 ////////////////////////////////////////////////////////////////////////
35 ////////////////////////////////////////////////////////////////////////
38 * Comparator class for sorting by index.
43 int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
44 return (n1->getIndex() < n2->getIndex());
50 ////////////////////////////////////////////////////////////////////////
51 // Convenience macros for value access.
52 ////////////////////////////////////////////////////////////////////////
54 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
55 #define TEST_WRITE if (!getAttribute(WRITE)) return false
59 ////////////////////////////////////////////////////////////////////////
60 // Default values for every type.
61 ////////////////////////////////////////////////////////////////////////
63 const bool SGRawValue<bool>::DefaultValue = false;
64 const int SGRawValue<int>::DefaultValue = 0;
65 const long SGRawValue<long>::DefaultValue = 0L;
66 const float SGRawValue<float>::DefaultValue = 0.0;
67 const double SGRawValue<double>::DefaultValue = 0.0L;
68 const char * const SGRawValue<const char *>::DefaultValue = "";
72 ////////////////////////////////////////////////////////////////////////
73 // Local path normalization code.
74 ////////////////////////////////////////////////////////////////////////
77 * A component in a path.
86 * Parse the name for a path component.
88 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
90 static inline const string
91 parse_name (const string &path, int &i)
94 int max = path.size();
98 if (i < max && path[i] == '.') {
104 if (i < max && path[i] != '/')
105 throw string(string("Illegal character after ") + name);
108 else if (isalpha(path[i]) || path[i] == '_') {
112 // The rules inside a name are a little
115 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
116 path[i] == '-' || path[i] == '.') {
118 } else if (path[i] == '[' || path[i] == '/') {
121 throw string("name may contain only ._- and alphanumeric characters");
128 if (name.size() == 0)
129 throw string("name must begin with alpha or '_'");
137 * Parse the optional integer index for a path component.
139 * Index: "[" [0-9]+ "]"
142 parse_index (const string &path, int &i)
151 for (int max = path.size(); i < max; i++) {
152 if (isdigit(path[i])) {
153 index = (index * 10) + (path[i] - '0');
154 } else if (path[i] == ']') {
162 throw string("unterminated index (looking for ']')");
167 * Parse a single path component.
169 * Component: Name Index?
171 static inline PathComponent
172 parse_component (const string &path, int &i)
174 PathComponent component;
175 component.name = parse_name(path, i);
176 if (component.name[0] != '.')
177 component.index = parse_index(path, i);
179 component.index = -1;
185 * Parse a path into its components.
188 parse_path (const string &path, vector<PathComponent> &components)
191 int max = path.size();
193 // Check for initial '/'
194 if (path[pos] == '/') {
198 components.push_back(root);
200 while (pos < max && path[pos] == '/')
205 components.push_back(parse_component(path, pos));
206 while (pos < max && path[pos] == '/')
213 ////////////////////////////////////////////////////////////////////////
214 // Other static utility functions.
215 ////////////////////////////////////////////////////////////////////////
219 copy_string (const char * s)
221 // FIXME: potential buffer overflow.
222 // For some reason, strnlen and
223 // strncpy cause all kinds of crashes.
225 size_t len = strlen(s);
226 char * copy = new char[str.size() + 1];
227 strcpy(copy, str.c_str());
232 compare_strings (const char * s1, const char * s2)
234 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
238 * Locate a child node by name and index.
241 find_child (const char * name, int index, vector<SGPropertyNode *> nodes)
243 int nNodes = nodes.size();
244 for (int i = 0; i < nNodes; i++) {
245 SGPropertyNode * node = nodes[i];
246 if (compare_strings(node->getName(), name) && node->getIndex() == index)
254 * Locate another node, given a relative path.
256 static SGPropertyNode *
257 find_node (SGPropertyNode * current,
258 const vector<PathComponent> &components,
262 // Run off the end of the list
267 // Success! This is the one we want.
268 else if (position >= (int)components.size()) {
272 // Empty component means root.
273 else if (components[position].name == "") {
274 return find_node(current->getRootNode(), components, position + 1, create);
277 // . means current directory
278 else if (components[position].name == ".") {
279 return find_node(current, components, position + 1, create);
282 // .. means parent directory
283 else if (components[position].name == "..") {
284 SGPropertyNode * parent = current->getParent();
286 throw string("Attempt to move past root with '..'");
288 return find_node(parent, components, position + 1, create);
291 // Otherwise, a child name
293 SGPropertyNode * child =
294 current->getChild(components[position].name.c_str(),
295 components[position].index,
297 return find_node(child, components, position + 1, create);
303 ////////////////////////////////////////////////////////////////////////
304 // Private methods from SGPropertyNode (may be inlined for speed).
305 ////////////////////////////////////////////////////////////////////////
308 SGPropertyNode::get_bool () const
311 return _value.bool_val->getValue();
313 return _local_val.bool_val;
317 SGPropertyNode::get_int () const
320 return _value.int_val->getValue();
322 return _local_val.int_val;
326 SGPropertyNode::get_long () const
329 return _value.long_val->getValue();
331 return _local_val.long_val;
335 SGPropertyNode::get_float () const
338 return _value.float_val->getValue();
340 return _local_val.float_val;
344 SGPropertyNode::get_double () const
347 return _value.double_val->getValue();
349 return _local_val.double_val;
353 SGPropertyNode::get_string () const
356 return _value.string_val->getValue();
358 return _local_val.string_val;
362 SGPropertyNode::set_bool (bool val)
365 return _value.bool_val->setValue(val);
367 _local_val.bool_val = val;
373 SGPropertyNode::set_int (int val)
376 return _value.int_val->setValue(val);
378 _local_val.int_val = val;
384 SGPropertyNode::set_long (long val)
387 return _value.long_val->setValue(val);
389 _local_val.long_val = val;
395 SGPropertyNode::set_float (float val)
398 return _value.float_val->setValue(val);
400 _local_val.float_val = val;
406 SGPropertyNode::set_double (double val)
409 return _value.double_val->setValue(val);
411 _local_val.double_val = val;
417 SGPropertyNode::set_string (const char * val)
420 return _value.string_val->setValue(val);
422 delete _local_val.string_val;
423 _local_val.string_val = copy_string(val);
429 SGPropertyNode::clear_value ()
437 delete _value.bool_val;
439 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
442 delete _value.int_val;
444 _local_val.int_val = SGRawValue<int>::DefaultValue;
447 delete _value.long_val;
448 _value.long_val = 0L;
449 _local_val.long_val = SGRawValue<long>::DefaultValue;
452 delete _value.float_val;
453 _value.float_val = 0;
454 _local_val.float_val = SGRawValue<float>::DefaultValue;
457 delete _value.double_val;
458 _value.double_val = 0;
459 _local_val.double_val = SGRawValue<double>::DefaultValue;
463 delete _value.string_val;
464 _value.string_val = 0;
465 delete _local_val.string_val;
466 _local_val.string_val = 0;
475 * Get the value as a string.
478 SGPropertyNode::make_string () const
480 if (!getAttribute(READ))
485 return _value.alias->getStringValue();
492 sprintf(_buffer, "%d", get_int());
495 sprintf(_buffer, "%ld", get_long());
498 sprintf(_buffer, "%f", get_float());
501 sprintf(_buffer, "%f", get_double());
513 * Trace a write access for a property.
516 SGPropertyNode::trace_write () const
519 cerr << "TRACE: Write node " << getPath () << ", value\""
520 << make_string() << '"' << endl;
522 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
523 << ", value\"" << make_string() << '"');
528 * Trace a read access for a property.
531 SGPropertyNode::trace_read () const
534 cerr << "TRACE: Write node " << getPath () << ", value \""
535 << make_string() << '"' << endl;
537 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
538 << ", value \"" << make_string() << '"');
544 ////////////////////////////////////////////////////////////////////////
545 // Public methods from SGPropertyNode.
546 ////////////////////////////////////////////////////////////////////////
549 * Default constructor: always creates a root node.
551 SGPropertyNode::SGPropertyNode ()
552 : _name(copy_string("")),
560 _local_val.string_val = 0;
567 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
568 : _index(node._index),
569 _parent(0), // don't copy the parent
575 _name = copy_string(node._name);
576 _local_val.string_val = 0;
581 _value.alias = node._value.alias;
587 _value.bool_val = node._value.bool_val->clone();
590 set_bool(node.get_bool());
596 _value.int_val = node._value.int_val->clone();
599 set_int(node.get_int());
605 _value.long_val = node._value.long_val->clone();
608 set_long(node.get_long());
614 _value.float_val = node._value.float_val->clone();
617 set_float(node.get_float());
623 _value.double_val = node._value.double_val->clone();
626 set_double(node.get_double());
633 _value.string_val = node._value.string_val->clone();
636 set_string(node.get_string());
644 * Convenience constructor.
646 SGPropertyNode::SGPropertyNode (const char * name,
648 SGPropertyNode * parent)
656 _name = copy_string(name);
657 _local_val.string_val = 0;
664 SGPropertyNode::~SGPropertyNode ()
667 for (int i = 0; i < (int)_children.size(); i++) {
670 // delete _path_cache;
676 * Alias to another node.
679 SGPropertyNode::alias (SGPropertyNode * target)
681 if (target == 0 || _type == ALIAS || _tied)
684 _value.alias = target;
691 * Alias to another node by path.
694 SGPropertyNode::alias (const char * path)
696 return alias(getNode(path, true));
704 SGPropertyNode::unalias ()
715 * Get the target of an alias.
718 SGPropertyNode::getAliasTarget ()
720 return (_type == ALIAS ? _value.alias : 0);
724 const SGPropertyNode *
725 SGPropertyNode::getAliasTarget () const
727 return (_type == ALIAS ? _value.alias : 0);
732 * Get a non-const child by index.
735 SGPropertyNode::getChild (int position)
737 if (position >= 0 && position < nChildren())
738 return _children[position];
745 * Get a const child by index.
747 const SGPropertyNode *
748 SGPropertyNode::getChild (int position) const
750 if (position >= 0 && position < nChildren())
751 return _children[position];
758 * Get a non-const child by name and index, creating if necessary.
761 SGPropertyNode::getChild (const char * name, int index, bool create)
763 int pos = find_child(name, index, _children);
765 return _children[pos];
767 _children.push_back(new SGPropertyNode(name, index, this));
768 return _children[_children.size()-1];
776 * Get a const child by name and index.
778 const SGPropertyNode *
779 SGPropertyNode::getChild (const char * name, int index) const
781 int pos = find_child(name, index, _children);
783 return _children[pos];
790 * Get all children with the same name (but different indices).
792 vector<SGPropertyNode *>
793 SGPropertyNode::getChildren (const char * name)
795 vector<SGPropertyNode *> children;
796 int max = _children.size();
798 for (int i = 0; i < max; i++)
799 if (compare_strings(_children[i]->getName(), name))
800 children.push_back(_children[i]);
802 sort(children.begin(), children.end(), CompareIndices());
808 * Get all children const with the same name (but different indices).
810 vector<const SGPropertyNode *>
811 SGPropertyNode::getChildren (const char * name) const
813 vector<const SGPropertyNode *> children;
814 int max = _children.size();
816 for (int i = 0; i < max; i++)
817 if (compare_strings(_children[i]->getName(), name))
818 children.push_back(_children[i]);
820 sort(children.begin(), children.end(), CompareIndices());
826 SGPropertyNode::getPath (bool simplify) const
831 string path = _parent->getPath(simplify);
834 if (_index != 0 || !simplify) {
836 sprintf(buffer, "[%d]", _index);
843 SGPropertyNode::getType () const
846 return _value.alias->getType();
853 SGPropertyNode::getBoolValue () const
855 // Shortcut for common case
856 if (_attr == (READ|WRITE) && _type == BOOL)
859 if (getAttribute(TRACE_READ))
861 if (!getAttribute(READ))
862 return SGRawValue<bool>::DefaultValue;
865 return _value.alias->getBoolValue();
869 return get_int() == 0 ? false : true;
871 return get_long() == 0L ? false : true;
873 return get_float() == 0.0 ? false : true;
875 return get_double() == 0.0L ? false : true;
878 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
881 return SGRawValue<bool>::DefaultValue;
886 SGPropertyNode::getIntValue () const
888 // Shortcut for common case
889 if (_attr == (READ|WRITE) && _type == INT)
892 if (getAttribute(TRACE_READ))
894 if (!getAttribute(READ))
895 return SGRawValue<int>::DefaultValue;
898 return _value.alias->getIntValue();
900 return int(get_bool());
904 return int(get_long());
906 return int(get_float());
908 return int(get_double());
911 return atoi(get_string());
914 return SGRawValue<int>::DefaultValue;
919 SGPropertyNode::getLongValue () const
921 // Shortcut for common case
922 if (_attr == (READ|WRITE) && _type == LONG)
925 if (getAttribute(TRACE_READ))
927 if (!getAttribute(READ))
928 return SGRawValue<long>::DefaultValue;
931 return _value.alias->getLongValue();
933 return long(get_bool());
935 return long(get_int());
939 return long(get_float());
941 return long(get_double());
944 return strtol(get_string(), 0, 0);
947 return SGRawValue<long>::DefaultValue;
952 SGPropertyNode::getFloatValue () const
954 // Shortcut for common case
955 if (_attr == (READ|WRITE) && _type == FLOAT)
958 if (getAttribute(TRACE_READ))
960 if (!getAttribute(READ))
961 return SGRawValue<float>::DefaultValue;
964 return _value.alias->getFloatValue();
966 return float(get_bool());
968 return float(get_int());
970 return float(get_long());
974 return float(get_double());
977 return atof(get_string());
980 return SGRawValue<float>::DefaultValue;
985 SGPropertyNode::getDoubleValue () const
987 // Shortcut for common case
988 if (_attr == (READ|WRITE) && _type == DOUBLE)
991 if (getAttribute(TRACE_READ))
993 if (!getAttribute(READ))
994 return SGRawValue<double>::DefaultValue;
998 return _value.alias->getDoubleValue();
1000 return double(get_bool());
1002 return double(get_int());
1004 return double(get_long());
1006 return double(get_float());
1008 return get_double();
1011 return strtod(get_string(), 0);
1014 return SGRawValue<double>::DefaultValue;
1019 SGPropertyNode::getStringValue () const
1021 // Shortcut for common case
1022 if (_attr == (READ|WRITE) && _type == STRING)
1023 return get_string();
1025 if (getAttribute(TRACE_READ))
1027 if (!getAttribute(READ))
1028 return SGRawValue<const char *>::DefaultValue;
1029 return make_string();
1033 SGPropertyNode::setBoolValue (bool value)
1035 // Shortcut for common case
1036 if (_attr == (READ|WRITE) && _type == BOOL)
1037 return set_bool(value);
1039 bool result = false;
1041 if (_type == NONE || _type == UNSPECIFIED) {
1049 result = _value.alias->setBoolValue(value);
1052 result = set_bool(value);
1055 result = set_int(int(value));
1058 result = set_long(long(value));
1061 result = set_float(float(value));
1064 result = set_double(double(value));
1068 result = set_string(value ? "true" : "false");
1075 if (getAttribute(TRACE_WRITE))
1081 SGPropertyNode::setIntValue (int value)
1083 // Shortcut for common case
1084 if (_attr == (READ|WRITE) && _type == INT)
1085 return set_int(value);
1087 bool result = false;
1089 if (_type == NONE || _type == UNSPECIFIED) {
1092 _local_val.int_val = 0;
1097 result = _value.alias->setIntValue(value);
1100 result = set_bool(value == 0 ? false : true);
1103 result = set_int(value);
1106 result = set_long(long(value));
1109 result = set_float(float(value));
1112 result = set_double(double(value));
1117 sprintf(buf, "%d", value);
1118 result = set_string(buf);
1126 if (getAttribute(TRACE_WRITE))
1132 SGPropertyNode::setLongValue (long value)
1134 // Shortcut for common case
1135 if (_attr == (READ|WRITE) && _type == LONG)
1136 return set_long(value);
1138 bool result = false;
1140 if (_type == NONE || _type == UNSPECIFIED) {
1143 _local_val.long_val = 0L;
1148 result = _value.alias->setLongValue(value);
1151 result = set_bool(value == 0L ? false : true);
1154 result = set_int(int(value));
1157 result = set_long(value);
1160 result = set_float(float(value));
1163 result = set_double(double(value));
1168 sprintf(buf, "%ld", value);
1169 result = set_string(buf);
1177 if (getAttribute(TRACE_WRITE))
1183 SGPropertyNode::setFloatValue (float value)
1185 // Shortcut for common case
1186 if (_attr == (READ|WRITE) && _type == FLOAT)
1187 return set_float(value);
1189 bool result = false;
1191 if (_type == NONE || _type == UNSPECIFIED) {
1194 _local_val.float_val = 0;
1199 result = _value.alias->setFloatValue(value);
1202 result = set_bool(value == 0.0 ? false : true);
1205 result = set_int(int(value));
1208 result = set_long(long(value));
1211 result = set_float(value);
1214 result = set_double(double(value));
1219 sprintf(buf, "%f", value);
1220 result = set_string(buf);
1228 if (getAttribute(TRACE_WRITE))
1234 SGPropertyNode::setDoubleValue (double value)
1236 // Shortcut for common case
1237 if (_attr == (READ|WRITE) && _type == DOUBLE)
1238 return set_double(value);
1240 bool result = false;
1242 if (_type == NONE || _type == UNSPECIFIED) {
1244 _local_val.double_val = value;
1250 result = _value.alias->setDoubleValue(value);
1253 result = set_bool(value == 0.0L ? false : true);
1256 result = set_int(int(value));
1259 result = set_long(long(value));
1262 result = set_float(float(value));
1265 result = set_double(value);
1270 sprintf(buf, "%f", value);
1271 result = set_string(buf);
1279 if (getAttribute(TRACE_WRITE))
1285 SGPropertyNode::setStringValue (const char * value)
1287 // Shortcut for common case
1288 if (_attr == (READ|WRITE) && _type == STRING)
1289 return set_string(value);
1291 bool result = false;
1293 if (_type == NONE || _type == UNSPECIFIED) {
1300 result = _value.alias->setStringValue(value);
1303 result = set_bool((compare_strings(value, "true")
1304 || atoi(value)) ? true : false);
1307 result = set_int(atoi(value));
1310 result = set_long(strtol(value, 0, 0));
1313 result = set_float(atof(value));
1316 result = set_double(strtod(value, 0));
1320 result = set_string(value);
1327 if (getAttribute(TRACE_WRITE))
1333 SGPropertyNode::setUnspecifiedValue (const char * value)
1335 bool result = false;
1337 if (_type == NONE) {
1339 _type = UNSPECIFIED;
1344 result = _value.alias->setUnspecifiedValue(value);
1347 result = set_bool((compare_strings(value, "true")
1348 || atoi(value)) ? true : false);
1351 result = set_int(atoi(value));
1354 result = set_long(strtol(value, 0, 0));
1357 result = set_float(atof(value));
1360 result = set_double(strtod(value, 0));
1364 result = set_string(value);
1371 if (getAttribute(TRACE_WRITE))
1377 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1379 if (_type == ALIAS || _tied)
1382 useDefault = useDefault && hasValue();
1383 bool old_val = false;
1385 old_val = getBoolValue();
1390 _value.bool_val = rawValue.clone();
1393 setBoolValue(old_val);
1399 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1401 if (_type == ALIAS || _tied)
1404 useDefault = useDefault && hasValue();
1407 old_val = getIntValue();
1412 _value.int_val = rawValue.clone();
1415 setIntValue(old_val);
1421 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1423 if (_type == ALIAS || _tied)
1426 useDefault = useDefault && hasValue();
1429 old_val = getLongValue();
1434 _value.long_val = rawValue.clone();
1437 setLongValue(old_val);
1443 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1445 if (_type == ALIAS || _tied)
1448 useDefault = useDefault && hasValue();
1449 float old_val = 0.0;
1451 old_val = getFloatValue();
1456 _value.float_val = rawValue.clone();
1459 setFloatValue(old_val);
1465 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1467 if (_type == ALIAS || _tied)
1470 useDefault = useDefault && hasValue();
1471 double old_val = 0.0;
1473 old_val = getDoubleValue();
1478 _value.double_val = rawValue.clone();
1481 setDoubleValue(old_val);
1488 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1490 if (_type == ALIAS || _tied)
1493 useDefault = useDefault && hasValue();
1496 old_val = getStringValue();
1501 _value.string_val = rawValue.clone();
1504 setStringValue(old_val.c_str());
1510 SGPropertyNode::untie ()
1517 bool val = getBoolValue();
1520 _local_val.bool_val = val;
1524 int val = getIntValue();
1527 _local_val.int_val = val;
1531 long val = getLongValue();
1534 _local_val.long_val = val;
1538 float val = getFloatValue();
1541 _local_val.float_val = val;
1545 double val = getDoubleValue();
1548 _local_val.double_val = val;
1553 string val = getStringValue();
1556 _local_val.string_val = copy_string(val.c_str());
1569 SGPropertyNode::getRootNode ()
1574 return _parent->getRootNode();
1577 const SGPropertyNode *
1578 SGPropertyNode::getRootNode () const
1583 return _parent->getRootNode();
1587 SGPropertyNode::getNode (const char * relative_path, bool create)
1589 // if (_path_cache == 0)
1590 // _path_cache = new cache_map;
1592 // SGPropertyNode * result = (*_path_cache)[relative_path];
1593 // if (result == 0) {
1594 // vector<PathComponent> components;
1595 // parse_path(relative_path, components);
1596 // result = find_node(this, components, 0, create);
1598 // (*_path_cache)[relative_path] = result;
1602 vector<PathComponent> components;
1603 parse_path(relative_path, components);
1604 return find_node(this, components, 0, create);
1608 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1610 vector<PathComponent> components;
1611 parse_path(relative_path, components);
1612 if (components.size() > 0)
1613 components[components.size()-1].index = index;
1614 return find_node(this, components, 0, create);
1617 const SGPropertyNode *
1618 SGPropertyNode::getNode (const char * relative_path) const
1620 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1623 const SGPropertyNode *
1624 SGPropertyNode::getNode (const char * relative_path, int index) const
1626 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1630 ////////////////////////////////////////////////////////////////////////
1631 // Convenience methods using relative paths.
1632 ////////////////////////////////////////////////////////////////////////
1636 * Test whether another node has a value attached.
1639 SGPropertyNode::hasValue (const char * relative_path) const
1641 const SGPropertyNode * node = getNode(relative_path);
1642 return (node == 0 ? false : node->hasValue());
1647 * Get the value type for another node.
1649 SGPropertyNode::Type
1650 SGPropertyNode::getType (const char * relative_path) const
1652 const SGPropertyNode * node = getNode(relative_path);
1653 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1658 * Get a bool value for another node.
1661 SGPropertyNode::getBoolValue (const char * relative_path,
1662 bool defaultValue) const
1664 const SGPropertyNode * node = getNode(relative_path);
1665 return (node == 0 ? defaultValue : node->getBoolValue());
1670 * Get an int value for another node.
1673 SGPropertyNode::getIntValue (const char * relative_path,
1674 int defaultValue) const
1676 const SGPropertyNode * node = getNode(relative_path);
1677 return (node == 0 ? defaultValue : node->getIntValue());
1682 * Get a long value for another node.
1685 SGPropertyNode::getLongValue (const char * relative_path,
1686 long defaultValue) const
1688 const SGPropertyNode * node = getNode(relative_path);
1689 return (node == 0 ? defaultValue : node->getLongValue());
1694 * Get a float value for another node.
1697 SGPropertyNode::getFloatValue (const char * relative_path,
1698 float defaultValue) const
1700 const SGPropertyNode * node = getNode(relative_path);
1701 return (node == 0 ? defaultValue : node->getFloatValue());
1706 * Get a double value for another node.
1709 SGPropertyNode::getDoubleValue (const char * relative_path,
1710 double defaultValue) const
1712 const SGPropertyNode * node = getNode(relative_path);
1713 return (node == 0 ? defaultValue : node->getDoubleValue());
1718 * Get a string value for another node.
1721 SGPropertyNode::getStringValue (const char * relative_path,
1722 const char * defaultValue) const
1724 const SGPropertyNode * node = getNode(relative_path);
1725 return (node == 0 ? defaultValue : node->getStringValue());
1730 * Set a bool value for another node.
1733 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1735 return getNode(relative_path, true)->setBoolValue(value);
1740 * Set an int value for another node.
1743 SGPropertyNode::setIntValue (const char * relative_path, int value)
1745 return getNode(relative_path, true)->setIntValue(value);
1750 * Set a long value for another node.
1753 SGPropertyNode::setLongValue (const char * relative_path, long value)
1755 return getNode(relative_path, true)->setLongValue(value);
1760 * Set a float value for another node.
1763 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1765 return getNode(relative_path, true)->setFloatValue(value);
1770 * Set a double value for another node.
1773 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1775 return getNode(relative_path, true)->setDoubleValue(value);
1780 * Set a string value for another node.
1783 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1785 return getNode(relative_path, true)->setStringValue(value);
1790 * Set an unknown value for another node.
1793 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1796 return getNode(relative_path, true)->setUnspecifiedValue(value);
1801 * Test whether another node is tied.
1804 SGPropertyNode::isTied (const char * relative_path) const
1806 const SGPropertyNode * node = getNode(relative_path);
1807 return (node == 0 ? false : node->isTied());
1812 * Tie a node reached by a relative path, creating it if necessary.
1815 SGPropertyNode::tie (const char * relative_path,
1816 const SGRawValue<bool> &rawValue,
1819 return getNode(relative_path, true)->tie(rawValue, useDefault);
1824 * Tie a node reached by a relative path, creating it if necessary.
1827 SGPropertyNode::tie (const char * relative_path,
1828 const SGRawValue<int> &rawValue,
1831 return getNode(relative_path, true)->tie(rawValue, useDefault);
1836 * Tie a node reached by a relative path, creating it if necessary.
1839 SGPropertyNode::tie (const char * relative_path,
1840 const SGRawValue<long> &rawValue,
1843 return getNode(relative_path, true)->tie(rawValue, useDefault);
1848 * Tie a node reached by a relative path, creating it if necessary.
1851 SGPropertyNode::tie (const char * relative_path,
1852 const SGRawValue<float> &rawValue,
1855 return getNode(relative_path, true)->tie(rawValue, useDefault);
1860 * Tie a node reached by a relative path, creating it if necessary.
1863 SGPropertyNode::tie (const char * relative_path,
1864 const SGRawValue<double> &rawValue,
1867 return getNode(relative_path, true)->tie(rawValue, useDefault);
1872 * Tie a node reached by a relative path, creating it if necessary.
1875 SGPropertyNode::tie (const char * relative_path,
1876 const SGRawValue<const char *> &rawValue,
1879 return getNode(relative_path, true)->tie(rawValue, useDefault);
1884 * Attempt to untie another node reached by a relative path.
1887 SGPropertyNode::untie (const char * relative_path)
1889 SGPropertyNode * node = getNode(relative_path);
1890 return (node == 0 ? false : node->untie());