mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-09 12:22:34 +01:00
rwgame+config: show an error dialog when an error occurred on parsing the config file
This commit is contained in:
parent
76f2665acf
commit
e28e429b86
@ -17,8 +17,7 @@ GameBase::GameBase(Logger &inlog, int argc, char *argv[]) : log(inlog) {
|
|||||||
+ config.getConfigFile() + "\".\n"
|
+ config.getConfigFile() + "\".\n"
|
||||||
+ "Adapt the following default INI to your configuration.\n"
|
+ "Adapt the following default INI to your configuration.\n"
|
||||||
+ config.getDefaultINIString());
|
+ config.getDefaultINIString());
|
||||||
throw std::runtime_error("Invalid configuration file at: " +
|
throw std::runtime_error(config.getParseResult().what());
|
||||||
config.getConfigFile());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t w = kWindowWidth, h = kWindowHeight;
|
size_t w = kWindowWidth, h = kWindowHeight;
|
||||||
@ -28,11 +27,12 @@ GameBase::GameBase(Logger &inlog, int argc, char *argv[]) : log(inlog) {
|
|||||||
// Define and parse command line options
|
// Define and parse command line options
|
||||||
namespace po = boost::program_options;
|
namespace po = boost::program_options;
|
||||||
po::options_description desc("Available options");
|
po::options_description desc("Available options");
|
||||||
desc.add_options()("help", "Show this help message")(
|
desc.add_options()(
|
||||||
|
"help", "Show this help message")(
|
||||||
"width,w", po::value<size_t>(), "Game resolution width in pixel")(
|
"width,w", po::value<size_t>(), "Game resolution width in pixel")(
|
||||||
"height,h", po::value<size_t>(), "Game resolution height in pixel")(
|
"height,h", po::value<size_t>(), "Game resolution height in pixel")(
|
||||||
"fullscreen,f", "Enable fullscreen mode")("newgame,n",
|
"fullscreen,f", "Enable fullscreen mode")(
|
||||||
"Directly start a new game")(
|
"newgame,n", "Directly start a new game")(
|
||||||
"test,t", "Starts a new game in a test location")(
|
"test,t", "Starts a new game in a test location")(
|
||||||
"load,l", po::value<std::string>(), "Load save file")(
|
"load,l", po::value<std::string>(), "Load save file")(
|
||||||
"benchmark,b", po::value<std::string>(), "Run benchmark from file");
|
"benchmark,b", po::value<std::string>(), "Run benchmark from file");
|
||||||
|
@ -130,7 +130,7 @@ GameConfig::ParseResult GameConfig::parseConfig(
|
|||||||
ParseType destType, std::string &destination)
|
ParseType destType, std::string &destination)
|
||||||
{
|
{
|
||||||
pt::ptree srcTree;
|
pt::ptree srcTree;
|
||||||
ParseResult parseResult;
|
ParseResult parseResult(srcType, source, destType, destination);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (srcType == ParseType::STRING) {
|
if (srcType == ParseType::STRING) {
|
||||||
@ -140,7 +140,7 @@ GameConfig::ParseResult GameConfig::parseConfig(
|
|||||||
}
|
}
|
||||||
} catch (pt::ini_parser_error &e) {
|
} catch (pt::ini_parser_error &e) {
|
||||||
// Catches illegal input files (nonsensical input, duplicate keys)
|
// Catches illegal input files (nonsensical input, duplicate keys)
|
||||||
parseResult.failInputFile(e.filename(), e.line(), e.message());
|
parseResult.failInputFile(e.line(), e.message());
|
||||||
RW_MESSAGE(e.what());
|
RW_MESSAGE(e.what());
|
||||||
return parseResult;
|
return parseResult;
|
||||||
}
|
}
|
||||||
@ -226,16 +226,44 @@ GameConfig::ParseResult GameConfig::parseConfig(
|
|||||||
pt::write_ini(destination, srcTree);
|
pt::write_ini(destination, srcTree);
|
||||||
}
|
}
|
||||||
} catch (pt::ini_parser_error &e) {
|
} catch (pt::ini_parser_error &e) {
|
||||||
parseResult.failOutputFile(e.filename(), e.line(), e.message());
|
parseResult.failOutputFile(e.line(), e.message());
|
||||||
RW_MESSAGE(e.what());
|
RW_MESSAGE(e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseResult;
|
return parseResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GameConfig::extractFilenameParseTypeData(ParseType type, const std::string &data)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ParseType::CONFIG:
|
||||||
|
return "<configuration>";
|
||||||
|
case ParseType::FILE:
|
||||||
|
return data;
|
||||||
|
case ParseType::STRING:
|
||||||
|
return "<string>";
|
||||||
|
case ParseType::DEFAULT:
|
||||||
|
default:
|
||||||
|
return "<default>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameConfig::ParseResult::ParseResult(
|
||||||
|
GameConfig::ParseType srcType, const std::string &source,
|
||||||
|
GameConfig::ParseType destType, const std::string &destination)
|
||||||
|
: m_result(ErrorType::GOOD)
|
||||||
|
, m_inputfilename(GameConfig::extractFilenameParseTypeData(srcType, source))
|
||||||
|
, m_outputfilename(GameConfig::extractFilenameParseTypeData(destType, destination))
|
||||||
|
, m_line(0)
|
||||||
|
, m_message()
|
||||||
|
, m_keys_requiredMissing()
|
||||||
|
, m_keys_invalidData() {
|
||||||
|
}
|
||||||
|
|
||||||
GameConfig::ParseResult::ParseResult()
|
GameConfig::ParseResult::ParseResult()
|
||||||
: m_result(ErrorType::GOOD)
|
: m_result(ErrorType::GOOD)
|
||||||
, m_filename()
|
, m_inputfilename()
|
||||||
|
, m_outputfilename()
|
||||||
, m_line(0)
|
, m_line(0)
|
||||||
, m_message()
|
, m_message()
|
||||||
, m_keys_requiredMissing()
|
, m_keys_requiredMissing()
|
||||||
@ -250,10 +278,9 @@ bool GameConfig::ParseResult::isValid() const {
|
|||||||
return this->type() == ErrorType::GOOD;
|
return this->type() == ErrorType::GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameConfig::ParseResult::failInputFile(const std::string &filename, size_t line,
|
void GameConfig::ParseResult::failInputFile(size_t line,
|
||||||
const std::string &message) {
|
const std::string &message) {
|
||||||
this->m_result = ParseResult::ErrorType::INVALIDINPUTFILE;
|
this->m_result = ParseResult::ErrorType::INVALIDINPUTFILE;
|
||||||
this->m_filename = filename;
|
|
||||||
this->m_line = line;
|
this->m_line = line;
|
||||||
this->m_message = message;
|
this->m_message = message;
|
||||||
}
|
}
|
||||||
@ -272,9 +299,9 @@ void GameConfig::ParseResult::failInvalidData(const std::string &key) {
|
|||||||
this->m_keys_invalidData.push_back(key);
|
this->m_keys_invalidData.push_back(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameConfig::ParseResult::failOutputFile(const std::string &filename, size_t line, const std::string &message) {
|
void GameConfig::ParseResult::failOutputFile(size_t line,
|
||||||
|
const std::string &message) {
|
||||||
this->m_result = ParseResult::ErrorType::INVALIDOUTPUTFILE;
|
this->m_result = ParseResult::ErrorType::INVALIDOUTPUTFILE;
|
||||||
this->m_filename = filename;
|
|
||||||
this->m_line = line;
|
this->m_line = line;
|
||||||
this->m_message = message;
|
this->m_message = message;
|
||||||
}
|
}
|
||||||
@ -287,3 +314,48 @@ const std::vector<std::string> &GameConfig::ParseResult::getKeysInvalidData() co
|
|||||||
return this->m_keys_invalidData;
|
return this->m_keys_invalidData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GameConfig::ParseResult::what() const {
|
||||||
|
switch (this->m_result) {
|
||||||
|
case ErrorType::GOOD:
|
||||||
|
return "Good";
|
||||||
|
case ErrorType::INVALIDARGUMENT:
|
||||||
|
return "Invalid argument: destination cannot be the default config";
|
||||||
|
case ErrorType::INVALIDINPUTFILE:
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Error while reading \""
|
||||||
|
<< this->m_inputfilename << "\":" << this->m_line << ":\n"
|
||||||
|
<< this->m_message;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
case ErrorType::INVALIDOUTPUTFILE:
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Error while writing \""
|
||||||
|
<< this->m_inputfilename << "\":" << this->m_line << ":\n"
|
||||||
|
<< this->m_message;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
case ErrorType::INVALIDCONTENT:
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Error while parsing \""
|
||||||
|
<< this->m_inputfilename << "\".";
|
||||||
|
if (this->m_keys_requiredMissing.size()) {
|
||||||
|
oss << "\nRequired keys that are missing:";
|
||||||
|
for (auto &key : this->m_keys_requiredMissing) {
|
||||||
|
oss << "\n - " << key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this->m_keys_invalidData.size()) {
|
||||||
|
oss << "\nKeys that contain invalid data:";
|
||||||
|
for (auto &key : this->m_keys_invalidData) {
|
||||||
|
oss << "\n - " << key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,19 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class GameConfig {
|
class GameConfig {
|
||||||
|
private:
|
||||||
|
enum ParseType {
|
||||||
|
DEFAULT,
|
||||||
|
CONFIG,
|
||||||
|
FILE,
|
||||||
|
STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief extractFilenameParseTypeData Get a human readable filename string
|
||||||
|
* @return file path or a description of the data type
|
||||||
|
*/
|
||||||
|
static std::string extractFilenameParseTypeData(ParseType type, const std::string &data);
|
||||||
public:
|
public:
|
||||||
class ParseResult {
|
class ParseResult {
|
||||||
public:
|
public:
|
||||||
@ -19,11 +32,23 @@ public:
|
|||||||
/// INVALIDOUTPUTFILE: There was some error while writing to a file or string
|
/// INVALIDOUTPUTFILE: There was some error while writing to a file or string
|
||||||
INVALIDOUTPUTFILE
|
INVALIDOUTPUTFILE
|
||||||
};
|
};
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief ParseResult Holds the issues occurred while parsing of a config file.
|
* @brief ParseResult Holds the issues occurred while parsing of a config file.
|
||||||
|
* @param srcType Type of the source
|
||||||
|
* @param source The source of the parser
|
||||||
|
* @param destType Type of the destination
|
||||||
|
* @param destination The destination
|
||||||
*/
|
*/
|
||||||
|
ParseResult(ParseType srcType, const std::string &source,
|
||||||
|
ParseType destType, const std::string &destination);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ParseResult Create empty ParseResult
|
||||||
|
*/
|
||||||
ParseResult();
|
ParseResult();
|
||||||
|
|
||||||
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief type Get the type of error
|
* @brief type Get the type of error
|
||||||
* @return Type of error or GOOD if there was no error
|
* @return Type of error or GOOD if there was no error
|
||||||
@ -43,14 +68,15 @@ public:
|
|||||||
const std::vector<std::string> &getKeysInvalidData() const;
|
const std::vector<std::string> &getKeysInvalidData() const;
|
||||||
/**
|
/**
|
||||||
* @brief failInputFile Fail because the input file was invalid
|
* @brief failInputFile Fail because the input file was invalid
|
||||||
* @param filename Filename of the invalid file
|
|
||||||
* @param line Line number where the error is located
|
* @param line Line number where the error is located
|
||||||
* @param message Description of the error
|
* @param message Description of the error
|
||||||
*/
|
*/
|
||||||
void failInputFile(const std::string &filename, size_t line, const std::string &message);
|
void failInputFile(size_t line, const std::string &message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief failArgument Fail because an argument was invalid
|
* @brief failArgument Fail because an argument was invalid
|
||||||
|
* @param srcType type of the source
|
||||||
|
* @param destType type of the destination
|
||||||
*/
|
*/
|
||||||
void failArgument();
|
void failArgument();
|
||||||
|
|
||||||
@ -68,23 +94,31 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief failOutputFile Fail because an error occurred while while writing to the output
|
* @brief failOutputFile Fail because an error occurred while while writing to the output
|
||||||
* @param filename Filename of the invalid file
|
|
||||||
* @param line Line number where the error is located
|
* @param line Line number where the error is located
|
||||||
* @param message Description of the error
|
* @param message Description of the error
|
||||||
*/
|
*/
|
||||||
void failOutputFile(const std::string &filename, size_t line, const std::string &message);
|
void failOutputFile(size_t line, const std::string &message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief isValid
|
* @brief isValid
|
||||||
* @return True if the loaded configuration is valid
|
* @return True if the loaded configuration is valid
|
||||||
*/
|
*/
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief what Get a string representing the error
|
||||||
|
* @return String with the error description
|
||||||
|
*/
|
||||||
|
std::string what() const;
|
||||||
private:
|
private:
|
||||||
/// Type of the failure
|
/// Type of the failure
|
||||||
ErrorType m_result;
|
ErrorType m_result;
|
||||||
|
|
||||||
/// Filename of the invalid input or output file
|
/// Filename of the input file
|
||||||
std::string m_filename;
|
std::string m_inputfilename;
|
||||||
|
|
||||||
|
/// Filename of the output file
|
||||||
|
std::string m_outputfilename;
|
||||||
|
|
||||||
/// Line number where the failure occurred (on invalid input or output file)
|
/// Line number where the failure occurred (on invalid input or output file)
|
||||||
size_t m_line;
|
size_t m_line;
|
||||||
@ -97,6 +131,8 @@ public:
|
|||||||
|
|
||||||
/// All keys that contain invalid data
|
/// All keys that contain invalid data
|
||||||
std::vector<std::string> m_keys_invalidData;
|
std::vector<std::string> m_keys_invalidData;
|
||||||
|
|
||||||
|
friend class GameConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,13 +184,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
static std::string getDefaultConfigPath();
|
static std::string getDefaultConfigPath();
|
||||||
|
|
||||||
enum ParseType {
|
|
||||||
DEFAULT,
|
|
||||||
CONFIG,
|
|
||||||
FILE,
|
|
||||||
STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief parseConfig Load data from source and write it to destination.
|
* @brief parseConfig Load data from source and write it to destination.
|
||||||
* @param srcType Can be DEFAULT | CONFIG | FILE | STRING
|
* @param srcType Can be DEFAULT | CONFIG | FILE | STRING
|
||||||
|
@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(test_config_valid) {
|
|||||||
GameConfig config(tempFile.filename(), tempFile.dirname());
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
||||||
|
|
||||||
BOOST_CHECK(config.isValid());
|
BOOST_CHECK(config.isValid());
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::GOOD);
|
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ BOOST_AUTO_TEST_CASE(test_config_valid_modified) {
|
|||||||
GameConfig config(tempFile.filename(), tempFile.dirname());
|
GameConfig config(tempFile.filename(), tempFile.dirname());
|
||||||
|
|
||||||
BOOST_CHECK(config.isValid());
|
BOOST_CHECK(config.isValid());
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::GOOD);
|
BOOST_CHECK_EQUAL(config.getParseResult().type(), GameConfig::ParseResult::ErrorType::GOOD);
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysRequiredMissing().size(), 0);
|
||||||
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
BOOST_CHECK_EQUAL(config.getParseResult().getKeysInvalidData().size(), 0);
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE(test_config_save_readonly) {
|
|||||||
|
|
||||||
auto writeResult = config.saveConfig();
|
auto writeResult = config.saveConfig();
|
||||||
BOOST_CHECK(!writeResult.isValid());
|
BOOST_CHECK(!writeResult.isValid());
|
||||||
BOOST_CHECK_EQUAL(writeResult.type(), GameConfig::ParseResult::INVALIDOUTPUTFILE);
|
BOOST_CHECK_EQUAL(writeResult.type(), GameConfig::ParseResult::ErrorType::INVALIDOUTPUTFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_config_valid_default) {
|
BOOST_AUTO_TEST_CASE(test_config_valid_default) {
|
||||||
@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_duplicate) {
|
|||||||
|
|
||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
const auto &parseResult = config.getParseResult();
|
const auto &parseResult = config.getParseResult();
|
||||||
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::INVALIDINPUTFILE);
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
|
BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
|
||||||
@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_required_missing) {
|
|||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
const auto &parseResult = config.getParseResult();
|
||||||
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::INVALIDCONTENT);
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 1);
|
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 1);
|
||||||
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 0);
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 0);
|
||||||
@ -258,7 +258,7 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_wrong_type) {
|
|||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
const auto &parseResult = config.getParseResult();
|
||||||
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::INVALIDCONTENT);
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 0);
|
BOOST_CHECK_EQUAL(parseResult.getKeysRequiredMissing().size(), 0);
|
||||||
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 1);
|
BOOST_CHECK_EQUAL(parseResult.getKeysInvalidData().size(), 1);
|
||||||
@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_empty) {
|
|||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
const auto &parseResult = config.getParseResult();
|
||||||
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::INVALIDCONTENT);
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDCONTENT);
|
||||||
BOOST_CHECK_GE(parseResult.getKeysRequiredMissing().size(), 1);
|
BOOST_CHECK_GE(parseResult.getKeysRequiredMissing().size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +292,7 @@ BOOST_AUTO_TEST_CASE(test_config_invalid_nonexisting) {
|
|||||||
BOOST_CHECK(!config.isValid());
|
BOOST_CHECK(!config.isValid());
|
||||||
|
|
||||||
const auto &parseResult = config.getParseResult();
|
const auto &parseResult = config.getParseResult();
|
||||||
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::INVALIDINPUTFILE);
|
BOOST_CHECK_EQUAL(parseResult.type(), GameConfig::ParseResult::ErrorType::INVALIDINPUTFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
Reference in New Issue
Block a user