Move safe_strerror to anonymous namespace.

This commit is contained in:
Victor Zverovich 2014-09-05 08:44:41 -07:00
parent b33d2aa825
commit f2c9df8e9f
6 changed files with 90 additions and 86 deletions

View File

@ -138,6 +138,43 @@ const char RESET_COLOR[] = "\x1b[0m";
typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef); typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
assert(buffer != 0 && buffer_size != 0);
int result = 0;
#ifdef _GNU_SOURCE
char *message = strerror_r(error_code, buffer, buffer_size);
// If the buffer is full then the message is probably truncated.
if (message == buffer && strlen(buffer) == buffer_size - 1)
result = ERANGE;
buffer = message;
#elif __MINGW32__
errno = 0;
(void)buffer_size;
buffer = strerror(error_code);
result = errno;
#elif _WIN32
result = strerror_s(buffer, buffer_size, error_code);
// If the buffer is full then the message is probably truncated.
if (result == 0 && std::strlen(buffer) == buffer_size - 1)
result = ERANGE;
#else
result = strerror_r(error_code, buffer, buffer_size);
if (result == -1)
result = errno; // glibc versions before 2.13 return result in errno.
#endif
return result;
}
void format_error_code(fmt::Writer &out, int error_code, void format_error_code(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT(true) { fmt::StringRef message) FMT_NOEXCEPT(true) {
// Report error code making sure that the output fits into // Report error code making sure that the output fits into
@ -442,34 +479,6 @@ void fmt::WindowsError::init(
#endif #endif
int fmt::internal::safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
assert(buffer != 0 && buffer_size != 0);
int result = 0;
#ifdef _GNU_SOURCE
char *message = strerror_r(error_code, buffer, buffer_size);
// If the buffer is full then the message is probably truncated.
if (message == buffer && strlen(buffer) == buffer_size - 1)
result = ERANGE;
buffer = message;
#elif __MINGW32__
errno = 0;
(void)buffer_size;
buffer = strerror(error_code);
result = errno;
#elif _WIN32
result = strerror_s(buffer, buffer_size, error_code);
// If the buffer is full then the message is probably truncated.
if (result == 0 && std::strlen(buffer) == buffer_size - 1)
result = ERANGE;
#else
result = strerror_r(error_code, buffer, buffer_size);
if (result == -1)
result = errno; // glibc versions before 2.13 return result in errno.
#endif
return result;
}
void fmt::internal::format_system_error( void fmt::internal::format_system_error(
fmt::Writer &out, int error_code, fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT(true) { fmt::StringRef message) FMT_NOEXCEPT(true) {

View File

@ -534,18 +534,6 @@ class UTF16ToUTF8 {
}; };
#endif #endif
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(int error_code,
char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true);
void format_system_error(fmt::Writer &out, int error_code, void format_system_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT(true); fmt::StringRef message) FMT_NOEXCEPT(true);

View File

@ -27,7 +27,11 @@
// Include format.cc instead of format.h to test implementation-specific stuff. // Include format.cc instead of format.h to test implementation-specific stuff.
#include "format.cc" #include "format.cc"
#include <cstring>
#include "gtest-extra.h" #include "gtest-extra.h"
#include "util.h"
#undef max #undef max
@ -48,6 +52,39 @@ TEST(FormatTest, FormatNegativeNaN) {
fmt::print("Warning: compiler doesn't handle negative NaN correctly"); fmt::print("Warning: compiler doesn't handle negative NaN correctly");
} }
TEST(FormatTest, StrError) {
char *message = 0;
char buffer[BUFFER_SIZE];
#ifndef NDEBUG
EXPECT_DEBUG_DEATH(safe_strerror(EDOM, message = 0, 0), "Assertion");
EXPECT_DEBUG_DEATH(safe_strerror(EDOM, message = buffer, 0), "Assertion");
#endif
buffer[0] = 'x';
#ifdef _GNU_SOURCE
// Use invalid error code to make sure that safe_strerror returns an error
// message in the buffer rather than a pointer to a static string.
int error_code = -1;
#else
int error_code = EDOM;
#endif
int result = safe_strerror(error_code, message = buffer, BUFFER_SIZE);
EXPECT_EQ(0, result);
std::size_t message_size = std::strlen(message);
EXPECT_GE(BUFFER_SIZE - 1u, message_size);
EXPECT_EQ(get_system_error(error_code), message);
// safe_strerror never uses buffer on MinGW.
#ifndef __MINGW32__
result = safe_strerror(error_code, message = buffer, message_size);
EXPECT_EQ(ERANGE, result);
result = safe_strerror(error_code, message = buffer, 1);
EXPECT_EQ(buffer, message); // Message should point to buffer.
EXPECT_EQ(ERANGE, result);
EXPECT_STREQ("", message);
#endif
}
TEST(FormatTest, FormatErrorCode) { TEST(FormatTest, FormatErrorCode) {
std::string msg = "error 42", sep = ": "; std::string msg = "error 42", sep = ": ";
{ {

View File

@ -46,18 +46,6 @@ using fmt::internal::Arg;
using fmt::internal::MakeArg; using fmt::internal::MakeArg;
namespace { namespace {
std::string get_system_error(int error_code) {
#if defined(__MINGW32__) || !defined(_WIN32)
return strerror(error_code);
#else
enum { BUFFER_SIZE = 200 };
char buffer[BUFFER_SIZE];
EXPECT_EQ(0, strerror_s(buffer, BUFFER_SIZE, error_code));
std::size_t max_len = BUFFER_SIZE - 1;
EXPECT_LT(std::strlen(buffer), max_len);
return buffer;
#endif
}
struct Test {}; struct Test {};
template <typename Char> template <typename Char>
@ -417,40 +405,6 @@ TEST(UtilTest, UTF16ToUTF8Convert) {
} }
#endif // _WIN32 #endif // _WIN32
TEST(UtilTest, StrError) {
using fmt::internal::safe_strerror;
char *message = 0;
char buffer[BUFFER_SIZE];
#ifndef NDEBUG
EXPECT_DEBUG_DEATH(safe_strerror(EDOM, message = 0, 0), "Assertion");
EXPECT_DEBUG_DEATH(safe_strerror(EDOM, message = buffer, 0), "Assertion");
#endif
buffer[0] = 'x';
#ifdef _GNU_SOURCE
// Use invalid error code to make sure that safe_strerror returns an error
// message in the buffer rather than a pointer to a static string.
int error_code = -1;
#else
int error_code = EDOM;
#endif
int result = safe_strerror(error_code, message = buffer, BUFFER_SIZE);
EXPECT_EQ(0, result);
std::size_t message_size = std::strlen(message);
EXPECT_GE(BUFFER_SIZE - 1u, message_size);
EXPECT_EQ(get_system_error(error_code), message);
// safe_strerror never uses buffer on MinGW.
#ifndef __MINGW32__
result = safe_strerror(error_code, message = buffer, message_size);
EXPECT_EQ(ERANGE, result);
result = safe_strerror(error_code, message = buffer, 1);
EXPECT_EQ(buffer, message); // Message should point to buffer.
EXPECT_EQ(ERANGE, result);
EXPECT_STREQ("", message);
#endif
}
typedef void (*FormatErrorMessage)( typedef void (*FormatErrorMessage)(
fmt::Writer &out, int error_code, StringRef message); fmt::Writer &out, int error_code, StringRef message);

View File

@ -37,3 +37,16 @@ void increment(char *s) {
s[i] = '0'; s[i] = '0';
} }
} }
std::string get_system_error(int error_code) {
#if defined(__MINGW32__) || !defined(_WIN32)
return strerror(error_code);
#else
enum { BUFFER_SIZE = 200 };
char buffer[BUFFER_SIZE];
EXPECT_EQ(0, strerror_s(buffer, BUFFER_SIZE, error_code));
std::size_t max_len = BUFFER_SIZE - 1;
EXPECT_LT(std::strlen(buffer), max_len);
return buffer;
#endif
}

View File

@ -27,6 +27,7 @@
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <string>
enum {BUFFER_SIZE = 256}; enum {BUFFER_SIZE = 256};
@ -46,3 +47,5 @@ void safe_sprintf(char (&buffer)[SIZE], const char *format, ...) {
// Increment a number in a string. // Increment a number in a string.
void increment(char *s); void increment(char *s);
std::string get_system_error(int error_code);