add more robust error handling
...incl handling of secondary errors
This commit is contained in:
parent
e838fb9799
commit
35ed2dcf5c
3 changed files with 101 additions and 26 deletions
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
|
#include "lib/format-util.hpp"
|
||||||
#include "lib/format-string.hpp"
|
#include "lib/format-string.hpp"
|
||||||
|
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
|
|
@ -68,15 +69,45 @@ namespace util {
|
||||||
return reinterpret_cast<boost::format&> (*buffer);
|
return reinterpret_cast<boost::format&> (*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("<Error");
|
||||||
|
if (errorMsg){
|
||||||
|
placeholder += ": ";
|
||||||
|
placeholder += errorMsg;
|
||||||
|
}
|
||||||
|
placeholder += ">";
|
||||||
|
|
||||||
|
accessImpl(formatter) % placeholder;
|
||||||
|
}
|
||||||
|
ERROR_LOG_AND_IGNORE (progress, "Supplying placeholder for problematic format parameter")
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
suppressInsufficientArgumentErrors (char* formatter)
|
||||||
|
{
|
||||||
|
using namespace boost::io;
|
||||||
|
accessImpl(formatter).exceptions (all_error_bits ^ too_few_args_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}//(End) implementation details
|
}//(End) implementation details
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
_Fmt::_Fmt (string formatString)
|
_Fmt::_Fmt (string formatString)
|
||||||
{
|
{
|
||||||
BOOST_STATIC_ASSERT (sizeof(boost::format) <= FORMATTER_SIZE);
|
BOOST_STATIC_ASSERT (sizeof(boost::format) <= FORMATTER_SIZE);
|
||||||
|
|
||||||
new(formatter_) boost::format(formatString);
|
new(formatter_) boost::format(formatString);
|
||||||
|
suppressInsufficientArgumentErrors (formatter_);
|
||||||
}
|
}
|
||||||
|
|
||||||
_Fmt::~_Fmt ()
|
_Fmt::~_Fmt ()
|
||||||
|
|
@ -86,8 +117,8 @@ namespace util {
|
||||||
|
|
||||||
|
|
||||||
/** @internal access points for the frontend,
|
/** @internal access points for the frontend,
|
||||||
* allowing to push a parameter value down into
|
* allowing to push a parameter value down into the implementation
|
||||||
* the implementation for the actual formatting.
|
* for the actual formatting.
|
||||||
* @note we need to generate instantiations of this template function
|
* @note we need to generate instantiations of this template function
|
||||||
* explicitly for all basic types to be supported for direct handling,
|
* explicitly for all basic types to be supported for direct handling,
|
||||||
* otherwise we'll get linker errors. Lumiera uses the ``inclusion model''
|
* otherwise we'll get linker errors. Lumiera uses the ``inclusion model''
|
||||||
|
|
@ -98,18 +129,38 @@ namespace util {
|
||||||
template<typename VAL>
|
template<typename VAL>
|
||||||
void
|
void
|
||||||
_Fmt::pushParameter (VAL const& val)
|
_Fmt::pushParameter (VAL const& val)
|
||||||
{
|
try {
|
||||||
accessImpl(formatter_) % val;
|
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<typename VAL>
|
template<typename VAL>
|
||||||
void
|
void
|
||||||
_Fmt::pushParameter (const VAL * const pVal)
|
_Fmt::pushParameter (const VAL * const pVal)
|
||||||
{
|
{
|
||||||
if (pVal)
|
if (pVal)
|
||||||
pushParameter(*pVal);
|
pushParameter (*pVal);
|
||||||
else
|
else
|
||||||
pushParameter(string("(null)"));
|
pushParameter (string("<null>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
@ -157,21 +208,44 @@ namespace util {
|
||||||
* are evaluated and formatted prior to receiving the formatted result
|
* are evaluated and formatted prior to receiving the formatted result
|
||||||
*/
|
*/
|
||||||
_Fmt::operator string() const
|
_Fmt::operator string() const
|
||||||
{
|
try {
|
||||||
return accessImpl(formatter_).str();
|
return accessImpl(formatter_).str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch (std::exception& failure)
|
||||||
|
{
|
||||||
|
WARN (progress, "Format: Failure to receive formatted result: %s", failure.what());
|
||||||
|
return "<formatting failure>";
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
WARN (progress, "Format: Unexpected problems while formatting output.");
|
||||||
|
return "<unexpected problems>";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** send the formatted buffer directly to the output stream.
|
/** send the formatted buffer directly to the output stream.
|
||||||
* @note this is more efficient than creating a string and outputting that,
|
* @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
|
* the formatted representation, relying on the C++ output framework
|
||||||
*/
|
*/
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<< (std::ostream& os, _Fmt const& fmt)
|
operator<< (std::ostream& os, _Fmt const& fmt)
|
||||||
{
|
try {
|
||||||
return os << accessImpl(fmt.formatter_);
|
return os << accessImpl(fmt.formatter_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch(std::exception& failure)
|
||||||
|
{
|
||||||
|
WARN (progress, "Format: Failure when outputting formatted result: %s", failure.what());
|
||||||
|
return os << "<formatting failure>";
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
WARN (progress, "Format: Unexpected problems while producing formatted output.");
|
||||||
|
return os << "<unexpected problems>";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,11 @@ namespace util {
|
||||||
_log_and_stringify (std::exception const& ex)
|
_log_and_stringify (std::exception const& ex)
|
||||||
{
|
{
|
||||||
WARN (progress, "Error while invoking custom string conversion: %s", ex.what());
|
WARN (progress, "Error while invoking custom string conversion: %s", ex.what());
|
||||||
return ex.what();
|
try {
|
||||||
|
return string("<string conversion failed: ")+ex.what()+">";
|
||||||
|
}
|
||||||
|
catch(...) { /* secondary errors ignored */ }
|
||||||
|
return "(formatting failure)";
|
||||||
}
|
}
|
||||||
|
|
||||||
inline string
|
inline string
|
||||||
|
|
@ -209,15 +213,10 @@ namespace util {
|
||||||
{
|
{
|
||||||
const char* errID = lumiera_error();
|
const char* errID = lumiera_error();
|
||||||
if (errID)
|
if (errID)
|
||||||
{
|
ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID);
|
||||||
ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID);
|
|
||||||
return string("Unknown error in string conversion. FLAG=")+errID;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set.");
|
||||||
ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set.");
|
return "<Unknown error in string conversion>";
|
||||||
return "Unknown error in string conversion";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}//(End) guards/helpers
|
}//(End) guards/helpers
|
||||||
|
|
|
||||||
|
|
@ -237,12 +237,12 @@ namespace test {
|
||||||
CHECK (contains (mangledType, "Silent"));
|
CHECK (contains (mangledType, "Silent"));
|
||||||
|
|
||||||
CHECK (_Fmt("!!%s!!") % v == "!!Number-013!!");
|
CHECK (_Fmt("!!%s!!") % v == "!!Number-013!!");
|
||||||
CHECK (_Fmt("!!%s!!") % x == "!!LUMIERA_ERROR_STATE:unforeseen state (encountered Fantomas).!!");
|
CHECK (_Fmt("!!%s!!") % x == "!!<string conversion failed: LUMIERA_ERROR_STATE:unforeseen state (encountered Fantomas).>!!");
|
||||||
|
|
||||||
CHECK (contains (_Fmt("%s") % rs1, "Silent"));
|
CHECK (contains (_Fmt("%s") % rs1, "Silent"));
|
||||||
CHECK (contains (_Fmt("%s") % rs2, "Silent"));
|
CHECK (contains (_Fmt("%s") % rs2, "Silent"));
|
||||||
|
|
||||||
CHECK (_Fmt("!!%s!!") % rv == "!!LUMIERA_ERROR_STATE:unforeseen state (encountered Fantomas).!!");
|
CHECK (_Fmt("!!%s!!") % rv == "!!<string conversion failed: LUMIERA_ERROR_STATE:unforeseen state (encountered Fantomas).>!!");
|
||||||
|
|
||||||
x.i_ = 42;
|
x.i_ = 42;
|
||||||
CHECK (_Fmt("!!%s!!") % rv == "!!Number-042!!");
|
CHECK (_Fmt("!!%s!!") % rv == "!!Number-042!!");
|
||||||
|
|
@ -258,6 +258,8 @@ namespace test {
|
||||||
cout << _Fmt("__%d__") % 1 << endl;
|
cout << _Fmt("__%d__") % 1 << endl;
|
||||||
cout << _Fmt("__%d__") % 1 % 2 << endl;
|
cout << _Fmt("__%d__") % 1 % 2 << endl;
|
||||||
|
|
||||||
|
const char* evil = NULL;
|
||||||
|
cout << _Fmt("__%d__") % evil << endl;
|
||||||
cout << _Fmt("__%d__") % "dirt" << endl;
|
cout << _Fmt("__%d__") % "dirt" << endl;
|
||||||
cout << _Fmt("__%d__") % "1234" << endl;
|
cout << _Fmt("__%d__") % "1234" << endl;
|
||||||
cout << _Fmt("__%d__") % "0xff" << endl;
|
cout << _Fmt("__%d__") % "0xff" << endl;
|
||||||
|
|
@ -307,7 +309,7 @@ namespace test {
|
||||||
|
|
||||||
pv = NULL;
|
pv = NULL;
|
||||||
vv = NULL;
|
vv = NULL;
|
||||||
CHECK (_Fmt("__%s__") % pv == "__(null)__");
|
CHECK (_Fmt("__%s__") % pv == "__<null>__");
|
||||||
CHECK (_Fmt("__%s__") % pv == "__0__");
|
CHECK (_Fmt("__%s__") % pv == "__0__");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue