aboutsummaryrefslogtreecommitdiff
path: root/butl
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-01-06 03:26:03 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-01-09 21:31:14 +0300
commit9a81c308f2d4217592630ef41a18a8998bd66f5c (patch)
treee5ab252f90d1b3aa2a2f2775f0f36e569d48b4a5 /butl
parent39101a4383d38c1217c44b999a6e3bd199727c60 (diff)
Add operator<<(ostream, exception)
Diffstat (limited to 'butl')
-rw-r--r--butl/fdstream2
-rw-r--r--butl/fdstream.cxx12
-rw-r--r--butl/pager2
-rw-r--r--butl/pager.cxx3
-rw-r--r--butl/utility15
-rw-r--r--butl/utility.cxx68
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
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 <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;
+ }
+}