From 7e0962c5ea0f7cf5ebb24cb1dd63f88d940935e7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 01:09:34 +0100 Subject: [PATCH 01/14] Make # only start a comment in openmw.cfg if it starts a line and introduct compilation errors --- apps/openmw/main.cpp | 13 +-- components/fallback/validate.hpp | 4 +- components/files/configurationmanager.cpp | 114 +++++++++++++++++++++- components/files/configurationmanager.hpp | 43 ++++++++ 4 files changed, 165 insertions(+), 9 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index a4bf1fe5b..e4a918271 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -69,7 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { // Create a local alias for brevity namespace bpo = boost::program_options; - typedef std::vector StringsVector; + typedef Files::EscapeHashString string; + typedef std::vector StringsVector; bpo::options_description desc("Syntax: openmw \nAllowed options"); @@ -79,13 +80,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("data", bpo::value()->default_value(Files::PathContainer(), "data") ->multitoken()->composing(), "set data directories (later directories have higher priority)") - ("data-local", bpo::value()->default_value(""), + ("data-local", bpo::value()->default_value(""), "set local data directory (highest priority)") ("fallback-archive", bpo::value()->default_value(StringsVector(), "fallback-archive") ->multitoken(), "set fallback BSA archives (later archives have higher priority)") - ("resources", bpo::value()->default_value("resources"), + ("resources", bpo::value()->default_value("resources"), "set resources directory") ("start", bpo::value()->default_value(""), @@ -109,7 +110,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-console", bpo::value()->implicit_value(true) ->default_value(false), "enable console-only script functionality") - ("script-run", bpo::value()->default_value(""), + ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") ("script-warn", bpo::value()->implicit_value (1) @@ -125,7 +126,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-blacklist-use", bpo::value()->implicit_value(true) ->default_value(true), "enable script blacklisting") - ("load-savegame", bpo::value()->default_value(""), + ("load-savegame", bpo::value()->default_value(""), "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) @@ -137,7 +138,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") - ( "encoding", bpo::value()-> + ( "encoding", bpo::value()-> default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 3b6398d6a..531711544 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -3,6 +3,8 @@ #include +#include + // Parses and validates a fallback map from boost program_options. // Note: for boost to pick up the validate function, you need to pull in the namespace e.g. // by using namespace Fallback; @@ -11,7 +13,7 @@ namespace Fallback { struct FallbackMap { - std::map mMap; + std::map mMap; }; void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 5ac3dd695..c50303d97 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -3,9 +3,11 @@ #include #include #include +#include #include #include +#include #include /** @@ -139,8 +141,11 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, if (!mSilent) std::cout << "Loading config file: " << cfgFile.string() << "... "; - boost::filesystem::ifstream configFileStream(cfgFile); - if (configFileStream.is_open()) + boost::filesystem::ifstream configFileStreamUnfiltered(cfgFile); + boost::iostreams::filtering_istream configFileStream; + configFileStream.push(escape_hash_filter()); + configFileStream.push(configFileStreamUnfiltered); + if (configFileStreamUnfiltered.is_open()) { boost::program_options::store(boost::program_options::parse_config_file( configFileStream, description, true), variables); @@ -159,6 +164,111 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, return false; } +escape_hash_filter::escape_hash_filter() : mNext() +{ +} + +escape_hash_filter::~escape_hash_filter() +{ +} + +template +int escape_hash_filter::get(Source & src) +{ + if (mNext.empty()) + { + int character = boost::iostreams::get(src); + bool record = true; + if (character == boost::iostreams::WOULD_BLOCK) + { + mNext.push(character); + record = false; + } + else if (character == EOF) + { + seenNonWhitespace = false; + finishLine = false; + mNext.push(character); + } + else if (character == '\n') + { + seenNonWhitespace = false; + finishLine = false; + mNext.push(character); + } + else if (finishLine) + { + mNext.push(character); + } + else if (character == '#') + { + if (seenNonWhitespace) + { + mNext.push(sEscape); + mNext.push(sHashIdentifier); + } + else + { + //it's fine being interpreted by Boost as a comment, and so is anything afterwards + mNext.push(character); + finishLine = true; + } + } + else if (mPrevious == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + } + else + { + mNext.push(character); + } + if (!seenNonWhitespace && !isspace(character)) + seenNonWhitespace = true; + if (record) + mPrevious = character; + } + int retval = mNext.front(); + mNext.pop(); + return retval; +} + +std::string EscapeHashString::processString(const std::string & str) +{ + std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1)); + return temp; +} + +EscapeHashString::EscapeHashString() +{ +} + +EscapeHashString::EscapeHashString(const std::string & str) : std::string(EscapeHashString::processString(str)) +{ +} + +EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : std::string(EscapeHashString::processString(str), pos, len) +{ +} + +EscapeHashString::EscapeHashString(const char * s) : std::string(EscapeHashString::processString(std::string(s))) +{ +} + +EscapeHashString::EscapeHashString(const char * s, size_t n) : std::string(EscapeHashString::processString(std::string(s)), 0, n) +{ +} + +EscapeHashString::EscapeHashString(size_t n, char c) : std::string(n, c) +{ +} + +template +EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : std::string(EscapeHashString::processString(std::string(first, last))) +{ +} + const boost::filesystem::path& ConfigurationManager::getGlobalPath() const { return mFixedPath.getGlobalConfigPath(); diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index c05dbbb45..7ef7d6fae 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -2,8 +2,10 @@ #define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP #include +#include #include +#include #include #include @@ -63,6 +65,47 @@ struct ConfigurationManager bool mSilent; }; + +/** + * \struct escape_hash_filter + */ +struct escape_hash_filter : public boost::iostreams::input_filter +{ + static const int sEscape = '@'; + static const int sHashIdentifier = 'h'; + static const int sEscapeIdentifier = 'a'; + + escape_hash_filter(); + virtual ~escape_hash_filter(); + + template int get(Source & src); + + private: + std::queue mNext; + int mPrevious; + + bool seenNonWhitespace = false; + bool finishLine = false; +}; + +/** + * \class EscapeHashString + */ +class EscapeHashString : public std::string +{ + public: + static std::string processString(const std::string & str); + + EscapeHashString(); + EscapeHashString(const std::string & str); + EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos); + EscapeHashString(const char * s); + EscapeHashString(const char * s, size_t n); + EscapeHashString(size_t n, char c); + template + EscapeHashString(InputIterator first, InputIterator last); +}; + } /* namespace Cfg */ #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */ From e17e354e8438b8ee3d0a0d5785f8201b69dd4136 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 01:09:34 +0100 Subject: [PATCH 02/14] Make # only start a comment in openmw.cfg if it starts a line and introduct compilation errors --- apps/openmw/main.cpp | 13 +-- components/fallback/validate.hpp | 4 +- components/files/configurationmanager.cpp | 114 +++++++++++++++++++++- components/files/configurationmanager.hpp | 43 ++++++++ 4 files changed, 165 insertions(+), 9 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index a4bf1fe5b..e4a918271 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -69,7 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { // Create a local alias for brevity namespace bpo = boost::program_options; - typedef std::vector StringsVector; + typedef Files::EscapeHashString string; + typedef std::vector StringsVector; bpo::options_description desc("Syntax: openmw \nAllowed options"); @@ -79,13 +80,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("data", bpo::value()->default_value(Files::PathContainer(), "data") ->multitoken()->composing(), "set data directories (later directories have higher priority)") - ("data-local", bpo::value()->default_value(""), + ("data-local", bpo::value()->default_value(""), "set local data directory (highest priority)") ("fallback-archive", bpo::value()->default_value(StringsVector(), "fallback-archive") ->multitoken(), "set fallback BSA archives (later archives have higher priority)") - ("resources", bpo::value()->default_value("resources"), + ("resources", bpo::value()->default_value("resources"), "set resources directory") ("start", bpo::value()->default_value(""), @@ -109,7 +110,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-console", bpo::value()->implicit_value(true) ->default_value(false), "enable console-only script functionality") - ("script-run", bpo::value()->default_value(""), + ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") ("script-warn", bpo::value()->implicit_value (1) @@ -125,7 +126,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-blacklist-use", bpo::value()->implicit_value(true) ->default_value(true), "enable script blacklisting") - ("load-savegame", bpo::value()->default_value(""), + ("load-savegame", bpo::value()->default_value(""), "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) @@ -137,7 +138,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") - ( "encoding", bpo::value()-> + ( "encoding", bpo::value()-> default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 3b6398d6a..531711544 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -3,6 +3,8 @@ #include +#include + // Parses and validates a fallback map from boost program_options. // Note: for boost to pick up the validate function, you need to pull in the namespace e.g. // by using namespace Fallback; @@ -11,7 +13,7 @@ namespace Fallback { struct FallbackMap { - std::map mMap; + std::map mMap; }; void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 5ac3dd695..c50303d97 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -3,9 +3,11 @@ #include #include #include +#include #include #include +#include #include /** @@ -139,8 +141,11 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, if (!mSilent) std::cout << "Loading config file: " << cfgFile.string() << "... "; - boost::filesystem::ifstream configFileStream(cfgFile); - if (configFileStream.is_open()) + boost::filesystem::ifstream configFileStreamUnfiltered(cfgFile); + boost::iostreams::filtering_istream configFileStream; + configFileStream.push(escape_hash_filter()); + configFileStream.push(configFileStreamUnfiltered); + if (configFileStreamUnfiltered.is_open()) { boost::program_options::store(boost::program_options::parse_config_file( configFileStream, description, true), variables); @@ -159,6 +164,111 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, return false; } +escape_hash_filter::escape_hash_filter() : mNext() +{ +} + +escape_hash_filter::~escape_hash_filter() +{ +} + +template +int escape_hash_filter::get(Source & src) +{ + if (mNext.empty()) + { + int character = boost::iostreams::get(src); + bool record = true; + if (character == boost::iostreams::WOULD_BLOCK) + { + mNext.push(character); + record = false; + } + else if (character == EOF) + { + seenNonWhitespace = false; + finishLine = false; + mNext.push(character); + } + else if (character == '\n') + { + seenNonWhitespace = false; + finishLine = false; + mNext.push(character); + } + else if (finishLine) + { + mNext.push(character); + } + else if (character == '#') + { + if (seenNonWhitespace) + { + mNext.push(sEscape); + mNext.push(sHashIdentifier); + } + else + { + //it's fine being interpreted by Boost as a comment, and so is anything afterwards + mNext.push(character); + finishLine = true; + } + } + else if (mPrevious == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + } + else + { + mNext.push(character); + } + if (!seenNonWhitespace && !isspace(character)) + seenNonWhitespace = true; + if (record) + mPrevious = character; + } + int retval = mNext.front(); + mNext.pop(); + return retval; +} + +std::string EscapeHashString::processString(const std::string & str) +{ + std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1)); + return temp; +} + +EscapeHashString::EscapeHashString() +{ +} + +EscapeHashString::EscapeHashString(const std::string & str) : std::string(EscapeHashString::processString(str)) +{ +} + +EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : std::string(EscapeHashString::processString(str), pos, len) +{ +} + +EscapeHashString::EscapeHashString(const char * s) : std::string(EscapeHashString::processString(std::string(s))) +{ +} + +EscapeHashString::EscapeHashString(const char * s, size_t n) : std::string(EscapeHashString::processString(std::string(s)), 0, n) +{ +} + +EscapeHashString::EscapeHashString(size_t n, char c) : std::string(n, c) +{ +} + +template +EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : std::string(EscapeHashString::processString(std::string(first, last))) +{ +} + const boost::filesystem::path& ConfigurationManager::getGlobalPath() const { return mFixedPath.getGlobalConfigPath(); diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index c05dbbb45..7ef7d6fae 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -2,8 +2,10 @@ #define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP #include +#include #include +#include #include #include @@ -63,6 +65,47 @@ struct ConfigurationManager bool mSilent; }; + +/** + * \struct escape_hash_filter + */ +struct escape_hash_filter : public boost::iostreams::input_filter +{ + static const int sEscape = '@'; + static const int sHashIdentifier = 'h'; + static const int sEscapeIdentifier = 'a'; + + escape_hash_filter(); + virtual ~escape_hash_filter(); + + template int get(Source & src); + + private: + std::queue mNext; + int mPrevious; + + bool seenNonWhitespace = false; + bool finishLine = false; +}; + +/** + * \class EscapeHashString + */ +class EscapeHashString : public std::string +{ + public: + static std::string processString(const std::string & str); + + EscapeHashString(); + EscapeHashString(const std::string & str); + EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos); + EscapeHashString(const char * s); + EscapeHashString(const char * s, size_t n); + EscapeHashString(size_t n, char c); + template + EscapeHashString(InputIterator first, InputIterator last); +}; + } /* namespace Cfg */ #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */ From c1ffc9e7769c4ed7a33804e59a51e97016e47dfd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 01:59:16 +0100 Subject: [PATCH 03/14] Remove a compilation error and set up framework to remove the others --- apps/openmw/main.cpp | 2 +- components/files/configurationmanager.cpp | 16 ++++++++++++++++ components/files/configurationmanager.hpp | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index e4a918271..cd45ddcf5 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -242,7 +242,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setScriptConsoleMode (variables["script-console"].as()); engine.setStartupScript (variables["script-run"].as()); engine.setWarningsMode (variables["script-warn"].as()); - engine.setScriptBlacklist (variables["script-blacklist"].as()); + engine.setScriptBlacklist (string::toStdStringVector(variables["script-blacklist"].as())); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); engine.setSaveGameFile (variables["load-savegame"].as()); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index c50303d97..c7ac976d6 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -240,6 +240,17 @@ std::string EscapeHashString::processString(const std::string & str) return temp; } + +std::vector EscapeHashString::toStdStringVector(const std::vector & vec) +{ + std::vector temp = std::vector(); + for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) + { + temp.push_back(it->toStdString()); + } + return temp; +} + EscapeHashString::EscapeHashString() { } @@ -269,6 +280,11 @@ EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : st { } +std::string EscapeHashString::toStdString() const +{ + return std::string(* this); +} + const boost::filesystem::path& ConfigurationManager::getGlobalPath() const { return mFixedPath.getGlobalConfigPath(); diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 7ef7d6fae..47ecc9eb2 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -95,6 +95,7 @@ class EscapeHashString : public std::string { public: static std::string processString(const std::string & str); + static std::vector toStdStringVector(const std::vector & vec); EscapeHashString(); EscapeHashString(const std::string & str); @@ -104,6 +105,8 @@ class EscapeHashString : public std::string EscapeHashString(size_t n, char c); template EscapeHashString(InputIterator first, InputIterator last); + + std::string toStdString() const; }; } /* namespace Cfg */ From 2a9b12bb3fb844f30aba7d9fada0170e3b86c1c9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 14:15:35 +0100 Subject: [PATCH 04/14] Fix an issue preventing compilation, revealing another that doesn't make much sense. --- apps/openmw/main.cpp | 4 ++-- components/fallback/validate.hpp | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index cd45ddcf5..9be1e8a7f 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -145,7 +145,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" "\n\twin1252 - Western European (Latin) alphabet, used by default") - ("fallback", bpo::value()->default_value(FallbackMap(), "") + ("fallback", bpo::value()->default_value(EscapeFallbackMap(), "") ->multitoken()->composing(), "fallback values") ("no-grab", "Don't grab mouse cursor") @@ -248,7 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // other settings engine.setSoundUsage(!variables["no-sound"].as()); - engine.setFallbackValues(variables["fallback"].as().mMap); + engine.setFallbackValues(variables["fallback"].as().toFallbackMap().mMap); engine.setActivationDistanceOverride (variables["activate-dist"].as()); engine.enableFontExport(variables["export-fonts"].as()); diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 531711544..c41ff6b96 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -13,9 +13,22 @@ namespace Fallback { struct FallbackMap { - std::map mMap; + std::map mMap; }; + struct EscapeFallbackMap : FallbackMap + { + std::map mMap; + + FallbackMap toFallbackMap() const + { + FallbackMap temp = FallbackMap(); + for (std::map::const_iterator it = mMap.begin(); it != mMap.end(); ++it) + temp.mMap[it->first.toStdString()] = it->second.toStdString(); + return temp; + } + }; + void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) { if(v.empty()) From 7697406467d19bf39c568c35be2cc5293e082d35 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 14:39:38 +0100 Subject: [PATCH 05/14] Partially fix '2 overloads have similar conversions' compilation error --- components/fallback/validate.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index c41ff6b96..4df7da6e7 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -58,6 +58,10 @@ namespace Fallback } } + void validate(boost::any &v, std::vector const &tokens, EscapeFallbackMap* eFM, int a) + { + validate(v, tokens, (FallbackMap *)eFM, a); + } } #endif From fbe6dc97043bf2bfd52c4e44096b5bd967b40fa5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 21:33:36 +0100 Subject: [PATCH 06/14] Change compilation error to runtime exception and decide that inheriting from std::string may have been a bad idea in C++ --- apps/openmw/main.cpp | 17 +++--- components/fallback/validate.hpp | 65 +++++++++++++---------- components/files/configurationmanager.cpp | 6 +++ components/files/configurationmanager.hpp | 1 + 4 files changed, 52 insertions(+), 37 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 9be1e8a7f..645316f9c 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -69,8 +69,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { // Create a local alias for brevity namespace bpo = boost::program_options; - typedef Files::EscapeHashString string; - typedef std::vector StringsVector; + typedef std::vector StringsVector; bpo::options_description desc("Syntax: openmw \nAllowed options"); @@ -80,16 +79,16 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("data", bpo::value()->default_value(Files::PathContainer(), "data") ->multitoken()->composing(), "set data directories (later directories have higher priority)") - ("data-local", bpo::value()->default_value(""), + ("data-local", bpo::value()->default_value(""), "set local data directory (highest priority)") ("fallback-archive", bpo::value()->default_value(StringsVector(), "fallback-archive") ->multitoken(), "set fallback BSA archives (later archives have higher priority)") - ("resources", bpo::value()->default_value("resources"), + ("resources", bpo::value()->default_value("resources"), "set resources directory") - ("start", bpo::value()->default_value(""), + ("start", bpo::value()->default_value(""), "set initial cell") ("content", bpo::value()->default_value(StringsVector(), "") @@ -110,7 +109,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-console", bpo::value()->implicit_value(true) ->default_value(false), "enable console-only script functionality") - ("script-run", bpo::value()->default_value(""), + ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") ("script-warn", bpo::value()->implicit_value (1) @@ -126,7 +125,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-blacklist-use", bpo::value()->implicit_value(true) ->default_value(true), "enable script blacklisting") - ("load-savegame", bpo::value()->default_value(""), + ("load-savegame", bpo::value()->default_value(""), "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) @@ -138,7 +137,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") - ( "encoding", bpo::value()-> + ("encoding", bpo::value()-> default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" @@ -242,7 +241,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setScriptConsoleMode (variables["script-console"].as()); engine.setStartupScript (variables["script-run"].as()); engine.setWarningsMode (variables["script-warn"].as()); - engine.setScriptBlacklist (string::toStdStringVector(variables["script-blacklist"].as())); + engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as())); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); engine.setSaveGameFile (variables["load-savegame"].as()); diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 4df7da6e7..4c4897c27 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -12,11 +12,11 @@ namespace Fallback { - struct FallbackMap { - std::map mMap; - }; + struct FallbackMap { + std::map mMap; + }; - struct EscapeFallbackMap : FallbackMap + struct EscapeFallbackMap : FallbackMap { std::map mMap; @@ -29,34 +29,34 @@ namespace Fallback } }; - void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) - { - if(v.empty()) - { - v = boost::any(FallbackMap()); - } + void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) + { + if (v.empty()) + { + v = boost::any(FallbackMap()); + } - FallbackMap *map = boost::any_cast(&v); + FallbackMap *map = boost::any_cast(&v); - for(std::vector::const_iterator it=tokens.begin(); it != tokens.end(); ++it) - { - int sep = it->find(","); - if(sep < 1 || sep == (int)it->length()-1) - #if (BOOST_VERSION < 104200) - throw boost::program_options::validation_error("invalid value"); - #else - throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); - #endif + for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) + { + int sep = it->find(","); + if (sep < 1 || sep == (int)it->length() - 1) +#if (BOOST_VERSION < 104200) + throw boost::program_options::validation_error("invalid value"); +#else + throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); +#endif - std::string key(it->substr(0,sep)); - std::string value(it->substr(sep+1)); + std::string key(it->substr(0, sep)); + std::string value(it->substr(sep + 1)); - if(map->mMap.find(key) == map->mMap.end()) - { - map->mMap.insert(std::make_pair (key,value)); - } - } - } + if (map->mMap.find(key) == map->mMap.end()) + { + map->mMap.insert(std::make_pair(key, value)); + } + } + } void validate(boost::any &v, std::vector const &tokens, EscapeFallbackMap* eFM, int a) { @@ -64,4 +64,13 @@ namespace Fallback } } +namespace Files { + void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a) + { + std::string * temp = eHS->toStdStringPtr(); + boost::program_options::validate(v, tokens, temp, a); + delete temp; + } +} + #endif diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index c7ac976d6..78e49e23d 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -285,6 +285,12 @@ std::string EscapeHashString::toStdString() const return std::string(* this); } +std::string * EscapeHashString::toStdStringPtr() const +{ + std::string * ret = new std::string(*this); + return ret; +} + const boost::filesystem::path& ConfigurationManager::getGlobalPath() const { return mFixedPath.getGlobalConfigPath(); diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 47ecc9eb2..0d3517d48 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -107,6 +107,7 @@ class EscapeHashString : public std::string EscapeHashString(InputIterator first, InputIterator last); std::string toStdString() const; + std::string * toStdStringPtr() const; }; } /* namespace Cfg */ From 195dd277804701438a82875a5829c61d27857976 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 22:05:38 +0100 Subject: [PATCH 07/14] Resolve obvious runtime error revealing more subtle one --- apps/openmw/main.cpp | 31 ++++++++++++----------- components/fallback/validate.hpp | 11 +++++--- components/files/configurationmanager.cpp | 19 +++++++------- components/files/configurationmanager.hpp | 2 ++ 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 645316f9c..d63d1f60c 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -69,7 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { // Create a local alias for brevity namespace bpo = boost::program_options; - typedef std::vector StringsVector; + typedef std::vector EscapeStringsVector; + typedef std::vector StringsVector; bpo::options_description desc("Syntax: openmw \nAllowed options"); @@ -82,7 +83,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("data-local", bpo::value()->default_value(""), "set local data directory (highest priority)") - ("fallback-archive", bpo::value()->default_value(StringsVector(), "fallback-archive") + ("fallback-archive", bpo::value()->default_value(EscapeStringsVector(), "fallback-archive") ->multitoken(), "set fallback BSA archives (later archives have higher priority)") ("resources", bpo::value()->default_value("resources"), @@ -91,7 +92,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("start", bpo::value()->default_value(""), "set initial cell") - ("content", bpo::value()->default_value(StringsVector(), "") + ("content", bpo::value()->default_value(EscapeStringsVector(), "") ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") ("no-sound", bpo::value()->implicit_value(true) @@ -119,7 +120,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat "\t1 - show warning but consider script as correctly compiled anyway\n" "\t2 - treat warnings as errors") - ("script-blacklist", bpo::value()->default_value(StringsVector(), "") + ("script-blacklist", bpo::value()->default_value(EscapeStringsVector(), "") ->multitoken(), "ignore the specified script (if the use of the blacklist is enabled)") ("script-blacklist-use", bpo::value()->implicit_value(true) @@ -173,20 +174,20 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { cfgMgr.readConfiguration(variables, desc, true); - Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as().toStdString()); std::cout << v.describe() << std::endl; return false; } cfgMgr.readConfiguration(variables, desc); - Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as().toStdString()); std::cout << v.describe() << std::endl; engine.setGrabMouse(!variables.count("no-grab")); // Font encoding settings - std::string encoding(variables["encoding"].as()); + std::string encoding(variables["encoding"].as().toStdString()); std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl; engine.setEncoding(ToUTF8::calculateEncoding(encoding)); @@ -195,7 +196,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat Files::PathContainer dataDirs(variables["data"].as()); - std::string local(variables["data-local"].as()); + std::string local(variables["data-local"].as().toStdString()); if (!local.empty()) { dataDirs.push_back(Files::PathContainer::value_type(local)); @@ -206,15 +207,15 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setDataDirs(dataDirs); // fallback archives - StringsVector archives = variables["fallback-archive"].as(); + StringsVector archives = Files::EscapeHashString::toStdStringVector(variables["fallback-archive"].as()); for (StringsVector::const_iterator it = archives.begin(); it != archives.end(); ++it) { engine.addArchive(*it); } - engine.setResourceDir(variables["resources"].as()); + engine.setResourceDir(variables["resources"].as().toStdString()); - StringsVector content = variables["content"].as(); + StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as()); if (content.empty()) { std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl; @@ -229,7 +230,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat } // startup-settings - engine.setCell(variables["start"].as()); + engine.setCell(variables["start"].as().toStdString()); engine.setSkipMenu (variables["skip-menu"].as(), variables["new-game"].as()); if (!variables["skip-menu"].as() && variables["new-game"].as()) std::cerr << "new-game used without skip-menu -> ignoring it" << std::endl; @@ -239,11 +240,11 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setCompileAllDialogue(variables["script-all-dialogue"].as()); engine.setScriptsVerbosity(variables["script-verbose"].as()); engine.setScriptConsoleMode (variables["script-console"].as()); - engine.setStartupScript (variables["script-run"].as()); + engine.setStartupScript (variables["script-run"].as().toStdString()); engine.setWarningsMode (variables["script-warn"].as()); - engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as())); + engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as())); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); - engine.setSaveGameFile (variables["load-savegame"].as()); + engine.setSaveGameFile (variables["load-savegame"].as().toStdString()); // other settings engine.setSoundUsage(!variables["no-sound"].as()); diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 4c4897c27..7683a1297 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -67,9 +67,14 @@ namespace Fallback namespace Files { void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a) { - std::string * temp = eHS->toStdStringPtr(); - boost::program_options::validate(v, tokens, temp, a); - delete temp; + if (eHS == NULL) + boost::program_options::validate(v, tokens, (std::string *) NULL, a); + else + { + std::string * temp = eHS->toStdStringPtr(); + boost::program_options::validate(v, tokens, temp, a); + delete temp; + } } } diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 78e49e23d..d8543738d 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -251,44 +251,43 @@ std::vector EscapeHashString::toStdStringVector(const std::vector -EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : std::string(EscapeHashString::processString(std::string(first, last))) +EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mData(EscapeHashString::processString(std::string(first, last))) { } std::string EscapeHashString::toStdString() const { - return std::string(* this); + return std::string(mData); } std::string * EscapeHashString::toStdStringPtr() const { - std::string * ret = new std::string(*this); - return ret; + return new std::string(mData); } const boost::filesystem::path& ConfigurationManager::getGlobalPath() const diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 0d3517d48..e6257eec4 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -93,6 +93,8 @@ struct escape_hash_filter : public boost::iostreams::input_filter */ class EscapeHashString : public std::string { + private: + std::string mData; public: static std::string processString(const std::string & str); static std::vector toStdStringVector(const std::vector & vec); From 1a0642f1dbcbcfdc341989f2ec7e81aedee86f3f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Jul 2016 22:33:15 +0100 Subject: [PATCH 08/14] Make it work by realising that what boost::program_options calls validation is what any sane person would regard as parsing --- apps/openmw/main.cpp | 4 ++-- components/fallback/validate.hpp | 39 ++++++++------------------------ 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index d63d1f60c..e57ff867c 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -145,7 +145,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" "\n\twin1252 - Western European (Latin) alphabet, used by default") - ("fallback", bpo::value()->default_value(EscapeFallbackMap(), "") + ("fallback", bpo::value()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") ("no-grab", "Don't grab mouse cursor") @@ -248,7 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // other settings engine.setSoundUsage(!variables["no-sound"].as()); - engine.setFallbackValues(variables["fallback"].as().toFallbackMap().mMap); + engine.setFallbackValues(variables["fallback"].as().mMap); engine.setActivationDistanceOverride (variables["activate-dist"].as()); engine.enableFontExport(variables["export-fonts"].as()); diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 7683a1297..605b64702 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -16,19 +16,6 @@ namespace Fallback std::map mMap; }; - struct EscapeFallbackMap : FallbackMap - { - std::map mMap; - - FallbackMap toFallbackMap() const - { - FallbackMap temp = FallbackMap(); - for (std::map::const_iterator it = mMap.begin(); it != mMap.end(); ++it) - temp.mMap[it->first.toStdString()] = it->second.toStdString(); - return temp; - } - }; - void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) { if (v.empty()) @@ -40,16 +27,17 @@ namespace Fallback for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { - int sep = it->find(","); - if (sep < 1 || sep == (int)it->length() - 1) + std::string temp = Files::EscapeHashString::processString(*it); + int sep = temp.find(","); + if (sep < 1 || sep == (int)temp.length() - 1) #if (BOOST_VERSION < 104200) throw boost::program_options::validation_error("invalid value"); #else throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); #endif - std::string key(it->substr(0, sep)); - std::string value(it->substr(sep + 1)); + std::string key(temp.substr(0, sep)); + std::string value(temp.substr(sep + 1)); if (map->mMap.find(key) == map->mMap.end()) { @@ -57,24 +45,15 @@ namespace Fallback } } } - - void validate(boost::any &v, std::vector const &tokens, EscapeFallbackMap* eFM, int a) - { - validate(v, tokens, (FallbackMap *)eFM, a); - } } namespace Files { void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a) { - if (eHS == NULL) - boost::program_options::validate(v, tokens, (std::string *) NULL, a); - else - { - std::string * temp = eHS->toStdStringPtr(); - boost::program_options::validate(v, tokens, temp, a); - delete temp; - } + boost::program_options::validators::check_first_occurrence(v); + + if (v.empty()) + v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens))); } } From 5121e77a95667aafc82665ad8d8cb390153058bf Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Jul 2016 00:00:29 +0100 Subject: [PATCH 09/14] Remove the cause of a warning which upset Travis (but not the thing that made the Travis build fail, as I have no idea why it wouldn't work or how to fix it --- components/files/configurationmanager.cpp | 20 ++++++++++---------- components/files/configurationmanager.hpp | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index d8543738d..951c444a5 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -164,7 +164,7 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, return false; } -escape_hash_filter::escape_hash_filter() : mNext() +escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false) { } @@ -186,23 +186,23 @@ int escape_hash_filter::get(Source & src) } else if (character == EOF) { - seenNonWhitespace = false; - finishLine = false; + mSeenNonWhitespace = false; + mFinishLine = false; mNext.push(character); } else if (character == '\n') { - seenNonWhitespace = false; - finishLine = false; + mSeenNonWhitespace = false; + mFinishLine = false; mNext.push(character); } - else if (finishLine) + else if (mFinishLine) { mNext.push(character); } else if (character == '#') { - if (seenNonWhitespace) + if (mSeenNonWhitespace) { mNext.push(sEscape); mNext.push(sHashIdentifier); @@ -211,7 +211,7 @@ int escape_hash_filter::get(Source & src) { //it's fine being interpreted by Boost as a comment, and so is anything afterwards mNext.push(character); - finishLine = true; + mFinishLine = true; } } else if (mPrevious == sEscape) @@ -223,8 +223,8 @@ int escape_hash_filter::get(Source & src) { mNext.push(character); } - if (!seenNonWhitespace && !isspace(character)) - seenNonWhitespace = true; + if (!mSeenNonWhitespace && !isspace(character)) + mSeenNonWhitespace = true; if (record) mPrevious = character; } diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index e6257eec4..20d5c62ec 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -84,8 +84,8 @@ struct escape_hash_filter : public boost::iostreams::input_filter std::queue mNext; int mPrevious; - bool seenNonWhitespace = false; - bool finishLine = false; + bool mSeenNonWhitespace; + bool mFinishLine; }; /** From 7475d90693a7344735d744c66a993d51842a7244 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Jul 2016 00:14:19 +0100 Subject: [PATCH 10/14] Fix dodgy include by changing backslashes to forwardslashes --- components/fallback/validate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index 605b64702..fe545ce4b 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -3,7 +3,7 @@ #include -#include +#include // Parses and validates a fallback map from boost program_options. // Note: for boost to pick up the validate function, you need to pull in the namespace e.g. From 08df463c949fc1f1d51b51f61f00a5cd0e626e71 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Jul 2016 00:37:08 +0100 Subject: [PATCH 11/14] Separate declaration and definition of some static members to hopefully calm Travis down. --- components/files/configurationmanager.cpp | 4 ++++ components/files/configurationmanager.hpp | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 951c444a5..46775a7fb 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -164,6 +164,10 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, return false; } +const int escape_hash_filter::sEscape = '@'; +const int escape_hash_filter::sEscapeIdentifier = 'a'; +const int escape_hash_filter::sHashIdentifier = 'h'; + escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false) { } diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 20d5c62ec..6e1cfbdb1 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -71,9 +71,9 @@ struct ConfigurationManager */ struct escape_hash_filter : public boost::iostreams::input_filter { - static const int sEscape = '@'; - static const int sHashIdentifier = 'h'; - static const int sEscapeIdentifier = 'a'; + static const int sEscape; + static const int sHashIdentifier; + static const int sEscapeIdentifier; escape_hash_filter(); virtual ~escape_hash_filter(); From e6f78ae5b74272aa8e10dc0b803c60138de15978 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Jul 2016 01:06:57 +0100 Subject: [PATCH 12/14] Switch indentation to spaces to remain consistent with the rest of the project --- apps/openmw/main.cpp | 22 ++-- components/fallback/validate.hpp | 70 +++++------ components/files/configurationmanager.cpp | 140 +++++++++++----------- components/files/configurationmanager.hpp | 56 ++++----- 4 files changed, 144 insertions(+), 144 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index e57ff867c..e96b6e595 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -69,8 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { // Create a local alias for brevity namespace bpo = boost::program_options; - typedef std::vector EscapeStringsVector; - typedef std::vector StringsVector; + typedef std::vector EscapeStringsVector; + typedef std::vector StringsVector; bpo::options_description desc("Syntax: openmw \nAllowed options"); @@ -80,16 +80,16 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("data", bpo::value()->default_value(Files::PathContainer(), "data") ->multitoken()->composing(), "set data directories (later directories have higher priority)") - ("data-local", bpo::value()->default_value(""), + ("data-local", bpo::value()->default_value(""), "set local data directory (highest priority)") ("fallback-archive", bpo::value()->default_value(EscapeStringsVector(), "fallback-archive") ->multitoken(), "set fallback BSA archives (later archives have higher priority)") - ("resources", bpo::value()->default_value("resources"), + ("resources", bpo::value()->default_value("resources"), "set resources directory") - ("start", bpo::value()->default_value(""), + ("start", bpo::value()->default_value(""), "set initial cell") ("content", bpo::value()->default_value(EscapeStringsVector(), "") @@ -110,7 +110,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-console", bpo::value()->implicit_value(true) ->default_value(false), "enable console-only script functionality") - ("script-run", bpo::value()->default_value(""), + ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") ("script-warn", bpo::value()->implicit_value (1) @@ -126,7 +126,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-blacklist-use", bpo::value()->implicit_value(true) ->default_value(true), "enable script blacklisting") - ("load-savegame", bpo::value()->default_value(""), + ("load-savegame", bpo::value()->default_value(""), "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) @@ -138,14 +138,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") - ("encoding", bpo::value()-> + ("encoding", bpo::value()-> default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" "\n\twin1252 - Western European (Latin) alphabet, used by default") - ("fallback", bpo::value()->default_value(FallbackMap(), "") + ("fallback", bpo::value()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") ("no-grab", "Don't grab mouse cursor") @@ -215,7 +215,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setResourceDir(variables["resources"].as().toStdString()); - StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as()); + StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as()); if (content.empty()) { std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl; @@ -248,7 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // other settings engine.setSoundUsage(!variables["no-sound"].as()); - engine.setFallbackValues(variables["fallback"].as().mMap); + engine.setFallbackValues(variables["fallback"].as().mMap); engine.setActivationDistanceOverride (variables["activate-dist"].as()); engine.enableFontExport(variables["export-fonts"].as()); diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index fe545ce4b..e609297ae 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -12,49 +12,49 @@ namespace Fallback { - struct FallbackMap { - std::map mMap; - }; - - void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) - { - if (v.empty()) - { - v = boost::any(FallbackMap()); - } - - FallbackMap *map = boost::any_cast(&v); - - for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) - { - std::string temp = Files::EscapeHashString::processString(*it); - int sep = temp.find(","); - if (sep < 1 || sep == (int)temp.length() - 1) + struct FallbackMap { + std::map mMap; + }; + + void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) + { + if (v.empty()) + { + v = boost::any(FallbackMap()); + } + + FallbackMap *map = boost::any_cast(&v); + + for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) + { + std::string temp = Files::EscapeHashString::processString(*it); + int sep = temp.find(","); + if (sep < 1 || sep == (int)temp.length() - 1) #if (BOOST_VERSION < 104200) - throw boost::program_options::validation_error("invalid value"); + throw boost::program_options::validation_error("invalid value"); #else - throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); + throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); #endif - std::string key(temp.substr(0, sep)); - std::string value(temp.substr(sep + 1)); + std::string key(temp.substr(0, sep)); + std::string value(temp.substr(sep + 1)); - if (map->mMap.find(key) == map->mMap.end()) - { - map->mMap.insert(std::make_pair(key, value)); - } - } - } + if (map->mMap.find(key) == map->mMap.end()) + { + map->mMap.insert(std::make_pair(key, value)); + } + } + } } namespace Files { - void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a) - { - boost::program_options::validators::check_first_occurrence(v); - - if (v.empty()) - v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens))); - } + void validate(boost::any &v, const std::vector &tokens, Files::EscapeHashString * eHS, int a) + { + boost::program_options::validators::check_first_occurrence(v); + + if (v.empty()) + v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens))); + } } #endif diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 46775a7fb..511dbe411 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -142,9 +142,9 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path, std::cout << "Loading config file: " << cfgFile.string() << "... "; boost::filesystem::ifstream configFileStreamUnfiltered(cfgFile); - boost::iostreams::filtering_istream configFileStream; - configFileStream.push(escape_hash_filter()); - configFileStream.push(configFileStreamUnfiltered); + boost::iostreams::filtering_istream configFileStream; + configFileStream.push(escape_hash_filter()); + configFileStream.push(configFileStreamUnfiltered); if (configFileStreamUnfiltered.is_open()) { boost::program_options::store(boost::program_options::parse_config_file( @@ -179,80 +179,80 @@ escape_hash_filter::~escape_hash_filter() template int escape_hash_filter::get(Source & src) { - if (mNext.empty()) - { - int character = boost::iostreams::get(src); - bool record = true; - if (character == boost::iostreams::WOULD_BLOCK) - { - mNext.push(character); - record = false; - } - else if (character == EOF) - { - mSeenNonWhitespace = false; - mFinishLine = false; - mNext.push(character); - } - else if (character == '\n') - { - mSeenNonWhitespace = false; - mFinishLine = false; - mNext.push(character); - } - else if (mFinishLine) - { - mNext.push(character); - } - else if (character == '#') - { - if (mSeenNonWhitespace) - { - mNext.push(sEscape); - mNext.push(sHashIdentifier); - } - else - { - //it's fine being interpreted by Boost as a comment, and so is anything afterwards - mNext.push(character); - mFinishLine = true; - } - } - else if (mPrevious == sEscape) - { - mNext.push(sEscape); - mNext.push(sEscapeIdentifier); - } - else - { - mNext.push(character); - } - if (!mSeenNonWhitespace && !isspace(character)) - mSeenNonWhitespace = true; - if (record) - mPrevious = character; - } - int retval = mNext.front(); - mNext.pop(); - return retval; + if (mNext.empty()) + { + int character = boost::iostreams::get(src); + bool record = true; + if (character == boost::iostreams::WOULD_BLOCK) + { + mNext.push(character); + record = false; + } + else if (character == EOF) + { + mSeenNonWhitespace = false; + mFinishLine = false; + mNext.push(character); + } + else if (character == '\n') + { + mSeenNonWhitespace = false; + mFinishLine = false; + mNext.push(character); + } + else if (mFinishLine) + { + mNext.push(character); + } + else if (character == '#') + { + if (mSeenNonWhitespace) + { + mNext.push(sEscape); + mNext.push(sHashIdentifier); + } + else + { + //it's fine being interpreted by Boost as a comment, and so is anything afterwards + mNext.push(character); + mFinishLine = true; + } + } + else if (mPrevious == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + } + else + { + mNext.push(character); + } + if (!mSeenNonWhitespace && !isspace(character)) + mSeenNonWhitespace = true; + if (record) + mPrevious = character; + } + int retval = mNext.front(); + mNext.pop(); + return retval; } std::string EscapeHashString::processString(const std::string & str) { - std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1)); - return temp; + std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1)); + return temp; } std::vector EscapeHashString::toStdStringVector(const std::vector & vec) { - std::vector temp = std::vector(); - for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) - { - temp.push_back(it->toStdString()); - } - return temp; + std::vector temp = std::vector(); + for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) + { + temp.push_back(it->toStdString()); + } + return temp; } EscapeHashString::EscapeHashString() : mData() @@ -286,12 +286,12 @@ EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mD std::string EscapeHashString::toStdString() const { - return std::string(mData); + return std::string(mData); } std::string * EscapeHashString::toStdStringPtr() const { - return new std::string(mData); + return new std::string(mData); } const boost::filesystem::path& ConfigurationManager::getGlobalPath() const diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 6e1cfbdb1..5138b3ca7 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -71,21 +71,21 @@ struct ConfigurationManager */ struct escape_hash_filter : public boost::iostreams::input_filter { - static const int sEscape; - static const int sHashIdentifier; - static const int sEscapeIdentifier; + static const int sEscape; + static const int sHashIdentifier; + static const int sEscapeIdentifier; - escape_hash_filter(); - virtual ~escape_hash_filter(); + escape_hash_filter(); + virtual ~escape_hash_filter(); - template int get(Source & src); + template int get(Source & src); - private: - std::queue mNext; - int mPrevious; + private: + std::queue mNext; + int mPrevious; - bool mSeenNonWhitespace; - bool mFinishLine; + bool mSeenNonWhitespace; + bool mFinishLine; }; /** @@ -93,23 +93,23 @@ struct escape_hash_filter : public boost::iostreams::input_filter */ class EscapeHashString : public std::string { - private: - std::string mData; - public: - static std::string processString(const std::string & str); - static std::vector toStdStringVector(const std::vector & vec); - - EscapeHashString(); - EscapeHashString(const std::string & str); - EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos); - EscapeHashString(const char * s); - EscapeHashString(const char * s, size_t n); - EscapeHashString(size_t n, char c); - template - EscapeHashString(InputIterator first, InputIterator last); - - std::string toStdString() const; - std::string * toStdStringPtr() const; + private: + std::string mData; + public: + static std::string processString(const std::string & str); + static std::vector toStdStringVector(const std::vector & vec); + + EscapeHashString(); + EscapeHashString(const std::string & str); + EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos); + EscapeHashString(const char * s); + EscapeHashString(const char * s, size_t n); + EscapeHashString(size_t n, char c); + template + EscapeHashString(InputIterator first, InputIterator last); + + std::string toStdString() const; + std::string * toStdStringPtr() const; }; } /* namespace Cfg */ From f1b5ad580427cb7ab9812b8664009e375e21e921 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Jul 2016 17:09:57 +0100 Subject: [PATCH 13/14] Remove unused unsafe function and properly remove inheritance from std::string, providing implementations of missing stream operators preventing boost reading and writing to escape strings. --- apps/openmw/main.cpp | 13 ++++--- components/fallback/validate.hpp | 11 ++++++ components/files/configurationmanager.cpp | 42 ++++++++++++++++------- components/files/configurationmanager.hpp | 18 ++++++++-- 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index e96b6e595..f54905a2c 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -69,7 +69,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { // Create a local alias for brevity namespace bpo = boost::program_options; - typedef std::vector EscapeStringsVector; typedef std::vector StringsVector; bpo::options_description desc("Syntax: openmw \nAllowed options"); @@ -83,7 +82,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("data-local", bpo::value()->default_value(""), "set local data directory (highest priority)") - ("fallback-archive", bpo::value()->default_value(EscapeStringsVector(), "fallback-archive") + ("fallback-archive", bpo::value()->default_value(Files::EscapeStringVector(), "fallback-archive") ->multitoken(), "set fallback BSA archives (later archives have higher priority)") ("resources", bpo::value()->default_value("resources"), @@ -92,7 +91,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("start", bpo::value()->default_value(""), "set initial cell") - ("content", bpo::value()->default_value(EscapeStringsVector(), "") + ("content", bpo::value()->default_value(Files::EscapeStringVector(), "") ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") ("no-sound", bpo::value()->implicit_value(true) @@ -120,7 +119,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat "\t1 - show warning but consider script as correctly compiled anyway\n" "\t2 - treat warnings as errors") - ("script-blacklist", bpo::value()->default_value(EscapeStringsVector(), "") + ("script-blacklist", bpo::value()->default_value(Files::EscapeStringVector(), "") ->multitoken(), "ignore the specified script (if the use of the blacklist is enabled)") ("script-blacklist-use", bpo::value()->implicit_value(true) @@ -207,7 +206,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setDataDirs(dataDirs); // fallback archives - StringsVector archives = Files::EscapeHashString::toStdStringVector(variables["fallback-archive"].as()); + StringsVector archives = variables["fallback-archive"].as().toStdStringVector(); for (StringsVector::const_iterator it = archives.begin(); it != archives.end(); ++it) { engine.addArchive(*it); @@ -215,7 +214,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setResourceDir(variables["resources"].as().toStdString()); - StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as()); + StringsVector content = variables["content"].as().toStdStringVector(); if (content.empty()) { std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl; @@ -242,7 +241,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setScriptConsoleMode (variables["script-console"].as()); engine.setStartupScript (variables["script-run"].as().toStdString()); engine.setWarningsMode (variables["script-warn"].as()); - engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as())); + engine.setScriptBlacklist (variables["script-blacklist"].as().toStdStringVector()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); engine.setSaveGameFile (variables["load-savegame"].as().toStdString()); diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp index e609297ae..d82ef5770 100644 --- a/components/fallback/validate.hpp +++ b/components/fallback/validate.hpp @@ -55,6 +55,17 @@ namespace Files { if (v.empty()) v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens))); } + + void validate(boost::any &v, const std::vector &tokens, EscapeStringVector *, int) + { + if (v.empty()) + v = boost::any(EscapeStringVector()); + + EscapeStringVector * eSV = boost::any_cast(&v); + + for (std::vector::const_iterator it = tokens.begin(); it != tokens.end(); ++it) + eSV->mVector.push_back(EscapeHashString(*it)); + } } #endif diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 511dbe411..3a7f57949 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -244,17 +244,6 @@ std::string EscapeHashString::processString(const std::string & str) return temp; } - -std::vector EscapeHashString::toStdStringVector(const std::vector & vec) -{ - std::vector temp = std::vector(); - for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) - { - temp.push_back(it->toStdString()); - } - return temp; -} - EscapeHashString::EscapeHashString() : mData() { } @@ -289,9 +278,36 @@ std::string EscapeHashString::toStdString() const return std::string(mData); } -std::string * EscapeHashString::toStdStringPtr() const +std::istream & operator>> (std::istream & is, EscapeHashString & eHS) +{ + std::string temp; + is >> temp; + eHS = EscapeHashString(temp); + return is; +} + +std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS) +{ + os << eHS.mData; + return os; +} + +EscapeStringVector::EscapeStringVector() : mVector() { - return new std::string(mData); +} + +EscapeStringVector::~EscapeStringVector() +{ +} + +std::vector EscapeStringVector::toStdStringVector() const +{ + std::vector temp = std::vector(); + for (std::vector::const_iterator it = mVector.begin(); it != mVector.end(); ++it) + { + temp.push_back(it->toStdString()); + } + return temp; } const boost::filesystem::path& ConfigurationManager::getGlobalPath() const diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 5138b3ca7..3ce995983 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -91,13 +91,12 @@ struct escape_hash_filter : public boost::iostreams::input_filter /** * \class EscapeHashString */ -class EscapeHashString : public std::string +class EscapeHashString { private: std::string mData; public: static std::string processString(const std::string & str); - static std::vector toStdStringVector(const std::vector & vec); EscapeHashString(); EscapeHashString(const std::string & str); @@ -109,7 +108,20 @@ class EscapeHashString : public std::string EscapeHashString(InputIterator first, InputIterator last); std::string toStdString() const; - std::string * toStdStringPtr() const; + + friend std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS); +}; + +std::istream & operator>> (std::istream & is, EscapeHashString & eHS); + +struct EscapeStringVector +{ + std::vector mVector; + + EscapeStringVector(); + virtual ~EscapeStringVector(); + + std::vector toStdStringVector() const; }; } /* namespace Cfg */ From 4ac5174d899f03eff4449f7d8d74e2f0e2b9a8ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Jul 2016 16:29:26 +0200 Subject: [PATCH 14/14] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index b97642aba..60e969cdc 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -22,6 +22,7 @@ Programmers Alexander Nadeau (wareya) Alexander Olofsson (Ace) Allofich + AnyOldName3 Austin Salgat (Salgat) Artem Kotsynyak (greye) artemutin