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].
9 #include <simgear/compiler.h>
21 ////////////////////////////////////////////////////////////////////////
23 ////////////////////////////////////////////////////////////////////////
26 * Comparator class for sorting by index.
31 int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
32 return (n1->getIndex() < n2->getIndex());
38 ////////////////////////////////////////////////////////////////////////
39 // Convenience macros for value access.
40 ////////////////////////////////////////////////////////////////////////
42 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
43 #define TEST_WRITE if (!getAttribute(WRITE)) return false
45 #define GET_BOOL (_value.bool_val->getValue())
46 #define GET_INT (_value.int_val->getValue())
47 #define GET_LONG (_value.long_val->getValue())
48 #define GET_FLOAT (_value.float_val->getValue())
49 #define GET_DOUBLE (_value.double_val->getValue())
50 #define GET_STRING (_value.string_val->getValue())
52 #define SET_BOOL(val) (_value.bool_val->setValue(val))
53 #define SET_INT(val) (_value.int_val->setValue(val))
54 #define SET_LONG(val) (_value.long_val->setValue(val))
55 #define SET_FLOAT(val) (_value.float_val->setValue(val))
56 #define SET_DOUBLE(val) (_value.double_val->setValue(val))
57 #define SET_STRING(val) (_value.string_val->setValue(val))
61 ////////////////////////////////////////////////////////////////////////
62 // Default values for every type.
63 ////////////////////////////////////////////////////////////////////////
65 const bool SGRawValue<bool>::DefaultValue = false;
66 const int SGRawValue<int>::DefaultValue = 0;
67 const long SGRawValue<long>::DefaultValue = 0L;
68 const float SGRawValue<float>::DefaultValue = 0.0;
69 const double SGRawValue<double>::DefaultValue = 0.0L;
70 const string SGRawValue<string>::DefaultValue = "";
74 ////////////////////////////////////////////////////////////////////////
75 // Local path normalization code.
76 ////////////////////////////////////////////////////////////////////////
79 * A component in a path.
88 * Parse the name for a path component.
90 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
93 parse_name (const string &path, int &i)
96 int max = path.size();
100 if (i < max && path[i] == '.') {
106 if (i < max && path[i] != '/')
107 throw string(string("Illegal character after ") + name);
110 else if (isalpha(path[i]) || path[i] == '_') {
114 // The rules inside a name are a little
117 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
118 path[i] == '-' || path[i] == '.') {
120 } else if (path[i] == '[' || path[i] == '/') {
123 throw string("name may contain only ._- and alphanumeric characters");
130 if (name.size() == 0)
131 throw string("name must begin with alpha or '_'");
139 * Parse the optional integer index for a path component.
141 * Index: "[" [0-9]+ "]"
144 parse_index (const string &path, int &i)
153 for (int max = path.size(); i < max; i++) {
154 if (isdigit(path[i])) {
155 index = (index * 10) + (path[i] - '0');
156 } else if (path[i] == ']') {
164 throw string("unterminated index (looking for ']')");
169 * Parse a single path component.
171 * Component: Name Index?
173 static inline PathComponent
174 parse_component (const string &path, int &i)
176 PathComponent component;
177 component.name = parse_name(path, i);
178 if (component.name[0] != '.')
179 component.index = parse_index(path, i);
181 component.index = -1;
187 * Parse a path into its components.
190 parse_path (const string &path, vector<PathComponent> &components)
193 int max = path.size();
195 // Check for initial '/'
196 if (path[pos] == '/') {
200 components.push_back(root);
202 while (pos < max && path[pos] == '/')
207 components.push_back(parse_component(path, pos));
208 while (pos < max && path[pos] == '/')
215 ////////////////////////////////////////////////////////////////////////
216 // Other static utility functions.
217 ////////////////////////////////////////////////////////////////////////
221 * Locate a child node by name and index.
224 find_child (const string &name, int index, vector<SGPropertyNode *> nodes)
226 int nNodes = nodes.size();
227 for (int i = 0; i < nNodes; i++) {
228 SGPropertyNode * node = nodes[i];
229 if (node->getName() == name && node->getIndex() == index)
237 * Locate another node, given a relative path.
239 static SGPropertyNode *
240 find_node (SGPropertyNode * current,
241 const vector<PathComponent> &components,
245 // Run off the end of the list
250 // Success! This is the one we want.
251 else if (position >= (int)components.size()) {
255 // Empty component means root.
256 else if (components[position].name == "") {
257 return find_node(current->getRootNode(), components, position + 1, create);
260 // . means current directory
261 else if (components[position].name == ".") {
262 return find_node(current, components, position + 1, create);
265 // .. means parent directory
266 else if (components[position].name == "..") {
267 SGPropertyNode * parent = current->getParent();
269 throw string("Attempt to move past root with '..'");
271 return find_node(parent, components, position + 1, create);
274 // Otherwise, a child name
276 SGPropertyNode * child =
277 current->getChild(components[position].name,
278 components[position].index,
280 return find_node(child, components, position + 1, create);
286 ////////////////////////////////////////////////////////////////////////
287 // Implementation of SGPropertyNode.
288 ////////////////////////////////////////////////////////////////////////
292 * Default constructor: always creates a root node.
294 SGPropertyNode::SGPropertyNode ()
308 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
311 _parent(0), // don't copy the parent
320 _value.alias = node._value.alias;
323 _value.bool_val = node._value.bool_val->clone();
326 _value.int_val = node._value.int_val->clone();
329 _value.long_val = node._value.long_val->clone();
332 _value.float_val = node._value.float_val->clone();
335 _value.double_val = node._value.double_val->clone();
339 _value.string_val = node._value.string_val->clone();
346 * Convenience constructor.
348 SGPropertyNode::SGPropertyNode (const string &name,
349 int index, SGPropertyNode * parent)
350 : _name(name), _index(index), _parent(parent), _type(NONE),
351 _tied(false), _attr(READ|WRITE)
359 SGPropertyNode::~SGPropertyNode ()
361 for (int i = 0; i < (int)_children.size(); i++) {
369 * Delete and clear the current value.
372 SGPropertyNode::clear_value ()
380 delete _value.bool_val;
384 delete _value.int_val;
388 delete _value.long_val;
389 _value.long_val = 0L;
392 delete _value.float_val;
393 _value.float_val = 0;
396 delete _value.double_val;
397 _value.double_val = 0;
401 delete _value.string_val;
402 _value.string_val = 0;
410 * Alias to another node.
413 SGPropertyNode::alias (SGPropertyNode * target)
415 if (target == 0 || _type == ALIAS || _tied)
418 _value.alias = target;
425 * Alias to another node by path.
428 SGPropertyNode::alias (const string &path)
430 return alias(getNode(path, true));
438 SGPropertyNode::unalias ()
449 * Get the target of an alias.
452 SGPropertyNode::getAliasTarget ()
454 return (_type == ALIAS ? _value.alias : 0);
458 const SGPropertyNode *
459 SGPropertyNode::getAliasTarget () const
461 return (_type == ALIAS ? _value.alias : 0);
466 * Get a non-const child by index.
469 SGPropertyNode::getChild (int position)
471 if (position >= 0 && position < nChildren())
472 return _children[position];
479 * Get a const child by index.
481 const SGPropertyNode *
482 SGPropertyNode::getChild (int position) const
484 if (position >= 0 && position < nChildren())
485 return _children[position];
492 * Get a non-const child by name and index, creating if necessary.
495 SGPropertyNode::getChild (const string &name, int index, bool create)
497 int pos = find_child(name, index, _children);
499 return _children[pos];
501 _children.push_back(new SGPropertyNode(name, index, this));
502 return _children[_children.size()-1];
510 * Get a const child by name and index.
512 const SGPropertyNode *
513 SGPropertyNode::getChild (const string &name, int index) const
515 int pos = find_child(name, index, _children);
517 return _children[pos];
524 * Get all children with the same name (but different indices).
526 vector<SGPropertyNode *>
527 SGPropertyNode::getChildren (const string &name)
529 vector<SGPropertyNode *> children;
530 int max = _children.size();
532 for (int i = 0; i < max; i++)
533 if (_children[i]->getName() == name)
534 children.push_back(_children[i]);
536 sort(children.begin(), children.end(), CompareIndices());
542 * Get all children const with the same name (but different indices).
544 vector<const SGPropertyNode *>
545 SGPropertyNode::getChildren (const string &name) const
547 vector<const SGPropertyNode *> children;
548 int max = _children.size();
550 for (int i = 0; i < max; i++)
551 if (_children[i]->getName() == name)
552 children.push_back(_children[i]);
554 sort(children.begin(), children.end(), CompareIndices());
560 SGPropertyNode::getPath (bool simplify) const
565 string path = _parent->getPath(simplify);
568 if (_index != 0 || !simplify) {
570 sprintf(buffer, "[%d]", _index);
577 SGPropertyNode::getType () const
580 return _value.alias->getType();
587 SGPropertyNode::getBoolValue () const
592 return _value.alias->getBoolValue();
596 return GET_INT == 0 ? false : true;
598 return GET_LONG == 0L ? false : true;
600 return GET_FLOAT == 0.0 ? false : true;
602 return GET_DOUBLE == 0.0L ? false : true;
605 return (GET_STRING == "true" || getDoubleValue() != 0.0L);
608 return false; // if NONE
612 SGPropertyNode::getIntValue () const
617 return _value.alias->getIntValue();
619 return int(GET_BOOL);
623 return int(GET_LONG);
625 return int(GET_FLOAT);
627 return int(GET_DOUBLE);
630 return atoi(GET_STRING.c_str());
637 SGPropertyNode::getLongValue () const
642 return _value.alias->getLongValue();
644 return long(GET_BOOL);
646 return long(GET_INT);
650 return long(GET_FLOAT);
652 return long(GET_DOUBLE);
655 return strtol(GET_STRING.c_str(), 0, 0);
658 return 0L; // if NONE
662 SGPropertyNode::getFloatValue () const
667 return _value.alias->getFloatValue();
669 return float(GET_BOOL);
671 return float(GET_INT);
673 return float(GET_LONG);
677 return float(GET_DOUBLE);
680 return atof(GET_STRING.c_str());
683 return 0.0; // if NONE
687 SGPropertyNode::getDoubleValue () const
692 return _value.alias->getDoubleValue();
694 return double(GET_BOOL);
696 return double(GET_INT);
698 return double(GET_LONG);
700 return double(GET_FLOAT);
705 return strtod(GET_STRING.c_str(), 0);
708 return 0.0L; // if NONE
712 SGPropertyNode::getStringValue () const
719 return _value.alias->getStringValue();
726 sprintf(buf, "%d", GET_INT);
729 sprintf(buf, "%ld", GET_LONG);
732 sprintf(buf, "%f", GET_FLOAT);
735 sprintf(buf, "%f", GET_DOUBLE);
742 return ""; // if NONE
746 SGPropertyNode::setBoolValue (bool value)
749 if (_type == NONE || _type == UNSPECIFIED) {
751 _value.bool_val = new SGRawValueInternal<bool>;
757 return _value.alias->setBoolValue(value);
759 return SET_BOOL(value);
761 return SET_INT(int(value));
763 return SET_LONG(long(value));
765 return SET_FLOAT(float(value));
767 return SET_DOUBLE(double(value));
769 return SET_STRING(value ? "true" : "false");
772 return false; // should never happen
776 SGPropertyNode::setIntValue (int value)
779 if (_type == NONE || _type == UNSPECIFIED) {
781 _value.int_val = new SGRawValueInternal<int>;
787 return _value.alias->setIntValue(value);
789 return SET_BOOL(value == 0 ? false : true);
791 return SET_INT(value);
793 return SET_LONG(long(value));
795 return SET_FLOAT(float(value));
797 return SET_DOUBLE(double(value));
800 sprintf(buf, "%d", value);
801 return SET_STRING(buf);
805 return false; // should never happen
809 SGPropertyNode::setLongValue (long value)
812 if (_type == NONE || _type == UNSPECIFIED) {
814 _value.long_val = new SGRawValueInternal<long>;
820 return _value.alias->setLongValue(value);
822 return SET_BOOL(value == 0L ? false : true);
824 return SET_INT(int(value));
826 return SET_LONG(value);
828 return SET_FLOAT(float(value));
830 return SET_DOUBLE(double(value));
833 sprintf(buf, "%d", value);
834 return SET_STRING(buf);
838 return false; // should never happen
842 SGPropertyNode::setFloatValue (float value)
845 if (_type == NONE || _type == UNSPECIFIED) {
847 _value.float_val = new SGRawValueInternal<float>;
853 return _value.alias->setFloatValue(value);
855 return SET_BOOL(value == 0.0 ? false : true);
857 return SET_INT(int(value));
859 return SET_LONG(long(value));
861 return SET_FLOAT(value);
863 return SET_DOUBLE(double(value));
866 sprintf(buf, "%f", value);
867 return SET_STRING(buf);
871 return false; // should never happen
875 SGPropertyNode::setDoubleValue (double value)
878 if (_type == NONE || _type == UNSPECIFIED) {
880 _value.double_val = new SGRawValueInternal<double>;
886 return _value.alias->setDoubleValue(value);
888 return SET_BOOL(value == 0.0L ? false : true);
890 return SET_INT(int(value));
892 return SET_LONG(long(value));
894 return SET_FLOAT(float(value));
896 return SET_DOUBLE(value);
899 sprintf(buf, "%lf", value);
900 return SET_STRING(buf);
904 return false; // should never happen
908 SGPropertyNode::setStringValue (string value)
911 if (_type == NONE || _type == UNSPECIFIED) {
913 _value.string_val = new SGRawValueInternal<string>;
919 return _value.alias->setStringValue(value);
921 return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
923 return SET_INT(atoi(value.c_str()));
925 return SET_LONG(strtol(value.c_str(), 0, 0));
927 return SET_FLOAT(atof(value.c_str()));
929 return SET_DOUBLE(strtod(value.c_str(), 0));
931 return SET_STRING(value);
934 return false; // should never happen
938 SGPropertyNode::setUnspecifiedValue (string value)
943 _value.string_val = new SGRawValueInternal<string>;
949 return _value.alias->setUnspecifiedValue(value);
951 return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
953 return SET_INT(atoi(value.c_str()));
955 return SET_LONG(strtol(value.c_str(), 0, 0));
957 return SET_FLOAT(atof(value.c_str()));
959 return SET_DOUBLE(strtod(value.c_str(), 0));
962 return SET_STRING(value);
965 return false; // should never happen
969 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
971 if (_type == ALIAS || _tied)
974 bool old_val = false;
976 old_val = getBoolValue();
981 _value.bool_val = rawValue.clone();
984 setBoolValue(old_val);
990 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
992 if (_type == ALIAS || _tied)
997 old_val = getIntValue();
1002 _value.int_val = rawValue.clone();
1005 setIntValue(old_val);
1011 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1013 if (_type == ALIAS || _tied)
1018 old_val = getLongValue();
1023 _value.long_val = rawValue.clone();
1026 setLongValue(old_val);
1032 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1034 if (_type == ALIAS || _tied)
1037 float old_val = 0.0;
1039 old_val = getFloatValue();
1044 _value.float_val = rawValue.clone();
1047 setFloatValue(old_val);
1053 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1055 if (_type == ALIAS || _tied)
1058 double old_val = 0.0;
1060 old_val = getDoubleValue();
1065 _value.double_val = rawValue.clone();
1068 setDoubleValue(old_val);
1075 SGPropertyNode::tie (const SGRawValue<string> &rawValue, bool useDefault)
1077 if (_type == ALIAS || _tied)
1082 old_val = getStringValue();
1087 _value.string_val = rawValue.clone();
1090 setStringValue(old_val);
1096 SGPropertyNode::untie ()
1103 bool val = getBoolValue();
1106 _value.bool_val = new SGRawValueInternal<bool>;
1111 int val = getIntValue();
1114 _value.int_val = new SGRawValueInternal<int>;
1119 long val = getLongValue();
1122 _value.long_val = new SGRawValueInternal<long>;
1127 float val = getFloatValue();
1130 _value.float_val = new SGRawValueInternal<float>;
1135 double val = getDoubleValue();
1138 _value.double_val = new SGRawValueInternal<double>;
1143 string val = getStringValue();
1146 _value.string_val = new SGRawValueInternal<string>;
1157 SGPropertyNode::getRootNode ()
1162 return _parent->getRootNode();
1165 const SGPropertyNode *
1166 SGPropertyNode::getRootNode () const
1171 return _parent->getRootNode();
1175 SGPropertyNode::getNode (const string &relative_path, bool create)
1177 vector<PathComponent> components;
1178 parse_path(relative_path, components);
1179 return find_node(this, components, 0, create);
1182 const SGPropertyNode *
1183 SGPropertyNode::getNode (const string &relative_path) const
1185 vector<PathComponent> components;
1186 parse_path(relative_path, components);
1187 // FIXME: cast away const
1188 return find_node((SGPropertyNode *)this, components, 0, false);
1193 ////////////////////////////////////////////////////////////////////////
1194 // Convenience methods using relative paths.
1195 ////////////////////////////////////////////////////////////////////////
1199 * Test whether another node has a value attached.
1202 SGPropertyNode::hasValue (const string &relative_path) const
1204 const SGPropertyNode * node = getNode(relative_path);
1205 return (node == 0 ? false : node->hasValue());
1210 * Get the value type for another node.
1212 SGPropertyNode::Type
1213 SGPropertyNode::getType (const string &relative_path) const
1215 const SGPropertyNode * node = getNode(relative_path);
1216 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1221 * Get a bool value for another node.
1224 SGPropertyNode::getBoolValue (const string &relative_path,
1225 bool defaultValue) const
1227 const SGPropertyNode * node = getNode(relative_path);
1228 return (node == 0 ? defaultValue : node->getBoolValue());
1233 * Get an int value for another node.
1236 SGPropertyNode::getIntValue (const string &relative_path,
1237 int defaultValue) const
1239 const SGPropertyNode * node = getNode(relative_path);
1240 return (node == 0 ? defaultValue : node->getIntValue());
1245 * Get a long value for another node.
1248 SGPropertyNode::getLongValue (const string &relative_path,
1249 long defaultValue) const
1251 const SGPropertyNode * node = getNode(relative_path);
1252 return (node == 0 ? defaultValue : node->getLongValue());
1257 * Get a float value for another node.
1260 SGPropertyNode::getFloatValue (const string &relative_path,
1261 float defaultValue) const
1263 const SGPropertyNode * node = getNode(relative_path);
1264 return (node == 0 ? defaultValue : node->getFloatValue());
1269 * Get a double value for another node.
1272 SGPropertyNode::getDoubleValue (const string &relative_path,
1273 double defaultValue) const
1275 const SGPropertyNode * node = getNode(relative_path);
1276 return (node == 0 ? defaultValue : node->getDoubleValue());
1281 * Get a string value for another node.
1284 SGPropertyNode::getStringValue (const string &relative_path,
1285 string defaultValue) const
1287 const SGPropertyNode * node = getNode(relative_path);
1288 return (node == 0 ? defaultValue : node->getStringValue());
1293 * Set a bool value for another node.
1296 SGPropertyNode::setBoolValue (const string &relative_path, bool value)
1298 return getNode(relative_path, true)->setBoolValue(value);
1303 * Set an int value for another node.
1306 SGPropertyNode::setIntValue (const string &relative_path, int value)
1308 return getNode(relative_path, true)->setIntValue(value);
1313 * Set a long value for another node.
1316 SGPropertyNode::setLongValue (const string &relative_path, long value)
1318 return getNode(relative_path, true)->setLongValue(value);
1323 * Set a float value for another node.
1326 SGPropertyNode::setFloatValue (const string &relative_path, float value)
1328 return getNode(relative_path, true)->setFloatValue(value);
1333 * Set a double value for another node.
1336 SGPropertyNode::setDoubleValue (const string &relative_path, double value)
1338 return getNode(relative_path, true)->setDoubleValue(value);
1343 * Set a string value for another node.
1346 SGPropertyNode::setStringValue (const string &relative_path, string value)
1348 return getNode(relative_path, true)->setStringValue(value);
1353 * Set an unknown value for another node.
1356 SGPropertyNode::setUnspecifiedValue (const string &relative_path, string value)
1358 return getNode(relative_path, true)->setUnspecifiedValue(value);
1363 * Test whether another node is tied.
1366 SGPropertyNode::isTied (const string &relative_path) const
1368 const SGPropertyNode * node = getNode(relative_path);
1369 return (node == 0 ? false : node->isTied());
1374 * Tie a node reached by a relative path, creating it if necessary.
1377 SGPropertyNode::tie (const string &relative_path,
1378 const SGRawValue<bool> &rawValue,
1381 return getNode(relative_path, true)->tie(rawValue, useDefault);
1386 * Tie a node reached by a relative path, creating it if necessary.
1389 SGPropertyNode::tie (const string &relative_path,
1390 const SGRawValue<int> &rawValue,
1393 return getNode(relative_path, true)->tie(rawValue, useDefault);
1398 * Tie a node reached by a relative path, creating it if necessary.
1401 SGPropertyNode::tie (const string &relative_path,
1402 const SGRawValue<long> &rawValue,
1405 return getNode(relative_path, true)->tie(rawValue, useDefault);
1410 * Tie a node reached by a relative path, creating it if necessary.
1413 SGPropertyNode::tie (const string &relative_path,
1414 const SGRawValue<float> &rawValue,
1417 return getNode(relative_path, true)->tie(rawValue, useDefault);
1422 * Tie a node reached by a relative path, creating it if necessary.
1425 SGPropertyNode::tie (const string &relative_path,
1426 const SGRawValue<double> &rawValue,
1429 return getNode(relative_path, true)->tie(rawValue, useDefault);
1434 * Tie a node reached by a relative path, creating it if necessary.
1437 SGPropertyNode::tie (const string &relative_path,
1438 const SGRawValue<string> &rawValue,
1441 return getNode(relative_path, true)->tie(rawValue, useDefault);
1446 * Attempt to untie another node reached by a relative path.
1449 SGPropertyNode::untie (const string &relative_path)
1451 SGPropertyNode * node = getNode(relative_path);
1452 return (node == 0 ? false : node->untie());