aboutsummaryrefslogtreecommitdiff
path: root/butl/utility.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'butl/utility.cxx')
-rw-r--r--butl/utility.cxx68
1 files changed, 68 insertions, 0 deletions
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;
+ }
+}