diff --git a/src/lib/format-string.cpp b/src/lib/format-string.cpp index d11f63bc2..927200f30 100644 --- a/src/lib/format-string.cpp +++ b/src/lib/format-string.cpp @@ -46,6 +46,7 @@ #include "lib/error.hpp" +#include "lib/format-util.hpp" #include "lib/format-string.hpp" #include @@ -68,15 +69,45 @@ namespace util { return reinterpret_cast (*buffer); } + /** in case the formatting of a (primitive) value fails, + * we try to use a error indicator instead + */ + inline void + pushFailsafeReplacement (char* formatter, const char* errorMsg =NULL) + try { + string placeholder(" void _Fmt::pushParameter (VAL const& val) - { - accessImpl(formatter_) % val; - } + try { + accessImpl(formatter_) % val; + } + + catch (boost::io::too_many_args& argErr) + { + WARN (progress, "Format: excess argument '%s' of type %s ignored." + , cStr(str(val)) + , cStr(tyStr(val))); + } + catch (std::exception& failure) + { + WARN (progress, "Format: Parameter '%s' causes problems: %s" + , cStr(str(val)) + , failure.what()); + pushFailsafeReplacement (formatter_, failure.what()); + } + catch (...) + { + WARN (progress, "Format: Unexpected problems accepting format parameter '%s'", cStr(str(val))); + pushFailsafeReplacement (formatter_); + } + template void _Fmt::pushParameter (const VAL * const pVal) { if (pVal) - pushParameter(*pVal); + pushParameter (*pVal); else - pushParameter(string("(null)")); + pushParameter (string("")); } template<> @@ -157,21 +208,44 @@ namespace util { * are evaluated and formatted prior to receiving the formatted result */ _Fmt::operator string() const - { - return accessImpl(formatter_).str(); - } + try { + return accessImpl(formatter_).str(); + } + + catch (std::exception& failure) + { + WARN (progress, "Format: Failure to receive formatted result: %s", failure.what()); + return ""; + } + catch (...) + { + WARN (progress, "Format: Unexpected problems while formatting output."); + return ""; + } + /** send the formatted buffer directly to the output stream. * @note this is more efficient than creating a string and outputting that, - * because boost::format internally uses a stringstream to generate + * because boost::format internally uses a string-stream to generate * the formatted representation, relying on the C++ output framework */ std::ostream& operator<< (std::ostream& os, _Fmt const& fmt) - { - return os << accessImpl(fmt.formatter_); - } + try { + return os << accessImpl(fmt.formatter_); + } + + catch(std::exception& failure) + { + WARN (progress, "Format: Failure when outputting formatted result: %s", failure.what()); + return os << ""; + } + catch(...) + { + WARN (progress, "Format: Unexpected problems while producing formatted output."); + return os << ""; + } diff --git a/src/lib/format-string.hpp b/src/lib/format-string.hpp index d7eb1fde2..af58a9bda 100644 --- a/src/lib/format-string.hpp +++ b/src/lib/format-string.hpp @@ -201,7 +201,11 @@ namespace util { _log_and_stringify (std::exception const& ex) { WARN (progress, "Error while invoking custom string conversion: %s", ex.what()); - return ex.what(); + try { + return string(""; + } + catch(...) { /* secondary errors ignored */ } + return "(formatting failure)"; } inline string @@ -209,15 +213,10 @@ namespace util { { const char* errID = lumiera_error(); if (errID) - { - ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID); - return string("Unknown error in string conversion. FLAG=")+errID; - } + ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID); else - { - ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set."); - return "Unknown error in string conversion"; - } + ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set."); + return ""; } }//(End) guards/helpers diff --git a/tests/lib/format-string-test.cpp b/tests/lib/format-string-test.cpp index 530339ec5..46cae95c1 100644 --- a/tests/lib/format-string-test.cpp +++ b/tests/lib/format-string-test.cpp @@ -237,12 +237,12 @@ namespace test { CHECK (contains (mangledType, "Silent")); CHECK (_Fmt("!!%s!!") % v == "!!Number-013!!"); - CHECK (_Fmt("!!%s!!") % x == "!!LUMIERA_ERROR_STATE:unforeseen state (encountered Fantomas).!!"); + CHECK (_Fmt("!!%s!!") % x == "!!!!"); CHECK (contains (_Fmt("%s") % rs1, "Silent")); CHECK (contains (_Fmt("%s") % rs2, "Silent")); - CHECK (_Fmt("!!%s!!") % rv == "!!LUMIERA_ERROR_STATE:unforeseen state (encountered Fantomas).!!"); + CHECK (_Fmt("!!%s!!") % rv == "!!!!"); x.i_ = 42; CHECK (_Fmt("!!%s!!") % rv == "!!Number-042!!"); @@ -258,6 +258,8 @@ namespace test { cout << _Fmt("__%d__") % 1 << endl; cout << _Fmt("__%d__") % 1 % 2 << endl; + const char* evil = NULL; + cout << _Fmt("__%d__") % evil << endl; cout << _Fmt("__%d__") % "dirt" << endl; cout << _Fmt("__%d__") % "1234" << endl; cout << _Fmt("__%d__") % "0xff" << endl; @@ -307,7 +309,7 @@ namespace test { pv = NULL; vv = NULL; - CHECK (_Fmt("__%s__") % pv == "__(null)__"); + CHECK (_Fmt("__%s__") % pv == "____"); CHECK (_Fmt("__%s__") % pv == "__0__"); } };