diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 40c122de9..807a2845e 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -57,6 +57,7 @@ SET(MAIN_SOURCES Core.cpp ColorText.cpp DataDefs.cpp +Error.cpp VTableInterpose.cpp LuaWrapper.cpp LuaTypes.cpp diff --git a/library/Error.cpp b/library/Error.cpp new file mode 100644 index 000000000..773362af3 --- /dev/null +++ b/library/Error.cpp @@ -0,0 +1,44 @@ +#include "Error.h" +#include "MiscUtils.h" + +using namespace DFHack::Error; + +inline const char *safe_str(const char *s) +{ + return s ? s : "(NULL)"; +} + +NullPointer::NullPointer(const char *varname) + :All(stl_concat("NULL pointer: ", safe_str(varname))), + varname(varname) +{} + +InvalidArgument::InvalidArgument(const char *expr) + :All(stl_concat("Invalid argument; expected: ", safe_str(expr))), + expr(expr) +{} + +VTableMissing::VTableMissing(const char *name) + :All(stl_concat("Missing vtable address: ", safe_str(name))), + name(name) +{} + +SymbolsXmlParse::SymbolsXmlParse(const char* desc, int id, int row, int col) + :AllSymbols(stl_concat("error ", id, ": ", desc, ", at row ", row, " col ", col)), + desc(safe_str(desc)), id(id), row(row), col(col) +{} + +SymbolsXmlBadAttribute::SymbolsXmlBadAttribute(const char *attr) + :AllSymbols(stl_concat("attribute is either missing or invalid: ", safe_str(attr))), + attr(safe_str(attr)) +{} + +SymbolsXmlNoRoot::SymbolsXmlNoRoot() + :AllSymbols("no root element") +{} + +SymbolsXmlUnderspecifiedEntry::SymbolsXmlUnderspecifiedEntry(const char *where) + :AllSymbols(stl_concat("Underspecified symbol file entry, each entry needs to set both the name attribute and have a value. parent: ", + safe_str(where))), + where(safe_str(where)) +{} diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index f30a1878e..f744f3eba 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1076,20 +1076,8 @@ int LuaWrapper::method_wrapper_core(lua_State *state, function_identity_base *id try { id->invoke(state, 1); } - catch (Error::NullPointer &e) { - const char *vn = e.varname(); - std::string tmp = stl_sprintf("NULL pointer: %s", vn ? vn : "?"); - field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); - } - catch (Error::InvalidArgument &e) { - const char *vn = e.expr(); - std::string tmp = stl_sprintf("Invalid argument; expected: %s", vn ? vn : "?"); - field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); - } - catch (Error::VTableMissing &e) { - const char *cn = e.name(); - std::string tmp = stl_sprintf("Missing vtable address: %s", cn ? cn : "?"); - field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); + catch (Error::All &e) { + field_error(state, UPVAL_METHOD_NAME, e.what(), "invoke"); } catch (std::exception &e) { std::string tmp = stl_sprintf("C++ exception: %s", e.what()); @@ -1107,17 +1095,8 @@ int Lua::CallWithCatch(lua_State *state, int (*fn)(lua_State*), const char *cont try { return fn(state); } - catch (Error::NullPointer &e) { - const char *vn = e.varname(); - return luaL_error(state, "%s: NULL pointer: %s", context, vn ? vn : "?"); - } - catch (Error::InvalidArgument &e) { - const char *vn = e.expr(); - return luaL_error(state, "%s: Invalid argument; expected: %s", context, vn ? vn : "?"); - } - catch (Error::VTableMissing &e) { - const char *cn = e.name(); - return luaL_error(state, "%s: Missing vtable address: %s", context, cn ? cn : "?"); + catch (Error::All &e) { + return luaL_error(state, "%s: %s", context, e.what()); } catch (std::exception &e) { return luaL_error(state, "%s: C++ exception: %s", context, e.what()); diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index bff7f07e1..afc3dca70 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -41,18 +41,6 @@ distribution. #include #include -const char *DFHack::Error::NullPointer::what() const throw() { - return "DFHack::Error::NullPointer"; -} - -const char *DFHack::Error::InvalidArgument::what() const throw() { - return "DFHack::Error::InvalidArgument"; -} - -const char *DFHack::Error::VTableMissing::what() const throw() { - return "DFHack::Error::VTableMissing"; -} - std::string stl_sprintf(const char *fmt, ...) { va_list lst; va_start(lst, fmt); diff --git a/library/include/Error.h b/library/include/Error.h index 2d0baadfc..d3d208b1f 100644 --- a/library/include/Error.h +++ b/library/include/Error.h @@ -41,118 +41,91 @@ namespace DFHack #ifdef _MSC_VER #pragma push /** - * C4275 is - The warning officially is non dll-interface class 'std::exception' used as base for + * C4275 - The warning officially is non dll-interface class 'std::exception' used as base for * dll-interface class * - * Basically, its saying that you might have an ABI problem if you mismatch compilers. We don't + * Basically, it's saying that you might have an ABI problem if you mismatch compilers. We don't * care since we build all of DFhack at once against whatever Toady is using */ #pragma warning(disable: 4275) #endif - class DFHACK_EXPORT All : public std::exception{}; + class DFHACK_EXPORT All : public std::exception + { + public: + const std::string full; + All(const std::string &full) + :full(full) + {} + virtual const char *what() const noexcept + { + return full.c_str(); + } + virtual ~All() noexcept {} + }; #ifdef _MSC_VER #pragma pop #endif class DFHACK_EXPORT NullPointer : public All { - const char *varname_; public: - NullPointer(const char *varname_ = NULL) : varname_(varname_) {} - const char *varname() const { return varname_; } - virtual const char *what() const throw(); + const char *const varname; + NullPointer(const char *varname = NULL); }; #define CHECK_NULL_POINTER(var) \ { if (var == NULL) throw DFHack::Error::NullPointer(#var); } class DFHACK_EXPORT InvalidArgument : public All { - const char *expr_; public: - InvalidArgument(const char *expr_ = NULL) : expr_(expr_) {} - const char *expr() const { return expr_; } - virtual const char *what() const throw(); + const char *const expr; + InvalidArgument(const char *expr = NULL); }; #define CHECK_INVALID_ARGUMENT(expr) \ { if (!(expr)) throw DFHack::Error::InvalidArgument(#expr); } class DFHACK_EXPORT VTableMissing : public All { - const char *name_; public: - VTableMissing(const char *name_ = NULL) : name_(name_) {} - const char *name() const { return name_; } - virtual const char *what() const throw(); + const char *const name; + VTableMissing(const char *name = NULL); }; - class DFHACK_EXPORT AllSymbols : public All{}; + class DFHACK_EXPORT AllSymbols : public All + { + public: + AllSymbols(const std::string &full) + :All(full) + {} + }; // Syntax errors and whatnot, the xml can't be read class DFHACK_EXPORT SymbolsXmlParse : public AllSymbols { public: - SymbolsXmlParse(const char* _desc, int _id, int _row, int _col) - :desc(_desc), id(_id), row(_row), col(_col) - { - std::stringstream s; - s << "error " << id << ": " << desc << ", at row " << row << " col " << col; - full = s.str(); - } - std::string full; + SymbolsXmlParse(const char* desc, int id, int row, int col); const std::string desc; const int id; const int row; const int col; - virtual ~SymbolsXmlParse() throw(){}; - virtual const char* what() const throw() - { - return full.c_str(); - } }; - class DFHACK_EXPORT SymbolsXmlBadAttribute : public All + class DFHACK_EXPORT SymbolsXmlBadAttribute : public AllSymbols { public: - SymbolsXmlBadAttribute(const char* _attr) : attr(_attr) - { - std::stringstream s; - s << "attribute is either missing or invalid: " << attr; - full = s.str(); - } - std::string full; + SymbolsXmlBadAttribute(const char* attr); std::string attr; - virtual ~SymbolsXmlBadAttribute() throw(){}; - virtual const char* what() const throw() - { - return full.c_str(); - } }; - class DFHACK_EXPORT SymbolsXmlNoRoot : public All + class DFHACK_EXPORT SymbolsXmlNoRoot : public AllSymbols { public: - SymbolsXmlNoRoot() {} - virtual ~SymbolsXmlNoRoot() throw(){}; - virtual const char* what() const throw() - { - return "Symbol file is missing root element."; - } + SymbolsXmlNoRoot(); }; - class DFHACK_EXPORT SymbolsXmlUnderspecifiedEntry : public All + class DFHACK_EXPORT SymbolsXmlUnderspecifiedEntry : public AllSymbols { public: - SymbolsXmlUnderspecifiedEntry(const char * _where) : where(_where) - { - std::stringstream s; - s << "Underspecified symbol file entry, each entry needs to set both the name attribute and have a value. parent: " << where; - full = s.str(); - } - virtual ~SymbolsXmlUnderspecifiedEntry() throw(){}; + SymbolsXmlUnderspecifiedEntry(const char *where); std::string where; - std::string full; - virtual const char* what() const throw() - { - return full.c_str(); - } }; } } diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 917b67489..ff0c842c5 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -349,6 +349,24 @@ DFHACK_EXPORT uint64_t GetTimeMs64(); DFHACK_EXPORT std::string stl_sprintf(const char *fmt, ...); DFHACK_EXPORT std::string stl_vsprintf(const char *fmt, va_list args); +// https://stackoverflow.com/questions/27375089/what-is-the-easiest-way-to-print-a-variadic-parameter-pack-using-stdostream +template +inline std::string stl_concat(Args... args) +{ + std::ostringstream os; + (void)(int[]){0, (void(os << std::forward(args)), 0)...}; + return os.str(); +} + +template +inline std::string stl_concat(const std::string &sep, Args... args) +{ + std::ostringstream os; + (void)(int[]){0, (void(os << sep << std::forward(args)), 0)...}; + return os.str(); +} + + // Conversion between CP437 and UTF-8 DFHACK_EXPORT std::string UTF2DF(const std::string &in); DFHACK_EXPORT std::string DF2UTF(const std::string &in);