Commit 6128a87d authored by gabime's avatar gabime

Fix issue #300

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