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 * 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.
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 *> 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() << '"');
556 ////////////////////////////////////////////////////////////////////////
557 // Public methods from SGPropertyNode.
558 ////////////////////////////////////////////////////////////////////////
561 * Default constructor: always creates a root node.
563 SGPropertyNode::SGPropertyNode ()
564 : _name(copy_string("")),
572 _local_val.string_val = 0;
579 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
580 : _index(node._index),
581 _parent(0), // don't copy the parent
587 _name = copy_string(node._name);
588 _local_val.string_val = 0;
593 _value.alias = node._value.alias;
599 _value.bool_val = node._value.bool_val->clone();
602 set_bool(node.get_bool());
608 _value.int_val = node._value.int_val->clone();
611 set_int(node.get_int());
617 _value.long_val = node._value.long_val->clone();
620 set_long(node.get_long());
626 _value.float_val = node._value.float_val->clone();
629 set_float(node.get_float());
635 _value.double_val = node._value.double_val->clone();
638 set_double(node.get_double());
645 _value.string_val = node._value.string_val->clone();
648 set_string(node.get_string());
656 * Convenience constructor.
658 SGPropertyNode::SGPropertyNode (const char * name,
660 SGPropertyNode * parent)
668 _name = copy_string(name);
669 _local_val.string_val = 0;
676 SGPropertyNode::~SGPropertyNode ()
679 for (int i = 0; i < (int)_children.size(); i++) {
688 * Alias to another node.
691 SGPropertyNode::alias (SGPropertyNode * target)
693 if (target == 0 || _type == ALIAS || _tied)
696 _value.alias = target;
703 * Alias to another node by path.
706 SGPropertyNode::alias (const char * path)
708 return alias(getNode(path, true));
716 SGPropertyNode::unalias ()
727 * Get the target of an alias.
730 SGPropertyNode::getAliasTarget ()
732 return (_type == ALIAS ? _value.alias : 0);
736 const SGPropertyNode *
737 SGPropertyNode::getAliasTarget () const
739 return (_type == ALIAS ? _value.alias : 0);
744 * Get a non-const child by index.
747 SGPropertyNode::getChild (int position)
749 if (position >= 0 && position < nChildren())
750 return _children[position];
757 * Get a const child by index.
759 const SGPropertyNode *
760 SGPropertyNode::getChild (int position) const
762 if (position >= 0 && position < nChildren())
763 return _children[position];
770 * Get a non-const child by name and index, creating if necessary.
773 SGPropertyNode::getChild (const char * name, int index, bool create)
775 int pos = find_child(name, index, _children);
777 return _children[pos];
779 _children.push_back(new SGPropertyNode(name, index, this));
780 return _children[_children.size()-1];
788 * Get a const child by name and index.
790 const SGPropertyNode *
791 SGPropertyNode::getChild (const char * name, int index) const
793 int pos = find_child(name, index, _children);
795 return _children[pos];
802 * Get all children with the same name (but different indices).
804 vector<SGPropertyNode *>
805 SGPropertyNode::getChildren (const char * name)
807 vector<SGPropertyNode *> children;
808 int max = _children.size();
810 for (int i = 0; i < max; i++)
811 if (compare_strings(_children[i]->getName(), name))
812 children.push_back(_children[i]);
814 sort(children.begin(), children.end(), CompareIndices());
820 * Get all children const with the same name (but different indices).
822 vector<const SGPropertyNode *>
823 SGPropertyNode::getChildren (const char * name) const
825 vector<const SGPropertyNode *> children;
826 int max = _children.size();
828 for (int i = 0; i < max; i++)
829 if (compare_strings(_children[i]->getName(), name))
830 children.push_back(_children[i]);
832 sort(children.begin(), children.end(), CompareIndices());
838 SGPropertyNode::getPath (bool simplify) const
843 string path = _parent->getPath(simplify);
846 if (_index != 0 || !simplify) {
848 sprintf(buffer, "[%d]", _index);
855 SGPropertyNode::getType () const
858 return _value.alias->getType();
865 SGPropertyNode::getBoolValue () const
867 // Shortcut for common case
868 if (_attr == (READ|WRITE) && _type == BOOL)
871 if (getAttribute(TRACE_READ))
873 if (!getAttribute(READ))
874 return SGRawValue<bool>::DefaultValue;
877 return _value.alias->getBoolValue();
881 return get_int() == 0 ? false : true;
883 return get_long() == 0L ? false : true;
885 return get_float() == 0.0 ? false : true;
887 return get_double() == 0.0L ? false : true;
890 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
893 return SGRawValue<bool>::DefaultValue;
898 SGPropertyNode::getIntValue () const
900 // Shortcut for common case
901 if (_attr == (READ|WRITE) && _type == INT)
904 if (getAttribute(TRACE_READ))
906 if (!getAttribute(READ))
907 return SGRawValue<int>::DefaultValue;
910 return _value.alias->getIntValue();
912 return int(get_bool());
916 return int(get_long());
918 return int(get_float());
920 return int(get_double());
923 return atoi(get_string());
926 return SGRawValue<int>::DefaultValue;
931 SGPropertyNode::getLongValue () const
933 // Shortcut for common case
934 if (_attr == (READ|WRITE) && _type == LONG)
937 if (getAttribute(TRACE_READ))
939 if (!getAttribute(READ))
940 return SGRawValue<long>::DefaultValue;
943 return _value.alias->getLongValue();
945 return long(get_bool());
947 return long(get_int());
951 return long(get_float());
953 return long(get_double());
956 return strtol(get_string(), 0, 0);
959 return SGRawValue<long>::DefaultValue;
964 SGPropertyNode::getFloatValue () const
966 // Shortcut for common case
967 if (_attr == (READ|WRITE) && _type == FLOAT)
970 if (getAttribute(TRACE_READ))
972 if (!getAttribute(READ))
973 return SGRawValue<float>::DefaultValue;
976 return _value.alias->getFloatValue();
978 return float(get_bool());
980 return float(get_int());
982 return float(get_long());
986 return float(get_double());
989 return atof(get_string());
992 return SGRawValue<float>::DefaultValue;
997 SGPropertyNode::getDoubleValue () const
999 // Shortcut for common case
1000 if (_attr == (READ|WRITE) && _type == DOUBLE)
1001 return get_double();
1003 if (getAttribute(TRACE_READ))
1005 if (!getAttribute(READ))
1006 return SGRawValue<double>::DefaultValue;
1010 return _value.alias->getDoubleValue();
1012 return double(get_bool());
1014 return double(get_int());
1016 return double(get_long());
1018 return double(get_float());
1020 return get_double();
1023 return strtod(get_string(), 0);
1026 return SGRawValue<double>::DefaultValue;
1031 SGPropertyNode::getStringValue () const
1033 // Shortcut for common case
1034 if (_attr == (READ|WRITE) && _type == STRING)
1035 return get_string();
1037 if (getAttribute(TRACE_READ))
1039 if (!getAttribute(READ))
1040 return SGRawValue<const char *>::DefaultValue;
1041 return make_string();
1045 SGPropertyNode::setBoolValue (bool value)
1047 // Shortcut for common case
1048 if (_attr == (READ|WRITE) && _type == BOOL)
1049 return set_bool(value);
1051 bool result = false;
1053 if (_type == NONE || _type == UNSPECIFIED) {
1061 result = _value.alias->setBoolValue(value);
1064 result = set_bool(value);
1067 result = set_int(int(value));
1070 result = set_long(long(value));
1073 result = set_float(float(value));
1076 result = set_double(double(value));
1080 result = set_string(value ? "true" : "false");
1087 if (getAttribute(TRACE_WRITE))
1093 SGPropertyNode::setIntValue (int value)
1095 // Shortcut for common case
1096 if (_attr == (READ|WRITE) && _type == INT)
1097 return set_int(value);
1099 bool result = false;
1101 if (_type == NONE || _type == UNSPECIFIED) {
1104 _local_val.int_val = 0;
1109 result = _value.alias->setIntValue(value);
1112 result = set_bool(value == 0 ? false : true);
1115 result = set_int(value);
1118 result = set_long(long(value));
1121 result = set_float(float(value));
1124 result = set_double(double(value));
1129 sprintf(buf, "%d", value);
1130 result = set_string(buf);
1138 if (getAttribute(TRACE_WRITE))
1144 SGPropertyNode::setLongValue (long value)
1146 // Shortcut for common case
1147 if (_attr == (READ|WRITE) && _type == LONG)
1148 return set_long(value);
1150 bool result = false;
1152 if (_type == NONE || _type == UNSPECIFIED) {
1155 _local_val.long_val = 0L;
1160 result = _value.alias->setLongValue(value);
1163 result = set_bool(value == 0L ? false : true);
1166 result = set_int(int(value));
1169 result = set_long(value);
1172 result = set_float(float(value));
1175 result = set_double(double(value));
1180 sprintf(buf, "%ld", value);
1181 result = set_string(buf);
1189 if (getAttribute(TRACE_WRITE))
1195 SGPropertyNode::setFloatValue (float value)
1197 // Shortcut for common case
1198 if (_attr == (READ|WRITE) && _type == FLOAT)
1199 return set_float(value);
1201 bool result = false;
1203 if (_type == NONE || _type == UNSPECIFIED) {
1206 _local_val.float_val = 0;
1211 result = _value.alias->setFloatValue(value);
1214 result = set_bool(value == 0.0 ? false : true);
1217 result = set_int(int(value));
1220 result = set_long(long(value));
1223 result = set_float(value);
1226 result = set_double(double(value));
1231 sprintf(buf, "%f", value);
1232 result = set_string(buf);
1240 if (getAttribute(TRACE_WRITE))
1246 SGPropertyNode::setDoubleValue (double value)
1248 // Shortcut for common case
1249 if (_attr == (READ|WRITE) && _type == DOUBLE)
1250 return set_double(value);
1252 bool result = false;
1254 if (_type == NONE || _type == UNSPECIFIED) {
1256 _local_val.double_val = value;
1262 result = _value.alias->setDoubleValue(value);
1265 result = set_bool(value == 0.0L ? false : true);
1268 result = set_int(int(value));
1271 result = set_long(long(value));
1274 result = set_float(float(value));
1277 result = set_double(value);
1282 sprintf(buf, "%f", value);
1283 result = set_string(buf);
1291 if (getAttribute(TRACE_WRITE))
1297 SGPropertyNode::setStringValue (const char * value)
1299 // Shortcut for common case
1300 if (_attr == (READ|WRITE) && _type == STRING)
1301 return set_string(value);
1303 bool result = false;
1305 if (_type == NONE || _type == UNSPECIFIED) {
1312 result = _value.alias->setStringValue(value);
1315 result = set_bool((compare_strings(value, "true")
1316 || atoi(value)) ? true : false);
1319 result = set_int(atoi(value));
1322 result = set_long(strtol(value, 0, 0));
1325 result = set_float(atof(value));
1328 result = set_double(strtod(value, 0));
1332 result = set_string(value);
1339 if (getAttribute(TRACE_WRITE))
1345 SGPropertyNode::setUnspecifiedValue (const char * value)
1347 bool result = false;
1349 if (_type == NONE) {
1351 _type = UNSPECIFIED;
1356 result = _value.alias->setUnspecifiedValue(value);
1359 result = set_bool((compare_strings(value, "true")
1360 || atoi(value)) ? true : false);
1363 result = set_int(atoi(value));
1366 result = set_long(strtol(value, 0, 0));
1369 result = set_float(atof(value));
1372 result = set_double(strtod(value, 0));
1376 result = set_string(value);
1383 if (getAttribute(TRACE_WRITE))
1389 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1391 if (_type == ALIAS || _tied)
1394 useDefault = useDefault && hasValue();
1395 bool old_val = false;
1397 old_val = getBoolValue();
1402 _value.bool_val = rawValue.clone();
1405 setBoolValue(old_val);
1411 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1413 if (_type == ALIAS || _tied)
1416 useDefault = useDefault && hasValue();
1419 old_val = getIntValue();
1424 _value.int_val = rawValue.clone();
1427 setIntValue(old_val);
1433 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1435 if (_type == ALIAS || _tied)
1438 useDefault = useDefault && hasValue();
1441 old_val = getLongValue();
1446 _value.long_val = rawValue.clone();
1449 setLongValue(old_val);
1455 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1457 if (_type == ALIAS || _tied)
1460 useDefault = useDefault && hasValue();
1461 float old_val = 0.0;
1463 old_val = getFloatValue();
1468 _value.float_val = rawValue.clone();
1471 setFloatValue(old_val);
1477 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1479 if (_type == ALIAS || _tied)
1482 useDefault = useDefault && hasValue();
1483 double old_val = 0.0;
1485 old_val = getDoubleValue();
1490 _value.double_val = rawValue.clone();
1493 setDoubleValue(old_val);
1500 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1502 if (_type == ALIAS || _tied)
1505 useDefault = useDefault && hasValue();
1508 old_val = getStringValue();
1513 _value.string_val = rawValue.clone();
1516 setStringValue(old_val.c_str());
1522 SGPropertyNode::untie ()
1529 bool val = getBoolValue();
1532 _local_val.bool_val = val;
1536 int val = getIntValue();
1539 _local_val.int_val = val;
1543 long val = getLongValue();
1546 _local_val.long_val = val;
1550 float val = getFloatValue();
1553 _local_val.float_val = val;
1557 double val = getDoubleValue();
1560 _local_val.double_val = val;
1565 string val = getStringValue();
1568 _local_val.string_val = copy_string(val.c_str());
1581 SGPropertyNode::getRootNode ()
1586 return _parent->getRootNode();
1589 const SGPropertyNode *
1590 SGPropertyNode::getRootNode () const
1595 return _parent->getRootNode();
1599 SGPropertyNode::getNode (const char * relative_path, bool create)
1601 if (_path_cache == 0)
1602 _path_cache = new hash_table;
1604 SGPropertyNode * result = _path_cache->get(relative_path);
1606 vector<PathComponent> components;
1607 parse_path(relative_path, components);
1608 result = find_node(this, components, 0, create);
1610 _path_cache->put(relative_path, result);
1617 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1619 vector<PathComponent> components;
1620 parse_path(relative_path, components);
1621 if (components.size() > 0)
1622 components[components.size()-1].index = index;
1623 return find_node(this, components, 0, create);
1626 const SGPropertyNode *
1627 SGPropertyNode::getNode (const char * relative_path) const
1629 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1632 const SGPropertyNode *
1633 SGPropertyNode::getNode (const char * relative_path, int index) const
1635 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1639 ////////////////////////////////////////////////////////////////////////
1640 // Convenience methods using relative paths.
1641 ////////////////////////////////////////////////////////////////////////
1645 * Test whether another node has a value attached.
1648 SGPropertyNode::hasValue (const char * relative_path) const
1650 const SGPropertyNode * node = getNode(relative_path);
1651 return (node == 0 ? false : node->hasValue());
1656 * Get the value type for another node.
1658 SGPropertyNode::Type
1659 SGPropertyNode::getType (const char * relative_path) const
1661 const SGPropertyNode * node = getNode(relative_path);
1662 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1667 * Get a bool value for another node.
1670 SGPropertyNode::getBoolValue (const char * relative_path,
1671 bool defaultValue) const
1673 const SGPropertyNode * node = getNode(relative_path);
1674 return (node == 0 ? defaultValue : node->getBoolValue());
1679 * Get an int value for another node.
1682 SGPropertyNode::getIntValue (const char * relative_path,
1683 int defaultValue) const
1685 const SGPropertyNode * node = getNode(relative_path);
1686 return (node == 0 ? defaultValue : node->getIntValue());
1691 * Get a long value for another node.
1694 SGPropertyNode::getLongValue (const char * relative_path,
1695 long defaultValue) const
1697 const SGPropertyNode * node = getNode(relative_path);
1698 return (node == 0 ? defaultValue : node->getLongValue());
1703 * Get a float value for another node.
1706 SGPropertyNode::getFloatValue (const char * relative_path,
1707 float defaultValue) const
1709 const SGPropertyNode * node = getNode(relative_path);
1710 return (node == 0 ? defaultValue : node->getFloatValue());
1715 * Get a double value for another node.
1718 SGPropertyNode::getDoubleValue (const char * relative_path,
1719 double defaultValue) const
1721 const SGPropertyNode * node = getNode(relative_path);
1722 return (node == 0 ? defaultValue : node->getDoubleValue());
1727 * Get a string value for another node.
1730 SGPropertyNode::getStringValue (const char * relative_path,
1731 const char * defaultValue) const
1733 const SGPropertyNode * node = getNode(relative_path);
1734 return (node == 0 ? defaultValue : node->getStringValue());
1739 * Set a bool value for another node.
1742 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1744 return getNode(relative_path, true)->setBoolValue(value);
1749 * Set an int value for another node.
1752 SGPropertyNode::setIntValue (const char * relative_path, int value)
1754 return getNode(relative_path, true)->setIntValue(value);
1759 * Set a long value for another node.
1762 SGPropertyNode::setLongValue (const char * relative_path, long value)
1764 return getNode(relative_path, true)->setLongValue(value);
1769 * Set a float value for another node.
1772 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1774 return getNode(relative_path, true)->setFloatValue(value);
1779 * Set a double value for another node.
1782 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1784 return getNode(relative_path, true)->setDoubleValue(value);
1789 * Set a string value for another node.
1792 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1794 return getNode(relative_path, true)->setStringValue(value);
1799 * Set an unknown value for another node.
1802 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1805 return getNode(relative_path, true)->setUnspecifiedValue(value);
1810 * Test whether another node is tied.
1813 SGPropertyNode::isTied (const char * relative_path) const
1815 const SGPropertyNode * node = getNode(relative_path);
1816 return (node == 0 ? false : node->isTied());
1821 * Tie a node reached by a relative path, creating it if necessary.
1824 SGPropertyNode::tie (const char * relative_path,
1825 const SGRawValue<bool> &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<int> &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<long> &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<float> &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<double> &rawValue,
1876 return getNode(relative_path, true)->tie(rawValue, useDefault);
1881 * Tie a node reached by a relative path, creating it if necessary.
1884 SGPropertyNode::tie (const char * relative_path,
1885 const SGRawValue<const char *> &rawValue,
1888 return getNode(relative_path, true)->tie(rawValue, useDefault);
1893 * Attempt to untie another node reached by a relative path.
1896 SGPropertyNode::untie (const char * relative_path)
1898 SGPropertyNode * node = getNode(relative_path);
1899 return (node == 0 ? false : node->untie());
1904 ////////////////////////////////////////////////////////////////////////
1905 // Simplified hash table for caching paths.
1906 ////////////////////////////////////////////////////////////////////////
1908 #define HASH_TABLE_SIZE 199
1910 SGPropertyNode::hash_table::entry::entry ()
1916 SGPropertyNode::hash_table::entry::~entry ()
1918 // Don't delete the value; we don't own
1924 SGPropertyNode::hash_table::entry::set_key (const char * key)
1926 _key = copy_string(key);
1930 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
1935 SGPropertyNode::hash_table::bucket::bucket ()
1941 SGPropertyNode::hash_table::bucket::~bucket ()
1943 for (int i = 0; i < _length; i++)
1947 SGPropertyNode::hash_table::entry *
1948 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
1951 for (i = 0; i < _length; i++) {
1952 if (!strcmp(_entries[i]->get_key(), key))
1956 entry ** new_entries = new entry*[_length+1];
1957 for (i = 0; i < _length; i++) {
1958 new_entries[i] = _entries[i];
1961 _entries = new_entries;
1962 _entries[_length] = new entry;
1963 _entries[_length]->set_key(key);
1965 return _entries[_length - 1];
1972 SGPropertyNode::hash_table::hash_table ()
1978 SGPropertyNode::hash_table::~hash_table ()
1980 for (int i = 0; i < _data_length; i++)
1985 SGPropertyNode::hash_table::get (const char * key)
1987 if (_data_length == 0)
1989 unsigned int index = hashcode(key) % _data_length;
1990 if (_data[index] == 0)
1992 entry * e = _data[index]->get_entry(key);
1996 return e->get_value();
2000 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2002 if (_data_length == 0) {
2003 _data = new bucket*[HASH_TABLE_SIZE];
2004 _data_length = HASH_TABLE_SIZE;
2005 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2008 unsigned int index = hashcode(key) % _data_length;
2009 if (_data[index] == 0) {
2010 _data[index] = new bucket;
2012 entry * e = _data[index]->get_entry(key, true);
2013 e->set_value(value);
2017 SGPropertyNode::hash_table::hashcode (const char * key)
2019 unsigned int hash = 0;
2021 hash = 31 * hash + *key;