diff options
Diffstat (limited to 'butl')
-rw-r--r-- | butl/fdstream | 2 | ||||
-rw-r--r-- | butl/fdstream.cxx | 12 | ||||
-rw-r--r-- | butl/pager | 2 | ||||
-rw-r--r-- | butl/pager.cxx | 3 | ||||
-rw-r--r-- | butl/utility | 15 | ||||
-rw-r--r-- | butl/utility.cxx | 68 |
6 files changed, 94 insertions, 8 deletions
diff --git a/butl/fdstream b/butl/fdstream index d955476..8d01b2f 100644 --- a/butl/fdstream +++ b/butl/fdstream @@ -299,7 +299,7 @@ namespace butl // } // catch (const process_error& e) // { - // error << ... << e.what (); + // error << ... << e; // // if (e.child ()) // exit (1); diff --git a/butl/fdstream.cxx b/butl/fdstream.cxx index 2eee7c5..370a75e 100644 --- a/butl/fdstream.cxx +++ b/butl/fdstream.cxx @@ -46,18 +46,22 @@ namespace butl // exception and to make a string returned by what() to contain the error // description plus an optional custom message if provided. Unfortunatelly // there is no way to say that the custom message is absent. Passing an - // empty string results for GCC (as of version 5.3.1) with a description - // like this (note the ugly ": " prefix): ": No such file or directory". + // empty string results for libstdc++ (as of version 5.3.1) with a + // description like this (note the ': ' prefix): + // + // : No such file or directory + // + // Note that our custom operator<<(ostream, exception) strips this prefix. // throw ios_base::failure (m != nullptr ? m : "", e); } template <bool v> static inline void - throw_ios_failure (error_code ec, + throw_ios_failure (error_code e, typename enable_if<!v, const char*>::type m) { - throw ios_base::failure (m != nullptr ? m : ec.message ().c_str ()); + throw ios_base::failure (m != nullptr ? m : e.message ().c_str ()); } inline void @@ -41,7 +41,7 @@ namespace butl // } // catch (const std::system_error& e) // { - // cerr << "pager error: " << e.what () << endl; + // cerr << "pager error: " << e << endl; // } // class LIBBUTL_EXPORT pager: protected std::streambuf diff --git a/butl/pager.cxx b/butl/pager.cxx index 066cd7b..e327960 100644 --- a/butl/pager.cxx +++ b/butl/pager.cxx @@ -18,6 +18,7 @@ #include <utility> // move() #include <system_error> +#include <butl/utility> // operator<<(ostream, exception) #include <butl/fdstream> // fdclose() using namespace std; @@ -147,7 +148,7 @@ namespace butl { if (e.child ()) { - cerr << args[0] << ": unable to execute: " << e.what () << endl; + cerr << args[0] << ": unable to execute: " << e << endl; exit (1); } diff --git a/butl/utility b/butl/utility index f668ecc..ac94171 100644 --- a/butl/utility +++ b/butl/utility @@ -6,10 +6,11 @@ #define BUTL_UTILITY #include <string> +#include <iosfwd> // ostream #include <cstddef> // size_t #include <utility> // move(), forward() #include <cstring> // strcmp(), strlen() -#include <exception> // uncaught_exception(s)() +#include <exception> // exception, uncaught_exception(s)() //#include <functional> // hash #include <butl/export> @@ -227,6 +228,18 @@ namespace butl #endif } +namespace std +{ + // Sanitize the exception description before printing. This includes: + // + // - stripping leading colons and spaces (see fdstream.cxx) + // - stripping trailing newlines, periods, and spaces + // - lower-case the first letter if the beginning looks like a word + // + LIBBUTL_EXPORT ostream& + operator<< (ostream&, const exception&); +} + #include <butl/utility.ixx> #endif // BUTL_UTILITY diff --git a/butl/utility.cxx b/butl/utility.cxx index d684553..d971a3f 100644 --- a/butl/utility.cxx +++ b/butl/utility.cxx @@ -2,6 +2,8 @@ // copyright : Copyright (c) 2014-2017 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include <ostream> + #include <butl/utility> namespace butl @@ -22,3 +24,69 @@ namespace butl #endif } + +namespace std +{ + using namespace butl; + + ostream& + operator<< (ostream& o, const exception& e) + { + const char* d (e.what ()); + const char* s (d); + + // Strip the leading junk (colons and spaces). + // + // Note that error descriptions for ios_base::failure exceptions thrown by + // fdstream can have the ': ' prefix for libstdc++ (read more in comment + // for throw_ios_failure()). + // + for (; *s == ' ' || *s == ':'; ++s) ; + + // Strip the trailing junk (periods, spaces, newlines). + // + // Note that msvcrt adds some junk like this: + // + // Invalid data.\r\n + // + size_t n (string::traits_type::length (s)); + for (; n > 0; --n) + { + switch (s[n-1]) + { + case '\r': + case '\n': + case '.': + case ' ': continue; + } + + break; + } + + // Lower-case the first letter if the beginning looks like a word (the + // second character is the lower-case letter or space). + // + char c; + bool lc (n > 0 && alpha (c = s[0]) && c == ucase (c) && + (n == 1 || (alpha (c = s[1]) && c == lcase (c)) || c == ' ')); + + // Print the description as is if no adjustment is required. + // + if (!lc && s == d && s[n] == '\0') + o << d; + else + { + // We need to produce the resulting description and then write it + // with a single formatted output operation. + // + string r (s, n); + + if (lc) + r[0] = lcase (r[0]); + + o << r; + } + + return o; + } +} |