1 // props.hxx - interface definition for 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].
21 ////////////////////////////////////////////////////////////////////////
22 // Convenience macros for value access.
23 ////////////////////////////////////////////////////////////////////////
25 #define GET_BOOL (_value.bool_val->getValue())
26 #define GET_INT (_value.int_val->getValue())
27 #define GET_FLOAT (_value.float_val->getValue())
28 #define GET_DOUBLE (_value.double_val->getValue())
29 #define GET_STRING (_value.string_val->getValue())
31 #define SET_BOOL(val) (_value.bool_val->setValue(val))
32 #define SET_INT(val) (_value.int_val->setValue(val))
33 #define SET_FLOAT(val) (_value.float_val->setValue(val))
34 #define SET_DOUBLE(val) (_value.double_val->setValue(val))
35 #define SET_STRING(val) (_value.string_val->setValue(val))
39 ////////////////////////////////////////////////////////////////////////
40 // Default values for every type.
41 ////////////////////////////////////////////////////////////////////////
43 const bool SGRawValue<bool>::DefaultValue = false;
44 const int SGRawValue<int>::DefaultValue = 0;
45 const float SGRawValue<float>::DefaultValue = 0.0;
46 const double SGRawValue<double>::DefaultValue = 0.0L;
47 const string SGRawValue<string>::DefaultValue = "";
51 ////////////////////////////////////////////////////////////////////////
52 // Local path normalization code.
53 ////////////////////////////////////////////////////////////////////////
56 * A component in a path.
65 * Parse the name for a path component.
67 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
70 parse_name (const string &path, int &i)
73 int max = path.size();
77 if (i < max && path[i] == '.') {
83 if (i < max && path[i] != '/')
84 throw string(string("Illegal character after ") + name);
87 else if (isalpha(path[i]) || path[i] == '_') {
91 // The rules inside a name are a little
94 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
95 path[i] == '-' || path[i] == '.') {
97 } else if (path[i] == '[' || path[i] == '/') {
100 throw string("name may contain only ._- and alphanumeric characters");
107 if (name.size() == 0)
108 throw string("name must begin with alpha or '_'");
116 * Parse the optional integer index for a path component.
118 * Index: "[" [0-9]+ "]"
121 parse_index (const string &path, int &i)
130 for (int max = path.size(); i < max; i++) {
131 if (isdigit(path[i])) {
132 index = (index * 10) + (path[i] - '0');
133 } else if (path[i] == ']') {
141 throw string("unterminated index (looking for ']')");
146 * Parse a single path component.
148 * Component: Name Index?
150 static inline PathComponent
151 parse_component (const string &path, int &i)
153 PathComponent component;
154 component.name = parse_name(path, i);
155 if (component.name[0] != '.')
156 component.index = parse_index(path, i);
158 component.index = -1;
164 * Parse a path into its components.
167 parse_path (const string &path, vector<PathComponent> &components)
170 int max = path.size();
172 // Check for initial '/'
173 if (path[pos] == '/') {
177 components.push_back(root);
179 while (pos < max && path[pos] == '/')
184 components.push_back(parse_component(path, pos));
185 while (pos < max && path[pos] == '/')
192 ////////////////////////////////////////////////////////////////////////
193 // Other static utility functions.
194 ////////////////////////////////////////////////////////////////////////
198 * Locate a child node by name and index.
201 find_child (const string &name, int index, vector<SGPropertyNode *> nodes)
203 int nNodes = nodes.size();
204 for (int i = 0; i < nNodes; i++) {
205 SGPropertyNode * node = nodes[i];
206 if (node->getName() == name && node->getIndex() == index)
214 * Locate another node, given a relative path.
216 static SGPropertyNode *
217 find_node (SGPropertyNode * current,
218 const vector<PathComponent> &components,
226 else if (position >= components.size()) {
230 else if (components[position].name == "") {
231 return find_node(current->getRootNode(), components, position + 1, create);
234 else if (components[position].name == ".") {
235 return find_node(current, components, position + 1, create);
238 else if (components[position].name == "..") {
239 SGPropertyNode * parent = current->getParent();
241 throw string("Attempt to move past root with '..'");
243 return find_node(parent, components, position + 1, create);
247 SGPropertyNode * child =
248 current->getChild(components[position].name,
249 components[position].index,
251 return find_node(child, components, position + 1, create);
257 ////////////////////////////////////////////////////////////////////////
258 // Implementation of SGValue.
259 ////////////////////////////////////////////////////////////////////////
263 * Default constructor.
265 * The type will be UNKNOWN and the raw value will be "".
268 : _type(UNKNOWN), _tied(false)
270 _value.string_val = new SGRawValueInternal<string>;
277 SGValue::SGValue (const SGValue &source)
279 _type = source._type;
280 _tied = source._tied;
281 switch (source._type) {
283 _value.bool_val = source._value.bool_val->clone();
286 _value.int_val = source._value.int_val->clone();
289 _value.float_val = source._value.float_val->clone();
292 _value.double_val = source._value.double_val->clone();
296 _value.string_val = source._value.string_val->clone();
312 * Delete and clear the current value.
315 SGValue::clear_value ()
319 delete _value.bool_val;
323 delete _value.int_val;
327 delete _value.float_val;
328 _value.float_val = 0;
331 delete _value.double_val;
332 _value.double_val = 0;
336 delete _value.string_val;
337 _value.string_val = 0;
344 * Get a boolean value.
347 SGValue::getBoolValue () const
353 return GET_INT == 0 ? false : true;
355 return GET_FLOAT == 0.0 ? false : true;
357 return GET_DOUBLE == 0.0L ? false : true;
360 return (GET_STRING == "true" || getDoubleValue() != 0.0L);
366 * Get an integer value.
369 SGValue::getIntValue () const
373 return (int)GET_BOOL;
377 return (int)GET_FLOAT;
379 return (int)GET_DOUBLE;
382 return atoi(GET_STRING.c_str());
391 SGValue::getFloatValue () const
395 return (float)GET_BOOL;
397 return (float)GET_INT;
404 return atof(GET_STRING.c_str());
410 * Get a double value.
413 SGValue::getDoubleValue () const
417 return (double)GET_BOOL;
419 return (double)GET_INT;
421 return (double)GET_FLOAT;
426 return (double)atof(GET_STRING.c_str());
432 * Get a string value.
435 SGValue::getStringValue () const
446 sprintf(buf, "%d", GET_INT);
449 sprintf(buf, "%f", GET_FLOAT);
452 sprintf(buf, "%lf", GET_DOUBLE);
465 SGValue::setBoolValue (bool value)
467 if (_type == UNKNOWN) {
469 _value.bool_val = new SGRawValueInternal<bool>;
475 return SET_BOOL(value);
477 return SET_INT((int)value);
479 return SET_FLOAT((float)value);
481 return SET_DOUBLE((double)value);
483 return SET_STRING(value ? "true" : "false");
494 SGValue::setIntValue (int value)
496 if (_type == UNKNOWN) {
498 _value.int_val = new SGRawValueInternal<int>;
504 return SET_BOOL(value == 0 ? false : true);
506 return SET_INT(value);
508 return SET_FLOAT((float)value);
510 return SET_DOUBLE((double)value);
513 sprintf(buf, "%d", value);
514 return SET_STRING(buf);
526 SGValue::setFloatValue (float value)
528 if (_type == UNKNOWN) {
530 _value.float_val = new SGRawValueInternal<float>;
536 return SET_BOOL(value == 0.0 ? false : true);
538 return SET_INT((int)value);
540 return SET_FLOAT(value);
542 return SET_DOUBLE((double)value);
545 sprintf(buf, "%f", value);
546 return SET_STRING(buf);
555 * Set a double value.
558 SGValue::setDoubleValue (double value)
560 if (_type == UNKNOWN) {
562 _value.double_val = new SGRawValueInternal<double>;
568 return SET_BOOL(value == 0.0L ? false : true);
570 return SET_INT((int)value);
572 return SET_FLOAT((float)value);
574 return SET_DOUBLE(value);
577 sprintf(buf, "%lf", value);
578 return SET_STRING(buf);
587 * Set a string value.
590 SGValue::setStringValue (string value)
592 if (_type == UNKNOWN) {
594 _value.string_val = new SGRawValueInternal<string>;
600 return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
602 return SET_INT(atoi(value.c_str()));
604 return SET_FLOAT(atof(value.c_str()));
606 return SET_DOUBLE((double)atof(value.c_str()));
608 return SET_STRING(value);
616 * Set a value of unknown type (stored as a string).
619 SGValue::setUnknownValue (string value)
623 return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
625 return SET_INT(atoi(value.c_str()));
627 return SET_FLOAT(atof(value.c_str()));
629 return SET_DOUBLE((double)atof(value.c_str()));
632 return SET_STRING(value);
643 SGValue::tie (const SGRawValue<bool> &value, bool use_default)
650 old_val = getBoolValue();
655 _value.bool_val = value.clone();
658 setBoolValue(old_val);
668 SGValue::tie (const SGRawValue<int> &value, bool use_default)
675 old_val = getIntValue();
680 _value.int_val = value.clone();
683 setIntValue(old_val);
693 SGValue::tie (const SGRawValue<float> &value, bool use_default)
700 old_val = getFloatValue();
705 _value.float_val = value.clone();
708 setFloatValue(old_val);
715 * Tie a double value.
718 SGValue::tie (const SGRawValue<double> &value, bool use_default)
725 old_val = getDoubleValue();
730 _value.double_val = value.clone();
733 setDoubleValue(old_val);
740 * Tie a string value.
743 SGValue::tie (const SGRawValue<string> &value, bool use_default)
750 old_val = getStringValue();
755 _value.string_val = value.clone();
758 setStringValue(old_val);
775 bool val = getBoolValue();
777 _value.bool_val = new SGRawValueInternal<bool>;
782 int val = getIntValue();
784 _value.int_val = new SGRawValueInternal<int>;
789 float val = getFloatValue();
791 _value.float_val = new SGRawValueInternal<float>;
796 double val = getDoubleValue();
798 _value.double_val = new SGRawValueInternal<double>;
803 string val = getStringValue();
805 _value.string_val = new SGRawValueInternal<string>;
817 ////////////////////////////////////////////////////////////////////////
818 // Implementation of SGPropertyNode.
819 ////////////////////////////////////////////////////////////////////////
823 * Default constructor: always creates a root node.
825 SGPropertyNode::SGPropertyNode ()
826 : _value(0), _name(""), _index(0), _parent(0)
832 * Convenience constructor.
834 SGPropertyNode::SGPropertyNode (const string &name,
835 int index, SGPropertyNode * parent)
836 : _value(0), _name(name), _index(index), _parent(parent)
840 SGPropertyNode::~SGPropertyNode ()
843 for (int i = 0; i < _children.size(); i++)
848 SGPropertyNode::getChild (int position)
850 if (position >= 0 && position < nChildren())
851 return _children[position];
856 const SGPropertyNode *
857 SGPropertyNode::getChild (int position) const
859 if (position >= 0 && position < nChildren())
860 return _children[position];
866 SGPropertyNode::getChild (const string &name, int index, bool create)
868 int pos = find_child(name, index, _children);
870 return getChild(pos);
872 _children.push_back(new SGPropertyNode(name, index, this));
873 return _children[_children.size()-1];
879 const SGPropertyNode *
880 SGPropertyNode::getChild (const string &name, int index) const
882 int pos = find_child(name, index, _children);
884 _children[_children.size()-1];
893 int operator() (const SGPropertyNode * n1, const SGPropertyNode *n2) const {
894 return (n1->getIndex() < n2->getIndex());
900 * Get all children with the same name (but different indices).
902 vector<SGPropertyNode *>
903 SGPropertyNode::getChildren (const string &name)
905 vector<SGPropertyNode *> children;
906 int max = _children.size();
908 for (int i = 0; i < max; i++)
909 if (_children[i]->getName() == name)
910 children.push_back(_children[i]);
912 sort(children.begin(), children.end(), CompareIndices());
918 * Get all children with the same name (but different indices).
920 vector<const SGPropertyNode *>
921 SGPropertyNode::getChildren (const string &name) const
923 vector<const SGPropertyNode *> children;
924 int max = _children.size();
926 for (int i = 0; i < max; i++)
927 if (_children[i]->getName() == name)
928 children.push_back(_children[i]);
930 sort(children.begin(), children.end(), CompareIndices());
936 SGPropertyNode::getPath (bool simplify) const
941 string path = _parent->getPath(simplify);
944 if (_index != 0 || !simplify) {
946 sprintf(buffer, "[%d]", _index);
953 SGPropertyNode::getType () const
956 return _value->getType();
958 return SGValue::UNKNOWN;
962 SGPropertyNode::getBoolValue () const
964 return (_value == 0 ? SGRawValue<bool>::DefaultValue
965 : _value->getBoolValue());
969 SGPropertyNode::getIntValue () const
971 return (_value == 0 ? SGRawValue<int>::DefaultValue
972 : _value->getIntValue());
976 SGPropertyNode::getFloatValue () const
978 return (_value == 0 ? SGRawValue<float>::DefaultValue
979 : _value->getFloatValue());
983 SGPropertyNode::getDoubleValue () const
985 return (_value == 0 ? SGRawValue<double>::DefaultValue
986 : _value->getDoubleValue());
990 SGPropertyNode::getStringValue () const
992 return (_value == 0 ? SGRawValue<string>::DefaultValue
993 : _value->getStringValue());
997 SGPropertyNode::setBoolValue (bool val)
1000 _value = new SGValue();
1001 return _value->setBoolValue(val);
1005 SGPropertyNode::setIntValue (int val)
1008 _value = new SGValue();
1009 return _value->setIntValue(val);
1013 SGPropertyNode::setFloatValue (float val)
1016 _value = new SGValue();
1017 return _value->setFloatValue(val);
1021 SGPropertyNode::setDoubleValue (double val)
1024 _value = new SGValue();
1025 return _value->setDoubleValue(val);
1029 SGPropertyNode::setStringValue (string val)
1032 _value = new SGValue();
1033 return _value->setStringValue(val);
1037 SGPropertyNode::setUnknownValue (string val)
1040 _value = new SGValue();
1041 return _value->setUnknownValue(val);
1045 SGPropertyNode::isTied () const
1047 return (_value == 0 ? false : _value->isTied());
1051 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1053 return (_value == 0 ? false : _value->tie(rawValue, useDefault));
1057 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1059 return (_value == 0 ? false : _value->tie(rawValue, useDefault));
1063 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1065 return (_value == 0 ? false : _value->tie(rawValue, useDefault));
1069 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1071 return (_value == 0 ? false : _value->tie(rawValue, useDefault));
1075 SGPropertyNode::tie (const SGRawValue<string> &rawValue, bool useDefault)
1077 return (_value == 0 ? false : _value->tie(rawValue, useDefault));
1081 SGPropertyNode::untie ()
1083 return (_value == 0 ? false : _value->untie());
1087 SGPropertyNode::getRootNode ()
1092 return _parent->getRootNode();
1095 const SGPropertyNode *
1096 SGPropertyNode::getRootNode () const
1101 return _parent->getRootNode();
1105 SGPropertyNode::getNode (const string &relative_path, bool create)
1107 vector<PathComponent> components;
1108 parse_path(relative_path, components);
1109 return find_node(this, components, 0, create);
1112 const SGPropertyNode *
1113 SGPropertyNode::getNode (const string &relative_path) const
1115 vector<PathComponent> components;
1116 parse_path(relative_path, components);
1117 // FIXME: cast away const
1118 return find_node((SGPropertyNode *)this, components, 0, false);
1123 ////////////////////////////////////////////////////////////////////////
1124 // Convenience methods using relative paths.
1125 ////////////////////////////////////////////////////////////////////////
1129 * Test whether another node has a value attached.
1132 SGPropertyNode::hasValue (const string &relative_path) const
1134 const SGPropertyNode * node = getNode(relative_path);
1135 return (node == 0 ? false : node->hasValue());
1140 * Get the value for another node.
1143 SGPropertyNode::getValue (const string &relative_path, bool create)
1145 SGPropertyNode * node = getNode(relative_path, create);
1146 if (node != 0 && !node->hasValue())
1147 node->setUnknownValue("");
1148 return (node == 0 ? 0 : node->getValue());
1153 * Get the value for another node.
1156 SGPropertyNode::getValue (const string &relative_path) const
1158 const SGPropertyNode * node = getNode(relative_path);
1159 return (node == 0 ? 0 : node->getValue());
1164 * Get the value type for another node.
1167 SGPropertyNode::getType (const string &relative_path) const
1169 const SGPropertyNode * node = getNode(relative_path);
1170 return (node == 0 ? SGValue::UNKNOWN : node->getType());
1175 * Get a bool value for another node.
1178 SGPropertyNode::getBoolValue (const string &relative_path,
1179 bool defaultValue) const
1181 const SGPropertyNode * node = getNode(relative_path);
1182 return (node == 0 ? defaultValue : node->getBoolValue());
1187 * Get an int value for another node.
1190 SGPropertyNode::getIntValue (const string &relative_path,
1191 int defaultValue) const
1193 const SGPropertyNode * node = getNode(relative_path);
1194 return (node == 0 ? defaultValue : node->getIntValue());
1199 * Get a float value for another node.
1202 SGPropertyNode::getFloatValue (const string &relative_path,
1203 float defaultValue) const
1205 const SGPropertyNode * node = getNode(relative_path);
1206 return (node == 0 ? defaultValue : node->getFloatValue());
1211 * Get a double value for another node.
1214 SGPropertyNode::getDoubleValue (const string &relative_path,
1215 double defaultValue) const
1217 const SGPropertyNode * node = getNode(relative_path);
1218 return (node == 0 ? defaultValue : node->getDoubleValue());
1223 * Get a string value for another node.
1226 SGPropertyNode::getStringValue (const string &relative_path,
1227 string defaultValue) const
1229 const SGPropertyNode * node = getNode(relative_path);
1230 return (node == 0 ? defaultValue : node->getStringValue());
1235 * Set a bool value for another node.
1238 SGPropertyNode::setBoolValue (const string &relative_path, bool value)
1240 return getNode(relative_path, true)->setBoolValue(value);
1245 * Set an int value for another node.
1248 SGPropertyNode::setIntValue (const string &relative_path, int value)
1250 return getNode(relative_path, true)->setIntValue(value);
1255 * Set a float value for another node.
1258 SGPropertyNode::setFloatValue (const string &relative_path, float value)
1260 return getNode(relative_path, true)->setFloatValue(value);
1265 * Set a double value for another node.
1268 SGPropertyNode::setDoubleValue (const string &relative_path, double value)
1270 return getNode(relative_path, true)->setDoubleValue(value);
1275 * Set a string value for another node.
1278 SGPropertyNode::setStringValue (const string &relative_path, string value)
1280 return getNode(relative_path, true)->setStringValue(value);
1285 * Set an unknown value for another node.
1288 SGPropertyNode::setUnknownValue (const string &relative_path, string value)
1290 return getNode(relative_path, true)->setUnknownValue(value);
1295 * Test whether another node is tied.
1298 SGPropertyNode::isTied (const string &relative_path) const
1300 const SGPropertyNode * node = getNode(relative_path);
1301 return (node == 0 ? false : node->isTied());
1306 * Tie a node reached by a relative path, creating it if necessary.
1309 SGPropertyNode::tie (const string &relative_path,
1310 const SGRawValue<bool> &rawValue,
1311 bool useDefault = true)
1313 return getNode(relative_path, true)->tie(rawValue, useDefault);
1318 * Tie a node reached by a relative path, creating it if necessary.
1321 SGPropertyNode::tie (const string &relative_path,
1322 const SGRawValue<int> &rawValue,
1323 bool useDefault = true)
1325 return getNode(relative_path, true)->tie(rawValue, useDefault);
1330 * Tie a node reached by a relative path, creating it if necessary.
1333 SGPropertyNode::tie (const string &relative_path,
1334 const SGRawValue<float> &rawValue,
1335 bool useDefault = true)
1337 return getNode(relative_path, true)->tie(rawValue, useDefault);
1342 * Tie a node reached by a relative path, creating it if necessary.
1345 SGPropertyNode::tie (const string &relative_path,
1346 const SGRawValue<double> &rawValue,
1347 bool useDefault = true)
1349 return getNode(relative_path, true)->tie(rawValue, useDefault);
1354 * Tie a node reached by a relative path, creating it if necessary.
1357 SGPropertyNode::tie (const string &relative_path,
1358 const SGRawValue<string> &rawValue,
1359 bool useDefault = true)
1361 return getNode(relative_path, true)->tie(rawValue, useDefault);
1366 * Attempt to untie another node reached by a relative path.
1369 SGPropertyNode::untie (const string &relative_path)
1371 SGPropertyNode * node = getNode(relative_path);
1372 return (node == 0 ? false : node->untie());