|
From: Lasse Kärkkäi. <tr...@us...> - 2011-07-06 23:34:17
|
Author: Lasse Karkkainen <tro...@tr...>
Date: Mon Mar 28 23:54:42 2011 +0200
Enum values for config options and improved config parser diagnostics & error checking.
---
data/schema.xml | 8 ++++++--
game/configuration.cc | 45 +++++++++++++++++++++++++++++++++++----------
game/configuration.hh | 1 +
3 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/data/schema.xml b/data/schema.xml
index 3219b2f..4c1ee9e 100644
--- a/data/schema.xml
+++ b/data/schema.xml
@@ -132,10 +132,14 @@ to save the current settings to XML.
</locale>
</entry>
<entry name="graphic/stereo3dtype" type="int" value="0">
- <limits min="0" max="2" step="1" />
+ <limits>
+ <enum>Red/Cyan</enum>
+ <enum>Green/Magenta</enum>
+ <enum>Over/Under</enum>
+ </limits>
<locale name="C">
<short>Stereo3D type</short>
- <long>Some modes may only be activated in fullscreen mode. 0 = red/cyan, 1 = green/magenta, 2 = over/under.</long>
+ <long>Some modes may only get activated in fullscreen mode.</long>
</locale>
</entry>
<entry name="graphic/stereo3dseparation" type="float" value="50">
diff --git a/game/configuration.cc b/game/configuration.cc
index fdc1bcd..571a0f1 100644
--- a/game/configuration.cc
+++ b/game/configuration.cc
@@ -97,7 +97,11 @@ namespace {
}
std::string ConfigItem::getValue() const {
- if (m_type == "int") return numericFormat<int>(m_value, m_multiplier, m_step) + m_unit;
+ if (m_type == "int") {
+ int val = boost::get<int>(m_value);
+ if (val >= 0 && val < m_enums.size()) return m_enums[val];
+ return numericFormat<int>(m_value, m_multiplier, m_step) + m_unit;
+ }
if (m_type == "float") return numericFormat<double>(m_value, m_multiplier, m_step) + m_unit;
if (m_type == "bool") return boost::get<bool>(m_value) ? _("Enabled") : _("Disabled");
if (m_type == "string") return boost::get<std::string>(m_value);
@@ -131,12 +135,12 @@ namespace {
}
template <typename T, typename V> void setLimits(xmlpp::Element& e, V& min, V& max, V& step) {
- std::string value = getAttribute(e, "min");
- if (!value.empty()) min = boost::lexical_cast<T>(value);
- value = getAttribute(e, "max");
- if (!value.empty()) max = boost::lexical_cast<T>(value);
- value = getAttribute(e, "step");
- if (!value.empty()) step = boost::lexical_cast<T>(value);
+ xmlpp::Attribute* a = e.get_attribute("min");
+ if (a) min = boost::lexical_cast<T>(a->get_value());
+ a = e.get_attribute("max");
+ if (a) max = boost::lexical_cast<T>(a->get_value());
+ a = e.get_attribute("step");
+ if (a) step = boost::lexical_cast<T>(a->get_value());
}
}
@@ -162,10 +166,14 @@ template <typename T> void ConfigItem::updateNumeric(xmlpp::Element& elem, int m
}
}
-void ConfigItem::update(xmlpp::Element& elem, int mode) {
+
+void ConfigItem::update(xmlpp::Element& elem, int mode) try {
if (mode == 0) {
m_type = getAttribute(elem, "type");
if (m_type.empty()) throw std::runtime_error("Entry type attribute is missing");
+ } else {
+ std::string type = getAttribute(elem, "type");
+ if (!type.empty() && type != m_type) throw std::runtime_error("Entry type mismatch: " + getAttribute(elem, "name") + ": schema type = " + m_type + ", config type = " + type);
}
if (m_type == "bool") {
std::string value_string = getAttribute(elem, "value");
@@ -177,6 +185,19 @@ void ConfigItem::update(xmlpp::Element& elem, int mode) {
} else if (m_type == "int") {
std::string value_string = getAttribute(elem, "value");
if (!value_string.empty()) m_value = boost::lexical_cast<int>(value_string);
+ // Enum handling
+ if (mode == 0) {
+ xmlpp::NodeSet n2 = elem.find("limits/enum");
+ if (!n2.empty()) {
+ for (xmlpp::NodeSet::const_iterator it2 = n2.begin(), end2 = n2.end(); it2 != end2; ++it2) {
+ xmlpp::Element& elem2 = dynamic_cast<xmlpp::Element&>(**it2);
+ m_enums.push_back(elem2.get_child_text()->get_content());
+ }
+ m_min = 0;
+ m_max = int(m_enums.size() - 1);
+ m_step = 1;
+ }
+ }
updateNumeric<int>(elem, mode);
} else if (m_type == "float") {
std::string value_string = getAttribute(elem, "value");
@@ -200,8 +221,7 @@ void ConfigItem::update(xmlpp::Element& elem, int mode) {
value.push_back(elem2.get_content());
}
m_value = value;
- }
-
+ } else if (!m_type.empty()) throw std::runtime_error("Invalid value type in config schema: " + m_type);
{
// Update short description
xmlpp::NodeSet n2 = elem.find("locale/short/text()");
@@ -220,6 +240,9 @@ void ConfigItem::update(xmlpp::Element& elem, int mode) {
}
if (mode < 1) m_factoryDefaultValue = m_defaultValue = m_value;
if (mode < 2) m_defaultValue = m_value;
+} catch (std::exception& e) {
+ int line = elem.get_line();
+ throw std::runtime_error(boost::lexical_cast<std::string>(line) + ": Error while reading entry: " + e.what());
}
fs::path systemConfFile = "/etc/xdg/performous/config.xml";
@@ -334,6 +357,8 @@ void readConfigXML(fs::path const& file, int mode) {
int line = e.elem.get_line();
std::string name = e.elem.get_name();
throw std::runtime_error(file.string() + ":" + boost::lexical_cast<std::string>(line) + " element " + name + " " + e.message);
+ } catch (std::exception& e) {
+ throw std::runtime_error(file.string() + ":" + e.what());
}
}
diff --git a/game/configuration.hh b/game/configuration.hh
index 6699afd..82f2e6e 100644
--- a/game/configuration.hh
+++ b/game/configuration.hh
@@ -51,6 +51,7 @@ class ConfigItem {
Value m_value; ///< The current value
Value m_factoryDefaultValue; ///< The value from config schema
Value m_defaultValue; ///< The value from config schema or system config
+ std::vector<std::string> m_enums; ///< Enum value titles
boost::variant<int, double> m_step, m_min, m_max;
boost::variant<int, double> m_multiplier;
std::string m_unit;
|