mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-21 01:37:37 +01:00
Dep/CppFormat: Update cppformat to cppformat/cppformat@7859f81233
* clean up our custom CMakeList.txt
This commit is contained in:
@@ -14,7 +14,7 @@ bzip2 (a freely available, patent free, high-quality data compressor)
|
||||
|
||||
cppformat (type safe format library)
|
||||
https://github.com/cppformat/cppformat
|
||||
Version: 1.1.0 fd53bb6fb88a23e38ec4fe331bfe95d7372d49c9
|
||||
Version: 7859f8123311c1b8f69856d3c5e1b8501fbdae11
|
||||
|
||||
G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License)
|
||||
http://g3d.sourceforge.net/
|
||||
|
||||
@@ -6,12 +6,7 @@ set(FMT_SOURCES format.cc format.h)
|
||||
# Use variadic templates
|
||||
add_definitions(-DFMT_VARIADIC_TEMPLATES=1)
|
||||
|
||||
# Check if initializer lists are supported.
|
||||
check_cxx_source_compiles("
|
||||
#include <initializer_list>
|
||||
int main() {}" FMT_INITIALIZER_LIST)
|
||||
|
||||
# Use delete
|
||||
# Use deleted functions
|
||||
add_definitions(-DFMT_USE_DELETED_FUNCTIONS=1)
|
||||
|
||||
# Use static assert
|
||||
@@ -22,6 +17,7 @@ if (WIN32)
|
||||
else ()
|
||||
check_symbol_exists(open fcntl.h HAVE_OPEN)
|
||||
endif ()
|
||||
|
||||
if (HAVE_OPEN)
|
||||
add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1)
|
||||
set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h)
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
`#96 <https://github.com/cppformat/cppformat/issues/96>`_ and
|
||||
`#114 <https://github.com/cppformat/cppformat/pull/114>`_).
|
||||
|
||||
* Added `changelog <https://github.com/cppformat/cppformat/edit/master/ChangeLog.rst>`_
|
||||
* Added `changelog <https://github.com/cppformat/cppformat/blob/master/ChangeLog.rst>`_
|
||||
(`#103 <https://github.com/cppformat/cppformat/issues/103>`_).
|
||||
|
||||
1.0.0 - 2015-02-05
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Copyright (c) 2014 - 2015, Victor Zverovich
|
||||
Copyright (c) 2012 - 2015, Victor Zverovich
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
409
dep/cppformat/README.rst
Normal file
409
dep/cppformat/README.rst
Normal file
@@ -0,0 +1,409 @@
|
||||
C++ Format
|
||||
==========
|
||||
|
||||
.. image:: https://travis-ci.org/cppformat/cppformat.png?branch=master
|
||||
:target: https://travis-ci.org/cppformat/cppformat
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/qk0bhyhqp1ekpat8
|
||||
:target: https://ci.appveyor.com/project/vitaut/cppformat
|
||||
|
||||
.. image:: https://webapi.biicode.com/v1/badges/vitaut/vitaut/cppformat/master?dummy
|
||||
:target: https://www.biicode.com/vitaut/cppformat
|
||||
|
||||
.. image:: https://badges.gitter.im/Join%20Chat.svg
|
||||
:alt: Join the chat at https://gitter.im/cppformat/cppformat
|
||||
:target: https://gitter.im/cppformat/cppformat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
|
||||
C++ Format is an open-source formatting library for C++.
|
||||
It can be used as a safe alternative to printf or as a fast
|
||||
alternative to IOStreams.
|
||||
|
||||
`Documentation <http://cppformat.github.io/latest/>`_
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Two APIs: faster concatenation-based write API and slower (but still
|
||||
very fast) replacement-based format API with positional arguments for
|
||||
localization.
|
||||
* Write API similar to the one used by IOStreams but stateless allowing
|
||||
faster implementation.
|
||||
* Format API with `format string syntax
|
||||
<http://cppformat.github.io/latest/syntax.html>`_
|
||||
similar to the one used by `str.format
|
||||
<http://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
|
||||
* Safe `printf implementation
|
||||
<http://cppformat.github.io/latest/reference.html#printf-formatting-functions>`_
|
||||
including the POSIX extension for positional arguments.
|
||||
* Support for user-defined types.
|
||||
* High speed: performance of the format API is close to that of
|
||||
glibc's `printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`_
|
||||
and better than performance of IOStreams. See `Speed tests`_ and
|
||||
`Fast integer to string conversion in C++
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||
* Small code size both in terms of source code (format consists of a single
|
||||
header file and a single source file) and compiled code.
|
||||
See `Compile time and code bloat`_.
|
||||
* Reliability: the library has an extensive set of `unit tests
|
||||
<https://github.com/cppformat/cppformat/tree/master/test>`_.
|
||||
* Safety: the library is fully type safe, errors in format strings are
|
||||
reported using exceptions, automatic memory management prevents buffer
|
||||
overflow errors.
|
||||
* Ease of use: small self-contained code base, no external dependencies,
|
||||
permissive BSD `license
|
||||
<https://github.com/cppformat/cppformat/blob/master/LICENSE.rst>`_
|
||||
* `Portability <http://cppformat.github.io#portability>`_ with consistent output
|
||||
across platforms and support for older compilers.
|
||||
* Clean warning-free codebase even on high warning levels
|
||||
(-Wall -Wextra -pedantic).
|
||||
* Support for wide strings.
|
||||
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
|
||||
|
||||
See the `documentation <http://cppformat.github.io/latest/>`_ for more details.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
This prints ``Hello, world!`` to stdout:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
|
||||
fmt::printf("Hello, %s!", "world"); // uses printf format string syntax
|
||||
|
||||
Arguments can be accessed by position and arguments' indices can be repeated:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
|
||||
// s == "abracadabra"
|
||||
|
||||
C++ Format can be used as a safe portable replacement for ``itoa``:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
fmt::MemoryWriter w;
|
||||
w << 42; // replaces itoa(42, buffer, 10)
|
||||
w << fmt::hex(42); // replaces itoa(42, buffer, 16)
|
||||
// access the string using w.str() or w.c_str()
|
||||
|
||||
An object of any user-defined type for which there is an overloaded
|
||||
:code:`std::ostream` insertion operator (``operator<<``) can be formatted:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
|
||||
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
||||
}
|
||||
};
|
||||
|
||||
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
|
||||
// s == "The date is 2012-12-9"
|
||||
|
||||
You can use the `FMT_VARIADIC
|
||||
<http://cppformat.github.io/latest/reference.html#utilities>`_
|
||||
macro to create your own functions similar to `format
|
||||
<http://cppformat.github.io/latest/reference.html#format>`_ and
|
||||
`print <http://cppformat.github.io/latest/reference.html#print>`_
|
||||
which take arbitrary arguments:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
// Prints formatted error message.
|
||||
void report_error(const char *format, fmt::ArgList args) {
|
||||
fmt::print("Error: ");
|
||||
fmt::print(format, args);
|
||||
}
|
||||
FMT_VARIADIC(void, report_error, const char *)
|
||||
|
||||
report_error("file not found: {}", path);
|
||||
|
||||
Note that you only need to define one function that takes ``fmt::ArgList``
|
||||
argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that
|
||||
accept variable number of arguments.
|
||||
|
||||
Projects using this library
|
||||
---------------------------
|
||||
|
||||
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time strategy game
|
||||
|
||||
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||
An open-source library for mathematical programming
|
||||
|
||||
* `HarpyWar/pvpgn <https://github.com/HarpyWar/pvpgn>`_:
|
||||
Player vs Player Gaming Network with tweaks
|
||||
|
||||
* `KBEngine <http://www.kbengine.org/>`_: An open-source MMOG server engine
|
||||
|
||||
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
|
||||
|
||||
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
|
||||
An MMO server, compatible with most Ultima Online clients
|
||||
|
||||
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance, associative database
|
||||
|
||||
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
|
||||
|
||||
* `Saddy <https://code.google.com/p/saddy/>`_:
|
||||
Small crossplatform 2D graphic engine
|
||||
|
||||
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
|
||||
Business intelligence software
|
||||
|
||||
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
||||
|
||||
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source MMORPG framework
|
||||
|
||||
`More... <https://github.com/search?q=cppformat&type=Code>`_
|
||||
|
||||
If you are aware of other projects using this library, please let me know
|
||||
by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an
|
||||
`issue <https://github.com/cppformat/cppformat/issues>`_.
|
||||
|
||||
Motivation
|
||||
----------
|
||||
|
||||
So why yet another formatting library?
|
||||
|
||||
There are plenty of methods for doing this task, from standard ones like
|
||||
the printf family of function and IOStreams to Boost Format library and
|
||||
FastFormat. The reason for creating a new library is that every existing
|
||||
solution that I found either had serious issues or didn't provide
|
||||
all the features I needed.
|
||||
|
||||
Printf
|
||||
~~~~~~
|
||||
|
||||
The good thing about printf is that it is pretty fast and readily available
|
||||
being a part of the C standard library. The main drawback is that it
|
||||
doesn't support user-defined types. Printf also has safety issues although
|
||||
they are mostly solved with `__attribute__ ((format (printf, ...))
|
||||
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
|
||||
There is a POSIX extension that adds positional arguments required for
|
||||
`i18n <http://en.wikipedia.org/wiki/Internationalization_and_localization>`_
|
||||
to printf but it is not a part of C99 and may not be available on some
|
||||
platforms.
|
||||
|
||||
IOStreams
|
||||
~~~~~~~~~
|
||||
|
||||
The main issue with IOStreams is best illustrated with an example:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
|
||||
|
||||
which is a lot of typing compared to printf:
|
||||
|
||||
.. code:: c++
|
||||
|
||||
printf("%.2f\n", 1.23456);
|
||||
|
||||
Matthew Wilson, the author of FastFormat, referred to this situation with
|
||||
IOStreams as "chevron hell". IOStreams doesn't support positional arguments
|
||||
by design.
|
||||
|
||||
The good part is that IOStreams supports user-defined types and is safe
|
||||
although error reporting is awkward.
|
||||
|
||||
Boost Format library
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is a very powerful library which supports both printf-like format
|
||||
strings and positional arguments. The main its drawback is performance.
|
||||
According to various benchmarks it is much slower than other methods
|
||||
considered here. Boost Format also has excessive build times and severe
|
||||
code bloat issues (see `Benchmarks`_).
|
||||
|
||||
FastFormat
|
||||
~~~~~~~~~~
|
||||
|
||||
This is an interesting library which is fast, safe and has positional
|
||||
arguments. However it has significant limitations, citing its author:
|
||||
|
||||
Three features that have no hope of being accommodated within the
|
||||
current design are:
|
||||
|
||||
* Leading zeros (or any other non-space padding)
|
||||
* Octal/hexadecimal encoding
|
||||
* Runtime width/alignment specification
|
||||
|
||||
It is also quite big and has a heavy dependency, STLSoft, which might be
|
||||
too restrictive for using it in some projects.
|
||||
|
||||
Loki SafeFormat
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
SafeFormat is a formatting library which uses printf-like format strings
|
||||
and is type safe. It doesn't support user-defined types or positional
|
||||
arguments. It makes unconventional use of ``operator()`` for passing
|
||||
format arguments.
|
||||
|
||||
Tinyformat
|
||||
~~~~~~~~~~
|
||||
|
||||
This library supports printf-like format strings and is very small and
|
||||
fast. Unfortunately it doesn't support positional arguments and wrapping
|
||||
it in C++98 is somewhat difficult. Also its performance and code compactness
|
||||
are limited by IOStreams.
|
||||
|
||||
Boost Spirit.Karma
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is not really a formatting library but I decided to include it here
|
||||
for completeness. As IOStreams it suffers from the problem of mixing
|
||||
verbatim text with arguments. The library is pretty fast, but slower
|
||||
on integer formatting than ``fmt::Writer`` on Karma's own benchmark,
|
||||
see `Fast integer to string conversion in C++
|
||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||
|
||||
Benchmarks
|
||||
----------
|
||||
|
||||
Speed tests
|
||||
~~~~~~~~~~~
|
||||
|
||||
The following speed tests results were generated by building
|
||||
``tinyformat_test.cpp`` on Ubuntu GNU/Linux 14.04.1 with
|
||||
``g++-4.8.2 -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of three
|
||||
runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or
|
||||
equivalent is filled 2000000 times with output sent to ``/dev/null``; for
|
||||
further details see the `source
|
||||
<https://github.com/cppformat/format-benchmark/blob/master/tinyformat_test.cpp>`_.
|
||||
|
||||
================= ============= ===========
|
||||
Library Method Run Time, s
|
||||
================= ============= ===========
|
||||
EGLIBC 2.19 printf 1.30
|
||||
libstdc++ 4.8.2 std::ostream 1.85
|
||||
C++ Format 1.0 fmt::print 1.42
|
||||
tinyformat 2.0.1 tfm::printf 2.25
|
||||
Boost Format 1.54 boost::format 9.94
|
||||
================= ============= ===========
|
||||
|
||||
As you can see ``boost::format`` is much slower than the alternative methods; this
|
||||
is confirmed by `other tests <http://accu.org/index.php/journals/1539>`_.
|
||||
Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat
|
||||
cannot be faster than the IOStreams because it uses them internally.
|
||||
Performance of cppformat is close to that of printf, being `faster than printf on integer
|
||||
formatting <http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_,
|
||||
but slower on floating-point formatting which dominates this benchmark.
|
||||
|
||||
Compile time and code bloat
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The script `bloat-test.py
|
||||
<https://github.com/cppformat/format-benchmark/blob/master/bloat-test.py>`_
|
||||
from `format-benchmark <https://github.com/cppformat/format-benchmark>`_
|
||||
tests compile time and code bloat for nontrivial projects.
|
||||
It generates 100 translation units and uses ``printf()`` or its alternative
|
||||
five times in each to simulate a medium sized project. The resulting
|
||||
executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10,
|
||||
best of three) is shown in the following tables.
|
||||
|
||||
**Optimized build (-O3)**
|
||||
|
||||
============ =============== ==================== ==================
|
||||
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||
============ =============== ==================== ==================
|
||||
printf 2.6 41 30
|
||||
IOStreams 19.4 92 70
|
||||
C++ Format 46.8 46 34
|
||||
tinyformat 64.6 418 386
|
||||
Boost Format 222.8 990 923
|
||||
============ =============== ==================== ==================
|
||||
|
||||
As you can see, C++ Format has two times less overhead in terms of resulting
|
||||
code size compared to IOStreams and comes pretty close to ``printf``.
|
||||
Boost Format has by far the largest overheads.
|
||||
|
||||
**Non-optimized build**
|
||||
|
||||
============ =============== ==================== ==================
|
||||
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||
============ =============== ==================== ==================
|
||||
printf 2.1 41 30
|
||||
IOStreams 19.7 86 62
|
||||
C++ Format 47.9 108 86
|
||||
tinyformat 27.7 234 190
|
||||
Boost Format 122.6 884 763
|
||||
============ =============== ==================== ==================
|
||||
|
||||
``libc``, ``libstdc++`` and ``libformat`` are all linked as shared
|
||||
libraries to compare formatting function overhead only. Boost Format
|
||||
and tinyformat are header-only libraries so they don't provide any
|
||||
linkage options.
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Please refer to `Building the library`__ for the instructions on how to build
|
||||
the library and run the unit tests.
|
||||
|
||||
__ http://cppformat.github.io/latest/usage.html#building-the-library
|
||||
|
||||
Benchmarks reside in a separate repository,
|
||||
`format-benchmarks <https://github.com/cppformat/format-benchmark>`_,
|
||||
so to run the benchmarks you first need to clone this repository and
|
||||
generate Makefiles with CMake::
|
||||
|
||||
$ git clone --recursive https://github.com/cppformat/format-benchmark.git
|
||||
$ cd format-benchmark
|
||||
$ cmake .
|
||||
|
||||
Then you can run the speed test::
|
||||
|
||||
$ make speed-test
|
||||
|
||||
or the bloat test::
|
||||
|
||||
$ make bloat-test
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
C++ Format is distributed under the BSD `license
|
||||
<https://github.com/cppformat/cppformat/blob/master/LICENSE.rst>`_.
|
||||
|
||||
The `Format String Syntax
|
||||
<http://cppformat.github.io/latest/syntax.html>`_
|
||||
section in the documentation is based on the one from Python `string module
|
||||
documentation <http://docs.python.org/3/library/string.html#module-string>`_
|
||||
adapted for the current library. For this reason the documentation is
|
||||
distributed under the Python Software Foundation license available in
|
||||
`doc/python-license.txt
|
||||
<https://raw.github.com/cppformat/cppformat/master/doc/python-license.txt>`_.
|
||||
It only applies if you distribute the documentation of C++ Format.
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
`API changes/compatibility report <http://upstream-tracker.org/versions/cppformat.html>`_
|
||||
|
||||
Acknowledgments
|
||||
---------------
|
||||
|
||||
The benchmark section of this readme file and the performance tests are taken
|
||||
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`_ library
|
||||
written by Chris Foster. Boost Format library is acknowledged transitively
|
||||
since it had some influence on tinyformat.
|
||||
Some ideas used in the implementation are borrowed from `Loki
|
||||
<http://loki-lib.sourceforge.net/>`_ SafeFormat and `Diagnostic API
|
||||
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
|
||||
`Clang <http://clang.llvm.org/>`_.
|
||||
Format string syntax and the documentation are based on Python's `str.format
|
||||
<http://docs.python.org/2/library/stdtypes.html#str.format>`_.
|
||||
Thanks `Doug Turnbull <https://github.com/softwaredoug>`_ for his valuable
|
||||
comments and contribution to the design of the type-safe API and
|
||||
`Gregory Czajkowski <https://github.com/gcflymoto>`_ for implementing binary
|
||||
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensive
|
||||
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`_
|
||||
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`_ for
|
||||
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`_.
|
||||
Thanks to `CarterLi <https://github.com/CarterLi>`_ for contributing various
|
||||
improvements to the code.
|
||||
@@ -35,11 +35,18 @@
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef __MINGW32__
|
||||
# include <cstring>
|
||||
#if defined(_WIN32) && defined(__MINGW32__)
|
||||
# include <cstring>
|
||||
#endif
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
|
||||
# include <windows.h>
|
||||
# else
|
||||
# define NOMINMAX
|
||||
# include <windows.h>
|
||||
# undef NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
using fmt::internal::Arg;
|
||||
@@ -95,6 +102,7 @@ static inline fmt::internal::None<> strerror_s(char *, std::size_t, ...) {
|
||||
return fmt::internal::None<>();
|
||||
}
|
||||
|
||||
namespace fmt {
|
||||
namespace {
|
||||
|
||||
#ifndef _MSC_VER
|
||||
@@ -150,7 +158,7 @@ typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
|
||||
// Buffer should be at least of size 1.
|
||||
int safe_strerror(
|
||||
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
|
||||
assert(buffer != 0 && buffer_size != 0);
|
||||
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
|
||||
|
||||
class StrError {
|
||||
private:
|
||||
@@ -199,7 +207,10 @@ int safe_strerror(
|
||||
StrError(int error_code, char *&buffer, std::size_t buffer_size)
|
||||
: error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {}
|
||||
|
||||
int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); }
|
||||
int run() {
|
||||
strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
|
||||
return handle(strerror_r(error_code_, buffer_, buffer_size_));
|
||||
}
|
||||
};
|
||||
return StrError(error_code, buffer, buffer_size).run();
|
||||
}
|
||||
@@ -259,6 +270,11 @@ int parse_nonnegative_int(const Char *&s) {
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline bool is_name_start(Char c) {
|
||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
|
||||
}
|
||||
|
||||
inline void require_numeric_argument(const Arg &arg, char spec) {
|
||||
if (arg.type > Arg::LAST_NUMERIC_TYPE) {
|
||||
std::string message =
|
||||
@@ -379,24 +395,139 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
|
||||
arg_.int_value = static_cast<char>(value);
|
||||
}
|
||||
};
|
||||
|
||||
// This function template is used to prevent compile errors when handling
|
||||
// incompatible string arguments, e.g. handling a wide string in a narrow
|
||||
// string formatter.
|
||||
template <typename Char>
|
||||
Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
|
||||
|
||||
template <>
|
||||
inline Arg::StringValue<char> ignore_incompatible_str(
|
||||
Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
|
||||
|
||||
template <>
|
||||
inline Arg::StringValue<wchar_t> ignore_incompatible_str(
|
||||
Arg::StringValue<wchar_t> s) { return s; }
|
||||
} // namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Impl, typename Char>
|
||||
class BasicArgFormatter : public ArgVisitor<Impl, void> {
|
||||
private:
|
||||
BasicWriter<Char> &writer_;
|
||||
FormatSpec &spec_;
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
|
||||
|
||||
protected:
|
||||
BasicWriter<Char> &writer() { return writer_; }
|
||||
const FormatSpec &spec() const { return spec_; }
|
||||
|
||||
public:
|
||||
BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
|
||||
: writer_(w), spec_(s) {}
|
||||
|
||||
template <typename T>
|
||||
void visit_any_int(T value) { writer_.write_int(value, spec_); }
|
||||
|
||||
template <typename T>
|
||||
void visit_any_double(T value) { writer_.write_double(value, spec_); }
|
||||
|
||||
void visit_bool(bool value) {
|
||||
if (spec_.type_) {
|
||||
writer_.write_int(value, spec_);
|
||||
return;
|
||||
}
|
||||
const char *str_value = value ? "true" : "false";
|
||||
Arg::StringValue<char> str = { str_value, strlen(str_value) };
|
||||
writer_.write_str(str, spec_);
|
||||
}
|
||||
|
||||
void visit_char(int value) {
|
||||
if (spec_.type_ && spec_.type_ != 'c') {
|
||||
spec_.flags_ |= CHAR_FLAG;
|
||||
writer_.write_int(value, spec_);
|
||||
return;
|
||||
}
|
||||
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
|
||||
FMT_THROW(FormatError("invalid format specifier for char"));
|
||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||
Char fill = internal::CharTraits<Char>::cast(spec_.fill());
|
||||
CharPtr out = CharPtr();
|
||||
if (spec_.width_ > 1) {
|
||||
out = writer_.grow_buffer(spec_.width_);
|
||||
if (spec_.align_ == ALIGN_RIGHT) {
|
||||
std::fill_n(out, spec_.width_ - 1, fill);
|
||||
out += spec_.width_ - 1;
|
||||
} else if (spec_.align_ == ALIGN_CENTER) {
|
||||
out = writer_.fill_padding(out, spec_.width_, 1, fill);
|
||||
} else {
|
||||
std::fill_n(out + 1, spec_.width_ - 1, fill);
|
||||
}
|
||||
} else {
|
||||
out = writer_.grow_buffer(1);
|
||||
}
|
||||
*out = internal::CharTraits<Char>::cast(value);
|
||||
}
|
||||
|
||||
void visit_string(Arg::StringValue<char> value) {
|
||||
writer_.write_str(value, spec_);
|
||||
}
|
||||
|
||||
using ArgVisitor<Impl, void>::visit_wstring;
|
||||
|
||||
void visit_wstring(Arg::StringValue<Char> value) {
|
||||
writer_.write_str(value, spec_);
|
||||
}
|
||||
|
||||
void visit_pointer(const void *value) {
|
||||
if (spec_.type_ && spec_.type_ != 'p')
|
||||
report_unknown_type(spec_.type_, "pointer");
|
||||
spec_.flags_ = HASH_FLAG;
|
||||
spec_.type_ = 'x';
|
||||
writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
|
||||
}
|
||||
};
|
||||
|
||||
// An argument formatter.
|
||||
template <typename Char>
|
||||
class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
|
||||
private:
|
||||
BasicFormatter<Char> &formatter_;
|
||||
const Char *format_;
|
||||
|
||||
public:
|
||||
ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
|
||||
: BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
|
||||
formatter_(f), format_(fmt) {}
|
||||
|
||||
void visit_custom(Arg::CustomValue c) {
|
||||
c.format(&formatter_, c.value, &format_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
class PrintfArgFormatter :
|
||||
public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
|
||||
public:
|
||||
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
|
||||
: BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
|
||||
|
||||
void visit_char(int value) {
|
||||
const FormatSpec &spec = this->spec();
|
||||
BasicWriter<Char> &writer = this->writer();
|
||||
if (spec.type_ && spec.type_ != 'c')
|
||||
writer.write_int(value, spec);
|
||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||
CharPtr out = CharPtr();
|
||||
if (spec.width_ > 1) {
|
||||
Char fill = ' ';
|
||||
out = writer.grow_buffer(spec.width_);
|
||||
if (spec.align_ != ALIGN_LEFT) {
|
||||
std::fill_n(out, spec.width_ - 1, fill);
|
||||
out += spec.width_ - 1;
|
||||
} else {
|
||||
std::fill_n(out + 1, spec.width_ - 1, fill);
|
||||
}
|
||||
} else {
|
||||
out = writer.grow_buffer(1);
|
||||
}
|
||||
*out = static_cast<Char>(value);
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace fmt
|
||||
|
||||
FMT_FUNC void fmt::SystemError::init(
|
||||
int err_code, StringRef format_str, ArgList args) {
|
||||
int err_code, CStringRef format_str, ArgList args) {
|
||||
error_code_ = err_code;
|
||||
MemoryWriter w;
|
||||
internal::format_system_error(w, err_code, format(format_str, args));
|
||||
@@ -477,19 +608,20 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
|
||||
static_cast<unsigned>(code), type)));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
|
||||
int length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0);
|
||||
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
|
||||
if (length == 0)
|
||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||
buffer_.resize(length);
|
||||
buffer_.resize(length + 1);
|
||||
length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length);
|
||||
if (length == 0)
|
||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||
buffer_[length] = 0;
|
||||
}
|
||||
|
||||
FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
|
||||
@@ -500,19 +632,20 @@ FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
|
||||
}
|
||||
|
||||
FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_.resize(length);
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
|
||||
CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::WindowsError::init(
|
||||
int err_code, StringRef format_str, ArgList args) {
|
||||
int err_code, CStringRef format_str, ArgList args) {
|
||||
error_code_ = err_code;
|
||||
MemoryWriter w;
|
||||
internal::format_windows_error(w, err_code, format(format_str, args));
|
||||
@@ -520,30 +653,6 @@ FMT_FUNC void fmt::WindowsError::init(
|
||||
base = std::runtime_error(w.str());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
FMT_FUNC void fmt::internal::format_system_error(
|
||||
fmt::Writer &out, int error_code,
|
||||
fmt::StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
|
||||
buffer.resize(INLINE_BUFFER_SIZE);
|
||||
for (;;) {
|
||||
char *system_message = &buffer[0];
|
||||
int result = safe_strerror(error_code, system_message, buffer.size());
|
||||
if (result == 0) {
|
||||
out << message << ": " << system_message;
|
||||
return;
|
||||
}
|
||||
if (result != ERANGE)
|
||||
break; // Can't get error message, report error code instead.
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FMT_FUNC void fmt::internal::format_windows_error(
|
||||
fmt::Writer &out, int error_code,
|
||||
fmt::StringRef message) FMT_NOEXCEPT {
|
||||
@@ -572,81 +681,74 @@ FMT_FUNC void fmt::internal::format_windows_error(
|
||||
} FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
// An argument formatter.
|
||||
template <typename Char>
|
||||
class fmt::internal::ArgFormatter :
|
||||
public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
|
||||
private:
|
||||
fmt::BasicFormatter<Char> &formatter_;
|
||||
fmt::BasicWriter<Char> &writer_;
|
||||
fmt::FormatSpec &spec_;
|
||||
const Char *format_;
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
|
||||
|
||||
public:
|
||||
ArgFormatter(
|
||||
fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
|
||||
: formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
|
||||
|
||||
template <typename T>
|
||||
void visit_any_int(T value) { writer_.write_int(value, spec_); }
|
||||
|
||||
template <typename T>
|
||||
void visit_any_double(T value) { writer_.write_double(value, spec_); }
|
||||
|
||||
void visit_char(int value) {
|
||||
if (spec_.type_ && spec_.type_ != 'c') {
|
||||
spec_.flags_ |= CHAR_FLAG;
|
||||
writer_.write_int(value, spec_);
|
||||
return;
|
||||
}
|
||||
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
|
||||
FMT_THROW(FormatError("invalid format specifier for char"));
|
||||
typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
|
||||
Char fill = static_cast<Char>(spec_.fill());
|
||||
if (spec_.precision_ == 0) {
|
||||
std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
|
||||
return;
|
||||
}
|
||||
CharPtr out = CharPtr();
|
||||
if (spec_.width_ > 1) {
|
||||
out = writer_.grow_buffer(spec_.width_);
|
||||
if (spec_.align_ == fmt::ALIGN_RIGHT) {
|
||||
std::fill_n(out, spec_.width_ - 1, fill);
|
||||
out += spec_.width_ - 1;
|
||||
} else if (spec_.align_ == fmt::ALIGN_CENTER) {
|
||||
out = writer_.fill_padding(out, spec_.width_, 1, fill);
|
||||
} else {
|
||||
std::fill_n(out + 1, spec_.width_ - 1, fill);
|
||||
FMT_FUNC void fmt::internal::format_system_error(
|
||||
fmt::Writer &out, int error_code,
|
||||
fmt::StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
|
||||
buffer.resize(INLINE_BUFFER_SIZE);
|
||||
for (;;) {
|
||||
char *system_message = &buffer[0];
|
||||
int result = safe_strerror(error_code, system_message, buffer.size());
|
||||
if (result == 0) {
|
||||
out << message << ": " << system_message;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
out = writer_.grow_buffer(1);
|
||||
if (result != ERANGE)
|
||||
break; // Can't get error message, report error code instead.
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
*out = static_cast<Char>(value);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
void visit_string(Arg::StringValue<char> value) {
|
||||
writer_.write_str(value, spec_);
|
||||
template <typename Char>
|
||||
void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
|
||||
if (!map_.empty())
|
||||
return;
|
||||
typedef internal::NamedArg<Char> NamedArg;
|
||||
const NamedArg *named_arg = 0;
|
||||
bool use_values =
|
||||
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
|
||||
if (use_values) {
|
||||
for (unsigned i = 0;/*nothing*/; ++i) {
|
||||
internal::Arg::Type arg_type = args.type(i);
|
||||
switch (arg_type) {
|
||||
case internal::Arg::NONE:
|
||||
return;
|
||||
case internal::Arg::NAMED_ARG:
|
||||
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
|
||||
map_.insert(Pair(named_arg->name, *named_arg));
|
||||
break;
|
||||
default:
|
||||
/*nothing*/;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
void visit_wstring(Arg::StringValue<wchar_t> value) {
|
||||
writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
|
||||
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
|
||||
internal::Arg::Type arg_type = args.type(i);
|
||||
if (arg_type == internal::Arg::NAMED_ARG) {
|
||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
||||
map_.insert(Pair(named_arg->name, *named_arg));
|
||||
}
|
||||
}
|
||||
|
||||
void visit_pointer(const void *value) {
|
||||
if (spec_.type_ && spec_.type_ != 'p')
|
||||
fmt::internal::report_unknown_type(spec_.type_, "pointer");
|
||||
spec_.flags_ = fmt::HASH_FLAG;
|
||||
spec_.type_ = 'x';
|
||||
writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
|
||||
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
|
||||
switch (args.args_[i].type) {
|
||||
case internal::Arg::NONE:
|
||||
return;
|
||||
case internal::Arg::NAMED_ARG:
|
||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
||||
map_.insert(Pair(named_arg->name, *named_arg));
|
||||
break;
|
||||
default:
|
||||
/*nothing*/;
|
||||
}
|
||||
}
|
||||
|
||||
void visit_custom(Arg::CustomValue c) {
|
||||
c.format(&formatter_, c.value, &format_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
|
||||
@@ -675,6 +777,19 @@ void fmt::BasicWriter<Char>::write_str(
|
||||
write_str(str_value, str_size, spec);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline Arg fmt::BasicFormatter<Char>::get_arg(
|
||||
BasicStringRef<Char> arg_name, const char *&error) {
|
||||
if (check_no_auto_index(error)) {
|
||||
map_.init(args());
|
||||
const Arg *arg = map_.find(arg_name);
|
||||
if (arg)
|
||||
return *arg;
|
||||
error = "argument not found";
|
||||
}
|
||||
return Arg();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
|
||||
const char *error = 0;
|
||||
@@ -687,11 +802,33 @@ inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
|
||||
assert(is_name_start(*s));
|
||||
const Char *start = s;
|
||||
Char c;
|
||||
do {
|
||||
c = *++s;
|
||||
} while (is_name_start(c) || ('0' <= c && c <= '9'));
|
||||
const char *error = 0;
|
||||
Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
|
||||
if (error)
|
||||
FMT_THROW(fmt::FormatError(error));
|
||||
return arg;
|
||||
}
|
||||
|
||||
FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
|
||||
unsigned arg_index, const char *&error) {
|
||||
Arg arg = args_[arg_index];
|
||||
if (arg.type == Arg::NONE)
|
||||
switch (arg.type) {
|
||||
case Arg::NONE:
|
||||
error = "argument index out of range";
|
||||
break;
|
||||
case Arg::NAMED_ARG:
|
||||
arg = *static_cast<const internal::Arg*>(arg.pointer);
|
||||
default:
|
||||
/*nothing*/;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
@@ -702,14 +839,19 @@ inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
|
||||
return Arg();
|
||||
}
|
||||
|
||||
inline bool fmt::internal::FormatterBase::check_no_auto_index(
|
||||
const char *&error) {
|
||||
if (next_arg_index_ > 0) {
|
||||
error = "cannot switch from automatic to manual argument indexing";
|
||||
return false;
|
||||
}
|
||||
next_arg_index_ = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Arg fmt::internal::FormatterBase::get_arg(
|
||||
unsigned arg_index, const char *&error) {
|
||||
if (next_arg_index_ <= 0) {
|
||||
next_arg_index_ = -1;
|
||||
return do_get_arg(arg_index, error);
|
||||
}
|
||||
error = "cannot switch from automatic to manual argument indexing";
|
||||
return Arg();
|
||||
return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
@@ -787,7 +929,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
|
||||
|
||||
template <typename Char>
|
||||
void fmt::internal::PrintfFormatter<Char>::format(
|
||||
BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
|
||||
BasicWriter<Char> &writer, BasicCStringRef<Char> format_str,
|
||||
const ArgList &args) {
|
||||
const Char *start = format_str.c_str();
|
||||
set_args(args);
|
||||
@@ -881,73 +1023,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
|
||||
start = s;
|
||||
|
||||
// Format argument.
|
||||
switch (arg.type) {
|
||||
case Arg::INT:
|
||||
writer.write_int(arg.int_value, spec);
|
||||
break;
|
||||
case Arg::UINT:
|
||||
writer.write_int(arg.uint_value, spec);
|
||||
break;
|
||||
case Arg::LONG_LONG:
|
||||
writer.write_int(arg.long_long_value, spec);
|
||||
break;
|
||||
case Arg::ULONG_LONG:
|
||||
writer.write_int(arg.ulong_long_value, spec);
|
||||
break;
|
||||
case Arg::CHAR: {
|
||||
if (spec.type_ && spec.type_ != 'c')
|
||||
writer.write_int(arg.int_value, spec);
|
||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||
CharPtr out = CharPtr();
|
||||
if (spec.width_ > 1) {
|
||||
Char fill = ' ';
|
||||
out = writer.grow_buffer(spec.width_);
|
||||
if (spec.align_ != ALIGN_LEFT) {
|
||||
std::fill_n(out, spec.width_ - 1, fill);
|
||||
out += spec.width_ - 1;
|
||||
} else {
|
||||
std::fill_n(out + 1, spec.width_ - 1, fill);
|
||||
}
|
||||
} else {
|
||||
out = writer.grow_buffer(1);
|
||||
}
|
||||
*out = static_cast<Char>(arg.int_value);
|
||||
break;
|
||||
}
|
||||
case Arg::DOUBLE:
|
||||
writer.write_double(arg.double_value, spec);
|
||||
break;
|
||||
case Arg::LONG_DOUBLE:
|
||||
writer.write_double(arg.long_double_value, spec);
|
||||
break;
|
||||
case Arg::CSTRING:
|
||||
arg.string.size = 0;
|
||||
writer.write_str(arg.string, spec);
|
||||
break;
|
||||
case Arg::STRING:
|
||||
writer.write_str(arg.string, spec);
|
||||
break;
|
||||
case Arg::WSTRING:
|
||||
writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
|
||||
break;
|
||||
case Arg::POINTER:
|
||||
if (spec.type_ && spec.type_ != 'p')
|
||||
internal::report_unknown_type(spec.type_, "pointer");
|
||||
spec.flags_= HASH_FLAG;
|
||||
spec.type_ = 'x';
|
||||
writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
|
||||
break;
|
||||
case Arg::CUSTOM: {
|
||||
if (spec.type_)
|
||||
internal::report_unknown_type(spec.type_, "object");
|
||||
const void *str_format = "s";
|
||||
arg.custom.format(&writer, arg.custom.value, &str_format);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
|
||||
}
|
||||
write(writer, start, s);
|
||||
}
|
||||
@@ -1019,16 +1095,47 @@ const Char *fmt::BasicFormatter<Char>::format(
|
||||
++s;
|
||||
}
|
||||
|
||||
// Parse width and zero flag.
|
||||
// Parse zero flag.
|
||||
if (*s == '0') {
|
||||
require_numeric_argument(arg, '0');
|
||||
spec.align_ = ALIGN_NUMERIC;
|
||||
spec.fill_ = '0';
|
||||
++s;
|
||||
}
|
||||
|
||||
// Parse width.
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
if (*s == '0') {
|
||||
require_numeric_argument(arg, '0');
|
||||
spec.align_ = ALIGN_NUMERIC;
|
||||
spec.fill_ = '0';
|
||||
}
|
||||
// Zero may be parsed again as a part of the width, but it is simpler
|
||||
// and more efficient than checking if the next char is a digit.
|
||||
spec.width_ = parse_nonnegative_int(s);
|
||||
} else if (*s == '{') {
|
||||
++s;
|
||||
Arg width_arg = is_name_start(*s) ?
|
||||
parse_arg_name(s) : parse_arg_index(s);
|
||||
if (*s++ != '}')
|
||||
FMT_THROW(FormatError("invalid format string"));
|
||||
ULongLong value = 0;
|
||||
switch (width_arg.type) {
|
||||
case Arg::INT:
|
||||
if (width_arg.int_value < 0)
|
||||
FMT_THROW(FormatError("negative width"));
|
||||
value = width_arg.int_value;
|
||||
break;
|
||||
case Arg::UINT:
|
||||
value = width_arg.uint_value;
|
||||
break;
|
||||
case Arg::LONG_LONG:
|
||||
if (width_arg.long_long_value < 0)
|
||||
FMT_THROW(FormatError("negative width"));
|
||||
value = width_arg.long_long_value;
|
||||
break;
|
||||
case Arg::ULONG_LONG:
|
||||
value = width_arg.ulong_long_value;
|
||||
break;
|
||||
default:
|
||||
FMT_THROW(FormatError("width is not integer"));
|
||||
}
|
||||
if (value > INT_MAX)
|
||||
FMT_THROW(FormatError("number is too big"));
|
||||
spec.width_ = static_cast<int>(value);
|
||||
}
|
||||
|
||||
// Parse precision.
|
||||
@@ -1039,7 +1146,8 @@ const Char *fmt::BasicFormatter<Char>::format(
|
||||
spec.precision_ = parse_nonnegative_int(s);
|
||||
} else if (*s == '{') {
|
||||
++s;
|
||||
const Arg &precision_arg = parse_arg_index(s);
|
||||
Arg precision_arg =
|
||||
is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
|
||||
if (*s++ != '}')
|
||||
FMT_THROW(FormatError("invalid format string"));
|
||||
ULongLong value = 0;
|
||||
@@ -1069,7 +1177,7 @@ const Char *fmt::BasicFormatter<Char>::format(
|
||||
} else {
|
||||
FMT_THROW(FormatError("missing precision specifier"));
|
||||
}
|
||||
if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
|
||||
if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
|
||||
FMT_THROW(FormatError(
|
||||
fmt::format("precision not allowed in {} format specifier",
|
||||
arg.type == Arg::POINTER ? "pointer" : "integer")));
|
||||
@@ -1092,7 +1200,7 @@ const Char *fmt::BasicFormatter<Char>::format(
|
||||
|
||||
template <typename Char>
|
||||
void fmt::BasicFormatter<Char>::format(
|
||||
BasicStringRef<Char> format_str, const ArgList &args) {
|
||||
BasicCStringRef<Char> format_str, const ArgList &args) {
|
||||
const Char *s = start_ = format_str.c_str();
|
||||
set_args(args);
|
||||
while (*s) {
|
||||
@@ -1106,7 +1214,7 @@ void fmt::BasicFormatter<Char>::format(
|
||||
if (c == '}')
|
||||
FMT_THROW(FormatError("unmatched '}' in format string"));
|
||||
write(writer_, start_, s - 1);
|
||||
Arg arg = parse_arg_index(s);
|
||||
Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
|
||||
s = format(s, arg);
|
||||
}
|
||||
write(writer_, start_, s);
|
||||
@@ -1117,30 +1225,30 @@ FMT_FUNC void fmt::report_system_error(
|
||||
report_error(internal::format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void fmt::report_windows_error(
|
||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
|
||||
FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
|
||||
MemoryWriter w;
|
||||
w.write(format_str, args);
|
||||
std::fwrite(w.data(), 1, w.size(), f);
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
|
||||
FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
|
||||
print(stdout, format_str, args);
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
|
||||
FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
|
||||
MemoryWriter w;
|
||||
w.write(format_str, args);
|
||||
os.write(w.data(), w.size());
|
||||
}
|
||||
|
||||
FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
|
||||
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
|
||||
char escape[] = "\x1b[30m";
|
||||
escape[3] = '0' + static_cast<char>(c);
|
||||
std::fputs(escape, stdout);
|
||||
@@ -1148,7 +1256,7 @@ FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
|
||||
std::fputs(RESET_COLOR, stdout);
|
||||
}
|
||||
|
||||
FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
|
||||
FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
|
||||
MemoryWriter w;
|
||||
printf(w, format, args);
|
||||
std::size_t size = w.size();
|
||||
@@ -1157,6 +1265,8 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
|
||||
template struct fmt::internal::BasicData<void>;
|
||||
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
|
||||
@@ -1165,10 +1275,10 @@ template const char *fmt::BasicFormatter<char>::format(
|
||||
const char *&format_str, const fmt::internal::Arg &arg);
|
||||
|
||||
template void fmt::BasicFormatter<char>::format(
|
||||
BasicStringRef<char> format, const ArgList &args);
|
||||
CStringRef format, const ArgList &args);
|
||||
|
||||
template void fmt::internal::PrintfFormatter<char>::format(
|
||||
BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
|
||||
BasicWriter<char> &writer, CStringRef format, const ArgList &args);
|
||||
|
||||
template int fmt::internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
@@ -1186,10 +1296,10 @@ template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
|
||||
const wchar_t *&format_str, const fmt::internal::Arg &arg);
|
||||
|
||||
template void fmt::BasicFormatter<wchar_t>::format(
|
||||
BasicStringRef<wchar_t> format, const ArgList &args);
|
||||
BasicCStringRef<wchar_t> format, const ArgList &args);
|
||||
|
||||
template void fmt::internal::PrintfFormatter<wchar_t>::format(
|
||||
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
|
||||
BasicWriter<wchar_t> &writer, WCStringRef format,
|
||||
const ArgList &args);
|
||||
|
||||
template int fmt::internal::CharTraits<wchar_t>::format_float(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -83,7 +83,8 @@ fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
|
||||
fmt::report_system_error(errno, "cannot close file");
|
||||
}
|
||||
|
||||
fmt::BufferedFile::BufferedFile(fmt::StringRef filename, fmt::StringRef mode) {
|
||||
fmt::BufferedFile::BufferedFile(
|
||||
fmt::CStringRef filename, fmt::CStringRef mode) {
|
||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
|
||||
if (!file_)
|
||||
throw SystemError(errno, "cannot open file {}", filename);
|
||||
@@ -108,7 +109,7 @@ int fmt::BufferedFile::fileno() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
fmt::File::File(fmt::StringRef path, int oflag) {
|
||||
fmt::File::File(fmt::CStringRef path, int oflag) {
|
||||
int mode = S_IRUSR | S_IWUSR;
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
fd_ = -1;
|
||||
@@ -151,8 +152,8 @@ fmt::LongLong fmt::File::size() const {
|
||||
if (error != NO_ERROR)
|
||||
throw WindowsError(GetLastError(), "cannot get file size");
|
||||
}
|
||||
fmt::ULongLong size = size_upper;
|
||||
return (size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
||||
fmt::ULongLong long_size = size_upper;
|
||||
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
||||
#else
|
||||
typedef struct stat Stat;
|
||||
Stat file_stat = Stat();
|
||||
|
||||
@@ -41,10 +41,6 @@
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifdef FMT_INCLUDE_POSIX_TEST
|
||||
# include "test/posix-test.h"
|
||||
#endif
|
||||
|
||||
#ifndef FMT_POSIX
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// Fix warnings about deprecated symbols.
|
||||
@@ -185,7 +181,7 @@ public:
|
||||
#endif
|
||||
|
||||
// Opens a file.
|
||||
BufferedFile(fmt::StringRef filename, fmt::StringRef mode);
|
||||
BufferedFile(CStringRef filename, CStringRef mode);
|
||||
|
||||
// Closes the file.
|
||||
void close();
|
||||
@@ -197,10 +193,10 @@ public:
|
||||
// of MinGW that define fileno as a macro.
|
||||
int (fileno)() const;
|
||||
|
||||
void print(fmt::StringRef format_str, const ArgList &args) {
|
||||
void print(CStringRef format_str, const ArgList &args) {
|
||||
fmt::print(file_, format_str, args);
|
||||
}
|
||||
FMT_VARIADIC(void, print, fmt::StringRef)
|
||||
FMT_VARIADIC(void, print, CStringRef)
|
||||
};
|
||||
|
||||
// A file. Closed file is represented by a File object with descriptor -1.
|
||||
@@ -228,7 +224,7 @@ class File {
|
||||
File() FMT_NOEXCEPT : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a File object representing this file.
|
||||
File(fmt::StringRef path, int oflag);
|
||||
File(CStringRef path, int oflag);
|
||||
|
||||
#if !FMT_USE_RVALUE_REFERENCES
|
||||
// Emulate a move constructor and a move assignment operator if rvalue
|
||||
@@ -300,7 +296,7 @@ class File {
|
||||
void close();
|
||||
|
||||
// Returns the file size.
|
||||
fmt::LongLong size() const;
|
||||
LongLong size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
std::size_t read(void *buffer, std::size_t count);
|
||||
|
||||
Reference in New Issue
Block a user