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].
13 #include <simgear/compiler.h>
21 #if !defined(FG_HAVE_NATIVE_SGI_COMPILERS)
29 ////////////////////////////////////////////////////////////////////////
30 // Convenience macros for value access.
31 ////////////////////////////////////////////////////////////////////////
33 #define GET_BOOL (_value.bool_val->getValue())
34 #define GET_INT (_value.int_val->getValue())
35 #define GET_FLOAT (_value.float_val->getValue())
36 #define GET_DOUBLE (_value.double_val->getValue())
37 #define GET_STRING (_value.string_val->getValue())
39 #define SET_BOOL(val) (_value.bool_val->setValue(val))
40 #define SET_INT(val) (_value.int_val->setValue(val))
41 #define SET_FLOAT(val) (_value.float_val->setValue(val))
42 #define SET_DOUBLE(val) (_value.double_val->setValue(val))
43 #define SET_STRING(val) (_value.string_val->setValue(val))
47 ////////////////////////////////////////////////////////////////////////
48 // Default values for every type.
49 ////////////////////////////////////////////////////////////////////////
51 const bool SGRawValue<bool>::DefaultValue = false;
52 const int SGRawValue<int>::DefaultValue = 0;
53 const float SGRawValue<float>::DefaultValue = 0.0;
54 const double SGRawValue<double>::DefaultValue = 0.0L;
55 const string SGRawValue<string>::DefaultValue = "";
59 ////////////////////////////////////////////////////////////////////////
60 // Local path normalization code.
61 ////////////////////////////////////////////////////////////////////////
64 * A component in a path.
73 * Parse the name for a path component.
75 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
78 parse_name (const string &path, int &i)
81 int max = path.size();
85 if (i < max && path[i] == '.') {
91 if (i < max && path[i] != '/')
92 throw string(string("Illegal character after ") + name);
95 else if (isalpha(path[i]) || path[i] == '_') {
99 // The rules inside a name are a little
102 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
103 path[i] == '-' || path[i] == '.') {
105 } else if (path[i] == '[' || path[i] == '/') {
108 throw string("name may contain only ._- and alphanumeric characters");
115 if (name.size() == 0)
116 throw string("name must begin with alpha or '_'");
124 * Parse the optional integer index for a path component.
126 * Index: "[" [0-9]+ "]"
129 parse_index (const string &path, int &i)
138 for (int max = path.size(); i < max; i++) {
139 if (isdigit(path[i])) {
140 index = (index * 10) + (path[i] - '0');
141 } else if (path[i] == ']') {
149 throw string("unterminated index (looking for ']')");
154 * Parse a single path component.
156 * Component: Name Index?
158 static inline PathComponent
159 parse_component (const string &path, int &i)
161 PathComponent component;
162 component.name = parse_name(path, i);
163 if (component.name[0] != '.')
164 component.index = parse_index(path, i);
166 component.index = -1;
172 * Parse a path into its components.
175 parse_path (const string &path, vector<PathComponent> &components)
178 int max = path.size();
180 // Check for initial '/'
181 if (path[pos] == '/') {
185 components.push_back(root);
187 while (pos < max && path[pos] == '/')
192 components.push_back(parse_component(path, pos));
193 while (pos < max && path[pos] == '/')
200 ////////////////////////////////////////////////////////////////////////
201 // Other static utility functions.
202 ////////////////////////////////////////////////////////////////////////
206 * Locate a child node by name and index.
209 find_child (const string &name, int index, vector<SGPropertyNode *> nodes)
211 int nNodes = nodes.size();
212 for (int i = 0; i < nNodes; i++) {
213 SGPropertyNode * node = nodes[i];
214 if (node->getName() == name && node->getIndex() == index)
222 * Locate another node, given a relative path.
224 static SGPropertyNode *
225 find_node (SGPropertyNode * current,
226 const vector<PathComponent> &components,
234 else if (position >= components.size()) {
238 else if (components[position].name == "") {
239 return find_node(current->getRootNode(), components, position + 1, create);
242 else if (components[position].name == ".") {
243 return find_node(current, components, position + 1, create);
246 else if (components[position].name == "..") {
247 SGPropertyNode * parent = current->getParent();
249 throw string("Attempt to move past root with '..'");
251 return find_node(parent, components, position + 1, create);
255 SGPropertyNode * child =
256 current->getChild(components[position].name,
257 components[position].index,
259 return find_node(child, components, position + 1, create);
265 ////////////////////////////////////////////////////////////////////////
266 // Implementation of SGValue.
267 ////////////////////////////////////////////////////////////////////////
271 * Default constructor.
273 * The type will be UNKNOWN and the raw value will be "".
276 : _type(UNKNOWN), _tied(false)
278 _value.string_val = new SGRawValueInternal<string>;
285 SGValue::SGValue (const SGValue &source)
287 _type = source._type;
288 _tied = source._tied;
289 switch (source._type) {
291 _value.bool_val = source._value.bool_val->clone();
294 _value.int_val = source._value.int_val->clone();
297 _value.float_val = source._value.float_val->clone();
300 _value.double_val = source._value.double_val->clone();
304 _value.string_val = source._value.string_val->clone();
320 * Delete and clear the current value.
323 SGValue::clear_value ()
327 delete _value.bool_val;
331 delete _value.int_val;
335 delete _value.float_val;
336 _value.float_val = 0;
339 delete _value.double_val;
340 _value.double_val = 0;
344 delete _value.string_val;
345 _value.string_val = 0;
352 * Get a boolean value.
355 SGValue::getBoolValue () const
361 return GET_INT == 0 ? false : true;
363 return GET_FLOAT == 0.0 ? false : true;
365 return GET_DOUBLE == 0.0L ? false : true;
368 return (GET_STRING == "true" || getDoubleValue() != 0.0L);
374 * Get an integer value.
377 SGValue::getIntValue () const
381 return (int)GET_BOOL;
385 return (int)GET_FLOAT;
387 return (int)GET_DOUBLE;
390 return atoi(GET_STRING.c_str());
399 SGValue::getFloatValue () const
403 return (float)GET_BOOL;
405 return (float)GET_INT;
412 return atof(GET_STRING.c_str());
418 * Get a double value.
421 SGValue::getDoubleValue () const
425 return (double)GET_BOOL;
427 return (double)GET_INT;
429 return (double)GET_FLOAT;
434 return (double)atof(GET_STRING.c_str());
440 * Get a string value.
443 SGValue::getStringValue () const
454 sprintf(buf, "%d", GET_INT);
457 sprintf(buf, "%f", GET_FLOAT);
460 sprintf(buf, "%lf", GET_DOUBLE);
473 SGValue::setBoolValue (bool value)
475 if (_type == UNKNOWN) {
477 _value.bool_val = new SGRawValueInternal<bool>;
483 return SET_BOOL(value);
485 return SET_INT((int)value);
487 return SET_FLOAT((float)value);
489 return SET_DOUBLE((double)value);
491 return SET_STRING(value ? "true" : "false");
502 SGValue::setIntValue (int value)
504 if (_type == UNKNOWN) {
506 _value.int_val = new SGRawValueInternal<int>;
512 return SET_BOOL(value == 0 ? false : true);
514 return SET_INT(value);
516 return SET_FLOAT((float)value);
518 return SET_DOUBLE((double)value);
521 sprintf(buf, "%d", value);
522 return SET_STRING(buf);
534 SGValue::setFloatValue (float value)
536 if (_type == UNKNOWN) {
538 _value.float_val = new SGRawValueInternal<float>;
544 return SET_BOOL(value == 0.0 ? false : true);
546 return SET_INT((int)value);
548 return SET_FLOAT(value);
550 return SET_DOUBLE((double)value);
553 sprintf(buf, "%f", value);
554 return SET_STRING(buf);
563 * Set a double value.
566 SGValue::setDoubleValue (double value)
568 if (_type == UNKNOWN) {
570 _value.double_val = new SGRawValueInternal<double>;
576 return SET_BOOL(value == 0.0L ? false : true);
578 return SET_INT((int)value);
580 return SET_FLOAT((float)value);
582 return SET_DOUBLE(value);
585 sprintf(buf, "%lf", value);
586 return SET_STRING(buf);
595 * Set a string value.
598 SGValue::setStringValue (string value)
600 if (_type == UNKNOWN) {
602 _value.string_val = new SGRawValueInternal<string>;
608 return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
610 return SET_INT(atoi(value.c_str()));
612 return SET_FLOAT(atof(value.c_str()));
614 return SET_DOUBLE((double)atof(value.c_str()));
616 return SET_STRING(value);
624 * Set a value of unknown type (stored as a string).
627 SGValue::setUnknownValue (string value)
631 return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
633 return SET_INT(atoi(value.c_str()));
635 return SET_FLOAT(atof(value.c_str()));
637 return SET_DOUBLE((double)atof(value.c_str()));
640 return SET_STRING(value);
651 SGValue::tie (const SGRawValue<bool> &value, bool use_default)
658 old_val = getBoolValue();
663 _value.bool_val = value.clone();
666 setBoolValue(old_val);
676 SGValue::tie (const SGRawValue<int> &value, bool use_default)
683 old_val = getIntValue();
688 _value.int_val = value.clone();
691 setIntValue(old_val);
701 SGValue::tie (const SGRawValue<float> &value, bool use_default)
708 old_val = getFloatValue();
713 _value.float_val = value.clone();
716 setFloatValue(old_val);
723 * Tie a double value.
726 SGValue::tie (const SGRawValue<double> &value, bool use_default)
733 old_val = getDoubleValue();
738 _value.double_val = value.clone();
741 setDoubleValue(old_val);
748 * Tie a string value.
751 SGValue::tie (const SGRawValue<string> &value, bool use_default)
758 old_val = getStringValue();
763 _value.string_val = value.clone();
766 setStringValue(old_val);
783 bool val = getBoolValue();
785 _value.bool_val = new SGRawValueInternal<bool>;
790 int val = getIntValue();
792 _value.int_val = new SGRawValueInternal<int>;
797 float val = getFloatValue();
799 _value.float_val = new SGRawValueInternal<float>;
804 double val = getDoubleValue();
806 _value.double_val = new SGRawValueInternal<double>;
811 string val = getStringValue();
813 _value.string_val = new SGRawValueInternal<string>;
825 ////////////////////////////////////////////////////////////////////////
826 // Implementation of SGPropertyNode.
827 ////////////////////////////////////////////////////////////////////////
831 * Default constructor: always creates a root node.
833 SGPropertyNode::SGPropertyNode ()
834 : _value(0), _name(""), _index(0), _parent(0)
840 * Convenience constructor.
842 SGPropertyNode::SGPropertyNode (const string &name,
843 int index, SGPropertyNode * parent)
844 : _value(0), _name(name), _index(index), _parent(parent)
848 SGPropertyNode::~SGPropertyNode ()
851 for (int i = 0; i < _children.size(); i++)
856 SGPropertyNode::getChild (int position)
858 if (position >= 0 && position < nChildren())
859 return _children[position];
864 const SGPropertyNode *
865 SGPropertyNode::getChild (int position) const
867 if (position >= 0 && position < nChildren())
868 return _children[position];
874 SGPropertyNode::getChild (const string &name, int index, bool create)
876 int pos = find_child(name, index, _children);
878 return getChild(pos);
880 _children.push_back(new SGPropertyNode(name, index, this));
881 return _children[_children.size()-1];
887 const SGPropertyNode *
888 SGPropertyNode::getChild (const string &name, int index) const
890 int pos = find_child(name, index, _children);
892 _children[_children.size()-1];
901 int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
902 return (n1->getIndex() < n2->getIndex());
908 * Get all children with the same name (but different indices).
910 vector<SGPropertyNode *>
911 SGPropertyNode::getChildren (const string &name)
913 vector<SGPropertyNode *> children;
914 int max = _children.size();
916 for (int i = 0; i < max; i++)
917 if (_children[i]->getName() == name)
918 children.push_back(_children[i]);
920 sort(children.begin(), children.end(), CompareIndices());
926 * Get all children with the same name (but different indices).
928 vector<const SGPropertyNode *>
929 SGPropertyNode::getChildren (const string &name) const
931 vector<const SGPropertyNode *> children;
932 int max = _children.size();
934 for (int i = 0; i < max; i++)
935 if (_children[i]->getName() == name)
936 children.push_back(_children[i]);
938 sort(children.begin(), children.end(), CompareIndices());
944 SGPropertyNode::getPath (bool simplify) const
949 string path = _parent->getPath(simplify);
952 if (_index != 0 || !simplify) {
954 sprintf(buffer, "[%d]", _index);
961 SGPropertyNode::getType () const
964 return _value->getType();
966 return SGValue::UNKNOWN;
970 SGPropertyNode::getBoolValue () const
972 return (_value == 0 ? SGRawValue<bool>::DefaultValue
973 : _value->getBoolValue());
977 SGPropertyNode::getIntValue () const
979 return (_value == 0 ? SGRawValue<int>::DefaultValue
980 : _value->getIntValue());
984 SGPropertyNode::getFloatValue () const
986 return (_value == 0 ? SGRawValue<float>::DefaultValue
987 : _value->getFloatValue());
991 SGPropertyNode::getDoubleValue () const
993 return (_value == 0 ? SGRawValue<double>::DefaultValue
994 : _value->getDoubleValue());
998 SGPropertyNode::getStringValue () const
1000 return (_value == 0 ? SGRawValue<string>::DefaultValue
1001 : _value->getStringValue());
1005 SGPropertyNode::setBoolValue (bool val)
1008 _value = new SGValue();
1009 return _value->setBoolValue(val);
1013 SGPropertyNode::setIntValue (int val)
1016 _value = new SGValue();
1017 return _value->setIntValue(val);
1021 SGPropertyNode::setFloatValue (float val)
1024 _value = new SGValue();
1025 return _value->setFloatValue(val);
1029 SGPropertyNode::setDoubleValue (double val)
1032 _value = new SGValue();
1033 return _value->setDoubleValue(val);
1037 SGPropertyNode::setStringValue (string val)
1040 _value = new SGValue();
1041 return _value->setStringValue(val);
1045 SGPropertyNode::setUnknownValue (string val)
1048 _value = new SGValue();
1049 return _value->setUnknownValue(val);
1053 SGPropertyNode::isTied () const
1055 return (_value == 0 ? false : _value->isTied());
1059 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1062 _value = new SGValue();
1063 return _value->tie(rawValue, useDefault);
1067 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1070 _value = new SGValue();
1071 return _value->tie(rawValue, useDefault);
1075 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1078 _value = new SGValue();
1079 return _value->tie(rawValue, useDefault);
1083 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1086 _value = new SGValue();
1087 return _value->tie(rawValue, useDefault);
1091 SGPropertyNode::tie (const SGRawValue<string> &rawValue, bool useDefault)
1094 _value = new SGValue();
1095 return _value->tie(rawValue, useDefault);
1099 SGPropertyNode::untie ()
1101 return (_value == 0 ? false : _value->untie());
1105 SGPropertyNode::getRootNode ()
1110 return _parent->getRootNode();
1113 const SGPropertyNode *
1114 SGPropertyNode::getRootNode () const
1119 return _parent->getRootNode();
1123 SGPropertyNode::getNode (const string &relative_path, bool create)
1125 vector<PathComponent> components;
1126 parse_path(relative_path, components);
1127 return find_node(this, components, 0, create);
1130 const SGPropertyNode *
1131 SGPropertyNode::getNode (const string &relative_path) const
1133 vector<PathComponent> components;
1134 parse_path(relative_path, components);
1135 // FIXME: cast away const
1136 return find_node((SGPropertyNode *)this, components, 0, false);
1141 ////////////////////////////////////////////////////////////////////////
1142 // Convenience methods using relative paths.
1143 ////////////////////////////////////////////////////////////////////////
1147 * Test whether another node has a value attached.
1150 SGPropertyNode::hasValue (const string &relative_path) const
1152 const SGPropertyNode * node = getNode(relative_path);
1153 return (node == 0 ? false : node->hasValue());
1158 * Get the value for another node.
1161 SGPropertyNode::getValue (const string &relative_path, bool create)
1163 SGPropertyNode * node = getNode(relative_path, create);
1164 if (node != 0 && !node->hasValue())
1165 node->setUnknownValue("");
1166 return (node == 0 ? 0 : node->getValue());
1171 * Get the value for another node.
1174 SGPropertyNode::getValue (const string &relative_path) const
1176 const SGPropertyNode * node = getNode(relative_path);
1177 return (node == 0 ? 0 : node->getValue());
1182 * Get the value type for another node.
1185 SGPropertyNode::getType (const string &relative_path) const
1187 const SGPropertyNode * node = getNode(relative_path);
1188 return (node == 0 ? SGValue::UNKNOWN : node->getType());
1193 * Get a bool value for another node.
1196 SGPropertyNode::getBoolValue (const string &relative_path,
1197 bool defaultValue) const
1199 const SGPropertyNode * node = getNode(relative_path);
1200 return (node == 0 ? defaultValue : node->getBoolValue());
1205 * Get an int value for another node.
1208 SGPropertyNode::getIntValue (const string &relative_path,
1209 int defaultValue) const
1211 const SGPropertyNode * node = getNode(relative_path);
1212 return (node == 0 ? defaultValue : node->getIntValue());
1217 * Get a float value for another node.
1220 SGPropertyNode::getFloatValue (const string &relative_path,
1221 float defaultValue) const
1223 const SGPropertyNode * node = getNode(relative_path);
1224 return (node == 0 ? defaultValue : node->getFloatValue());
1229 * Get a double value for another node.
1232 SGPropertyNode::getDoubleValue (const string &relative_path,
1233 double defaultValue) const
1235 const SGPropertyNode * node = getNode(relative_path);
1236 return (node == 0 ? defaultValue : node->getDoubleValue());
1241 * Get a string value for another node.
1244 SGPropertyNode::getStringValue (const string &relative_path,
1245 string defaultValue) const
1247 const SGPropertyNode * node = getNode(relative_path);
1248 return (node == 0 ? defaultValue : node->getStringValue());
1253 * Set a bool value for another node.
1256 SGPropertyNode::setBoolValue (const string &relative_path, bool value)
1258 return getNode(relative_path, true)->setBoolValue(value);
1263 * Set an int value for another node.
1266 SGPropertyNode::setIntValue (const string &relative_path, int value)
1268 return getNode(relative_path, true)->setIntValue(value);
1273 * Set a float value for another node.
1276 SGPropertyNode::setFloatValue (const string &relative_path, float value)
1278 return getNode(relative_path, true)->setFloatValue(value);
1283 * Set a double value for another node.
1286 SGPropertyNode::setDoubleValue (const string &relative_path, double value)
1288 return getNode(relative_path, true)->setDoubleValue(value);
1293 * Set a string value for another node.
1296 SGPropertyNode::setStringValue (const string &relative_path, string value)
1298 return getNode(relative_path, true)->setStringValue(value);
1303 * Set an unknown value for another node.
1306 SGPropertyNode::setUnknownValue (const string &relative_path, string value)
1308 return getNode(relative_path, true)->setUnknownValue(value);
1313 * Test whether another node is tied.
1316 SGPropertyNode::isTied (const string &relative_path) const
1318 const SGPropertyNode * node = getNode(relative_path);
1319 return (node == 0 ? false : node->isTied());
1324 * Tie a node reached by a relative path, creating it if necessary.
1327 SGPropertyNode::tie (const string &relative_path,
1328 const SGRawValue<bool> &rawValue,
1331 return getNode(relative_path, true)->tie(rawValue, useDefault);
1336 * Tie a node reached by a relative path, creating it if necessary.
1339 SGPropertyNode::tie (const string &relative_path,
1340 const SGRawValue<int> &rawValue,
1343 return getNode(relative_path, true)->tie(rawValue, useDefault);
1348 * Tie a node reached by a relative path, creating it if necessary.
1351 SGPropertyNode::tie (const string &relative_path,
1352 const SGRawValue<float> &rawValue,
1355 return getNode(relative_path, true)->tie(rawValue, useDefault);
1360 * Tie a node reached by a relative path, creating it if necessary.
1363 SGPropertyNode::tie (const string &relative_path,
1364 const SGRawValue<double> &rawValue,
1367 return getNode(relative_path, true)->tie(rawValue, useDefault);
1372 * Tie a node reached by a relative path, creating it if necessary.
1375 SGPropertyNode::tie (const string &relative_path,
1376 const SGRawValue<string> &rawValue,
1379 return getNode(relative_path, true)->tie(rawValue, useDefault);
1384 * Attempt to untie another node reached by a relative path.
1387 SGPropertyNode::untie (const string &relative_path)
1389 SGPropertyNode * node = getNode(relative_path);
1390 return (node == 0 ? false : node->untie());