Replace FMT_THROW with FMT_ERROR

FMT_ERROR uses fmt::error_reporter_t, which enables user
to customize error handler.
This is especially useful when the exception is disabled.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2021-02-25 19:15:36 +11:00
parent 578874033a
commit b23f48f297
No known key found for this signature in database
GPG Key ID: 28165BFE1CC855B2
7 changed files with 182 additions and 70 deletions

View File

@ -326,7 +326,7 @@ inline std::tm localtime(std::time_t time) {
}; };
dispatcher lt(time); dispatcher lt(time);
// Too big time values may be unsupported. // Too big time values may be unsupported.
if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); if (!lt.run()) FMT_ERROR(Error_type::format_error, "time_t value out of range");
return lt.tm_; return lt.tm_;
} }
@ -371,7 +371,7 @@ inline std::tm gmtime(std::time_t time) {
}; };
dispatcher gt(time); dispatcher gt(time);
// Too big time values may be unsupported. // Too big time values may be unsupported.
if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); if (!gt.run()) FMT_ERROR(Error_type::format_error, "time_t value out of range");
return gt.tm_; return gt.tm_;
} }
@ -537,7 +537,9 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
} }
if (begin != ptr) handler.on_text(begin, ptr); if (begin != ptr) handler.on_text(begin, ptr);
++ptr; // consume '%' ++ptr; // consume '%'
if (ptr == end) FMT_THROW(format_error("invalid format")); if (ptr == end)
FMT_ERROR(Error_type::format_error, "invalid format",
basic_string_view<Char>(begin, static_cast<std::size_t>(end - begin)));
c = *ptr++; c = *ptr++;
switch (c) { switch (c) {
case '%': case '%':
@ -628,7 +630,9 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
break; break;
// Alternative representation: // Alternative representation:
case 'E': { case 'E': {
if (ptr == end) FMT_THROW(format_error("invalid format")); if (ptr == end)
FMT_ERROR(Error_type::format_error, "invalid format",
basic_string_view<Char>(begin, static_cast<std::size_t>(end - begin)));
c = *ptr++; c = *ptr++;
switch (c) { switch (c) {
case 'c': case 'c':
@ -641,12 +645,15 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
handler.on_loc_time(numeric_system::alternative); handler.on_loc_time(numeric_system::alternative);
break; break;
default: default:
FMT_THROW(format_error("invalid format")); FMT_ERROR(Error_type::format_error, "invalid format",
basic_string_view<Char>(begin, static_cast<std::size_t>(end - begin)));
} }
break; break;
} }
case 'O': case 'O':
if (ptr == end) FMT_THROW(format_error("invalid format")); if (ptr == end)
FMT_ERROR(Error_type::format_error, "invalid format",
basic_string_view<Char>(begin, static_cast<std::size_t>(end - begin)));
c = *ptr++; c = *ptr++;
switch (c) { switch (c) {
case 'w': case 'w':
@ -668,11 +675,13 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
handler.on_second(numeric_system::alternative); handler.on_second(numeric_system::alternative);
break; break;
default: default:
FMT_THROW(format_error("invalid format")); FMT_ERROR(Error_type::format_error, "invalid format",
basic_string_view<Char>(begin, static_cast<std::size_t>(end - begin)));
} }
break; break;
default: default:
FMT_THROW(format_error("invalid format")); FMT_ERROR(Error_type::format_error, "invalid format",
basic_string_view<Char>(begin, static_cast<std::size_t>(end - begin)));
} }
begin = ptr; begin = ptr;
} }
@ -681,7 +690,7 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
} }
struct chrono_format_checker { struct chrono_format_checker {
FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); } FMT_NORETURN void report_no_date() { FMT_ERROR(Error_type::format_error, "no date"); }
template <typename Char> template <typename Char>
FMT_CONSTEXPR void on_text(const Char*, const Char*) {} FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
@ -771,7 +780,7 @@ template <typename To, typename FromRep, typename FromPeriod>
To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) { To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) {
int ec; int ec;
To to = safe_duration_cast::safe_duration_cast<To>(from, ec); To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
if (ec) FMT_THROW(format_error("cannot format duration")); if (ec) FMT_ERROR(Error_type::format_error, "cannot format duration");
return to; return to;
} }
#endif #endif
@ -1104,7 +1113,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
return arg_ref_type(context.next_arg_id()); return arg_ref_type(context.next_arg_id());
} }
void on_error(const char* msg) { FMT_THROW(format_error(msg)); } void on_error(const char* msg) { FMT_ERROR(Error_type::format_error, msg); }
FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) { FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
f.specs.fill = fill; f.specs.fill = fill;
} }

View File

@ -244,7 +244,7 @@ class text_style {
foreground_color = rhs.foreground_color; foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) { } else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
FMT_THROW(format_error("can't OR a terminal color")); FMT_ERROR(Error_type::format_error, "can't OR a terminal color");
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
} }
@ -253,7 +253,7 @@ class text_style {
background_color = rhs.background_color; background_color = rhs.background_color;
} else if (rhs.set_background_color) { } else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb) if (!background_color.is_rgb || !rhs.background_color.is_rgb)
FMT_THROW(format_error("can't OR a terminal color")); FMT_ERROR(Error_type::format_error, "can't OR a terminal color");
background_color.value.rgb_color |= rhs.background_color.value.rgb_color; background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
} }
@ -321,7 +321,7 @@ class text_style {
foreground_color = rhs.foreground_color; foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) { } else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color")); FMT_ERROR(Error_type::format_error, "can't AND a terminal color");
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
} }
@ -330,7 +330,7 @@ class text_style {
background_color = rhs.background_color; background_color = rhs.background_color;
} else if (rhs.set_background_color) { } else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb) if (!background_color.is_rgb || !rhs.background_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color")); FMT_ERROR(Error_type::format_error, "can't AND a terminal color");
background_color.value.rgb_color &= rhs.background_color.value.rgb_color; background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
} }

View File

@ -164,7 +164,7 @@ FMT_FUNC void report_error(format_func func, int error_code,
inline void fwrite_fully(const void* ptr, size_t size, size_t count, inline void fwrite_fully(const void* ptr, size_t size, size_t count,
FILE* stream) { FILE* stream) {
size_t written = std::fwrite(ptr, size, count, stream); size_t written = std::fwrite(ptr, size, count, stream);
if (written < count) FMT_THROW(system_error(errno, "cannot write to file")); if (written < count) FMT_ERROR(Error_type::system_error, errno, "cannot write to file");
} }
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
@ -2627,7 +2627,7 @@ template <> struct formatter<detail::bigint> {
FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
for_each_codepoint(s, [this](uint32_t cp, int error) { for_each_codepoint(s, [this](uint32_t cp, int error) {
if (error != 0) FMT_THROW(std::runtime_error("invalid utf8")); if (error != 0) FMT_ERROR(Error_type::runtime_error, "invalid utf8");
if (cp <= 0xFFFF) { if (cp <= 0xFFFF) {
buffer_.push_back(static_cast<wchar_t>(cp)); buffer_.push_back(static_cast<wchar_t>(cp));
} else { } else {
@ -2663,7 +2663,7 @@ FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code,
} }
FMT_FUNC void detail::error_handler::on_error(const char* message) { FMT_FUNC void detail::error_handler::on_error(const char* message) {
FMT_THROW(format_error(message)); FMT_ERROR(Error_type::format_error, message);
} }
FMT_FUNC void report_system_error(int error_code, FMT_FUNC void report_system_error(int error_code,

View File

@ -103,29 +103,53 @@
# endif # endif
#endif #endif
#ifndef FMT_THROW #ifndef FMT_ERROR
# if FMT_EXCEPTIONS
# if FMT_MSC_VER || FMT_NVCC
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace detail { enum class Error_type {
template <typename Exception> inline void do_throw(const Exception& x) { format_error,
// Silence unreachable code warnings in MSVC and NVCC because these system_error,
// are nearly impossible to fix in a generic code. runtime_error,
volatile bool b = true; # ifdef _WIN32
if (b) throw x; windows_error,
} # endif
} // namespace detail };
/**
* Use error_reporter_t as a customization point.
*/
template <Error_type error_type, typename = void> struct error_reporter_t;
template <typename void_type> struct error_reporter_t<Error_type::format_error, void_type> {
template <typename Char = char>
FMT_NORETURN void operator () (int line, const char *func, const char *file, const char *msg,
basic_string_view<Char> fmt = basic_string_view<Char>());
};
template <typename void_type> struct error_reporter_t<Error_type::system_error, void_type> {
template <typename ...Args>
FMT_NORETURN void operator () (int line, const char *func, const char *file,
int error_code, const char *msg,
const Args&... args);
};
template <typename void_type> struct error_reporter_t<Error_type::runtime_error, void_type> {
FMT_NORETURN void operator () (int line, const char *func, const char *file, const char *msg);
};
# ifdef __GNUC__
# define FMT_ERROR(error_type, ...) \
do { \
::fmt::error_reporter_t<(error_type)> error_reporter; \
error_reporter(__LINE__, __PRETTY_FUNCTION__, __FILE__, __VA_ARGS__); \
} while (0)
# else
# define FMT_ERROR(error_type, ...) \
do { \
::fmt::error_reporter_t<(error_type)> error_reporter; \
error_reporter(__LINE__, __FUNCTION__, __FILE__, __VA_ARGS__); \
} while (0)
# endif
FMT_END_NAMESPACE FMT_END_NAMESPACE
# define FMT_THROW(x) detail::do_throw(x)
# else
# define FMT_THROW(x) throw x
# endif
# else
# define FMT_THROW(x) \
do { \
FMT_ASSERT(false, (x).what()); \
} while (false)
# endif
#endif #endif
#if FMT_EXCEPTIONS #if FMT_EXCEPTIONS
@ -940,7 +964,6 @@ class FMT_API format_error : public std::runtime_error {
}; };
namespace detail { namespace detail {
template <typename T> template <typename T>
using is_signed = using is_signed =
std::integral_constant<bool, std::numeric_limits<T>::is_signed || std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
@ -1324,7 +1347,7 @@ template <typename Char> struct fill_t {
FMT_CONSTEXPR void operator=(basic_string_view<Char> s) { FMT_CONSTEXPR void operator=(basic_string_view<Char> s) {
auto size = s.size(); auto size = s.size();
if (size > max_size) { if (size > max_size) {
FMT_THROW(format_error("invalid fill")); FMT_ERROR(Error_type::format_error, "invalid fill");
return; return;
} }
for (size_t i = 0; i < size; ++i) data_[i] = s[i]; for (size_t i = 0; i < size; ++i) data_[i] = s[i];
@ -1928,7 +1951,7 @@ template <typename OutputIt, typename Char, typename UInt> struct int_writer {
void on_chr() { out = write_char(out, static_cast<Char>(abs_value), specs); } void on_chr() { out = write_char(out, static_cast<Char>(abs_value), specs); }
FMT_NORETURN void on_error() { FMT_NORETURN void on_error() {
FMT_THROW(format_error("invalid type specifier")); FMT_ERROR(Error_type::format_error, "invalid type specifier");
} }
}; };
@ -2146,7 +2169,7 @@ OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs,
int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
if (fspecs.format == float_format::exp) { if (fspecs.format == float_format::exp) {
if (precision == max_value<int>()) if (precision == max_value<int>())
FMT_THROW(format_error("number is too big")); FMT_ERROR(Error_type::format_error, "number is too big");
else else
++precision; ++precision;
} }
@ -2282,7 +2305,7 @@ FMT_CONSTEXPR OutputIt write(OutputIt out, Char value) {
template <typename Char, typename OutputIt> template <typename Char, typename OutputIt>
FMT_CONSTEXPR OutputIt write(OutputIt out, const Char* value) { FMT_CONSTEXPR OutputIt write(OutputIt out, const Char* value) {
if (!value) { if (!value) {
FMT_THROW(format_error("string pointer is null")); FMT_ERROR(Error_type::format_error, "string pointer is null");
} else { } else {
auto length = std::char_traits<Char>::length(value); auto length = std::char_traits<Char>::length(value);
out = write(out, basic_string_view<Char>(value, length)); out = write(out, basic_string_view<Char>(value, length));
@ -2442,7 +2465,7 @@ class arg_formatter_base {
void write(const Char* value) { void write(const Char* value) {
if (!value) { if (!value) {
FMT_THROW(format_error("string pointer is null")); FMT_ERROR(Error_type::format_error, "string pointer is null");
} else { } else {
auto length = std::char_traits<char_type>::length(value); auto length = std::char_traits<char_type>::length(value);
basic_string_view<char_type> sv(value, length); basic_string_view<char_type> sv(value, length);
@ -3546,6 +3569,65 @@ FMT_API void format_system_error(detail::buffer<char>& out, int error_code,
FMT_API void report_system_error(int error_code, FMT_API void report_system_error(int error_code,
string_view message) FMT_NOEXCEPT; string_view message) FMT_NOEXCEPT;
/* Overload for format_error */
template <typename void_type>
template <typename Char>
FMT_NORETURN void error_reporter_t<Error_type::format_error, void_type>::operator () (
int line, const char *func, const char *file,
const char *msg, basic_string_view<Char> fmt) {
#if FMT_EXCEPTIONS
static_cast<void>(line);
static_cast<void>(func);
static_cast<void>(file);
static_cast<void>(fmt);
throw format_error(msg);
#else
if (fmt.size())
std::fprintf(stderr, "%d of %s, %s failed to format %s: %s\n",
line, func, file, fmt.data(), msg);
else
std::fprintf(stderr, "%d of %s, %s failed: %s\n",
line, func, file, msg);
std::terminate();
#endif
}
/* Overload for system_error */
template <typename void_type>
template <typename ...Args>
FMT_NORETURN void error_reporter_t<Error_type::system_error, void_type>::operator () (
int line, const char *func, const char *file,
int error_code, const char *msg, const Args&... args) {
#if FMT_EXCEPTIONS
static_cast<void>(line);
static_cast<void>(func);
static_cast<void>(file);
throw system_error(error_code, msg, args...);
#else
report_system_error(error_code, format(msg, args...));
std::terminate();
#endif
}
/* Overload for runtime_error */
template <typename void_type>
FMT_NORETURN void error_reporter_t<Error_type::runtime_error, void_type>::operator () (
int line, const char *func, const char *file,
const char *msg) {
#if FMT_EXCEPTIONS
static_cast<void>(line);
static_cast<void>(func);
static_cast<void>(file);
throw std::runtime_error(msg);
#else
std::fprintf(stderr, "Runtime error: %s\n", msg);
std::terminate();
#endif
}
/** Fast integer formatter. */ /** Fast integer formatter. */
class format_int { class format_int {
private: private:
@ -4123,7 +4205,7 @@ void vprint(std::FILE* f, basic_string_view<Char> format_str,
detail::vformat_to(buffer, format_str, args); detail::vformat_to(buffer, format_str, args);
buffer.push_back(L'\0'); buffer.push_back(L'\0');
if (std::fputws(buffer.data(), f) == -1) if (std::fputws(buffer.data(), f) == -1)
FMT_THROW(system_error(errno, "cannot write to file")); FMT_ERROR(Error_type::system_error, errno, "cannot write to file");
} }
template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)> template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>

View File

@ -198,6 +198,25 @@ class windows_error : public system_error {
// Can be used to report errors from destructors. // Can be used to report errors from destructors.
FMT_API void report_windows_error(int error_code, FMT_API void report_windows_error(int error_code,
string_view message) FMT_NOEXCEPT; string_view message) FMT_NOEXCEPT;
template <typename void_type> struct error_reporter_t<Error_type::windows_error, void_type> {
template <typename... Args>
FMT_NORETURN void operator () (int line, const char *func, const char *file,
int error_code, const char *message,
const Args&... args) {
#if FMT_EXCEPTIONS
static_cast<void>(line);
static_cast<void>(func);
static_cast<void>(file);
throw windows_error(error_code, message, args...);
#else
report_windows_error(error_code, format(message, args...));
std::terminate();
#endif
}
};
#endif // _WIN32 #endif // _WIN32
// A buffered file. // A buffered file.
@ -469,7 +488,7 @@ class locale {
# else # else
locale_ = _create_locale(LC_NUMERIC, "C"); locale_ = _create_locale(LC_NUMERIC, "C");
# endif # endif
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale")); if (!locale_) FMT_ERROR(Error_type::system_error, errno, "cannot create locale");
} }
~locale() { freelocale(locale_); } ~locale() { freelocale(locale_); }

View File

@ -39,13 +39,13 @@ class printf_precision_handler {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
int operator()(T value) { int operator()(T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big")); FMT_ERROR(Error_type::format_error, "number is too big");
return (std::max)(static_cast<int>(value), 0); return (std::max)(static_cast<int>(value), 0);
} }
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
int operator()(T) { int operator()(T) {
FMT_THROW(format_error("precision is not integer")); FMT_ERROR(Error_type::format_error, "precision is not integer");
return 0; return 0;
} }
}; };
@ -167,13 +167,13 @@ template <typename Char> class printf_width_handler {
width = 0 - width; width = 0 - width;
} }
unsigned int_max = max_value<int>(); unsigned int_max = max_value<int>();
if (width > int_max) FMT_THROW(format_error("number is too big")); if (width > int_max) FMT_ERROR(Error_type::format_error, "number is too big");
return static_cast<unsigned>(width); return static_cast<unsigned>(width);
} }
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
unsigned operator()(T) { unsigned operator()(T) {
FMT_THROW(format_error("width is not integer")); FMT_ERROR(Error_type::format_error, "width is not integer");
return 0; return 0;
} }
}; };
@ -577,7 +577,9 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
} }
// Parse type. // Parse type.
if (it == end) FMT_THROW(format_error("invalid format string")); if (it == end)
FMT_ERROR(Error_type::format_error, "invalid format string",
basic_string_view<Char>(start, static_cast<std::size_t>(end - start)));
specs.type = static_cast<char>(*it++); specs.type = static_cast<char>(*it++);
if (arg.is_integral()) { if (arg.is_integral()) {
// Normalize type. // Normalize type.

View File

@ -75,8 +75,8 @@ FMT_BEGIN_NAMESPACE
#ifdef _WIN32 #ifdef _WIN32
detail::utf16_to_utf8::utf16_to_utf8(wstring_view s) { detail::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
if (int error_code = convert(s)) { if (int error_code = convert(s)) {
FMT_THROW(windows_error(error_code, FMT_ERROR(Error_type::windows_error, error_code,
"cannot convert string from UTF-16 to UTF-8")); "cannot convert string from UTF-16 to UTF-8");
} }
} }
@ -154,14 +154,14 @@ buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
nullptr); nullptr);
if (!file_) if (!file_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str())); FMT_ERROR(Error_type::system_error, errno, "cannot open file {}", filename.c_str());
} }
void buffered_file::close() { void buffered_file::close() {
if (!file_) return; if (!file_) return;
int result = FMT_SYSTEM(fclose(file_)); int result = FMT_SYSTEM(fclose(file_));
file_ = nullptr; file_ = nullptr;
if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); if (result != 0) FMT_ERROR(Error_type::system_error, errno, "cannot close file");
} }
// A macro used to prevent expansion of fileno on broken versions of MinGW. // A macro used to prevent expansion of fileno on broken versions of MinGW.
@ -169,7 +169,7 @@ void buffered_file::close() {
int buffered_file::fileno() const { int buffered_file::fileno() const {
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor")); if (fd == -1) FMT_ERROR(Error_type::system_error, errno, "cannot get file descriptor");
return fd; return fd;
} }
@ -183,7 +183,7 @@ file::file(cstring_view path, int oflag) {
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
# endif # endif
if (fd_ == -1) if (fd_ == -1)
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str())); FMT_ERROR(Error_type::system_error, errno, "cannot open file {}", path.c_str());
} }
file::~file() FMT_NOEXCEPT { file::~file() FMT_NOEXCEPT {
@ -199,7 +199,7 @@ void file::close() {
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_)); int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1; fd_ = -1;
if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); if (result != 0) FMT_ERROR(Error_type::system_error, errno, "cannot close file");
} }
long long file::size() const { long long file::size() const {
@ -213,7 +213,7 @@ long long file::size() const {
if (size_lower == INVALID_FILE_SIZE) { if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError(); DWORD error = GetLastError();
if (error != NO_ERROR) if (error != NO_ERROR)
FMT_THROW(windows_error(GetLastError(), "cannot get file size")); FMT_ERROR(Error_type::windows_error, GetLastError(), "cannot get file size");
} }
unsigned long long long_size = size_upper; unsigned long long long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
@ -221,7 +221,7 @@ long long file::size() const {
using Stat = struct stat; using Stat = struct stat;
Stat file_stat = Stat(); Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
FMT_THROW(system_error(errno, "cannot get file attributes")); FMT_ERROR(Error_type::system_error, errno, "cannot get file attributes");
static_assert(sizeof(long long) >= sizeof(file_stat.st_size), static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
"return type of file::size is not large enough"); "return type of file::size is not large enough");
return file_stat.st_size; return file_stat.st_size;
@ -231,14 +231,14 @@ long long file::size() const {
std::size_t file::read(void* buffer, std::size_t count) { std::size_t file::read(void* buffer, std::size_t count) {
RWResult result = 0; RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file")); if (result < 0) FMT_ERROR(Error_type::system_error, errno, "cannot read from file");
return detail::to_unsigned(result); return detail::to_unsigned(result);
} }
std::size_t file::write(const void* buffer, std::size_t count) { std::size_t file::write(const void* buffer, std::size_t count) {
RWResult result = 0; RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file")); if (result < 0) FMT_ERROR(Error_type::system_error, errno, "cannot write to file");
return detail::to_unsigned(result); return detail::to_unsigned(result);
} }
@ -247,7 +247,7 @@ file file::dup(int fd) {
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd)); int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1) if (new_fd == -1)
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd)); FMT_ERROR(Error_type::system_error, errno, "cannot duplicate file descriptor {}", fd);
return file(new_fd); return file(new_fd);
} }
@ -255,8 +255,8 @@ void file::dup2(int fd) {
int result = 0; int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) { if (result == -1) {
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}", FMT_ERROR(Error_type::system_error, errno, "cannot duplicate file descriptor {} to {}",
fd_, fd)); fd_, fd);
} }
} }
@ -281,7 +281,7 @@ void file::pipe(file& read_end, file& write_end) {
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds)); int result = FMT_POSIX_CALL(pipe(fds));
# endif # endif
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe")); if (result != 0) FMT_ERROR(Error_type::system_error, errno, "cannot create pipe");
// The following assignments don't throw because read_fd and write_fd // The following assignments don't throw because read_fd and write_fd
// are closed. // are closed.
read_end = file(fds[0]); read_end = file(fds[0]);
@ -296,8 +296,8 @@ buffered_file file::fdopen(const char* mode) {
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
# endif # endif
if (!f) if (!f)
FMT_THROW( FMT_ERROR(
system_error(errno, "cannot associate stream with file descriptor")); Error_type::system_error, errno, "cannot associate stream with file descriptor");
buffered_file bf(f); buffered_file bf(f);
fd_ = -1; fd_ = -1;
return bf; return bf;
@ -310,7 +310,7 @@ long getpagesize() {
return si.dwPageSize; return si.dwPageSize;
# else # else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size")); if (size < 0) FMT_ERROR(Error_type::system_error, errno, "cannot get memory page size");
return size; return size;
# endif # endif
} }