From 9a81c308f2d4217592630ef41a18a8998bd66f5c Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 6 Jan 2017 03:26:03 +0300 Subject: Add operator<<(ostream, exception) --- butl/fdstream | 2 +- butl/fdstream.cxx | 12 ++++--- butl/pager | 2 +- butl/pager.cxx | 3 +- butl/utility | 15 +++++++- butl/utility.cxx | 68 ++++++++++++++++++++++++++++++++++++ tests/dir-iterator/driver.cxx | 3 +- tests/link/driver.cxx | 2 +- tests/manifest-parser/driver.cxx | 2 +- tests/manifest-roundtrip/driver.cxx | 3 +- tests/manifest-serializer/driver.cxx | 2 +- tests/process/driver.cxx | 2 +- tests/target-triplet/driver.cxx | 2 +- 13 files changed, 103 insertions(+), 15 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 static inline void - throw_ios_failure (error_code ec, + throw_ios_failure (error_code e, typename enable_if::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 diff --git a/butl/pager b/butl/pager index b1d7a9f..37dbc43 100644 --- a/butl/pager +++ b/butl/pager @@ -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 // move() #include +#include // operator<<(ostream, exception) #include // 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 +#include // ostream #include // size_t #include // move(), forward() #include // strcmp(), strlen() -#include // uncaught_exception(s)() +#include // exception, uncaught_exception(s)() //#include // hash #include @@ -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 #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 + #include 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; + } +} diff --git a/tests/dir-iterator/driver.cxx b/tests/dir-iterator/driver.cxx index 62f051b..d3d25b8 100644 --- a/tests/dir-iterator/driver.cxx +++ b/tests/dir-iterator/driver.cxx @@ -8,6 +8,7 @@ #include #include +#include // operator<<(ostream, exception) #include using namespace std; @@ -62,7 +63,7 @@ main (int argc, const char* argv[]) } catch (const exception& e) { - cerr << argv[1] << ": " << e.what () << endl; + cerr << argv[1] << ": " << e << endl; return 1; } } diff --git a/tests/link/driver.cxx b/tests/link/driver.cxx index 3171af0..3cade44 100644 --- a/tests/link/driver.cxx +++ b/tests/link/driver.cxx @@ -57,7 +57,7 @@ link_dir (const dir_path& target, } catch (const system_error& e) { - //cerr << e.what () << endl; + //cerr << e << endl; return false; } diff --git a/tests/manifest-parser/driver.cxx b/tests/manifest-parser/driver.cxx index 1068570..76d1579 100644 --- a/tests/manifest-parser/driver.cxx +++ b/tests/manifest-parser/driver.cxx @@ -200,7 +200,7 @@ fail (const char* m) } catch (const manifest_parsing& e) { - //cerr << e.what () << endl; + //cerr << e << endl; } return true; diff --git a/tests/manifest-roundtrip/driver.cxx b/tests/manifest-roundtrip/driver.cxx index cb48e74..69fcf03 100644 --- a/tests/manifest-roundtrip/driver.cxx +++ b/tests/manifest-roundtrip/driver.cxx @@ -5,6 +5,7 @@ #include #include +#include // operator<<(ostream, exception) #include #include #include @@ -46,7 +47,7 @@ main (int argc, char* argv[]) } catch (const exception& e) { - cerr << e.what () << endl; + cerr << e << endl; return 1; } } diff --git a/tests/manifest-serializer/driver.cxx b/tests/manifest-serializer/driver.cxx index 310e34c..64434c9 100644 --- a/tests/manifest-serializer/driver.cxx +++ b/tests/manifest-serializer/driver.cxx @@ -238,7 +238,7 @@ fail (const pairs& m) } catch (const manifest_serialization& e) { - //cerr << e.what () << endl; + //cerr << e << endl; } return true; diff --git a/tests/process/driver.cxx b/tests/process/driver.cxx index cc806f2..1fb685c 100644 --- a/tests/process/driver.cxx +++ b/tests/process/driver.cxx @@ -146,7 +146,7 @@ exec (const path& p, if (e.child ()) exit (1); - //cerr << args[0] << ": " << e.what () << endl; + //cerr << args[0] << ": " << e << endl; return false; } } diff --git a/tests/target-triplet/driver.cxx b/tests/target-triplet/driver.cxx index fe055db..24cd02f 100644 --- a/tests/target-triplet/driver.cxx +++ b/tests/target-triplet/driver.cxx @@ -154,7 +154,7 @@ fail (const char* s) } catch (invalid_argument& e) { - //cerr << e.what () << endl; + //cerr << e << endl; } return true; -- cgit v1.1