Merge a5231b86df into d16c4d20f8
This commit is contained in:
commit
be18e51fca
@ -192,7 +192,9 @@ The following functions use `printf format string syntax
|
|||||||
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
|
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
|
||||||
the POSIX extension for positional arguments. Unlike their standard
|
the POSIX extension for positional arguments. Unlike their standard
|
||||||
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
||||||
argument type doesn't match its format specification.
|
argument type doesn't match its format specification. They also support the
|
||||||
|
glibc '%m' extension to output the string corresponding to the error code
|
||||||
|
in errno.
|
||||||
|
|
||||||
.. doxygenfunction:: printf(CStringRef, ArgList)
|
.. doxygenfunction:: printf(CStringRef, ArgList)
|
||||||
|
|
||||||
|
|||||||
@ -385,7 +385,10 @@ FMT_FUNC void format_system_error(
|
|||||||
char *system_message = &buffer[0];
|
char *system_message = &buffer[0];
|
||||||
int result = safe_strerror(error_code, system_message, buffer.size());
|
int result = safe_strerror(error_code, system_message, buffer.size());
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
out << message << ": " << system_message;
|
if (message.size())
|
||||||
|
out << message << ": " << system_message;
|
||||||
|
else
|
||||||
|
out << system_message;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result != ERANGE)
|
if (result != ERANGE)
|
||||||
|
|||||||
28
fmt/printf.h
28
fmt/printf.h
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <algorithm> // std::fill_n
|
#include <algorithm> // std::fill_n
|
||||||
#include <limits> // std::numeric_limits
|
#include <limits> // std::numeric_limits
|
||||||
|
#include <cerrno> // errno
|
||||||
|
|
||||||
#include "ostream.h"
|
#include "ostream.h"
|
||||||
|
|
||||||
@ -197,6 +198,18 @@ class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
|
|||||||
return static_cast<unsigned>(width);
|
return static_cast<unsigned>(width);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ErrnoPreserver {
|
||||||
|
const int saved_errno_;
|
||||||
|
public:
|
||||||
|
ErrnoPreserver() : saved_errno_(errno) {}
|
||||||
|
~ErrnoPreserver() {
|
||||||
|
errno = saved_errno_;
|
||||||
|
}
|
||||||
|
int get() const {
|
||||||
|
return saved_errno_;
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -431,6 +444,21 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
|
|||||||
// Parse argument index, flags and width.
|
// Parse argument index, flags and width.
|
||||||
unsigned arg_index = parse_header(s, spec);
|
unsigned arg_index = parse_header(s, spec);
|
||||||
|
|
||||||
|
if (*s == 'm') {
|
||||||
|
// Something in here is changing errno in the mingw build. We
|
||||||
|
// ought to preserve it anyway, even if an exception is thrown.
|
||||||
|
internal::ErrnoPreserver errno_preserver;
|
||||||
|
|
||||||
|
// This dance is necessary because this function is templated on
|
||||||
|
// the character type but format_system_error is not.
|
||||||
|
MemoryWriter char_writer;
|
||||||
|
format_system_error(char_writer, errno_preserver.get(), "");
|
||||||
|
AF(writer_, spec).visit_cstring(char_writer.c_str());
|
||||||
|
|
||||||
|
start = ++s;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse precision.
|
// Parse precision.
|
||||||
if (*s == '.') {
|
if (*s == '.') {
|
||||||
++s;
|
++s;
|
||||||
|
|||||||
@ -1105,7 +1105,7 @@ template <typename T>
|
|||||||
void check_unknown_types(
|
void check_unknown_types(
|
||||||
const T &value, const char *types, const char *type_name) {
|
const T &value, const char *types, const char *type_name) {
|
||||||
char format_str[BUFFER_SIZE], message[BUFFER_SIZE];
|
char format_str[BUFFER_SIZE], message[BUFFER_SIZE];
|
||||||
const char *special = ".0123456789}";
|
const char *special = ".0123456789}m";
|
||||||
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
|
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
|
||||||
char c = static_cast<char>(i);
|
char c = static_cast<char>(i);
|
||||||
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
|
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
|
||||||
|
|||||||
@ -51,6 +51,10 @@ std::string make_positional(fmt::StringRef format) {
|
|||||||
<< "format: " << format; \
|
<< "format: " << format; \
|
||||||
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
|
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
|
||||||
|
|
||||||
|
#define EXPECT_PRINTF_NO_ARG(expected_output, format) \
|
||||||
|
EXPECT_EQ(expected_output, fmt::sprintf(format)) \
|
||||||
|
<< "format: " << format;
|
||||||
|
|
||||||
TEST(PrintfTest, NoArgs) {
|
TEST(PrintfTest, NoArgs) {
|
||||||
EXPECT_EQ("test", fmt::sprintf("test"));
|
EXPECT_EQ("test", fmt::sprintf("test"));
|
||||||
}
|
}
|
||||||
@ -472,6 +476,33 @@ TEST(PrintfTest, Enum) {
|
|||||||
EXPECT_PRINTF("42", "%d", A);
|
EXPECT_PRINTF("42", "%d", A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, ErrnoPreserved) {
|
||||||
|
errno = ENOENT;
|
||||||
|
EXPECT_PRINTF_NO_ARG("testing 1 2 3", "testing 1 2 3");
|
||||||
|
EXPECT_EQ(errno, ENOENT);
|
||||||
|
|
||||||
|
EXPECT_PRINTF("42", "%d", 42);
|
||||||
|
EXPECT_EQ(errno, ENOENT);
|
||||||
|
|
||||||
|
EXPECT_PRINTF(" Hello", "%6s", "Hello");
|
||||||
|
EXPECT_EQ(errno, ENOENT);
|
||||||
|
|
||||||
|
EXPECT_PRINTF_NO_ARG("No such file or directory", "%m");
|
||||||
|
EXPECT_EQ(errno, ENOENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, ErrorMessage) {
|
||||||
|
errno = ENOENT;
|
||||||
|
|
||||||
|
EXPECT_PRINTF_NO_ARG("No such file or directory", "%m");
|
||||||
|
EXPECT_PRINTF_NO_ARG("No such file or directory ", "%-30m");
|
||||||
|
EXPECT_PRINTF_NO_ARG(" No such file or directory", "%30m");
|
||||||
|
|
||||||
|
EXPECT_PRINTF_NO_ARG(L"No such file or directory", L"%m");
|
||||||
|
EXPECT_PRINTF_NO_ARG(L"No such file or directory ", L"%-30m");
|
||||||
|
EXPECT_PRINTF_NO_ARG(L" No such file or directory", L"%30m");
|
||||||
|
}
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FILE_DESCRIPTORS
|
||||||
TEST(PrintfTest, Examples) {
|
TEST(PrintfTest, Examples) {
|
||||||
const char *weekday = "Thursday";
|
const char *weekday = "Thursday";
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user