Add ThrowCError to throw an exception on C library errors.

This commit is contained in:
Victor Zverovich 2014-04-30 10:18:11 -07:00
parent 2c6372d790
commit f79398699b
3 changed files with 55 additions and 13 deletions

View File

@ -260,6 +260,7 @@ TEST(UtilTest, StrError) {
message = StrError(-1, buffer, BUFFER_SIZE); message = StrError(-1, buffer, BUFFER_SIZE);
EXPECT_EQ(0, errno); EXPECT_EQ(0, errno);
EXPECT_GE(BUFFER_SIZE - 1, std::strlen(message)); EXPECT_GE(BUFFER_SIZE - 1, std::strlen(message));
EXPECT_STREQ(strerror(-1), message);
message = StrError(-1, buffer, std::strlen(message)); message = StrError(-1, buffer, std::strlen(message));
EXPECT_EQ(ERANGE, errno); EXPECT_EQ(ERANGE, errno);
} }

View File

@ -224,19 +224,13 @@ char *fmt::internal::StrError(
#endif #endif
} }
void fmt::internal::FormatSystemErrorMessage( void fmt::internal::FormatCErrorMessage(
fmt::Writer &out, int error_code, fmt::StringRef message) { fmt::Writer &out, int error_code, fmt::StringRef message) {
#ifndef _WIN32
Array<char, INLINE_BUFFER_SIZE> buffer; Array<char, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE); buffer.resize(INLINE_BUFFER_SIZE);
char *system_message = 0; char *system_message = 0;
for (;;) { for (;;) {
errno = 0; system_message = StrError(error_code, &buffer[0], buffer.size());
# ifdef _GNU_SOURCE
system_message = strerror_r(error_code, &buffer[0], buffer.size());
# else
strerror_r(error_code, system_message = &buffer[0], buffer.size());
# endif
if (errno == 0) if (errno == 0)
break; break;
if (errno != ERANGE) { if (errno != ERANGE) {
@ -247,6 +241,12 @@ void fmt::internal::FormatSystemErrorMessage(
buffer.resize(buffer.size() * 2); buffer.resize(buffer.size() * 2);
} }
out << message << ": " << system_message; out << message << ": " << system_message;
}
void fmt::internal::FormatSystemErrorMessage(
fmt::Writer &out, int error_code, fmt::StringRef message) {
#ifndef _WIN32
FormatCErrorMessage(out, error_code, message);
#else #else
class String { class String {
private: private:
@ -806,6 +806,12 @@ void fmt::SystemErrorSink::operator()(const fmt::Writer &w) const {
throw SystemError(message.c_str(), error_code_); throw SystemError(message.c_str(), error_code_);
} }
void fmt::CErrorSink::operator()(const Writer &w) const {
Writer message;
internal::FormatCErrorMessage(message, error_code_, w.c_str());
throw SystemError(message.c_str(), error_code_);
}
void fmt::ANSITerminalSink::operator()( void fmt::ANSITerminalSink::operator()(
const fmt::BasicWriter<char> &w) const { const fmt::BasicWriter<char> &w) const {
char escape[] = "\x1b[30m"; char escape[] = "\x1b[30m";

View File

@ -499,6 +499,9 @@ class UTF16ToUTF8 {
// Buffer should be at least of size 1. // Buffer should be at least of size 1.
char *StrError(int error_code, char *buffer, std::size_t buffer_size); char *StrError(int error_code, char *buffer, std::size_t buffer_size);
// Formats a standard C library error message writing the output to out.
void FormatCErrorMessage(Writer &out, int error_code, StringRef message);
// Formats a system error message writing the output to out. // Formats a system error message writing the output to out.
void FormatSystemErrorMessage(Writer &out, int error_code, StringRef message); void FormatSystemErrorMessage(Writer &out, int error_code, StringRef message);
@ -1520,7 +1523,7 @@ class Formatter : private Sink, public BasicFormatter<Char> {
See also `Format String Syntax`_. See also `Format String Syntax`_.
\endrst \endrst
*/ */
inline Formatter<> Format(StringRef format) { inline Formatter<> Format(StringRef format) {
Formatter<> f(format); Formatter<> f(format);
return f; return f;
@ -1532,7 +1535,7 @@ inline Formatter<NullSink, wchar_t> Format(WStringRef format) {
} }
/** /**
A sink that gets the system error message corresponding to the error code A sink that gets the error message corresponding to a system error code
and throws SystemError. and throws SystemError.
*/ */
class SystemErrorSink { class SystemErrorSink {
@ -1545,13 +1548,45 @@ class SystemErrorSink {
void operator()(const Writer &w) const; void operator()(const Writer &w) const;
}; };
/** Throws SystemError with a code and a formatted message. */ /**
Formats a message and throws SystemError with the description of the form
"<message>: <system-message>", where <message> is the formatted message and
<system-message> is the system message corresponding to the error code.
error_code is a system error code as given by errno for POSIX and
GetLastError for Windows.
*/
inline Formatter<SystemErrorSink> ThrowSystemError( inline Formatter<SystemErrorSink> ThrowSystemError(
int error_code, StringRef format = 0) { int error_code, StringRef format) {
Formatter<SystemErrorSink> f(format, SystemErrorSink(error_code)); Formatter<SystemErrorSink> f(format, SystemErrorSink(error_code));
return f; return f;
} }
/**
A sink that gets the error message corresponding to a standard C library
error code as given by errno and throws SystemError.
*/
class CErrorSink {
private:
int error_code_;
public:
explicit CErrorSink(int error_code) : error_code_(error_code) {}
void operator()(const Writer &w) const;
};
/**
Formats a message and throws SystemError with the description of the form
"<message>: <system-message>", where <message> is the formatted message and
<system-message> is the system message corresponding to the error code.
error_code is an error code as given by errno after calling a C library
function.
*/
inline Formatter<CErrorSink> ThrowCError(int error_code, StringRef format) {
Formatter<CErrorSink> f(format, CErrorSink(error_code));
return f;
}
/** A sink that writes output to a file. */ /** A sink that writes output to a file. */
class FileSink { class FileSink {
private: private:
@ -1563,7 +1598,7 @@ class FileSink {
/** Writes the output to a file. */ /** Writes the output to a file. */
void operator()(const BasicWriter<char> &w) const { void operator()(const BasicWriter<char> &w) const {
if (std::fwrite(w.data(), w.size(), 1, file_) == 0) if (std::fwrite(w.data(), w.size(), 1, file_) == 0)
ThrowSystemError(errno, "cannot write to file"); ThrowCError(errno, "cannot write to file");
} }
}; };