aboutsummaryrefslogtreecommitdiff
path: root/butl
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-03-22 00:36:27 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-03-22 00:36:27 +0300
commit615d333787c1d8dc08df5e30c60ec20600a74b85 (patch)
treec1eccc15aa77b8d300f275d2aef169452a3db628 /butl
parent5a2fba169fc1bc3587d7d9b351d5c46a74f8f7b8 (diff)
Implement throw_generic_error() and throw_system_error()
Diffstat (limited to 'butl')
-rw-r--r--butl/fdstream.cxx38
-rw-r--r--butl/filesystem.cxx85
-rw-r--r--butl/pager.cxx6
-rw-r--r--butl/path.cxx62
-rw-r--r--butl/process9
-rw-r--r--butl/timestamp.cxx19
-rw-r--r--butl/utility7
-rw-r--r--butl/utility.cxx55
8 files changed, 169 insertions, 112 deletions
diff --git a/butl/fdstream.cxx b/butl/fdstream.cxx
index 41dd1f5..d841cc2 100644
--- a/butl/fdstream.cxx
+++ b/butl/fdstream.cxx
@@ -71,14 +71,36 @@ namespace butl
throw ios_base::failure (m != nullptr ? m : e.message ().c_str ());
}
+ // Throw system_error with generic_category.
+ //
static inline void
- throw_ios_failure (int ev, const char* m = nullptr)
+ throw_ios_failure (int errno_code, const char* m = nullptr)
{
- error_code ec (ev, system_category ());
+ error_code ec (errno_code, generic_category ());
throw_ios_failure<is_base_of<system_error, ios_base::failure>::value> (
ec, m);
}
+#ifdef _WIN32
+ // Throw system_error with system_category.
+ //
+ static inline void
+ throw_ios_system_failure (int system_code)
+ {
+ // Here we work around MinGW libstdc++ that interprets Windows system error
+ // codes (for example those returned by GetLastError()) as errno codes.
+ //
+ // Note that the resulting system_error description will have ': Success.'
+ // suffix that is stripped by our custom operator<<(ostream, exception).
+ //
+ error_code ec (0, system_category ());
+ string m (win32::error_msg (system_code));
+
+ throw_ios_failure<is_base_of<system_error, ios_base::failure>::value> (
+ ec, m.c_str ());
+ }
+#endif
+
// auto_fd
//
void auto_fd::
@@ -905,7 +927,7 @@ namespace butl
{
HANDLE h (reinterpret_cast<HANDLE> (_get_osfhandle (fd)));
if (h == INVALID_HANDLE_VALUE)
- throw_ios_failure (EIO, "unable to obtain file handle");
+ throw_ios_failure (errno); // EBADF (POSIX value).
return h;
};
@@ -921,7 +943,7 @@ namespace butl
DWORD f;
if (!GetHandleInformation (handle (fd), &f))
- throw_ios_failure (EIO, last_error_msg ().c_str ());
+ throw_ios_system_failure (GetLastError ());
// If the source handle is inheritable then no flag copy is required (as
// the duplicate handle will be inheritable by default).
@@ -933,7 +955,7 @@ namespace butl
auto_fd nfd (dup ());
if (!SetHandleInformation (handle (nfd.get ()), HANDLE_FLAG_INHERIT, 0))
- throw_ios_failure (EIO, last_error_msg ().c_str ());
+ throw_ios_system_failure (GetLastError ());
return nfd;
}
@@ -975,6 +997,10 @@ namespace butl
}
catch (const system_error& e)
{
+ // Make sure that the error denotes errno portable code.
+ //
+ assert (e.code ().category () == generic_category ());
+
errno = e.code ().value ();
return -1;
}
@@ -999,7 +1025,7 @@ namespace butl
//
int r (_setmode (fd, m == fdstream_mode::binary ? _O_BINARY : _O_TEXT));
if (r == -1)
- throw_ios_failure (errno);
+ throw_ios_failure (errno); // EBADF or EINVAL (POSIX values).
return fdstream_mode::blocking |
((r & _O_BINARY) == _O_BINARY
diff --git a/butl/filesystem.cxx b/butl/filesystem.cxx
index e881417..1873bfa 100644
--- a/butl/filesystem.cxx
+++ b/butl/filesystem.cxx
@@ -37,6 +37,7 @@
#include <system_error>
#include <butl/path>
+#include <butl/utility> // throw_generic_error()
#include <butl/fdstream>
#include <butl/small-vector>
@@ -75,7 +76,7 @@ namespace butl
if (errno == ENOENT || errno == ENOTDIR)
return make_pair (false, entry_type::unknown);
else
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
auto m (s.st_mode);
@@ -129,7 +130,7 @@ namespace butl
if (errno == ENOENT || errno == ENOTDIR)
return make_pair (false, entry_type::unknown);
else
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
auto m (s.st_mode);
@@ -166,7 +167,7 @@ namespace butl
if (e == EEXIST && dir_exists (p))
return mkdir_status::already_exists;
else
- throw system_error (e, system_category ());
+ throw_generic_error (e);
}
return mkdir_status::success;
@@ -202,7 +203,7 @@ namespace butl
else if (errno == ENOTEMPTY || errno == EEXIST)
r = rmdir_status::not_empty;
else if (!ignore_error)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
return r;
@@ -229,8 +230,9 @@ namespace butl
rmdir_status r (try_rmdir (p));
if (r != rmdir_status::success && !ignore_error)
- throw system_error (r == rmdir_status::not_empty ? ENOTEMPTY : ENOENT,
- system_category ());
+ throw_generic_error (r == rmdir_status::not_empty
+ ? ENOTEMPTY
+ : ENOENT);
}
}
@@ -251,7 +253,7 @@ namespace butl
if (errno == ENOENT || errno == ENOTDIR)
r = rmfile_status::not_exist;
else if (!ignore_error)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
return r;
@@ -262,14 +264,14 @@ namespace butl
mksymlink (const path& target, const path& link, bool)
{
if (symlink (target.string ().c_str (), link.string ().c_str ()) == -1)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
void
mkhardlink (const path& target, const path& link, bool)
{
if (::link (target.string ().c_str (), link.string ().c_str ()) == -1)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
#else
@@ -277,7 +279,7 @@ namespace butl
void
mksymlink (const path&, const path&, bool)
{
- throw system_error (ENOSYS, system_category (), "symlinks not supported");
+ throw_generic_error (ENOSYS, "symlinks not supported");
}
void
@@ -288,14 +290,10 @@ namespace butl
if (!CreateHardLinkA (link.string ().c_str (),
target.string ().c_str (),
nullptr))
- {
- string e (win32::last_error_msg ());
- throw system_error (EIO, system_category (), e);
- }
+ throw_system_error (GetLastError ());
}
else
- throw system_error (
- ENOSYS, system_category (), "directory hard links not supported");
+ throw_generic_error (ENOSYS, "directory hard links not supported");
}
#endif
@@ -362,7 +360,7 @@ namespace butl
// Note that our custom operator<<(ostream, exception) doesn't strip this
// suffix. This is a temporary code after all.
//
- throw system_error (EIO, system_category (), e.what ());
+ throw_generic_error (EIO, e.what ());
}
}
@@ -450,7 +448,7 @@ namespace butl
#ifndef _WIN32
if (!ovr && path_entry (to).first)
- throw system_error (EEXIST, system_category ());
+ throw_generic_error (EEXIST);
if (::rename (f, t) == 0) // POSIX implementation.
return;
@@ -459,7 +457,7 @@ namespace butl
// move the file ourselves.
//
if (errno != EXDEV)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
// Note that cpfile() follows symlinks, so we need to remove destination if
// exists.
@@ -474,7 +472,7 @@ namespace butl
//
struct stat s;
if (stat (f, &s) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
timeval times[2];
times[0].tv_sec = s.st_atime;
@@ -483,7 +481,7 @@ namespace butl
times[1].tv_usec = mnsec<struct stat> (&s, true) / 1000;
if (utimes (t, times) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
// Finally, remove the source file.
//
@@ -496,13 +494,8 @@ namespace butl
//
auto te (path_entry (to));
- // Note that it would be nicer to just pass standard error codes to
- // system_error ctors below, but their error descriptions horrifies for
- // msvcrt. Actually they just don't match the semantics. The resulted error
- // description is also not ideal (see below).
- //
if (!ovr && te.first)
- throw system_error (EEXIST, system_category (), "file exists");
+ throw_generic_error (EEXIST);
bool td (te.first && te.second == entry_type::directory);
@@ -513,7 +506,7 @@ namespace butl
// either directories or not directories.
//
if (fe.first && te.first && fd != td)
- throw system_error (EIO, system_category (), "not a directory");
+ throw_generic_error (ENOTDIR);
DWORD mfl (fd ? 0 : (MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING));
@@ -534,15 +527,7 @@ namespace butl
MoveFileExA (f, t, mfl))
return;
- // @@ The exception description will look like:
- //
- // file not found. : Access denied
- //
- // Probably need to consider such discriptions for sanitizing in
- // operator<<(ostream,exception).
- //
- string e (win32::error_msg (ec));
- throw system_error (EIO, system_category (), e);
+ throw_system_error (ec);
#endif
}
@@ -561,7 +546,7 @@ namespace butl
if (errno == ENOENT || errno == ENOTDIR)
return timestamp_nonexistent;
else
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
return S_ISREG (s.st_mode)
@@ -581,7 +566,7 @@ namespace butl
struct _stat s;
if (_stat (p.string ().c_str (), &s) != 0)
#endif
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
// VC++ has no S_IRWXU defined. MINGW GCC <= 4.9 has no S_IRWXG, S_IRWXO
// defined.
@@ -624,7 +609,7 @@ namespace butl
#else
if (_chmod (p.string ().c_str (), m) == -1)
#endif
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
// dir_{entry,iterator}
@@ -648,7 +633,7 @@ namespace butl
e_ = move (x.e_);
if (h_ != nullptr && closedir (h_) == -1)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
h_ = x.h_;
x.h_ = nullptr;
@@ -665,7 +650,7 @@ namespace butl
? stat (p.string ().c_str (), &s)
: lstat (p.string ().c_str (), &s)) != 0)
{
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
entry_type r;
@@ -696,7 +681,7 @@ namespace butl
h_ = h.get ();
if (h_ == nullptr)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
next ();
@@ -771,7 +756,7 @@ namespace butl
h_ = nullptr;
}
else
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
break;
}
@@ -796,7 +781,7 @@ namespace butl
e_ = move (x.e_);
if (h_ != -1 && _findclose (h_) == -1)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
h_ = x.h_;
x.h_ = -1;
@@ -814,7 +799,7 @@ namespace butl
struct _stat s;
if (_stat (p.string ().c_str (), &s) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
entry_type r;
if (S_ISREG (s.st_mode))
@@ -876,7 +861,7 @@ namespace butl
// Check to distinguish non-existent vs empty directories.
//
if (!dir_exists (e_.b_))
- throw system_error (ENOENT, system_category ());
+ throw_generic_error (ENOENT);
h_ = _findfirst ((e_.b_ / path ("*")).string ().c_str (), &fi);
r = h_ != -1;
@@ -917,7 +902,7 @@ namespace butl
}
}
else
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
break;
}
@@ -1187,6 +1172,10 @@ namespace butl
// other error. We consider ENOTDIR as a variety of removal, with a
// new filesystem entry being created afterwards.
//
+ // Make sure that the error denotes errno portable code.
+ //
+ assert (e.code ().category () == generic_category ());
+
int ec (e.code ().value ());
if (ec != ENOENT && ec != ENOTDIR)
throw;
diff --git a/butl/pager.cxx b/butl/pager.cxx
index e327960..fe59e5b 100644
--- a/butl/pager.cxx
+++ b/butl/pager.cxx
@@ -16,9 +16,9 @@
#include <cstring> // strchr()
#include <utility> // move()
-#include <system_error>
-#include <butl/utility> // operator<<(ostream, exception)
+#include <butl/utility> // operator<<(ostream, exception),
+ // throw_generic_error()
#include <butl/fdstream> // fdclose()
using namespace std;
@@ -139,7 +139,7 @@ namespace butl
p_.out_fd.reset ();
if (pager != nullptr)
- throw system_error (ECHILD, system_category ());
+ throw_generic_error (ECHILD);
}
else
os_.open (move (p_.out_fd));
diff --git a/butl/path.cxx b/butl/path.cxx
index 9947bbe..dfa812b 100644
--- a/butl/path.cxx
+++ b/butl/path.cxx
@@ -28,10 +28,10 @@
#include <atomic>
#include <cassert>
#include <cstring> // strcpy()
-#include <system_error>
#include <butl/export>
+#include <butl/utility> // throw_*_error()
#include <butl/process>
#ifndef _WIN32
@@ -65,12 +65,12 @@ namespace butl
#ifdef _WIN32
char cwd[_MAX_PATH];
if (_getcwd (cwd, _MAX_PATH) == 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
cwd[0] = toupper (cwd[0]); // Canonicalize.
#else
char cwd[PATH_MAX];
if (getcwd (cwd, PATH_MAX) == 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
#endif
return cwd;
@@ -93,10 +93,10 @@ namespace butl
: string_type (s + directory_separator));
if (_chdir (d.c_str ()) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
#else
if (chdir (s.c_str ()) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
#endif
}
@@ -115,10 +115,10 @@ namespace butl
struct stat s;
if (stat (dir, &s) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
if (!S_ISDIR (s.st_mode))
- throw system_error (ENOTDIR, system_category ());
+ throw_generic_error (ENOTDIR);
return dir;
}
@@ -141,13 +141,13 @@ namespace butl
int r (getpwuid_r (getuid (), &pw, buf, sizeof (buf), &rpw));
if (r == -1)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
if (r == 0 && rpw == nullptr)
// According to POSIX errno should be left unchanged if an entry is not
// found.
//
- throw system_error (ENOENT, system_category ());
+ throw_generic_error (ENOENT);
return pw.pw_dir;
}
@@ -160,10 +160,7 @@ namespace butl
#ifdef _WIN32
char d[_MAX_PATH + 1];
if (GetTempPathA (_MAX_PATH + 1, d) == 0)
- {
- string e (last_error_msg ());
- throw system_error (ENOTDIR, system_category (), e);
- }
+ throw_system_error (GetLastError ());
return d;
#else
@@ -198,10 +195,7 @@ namespace butl
HRESULT r (SHGetFolderPathA (NULL, CSIDL_PROFILE, NULL, 0, h));
if (!SUCCEEDED (r))
- {
- string e (error_msg (r));
- throw system_error (ENOTDIR, system_category (), e);
- }
+ throw_system_error (r);
return h;
#endif
@@ -221,7 +215,7 @@ namespace butl
if (errno == EACCES || errno == ENOENT || errno == ENOTDIR)
throw invalid_basic_path<char> (s);
else
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
}
s = r;
@@ -239,16 +233,16 @@ namespace butl
#ifdef _WIN32
wchar_t wcwd[_MAX_PATH];
if (_wgetcwd (wcwd, _MAX_PATH) == 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
wcwd[0] = toupper (wcwd[0]); // Canonicalize.
#else
char cwd[PATH_MAX];
if (getcwd (cwd, PATH_MAX) == 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
wchar_t wcwd[PATH_MAX];
if (mbstowcs (wcwd, cwd, PATH_MAX) == size_type (-1))
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
#endif
return wcwd;
@@ -268,17 +262,17 @@ namespace butl
: string_type (s + directory_separator));
if (_wchdir (d.c_str ()) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
#else
char ns[PATH_MAX + 1];
if (wcstombs (ns, s.c_str (), PATH_MAX) == size_type (-1))
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
ns[PATH_MAX] = '\0';
if (chdir (ns) != 0)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
#endif
}
@@ -289,10 +283,7 @@ namespace butl
#ifdef _WIN32
wchar_t d[_MAX_PATH + 1];
if (GetTempPathW (_MAX_PATH + 1, d) == 0)
- {
- string e (last_error_msg ());
- throw system_error (ENOTDIR, system_category (), e);
- }
+ throw_system_error (GetLastError ());
#else
wchar_t d[PATH_MAX];
@@ -304,10 +295,10 @@ namespace butl
size_t r (mbstowcs (d, butl::temp_directory (), PATH_MAX));
if (r == size_t (-1))
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
if (r == PATH_MAX)
- throw system_error (ENOTSUP, system_category ());
+ throw_generic_error (ENOTSUP);
#endif
return d;
@@ -331,10 +322,10 @@ namespace butl
size_t r (mbstowcs (d, home ().c_str (), PATH_MAX));
if (r == size_t (-1))
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
if (r == PATH_MAX)
- throw system_error (ENOTSUP, system_category ());
+ throw_generic_error (ENOTSUP);
return d;
#else
@@ -347,10 +338,7 @@ namespace butl
HRESULT r (SHGetFolderPathW (NULL, CSIDL_PROFILE, NULL, 0, h));
if (!SUCCEEDED (r))
- {
- string e (error_msg (r));
- throw system_error (ENOTDIR, system_category (), e);
- }
+ throw_system_error (r);
return h;
#endif
@@ -388,7 +376,7 @@ namespace butl
return false;
if (h == -1 || _findclose (h) == -1)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
r += fi.name;
return true;
diff --git a/butl/process b/butl/process
index 19bea3a..31cb681 100644
--- a/butl/process
+++ b/butl/process
@@ -30,13 +30,14 @@ namespace butl
#ifndef _WIN32
process_error (int e, bool child)
- : system_error (e, std::system_category ()), child_ (child) {}
+ : system_error (e, std::generic_category ()), child_ (child) {}
#else
process_error (int e, bool child = false)
- : system_error (e, std::system_category ()), child_ (child) {}
+ : system_error (e, std::generic_category ()), child_ (child) {}
- process_error (const std::string& d, int e = ECHILD)
- : system_error (e, std::system_category (), d), child_ (false) {}
+ process_error (const std::string& d, int fallback_errno_code = 0)
+ : system_error (fallback_errno_code, std::system_category (), d),
+ child_ (false) {}
#endif
private:
diff --git a/butl/timestamp.cxx b/butl/timestamp.cxx
index d38c018..971f1ef 100644
--- a/butl/timestamp.cxx
+++ b/butl/timestamp.cxx
@@ -15,7 +15,8 @@
#include <ostream>
#include <utility> // pair, make_pair()
#include <stdexcept> // runtime_error
-#include <system_error>
+
+#include <butl/utility> // throw_generic_error()
using namespace std;
@@ -137,7 +138,7 @@ namespace butl
if ((local
? details::localtime (&t, &tm)
: details::gmtime (&t, &tm)) == nullptr)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
using namespace chrono;
@@ -147,7 +148,7 @@ namespace butl
char fmt[256];
size_t n (strlen (format));
if (n + 1 > sizeof (fmt))
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
memcpy (fmt, format, n + 1);
// Chunk the format string into fragments that we feed to put_time() and
@@ -175,18 +176,18 @@ namespace butl
j += 2; // Character after '['.
if (j == n)
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
char d ('\0');
if (fmt[j] != 'N')
{
d = fmt[j];
if (++j == n || fmt[j] != 'N')
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
}
if (++j == n || fmt[j] != ']')
- throw system_error (EINVAL, system_category ());
+ throw_generic_error (EINVAL);
if (ns != nanoseconds::zero ())
{
@@ -267,7 +268,7 @@ namespace butl
{
std::tm tm;
if (details::gmtime (&t, &tm) == nullptr)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
if (t >= 24 * 60 * 60)
tm.tm_mday -= 1; // Make day of the month to be a zero-based number.
@@ -431,7 +432,7 @@ namespace butl
static pair<tm, chrono::nanoseconds>
from_string (const char* input, const char* format, const char** end)
{
- auto bad_val = []() {throw system_error (EINVAL, system_category ());};
+ auto bad_val = [] () {throw_generic_error (EINVAL);};
// See if we have our specifier.
//
@@ -603,7 +604,7 @@ namespace butl
time_t time (local ? mktime (&t.first) : timegm (&t.first));
if (time == -1)
- throw system_error (errno, system_category ());
+ throw_generic_error (errno);
return timestamp::clock::from_time_t (time) +
chrono::duration_cast<duration> (t.second);
diff --git a/butl/utility b/butl/utility
index 7dc4d73..673b715 100644
--- a/butl/utility
+++ b/butl/utility
@@ -30,10 +30,10 @@ namespace butl
//
// See also the exception sanitization below.
//
- [[noreturn]] void
- throw_generic_error (int errno_code);
+ [[noreturn]] LIBBUTL_EXPORT void
+ throw_generic_error (int errno_code, const char* what = nullptr);
- [[noreturn]] void
+ [[noreturn]] LIBBUTL_EXPORT void
throw_system_error (int system_code, int fallback_errno_code = 0);
// Convert ASCII character/string case. If there is no upper/lower case
@@ -252,6 +252,7 @@ namespace std
//
// - stripping leading colons and spaces (see fdstream.cxx)
// - stripping trailing newlines, periods, and spaces
+ // - stripping system error redundant suffix (see utility.cxx)
// - lower-case the first letter if the beginning looks like a word
//
LIBBUTL_EXPORT ostream&
diff --git a/butl/utility.cxx b/butl/utility.cxx
index 84c8a74..03045da 100644
--- a/butl/utility.cxx
+++ b/butl/utility.cxx
@@ -2,12 +2,20 @@
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#include <ostream>
-
#include <butl/utility>
+#ifdef _WIN32
+# include <butl/win32-utility>
+#endif
+
+#include <string>
+#include <ostream>
+#include <system_error>
+
namespace butl
{
+ using namespace std;
+
#ifndef __cpp_lib_uncaught_exceptions
#ifdef __cpp_thread_local
@@ -23,6 +31,39 @@ namespace butl
#endif
#endif
+
+ [[noreturn]] void
+ throw_generic_error (int errno_code, const char* what)
+ {
+ if (what == nullptr)
+ throw system_error (errno_code, generic_category ());
+ else
+ throw system_error (errno_code, generic_category (), what);
+ }
+
+ [[noreturn]] void
+#ifndef _WIN32
+ throw_system_error (int system_code, int)
+ {
+ throw system_error (system_code, system_category ());
+#else
+ throw_system_error (int system_code, int fallback_errno_code)
+ {
+ // Here we work around MinGW libstdc++ that interprets Windows system error
+ // codes (for example those returned by GetLastError()) as errno codes. The
+ // resulting system_error description will have the following form:
+ //
+ // <system_code description>: <fallback_errno_code description>
+ //
+ // Also note that the fallback-related description suffix is stripped by
+ // our custom operator<<(ostream, exception) for the common case (see
+ // below).
+ //
+ throw system_error (fallback_errno_code,
+ system_category (),
+ win32::error_msg (system_code));
+#endif
+ }
}
namespace std
@@ -63,6 +104,16 @@ namespace std
break;
}
+ // Strip the suffix for system_error thrown by
+ // throw_system_error(system_code) on Windows. For example for the
+ // ERROR_INVALID_DATA error code the original description will be
+ // 'Invalid data. : Success' for MinGW libstdc++ and
+ // 'Invalid data. : Success.' for msvcrt.
+ //
+ if (n >= 11 &&
+ string::traits_type::compare (s + n - 11, ". : Success", 11) == 0)
+ n -= 11;
+
// Lower-case the first letter if the beginning looks like a word (the
// second character is the lower-case letter or space).
//