Commit d142f135 authored by gabime's avatar gabime

Updated fmto to version def687462c32ec40757e49eb6069f109d50236d6

parent e12916c0
/* /*
Formatting library for C++ Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this 1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, 2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
// commented out by spdlog #include "format.h"
// #include "format.h"
// #include "printf.h" #include <string.h>
#include <string.h> #include <cctype>
#include <cerrno>
#include <cctype> #include <climits>
#include <cerrno> #include <cmath>
#include <climits> #include <cstdarg>
#include <cmath> #include <cstddef> // for std::ptrdiff_t
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t #if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
#if defined(_WIN32) && defined(__MINGW32__) #endif
# include <cstring>
#endif #if FMT_USE_WINDOWS_H
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
#if FMT_USE_WINDOWS_H # include <windows.h>
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) # else
# include <windows.h> # define NOMINMAX
# else # include <windows.h>
# define NOMINMAX # undef NOMINMAX
# include <windows.h> # endif
# undef NOMINMAX #endif
# endif
#endif using fmt::internal::Arg;
using fmt::internal::Arg; #if FMT_EXCEPTIONS
# define FMT_TRY try
#if FMT_EXCEPTIONS # define FMT_CATCH(x) catch (x)
# define FMT_TRY try #else
# define FMT_CATCH(x) catch (x) # define FMT_TRY if (true)
#else # define FMT_CATCH(x) if (false)
# define FMT_TRY if (true) #endif
# define FMT_CATCH(x) if (false)
#endif #ifdef _MSC_VER
# pragma warning(push)
#ifdef _MSC_VER # pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(push) # pragma warning(disable: 4702) // unreachable code
# pragma warning(disable: 4127) // conditional expression is constant // Disable deprecation warning for strerror. The latter is not called but
# pragma warning(disable: 4702) // unreachable code // MSVC fails to detect it.
// Disable deprecation warning for strerror. The latter is not called but # pragma warning(disable: 4996)
// MSVC fails to detect it. #endif
# pragma warning(disable: 4996)
#endif // Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
// Dummy implementations of strerror_r and strerror_s called if corresponding static inline fmt::internal::Null<> strerror_r(int, char *, ...)
// system functions are not available. {
static inline fmt::internal::Null<> strerror_r(int, char *, ...) { return fmt::internal::Null<>();
return fmt::internal::Null<>(); }
} static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...)
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { {
return fmt::internal::Null<>(); return fmt::internal::Null<>();
} }
namespace fmt { namespace fmt {
FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT
FMT_FUNC FormatError::~FormatError() throw() {} {}
FMT_FUNC SystemError::~SystemError() throw() {} FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT
{}
namespace { FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT
{}
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf namespace {
#else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { #ifndef _MSC_VER
va_list args; # define FMT_SNPRINTF snprintf
va_start(args, format); #else // _MSC_VER
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...)
va_end(args); {
return result; va_list args;
} va_start(args, format);
# define FMT_SNPRINTF fmt_snprintf int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
#endif // _MSC_VER va_end(args);
return result;
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) }
# define FMT_SWPRINTF snwprintf # define FMT_SNPRINTF fmt_snprintf
#else #endif // _MSC_VER
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
const char RESET_COLOR[] = "\x1b[0m"; #else
# define FMT_SWPRINTF swprintf
typedef void(*FormatFunc)(Writer &, int, StringRef); #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
// Portable thread-safe version of strerror. const char RESET_COLOR[] = "\x1b[0m";
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer, typedef void(*FormatFunc)(Writer &, int, StringRef);
// or a pointer to some static immutable string.
// Returns one of the following values: // Portable thread-safe version of strerror.
// 0 - success // Sets buffer to point to a string describing the error code.
// ERANGE - buffer is not large enough to store the error message // This can be either a pointer to a string stored in buffer,
// other - failure // or a pointer to some static immutable string.
// Buffer should be at least of size 1. // Returns one of the following values:
int safe_strerror( // 0 - success
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{ // ERANGE - buffer is not large enough to store the error message
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); // other - failure
// Buffer should be at least of size 1.
class StrError { int safe_strerror(
private: int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT
int error_code_; {
char *&buffer_; FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
std::size_t buffer_size_;
class StrError
// A noop assignment operator to avoid bogus warnings. {
void operator=(const StrError &) {} private:
int error_code_;
// Handle the result of XSI-compliant version of strerror_r. char *&buffer_;
int handle(int result) { std::size_t buffer_size_;
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result; // A noop assignment operator to avoid bogus warnings.
} void operator=(const StrError &)
{}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message) { // Handle the result of XSI-compliant version of strerror_r.
// If the buffer is full then the message is probably truncated. int handle(int result)
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) {
return ERANGE; // glibc versions before 2.13 return result in errno.
buffer_ = message; return result == -1 ? errno : result;
return 0; }
}
// Handle the result of GNU-specific version of strerror_r.
// Handle the case when strerror_r is not available. int handle(char *message)
int handle(internal::Null<>) { {
return fallback(strerror_s(buffer_, buffer_size_, error_code_)); // If the buffer is full then the message is probably truncated.
} if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
// Fallback to strerror_s when strerror_r is not available. buffer_ = message;
int fallback(int result) { return 0;
// If the buffer is full then the message is probably truncated. }
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result; // Handle the case when strerror_r is not available.
} int handle(internal::Null<>)
{
// Fallback to strerror if strerror_r and strerror_s are not available. return fallback(strerror_s(buffer_, buffer_size_, error_code_));
int fallback(internal::Null<>) { }
errno = 0;
buffer_ = strerror(error_code_); // Fallback to strerror_s when strerror_r is not available.
return errno; int fallback(int result)
} {
// If the buffer is full then the message is probably truncated.
public: return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
StrError(int err_code, char *&buf, std::size_t buf_size) ERANGE : result;
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} }
int run() { // Fallback to strerror if strerror_r and strerror_s are not available.
strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. int fallback(internal::Null<>)
return handle(strerror_r(error_code_, buffer_, buffer_size_)); {
} errno = 0;
}; buffer_ = strerror(error_code_);
return StrError(error_code, buffer, buffer_size).run(); return errno;
} }
void format_error_code(Writer &out, int error_code, public:
StringRef message) FMT_NOEXCEPT{ StrError(int err_code, char *&buf, std::size_t buf_size)
// Report error code making sure that the output fits into : error_code_(err_code), buffer_(buf), buffer_size_(buf_size)
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential {}
// bad_alloc.
out.clear(); int run()
static const char SEP[] = ": "; {
static const char ERROR_STR[] = "error "; // Suppress a warning about unused strerror_r.
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR. strerror_r(0, FMT_NULL, "");
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; return handle(strerror_r(error_code_, buffer_, buffer_size_));
typedef internal::IntTraits<int>::MainType MainType; }
MainType abs_value = static_cast<MainType>(error_code); };
if (internal::is_negative(error_code)) { return StrError(error_code, buffer, buffer_size).run();
abs_value = 0 - abs_value; }
++error_code_size;
} void format_error_code(Writer &out, int error_code,
error_code_size += internal::count_digits(abs_value); StringRef message) FMT_NOEXCEPT
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
out << message << SEP; // Report error code making sure that the output fits into
out << ERROR_STR << error_code; // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
assert(out.size() <= internal::INLINE_BUFFER_SIZE); // bad_alloc.
} out.clear();
static const char SEP[] = ": ";
void report_error(FormatFunc func, int error_code, static const char ERROR_STR[] = "error ";
StringRef message) FMT_NOEXCEPT{ // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
MemoryWriter full_message; std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
func(full_message, error_code, message); typedef internal::IntTraits<int>::MainType MainType;
// Use Writer::data instead of Writer::c_str to avoid potential memory MainType abs_value = static_cast<MainType>(error_code);
// allocation. if (internal::is_negative(error_code)) {
std::fwrite(full_message.data(), full_message.size(), 1, stderr); abs_value = 0 - abs_value;
std::fputc('\n', stderr); ++error_code_size;
} }
} // namespace error_code_size += internal::count_digits(abs_value);
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
namespace internal { out << message << SEP;
out << ERROR_STR << error_code;
// This method is used to preserve binary compatibility with fmt 3.0. assert(out.size() <= internal::INLINE_BUFFER_SIZE);
// It can be removed in 4.0. }
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{ void report_error(FormatFunc func, int error_code,
fmt::format_system_error(out, error_code, message); StringRef message) FMT_NOEXCEPT
} {
} // namespace internal MemoryWriter full_message;
func(full_message, error_code, message);
FMT_FUNC void SystemError::init( // Use Writer::data instead of Writer::c_str to avoid potential memory
int err_code, CStringRef format_str, ArgList args) { // allocation.
error_code_ = err_code; std::fwrite(full_message.data(), full_message.size(), 1, stderr);
MemoryWriter w; std::fputc('\n', stderr);
format_system_error(w, err_code, format(format_str, args)); }
std::runtime_error &base = *this; } // namespace
base = std::runtime_error(w.str());
} namespace internal {
template <typename T> // This method is used to preserve binary compatibility with fmt 3.0.
int internal::CharTraits<char>::format_float( // It can be removed in 4.0.
char *buffer, std::size_t size, const char *format, FMT_FUNC void format_system_error(
unsigned width, int precision, T value) { Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
if (width == 0) { {
return precision < 0 ? fmt::format_system_error(out, error_code, message);
FMT_SNPRINTF(buffer, size, format, value) : }
FMT_SNPRINTF(buffer, size, format, precision, value); } // namespace internal
}
return precision < 0 ? FMT_FUNC void SystemError::init(
FMT_SNPRINTF(buffer, size, format, width, value) : int err_code, CStringRef format_str, ArgList args)
FMT_SNPRINTF(buffer, size, format, width, precision, value); {
} error_code_ = err_code;
MemoryWriter w;
template <typename T> format_system_error(w, err_code, format(format_str, args));
int internal::CharTraits<wchar_t>::format_float( std::runtime_error &base = *this;
wchar_t *buffer, std::size_t size, const wchar_t *format, base = std::runtime_error(w.str());
unsigned width, int precision, T value) { }
if (width == 0) {
return precision < 0 ? template <typename T>
FMT_SWPRINTF(buffer, size, format, value) : int internal::CharTraits<char>::format_float(
FMT_SWPRINTF(buffer, size, format, precision, value); char *buffer, std::size_t size, const char *format,
} unsigned width, int precision, T value)
return precision < 0 ? {
FMT_SWPRINTF(buffer, size, format, width, value) : if (width == 0) {
FMT_SWPRINTF(buffer, size, format, width, precision, value); return precision < 0 ?
} FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
template <typename T> }
const char internal::BasicData<T>::DIGITS[] = return precision < 0 ?
"0001020304050607080910111213141516171819" FMT_SNPRINTF(buffer, size, format, width, value) :
"2021222324252627282930313233343536373839" FMT_SNPRINTF(buffer, size, format, width, precision, value);
"4041424344454647484950515253545556575859" }
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899"; template <typename T>
int internal::CharTraits<wchar_t>::format_float(
#define FMT_POWERS_OF_10(factor) \ wchar_t *buffer, std::size_t size, const wchar_t *format,
factor * 10, \ unsigned width, int precision, T value)
factor * 100, \ {
factor * 1000, \ if (width == 0) {
factor * 10000, \ return precision < 0 ?
factor * 100000, \ FMT_SWPRINTF(buffer, size, format, value) :
factor * 1000000, \ FMT_SWPRINTF(buffer, size, format, precision, value);
factor * 10000000, \ }
factor * 100000000, \ return precision < 0 ?
factor * 1000000000 FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
template <typename T> }
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1) template <typename T>
}; const char internal::BasicData<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
template <typename T> "2021222324252627282930313233343536373839"
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = { "4041424344454647484950515253545556575859"
0, "6061626364656667686970717273747576777879"
FMT_POWERS_OF_10(1), "8081828384858687888990919293949596979899";
FMT_POWERS_OF_10(ULongLong(1000000000)),
// Multiply several constants instead of using a single long long constant #define FMT_POWERS_OF_10(factor) \
// to avoid warnings about C++98 not supporting long long. factor * 10, \
ULongLong(1000000000) * ULongLong(1000000000) * 10 factor * 100, \
}; factor * 1000, \
factor * 10000, \
FMT_FUNC void internal::report_unknown_type(char code, const char *type) { factor * 100000, \
(void)type; factor * 1000000, \
if (std::isprint(static_cast<unsigned char>(code))) { factor * 10000000, \
FMT_THROW(FormatError( factor * 100000000, \
format("unknown format code '{}' for {}", code, type))); factor * 1000000000
}
FMT_THROW(FormatError( template <typename T>
format("unknown format code '\\x{:02x}' for {}", const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
static_cast<unsigned>(code), type))); 0, FMT_POWERS_OF_10(1)
} };
#if FMT_USE_WINDOWS_H template <typename T>
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { 0,
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; FMT_POWERS_OF_10(1),
if (s.size() > INT_MAX) FMT_POWERS_OF_10(ULongLong(1000000000)),
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); // Multiply several constants instead of using a single long long constant
int s_size = static_cast<int>(s.size()); // to avoid warnings about C++98 not supporting long long.
int length = MultiByteToWideChar( ULongLong(1000000000) * ULongLong(1000000000) * 10
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); };
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); FMT_FUNC void internal::report_unknown_type(char code, const char *type)
buffer_.resize(length + 1); {
length = MultiByteToWideChar( (void)type;
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); if (std::isprint(static_cast<unsigned char>(code))) {
if (length == 0) FMT_THROW(FormatError(
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); format("unknown format code '{}' for {}", code, type)));
buffer_[length] = 0; }
} FMT_THROW(FormatError(
format("unknown format code '\\x{:02x}' for {}",
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { static_cast<unsigned>(code), type)));
if (int error_code = convert(s)) { }
FMT_THROW(WindowsError(error_code,
"cannot convert string from UTF-16 to UTF-8")); #if FMT_USE_WINDOWS_H
}
} FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s)
{
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX) if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER; FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size()); int s_size = static_cast<int>(s.size());
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); int length = MultiByteToWideChar(
if (length == 0) CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
return GetLastError(); if (length == 0)
buffer_.resize(length + 1); FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
length = WideCharToMultiByte( buffer_.resize(length + 1);
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); length = MultiByteToWideChar(
if (length == 0) CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
return GetLastError(); if (length == 0)
buffer_[length] = 0; FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
return 0; buffer_[length] = 0;
} }
FMT_FUNC void WindowsError::init( FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s)
int err_code, CStringRef format_str, ArgList args) { {
error_code_ = err_code; if (int error_code = convert(s)) {
MemoryWriter w; FMT_THROW(WindowsError(error_code,
internal::format_windows_error(w, err_code, format(format_str, args)); "cannot convert string from UTF-16 to UTF-8"));
std::runtime_error &base = *this; }
base = std::runtime_error(w.str()); }
}
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s)
FMT_FUNC void internal::format_windows_error( {
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{ if (s.size() > INT_MAX)
FMT_TRY{ return ERROR_INVALID_PARAMETER;
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; int s_size = static_cast<int>(s.size());
buffer.resize(INLINE_BUFFER_SIZE); int length = WideCharToMultiByte(
for (;;) { CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
wchar_t *system_message = &buffer[0]; if (length == 0)
int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, return GetLastError();
0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer_.resize(length + 1);
system_message, static_cast<uint32_t>(buffer.size()), 0); length = WideCharToMultiByte(
if (result != 0) { CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
UTF16ToUTF8 utf8_message; if (length == 0)
if (utf8_message.convert(system_message) == ERROR_SUCCESS) { return GetLastError();
out << message << ": " << utf8_message; buffer_[length] = 0;
return; return 0;
} }
break;
} FMT_FUNC void WindowsError::init(
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) int err_code, CStringRef format_str, ArgList args)
break; // Can't get error message, report error code instead. {
buffer.resize(buffer.size() * 2); error_code_ = err_code;
} MemoryWriter w;
} FMT_CATCH(...) {} internal::format_windows_error(w, err_code, format(format_str, args));
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. std::runtime_error &base = *this;
} base = std::runtime_error(w.str());
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC void internal::format_windows_error(
FMT_FUNC void format_system_error( Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{ {
FMT_TRY{ FMT_TRY{
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer; MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
buffer.resize(internal::INLINE_BUFFER_SIZE); buffer.resize(INLINE_BUFFER_SIZE);
for (;;) { for (;;) {
char *system_message = &buffer[0]; wchar_t *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size()); int result = FormatMessageW(
if (result == 0) { FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
out << message << ": " << system_message; FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
return; system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
} if (result != 0) {
if (result != ERANGE) UTF16ToUTF8 utf8_message;
break; // Can't get error message, report error code instead. if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
buffer.resize(buffer.size() * 2); out << message << ": " << utf8_message;
} return;
} FMT_CATCH(...) {} }
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. break;
} }
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
template <typename Char> break; // Can't get error message, report error code instead.
void internal::ArgMap<Char>::init(const ArgList &args) { buffer.resize(buffer.size() * 2);
if (!map_.empty()) }
return; } FMT_CATCH(...)
typedef internal::NamedArg<Char> NamedArg; {}
const NamedArg *named_arg = 0; fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
bool use_values = }
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) { #endif // FMT_USE_WINDOWS_H
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i); FMT_FUNC void format_system_error(
switch (arg_type) { Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
case internal::Arg::NONE: {
return; FMT_TRY{
case internal::Arg::NAMED_ARG: internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); buffer.resize(internal::INLINE_BUFFER_SIZE);
map_.push_back(Pair(named_arg->name, *named_arg)); for (;;) {
break; char *system_message = &buffer[0];
default: int result = safe_strerror(error_code, system_message, buffer.size());
/*nothing*/ if (result == 0) {
; out << message << ": " << system_message;
} return;
} }
return; if (result != ERANGE)
} break; // Can't get error message, report error code instead.
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { buffer.resize(buffer.size() * 2);
internal::Arg::Type arg_type = args.type(i); }
if (arg_type == internal::Arg::NAMED_ARG) { } FMT_CATCH(...)
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); {}
map_.push_back(Pair(named_arg->name, *named_arg)); fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
} }
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { template <typename Char>
switch (args.args_[i].type) { void internal::ArgMap<Char>::init(const ArgList &args)
case internal::Arg::NONE: {
return; if (!map_.empty())
case internal::Arg::NAMED_ARG: return;
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); typedef internal::NamedArg<Char> NamedArg;
map_.push_back(Pair(named_arg->name, *named_arg)); const NamedArg *named_arg = FMT_NULL;
break; bool use_values =
default: args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
/*nothing*/ if (use_values) {
; for (unsigned i = 0;/*nothing*/; ++i) {
} internal::Arg::Type arg_type = args.type(i);
} switch (arg_type) {
} case internal::Arg::NONE:
return;
template <typename Char> case internal::Arg::NAMED_ARG:
void internal::FixedBuffer<Char>::grow(std::size_t) { named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
FMT_THROW(std::runtime_error("buffer overflow")); map_.push_back(Pair(named_arg->name, *named_arg));
} break;
default:
FMT_FUNC Arg internal::FormatterBase::do_get_arg( /*nothing*/;
unsigned arg_index, const char *&error) { }
Arg arg = args_[arg_index]; }
switch (arg.type) { return;
case Arg::NONE: }
error = "argument index out of range"; for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
break; internal::Arg::Type arg_type = args.type(i);
case Arg::NAMED_ARG: if (arg_type == internal::Arg::NAMED_ARG) {
arg = *static_cast<const internal::Arg*>(arg.pointer); named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
break; map_.push_back(Pair(named_arg->name, *named_arg));
default: }
/*nothing*/ }
; for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
} switch (args.args_[i].type) {
return arg; case internal::Arg::NONE:
} return;
case internal::Arg::NAMED_ARG:
FMT_FUNC void report_system_error( named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
int error_code, fmt::StringRef message) FMT_NOEXCEPT{ map_.push_back(Pair(named_arg->name, *named_arg));
// 'fmt::' is for bcc32. break;
report_error(format_system_error, error_code, message); default:
} /*nothing*/;
}
#if FMT_USE_WINDOWS_H }
FMT_FUNC void report_windows_error( }
int error_code, fmt::StringRef message) FMT_NOEXCEPT{
// 'fmt::' is for bcc32. template <typename Char>
report_error(internal::format_windows_error, error_code, message); void internal::FixedBuffer<Char>::grow(std::size_t)
} {
#endif FMT_THROW(std::runtime_error("buffer overflow"));
}
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
MemoryWriter w; FMT_FUNC Arg internal::FormatterBase::do_get_arg(
w.write(format_str, args); unsigned arg_index, const char *&error)
std::fwrite(w.data(), 1, w.size(), f); {
} Arg arg = args_[arg_index];
switch (arg.type) {
FMT_FUNC void print(CStringRef format_str, ArgList args) { case Arg::NONE:
print(stdout, format_str, args); error = "argument index out of range";
} break;
case Arg::NAMED_ARG:
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { arg = *static_cast<const internal::Arg*>(arg.pointer);
char escape[] = "\x1b[30m"; break;
escape[3] = static_cast<char>('0' + c); default:
std::fputs(escape, stdout); /*nothing*/;
print(format, args); }
std::fputs(RESET_COLOR, stdout); return arg;
} }
template <typename Char> FMT_FUNC void report_system_error(
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args); int error_code, fmt::StringRef message) FMT_NOEXCEPT
{
FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { // 'fmt::' is for bcc32.
MemoryWriter w; report_error(format_system_error, error_code, message);
printf(w, format, args); }
std::size_t size = w.size();
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); #if FMT_USE_WINDOWS_H
} FMT_FUNC void report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT
#ifndef FMT_HEADER_ONLY {
// 'fmt::' is for bcc32.
template struct internal::BasicData<void>; report_error(internal::format_windows_error, error_code, message);
}
// Explicit instantiations for char. #endif
template void internal::FixedBuffer<char>::grow(std::size_t); FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args)
{
template void internal::ArgMap<char>::init(const ArgList &args); MemoryWriter w;
w.write(format_str, args);
template void PrintfFormatter<char>::format(CStringRef format); std::fwrite(w.data(), 1, w.size(), f);
}
template int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format, FMT_FUNC void print(CStringRef format_str, ArgList args)
unsigned width, int precision, double value); {
print(stdout, format_str, args);
template int internal::CharTraits<char>::format_float( }
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value); FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args)
{
// Explicit instantiations for wchar_t. char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
template void internal::FixedBuffer<wchar_t>::grow(std::size_t); std::fputs(escape, stdout);
print(format, args);
template void internal::ArgMap<wchar_t>::init(const ArgList &args); std::fputs(RESET_COLOR, stdout);
}
template void PrintfFormatter<wchar_t>::format(WCStringRef format);
#ifndef FMT_HEADER_ONLY
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, template struct internal::BasicData<void>;
unsigned width, int precision, double value);
// Explicit instantiations for char.
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, template void internal::FixedBuffer<char>::grow(std::size_t);
unsigned width, int precision, long double value);
template void internal::ArgMap<char>::init(const ArgList &args);
#endif // FMT_HEADER_ONLY
template int internal::CharTraits<char>::format_float(
} // namespace fmt char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
#ifdef _MSC_VER
# pragma warning(pop) template int internal::CharTraits<char>::format_float(
#endif char *buffer, std::size_t size, const char *format,
\ No newline at end of file unsigned width, int precision, long double value);
// Explicit instantiations for wchar_t.
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
#endif // FMT_HEADER_ONLY
} // namespace fmt
#ifdef _MSC_VER
# pragma warning(pop)
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/* /*
Formatting library for C++ - std::ostream support Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved. All rights reserved.
For the license information refer to format.h. For the license information refer to format.h.
*/ */
#include "ostream.h" #include "ostream.h"
namespace fmt { namespace fmt {
namespace internal { namespace internal {
FMT_FUNC void write(std::ostream &os, Writer &w) { FMT_FUNC void write(std::ostream &os, Writer &w)
const char *data = w.data(); {
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; const char *data = w.data();
UnsignedStreamSize size = w.size(); typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize max_size = UnsignedStreamSize size = w.size();
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); UnsignedStreamSize max_size =
do { internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
UnsignedStreamSize n = size <= max_size ? size : max_size; do {
os.write(data, static_cast<std::streamsize>(n)); UnsignedStreamSize n = size <= max_size ? size : max_size;
data += n; os.write(data, static_cast<std::streamsize>(n));
size -= n; data += n;
} while (size != 0); size -= n;
} } while (size != 0);
} }
}
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w; FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args)
w.write(format_str, args); {
internal::write(os, w); MemoryWriter w;
} w.write(format_str, args);
} // namespace fmt internal::write(os, w);
\ No newline at end of file }
} // namespace fmt
...@@ -11,108 +11,105 @@ For the license information refer to format.h. ...@@ -11,108 +11,105 @@ For the license information refer to format.h.
#define FMT_OSTREAM_H_ #define FMT_OSTREAM_H_
// commented out by spdlog // commented out by spdlog
//#include "format.h" // #include "format.h"
#include <ostream> #include <ostream>
namespace fmt namespace fmt {
{
namespace internal {
namespace internal
{ template <class Char>
class FormatBuf: public std::basic_streambuf<Char>
template <class Char> {
class FormatBuf : public std::basic_streambuf<Char> private:
{ typedef typename std::basic_streambuf<Char>::int_type int_type;
private: typedef typename std::basic_streambuf<Char>::traits_type traits_type;
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type; Buffer<Char> &buffer_;
Char *start_;
Buffer<Char> &buffer_;
Char *start_; public:
FormatBuf(Buffer<Char> &buffer): buffer_(buffer), start_(&buffer[0])
public: {
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) this->setp(start_, start_ + buffer_.capacity());
{ }
this->setp(start_, start_ + buffer_.capacity());
} int_type overflow(int_type ch = traits_type::eof())
{
int_type overflow(int_type ch = traits_type::eof()) if (!traits_type::eq_int_type(ch, traits_type::eof())) {
{ size_t buf_size = size();
if (!traits_type::eq_int_type(ch, traits_type::eof())) buffer_.resize(buf_size);
{ buffer_.reserve(buf_size * 2);
size_t buf_size = size();
buffer_.resize(buf_size); start_ = &buffer_[0];
buffer_.reserve(buf_size * 2); start_[buf_size] = traits_type::to_char_type(ch);
this->setp(start_ + buf_size + 1, start_ + buf_size * 2);
start_ = &buffer_[0]; }
start_[buf_size] = traits_type::to_char_type(ch); return ch;
this->setp(start_ + buf_size + 1, start_ + buf_size * 2); }
}
return ch; size_t size() const
} {
return to_unsigned(this->pptr() - start_);
size_t size() const }
{ };
return to_unsigned(this->pptr() - start_);
} Yes &convert(std::ostream &);
};
struct DummyStream: std::ostream
Yes &convert(std::ostream &); {
DummyStream(); // Suppress a bogus warning in MSVC.
struct DummyStream : std::ostream // Hide all operator<< overloads from std::ostream.
{ void operator<<(Null<>);
DummyStream(); // Suppress a bogus warning in MSVC. };
// Hide all operator<< overloads from std::ostream.
void operator<<(Null<>); No &operator<<(std::ostream &, int);
};
template<typename T>
No &operator<<(std::ostream &, int); struct ConvertToIntImpl<T, true>
{
template<typename T> // Convert to int only if T doesn't have an overloaded operator<<.
struct ConvertToIntImpl<T, true> enum
{ {
// Convert to int only if T doesn't have an overloaded operator<<. value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
enum };
{ };
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
}; // Write the content of w to os.
}; void write(std::ostream &os, Writer &w);
} // namespace internal
// Write the content of w to os.
void write(std::ostream &os, Writer &w); // Formats a value.
} // namespace internal template <typename Char, typename ArgFormatter, typename T>
void format_arg(BasicFormatter<Char, ArgFormatter> &f,
// Formats a value. const Char *&format_str, const T &value)
template <typename Char, typename ArgFormatter, typename T> {
void format_arg(BasicFormatter<Char, ArgFormatter> &f, internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
const Char *&format_str, const T &value)
{ internal::FormatBuf<Char> format_buf(buffer);
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; std::basic_ostream<Char> output(&format_buf);
output << value;
internal::FormatBuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf); BasicStringRef<Char> str(&buffer[0], format_buf.size());
output << value; typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
format_str = f.format(format_str, MakeArg(str));
BasicStringRef<Char> str(&buffer[0], format_buf.size()); }
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
format_str = f.format(format_str, MakeArg(str)); /**
} \rst
Prints formatted data to the stream *os*.
/**
\rst **Example**::
Prints formatted data to the stream *os*.
print(cerr, "Don't {}!", "panic");
**Example**:: \endrst
*/
print(cerr, "Don't {}!", "panic"); FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
\endrst FMT_VARIADIC(void, print, std::ostream &, CStringRef)
*/
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
#ifdef FMT_HEADER_ONLY #ifdef FMT_HEADER_ONLY
# include "ostream.cc" # include "ostream.cc"
#endif #endif
#endif // FMT_OSTREAM_H_ #endif // FMT_OSTREAM_H_
\ No newline at end of file
...@@ -15,628 +15,613 @@ For the license information refer to format.h. ...@@ -15,628 +15,613 @@ For the license information refer to format.h.
#include "ostream.h" #include "ostream.h"
namespace fmt namespace fmt {
{ namespace internal {
namespace internal
{ // Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
// Checks if a value fits in int - used to avoid warnings about comparing template <bool IsSigned>
// signed and unsigned integers. struct IntChecker
template <bool IsSigned> {
struct IntChecker template <typename T>
{ static bool fits_in_int(T value)
template <typename T> {
static bool fits_in_int(T value) unsigned max = std::numeric_limits<int>::max();
{ return value <= max;
unsigned max = std::numeric_limits<int>::max(); }
return value <= max; static bool fits_in_int(bool)
} {
static bool fits_in_int(bool) return true;
{ }
return true; };
}
}; template <>
struct IntChecker<true>
template <> {
struct IntChecker<true> template <typename T>
{ static bool fits_in_int(T value)
template <typename T> {
static bool fits_in_int(T value) return value >= std::numeric_limits<int>::min() &&
{ value <= std::numeric_limits<int>::max();
return value >= std::numeric_limits<int>::min() && }
value <= std::numeric_limits<int>::max(); static bool fits_in_int(int)
} {
static bool fits_in_int(int) return true;
{ }
return true; };
}
}; class PrecisionHandler: public ArgVisitor<PrecisionHandler, int>
{
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> public:
{ void report_unhandled_arg()
public: {
void report_unhandled_arg() FMT_THROW(FormatError("precision is not integer"));
{ }
FMT_THROW(FormatError("precision is not integer"));
} template <typename T>
int visit_any_int(T value)
template <typename T> {
int visit_any_int(T value) if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
{ FMT_THROW(FormatError("number is too big"));
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) return static_cast<int>(value);
FMT_THROW(FormatError("number is too big")); }
return static_cast<int>(value); };
}
}; // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt: public ArgVisitor<IsZeroInt, bool>
// IsZeroInt::visit(arg) returns true iff arg is a zero integer. {
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> public:
{ template <typename T>
public: bool visit_any_int(T value)
template <typename T> {
bool visit_any_int(T value) return value == 0;
{ }
return value == 0; };
}
}; template <typename T, typename U>
struct is_same
template <typename T, typename U> {
struct is_same enum
{ {
enum { value = 0 }; value = 0
}; };
};
template <typename T>
struct is_same<T, T> template <typename T>
{ struct is_same<T, T>
enum { value = 1 }; {
}; enum
{
// An argument visitor that converts an integer argument to T for printf, value = 1
// if T is an integral type. If T is void, the argument is converted to };
// corresponding signed or unsigned type depending on the type specifier: };
// 'd' and 'i' - signed, other - unsigned)
template <typename T = void> // An argument visitor that converts an integer argument to T for printf,
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> // if T is an integral type. If T is void, the argument is converted to
{ // corresponding signed or unsigned type depending on the type specifier:
private: // 'd' and 'i' - signed, other - unsigned)
internal::Arg &arg_; template <typename T = void>
wchar_t type_; class ArgConverter: public ArgVisitor<ArgConverter<T>, void>
{
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); private:
internal::Arg &arg_;
public: wchar_t type_;
ArgConverter(internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {} FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
void visit_bool(bool value) public:
{ ArgConverter(internal::Arg &arg, wchar_t type)
if (type_ != 's') : arg_(arg), type_(type)
visit_any_int(value); {}
}
void visit_bool(bool value)
template <typename U> {
void visit_any_int(U value) if (type_ != 's')
{ visit_any_int(value);
bool is_signed = type_ == 'd' || type_ == 'i'; }
using internal::Arg;
typedef typename internal::Conditional< template <typename U>
is_same<T, void>::value, U, T>::type TargetType; void visit_any_int(U value)
if (sizeof(TargetType) <= sizeof(int)) {
{ bool is_signed = type_ == 'd' || type_ == 'i';
// Extra casts are used to silence warnings. using internal::Arg;
if (is_signed) typedef typename internal::Conditional<
{ is_same<T, void>::value, U, T>::type TargetType;
arg_.type = Arg::INT; if (sizeof(TargetType) <= sizeof(int)) {
arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); // Extra casts are used to silence warnings.
} if (is_signed) {
else arg_.type = Arg::INT;
{ arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
arg_.type = Arg::UINT; }
typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; else {
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); arg_.type = Arg::UINT;
} typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
} arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
else }
{ }
if (is_signed) else {
{ if (is_signed) {
arg_.type = Arg::LONG_LONG; arg_.type = Arg::LONG_LONG;
// glibc's printf doesn't sign extend arguments of smaller types: // glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254" // std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB. // but we don't have to do the same because it's a UB.
arg_.long_long_value = static_cast<LongLong>(value); arg_.long_long_value = static_cast<LongLong>(value);
} }
else else {
{ arg_.type = Arg::ULONG_LONG;
arg_.type = Arg::ULONG_LONG; arg_.ulong_long_value =
arg_.ulong_long_value = static_cast<typename internal::MakeUnsigned<U>::Type>(value);
static_cast<typename internal::MakeUnsigned<U>::Type>(value); }
} }
} }
} };
};
// Converts an integer argument to char for printf.
// Converts an integer argument to char for printf. class CharConverter: public ArgVisitor<CharConverter, void>
class CharConverter : public ArgVisitor<CharConverter, void> {
{ private:
private: internal::Arg &arg_;
internal::Arg &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public:
public: explicit CharConverter(internal::Arg &arg): arg_(arg)
explicit CharConverter(internal::Arg &arg) : arg_(arg) {} {}
template <typename T> template <typename T>
void visit_any_int(T value) void visit_any_int(T value)
{ {
arg_.type = internal::Arg::CHAR; arg_.type = internal::Arg::CHAR;
arg_.int_value = static_cast<char>(value); arg_.int_value = static_cast<char>(value);
} }
}; };
// Checks if an argument is a valid printf width specifier and sets // Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative. // left alignment if it is negative.
class WidthHandler : public ArgVisitor<WidthHandler, unsigned> class WidthHandler: public ArgVisitor<WidthHandler, unsigned>
{ {
private: private:
FormatSpec &spec_; FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public: public:
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} explicit WidthHandler(FormatSpec &spec): spec_(spec)
{}
void report_unhandled_arg()
{ void report_unhandled_arg()
FMT_THROW(FormatError("width is not integer")); {
} FMT_THROW(FormatError("width is not integer"));
}
template <typename T>
unsigned visit_any_int(T value) template <typename T>
{ unsigned visit_any_int(T value)
typedef typename internal::IntTraits<T>::MainType UnsignedType; {
UnsignedType width = static_cast<UnsignedType>(value); typedef typename internal::IntTraits<T>::MainType UnsignedType;
if (internal::is_negative(value)) UnsignedType width = static_cast<UnsignedType>(value);
{ if (internal::is_negative(value)) {
spec_.align_ = ALIGN_LEFT; spec_.align_ = ALIGN_LEFT;
width = 0 - width; width = 0 - width;
} }
unsigned int_max = std::numeric_limits<int>::max(); unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max) if (width > int_max)
FMT_THROW(FormatError("number is too big")); FMT_THROW(FormatError("number is too big"));
return static_cast<unsigned>(width); return static_cast<unsigned>(width);
} }
}; };
} // namespace internal } // namespace internal
/** /**
\rst \rst
A ``printf`` argument formatter based on the `curiously recurring template A ``printf`` argument formatter based on the `curiously recurring template
pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_. pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some
or all of the visit methods with the same signatures as the methods in or all of the visit methods with the same signatures as the methods in
`~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
Pass the subclass as the *Impl* template parameter. When a formatting Pass the subclass as the *Impl* template parameter. When a formatting
function processes an argument, it will dispatch to a visit method function processes an argument, it will dispatch to a visit method
specific to the argument type. For example, if the argument type is specific to the argument type. For example, if the argument type is
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
will be called. If the subclass doesn't contain a method with this signature, will be called. If the subclass doesn't contain a method with this signature,
then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its
superclass will be called. superclass will be called.
\endrst \endrst
*/ */
template <typename Impl, typename Char> template <typename Impl, typename Char>
class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char> class BasicPrintfArgFormatter: public internal::ArgFormatterBase<Impl, Char>
{ {
private: private:
void write_null_pointer() void write_null_pointer()
{ {
this->spec().type_ = 0; this->spec().type_ = 0;
this->write("(nil)"); this->write("(nil)");
} }
typedef internal::ArgFormatterBase<Impl, Char> Base; typedef internal::ArgFormatterBase<Impl, Char> Base;
public: public:
/** /**
\rst \rst
Constructs an argument formatter object. Constructs an argument formatter object.
*writer* is a reference to the output writer and *spec* contains format *writer* is a reference to the output writer and *spec* contains format
specifier information for standard argument types. specifier information for standard argument types.
\endrst \endrst
*/ */
BasicPrintfArgFormatter(BasicWriter<Char> &writer, FormatSpec &spec) BasicPrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: internal::ArgFormatterBase<Impl, Char>(writer, spec) {} : internal::ArgFormatterBase<Impl, Char>(w, s)
{}
/** Formats an argument of type ``bool``. */
void visit_bool(bool value) /** Formats an argument of type ``bool``. */
{ void visit_bool(bool value)
FormatSpec &fmt_spec = this->spec(); {
if (fmt_spec.type_ != 's') FormatSpec &fmt_spec = this->spec();
return this->visit_any_int(value); if (fmt_spec.type_ != 's')
fmt_spec.type_ = 0; return this->visit_any_int(value);
this->write(value); fmt_spec.type_ = 0;
} this->write(value);
}
/** Formats a character. */
void visit_char(int value) /** Formats a character. */
{ void visit_char(int value)
const FormatSpec &fmt_spec = this->spec(); {
BasicWriter<Char> &w = this->writer(); const FormatSpec &fmt_spec = this->spec();
if (fmt_spec.type_ && fmt_spec.type_ != 'c') BasicWriter<Char> &w = this->writer();
w.write_int(value, fmt_spec); if (fmt_spec.type_ && fmt_spec.type_ != 'c')
typedef typename BasicWriter<Char>::CharPtr CharPtr; w.write_int(value, fmt_spec);
CharPtr out = CharPtr(); typedef typename BasicWriter<Char>::CharPtr CharPtr;
if (fmt_spec.width_ > 1) CharPtr out = CharPtr();
{ if (fmt_spec.width_ > 1) {
Char fill = ' '; Char fill = ' ';
out = w.grow_buffer(fmt_spec.width_); out = w.grow_buffer(fmt_spec.width_);
if (fmt_spec.align_ != ALIGN_LEFT) if (fmt_spec.align_ != ALIGN_LEFT) {
{ std::fill_n(out, fmt_spec.width_ - 1, fill);
std::fill_n(out, fmt_spec.width_ - 1, fill); out += fmt_spec.width_ - 1;
out += fmt_spec.width_ - 1; }
} else {
else std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
{ }
std::fill_n(out + 1, fmt_spec.width_ - 1, fill); }
} else {
} out = w.grow_buffer(1);
else }
{ *out = static_cast<Char>(value);
out = w.grow_buffer(1); }
}
*out = static_cast<Char>(value); /** Formats a null-terminated C string. */
} void visit_cstring(const char *value)
{
/** Formats a null-terminated C string. */ if (value)
void visit_cstring(const char *value) Base::visit_cstring(value);
{ else if (this->spec().type_ == 'p')
if (value) write_null_pointer();
Base::visit_cstring(value); else
else if (this->spec().type_ == 'p') this->write("(null)");
write_null_pointer(); }
else
this->write("(null)"); /** Formats a pointer. */
} void visit_pointer(const void *value)
{
/** Formats a pointer. */ if (value)
void visit_pointer(const void *value) return Base::visit_pointer(value);
{ this->spec().type_ = 0;
if (value) write_null_pointer();
return Base::visit_pointer(value); }
this->spec().type_ = 0;
write_null_pointer(); /** Formats an argument of a custom (user-defined) type. */
} void visit_custom(internal::Arg::CustomValue c)
{
/** Formats an argument of a custom (user-defined) type. */ BasicFormatter<Char> formatter(ArgList(), this->writer());
void visit_custom(internal::Arg::CustomValue c) const Char format_str[] = { '}', 0 };
{ const Char *format = format_str;
BasicFormatter<Char> formatter(ArgList(), this->writer()); c.format(&formatter, c.value, &format);
const Char format_str[] = { '}', 0 }; }
const Char *format = format_str; };
c.format(&formatter, c.value, &format);
} /** The default printf argument formatter. */
}; template <typename Char>
class PrintfArgFormatter
/** The default printf argument formatter. */ : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>
template <typename Char> {
class PrintfArgFormatter public:
: public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char> /** Constructs an argument formatter object. */
{ PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
public: : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s)
/** Constructs an argument formatter object. */ {}
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) };
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
}; /** This template formats data and writes the output to a writer. */
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
/** This template formats data and writes the output to a writer. */ class PrintfFormatter: private internal::FormatterBase
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> > {
class PrintfFormatter : private internal::FormatterBase private:
{ BasicWriter<Char> &writer_;
private:
BasicWriter<Char> &writer_; void parse_flags(FormatSpec &spec, const Char *&s);
void parse_flags(FormatSpec &spec, const Char *&s); // Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
// Returns the argument with specified index or, if arg_index is equal internal::Arg get_arg(
// to the maximum unsigned value, the next argument. const Char *s,
internal::Arg get_arg( unsigned arg_index = (std::numeric_limits<unsigned>::max)());
const Char *s,
unsigned arg_index = (std::numeric_limits<unsigned>::max)()); // Parses argument index, flags and width and returns the argument index.
unsigned parse_header(const Char *&s, FormatSpec &spec);
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(const Char *&s, FormatSpec &spec); public:
/**
public: \rst
/** Constructs a ``PrintfFormatter`` object. References to the arguments and
\rst the writer are stored in the formatter object so make sure they have
Constructs a ``PrintfFormatter`` object. References to the arguments and appropriate lifetimes.
the writer are stored in the formatter object so make sure they have \endrst
appropriate lifetimes. */
\endrst explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
*/ : FormatterBase(al), writer_(w)
explicit PrintfFormatter(const ArgList &args, BasicWriter<Char> &w) {}
: FormatterBase(args), writer_(w) {}
/** Formats stored arguments and writes the output to the writer. */
/** Formats stored arguments and writes the output to the writer. */ FMT_API void format(BasicCStringRef<Char> format_str);
FMT_API void format(BasicCStringRef<Char> format_str); };
};
template <typename Char, typename AF>
template <typename Char, typename AF> void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s)
void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) {
{ for (;;) {
for (;;) switch (*s++) {
{ case '-':
switch (*s++) spec.align_ = ALIGN_LEFT;
{ break;
case '-': case '+':
spec.align_ = ALIGN_LEFT; spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break; break;
case '+': case '0':
spec.flags_ |= SIGN_FLAG | PLUS_FLAG; spec.fill_ = '0';
break; break;
case '0': case ' ':
spec.fill_ = '0'; spec.flags_ |= SIGN_FLAG;
break; break;
case ' ': case '#':
spec.flags_ |= SIGN_FLAG; spec.flags_ |= HASH_FLAG;
break; break;
case '#': default:
spec.flags_ |= HASH_FLAG; --s;
break; return;
default: }
--s; }
return; }
}
} template <typename Char, typename AF>
} internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
unsigned arg_index)
template <typename Char, typename AF> {
internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, (void)s;
unsigned arg_index) const char *error = FMT_NULL;
{ internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
(void)s; next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
const char *error = 0; if (error)
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? FMT_THROW(FormatError(!*s ? "invalid format string" : error));
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); return arg;
if (error) }
FMT_THROW(FormatError(!*s ? "invalid format string" : error));
return arg; template <typename Char, typename AF>
} unsigned PrintfFormatter<Char, AF>::parse_header(
const Char *&s, FormatSpec &spec)
template <typename Char, typename AF> {
unsigned PrintfFormatter<Char, AF>::parse_header( unsigned arg_index = std::numeric_limits<unsigned>::max();
const Char *&s, FormatSpec &spec) Char c = *s;
{ if (c >= '0' && c <= '9') {
unsigned arg_index = std::numeric_limits<unsigned>::max(); // Parse an argument index (if followed by '$') or a width possibly
Char c = *s; // preceded with '0' flag(s).
if (c >= '0' && c <= '9') unsigned value = internal::parse_nonnegative_int(s);
{ if (*s == '$') { // value is an argument index
// Parse an argument index (if followed by '$') or a width possibly ++s;
// preceded with '0' flag(s). arg_index = value;
unsigned value = internal::parse_nonnegative_int(s); }
if (*s == '$') // value is an argument index else {
{ if (c == '0')
++s; spec.fill_ = '0';
arg_index = value; if (value != 0) {
} // Nonzero value means that we parsed width and don't need to
else // parse it or flags again, so return now.
{ spec.width_ = value;
if (c == '0') return arg_index;
spec.fill_ = '0'; }
if (value != 0) }
{ }
// Nonzero value means that we parsed width and don't need to parse_flags(spec, s);
// parse it or flags again, so return now. // Parse width.
spec.width_ = value; if (*s >= '0' && *s <= '9') {
return arg_index; spec.width_ = internal::parse_nonnegative_int(s);
} }
} else if (*s == '*') {
} ++s;
parse_flags(spec, s); spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));
// Parse width. }
if (*s >= '0' && *s <= '9') return arg_index;
{ }
spec.width_ = internal::parse_nonnegative_int(s);
} template <typename Char, typename AF>
else if (*s == '*') void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)
{ {
++s; const Char *start = format_str.c_str();
spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); const Char *s = start;
} while (*s) {
return arg_index; Char c = *s++;
} if (c != '%') continue;
if (*s == c) {
template <typename Char, typename AF> write(writer_, start, s);
void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) start = ++s;
{ continue;
const Char *start = format_str.c_str(); }
const Char *s = start; write(writer_, start, s - 1);
while (*s)
{ FormatSpec spec;
Char c = *s++; spec.align_ = ALIGN_RIGHT;
if (c != '%') continue;
if (*s == c) // Parse argument index, flags and width.
{ unsigned arg_index = parse_header(s, spec);
write(writer_, start, s);
start = ++s; // Parse precision.
continue; if (*s == '.') {
} ++s;
write(writer_, start, s - 1); if ('0' <= *s && *s <= '9') {
spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));
FormatSpec spec; }
spec.align_ = ALIGN_RIGHT; else if (*s == '*') {
++s;
// Parse argument index, flags and width. spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));
unsigned arg_index = parse_header(s, spec); }
}
// Parse precision.
if (*s == '.') using internal::Arg;
{ Arg arg = get_arg(s, arg_index);
++s; if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))
if ('0' <= *s && *s <= '9') spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
{ if (spec.fill_ == '0') {
spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s)); if (arg.type <= Arg::LAST_NUMERIC_TYPE)
} spec.align_ = ALIGN_NUMERIC;
else if (*s == '*') else
{ spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
++s; }
spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));
} // Parse length and convert the argument to the required type.
} using internal::ArgConverter;
switch (*s++) {
using internal::Arg; case 'h':
Arg arg = get_arg(s, arg_index); if (*s == 'h')
if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) ArgConverter<signed char>(arg, *++s).visit(arg);
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); else
if (spec.fill_ == '0') ArgConverter<short>(arg, *s).visit(arg);
{ break;
if (arg.type <= Arg::LAST_NUMERIC_TYPE) case 'l':
spec.align_ = ALIGN_NUMERIC; if (*s == 'l')
else ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. else
} ArgConverter<long>(arg, *s).visit(arg);
break;
// Parse length and convert the argument to the required type. case 'j':
using internal::ArgConverter; ArgConverter<intmax_t>(arg, *s).visit(arg);
switch (*s++) break;
{ case 'z':
case 'h': ArgConverter<std::size_t>(arg, *s).visit(arg);
if (*s == 'h') break;
ArgConverter<signed char>(arg, *++s).visit(arg); case 't':
else ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
ArgConverter<short>(arg, *s).visit(arg); break;
break; case 'L':
case 'l': // printf produces garbage when 'L' is omitted for long double, no
if (*s == 'l') // need to do the same.
ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); break;
else default:
ArgConverter<long>(arg, *s).visit(arg); --s;
break; ArgConverter<void>(arg, *s).visit(arg);
case 'j': }
ArgConverter<intmax_t>(arg, *s).visit(arg);
break; // Parse type.
case 'z': if (!*s)
ArgConverter<std::size_t>(arg, *s).visit(arg); FMT_THROW(FormatError("invalid format string"));
break; spec.type_ = static_cast<char>(*s++);
case 't': if (arg.type <= Arg::LAST_INTEGER_TYPE) {
ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); // Normalize type.
break; switch (spec.type_) {
case 'L': case 'i': case 'u':
// printf produces garbage when 'L' is omitted for long double, no spec.type_ = 'd';
// need to do the same. break;
break; case 'c':
default: // TODO: handle wchar_t
--s; internal::CharConverter(arg).visit(arg);
ArgConverter<void>(arg, *s).visit(arg); break;
} }
}
// Parse type.
if (!*s) start = s;
FMT_THROW(FormatError("invalid format string"));
spec.type_ = static_cast<char>(*s++); // Format argument.
if (arg.type <= Arg::LAST_INTEGER_TYPE) AF(writer_, spec).visit(arg);
{ }
// Normalize type. write(writer_, start, s);
switch (spec.type_) }
{
case 'i': template <typename Char>
case 'u': void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args)
spec.type_ = 'd'; {
break; PrintfFormatter<Char>(args, w).format(format);
case 'c': }
// TODO: handle wchar_t
internal::CharConverter(arg).visit(arg); /**
break; \rst
} Formats arguments and returns the result as a string.
}
**Example**::
start = s;
std::string message = fmt::sprintf("The answer is %d", 42);
// Format argument. \endrst
AF(writer_, spec).visit(arg); */
} inline std::string sprintf(CStringRef format, ArgList args)
write(writer_, start, s); {
} MemoryWriter w;
printf(w, format, args);
template <typename Char> return w.str();
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) }
{ FMT_VARIADIC(std::string, sprintf, CStringRef)
PrintfFormatter<Char>(args, w).format(format);
} inline std::wstring sprintf(WCStringRef format, ArgList args)
{
/** WMemoryWriter w;
\rst printf(w, format, args);
Formats arguments and returns the result as a string. return w.str();
}
**Example**:: FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
std::string message = fmt::sprintf("The answer is %d", 42); /**
\endrst \rst
*/ Prints formatted data to the file *f*.
inline std::string sprintf(CStringRef format, ArgList args)
{ **Example**::
MemoryWriter w;
printf(w, format, args); fmt::fprintf(stderr, "Don't %s!", "panic");
return w.str(); \endrst
} */
FMT_VARIADIC(std::string, sprintf, CStringRef) FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
inline std::wstring sprintf(WCStringRef format, ArgList args)
{ /**
WMemoryWriter w; \rst
printf(w, format, args); Prints formatted data to ``stdout``.
return w.str();
} **Example**::
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
fmt::printf("Elapsed time: %.2f seconds", 1.23);
/** \endrst
\rst */
Prints formatted data to the file *f*. inline int printf(CStringRef format, ArgList args)
{
**Example**:: return fprintf(stdout, format, args);
}
fmt::fprintf(stderr, "Don't %s!", "panic"); FMT_VARIADIC(int, printf, CStringRef)
\endrst
*/ /**
FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); \rst
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) Prints formatted data to the stream *os*.
/** **Example**::
\rst
Prints formatted data to ``stdout``. fprintf(cerr, "Don't %s!", "panic");
\endrst
**Example**:: */
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args)
fmt::printf("Elapsed time: %.2f seconds", 1.23); {
\endrst MemoryWriter w;
*/ printf(w, format_str, args);
inline int printf(CStringRef format, ArgList args) internal::write(os, w);
{ return static_cast<int>(w.size());
return fprintf(stdout, format, args); }
} FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
FMT_VARIADIC(int, printf, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args)
{
MemoryWriter w;
printf(w, format_str, args);
internal::write(os, w);
return static_cast<int>(w.size());
}
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
#endif // FMT_PRINTF_H_ #ifdef FMT_HEADER_ONLY
\ No newline at end of file # include "printf.cc"
#endif
#endif // FMT_PRINTF_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment