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>
...@@ -109,7 +109,7 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { ...@@ -109,7 +109,7 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
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.
...@@ -121,7 +121,7 @@ typedef void (*FormatFunc)(Writer &, int, StringRef); ...@@ -121,7 +121,7 @@ typedef void (*FormatFunc)(Writer &, int, StringRef);
// 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 {
...@@ -180,7 +180,7 @@ int safe_strerror( ...@@ -180,7 +180,7 @@ int safe_strerror(
} }
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.
...@@ -203,7 +203,7 @@ void format_error_code(Writer &out, int error_code, ...@@ -203,7 +203,7 @@ void format_error_code(Writer &out, int error_code,
} }
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
...@@ -218,7 +218,7 @@ namespace internal { ...@@ -218,7 +218,7 @@ 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
...@@ -357,8 +357,8 @@ FMT_FUNC void WindowsError::init( ...@@ -357,8 +357,8 @@ FMT_FUNC void WindowsError::init(
} }
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 (;;) {
...@@ -385,8 +385,8 @@ FMT_FUNC void internal::format_windows_error( ...@@ -385,8 +385,8 @@ FMT_FUNC void internal::format_windows_error(
#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 (;;) {
...@@ -423,7 +423,8 @@ void internal::ArgMap<Char>::init(const ArgList &args) { ...@@ -423,7 +423,8 @@ void internal::ArgMap<Char>::init(const ArgList &args) {
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;
...@@ -444,7 +445,8 @@ void internal::ArgMap<Char>::init(const ArgList &args) { ...@@ -444,7 +445,8 @@ void internal::ArgMap<Char>::init(const ArgList &args) {
map_.push_back(Pair(named_arg->name, *named_arg)); map_.push_back(Pair(named_arg->name, *named_arg));
break; break;
default: default:
/*nothing*/; /*nothing*/
;
} }
} }
} }
...@@ -465,20 +467,21 @@ FMT_FUNC Arg internal::FormatterBase::do_get_arg( ...@@ -465,20 +467,21 @@ FMT_FUNC Arg internal::FormatterBase::do_get_arg(
arg = *static_cast<const internal::Arg*>(arg.pointer); arg = *static_cast<const internal::Arg*>(arg.pointer);
break; break;
default: default:
/*nothing*/; /*nothing*/
;
} }
return arg; return arg;
} }
FMT_FUNC void report_system_error( FMT_FUNC void report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT { int error_code, fmt::StringRef message) FMT_NOEXCEPT{
// 'fmt::' is for bcc32. // 'fmt::' is for bcc32.
report_error(format_system_error, error_code, message); report_error(format_system_error, error_code, message);
} }
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error( FMT_FUNC void report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT { int error_code, fmt::StringRef message) FMT_NOEXCEPT{
// 'fmt::' is for bcc32. // 'fmt::' is for bcc32.
report_error(internal::format_windows_error, error_code, message); report_error(internal::format_windows_error, error_code, message);
} }
......
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 {
......
/* /*
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> template <class Char>
class FormatBuf : public std::basic_streambuf<Char> class FormatBuf : public std::basic_streambuf<Char> {
{
private: private:
typedef typename std::basic_streambuf<Char>::int_type int_type; typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type; typedef typename std::basic_streambuf<Char>::traits_type traits_type;
...@@ -31,36 +28,31 @@ private: ...@@ -31,36 +28,31 @@ private:
Char *start_; Char *start_;
public: public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) 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())) {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
{
size_t buf_size = size(); size_t buf_size = size();
buffer_.resize(buf_size); buffer_.resize(buf_size);
buffer_.reserve(buf_size * 2); buffer_.reserve(buf_size * 2);
start_ = &buffer_[0]; start_ = &buffer_[0];
start_[buf_size] = traits_type::to_char_type(ch); start_[buf_size] = traits_type::to_char_type(ch);
this->setp(start_+ buf_size + 1, start_ + buf_size * 2); this->setp(start_ + buf_size + 1, start_ + buf_size * 2);
} }
return ch; return ch;
} }
size_t size() const size_t size() const {
{
return to_unsigned(this->pptr() - start_); return to_unsigned(this->pptr() - start_);
} }
}; };
Yes &convert(std::ostream &); Yes &convert(std::ostream &);
struct DummyStream : std::ostream struct DummyStream : std::ostream {
{
DummyStream(); // Suppress a bogus warning in MSVC. DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream. // Hide all operator<< overloads from std::ostream.
void operator<<(Null<>); void operator<<(Null<>);
...@@ -69,11 +61,9 @@ struct DummyStream : std::ostream ...@@ -69,11 +61,9 @@ struct DummyStream : std::ostream
No &operator<<(std::ostream &, int); No &operator<<(std::ostream &, int);
template<typename T> template<typename T>
struct ConvertToIntImpl<T, true> struct ConvertToIntImpl<T, true> {
{
// Convert to int only if T doesn't have an overloaded operator<<. // Convert to int only if T doesn't have an overloaded operator<<.
enum enum {
{
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No) value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
}; };
}; };
...@@ -85,8 +75,7 @@ void write(std::ostream &os, Writer &w); ...@@ -85,8 +75,7 @@ void write(std::ostream &os, Writer &w);
// Formats a value. // Formats a value.
template <typename Char, typename ArgFormatter, typename T> template <typename Char, typename ArgFormatter, typename T>
void format_arg(BasicFormatter<Char, ArgFormatter> &f, void format_arg(BasicFormatter<Char, ArgFormatter> &f,
const Char *&format_str, const T &value) const Char *&format_str, const T &value) {
{
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::FormatBuf<Char> format_buf(buffer); internal::FormatBuf<Char> format_buf(buffer);
...@@ -99,14 +88,14 @@ void format_arg(BasicFormatter<Char, ArgFormatter> &f, ...@@ -99,14 +88,14 @@ void format_arg(BasicFormatter<Char, ArgFormatter> &f,
} }
/** /**
\rst \rst
Prints formatted data to the stream *os*. Prints formatted data to the stream *os*.
**Example**:: **Example**::
print(cerr, "Don't {}!", "panic"); print(cerr, "Don't {}!", "panic");
\endrst \endrst
*/ */
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef) FMT_VARIADIC(void, print, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
......
/* /*
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_
...@@ -13,56 +13,45 @@ ...@@ -13,56 +13,45 @@
#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 // Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers. // signed and unsigned integers.
template <bool IsSigned> template <bool IsSigned>
struct IntChecker struct IntChecker {
{
template <typename T> template <typename T>
static bool fits_in_int(T value) static bool fits_in_int(T value) {
{
unsigned max = std::numeric_limits<int>::max(); unsigned max = std::numeric_limits<int>::max();
return value <= max; return value <= max;
} }
static bool fits_in_int(bool) static bool fits_in_int(bool) {
{
return true; return true;
} }
}; };
template <> template <>
struct IntChecker<true> struct IntChecker<true> {
{
template <typename T> template <typename T>
static bool fits_in_int(T value) static bool fits_in_int(T value) {
{
return value >= std::numeric_limits<int>::min() && return value >= std::numeric_limits<int>::min() &&
value <= std::numeric_limits<int>::max(); 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: public:
void report_unhandled_arg() void report_unhandled_arg() {
{
FMT_THROW(FormatError("precision is not integer")); FMT_THROW(FormatError("precision is not integer"));
} }
template <typename T> template <typename T>
int visit_any_int(T value) int visit_any_int(T value) {
{
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(FormatError("number is too big")); FMT_THROW(FormatError("number is too big"));
return static_cast<int>(value); return static_cast<int>(value);
...@@ -70,25 +59,21 @@ public: ...@@ -70,25 +59,21 @@ public:
}; };
// IsZeroInt::visit(arg) returns true iff arg is a zero integer. // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
{
public: public:
template <typename T> template <typename T>
bool visit_any_int(T value) bool visit_any_int(T value) {
{
return value == 0; return value == 0;
} }
}; };
template <typename T, typename U> template <typename T, typename U>
struct is_same struct is_same {
{
enum { value = 0 }; enum { value = 0 };
}; };
template <typename T> template <typename T>
struct is_same<T, T> struct is_same<T, T> {
{
enum { value = 1 }; enum { value = 1 };
}; };
...@@ -97,8 +82,7 @@ struct is_same<T, T> ...@@ -97,8 +82,7 @@ struct is_same<T, T>
// corresponding signed or unsigned type depending on the type specifier: // corresponding signed or unsigned type depending on the type specifier:
// 'd' and 'i' - signed, other - unsigned) // 'd' and 'i' - signed, other - unsigned)
template <typename T = void> template <typename T = void>
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
{
private: private:
internal::Arg &arg_; internal::Arg &arg_;
wchar_t type_; wchar_t type_;
...@@ -109,46 +93,38 @@ public: ...@@ -109,46 +93,38 @@ public:
ArgConverter(internal::Arg &arg, wchar_t type) ArgConverter(internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {} : arg_(arg), type_(type) {}
void visit_bool(bool value) void visit_bool(bool value) {
{
if (type_ != 's') if (type_ != 's')
visit_any_int(value); visit_any_int(value);
} }
template <typename U> template <typename U>
void visit_any_int(U value) void visit_any_int(U value) {
{
bool is_signed = type_ == 'd' || type_ == 'i'; bool is_signed = type_ == 'd' || type_ == 'i';
using internal::Arg; using internal::Arg;
typedef typename internal::Conditional< typedef typename internal::Conditional<
is_same<T, void>::value, U, T>::type TargetType; is_same<T, void>::value, U, T>::type TargetType;
if (sizeof(TargetType) <= sizeof(int)) if (sizeof(TargetType) <= sizeof(int)) {
{
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
if (is_signed) if (is_signed) {
{
arg_.type = Arg::INT; arg_.type = Arg::INT;
arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
} }
else else {
{
arg_.type = Arg::UINT; arg_.type = Arg::UINT;
typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
} }
} }
else else {
{ if (is_signed) {
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);
...@@ -158,8 +134,7 @@ public: ...@@ -158,8 +134,7 @@ public:
}; };
// 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_;
...@@ -169,8 +144,7 @@ public: ...@@ -169,8 +144,7 @@ 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);
} }
...@@ -178,8 +152,7 @@ public: ...@@ -178,8 +152,7 @@ public:
// 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_;
...@@ -188,18 +161,15 @@ private: ...@@ -188,18 +161,15 @@ private:
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> template <typename T>
unsigned visit_any_int(T value) unsigned visit_any_int(T value) {
{
typedef typename internal::IntTraits<T>::MainType UnsignedType; typedef typename internal::IntTraits<T>::MainType UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value); UnsignedType width = static_cast<UnsignedType>(value);
if (internal::is_negative(value)) if (internal::is_negative(value)) {
{
spec_.align_ = ALIGN_LEFT; spec_.align_ = ALIGN_LEFT;
width = 0 - width; width = 0 - width;
} }
...@@ -212,28 +182,26 @@ public: ...@@ -212,28 +182,26 @@ public:
} // 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)");
} }
...@@ -252,8 +220,7 @@ public: ...@@ -252,8 +220,7 @@ public:
: internal::ArgFormatterBase<Impl, Char>(writer, spec) {} : internal::ArgFormatterBase<Impl, Char>(writer, spec) {}
/** Formats an argument of type ``bool``. */ /** Formats an argument of type ``bool``. */
void visit_bool(bool value) void visit_bool(bool value) {
{
FormatSpec &fmt_spec = this->spec(); FormatSpec &fmt_spec = this->spec();
if (fmt_spec.type_ != 's') if (fmt_spec.type_ != 's')
return this->visit_any_int(value); return this->visit_any_int(value);
...@@ -262,38 +229,32 @@ public: ...@@ -262,38 +229,32 @@ public:
} }
/** Formats a character. */ /** Formats a character. */
void visit_char(int value) void visit_char(int value) {
{
const FormatSpec &fmt_spec = this->spec(); const FormatSpec &fmt_spec = this->spec();
BasicWriter<Char> &w = this->writer(); BasicWriter<Char> &w = this->writer();
if (fmt_spec.type_ && fmt_spec.type_ != 'c') if (fmt_spec.type_ && fmt_spec.type_ != 'c')
w.write_int(value, fmt_spec); w.write_int(value, fmt_spec);
typedef typename BasicWriter<Char>::CharPtr CharPtr; typedef typename BasicWriter<Char>::CharPtr CharPtr;
CharPtr out = CharPtr(); CharPtr out = CharPtr();
if (fmt_spec.width_ > 1) 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 else {
{
out = w.grow_buffer(1); out = w.grow_buffer(1);
} }
*out = static_cast<Char>(value); *out = static_cast<Char>(value);
} }
/** Formats a null-terminated C string. */ /** Formats a null-terminated C string. */
void visit_cstring(const char *value) void visit_cstring(const char *value) {
{
if (value) if (value)
Base::visit_cstring(value); Base::visit_cstring(value);
else if (this->spec().type_ == 'p') else if (this->spec().type_ == 'p')
...@@ -303,8 +264,7 @@ public: ...@@ -303,8 +264,7 @@ public:
} }
/** Formats a pointer. */ /** Formats a pointer. */
void visit_pointer(const void *value) void visit_pointer(const void *value) {
{
if (value) if (value)
return Base::visit_pointer(value); return Base::visit_pointer(value);
this->spec().type_ = 0; this->spec().type_ = 0;
...@@ -312,10 +272,9 @@ public: ...@@ -312,10 +272,9 @@ public:
} }
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c) void visit_custom(internal::Arg::CustomValue c) {
{
BasicFormatter<Char> formatter(ArgList(), this->writer()); BasicFormatter<Char> formatter(ArgList(), this->writer());
const Char format_str[] = {'}', 0}; const Char format_str[] = { '}', 0 };
const Char *format = format_str; const Char *format = format_str;
c.format(&formatter, c.value, &format); c.format(&formatter, c.value, &format);
} }
...@@ -324,8 +283,7 @@ public: ...@@ -324,8 +283,7 @@ public:
/** The default printf argument formatter. */ /** The default printf argument formatter. */
template <typename Char> template <typename Char>
class PrintfArgFormatter class PrintfArgFormatter
: public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char> : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char> {
{
public: public:
/** Constructs an argument formatter object. */ /** Constructs an argument formatter object. */
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
...@@ -334,8 +292,7 @@ public: ...@@ -334,8 +292,7 @@ public:
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> > template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
class PrintfFormatter : private internal::FormatterBase class PrintfFormatter : private internal::FormatterBase {
{
private: private:
BasicWriter<Char> &writer_; BasicWriter<Char> &writer_;
...@@ -366,12 +323,9 @@ public: ...@@ -366,12 +323,9 @@ public:
}; };
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++) {
{
switch (*s++)
{
case '-': case '-':
spec.align_ = ALIGN_LEFT; spec.align_ = ALIGN_LEFT;
break; break;
...@@ -396,8 +350,7 @@ void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) ...@@ -396,8 +350,7 @@ void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s)
template <typename Char, typename AF> template <typename Char, typename AF>
internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
unsigned arg_index) unsigned arg_index) {
{
(void)s; (void)s;
const char *error = 0; const char *error = 0;
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
...@@ -409,26 +362,21 @@ internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, ...@@ -409,26 +362,21 @@ internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
template <typename Char, typename AF> template <typename Char, typename AF>
unsigned PrintfFormatter<Char, AF>::parse_header( unsigned PrintfFormatter<Char, AF>::parse_header(
const Char *&s, FormatSpec &spec) const Char *&s, FormatSpec &spec) {
{
unsigned arg_index = std::numeric_limits<unsigned>::max(); unsigned arg_index = std::numeric_limits<unsigned>::max();
Char c = *s; Char c = *s;
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9') {
{
// Parse an argument index (if followed by '$') or a width possibly // Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s). // preceded with '0' flag(s).
unsigned value = internal::parse_nonnegative_int(s); unsigned value = internal::parse_nonnegative_int(s);
if (*s == '$') // value is an argument index if (*s == '$') { // value is an argument index
{
++s; ++s;
arg_index = value; arg_index = value;
} }
else else {
{
if (c == '0') if (c == '0')
spec.fill_ = '0'; spec.fill_ = '0';
if (value != 0) if (value != 0) {
{
// Nonzero value means that we parsed width and don't need to // Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now. // parse it or flags again, so return now.
spec.width_ = value; spec.width_ = value;
...@@ -438,12 +386,10 @@ unsigned PrintfFormatter<Char, AF>::parse_header( ...@@ -438,12 +386,10 @@ unsigned PrintfFormatter<Char, AF>::parse_header(
} }
parse_flags(spec, s); parse_flags(spec, s);
// Parse width. // Parse width.
if (*s >= '0' && *s <= '9') if (*s >= '0' && *s <= '9') {
{
spec.width_ = internal::parse_nonnegative_int(s); spec.width_ = internal::parse_nonnegative_int(s);
} }
else if (*s == '*') else if (*s == '*') {
{
++s; ++s;
spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));
} }
...@@ -451,16 +397,13 @@ unsigned PrintfFormatter<Char, AF>::parse_header( ...@@ -451,16 +397,13 @@ unsigned PrintfFormatter<Char, AF>::parse_header(
} }
template <typename Char, typename AF> template <typename Char, typename AF>
void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
{
const Char *start = format_str.c_str(); const Char *start = format_str.c_str();
const Char *s = start; const Char *s = start;
while (*s) while (*s) {
{
Char c = *s++; Char c = *s++;
if (c != '%') continue; if (c != '%') continue;
if (*s == c) if (*s == c) {
{
write(writer_, start, s); write(writer_, start, s);
start = ++s; start = ++s;
continue; continue;
...@@ -474,15 +417,12 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) ...@@ -474,15 +417,12 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)
unsigned arg_index = parse_header(s, spec); unsigned arg_index = parse_header(s, spec);
// Parse precision. // Parse precision.
if (*s == '.') if (*s == '.') {
{
++s; ++s;
if ('0' <= *s && *s <= '9') if ('0' <= *s && *s <= '9') {
{
spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s)); spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));
} }
else if (*s == '*') else if (*s == '*') {
{
++s; ++s;
spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));
} }
...@@ -492,8 +432,7 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) ...@@ -492,8 +432,7 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)
Arg arg = get_arg(s, arg_index); Arg arg = get_arg(s, arg_index);
if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
if (spec.fill_ == '0') if (spec.fill_ == '0') {
{
if (arg.type <= Arg::LAST_NUMERIC_TYPE) if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC; spec.align_ = ALIGN_NUMERIC;
else else
...@@ -502,8 +441,7 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) ...@@ -502,8 +441,7 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)
// Parse length and convert the argument to the required type. // Parse length and convert the argument to the required type.
using internal::ArgConverter; using internal::ArgConverter;
switch (*s++) switch (*s++) {
{
case 'h': case 'h':
if (*s == 'h') if (*s == 'h')
ArgConverter<signed char>(arg, *++s).visit(arg); ArgConverter<signed char>(arg, *++s).visit(arg);
...@@ -538,11 +476,9 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) ...@@ -538,11 +476,9 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)
if (!*s) if (!*s)
FMT_THROW(FormatError("invalid format string")); FMT_THROW(FormatError("invalid format string"));
spec.type_ = static_cast<char>(*s++); spec.type_ = static_cast<char>(*s++);
if (arg.type <= Arg::LAST_INTEGER_TYPE) if (arg.type <= Arg::LAST_INTEGER_TYPE) {
{
// Normalize type. // Normalize type.
switch (spec.type_) switch (spec.type_) {
{
case 'i': case 'i':
case 'u': case 'u':
spec.type_ = 'd'; spec.type_ = 'd';
...@@ -563,30 +499,27 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) ...@@ -563,30 +499,27 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)
} }
template <typename Char> template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
{
PrintfFormatter<Char>(args, w).format(format); PrintfFormatter<Char>(args, w).format(format);
} }
/** /**
\rst \rst
Formats arguments and returns the result as a string. Formats arguments and returns the result as a string.
**Example**:: **Example**::
std::string message = fmt::sprintf("The answer is %d", 42); std::string message = fmt::sprintf("The answer is %d", 42);
\endrst \endrst
*/ */
inline std::string sprintf(CStringRef format, ArgList args) inline std::string sprintf(CStringRef format, ArgList args) {
{
MemoryWriter w; MemoryWriter w;
printf(w, format, args); printf(w, format, args);
return w.str(); return w.str();
} }
FMT_VARIADIC(std::string, sprintf, CStringRef) FMT_VARIADIC(std::string, sprintf, CStringRef)
inline std::wstring sprintf(WCStringRef format, ArgList args) inline std::wstring sprintf(WCStringRef format, ArgList args) {
{
WMemoryWriter w; WMemoryWriter w;
printf(w, format, args); printf(w, format, args);
return w.str(); return w.str();
...@@ -594,43 +527,41 @@ inline std::wstring sprintf(WCStringRef format, ArgList args) ...@@ -594,43 +527,41 @@ inline std::wstring sprintf(WCStringRef format, ArgList args)
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
/** /**
\rst \rst
Prints formatted data to the file *f*. Prints formatted data to the file *f*.
**Example**:: **Example**::
fmt::fprintf(stderr, "Don't %s!", "panic"); fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst \endrst
*/ */
FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
/** /**
\rst \rst
Prints formatted data to ``stdout``. Prints formatted data to ``stdout``.
**Example**:: **Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23); fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst \endrst
*/ */
inline int printf(CStringRef format, ArgList args) inline int printf(CStringRef format, ArgList args) {
{
return fprintf(stdout, format, args); return fprintf(stdout, format, args);
} }
FMT_VARIADIC(int, printf, CStringRef) FMT_VARIADIC(int, printf, CStringRef)
/** /**
\rst \rst
Prints formatted data to the stream *os*. Prints formatted data to the stream *os*.
**Example**:: **Example**::
fprintf(cerr, "Don't %s!", "panic"); fprintf(cerr, "Don't %s!", "panic");
\endrst \endrst
*/ */
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
{
MemoryWriter w; MemoryWriter w;
printf(w, format_str, args); printf(w, format_str, args);
internal::write(os, w); internal::write(os, w);
......
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