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>
33 ////////////////////////////////////////////////////////////////////////
35 ////////////////////////////////////////////////////////////////////////
38 * Comparator class for sorting by index.
43 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr 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.
224 char * copy = new char[strlen(s) + 1];
230 compare_strings (const char * s1, const char * s2)
232 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
236 * Locate a child node by name and index.
239 find_child (const char * name, int index, vector<SGPropertyNode_ptr> nodes)
241 int nNodes = nodes.size();
242 for (int i = 0; i < nNodes; i++) {
243 SGPropertyNode * node = nodes[i];
244 if (compare_strings(node->getName(), name) && node->getIndex() == index)
252 * Locate another node, given a relative path.
254 static SGPropertyNode *
255 find_node (SGPropertyNode * current,
256 const vector<PathComponent> &components,
260 // Run off the end of the list
265 // Success! This is the one we want.
266 else if (position >= (int)components.size()) {
270 // Empty component means root.
271 else if (components[position].name == "") {
272 return find_node(current->getRootNode(), components, position + 1, create);
275 // . means current directory
276 else if (components[position].name == ".") {
277 return find_node(current, components, position + 1, create);
280 // .. means parent directory
281 else if (components[position].name == "..") {
282 SGPropertyNode * parent = current->getParent();
284 throw string("Attempt to move past root with '..'");
286 return find_node(parent, components, position + 1, create);
289 // Otherwise, a child name
291 SGPropertyNode * child =
292 current->getChild(components[position].name.c_str(),
293 components[position].index,
295 return find_node(child, components, position + 1, create);
301 ////////////////////////////////////////////////////////////////////////
302 // Private methods from SGPropertyNode (may be inlined for speed).
303 ////////////////////////////////////////////////////////////////////////
306 SGPropertyNode::get_bool () const
309 return _value.bool_val->getValue();
311 return _local_val.bool_val;
315 SGPropertyNode::get_int () const
318 return _value.int_val->getValue();
320 return _local_val.int_val;
324 SGPropertyNode::get_long () const
327 return _value.long_val->getValue();
329 return _local_val.long_val;
333 SGPropertyNode::get_float () const
336 return _value.float_val->getValue();
338 return _local_val.float_val;
342 SGPropertyNode::get_double () const
345 return _value.double_val->getValue();
347 return _local_val.double_val;
351 SGPropertyNode::get_string () const
354 return _value.string_val->getValue();
356 return _local_val.string_val;
360 SGPropertyNode::set_bool (bool val)
363 return _value.bool_val->setValue(val);
365 _local_val.bool_val = val;
371 SGPropertyNode::set_int (int val)
374 return _value.int_val->setValue(val);
376 _local_val.int_val = val;
382 SGPropertyNode::set_long (long val)
385 return _value.long_val->setValue(val);
387 _local_val.long_val = val;
393 SGPropertyNode::set_float (float val)
396 return _value.float_val->setValue(val);
398 _local_val.float_val = val;
404 SGPropertyNode::set_double (double val)
407 return _value.double_val->setValue(val);
409 _local_val.double_val = val;
415 SGPropertyNode::set_string (const char * val)
418 return _value.string_val->setValue(val);
420 delete [] _local_val.string_val;
421 _local_val.string_val = copy_string(val);
427 SGPropertyNode::clear_value ()
437 delete _value.bool_val;
440 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
444 delete _value.int_val;
447 _local_val.int_val = SGRawValue<int>::DefaultValue;
451 delete _value.long_val;
452 _value.long_val = 0L;
454 _local_val.long_val = SGRawValue<long>::DefaultValue;
458 delete _value.float_val;
459 _value.float_val = 0;
461 _local_val.float_val = SGRawValue<float>::DefaultValue;
465 delete _value.double_val;
466 _value.double_val = 0;
468 _local_val.double_val = SGRawValue<double>::DefaultValue;
473 delete _value.string_val;
474 _value.string_val = 0;
476 delete [] _local_val.string_val;
478 _local_val.string_val = 0;
487 * Get the value as a string.
490 SGPropertyNode::make_string () const
492 if (!getAttribute(READ))
497 return _value.alias->getStringValue();
504 sprintf(_buffer, "%d", get_int());
507 sprintf(_buffer, "%ld", get_long());
510 sprintf(_buffer, "%f", get_float());
513 sprintf(_buffer, "%f", get_double());
525 * Trace a write access for a property.
528 SGPropertyNode::trace_write () const
531 cerr << "TRACE: Write node " << getPath () << ", value\""
532 << make_string() << '"' << endl;
534 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
535 << ", value\"" << make_string() << '"');
540 * Trace a read access for a property.
543 SGPropertyNode::trace_read () const
546 cerr << "TRACE: Write node " << getPath () << ", value \""
547 << make_string() << '"' << endl;
549 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
550 << ", value \"" << make_string() << '"');
555 * Increment reference counter
558 SGPropertyNode::incrementRef()
564 * Decrement reference counter
567 SGPropertyNode::decrementRef()
574 ////////////////////////////////////////////////////////////////////////
575 // Public methods from SGPropertyNode.
576 ////////////////////////////////////////////////////////////////////////
579 * Last used attribute
580 * Update as needed when enum Attribute is changed
582 const int SGPropertyNode::LAST_USED_ATTRIBUTE = TRACE_WRITE;
585 * Default constructor: always creates a root node.
587 SGPropertyNode::SGPropertyNode ()
588 : _name(copy_string("")),
597 _local_val.string_val = 0;
604 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
605 : _index(node._index),
606 _parent(0), // don't copy the parent
613 _name = copy_string(node._name);
614 _local_val.string_val = 0;
619 _value.alias = node._value.alias;
625 _value.bool_val = node._value.bool_val->clone();
628 set_bool(node.get_bool());
634 _value.int_val = node._value.int_val->clone();
637 set_int(node.get_int());
643 _value.long_val = node._value.long_val->clone();
646 set_long(node.get_long());
652 _value.float_val = node._value.float_val->clone();
655 set_float(node.get_float());
661 _value.double_val = node._value.double_val->clone();
664 set_double(node.get_double());
671 _value.string_val = node._value.string_val->clone();
674 set_string(node.get_string());
682 * Convenience constructor.
684 SGPropertyNode::SGPropertyNode (const char * name,
686 SGPropertyNode * parent)
695 _name = copy_string(name);
696 _local_val.string_val = 0;
703 SGPropertyNode::~SGPropertyNode ()
712 * Alias to another node.
715 SGPropertyNode::alias (SGPropertyNode * target)
717 if (target == 0 || _type == ALIAS || _tied)
720 _value.alias = target;
727 * Alias to another node by path.
730 SGPropertyNode::alias (const char * path)
732 return alias(getNode(path, true));
740 SGPropertyNode::unalias ()
751 * Get the target of an alias.
754 SGPropertyNode::getAliasTarget ()
756 return (_type == ALIAS ? _value.alias : 0);
760 const SGPropertyNode *
761 SGPropertyNode::getAliasTarget () const
763 return (_type == ALIAS ? _value.alias : 0);
768 * Get a non-const child by index.
771 SGPropertyNode::getChild (int position)
773 if (position >= 0 && position < nChildren())
774 return _children[position];
781 * Get a const child by index.
783 const SGPropertyNode *
784 SGPropertyNode::getChild (int position) const
786 if (position >= 0 && position < nChildren())
787 return _children[position];
794 * Get a non-const child by name and index, creating if necessary.
797 SGPropertyNode::getChild (const char * name, int index, bool create)
799 int pos = find_child(name, index, _children);
801 return _children[pos];
803 SGPropertyNode_ptr node;
804 pos = find_child(name, index, _removedChildren);
806 std::vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
808 node = _removedChildren[pos];
809 _removedChildren.erase(it);
810 node->setAttribute(REMOVED, false);
812 node = new SGPropertyNode(name, index, this);
814 _children.push_back(node);
815 return _children[_children.size()-1];
823 * Get a const child by name and index.
825 const SGPropertyNode *
826 SGPropertyNode::getChild (const char * name, int index) const
828 int pos = find_child(name, index, _children);
830 return _children[pos];
837 * Get all children with the same name (but different indices).
839 vector<SGPropertyNode_ptr>
840 SGPropertyNode::getChildren (const char * name) const
842 vector<SGPropertyNode_ptr> children;
843 int max = _children.size();
845 for (int i = 0; i < max; i++)
846 if (compare_strings(_children[i]->getName(), name))
847 children.push_back(_children[i]);
849 sort(children.begin(), children.end(), CompareIndices());
855 * Remove a child node
858 SGPropertyNode::removeChild (const char * name, int index, bool keep)
860 SGPropertyNode_ptr ret;
861 int pos = find_child(name, index, _children);
863 std::vector<SGPropertyNode_ptr>::iterator it = _children.begin();
865 SGPropertyNode_ptr node = _children[pos];
868 _removedChildren.push_back(node);
870 node->setAttribute(REMOVED, true);
878 SGPropertyNode::getPath (bool simplify) const
883 string path = _parent->getPath(simplify);
886 if (_index != 0 || !simplify) {
888 sprintf(buffer, "[%d]", _index);
895 SGPropertyNode::getType () const
898 return _value.alias->getType();
905 SGPropertyNode::getBoolValue () const
907 // Shortcut for common case
908 if (_attr == (READ|WRITE) && _type == BOOL)
911 if (getAttribute(TRACE_READ))
913 if (!getAttribute(READ))
914 return SGRawValue<bool>::DefaultValue;
917 return _value.alias->getBoolValue();
921 return get_int() == 0 ? false : true;
923 return get_long() == 0L ? false : true;
925 return get_float() == 0.0 ? false : true;
927 return get_double() == 0.0L ? false : true;
930 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
933 return SGRawValue<bool>::DefaultValue;
938 SGPropertyNode::getIntValue () const
940 // Shortcut for common case
941 if (_attr == (READ|WRITE) && _type == INT)
944 if (getAttribute(TRACE_READ))
946 if (!getAttribute(READ))
947 return SGRawValue<int>::DefaultValue;
950 return _value.alias->getIntValue();
952 return int(get_bool());
956 return int(get_long());
958 return int(get_float());
960 return int(get_double());
963 return atoi(get_string());
966 return SGRawValue<int>::DefaultValue;
971 SGPropertyNode::getLongValue () const
973 // Shortcut for common case
974 if (_attr == (READ|WRITE) && _type == LONG)
977 if (getAttribute(TRACE_READ))
979 if (!getAttribute(READ))
980 return SGRawValue<long>::DefaultValue;
983 return _value.alias->getLongValue();
985 return long(get_bool());
987 return long(get_int());
991 return long(get_float());
993 return long(get_double());
996 return strtol(get_string(), 0, 0);
999 return SGRawValue<long>::DefaultValue;
1004 SGPropertyNode::getFloatValue () const
1006 // Shortcut for common case
1007 if (_attr == (READ|WRITE) && _type == FLOAT)
1010 if (getAttribute(TRACE_READ))
1012 if (!getAttribute(READ))
1013 return SGRawValue<float>::DefaultValue;
1016 return _value.alias->getFloatValue();
1018 return float(get_bool());
1020 return float(get_int());
1022 return float(get_long());
1026 return float(get_double());
1029 return atof(get_string());
1032 return SGRawValue<float>::DefaultValue;
1037 SGPropertyNode::getDoubleValue () const
1039 // Shortcut for common case
1040 if (_attr == (READ|WRITE) && _type == DOUBLE)
1041 return get_double();
1043 if (getAttribute(TRACE_READ))
1045 if (!getAttribute(READ))
1046 return SGRawValue<double>::DefaultValue;
1050 return _value.alias->getDoubleValue();
1052 return double(get_bool());
1054 return double(get_int());
1056 return double(get_long());
1058 return double(get_float());
1060 return get_double();
1063 return strtod(get_string(), 0);
1066 return SGRawValue<double>::DefaultValue;
1071 SGPropertyNode::getStringValue () const
1073 // Shortcut for common case
1074 if (_attr == (READ|WRITE) && _type == STRING)
1075 return get_string();
1077 if (getAttribute(TRACE_READ))
1079 if (!getAttribute(READ))
1080 return SGRawValue<const char *>::DefaultValue;
1081 return make_string();
1085 SGPropertyNode::setBoolValue (bool value)
1087 // Shortcut for common case
1088 if (_attr == (READ|WRITE) && _type == BOOL)
1089 return set_bool(value);
1091 bool result = false;
1093 if (_type == NONE || _type == UNSPECIFIED) {
1101 result = _value.alias->setBoolValue(value);
1104 result = set_bool(value);
1107 result = set_int(int(value));
1110 result = set_long(long(value));
1113 result = set_float(float(value));
1116 result = set_double(double(value));
1120 result = set_string(value ? "true" : "false");
1127 if (getAttribute(TRACE_WRITE))
1133 SGPropertyNode::setIntValue (int value)
1135 // Shortcut for common case
1136 if (_attr == (READ|WRITE) && _type == INT)
1137 return set_int(value);
1139 bool result = false;
1141 if (_type == NONE || _type == UNSPECIFIED) {
1144 _local_val.int_val = 0;
1149 result = _value.alias->setIntValue(value);
1152 result = set_bool(value == 0 ? false : true);
1155 result = set_int(value);
1158 result = set_long(long(value));
1161 result = set_float(float(value));
1164 result = set_double(double(value));
1169 sprintf(buf, "%d", value);
1170 result = set_string(buf);
1178 if (getAttribute(TRACE_WRITE))
1184 SGPropertyNode::setLongValue (long value)
1186 // Shortcut for common case
1187 if (_attr == (READ|WRITE) && _type == LONG)
1188 return set_long(value);
1190 bool result = false;
1192 if (_type == NONE || _type == UNSPECIFIED) {
1195 _local_val.long_val = 0L;
1200 result = _value.alias->setLongValue(value);
1203 result = set_bool(value == 0L ? false : true);
1206 result = set_int(int(value));
1209 result = set_long(value);
1212 result = set_float(float(value));
1215 result = set_double(double(value));
1220 sprintf(buf, "%ld", value);
1221 result = set_string(buf);
1229 if (getAttribute(TRACE_WRITE))
1235 SGPropertyNode::setFloatValue (float value)
1237 // Shortcut for common case
1238 if (_attr == (READ|WRITE) && _type == FLOAT)
1239 return set_float(value);
1241 bool result = false;
1243 if (_type == NONE || _type == UNSPECIFIED) {
1246 _local_val.float_val = 0;
1251 result = _value.alias->setFloatValue(value);
1254 result = set_bool(value == 0.0 ? false : true);
1257 result = set_int(int(value));
1260 result = set_long(long(value));
1263 result = set_float(value);
1266 result = set_double(double(value));
1271 sprintf(buf, "%f", value);
1272 result = set_string(buf);
1280 if (getAttribute(TRACE_WRITE))
1286 SGPropertyNode::setDoubleValue (double value)
1288 // Shortcut for common case
1289 if (_attr == (READ|WRITE) && _type == DOUBLE)
1290 return set_double(value);
1292 bool result = false;
1294 if (_type == NONE || _type == UNSPECIFIED) {
1296 _local_val.double_val = value;
1302 result = _value.alias->setDoubleValue(value);
1305 result = set_bool(value == 0.0L ? false : true);
1308 result = set_int(int(value));
1311 result = set_long(long(value));
1314 result = set_float(float(value));
1317 result = set_double(value);
1322 sprintf(buf, "%f", value);
1323 result = set_string(buf);
1331 if (getAttribute(TRACE_WRITE))
1337 SGPropertyNode::setStringValue (const char * value)
1339 // Shortcut for common case
1340 if (_attr == (READ|WRITE) && _type == STRING)
1341 return set_string(value);
1343 bool result = false;
1345 if (_type == NONE || _type == UNSPECIFIED) {
1352 result = _value.alias->setStringValue(value);
1355 result = set_bool((compare_strings(value, "true")
1356 || atoi(value)) ? true : false);
1359 result = set_int(atoi(value));
1362 result = set_long(strtol(value, 0, 0));
1365 result = set_float(atof(value));
1368 result = set_double(strtod(value, 0));
1372 result = set_string(value);
1379 if (getAttribute(TRACE_WRITE))
1385 SGPropertyNode::setUnspecifiedValue (const char * value)
1387 bool result = false;
1389 if (_type == NONE) {
1391 _type = UNSPECIFIED;
1396 result = _value.alias->setUnspecifiedValue(value);
1399 result = set_bool((compare_strings(value, "true")
1400 || atoi(value)) ? true : false);
1403 result = set_int(atoi(value));
1406 result = set_long(strtol(value, 0, 0));
1409 result = set_float(atof(value));
1412 result = set_double(strtod(value, 0));
1416 result = set_string(value);
1423 if (getAttribute(TRACE_WRITE))
1429 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1431 if (_type == ALIAS || _tied)
1434 useDefault = useDefault && hasValue();
1435 bool old_val = false;
1437 old_val = getBoolValue();
1442 _value.bool_val = rawValue.clone();
1445 setBoolValue(old_val);
1451 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1453 if (_type == ALIAS || _tied)
1456 useDefault = useDefault && hasValue();
1459 old_val = getIntValue();
1464 _value.int_val = rawValue.clone();
1467 setIntValue(old_val);
1473 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1475 if (_type == ALIAS || _tied)
1478 useDefault = useDefault && hasValue();
1481 old_val = getLongValue();
1486 _value.long_val = rawValue.clone();
1489 setLongValue(old_val);
1495 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1497 if (_type == ALIAS || _tied)
1500 useDefault = useDefault && hasValue();
1501 float old_val = 0.0;
1503 old_val = getFloatValue();
1508 _value.float_val = rawValue.clone();
1511 setFloatValue(old_val);
1517 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1519 if (_type == ALIAS || _tied)
1522 useDefault = useDefault && hasValue();
1523 double old_val = 0.0;
1525 old_val = getDoubleValue();
1530 _value.double_val = rawValue.clone();
1533 setDoubleValue(old_val);
1540 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1542 if (_type == ALIAS || _tied)
1545 useDefault = useDefault && hasValue();
1548 old_val = getStringValue();
1553 _value.string_val = rawValue.clone();
1556 setStringValue(old_val.c_str());
1562 SGPropertyNode::untie ()
1569 bool val = getBoolValue();
1572 _local_val.bool_val = val;
1576 int val = getIntValue();
1579 _local_val.int_val = val;
1583 long val = getLongValue();
1586 _local_val.long_val = val;
1590 float val = getFloatValue();
1593 _local_val.float_val = val;
1597 double val = getDoubleValue();
1600 _local_val.double_val = val;
1605 string val = getStringValue();
1608 _local_val.string_val = copy_string(val.c_str());
1621 SGPropertyNode::getRootNode ()
1626 return _parent->getRootNode();
1629 const SGPropertyNode *
1630 SGPropertyNode::getRootNode () const
1635 return _parent->getRootNode();
1639 SGPropertyNode::getNode (const char * relative_path, bool create)
1641 if (_path_cache == 0)
1642 _path_cache = new hash_table;
1644 SGPropertyNode * result = _path_cache->get(relative_path);
1646 vector<PathComponent> components;
1647 parse_path(relative_path, components);
1648 result = find_node(this, components, 0, create);
1650 _path_cache->put(relative_path, result);
1657 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1659 vector<PathComponent> components;
1660 parse_path(relative_path, components);
1661 if (components.size() > 0)
1662 components[components.size()-1].index = index;
1663 return find_node(this, components, 0, create);
1666 const SGPropertyNode *
1667 SGPropertyNode::getNode (const char * relative_path) const
1669 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1672 const SGPropertyNode *
1673 SGPropertyNode::getNode (const char * relative_path, int index) const
1675 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1679 ////////////////////////////////////////////////////////////////////////
1680 // Convenience methods using relative paths.
1681 ////////////////////////////////////////////////////////////////////////
1685 * Test whether another node has a value attached.
1688 SGPropertyNode::hasValue (const char * relative_path) const
1690 const SGPropertyNode * node = getNode(relative_path);
1691 return (node == 0 ? false : node->hasValue());
1696 * Get the value type for another node.
1698 SGPropertyNode::Type
1699 SGPropertyNode::getType (const char * relative_path) const
1701 const SGPropertyNode * node = getNode(relative_path);
1702 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1707 * Get a bool value for another node.
1710 SGPropertyNode::getBoolValue (const char * relative_path,
1711 bool defaultValue) const
1713 const SGPropertyNode * node = getNode(relative_path);
1714 return (node == 0 ? defaultValue : node->getBoolValue());
1719 * Get an int value for another node.
1722 SGPropertyNode::getIntValue (const char * relative_path,
1723 int defaultValue) const
1725 const SGPropertyNode * node = getNode(relative_path);
1726 return (node == 0 ? defaultValue : node->getIntValue());
1731 * Get a long value for another node.
1734 SGPropertyNode::getLongValue (const char * relative_path,
1735 long defaultValue) const
1737 const SGPropertyNode * node = getNode(relative_path);
1738 return (node == 0 ? defaultValue : node->getLongValue());
1743 * Get a float value for another node.
1746 SGPropertyNode::getFloatValue (const char * relative_path,
1747 float defaultValue) const
1749 const SGPropertyNode * node = getNode(relative_path);
1750 return (node == 0 ? defaultValue : node->getFloatValue());
1755 * Get a double value for another node.
1758 SGPropertyNode::getDoubleValue (const char * relative_path,
1759 double defaultValue) const
1761 const SGPropertyNode * node = getNode(relative_path);
1762 return (node == 0 ? defaultValue : node->getDoubleValue());
1767 * Get a string value for another node.
1770 SGPropertyNode::getStringValue (const char * relative_path,
1771 const char * defaultValue) const
1773 const SGPropertyNode * node = getNode(relative_path);
1774 return (node == 0 ? defaultValue : node->getStringValue());
1779 * Set a bool value for another node.
1782 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1784 return getNode(relative_path, true)->setBoolValue(value);
1789 * Set an int value for another node.
1792 SGPropertyNode::setIntValue (const char * relative_path, int value)
1794 return getNode(relative_path, true)->setIntValue(value);
1799 * Set a long value for another node.
1802 SGPropertyNode::setLongValue (const char * relative_path, long value)
1804 return getNode(relative_path, true)->setLongValue(value);
1809 * Set a float value for another node.
1812 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1814 return getNode(relative_path, true)->setFloatValue(value);
1819 * Set a double value for another node.
1822 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1824 return getNode(relative_path, true)->setDoubleValue(value);
1829 * Set a string value for another node.
1832 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1834 return getNode(relative_path, true)->setStringValue(value);
1839 * Set an unknown value for another node.
1842 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1845 return getNode(relative_path, true)->setUnspecifiedValue(value);
1850 * Test whether another node is tied.
1853 SGPropertyNode::isTied (const char * relative_path) const
1855 const SGPropertyNode * node = getNode(relative_path);
1856 return (node == 0 ? false : node->isTied());
1861 * Tie a node reached by a relative path, creating it if necessary.
1864 SGPropertyNode::tie (const char * relative_path,
1865 const SGRawValue<bool> &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<int> &rawValue,
1880 return getNode(relative_path, true)->tie(rawValue, useDefault);
1885 * Tie a node reached by a relative path, creating it if necessary.
1888 SGPropertyNode::tie (const char * relative_path,
1889 const SGRawValue<long> &rawValue,
1892 return getNode(relative_path, true)->tie(rawValue, useDefault);
1897 * Tie a node reached by a relative path, creating it if necessary.
1900 SGPropertyNode::tie (const char * relative_path,
1901 const SGRawValue<float> &rawValue,
1904 return getNode(relative_path, true)->tie(rawValue, useDefault);
1909 * Tie a node reached by a relative path, creating it if necessary.
1912 SGPropertyNode::tie (const char * relative_path,
1913 const SGRawValue<double> &rawValue,
1916 return getNode(relative_path, true)->tie(rawValue, useDefault);
1921 * Tie a node reached by a relative path, creating it if necessary.
1924 SGPropertyNode::tie (const char * relative_path,
1925 const SGRawValue<const char *> &rawValue,
1928 return getNode(relative_path, true)->tie(rawValue, useDefault);
1933 * Attempt to untie another node reached by a relative path.
1936 SGPropertyNode::untie (const char * relative_path)
1938 SGPropertyNode * node = getNode(relative_path);
1939 return (node == 0 ? false : node->untie());
1944 ////////////////////////////////////////////////////////////////////////
1945 // Simplified hash table for caching paths.
1946 ////////////////////////////////////////////////////////////////////////
1948 #define HASH_TABLE_SIZE 199
1950 SGPropertyNode::hash_table::entry::entry ()
1956 SGPropertyNode::hash_table::entry::~entry ()
1958 // Don't delete the value; we don't own
1964 SGPropertyNode::hash_table::entry::set_key (const char * key)
1966 _key = copy_string(key);
1970 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
1975 SGPropertyNode::hash_table::bucket::bucket ()
1981 SGPropertyNode::hash_table::bucket::~bucket ()
1983 for (int i = 0; i < _length; i++)
1987 SGPropertyNode::hash_table::entry *
1988 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
1991 for (i = 0; i < _length; i++) {
1992 if (!strcmp(_entries[i]->get_key(), key))
1996 entry ** new_entries = new entry*[_length+1];
1997 for (i = 0; i < _length; i++) {
1998 new_entries[i] = _entries[i];
2001 _entries = new_entries;
2002 _entries[_length] = new entry;
2003 _entries[_length]->set_key(key);
2005 return _entries[_length - 1];
2012 SGPropertyNode::hash_table::hash_table ()
2018 SGPropertyNode::hash_table::~hash_table ()
2020 for (unsigned int i = 0; i < _data_length; i++)
2025 SGPropertyNode::hash_table::get (const char * key)
2027 if (_data_length == 0)
2029 unsigned int index = hashcode(key) % _data_length;
2030 if (_data[index] == 0)
2032 entry * e = _data[index]->get_entry(key);
2036 return e->get_value();
2040 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2042 if (_data_length == 0) {
2043 _data = new bucket*[HASH_TABLE_SIZE];
2044 _data_length = HASH_TABLE_SIZE;
2045 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2048 unsigned int index = hashcode(key) % _data_length;
2049 if (_data[index] == 0) {
2050 _data[index] = new bucket;
2052 entry * e = _data[index]->get_entry(key, true);
2053 e->set_value(value);
2057 SGPropertyNode::hash_table::hashcode (const char * key)
2059 unsigned int hash = 0;
2061 hash = 31 * hash + *key;
2070 * Default constructor
2072 SGPropertyNode_ptr::SGPropertyNode_ptr()
2080 SGPropertyNode_ptr::SGPropertyNode_ptr( const SGPropertyNode_ptr &r )
2084 _ptr->incrementRef();
2088 * Constructor from a pointer to a node
2090 SGPropertyNode_ptr::SGPropertyNode_ptr( SGPropertyNode *p )
2094 _ptr->incrementRef();
2100 SGPropertyNode_ptr::~SGPropertyNode_ptr()
2102 if (_ptr && _ptr->decrementRef() == 0)
2107 * Assignement operator
2109 SGPropertyNode_ptr &
2110 SGPropertyNode_ptr::operator=( const SGPropertyNode_ptr &r )
2112 if (_ptr && _ptr->decrementRef() == 0)
2116 _ptr->incrementRef();
2122 * Pointer access operator
2125 SGPropertyNode_ptr::operator->()
2131 * Pointer access operator (const)
2133 const SGPropertyNode *
2134 SGPropertyNode_ptr::operator->() const
2140 * Conversion to SGPropertyNode * operator
2142 SGPropertyNode_ptr::operator SGPropertyNode *()
2148 * Conversion to const SGPropertyNode * operator
2150 SGPropertyNode_ptr::operator const SGPropertyNode *() const
2159 SGPropertyNode_ptr::valid() const