Compare commits

..

12 Commits
3.0.1 ... 2.1.0

Author SHA1 Message Date
vitaut
ab772254ce Update version 2016-03-21 07:58:24 -07:00
vitaut
76fba46190 Update changelog 2016-03-21 07:57:06 -07:00
vitaut
d7ddd61545 Update CMake config and tests from the master branch 2016-03-17 07:25:50 -07:00
vitaut
8c16747a80 Update version 2016-03-13 10:19:25 -07:00
vitaut
038009b2e5 Install new CMake on travis 2016-03-10 08:13:34 -08:00
vitaut
ee6b5a596e Add CMake config file 2016-03-10 07:46:39 -08:00
vitaut
f5f9bf7f1f Update version 2016-03-10 07:20:20 -08:00
vitaut
613f7df021 Update changelog 2016-03-10 07:19:17 -08:00
vitaut
8c68e2ca04 Fix fileno causing compile error when #defined
Error:
expected unqualified-id before '(' token
 int fmt::BufferedFile::fileno() const {

This is an issue with Android NDK and mingw32.

c2ffa14684
2016-03-10 07:16:48 -08:00
vitaut
368b66a806 Update changelog 2016-03-10 07:12:16 -08:00
vitaut
1a166b0e1b Update docs 2016-03-10 07:00:42 -08:00
vitaut
38275fb27f Update CMake config
to version 7ee287d3d9
2016-03-10 07:00:00 -08:00
72 changed files with 5054 additions and 6650 deletions

2
.gitignore vendored
View File

@@ -9,8 +9,8 @@ bin/
*.a
*.so*
*.zip
/*.cmake
cmake_install.cmake
CPack*Config.cmake
CTestTestfile.cmake
CMakeCache.txt
CMakeFiles

View File

@@ -1,5 +1,4 @@
language: cpp
sudo: required # the doc target uses sudo to install dependencies
os:
- linux
@@ -13,9 +12,8 @@ env:
6pxmyzLHSn1ZR7OX5rfPvwM3tOyZ3H0=
matrix:
- BUILD=Doc
- BUILD=Debug STANDARD=0x
- BUILD=Release STANDARD=98
- BUILD=Release STANDARD=0x
- BUILD=Debug
- BUILD=Release
matrix:
exclude:

View File

@@ -1,10 +1,10 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fmt_static
LOCAL_MODULE_FILENAME := libfmt
LOCAL_MODULE := cppformat_static
LOCAL_MODULE_FILENAME := libcppformat
LOCAL_SRC_FILES := fmt/format.cc
LOCAL_SRC_FILES := cppformat/format.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)

View File

@@ -2,8 +2,8 @@ message(STATUS "CMake version: ${CMAKE_VERSION}")
cmake_minimum_required(VERSION 2.8.12)
# Determine if fmt is built as a subproject (using add_subdirectory)
# or if it is the master project.
# determine if cppformat is built as sub project (using add_subdirectory)
# or if it is the master project
set(MASTER_PROJECT OFF)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MASTER_PROJECT ON)
@@ -25,12 +25,12 @@ option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT})
option(FMT_TEST "Generate the test target." ${MASTER_PROJECT})
option(FMT_USE_CPP11 "Enable the addition of C++11 compiler flags." ON)
project(FMT)
project(FORMAT)
# Starting with cmake 3.0 VERSION is part of the project command.
set(FMT_VERSION 3.0.1)
if (NOT FMT_VERSION MATCHES "^([0-9]+).([0-9]+).([0-9]+)$")
message(FATAL_ERROR "Invalid version format ${FMT_VERSION}.")
# starting with cmake 3.0 VERSION is part of the project command
set(CPPFORMAT_VERSION 2.1.0)
if (NOT CPPFORMAT_VERSION MATCHES "^([0-9]+).([0-9]+).([0-9]+)$")
message(FATAL_ERROR "Invalid version format ${CPPFORMAT_VERSION}.")
endif ()
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
@@ -43,7 +43,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(cxx11)
include(testCxx11)
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wshadow -pedantic)
@@ -51,7 +51,7 @@ endif ()
if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
# If Microsoft SDK is installed create script run-msbuild.bat that
# calls SetEnv.cmd to set up build environment and runs msbuild.
# calls SetEnv.cmd to to set up build environment and runs msbuild.
# It is useful when building Visual Studio projects with the SDK
# toolchain rather than Visual Studio.
include(FindSetEnv)
@@ -72,7 +72,7 @@ else ()
check_symbol_exists(open fcntl.h HAVE_OPEN)
endif ()
add_subdirectory(fmt)
add_subdirectory(cppformat)
if (FMT_DOC)
add_subdirectory(doc)
@@ -93,13 +93,13 @@ if (MASTER_PROJECT AND EXISTS ${gitignore})
string(REPLACE "*" ".*" line "${line}")
set(ignored_files ${ignored_files} "${line}$" "${line}/")
endforeach ()
set(ignored_files ${ignored_files} ${PROJECT_BINARY_DIR}
set(ignored_files ${ignored_files}
/.git /breathe /format-benchmark sphinx/ .buildinfo .doctrees)
set(CPACK_SOURCE_GENERATOR ZIP)
set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
set(CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION})
set(CPACK_PACKAGE_NAME fmt)
set(CPACK_SOURCE_PACKAGE_FILE_NAME cppformat-${CPPFORMAT_VERSION})
set(CPACK_PACKAGE_NAME cppformat)
set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.rst)
include(CPack)
endif ()

View File

@@ -1,200 +1,8 @@
3.0.1 - 2016-11-01
------------------
* Fixed handling of thousands seperator (`#353 <https://github.com/fmtlib/fmt/issues/353>`_)
* Fixed handling of ``unsigned char`` strings (`#373 <https://github.com/fmtlib/fmt/issues/373>`_)
* Corrected buffer growth when formatting time (`#367 <https://github.com/fmtlib/fmt/issues/367>`_)
* Removed warnings under MSVC and clang (`#318 <https://github.com/fmtlib/fmt/issues/318>`_, `#250 <https://github.com/fmtlib/fmt/issues/250>`_, also merged `#385 <https://github.com/fmtlib/fmt/pull/385>`_ and `#361 <https://github.com/fmtlib/fmt/pull/361>`_). Thanks `@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_ and `@nmoehrle (Nils Moehrle) <https://github.com/nmoehrle>`_.
* Fixed compilation issues under Android (`#327 <https://github.com/fmtlib/fmt/pull/327>`_, `#345 <https://github.com/fmtlib/fmt/issues/345>`_ and `#381 <https://github.com/fmtlib/fmt/pull/381>`_), FreeBSD (`#358 <https://github.com/fmtlib/fmt/pull/358>`_), Cygwin (`#388 <https://github.com/fmtlib/fmt/issues/388>`_), MinGW (`#355 <https://github.com/fmtlib/fmt/issues/355>`_) as well as other issues (`#350 <https://github.com/fmtlib/fmt/issues/350>`_, `#366 <https://github.com/fmtlib/fmt/issues/355>`_, `#348 <https://github.com/fmtlib/fmt/pull/348>`_, `#402 <https://github.com/fmtlib/fmt/pull/402>`_, `#405 <https://github.com/fmtlib/fmt/pull/405>`_). Thanks to `@dpantele (Dmitry) <https://github.com/dpantele>`_, `@hghwng (Hugh Wang) <https://github.com/hghwng>`_, `@arvedarved (Tilman Keskinöz) <https://github.com/arvedarved>`_, `@LogicalKnight (Sean) <https://github.com/LogicalKnight>`_ and `@JanHellwig (Jan Hellwig) <https://github.com/janhellwig>`_.
* Fixed some documentation issues and extended specification (`#320 <https://github.com/fmtlib/fmt/issues/320>`_, `#333 <https://github.com/fmtlib/fmt/pull/333>`_, `#347 <https://github.com/fmtlib/fmt/issues/347>`_, `#362 <https://github.com/fmtlib/fmt/pull/362>`_). Thanks to `@smellman (Taro Matsuzawa aka. btm) <https://github.com/smellman>`_.
3.0.0 - 2016-05-07
------------------
* The project has been renamed from C++ Format (cppformat) to fmt for
consistency with the used namespace and macro prefix
(`#307 <https://github.com/fmtlib/fmt/issues/307>`_).
Library headers are now located in the ``fmt`` directory:
.. code:: c++
#include "fmt/format.h"
Including ``format.h`` from the ``cppformat`` directory is deprecated
but works via a proxy header which will be removed in the next major version.
The documentation is now available at http://fmtlib.net.
* Added support for `strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like
`date and time formatting <http://fmtlib.net/3.0.0/api.html#date-and-time-formatting>`_
(`#283 <https://github.com/fmtlib/fmt/issues/283>`_):
.. code:: c++
#include "fmt/time.h"
std::time_t t = std::time(nullptr);
// Prints "The date is 2016-04-29." (with the current date)
fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t));
* ``std::ostream`` support including formatting of user-defined types that provide
overloaded ``operator<<`` has been moved to ``fmt/ostream.h``:
.. code:: c++
#include "fmt/ostream.h"
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"
* Added support for `custom argument formatters
<http://fmtlib.net/3.0.0/api.html#argument-formatters>`_
(`#235 <https://github.com/fmtlib/fmt/issues/235>`_).
* Added support for locale-specific integer formatting with the ``n`` specifier
(`#305 <https://github.com/fmtlib/fmt/issues/305>`_):
.. code:: c++
std::setlocale(LC_ALL, "en_US.utf8");
fmt::print("cppformat: {:n}\n", 1234567); // prints 1,234,567
* Sign is now preserved when formatting an integer with an incorrect ``printf``
format specifier (`#265 <https://github.com/fmtlib/fmt/issues/265>`_):
.. code:: c++
fmt::printf("%lld", -42); // prints -42
Note that it would be an undefined behavior in ``std::printf``.
* Length modifiers such as ``ll`` are now optional in printf formatting
functions and the correct type is determined automatically
(`#255 <https://github.com/fmtlib/fmt/issues/255>`_):
.. code:: c++
fmt::printf("%d", std::numeric_limits<long long>::max());
Note that it would be an undefined behavior in ``std::printf``.
* Added initial support for custom formatters
(`#231 <https://github.com/fmtlib/fmt/issues/231>`_).
* Fixed detection of user-defined literal support on Intel C++ compiler
(`#311 <https://github.com/fmtlib/fmt/issues/311>`_,
`#312 <https://github.com/fmtlib/fmt/pull/312>`_).
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_ and
`@speth (Ray Speth) <https://github.com/speth>`_.
* Reduced compile time
(`#243 <https://github.com/fmtlib/fmt/pull/243>`_,
`#249 <https://github.com/fmtlib/fmt/pull/249>`_,
`#317 <https://github.com/fmtlib/fmt/issues/317>`_):
.. image:: https://cloud.githubusercontent.com/assets/4831417/11614060/
b9e826d2-9c36-11e5-8666-d4131bf503ef.png
.. image:: https://cloud.githubusercontent.com/assets/4831417/11614080/
6ac903cc-9c37-11e5-8165-26df6efae364.png
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
* Compile test fixes (`#313 <https://github.com/fmtlib/fmt/pull/313>`_).
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
* Documentation fixes (`#239 <https://github.com/fmtlib/fmt/pull/239>`_,
`#248 <https://github.com/fmtlib/fmt/issues/248>`_,
`#252 <https://github.com/fmtlib/fmt/issues/252>`_,
`#258 <https://github.com/fmtlib/fmt/pull/258>`_,
`#260 <https://github.com/fmtlib/fmt/issues/260>`_,
`#301 <https://github.com/fmtlib/fmt/issues/301>`_,
`#309 <https://github.com/fmtlib/fmt/pull/309>`_).
Thanks to `@ReadmeCritic <https://github.com/ReadmeCritic>`_
`@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_ and
`@jwilk (Jakub Wilk) <https://github.com/jwilk>`_.
* Fixed compiler and sanitizer warnings (
`#244 <https://github.com/fmtlib/fmt/issues/244>`_,
`#256 <https://github.com/fmtlib/fmt/pull/256>`_,
`#259 <https://github.com/fmtlib/fmt/pull/259>`_,
`#263 <https://github.com/fmtlib/fmt/issues/263>`_,
`#274 <https://github.com/fmtlib/fmt/issues/274>`_,
`#277 <https://github.com/fmtlib/fmt/pull/277>`_,
`#286 <https://github.com/fmtlib/fmt/pull/286>`_,
`#291 <https://github.com/fmtlib/fmt/issues/291>`_,
`#296 <https://github.com/fmtlib/fmt/issues/296>`_,
`#308 <https://github.com/fmtlib/fmt/issues/308>`_)
Thanks to `@mwinterb <https://github.com/mwinterb>`_,
`@pweiskircher (Patrik Weiskircher) <https://github.com/pweiskircher>`_,
`@Naios <https://github.com/Naios>`_.
* Improved compatibility with Windows Store apps
(`#280 <https://github.com/fmtlib/fmt/issues/280>`_,
`#285 <https://github.com/fmtlib/fmt/pull/285>`_)
Thanks to `@mwinterb <https://github.com/mwinterb>`_.
* Added tests of compatibility with older C++ standards
(`#273 <https://github.com/fmtlib/fmt/pull/273>`_).
Thanks to `@niosHD <https://github.com/niosHD>`_.
* Fixed Android build (`#271 <https://github.com/fmtlib/fmt/pull/271>`_).
Thanks to `@newnon <https://github.com/newnon>`_.
* Changed ``ArgMap`` to be backed by a vector instead of a map.
(`#261 <https://github.com/fmtlib/fmt/issues/261>`_,
`#262 <https://github.com/fmtlib/fmt/pull/262>`_).
Thanks to `@mwinterb <https://github.com/mwinterb>`_.
* Added ``fprintf`` overload that writes to a ``std::ostream``
(`#251 <https://github.com/fmtlib/fmt/pull/251>`_).
Thanks to `nickhutchinson (Nicholas Hutchinson) <https://github.com/nickhutchinson>`_.
* Export symbols when building a Windows DLL
(`#245 <https://github.com/fmtlib/fmt/pull/245>`_).
Thanks to `macdems (Maciek Dems) <https://github.com/macdems>`_.
* Fixed compilation on Cygwin (`#304 <https://github.com/fmtlib/fmt/issues/304>`_).
* Implemented a workaround for a bug in Apple LLVM version 4.2 of clang
(`#276 <https://github.com/fmtlib/fmt/issues/276>`_).
* Implemented a workaround for Google Test bug
`#705 <https://github.com/google/googletest/issues/705>`_ on gcc 6
(`#268 <https://github.com/fmtlib/fmt/issues/268>`_).
Thanks to `octoploid <https://github.com/octoploid>`_.
* Removed Biicode support because the latter has been discontinued.
2.1.1 - 2016-04-11
------------------
* The install location for generated CMake files is now configurable via
the ``FMT_CMAKE_DIR`` CMake variable
(`#299 <https://github.com/fmtlib/fmt/pull/299>`_).
Thanks to `@niosHD <https://github.com/niosHD>`_.
* Documentation fixes (`#252 <https://github.com/fmtlib/fmt/issues/252>`_).
2.1.0 - 2016-03-21
------------------
* Project layout and build system improvements
(`#267 <https://github.com/fmtlib/fmt/pull/267>`_):
(`#267 <https://github.com/cppformat/cppformat/pull/267>`_):
* The code have been moved to the ``cppformat`` directory.
Including ``format.h`` from the top-level directory is deprecated
@@ -216,16 +24,16 @@
------------------
* Improved CMake find and package support
(`#264 <https://github.com/fmtlib/fmt/issues/264>`_).
(`#264 <https://github.com/cppformat/cppformat/issues/264>`_).
Thanks to `@niosHD <https://github.com/niosHD>`_.
* Fix compile error with Android NDK and mingw32
(`#241 <https://github.com/fmtlib/fmt/issues/241>`_).
(`#241 <https://github.com/cppformat/cppformat/issues/241>`_).
Thanks to `@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_.
* Documentation fixes
(`#248 <https://github.com/fmtlib/fmt/issues/248>`_,
`#260 <https://github.com/fmtlib/fmt/issues/260>`_).
(`#248 <https://github.com/cppformat/cppformat/issues/248>`_,
`#260 <https://github.com/cppformat/cppformat/issues/260>`_).
2.0.0 - 2015-12-01
------------------
@@ -234,9 +42,9 @@ General
~~~~~~~
* [Breaking] Named arguments
(`#169 <https://github.com/fmtlib/fmt/pull/169>`_,
`#173 <https://github.com/fmtlib/fmt/pull/173>`_,
`#174 <https://github.com/fmtlib/fmt/pull/174>`_):
(`#169 <https://github.com/cppformat/cppformat/pull/169>`_,
`#173 <https://github.com/cppformat/cppformat/pull/173>`_,
`#174 <https://github.com/cppformat/cppformat/pull/174>`_):
.. code:: c++
@@ -245,9 +53,9 @@ General
Thanks to `@jamboree <https://github.com/jamboree>`_.
* [Experimental] User-defined literals for format and named arguments
(`#204 <https://github.com/fmtlib/fmt/pull/204>`_,
`#206 <https://github.com/fmtlib/fmt/pull/206>`_,
`#207 <https://github.com/fmtlib/fmt/pull/207>`_):
(`#204 <https://github.com/cppformat/cppformat/pull/204>`_,
`#206 <https://github.com/cppformat/cppformat/pull/206>`_,
`#207 <https://github.com/cppformat/cppformat/pull/207>`_):
.. code:: c++
@@ -258,11 +66,11 @@ General
* [Breaking] Formatting of more than 16 arguments is now supported when using
variadic templates
(`#141 <https://github.com/fmtlib/fmt/issues/141>`_).
(`#141 <https://github.com/cppformat/cppformat/issues/141>`_).
Thanks to `@Shauren <https://github.com/Shauren>`_.
* Runtime width specification
(`#168 <https://github.com/fmtlib/fmt/pull/168>`_):
(`#168 <https://github.com/cppformat/cppformat/pull/168>`_):
.. code:: c++
@@ -272,10 +80,10 @@ General
* [Breaking] Enums are now formatted with an overloaded ``std::ostream`` insertion
operator (``operator<<``) if available
(`#232 <https://github.com/fmtlib/fmt/issues/232>`_).
(`#232 <https://github.com/cppformat/cppformat/issues/232>`_).
* [Breaking] Changed default ``bool`` format to textual, "true" or "false"
(`#170 <https://github.com/fmtlib/fmt/issues/170>`_):
(`#170 <https://github.com/cppformat/cppformat/issues/170>`_):
.. code:: c++
@@ -289,7 +97,7 @@ General
* ``fmt::printf`` and ``fmt::sprintf`` now support formatting of ``bool`` with the
``%s`` specifier giving textual output, "true" or "false"
(`#223 <https://github.com/fmtlib/fmt/pull/223>`_):
(`#223 <https://github.com/cppformat/cppformat/pull/223>`_):
.. code:: c++
@@ -298,10 +106,10 @@ General
Thanks to `@LarsGullik <https://github.com/LarsGullik>`_.
* [Breaking] ``signed char`` and ``unsigned char`` are now formatted as integers by default
(`#217 <https://github.com/fmtlib/fmt/pull/217>`_).
(`#217 <https://github.com/cppformat/cppformat/pull/217>`_).
* [Breaking] Pointers to C strings can now be formatted with the ``p`` specifier
(`#223 <https://github.com/fmtlib/fmt/pull/223>`_):
(`#223 <https://github.com/cppformat/cppformat/pull/223>`_):
.. code:: c++
@@ -311,12 +119,12 @@ General
* [Breaking] ``fmt::printf`` and ``fmt::sprintf`` now print null pointers as ``(nil)``
and null strings as ``(null)`` for consistency with glibc
(`#226 <https://github.com/fmtlib/fmt/pull/226>`_).
(`#226 <https://github.com/cppformat/cppformat/pull/226>`_).
Thanks to `@LarsGullik <https://github.com/LarsGullik>`_.
* [Breaking] ``fmt::(s)printf`` now supports formatting of objects of user-defined types
that provide an overloaded ``std::ostream`` insertion operator (``operator<<``)
(`#201 <https://github.com/fmtlib/fmt/issues/201>`_):
(`#201 <https://github.com/cppformat/cppformat/issues/201>`_):
.. code:: c++
@@ -324,15 +132,15 @@ General
* [Breaking] The ``Buffer`` template is now part of the public API and can be used
to implement custom memory buffers
(`#140 <https://github.com/fmtlib/fmt/issues/140>`_).
(`#140 <https://github.com/cppformat/cppformat/issues/140>`_).
Thanks to `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_.
* [Breaking] Improved compatibility between ``BasicStringRef`` and
`std::experimental::basic_string_view
<http://en.cppreference.com/w/cpp/experimental/basic_string_view>`_
(`#100 <https://github.com/fmtlib/fmt/issues/100>`_,
`#159 <https://github.com/fmtlib/fmt/issues/159>`_,
`#183 <https://github.com/fmtlib/fmt/issues/183>`_):
(`#100 <https://github.com/cppformat/cppformat/issues/100>`_,
`#159 <https://github.com/cppformat/cppformat/issues/159>`_,
`#183 <https://github.com/cppformat/cppformat/issues/183>`_):
- Comparison operators now compare string content, not pointers
- ``BasicStringRef::c_str`` replaced by ``BasicStringRef::data``
@@ -342,40 +150,40 @@ General
``BasicCStringRef``.
* Dependency on pthreads introduced by Google Test is now optional
(`#185 <https://github.com/fmtlib/fmt/issues/185>`_).
(`#185 <https://github.com/cppformat/cppformat/issues/185>`_).
* New CMake options ``FMT_DOC``, ``FMT_INSTALL`` and ``FMT_TEST`` to control
generation of ``doc``, ``install`` and ``test`` targets respectively, on by default
(`#197 <https://github.com/fmtlib/fmt/issues/197>`_,
`#198 <https://github.com/fmtlib/fmt/issues/198>`_,
`#200 <https://github.com/fmtlib/fmt/issues/200>`_).
(`#197 <https://github.com/cppformat/cppformat/issues/197>`_,
`#198 <https://github.com/cppformat/cppformat/issues/198>`_,
`#200 <https://github.com/cppformat/cppformat/issues/200>`_).
Thanks to `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* ``noexcept`` is now used when compiling with MSVC2015
(`#215 <https://github.com/fmtlib/fmt/pull/215>`_).
(`#215 <https://github.com/cppformat/cppformat/pull/215>`_).
Thanks to `@dmkrepo (Dmitriy) <https://github.com/dmkrepo>`_.
* Added an option to disable use of ``windows.h`` when ``FMT_USE_WINDOWS_H``
is defined as 0 before including ``format.h``
(`#171 <https://github.com/fmtlib/fmt/issues/171>`_).
(`#171 <https://github.com/cppformat/cppformat/issues/171>`_).
Thanks to `@alfps (Alf P. Steinbach) <https://github.com/alfps>`_.
* [Breaking] ``windows.h`` is now included with ``NOMINMAX`` unless
``FMT_WIN_MINMAX`` is defined. This is done to prevent breaking code using
``std::min`` and ``std::max`` and only affects the header-only configuration
(`#152 <https://github.com/fmtlib/fmt/issues/152>`_,
`#153 <https://github.com/fmtlib/fmt/pull/153>`_,
`#154 <https://github.com/fmtlib/fmt/pull/154>`_).
(`#152 <https://github.com/cppformat/cppformat/issues/152>`_,
`#153 <https://github.com/cppformat/cppformat/pull/153>`_,
`#154 <https://github.com/cppformat/cppformat/pull/154>`_).
Thanks to `@DevO2012 <https://github.com/DevO2012>`_.
* Improved support for custom character types
(`#171 <https://github.com/fmtlib/fmt/issues/171>`_).
(`#171 <https://github.com/cppformat/cppformat/issues/171>`_).
Thanks to `@alfps (Alf P. Steinbach) <https://github.com/alfps>`_.
* Added an option to disable use of IOStreams when ``FMT_USE_IOSTREAMS``
is defined as 0 before including ``format.h``
(`#205 <https://github.com/fmtlib/fmt/issues/205>`_,
`#208 <https://github.com/fmtlib/fmt/pull/208>`_).
(`#205 <https://github.com/cppformat/cppformat/issues/205>`_,
`#208 <https://github.com/cppformat/cppformat/pull/208>`_).
Thanks to `@JodiTheTigger <https://github.com/JodiTheTigger>`_.
* Improved detection of ``isnan``, ``isinf`` and ``signbit``.
@@ -384,31 +192,31 @@ Optimization
~~~~~~~~~~~~
* Made formatting of user-defined types more efficient with a custom stream buffer
(`#92 <https://github.com/fmtlib/fmt/issues/92>`_,
`#230 <https://github.com/fmtlib/fmt/pull/230>`_).
(`#92 <https://github.com/cppformat/cppformat/issues/92>`_,
`#230 <https://github.com/cppformat/cppformat/pull/230>`_).
Thanks to `@NotImplemented <https://github.com/NotImplemented>`_.
* Further improved performance of ``fmt::Writer`` on integer formatting
and fixed a minor regression. Now it is ~7% faster than ``karma::generate``
on Karma's benchmark
(`#186 <https://github.com/fmtlib/fmt/issues/186>`_).
(`#186 <https://github.com/cppformat/cppformat/issues/186>`_).
* [Breaking] Reduced `compiled code size
<https://github.com/fmtlib/fmt#compile-time-and-code-bloat>`_
(`#143 <https://github.com/fmtlib/fmt/issues/143>`_,
`#149 <https://github.com/fmtlib/fmt/pull/149>`_).
<https://github.com/cppformat/cppformat#compile-time-and-code-bloat>`_
(`#143 <https://github.com/cppformat/cppformat/issues/143>`_,
`#149 <https://github.com/cppformat/cppformat/pull/149>`_).
Distribution
~~~~~~~~~~~~
* [Breaking] Headers are now installed in
``${CMAKE_INSTALL_PREFIX}/include/cppformat``
(`#178 <https://github.com/fmtlib/fmt/issues/178>`_).
(`#178 <https://github.com/cppformat/cppformat/issues/178>`_).
Thanks to `@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_.
* [Breaking] Changed the library name from ``format`` to ``cppformat``
for consistency with the project name and to avoid potential conflicts
(`#178 <https://github.com/fmtlib/fmt/issues/178>`_).
(`#178 <https://github.com/cppformat/cppformat/issues/178>`_).
Thanks to `@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_.
* C++ Format is now available in `Debian <https://www.debian.org/>`_ GNU/Linux
@@ -416,7 +224,7 @@ Distribution
`sid <https://packages.debian.org/source/sid/cppformat>`_) and
derived distributions such as
`Ubuntu <https://launchpad.net/ubuntu/+source/cppformat>`_ 15.10 and later
(`#155 <https://github.com/fmtlib/fmt/issues/155>`_)::
(`#155 <https://github.com/cppformat/cppformat/issues/155>`_)::
$ sudo apt-get install libcppformat1-dev
@@ -426,7 +234,7 @@ Distribution
are now available. Thanks to Dave Johansen.
* C++ Format can now be installed via `Homebrew <http://brew.sh/>`_ on OS X
(`#157 <https://github.com/fmtlib/fmt/issues/157>`_)::
(`#157 <https://github.com/cppformat/cppformat/issues/157>`_)::
$ brew install cppformat
@@ -437,47 +245,47 @@ Documentation
* Migrated from ReadTheDocs to GitHub Pages for better responsiveness
and reliability
(`#128 <https://github.com/fmtlib/fmt/issues/128>`_).
(`#128 <https://github.com/cppformat/cppformat/issues/128>`_).
New documentation address is http://cppformat.github.io/.
* Added `Building the documentation
<http://fmtlib.net/2.0.0/usage.html#building-the-documentation>`_
<http://cppformat.github.io/dev/usage.html#building-the-documentation>`_
section to the documentation.
* Documentation build script is now compatible with Python 3 and newer pip versions.
(`#189 <https://github.com/fmtlib/fmt/pull/189>`_,
`#209 <https://github.com/fmtlib/fmt/issues/209>`_).
(`#189 <https://github.com/cppformat/cppformat/pull/189>`_,
`#209 <https://github.com/cppformat/cppformat/issues/209>`_).
Thanks to `@JodiTheTigger <https://github.com/JodiTheTigger>`_ and
`@xentec <https://github.com/xentec>`_.
* Documentation fixes and improvements
(`#36 <https://github.com/fmtlib/fmt/issues/36>`_,
`#75 <https://github.com/fmtlib/fmt/issues/75>`_,
`#125 <https://github.com/fmtlib/fmt/issues/125>`_,
`#160 <https://github.com/fmtlib/fmt/pull/160>`_,
`#161 <https://github.com/fmtlib/fmt/pull/161>`_,
`#162 <https://github.com/fmtlib/fmt/issues/162>`_,
`#165 <https://github.com/fmtlib/fmt/issues/165>`_,
`#210 <https://github.com/fmtlib/fmt/issues/210>`_).
(`#36 <https://github.com/cppformat/cppformat/issues/36>`_,
`#75 <https://github.com/cppformat/cppformat/issues/75>`_,
`#125 <https://github.com/cppformat/cppformat/issues/125>`_,
`#160 <https://github.com/cppformat/cppformat/pull/160>`_,
`#161 <https://github.com/cppformat/cppformat/pull/161>`_,
`#162 <https://github.com/cppformat/cppformat/issues/162>`_,
`#165 <https://github.com/cppformat/cppformat/issues/165>`_,
`#210 <https://github.com/cppformat/cppformat/issues/210>`_).
Thanks to `@syohex (Syohei YOSHIDA) <https://github.com/syohex>`_ and
bug reporters.
* Fixed out-of-tree documentation build
(`#177 <https://github.com/fmtlib/fmt/issues/177>`_).
(`#177 <https://github.com/cppformat/cppformat/issues/177>`_).
Thanks to `@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_.
Fixes
~~~~~
* Fixed ``initializer_list`` detection
(`#136 <https://github.com/fmtlib/fmt/issues/136>`_).
(`#136 <https://github.com/cppformat/cppformat/issues/136>`_).
Thanks to `@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_.
* [Breaking] Fixed formatting of enums with numeric format specifiers in
``fmt::(s)printf``
(`#131 <https://github.com/fmtlib/fmt/issues/131>`_,
`#139 <https://github.com/fmtlib/fmt/issues/139>`_):
(`#131 <https://github.com/cppformat/cppformat/issues/131>`_,
`#139 <https://github.com/cppformat/cppformat/issues/139>`_):
.. code:: c++
@@ -487,53 +295,51 @@ Fixes
Thanks to `@Naios <https://github.com/Naios>`_.
* Improved compatibility with old versions of MinGW
(`#129 <https://github.com/fmtlib/fmt/issues/129>`_,
`#130 <https://github.com/fmtlib/fmt/pull/130>`_,
`#132 <https://github.com/fmtlib/fmt/issues/132>`_).
(`#129 <https://github.com/cppformat/cppformat/issues/129>`_,
`#130 <https://github.com/cppformat/cppformat/pull/130>`_,
`#132 <https://github.com/cppformat/cppformat/issues/132>`_).
Thanks to `@cstamford (Christopher Stamford) <https://github.com/cstamford>`_.
* Fixed a compile error on MSVC with disabled exceptions
(`#144 <https://github.com/fmtlib/fmt/issues/144>`_).
(`#144 <https://github.com/cppformat/cppformat/issues/144>`_).
* Added a workaround for broken implementation of variadic templates in MSVC2012
(`#148 <https://github.com/fmtlib/fmt/issues/148>`_).
(`#148 <https://github.com/cppformat/cppformat/issues/148>`_).
* Placed the anonymous namespace within ``fmt`` namespace for the header-only
configuration
(`#171 <https://github.com/fmtlib/fmt/issues/171>`_).
(`#171 <https://github.com/cppformat/cppformat/issues/171>`_).
Thanks to `@alfps (Alf P. Steinbach) <https://github.com/alfps>`_.
* Fixed issues reported by Coverity Scan
(`#187 <https://github.com/fmtlib/fmt/issues/187>`_,
`#192 <https://github.com/fmtlib/fmt/issues/192>`_).
(`#187 <https://github.com/cppformat/cppformat/issues/187>`_,
`#192 <https://github.com/cppformat/cppformat/issues/192>`_).
* Implemented a workaround for a name lookup bug in MSVC2010
(`#188 <https://github.com/fmtlib/fmt/issues/188>`_).
(`#188 <https://github.com/cppformat/cppformat/issues/188>`_).
* Fixed compiler warnings
(`#95 <https://github.com/fmtlib/fmt/issues/95>`_,
`#96 <https://github.com/fmtlib/fmt/issues/96>`_,
`#114 <https://github.com/fmtlib/fmt/pull/114>`_,
`#135 <https://github.com/fmtlib/fmt/issues/135>`_,
`#142 <https://github.com/fmtlib/fmt/issues/142>`_,
`#145 <https://github.com/fmtlib/fmt/issues/145>`_,
`#146 <https://github.com/fmtlib/fmt/issues/146>`_,
`#158 <https://github.com/fmtlib/fmt/issues/158>`_,
`#163 <https://github.com/fmtlib/fmt/issues/163>`_,
`#175 <https://github.com/fmtlib/fmt/issues/175>`_,
`#190 <https://github.com/fmtlib/fmt/issues/190>`_,
`#191 <https://github.com/fmtlib/fmt/pull/191>`_,
`#194 <https://github.com/fmtlib/fmt/issues/194>`_,
`#196 <https://github.com/fmtlib/fmt/pull/196>`_,
`#216 <https://github.com/fmtlib/fmt/issues/216>`_,
`#218 <https://github.com/fmtlib/fmt/pull/218>`_,
`#220 <https://github.com/fmtlib/fmt/pull/220>`_,
`#229 <https://github.com/fmtlib/fmt/pull/229>`_,
`#233 <https://github.com/fmtlib/fmt/issues/233>`_,
`#234 <https://github.com/fmtlib/fmt/issues/234>`_,
`#236 <https://github.com/fmtlib/fmt/pull/236>`_,
`#281 <https://github.com/fmtlib/fmt/issues/281>`_,
`#289 <https://github.com/fmtlib/fmt/issues/289>`_).
(`#95 <https://github.com/cppformat/cppformat/issues/95>`_,
`#96 <https://github.com/cppformat/cppformat/issues/96>`_,
`#114 <https://github.com/cppformat/cppformat/pull/114>`_,
`#135 <https://github.com/cppformat/cppformat/issues/135>`_,
`#142 <https://github.com/cppformat/cppformat/issues/142>`_,
`#145 <https://github.com/cppformat/cppformat/issues/145>`_,
`#146 <https://github.com/cppformat/cppformat/issues/146>`_,
`#158 <https://github.com/cppformat/cppformat/issues/158>`_,
`#163 <https://github.com/cppformat/cppformat/issues/163>`_,
`#175 <https://github.com/cppformat/cppformat/issues/175>`_,
`#190 <https://github.com/cppformat/cppformat/issues/190>`_,
`#191 <https://github.com/cppformat/cppformat/pull/191>`_,
`#194 <https://github.com/cppformat/cppformat/issues/194>`_,
`#196 <https://github.com/cppformat/cppformat/pull/196>`_,
`#216 <https://github.com/cppformat/cppformat/issues/216>`_,
`#218 <https://github.com/cppformat/cppformat/pull/218>`_,
`#220 <https://github.com/cppformat/cppformat/pull/220>`_,
`#229 <https://github.com/cppformat/cppformat/pull/229>`_,
`#233 <https://github.com/cppformat/cppformat/issues/233>`_,
`#234 <https://github.com/cppformat/cppformat/issues/234>`_,
`#236 <https://github.com/cppformat/cppformat/pull/236>`_).
Thanks to `@seanmiddleditch (Sean Middleditch) <https://github.com/seanmiddleditch>`_,
`@dixlorenz (Dix Lorenz) <https://github.com/dixlorenz>`_,
`@CarterLi (李通洲) <https://github.com/CarterLi>`_,
@@ -550,36 +356,36 @@ Fixes
* Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le,
s390x and SunOS 5.11 i386 (
`#138 <https://github.com/fmtlib/fmt/issues/138>`_,
`#179 <https://github.com/fmtlib/fmt/issues/179>`_,
`#180 <https://github.com/fmtlib/fmt/issues/180>`_,
`#202 <https://github.com/fmtlib/fmt/issues/202>`_,
`#225 <https://github.com/fmtlib/fmt/issues/225>`_,
`#138 <https://github.com/cppformat/cppformat/issues/138>`_,
`#179 <https://github.com/cppformat/cppformat/issues/179>`_,
`#180 <https://github.com/cppformat/cppformat/issues/180>`_,
`#202 <https://github.com/cppformat/cppformat/issues/202>`_,
`#225 <https://github.com/cppformat/cppformat/issues/225>`_,
`Red Hat Bugzilla Bug 1260297 <https://bugzilla.redhat.com/show_bug.cgi?id=1260297>`_).
Thanks to `@Naios <https://github.com/Naios>`_,
`@jackyf (Eugene V. Lyubimkin) <https://github.com/jackyf>`_ and Dave Johansen.
* Fixed a name conflict with macro ``free`` defined in
``crtdbg.h`` when ``_CRTDBG_MAP_ALLOC`` is set
(`#211 <https://github.com/fmtlib/fmt/issues/211>`_).
(`#211 <https://github.com/cppformat/cppformat/issues/211>`_).
* Fixed shared library build on OS X
(`#212 <https://github.com/fmtlib/fmt/pull/212>`_).
(`#212 <https://github.com/cppformat/cppformat/pull/212>`_).
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
* Fixed an overload conflict on MSVC when ``/Zc:wchar_t-`` option is specified
(`#214 <https://github.com/fmtlib/fmt/pull/214>`_).
(`#214 <https://github.com/cppformat/cppformat/pull/214>`_).
Thanks to `@slavanap (Vyacheslav Napadovsky) <https://github.com/slavanap>`_.
* Improved compatibility with MSVC 2008
(`#236 <https://github.com/fmtlib/fmt/pull/236>`_).
(`#236 <https://github.com/cppformat/cppformat/pull/236>`_).
Thanks to `@Jopie64 (Johan) <https://github.com/Jopie64>`_.
* Improved compatibility with bcc32
(`#227 <https://github.com/fmtlib/fmt/issues/227>`_).
(`#227 <https://github.com/cppformat/cppformat/issues/227>`_).
* Fixed ``static_assert`` detection on Clang
(`#228 <https://github.com/fmtlib/fmt/pull/228>`_).
(`#228 <https://github.com/cppformat/cppformat/pull/228>`_).
Thanks to `@dean0x7d (Dean Moldovan) <https://github.com/dean0x7d>`_.
1.1.0 - 2015-03-06
@@ -587,8 +393,8 @@ Fixes
* Added ``BasicArrayWriter``, a class template that provides operations for
formatting and writing data into a fixed-size array
(`#105 <https://github.com/fmtlib/fmt/issues/105>`_ and
`#122 <https://github.com/fmtlib/fmt/issues/122>`_):
(`#105 <https://github.com/cppformat/cppformat/issues/105>`_ and
`#122 <https://github.com/cppformat/cppformat/issues/122>`_):
.. code:: c++
@@ -600,58 +406,58 @@ Fixes
<http://www.polserver.com/>`_ to the list of notable projects using C++ Format.
* C++ Format now uses MSVC intrinsics for better formatting performance
(`#115 <https://github.com/fmtlib/fmt/pull/115>`_,
`#116 <https://github.com/fmtlib/fmt/pull/116>`_,
`#118 <https://github.com/fmtlib/fmt/pull/118>`_ and
`#121 <https://github.com/fmtlib/fmt/pull/121>`_).
(`#115 <https://github.com/cppformat/cppformat/pull/115>`_,
`#116 <https://github.com/cppformat/cppformat/pull/116>`_,
`#118 <https://github.com/cppformat/cppformat/pull/118>`_ and
`#121 <https://github.com/cppformat/cppformat/pull/121>`_).
Previously these optimizations where only used on GCC and Clang.
Thanks to `@CarterLi <https://github.com/CarterLi>`_ and
`@objectx <https://github.com/objectx>`_.
* CMake install target (`#119 <https://github.com/fmtlib/fmt/pull/119>`_).
* CMake install target (`#119 <https://github.com/cppformat/cppformat/pull/119>`_).
Thanks to `@TrentHouliston <https://github.com/TrentHouliston>`_.
You can now install C++ Format with ``make install`` command.
* Improved `Biicode <http://www.biicode.com/>`_ support
(`#98 <https://github.com/fmtlib/fmt/pull/98>`_ and
`#104 <https://github.com/fmtlib/fmt/pull/104>`_). Thanks to
(`#98 <https://github.com/cppformat/cppformat/pull/98>`_ and
`#104 <https://github.com/cppformat/cppformat/pull/104>`_). Thanks to
`@MariadeAnton <https://github.com/MariadeAnton>`_ and
`@franramirez688 <https://github.com/franramirez688>`_.
* Improved support for building with `Android NDK
* Improved support for bulding with `Android NDK
<https://developer.android.com/tools/sdk/ndk/index.html>`_
(`#107 <https://github.com/fmtlib/fmt/pull/107>`_).
(`#107 <https://github.com/cppformat/cppformat/pull/107>`_).
Thanks to `@newnon <https://github.com/newnon>`_.
The `android-ndk-example <https://github.com/fmtlib/android-ndk-example>`_
The `android-ndk-example <https://github.com/cppformat/android-ndk-example>`_
repository provides and example of using C++ Format with Android NDK:
.. image:: https://raw.githubusercontent.com/fmtlib/android-ndk-example/
.. image:: https://raw.githubusercontent.com/cppformat/android-ndk-example/
master/screenshot.png
* Improved documentation of ``SystemError`` and ``WindowsError``
(`#54 <https://github.com/fmtlib/fmt/issues/54>`_).
(`#54 <https://github.com/cppformat/cppformat/issues/54>`_).
* Various code improvements
(`#110 <https://github.com/fmtlib/fmt/pull/110>`_,
`#111 <https://github.com/fmtlib/fmt/pull/111>`_
`#112 <https://github.com/fmtlib/fmt/pull/112>`_).
(`#110 <https://github.com/cppformat/cppformat/pull/110>`_,
`#111 <https://github.com/cppformat/cppformat/pull/111>`_
`#112 <https://github.com/cppformat/cppformat/pull/112>`_).
Thanks to `@CarterLi <https://github.com/CarterLi>`_.
* Improved compile-time errors when formatting wide into narrow strings
(`#117 <https://github.com/fmtlib/fmt/issues/117>`_).
(`#117 <https://github.com/cppformat/cppformat/issues/117>`_).
* Fixed ``BasicWriter::write`` without formatting arguments when C++11 support
is disabled (`#109 <https://github.com/fmtlib/fmt/issues/109>`_).
is disabled (`#109 <https://github.com/cppformat/cppformat/issues/109>`_).
* Fixed header-only build on OS X with GCC 4.9
(`#124 <https://github.com/fmtlib/fmt/issues/124>`_).
(`#124 <https://github.com/cppformat/cppformat/issues/124>`_).
* Fixed packaging issues (`#94 <https://github.com/fmtlib/fmt/issues/94>`_).
* Fixed packaging issues (`#94 <https://github.com/cppformat/cppformat/issues/94>`_).
* Added `changelog <https://github.com/fmtlib/fmt/blob/master/ChangeLog.rst>`_
(`#103 <https://github.com/fmtlib/fmt/issues/103>`_).
* 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
------------------
@@ -666,29 +472,29 @@ Fixes
* Compute string length in the constructor of ``BasicStringRef``
instead of the ``size`` method
(`#79 <https://github.com/fmtlib/fmt/issues/79>`_).
(`#79 <https://github.com/cppformat/cppformat/issues/79>`_).
This eliminates size computation for string literals on reasonable optimizing
compilers.
* Fix formatting of types with overloaded ``operator <<`` for ``std::wostream``
(`#86 <https://github.com/fmtlib/fmt/issues/86>`_):
(`#86 <https://github.com/cppformat/cppformat/issues/86>`_):
.. code:: c++
fmt::format(L"The date is {0}", Date(2012, 12, 9));
* Fix linkage of tests on Arch Linux
(`#89 <https://github.com/fmtlib/fmt/issues/89>`_).
(`#89 <https://github.com/cppformat/cppformat/issues/89>`_).
* Allow precision specifier for non-float arguments
(`#90 <https://github.com/fmtlib/fmt/issues/90>`_):
(`#90 <https://github.com/cppformat/cppformat/issues/90>`_):
.. code:: c++
fmt::print("{:.3}\n", "Carpet"); // prints "Car"
* Fix build on Android NDK
(`#93 <https://github.com/fmtlib/fmt/issues/93>`_)
(`#93 <https://github.com/cppformat/cppformat/issues/93>`_)
* Improvements to documentation build procedure.
@@ -729,17 +535,17 @@ Fixes
This doesn't affect the formatting API.
* Support for custom memory allocators
(`#69 <https://github.com/fmtlib/fmt/issues/69>`_)
(`#69 <https://github.com/cppformat/cppformat/issues/69>`_)
* Formatting functions now accept `signed char` and `unsigned char` strings as
arguments (`#73 <https://github.com/fmtlib/fmt/issues/73>`_):
arguments (`#73 <https://github.com/cppformat/cppformat/issues/73>`_):
.. code:: c++
auto s = format("GLSL version: {}", glGetString(GL_VERSION));
* Reduced code bloat. According to the new `benchmark results
<https://github.com/fmtlib/fmt#compile-time-and-code-bloat>`_,
<https://github.com/cppformat/cppformat#compile-time-and-code-bloat>`_,
cppformat is close to ``printf`` and by the order of magnitude better than
Boost Format in terms of compiled code size.
@@ -769,7 +575,7 @@ Fixes
fmt::printf("%1$s, %3$d %2$s", weekday, month, day);
* Arguments of ``char`` type can now be formatted as integers
(Issue `#55 <https://github.com/fmtlib/fmt/issues/55>`_):
(Issue `#55 <https://github.com/cppformat/cppformat/issues/55>`_):
.. code:: c++
@@ -805,7 +611,7 @@ Fixes
Apart from a more natural syntax, this also improves performance as there
is no need to construct temporary formatter objects and control arguments'
lifetimes. Because the wrapper functions are very lightweight, this doesn't
lifetimes. Because the wrapper functions are very ligthweight, this doesn't
cause code bloat even in pre-C++11 mode.
* Simplified common case of formatting an ``std::string``. Now it requires a
@@ -838,7 +644,7 @@ Fixes
Now all public functions are lowercase following the standard library
conventions. Previously it was a combination of lowercase and
CapitalizedWords.
Issue `#50 <https://github.com/fmtlib/fmt/issues/50>`_.
Issue `#50 <https://github.com/cppformat/cppformat/issues/50>`_.
* Old functions are marked as deprecated and will be removed in the next
release.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2012 - 2016, Victor Zverovich
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.

View File

@@ -1,64 +1,62 @@
{fmt}
=====
C++ Format
==========
.. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master
:target: https://travis-ci.org/fmtlib/fmt
.. 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/ehjkiefde6gucy1v
:target: https://ci.appveyor.com/project/vitaut/fmt
.. image:: https://ci.appveyor.com/api/projects/status/qk0bhyhqp1ekpat8
:target: https://ci.appveyor.com/project/vitaut/cppformat
.. image:: https://badges.gitter.im/Join%20Chat.svg
:alt: Join the chat at https://gitter.im/fmtlib/fmt
:target: https://gitter.im/fmtlib/fmt
: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
**fmt** is an open-source formatting library for C++.
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://fmtlib.net/latest/>`_
`Documentation <http://cppformat.github.io/latest/>`_
Features
--------
* Two APIs: faster concatenation-based `write API
<http://fmtlib.net/latest/api.html#write-api>`_ and slower,
but still very fast, replacement-based `format API
<http://fmtlib.net/latest/api.html#format-api>`_ with positional arguments
for localization.
* 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://fmtlib.net/latest/syntax.html>`_
<http://cppformat.github.io/latest/syntax.html>`_
similar to the one used by `str.format
<https://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
* Safe `printf implementation
<http://fmtlib.net/latest/api.html#printf-formatting-functions>`_
<http://cppformat.github.io/latest/api.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 the performance of IOStreams. See `Speed tests`_ and
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/fmtlib/fmt/tree/master/test>`_.
<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/fmtlib/fmt/blob/master/LICENSE.rst>`_
* `Portability <http://fmtlib.net/latest/index.html#portability>`_ with consistent output
<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://fmtlib.net/latest/>`_ for more details.
See the `documentation <http://cppformat.github.io/latest/>`_ for more details.
Examples
--------
@@ -77,7 +75,7 @@ Arguments can be accessed by position and arguments' indices can be repeated:
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
// s == "abracadabra"
fmt can be used as a safe portable replacement for ``itoa``:
C++ Format can be used as a safe portable replacement for ``itoa``:
.. code:: c++
@@ -91,8 +89,6 @@ An object of any user-defined type for which there is an overloaded
.. code:: c++
#include "fmt/ostream.h"
class Date {
int year_, month_, day_;
public:
@@ -107,10 +103,10 @@ An object of any user-defined type for which there is an overloaded
// s == "The date is 2012-12-9"
You can use the `FMT_VARIADIC
<http://fmtlib.net/latest/api.html#utilities>`_
<http://cppformat.github.io/latest/api.html#utilities>`_
macro to create your own functions similar to `format
<http://fmtlib.net/latest/api.html#format>`_ and
`print <http://fmtlib.net/latest/api.html#print>`_
<http://cppformat.github.io/latest/api.html#format>`_ and
`print <http://cppformat.github.io/latest/api.html#print>`_
which take arbitrary arguments:
.. code:: c++
@@ -136,19 +132,13 @@ Projects using this library
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater vehicle
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
@@ -164,12 +154,6 @@ Projects using this library
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
Business intelligence software
* `Scylla <http://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store that can handle
1 million transactions per second on a single server
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++ framework for
high-performance server applications on modern hardware
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
* `Stellar <https://www.stellar.org/>`_: Financial platform
@@ -182,7 +166,7 @@ Projects using this library
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/fmtlib/fmt/issues>`_.
`issue <https://github.com/cppformat/cppformat/issues>`_.
Motivation
----------
@@ -293,14 +277,14 @@ The following speed tests results were generated by building
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/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
<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
fmt 1.0 fmt::print 1.42
C++ Format 1.0 fmt::print 1.42
tinyformat 2.0.1 tfm::printf 2.25
Boost Format 1.54 boost::format 9.94
================= ============= ===========
@@ -309,7 +293,7 @@ As you can see ``boost::format`` is much slower than the alternative methods; th
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 fmt is close to that of printf, being `faster than printf on integer
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.
@@ -317,8 +301,8 @@ Compile time and code bloat
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The script `bloat-test.py
<https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py>`_
from `format-benchmark <https://github.com/fmtlib/format-benchmark>`_
<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
@@ -332,12 +316,12 @@ Method Compile Time, s Executable size, KiB Stripped size, KiB
============ =============== ==================== ==================
printf 2.6 41 30
IOStreams 19.4 92 70
fmt 46.8 46 34
C++ Format 46.8 46 34
tinyformat 64.6 418 386
Boost Format 222.8 990 923
============ =============== ==================== ==================
As you can see, fmt has two times less overhead in terms of resulting
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.
@@ -348,12 +332,12 @@ Method Compile Time, s Executable size, KiB Stripped size, KiB
============ =============== ==================== ==================
printf 2.1 41 30
IOStreams 19.7 86 62
fmt 47.9 108 86
C++ Format 47.9 108 86
tinyformat 27.7 234 190
Boost Format 122.6 884 763
============ =============== ==================== ==================
``libc``, ``libstdc++`` and ``libfmt`` are all linked as shared
``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.
@@ -364,14 +348,14 @@ Running the tests
Please refer to `Building the library`__ for the instructions on how to build
the library and run the unit tests.
__ http://fmtlib.net/latest/usage.html#building-the-library
__ http://cppformat.github.io/latest/usage.html#building-the-library
Benchmarks reside in a separate repository,
`format-benchmarks <https://github.com/fmtlib/format-benchmark>`_,
`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/fmtlib/format-benchmark.git
$ git clone --recursive https://github.com/cppformat/format-benchmark.git
$ cd format-benchmark
$ cmake .
@@ -386,18 +370,23 @@ or the bloat test::
License
-------
fmt is distributed under the BSD `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
C++ Format is distributed under the BSD `license
<https://github.com/cppformat/cppformat/blob/master/LICENSE.rst>`_.
The `Format String Syntax
<http://fmtlib.net/latest/syntax.html>`_
<http://cppformat.github.io/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
documentation <https://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/fmtlib/fmt/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of fmt.
<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
---------------
@@ -420,4 +409,4 @@ formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensiv
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.
improvements to the code.

View File

@@ -0,0 +1,31 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "2.1.0")
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()

View File

@@ -0,0 +1,28 @@
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was cppformat-config.cmake.in ########
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
macro(check_required_components _NAME)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(NOT ${_NAME}_${comp}_FOUND)
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
endif()
endif()
endforeach()
endmacro()
####################################################################################
include(${CMAKE_CURRENT_LIST_DIR}/cppformat-targets.cmake)
check_required_components(cppformat)

View File

@@ -0,0 +1,73 @@
# Generated by CMake 3.1.2
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
if(CMAKE_VERSION VERSION_LESS 3.0.0)
message(FATAL_ERROR "This file relies on consumers using CMake 3.0.0 or greater.")
endif()
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget cppformat cppformat-header-only)
list(APPEND _expectedTargets ${_expectedTarget})
if(NOT TARGET ${_expectedTarget})
list(APPEND _targetsNotDefined ${_expectedTarget})
endif()
if(TARGET ${_expectedTarget})
list(APPEND _targetsDefined ${_expectedTarget})
endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
# Create imported target cppformat
add_library(cppformat STATIC IMPORTED)
set_target_properties(cppformat PROPERTIES
INTERFACE_COMPILE_OPTIONS "-std=c++11"
INTERFACE_INCLUDE_DIRECTORIES "/home/viz/Downloads/cppformat"
)
# Create imported target cppformat-header-only
add_library(cppformat-header-only INTERFACE IMPORTED)
set_target_properties(cppformat-header-only PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "FMT_HEADER_ONLY=1"
INTERFACE_INCLUDE_DIRECTORIES "/home/viz/Downloads/cppformat"
)
# Import target "cppformat" for configuration "Release"
set_property(TARGET cppformat APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(cppformat PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
IMPORTED_LOCATION_RELEASE "/home/viz/Downloads/cppformat/build/cppformat/libcppformat.a"
)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

81
cppformat/CMakeLists.txt Normal file
View File

@@ -0,0 +1,81 @@
# Define the cppformat library, its includes and the needed defines.
# format.cc is added to FMT_HEADERS for the header-only configuration.
set(FMT_HEADERS format.h format.cc)
if (HAVE_OPEN)
set(FMT_HEADERS ${FMT_HEADERS} posix.h)
set(FMT_SOURCES ${FMT_SOURCES} posix.cc)
endif ()
add_library(cppformat ${FMT_SOURCES} ${FMT_HEADERS})
# Starting with cmake 3.1 the CXX_STANDARD property can be used instead.
target_compile_options(cppformat PUBLIC ${CPP11_FLAG})
if (FMT_PEDANTIC)
target_compile_options(cppformat PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(cppformat INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
set_target_properties(cppformat PROPERTIES
VERSION ${CPPFORMAT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE)
# Fix rpmlint warning:
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
target_link_libraries(cppformat -Wl,--as-needed)
endif ()
target_compile_definitions(cppformat PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif ()
#------------------------------------------------------------------------------
# additionally define a header only library when cmake is new enough
if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0)
add_library(cppformat-header-only INTERFACE)
target_compile_definitions(cppformat-header-only INTERFACE FMT_HEADER_ONLY=1)
target_include_directories(cppformat-header-only INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
endif ()
# Install targets.
if (FMT_INSTALL)
include(CMakePackageConfigHelpers)
set(config_install_dir lib/cmake/cppformat)
set(version_config ${PROJECT_BINARY_DIR}/cppformat-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/cppformat-config.cmake)
set(targets_export_name cppformat-targets)
set (INSTALL_TARGETS cppformat)
if (TARGET cppformat-header-only)
set(INSTALL_TARGETS ${INSTALL_TARGETS} cppformat-header-only)
endif ()
set(FMT_LIB_DIR lib CACHE STRING
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
VERSION ${CPPFORMAT_VERSION}
COMPATIBILITY AnyNewerVersion)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/support/cmake/cppformat-config.cmake.in
${project_config}
INSTALL_DESTINATION ${config_install_dir})
export(TARGETS ${INSTALL_TARGETS} FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
# Install version, config and target files.
install(
FILES ${project_config} ${version_config}
DESTINATION ${config_install_dir})
install(EXPORT ${targets_export_name} DESTINATION ${config_install_dir})
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} DESTINATION ${FMT_LIB_DIR})
install(FILES ${FMT_HEADERS} DESTINATION include/cppformat)
endif ()

View File

@@ -1,7 +1,7 @@
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,17 @@
using fmt::internal::Arg;
// Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0
#endif
#if defined(_MSC_VER) && !_HAS_EXCEPTIONS
# define FMT_EXCEPTIONS 0
#endif
#ifndef FMT_EXCEPTIONS
# define FMT_EXCEPTIONS 1
#endif
#if FMT_EXCEPTIONS
# define FMT_TRY try
# define FMT_CATCH(x) catch (x)
@@ -60,6 +71,20 @@ using fmt::internal::Arg;
# define FMT_CATCH(x) if (false)
#endif
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# define FMT_THROW(x) throw x
# else
# define FMT_THROW(x) assert(false)
# endif
#endif
#ifdef FMT_HEADER_ONLY
# define FMT_FUNC inline
#else
# define FMT_FUNC
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
@@ -79,11 +104,6 @@ static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
}
namespace fmt {
FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {}
FMT_FUNC FormatError::~FormatError() throw() {}
FMT_FUNC SystemError::~SystemError() throw() {}
namespace {
#ifndef _MSC_VER
@@ -128,7 +148,7 @@ struct IntChecker<true> {
const char RESET_COLOR[] = "\x1b[0m";
typedef void (*FormatFunc)(Writer &, int, StringRef);
typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
@@ -168,7 +188,7 @@ int safe_strerror(
}
// Handle the case when strerror_r is not available.
int handle(internal::Null<>) {
int handle(fmt::internal::Null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
@@ -180,7 +200,7 @@ int safe_strerror(
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) {
int fallback(fmt::internal::Null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
@@ -198,32 +218,27 @@ int safe_strerror(
return StrError(error_code, buffer, buffer_size).run();
}
void format_error_code(Writer &out, int error_code,
StringRef message) FMT_NOEXCEPT {
void format_error_code(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc.
out.clear();
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
fmt::internal::IntTraits<int>::MainType ec_value = error_code;
// 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;
typedef internal::IntTraits<int>::MainType MainType;
MainType abs_value = static_cast<MainType>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
error_code_size += fmt::internal::count_digits(ec_value);
if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERROR_STR << error_code;
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
}
void report_error(FormatFunc func, int error_code,
StringRef message) FMT_NOEXCEPT {
MemoryWriter full_message;
void report_error(FormatFunc func,
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
fmt::MemoryWriter full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
@@ -232,79 +247,111 @@ void report_error(FormatFunc func, int error_code,
}
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
public:
template <typename T>
bool visit_any_int(T value) { return value == 0; }
};
// Parses an unsigned integer advancing s to the end of the parsed input.
// This function assumes that the first character of s is a digit.
template <typename Char>
int parse_nonnegative_int(const Char *&s) {
assert('0' <= *s && *s <= '9');
unsigned value = 0;
do {
unsigned new_value = value * 10 + (*s++ - '0');
// Check if value wrapped around.
if (new_value < value) {
value = UINT_MAX;
break;
}
value = new_value;
} while ('0' <= *s && *s <= '9');
if (value > INT_MAX)
FMT_THROW(fmt::FormatError("number is too big"));
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 =
fmt::format("format specifier '{}' requires numeric argument", spec);
FMT_THROW(fmt::FormatError(message));
}
}
template <typename Char>
void check_sign(const Char *&s, const Arg &arg) {
char sign = static_cast<char>(*s);
require_numeric_argument(arg, sign);
if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
FMT_THROW(fmt::FormatError(fmt::format(
"format specifier '{}' requires signed argument", sign)));
}
++s;
}
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
private:
FormatSpec &spec_;
fmt::FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public:
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
void report_unhandled_arg() {
FMT_THROW(FormatError("width is not integer"));
FMT_THROW(fmt::FormatError("width is not integer"));
}
template <typename T>
unsigned visit_any_int(T value) {
typedef typename internal::IntTraits<T>::MainType UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value);
if (internal::is_negative(value)) {
spec_.align_ = ALIGN_LEFT;
typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
UnsignedType width = value;
if (fmt::internal::is_negative(value)) {
spec_.align_ = fmt::ALIGN_LEFT;
width = 0 - width;
}
if (width > INT_MAX)
FMT_THROW(FormatError("number is too big"));
FMT_THROW(fmt::FormatError("number is too big"));
return static_cast<unsigned>(width);
}
};
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
class PrecisionHandler :
public fmt::internal::ArgVisitor<PrecisionHandler, int> {
public:
void report_unhandled_arg() {
FMT_THROW(FormatError("precision is not integer"));
FMT_THROW(fmt::FormatError("precision is not integer"));
}
template <typename T>
int visit_any_int(T value) {
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(FormatError("number is too big"));
FMT_THROW(fmt::FormatError("number is too big"));
return static_cast<int>(value);
}
};
template <typename T, typename U>
struct is_same {
enum { value = 0 };
};
// Converts an integer argument to an integral type T for printf.
template <typename T>
struct is_same<T, T> {
enum { value = 1 };
};
// 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:
// 'd' and 'i' - signed, other - unsigned)
template <typename T = void>
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
private:
internal::Arg &arg_;
fmt::internal::Arg &arg_;
wchar_t type_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
public:
ArgConverter(internal::Arg &arg, wchar_t type)
ArgConverter(fmt::internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {}
void visit_bool(bool value) {
@@ -315,48 +362,44 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
template <typename U>
void visit_any_int(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
using internal::Arg;
typedef typename internal::Conditional<
is_same<T, void>::value, U, T>::type TargetType;
if (sizeof(TargetType) <= sizeof(int)) {
using fmt::internal::Arg;
if (sizeof(T) <= sizeof(int)) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_.type = Arg::INT;
arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
arg_.int_value = static_cast<int>(static_cast<T>(value));
} else {
arg_.type = Arg::UINT;
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<typename fmt::internal::MakeUnsigned<T>::Type>(value));
}
} else {
if (is_signed) {
arg_.type = Arg::LONG_LONG;
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// 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<typename fmt::internal::MakeUnsigned<U>::Type>(value);
} else {
arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value =
static_cast<typename internal::MakeUnsigned<U>::Type>(value);
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
}
}
}
};
// Converts an integer argument to char for printf.
class CharConverter : public ArgVisitor<CharConverter, void> {
class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
private:
internal::Arg &arg_;
fmt::internal::Arg &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public:
explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
template <typename T>
void visit_any_int(T value) {
arg_.type = internal::Arg::CHAR;
arg_.type = Arg::CHAR;
arg_.int_value = static_cast<char>(value);
}
};
@@ -364,20 +407,134 @@ class CharConverter : public ArgVisitor<CharConverter, void> {
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);
void write_pointer(const void *p) {
spec_.flags_ = HASH_FLAG;
spec_.type_ = 'x';
writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_);
}
protected:
BasicWriter<Char> &writer() { return writer_; }
FormatSpec &spec() { return spec_; }
void write(bool value) {
const char *str_value = value ? "true" : "false";
Arg::StringValue<char> str = { str_value, strlen(str_value) };
writer_.write_str(str, spec_);
}
void write(const char *value) {
Arg::StringValue<char> str = {value, value != 0 ? strlen(value) : 0};
writer_.write_str(str, 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_)
return visit_any_int(value);
write(value);
}
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();
const unsigned CHAR_WIDTH = 1;
if (spec_.width_ > CHAR_WIDTH) {
out = writer_.grow_buffer(spec_.width_);
if (spec_.align_ == ALIGN_RIGHT) {
std::fill_n(out, spec_.width_ - CHAR_WIDTH, fill);
out += spec_.width_ - CHAR_WIDTH;
} else if (spec_.align_ == ALIGN_CENTER) {
out = writer_.fill_padding(out, spec_.width_,
internal::check(CHAR_WIDTH), fill);
} else {
std::fill_n(out + CHAR_WIDTH, spec_.width_ - CHAR_WIDTH, fill);
}
} else {
out = writer_.grow_buffer(CHAR_WIDTH);
}
*out = internal::CharTraits<Char>::cast(value);
}
void visit_cstring(const char *value) {
if (spec_.type_ == 'p')
return write_pointer(value);
write(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");
write_pointer(value);
}
};
// 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 ArgFormatterBase<PrintfArgFormatter<Char>, Char> {
public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
void write_null_pointer() {
this->spec().type_ = 0;
this->write("(nil)");
}
typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base;
typedef BasicArgFormatter<PrintfArgFormatter<Char>, Char> Base;
public:
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {}
: BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
void visit_bool(bool value) {
FormatSpec &fmt_spec = this->spec();
@@ -571,25 +728,27 @@ FMT_FUNC void fmt::WindowsError::init(
FMT_FUNC void fmt::internal::format_windows_error(
fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT {
class String {
private:
LPWSTR str_;
public:
String() : str_() {}
~String() { LocalFree(str_); }
LPWSTR *ptr() { return &str_; }
LPCWSTR c_str() const { return str_; }
};
FMT_TRY {
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
wchar_t *system_message = &buffer[0];
int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buffer.size()), 0);
if (result != 0) {
UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
out << message << ": " << utf8_message;
return;
}
break;
String system_message;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
out << message << ": " << utf8_message;
return;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
@@ -634,7 +793,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
map_.insert(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
@@ -646,7 +805,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
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_.push_back(Pair(named_arg->name, *named_arg));
map_.insert(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
@@ -655,7 +814,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
map_.insert(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
@@ -668,6 +827,68 @@ void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
template <typename Char>
template <typename StrChar>
void fmt::BasicWriter<Char>::write_str(
const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
// Check if StrChar is convertible to Char.
internal::CharTraits<Char>::convert(StrChar());
if (spec.type_ && spec.type_ != 's')
internal::report_unknown_type(spec.type_, "string");
const StrChar *str_value = s.value;
std::size_t str_size = s.size;
if (str_size == 0) {
if (!str_value) {
FMT_THROW(FormatError("string pointer is null"));
return;
}
}
std::size_t precision = spec.precision_;
if (spec.precision_ >= 0 && precision < str_size)
str_size = spec.precision_;
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;
Arg arg = *s < '0' || *s > '9' ?
next_arg(error) : get_arg(parse_nonnegative_int(s), error);
if (error) {
FMT_THROW(FormatError(
*s != '}' && *s != ':' ? "invalid format string" : error));
}
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];
@@ -677,13 +898,34 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
break;
case Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
break;
default:
/*nothing*/;
}
return arg;
}
inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
if (next_arg_index_ >= 0)
return do_get_arg(next_arg_index_++, error);
error = "cannot switch from manual to automatic argument indexing";
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) {
return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
}
template <typename Char>
void fmt::internal::PrintfFormatter<Char>::parse_flags(
FormatSpec &spec, const Char *&s) {
@@ -782,7 +1024,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
if (*s == '.') {
++s;
if ('0' <= *s && *s <= '9') {
spec.precision_ = static_cast<int>(parse_nonnegative_int(s));
spec.precision_ = parse_nonnegative_int(s);
} else if (*s == '*') {
++s;
spec.precision_ = PrecisionHandler().visit(get_arg(s));
@@ -791,7 +1033,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
Arg arg = get_arg(s, arg_index);
if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
spec.flags_ &= ~to_unsigned<int>(HASH_FLAG);
spec.flags_ &= ~HASH_FLAG;
if (spec.fill_ == '0') {
if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC;
@@ -828,7 +1070,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
break;
default:
--s;
ArgConverter<void>(arg, *s).visit(arg);
ArgConverter<int>(arg, *s).visit(arg);
}
// Parse type.
@@ -856,6 +1098,196 @@ void fmt::internal::PrintfFormatter<Char>::format(
write(writer, start, s);
}
template <typename Char>
const Char *fmt::BasicFormatter<Char>::format(
const Char *&format_str, const Arg &arg) {
const Char *s = format_str;
FormatSpec spec;
if (*s == ':') {
if (arg.type == Arg::CUSTOM) {
arg.custom.format(this, arg.custom.value, &s);
return s;
}
++s;
// Parse fill and alignment.
if (Char c = *s) {
const Char *p = s + 1;
spec.align_ = ALIGN_DEFAULT;
do {
switch (*p) {
case '<':
spec.align_ = ALIGN_LEFT;
break;
case '>':
spec.align_ = ALIGN_RIGHT;
break;
case '=':
spec.align_ = ALIGN_NUMERIC;
break;
case '^':
spec.align_ = ALIGN_CENTER;
break;
}
if (spec.align_ != ALIGN_DEFAULT) {
if (p != s) {
if (c == '}') break;
if (c == '{')
FMT_THROW(FormatError("invalid fill character '{'"));
s += 2;
spec.fill_ = c;
} else ++s;
if (spec.align_ == ALIGN_NUMERIC)
require_numeric_argument(arg, '=');
break;
}
} while (--p >= s);
}
// Parse sign.
switch (*s) {
case '+':
check_sign(s, arg);
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break;
case '-':
check_sign(s, arg);
spec.flags_ |= MINUS_FLAG;
break;
case ' ':
check_sign(s, arg);
spec.flags_ |= SIGN_FLAG;
break;
}
if (*s == '#') {
require_numeric_argument(arg, '#');
spec.flags_ |= HASH_FLAG;
++s;
}
// 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') {
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.
if (*s == '.') {
++s;
spec.precision_ = 0;
if ('0' <= *s && *s <= '9') {
spec.precision_ = parse_nonnegative_int(s);
} else if (*s == '{') {
++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;
switch (precision_arg.type) {
case Arg::INT:
if (precision_arg.int_value < 0)
FMT_THROW(FormatError("negative precision"));
value = precision_arg.int_value;
break;
case Arg::UINT:
value = precision_arg.uint_value;
break;
case Arg::LONG_LONG:
if (precision_arg.long_long_value < 0)
FMT_THROW(FormatError("negative precision"));
value = precision_arg.long_long_value;
break;
case Arg::ULONG_LONG:
value = precision_arg.ulong_long_value;
break;
default:
FMT_THROW(FormatError("precision is not integer"));
}
if (value > INT_MAX)
FMT_THROW(FormatError("number is too big"));
spec.precision_ = static_cast<int>(value);
} else {
FMT_THROW(FormatError("missing precision specifier"));
}
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")));
}
}
// Parse type.
if (*s != '}' && *s)
spec.type_ = static_cast<char>(*s++);
}
if (*s++ != '}')
FMT_THROW(FormatError("missing '}' in format string"));
// Format argument.
internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
return s;
}
template <typename Char>
void fmt::BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) {
const Char *s = format_str.c_str();
const Char *start = s;
while (*s) {
Char c = *s++;
if (c != '{' && c != '}') continue;
if (*s == c) {
write(writer_, start, s);
start = ++s;
continue;
}
if (c == '}')
FMT_THROW(FormatError("unmatched '}' in format string"));
write(writer_, start, s - 1);
Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
start = s = format(s, arg);
}
write(writer_, start, s);
}
FMT_FUNC void fmt::report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32.
@@ -880,6 +1312,12 @@ FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
print(stdout, format_str, 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, CStringRef format, ArgList args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
@@ -903,7 +1341,10 @@ template struct fmt::internal::BasicData<void>;
template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
template const char *fmt::BasicFormatter<char>::format(
const char *&format_str, const fmt::internal::Arg &arg);
template void fmt::BasicFormatter<char>::format(CStringRef format);
template void fmt::internal::PrintfFormatter<char>::format(
BasicWriter<char> &writer, CStringRef format);
@@ -920,7 +1361,11 @@ template int fmt::internal::CharTraits<char>::format_float(
template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
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(
BasicCStringRef<wchar_t> format);
template void fmt::internal::PrintfFormatter<wchar_t>::format(
BasicWriter<wchar_t> &writer, WCStringRef format);

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,28 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2012 - 2016, Victor Zverovich
Copyright (c) 2014 - 2015, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
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
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Disable bogus MSVC warnings.
@@ -72,7 +90,7 @@ 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_)
FMT_THROW(SystemError(errno, "cannot open file {}", filename));
throw SystemError(errno, "cannot open file {}", filename);
}
void fmt::BufferedFile::close() {
@@ -81,7 +99,7 @@ void fmt::BufferedFile::close() {
int result = FMT_SYSTEM(fclose(file_));
file_ = 0;
if (result != 0)
FMT_THROW(SystemError(errno, "cannot close file"));
throw SystemError(errno, "cannot close file");
}
// A macro used to prevent expansion of fileno on broken versions of MinGW.
@@ -90,7 +108,7 @@ void fmt::BufferedFile::close() {
int fmt::BufferedFile::fileno() const {
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
if (fd == -1)
FMT_THROW(SystemError(errno, "cannot get file descriptor"));
throw SystemError(errno, "cannot get file descriptor");
return fd;
}
@@ -103,7 +121,7 @@ fmt::File::File(fmt::CStringRef path, int oflag) {
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
#endif
if (fd_ == -1)
FMT_THROW(SystemError(errno, "cannot open file {}", path));
throw SystemError(errno, "cannot open file {}", path);
}
fmt::File::~File() FMT_NOEXCEPT {
@@ -121,7 +139,7 @@ void fmt::File::close() {
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0)
FMT_THROW(SystemError(errno, "cannot close file"));
throw SystemError(errno, "cannot close file");
}
fmt::LongLong fmt::File::size() const {
@@ -135,7 +153,7 @@ fmt::LongLong fmt::File::size() const {
if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError();
if (error != NO_ERROR)
FMT_THROW(WindowsError(GetLastError(), "cannot get file size"));
throw WindowsError(GetLastError(), "cannot get file size");
}
fmt::ULongLong long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
@@ -143,7 +161,7 @@ fmt::LongLong fmt::File::size() const {
typedef struct stat Stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
FMT_THROW(SystemError(errno, "cannot get file attributes"));
throw SystemError(errno, "cannot get file attributes");
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
"return type of File::size is not large enough");
return file_stat.st_size;
@@ -154,16 +172,16 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0)
FMT_THROW(SystemError(errno, "cannot read from file"));
return internal::to_unsigned(result);
throw SystemError(errno, "cannot read from file");
return result;
}
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0)
FMT_THROW(SystemError(errno, "cannot write to file"));
return internal::to_unsigned(result);
throw SystemError(errno, "cannot write to file");
return result;
}
fmt::File fmt::File::dup(int fd) {
@@ -171,7 +189,7 @@ fmt::File fmt::File::dup(int fd) {
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1)
FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd));
throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
return File(new_fd);
}
@@ -179,8 +197,8 @@ void fmt::File::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
FMT_THROW(SystemError(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd));
throw SystemError(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd);
}
}
@@ -207,7 +225,7 @@ void fmt::File::pipe(File &read_end, File &write_end) {
int result = FMT_POSIX_CALL(pipe(fds));
#endif
if (result != 0)
FMT_THROW(SystemError(errno, "cannot create pipe"));
throw SystemError(errno, "cannot create pipe");
// The following assignments don't throw because read_fd and write_fd
// are closed.
read_end = File(fds[0]);
@@ -218,7 +236,7 @@ fmt::BufferedFile fmt::File::fdopen(const char *mode) {
// Don't retry as fdopen doesn't return EINTR.
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
if (!f)
FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor"));
throw SystemError(errno, "cannot associate stream with file descriptor");
BufferedFile file(f);
fd_ = -1;
return file;
@@ -232,7 +250,7 @@ long fmt::getpagesize() {
#else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0)
FMT_THROW(SystemError(errno, "cannot get memory page size"));
throw SystemError(errno, "cannot get memory page size");
return size;
#endif
}

View File

@@ -1,2 +1,344 @@
#include "../fmt/posix.h"
#warning Including cppformat/posix.h is deprecated. Include fmt/posix.h instead.
/*
A C++ interface to POSIX functions.
Copyright (c) 2014 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
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
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
#ifdef __MINGW32__
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <errno.h>
#include <fcntl.h> // for O_RDONLY
#include <stdio.h>
#include <cstddef>
#include "format.h"
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
#if FMT_GCC_VERSION >= 407
# define FMT_UNUSED __attribute__((unused))
#else
# define FMT_UNUSED
#endif
#ifndef FMT_USE_STATIC_ASSERT
# define FMT_USE_STATIC_ASSERT 0
#endif
#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
#else
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
# define FMT_STATIC_ASSERT(cond, message) \
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
result = (expression); \
} while (result == error_result && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt {
// An error code.
class ErrorCode {
private:
int value_;
public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class BufferedFile {
private:
FILE *file_;
friend class File;
explicit BufferedFile(FILE *f) : file_(f) {}
public:
// Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : file_(0) {}
// Destroys the object closing the file it represents if any.
~BufferedFile() FMT_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
FILE *file;
};
public:
// A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
// A "move constructor" for for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
f.file_ = 0;
}
// A "move assignment operator" for moving from a temporary.
BufferedFile &operator=(Proxy p) {
close();
file_ = p.file;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
BufferedFile &operator=(BufferedFile &other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
// Returns a proxy object for moving from a temporary:
// BufferedFile file = BufferedFile(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {file_};
file_ = 0;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = 0;
}
BufferedFile& operator=(BufferedFile &&other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
#endif
// Opens a file.
BufferedFile(CStringRef filename, CStringRef mode);
// Closes the file.
void close();
// Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
int (fileno)() const;
void print(CStringRef format_str, const ArgList &args) {
fmt::print(file_, format_str, args);
}
FMT_VARIADIC(void, print, CStringRef)
};
// A file. Closed file is represented by a File object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::SystemError in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class File {
private:
int fd_; // File descriptor.
// Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
};
// Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a File object representing this file.
File(CStringRef path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
int fd;
};
public:
// A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
// A "move assignment operator" for moving from a temporary.
File &operator=(Proxy p) {
close();
fd_ = p.fd;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
File &operator=(File &other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Returns a proxy object for moving from a temporary:
// File file = File(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {fd_};
fd_ = -1;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(File);
public:
File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
File& operator=(File &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
#endif
// Destroys the object closing the file it represents if any.
~File() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
void close();
// Returns the file size.
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);
// Attempts to write count bytes from the specified buffer to the file.
std::size_t write(const void *buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
static File dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
static void pipe(File &read_end, File &write_end);
// Creates a BufferedFile object associated with this file and detaches
// this File object from the file.
BufferedFile fdopen(const char *mode);
};
// Returns the memory page size.
long getpagesize();
} // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES
namespace std {
// For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
inline fmt::File &move(fmt::File &f) { return f; }
}
#endif
#endif // FMT_POSIX_H_

View File

@@ -5,7 +5,7 @@ if (NOT DOXYGEN)
endif ()
add_custom_target(doc
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION})
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${CPPFORMAT_VERSION})
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
DESTINATION share/doc/fmt OPTIONAL)
DESTINATION share/doc/cppformat)

View File

@@ -1,17 +1,17 @@
{% extends "!layout.html" %}
{% block extrahead %}
<meta name="description" content="Small, safe and fast formatting library">
<meta name="description" content="Small, safe and fast formatting library for C++">
<meta name="keywords" content="C++, formatting, printf, string, library">
<meta name="author" content="Victor Zverovich">
<link rel="stylesheet" href="_static/fmt.css">
<link rel="stylesheet" href="_static/cppformat.css">
{# Google Analytics #}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-20116650-4', 'fmtlib.net');
ga('create', 'UA-20116650-4', 'cppformat.github.io');
ga('send', 'pageview');
</script>
{% endblock %}
@@ -42,7 +42,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">{fmt}</a>
<a class="navbar-brand" href="index.html">C++ Format</a>
</div>
{# Collect the nav links, forms, and other content for toggling #}
@@ -53,9 +53,9 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
aria-expanded="false">{{ version }} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="http://fmtlib.net/2.0.0/">2.0.0</a></li>
<li><a href="http://fmtlib.net/1.1.0/">1.1.0</a></li>
<li><a href="http://fmtlib.net/1.0.0/">1.0.0</a></li>
<li><a href="http://cppformat.github.io/2.0.0/">2.0.0</a></li>
<li><a href="http://cppformat.github.io/1.1.0/">1.1.0</a></li>
<li><a href="http://cppformat.github.io/1.0.0/">1.0.0</a></li>
</ul>
</li>
{% for name in ['Contents', 'Usage', 'API', 'Syntax'] %}
@@ -77,18 +77,18 @@
{% if pagename == "index" %}
<div class="jumbotron">
<div class="tb-container">
<h1>{fmt}</h1>
<p class="lead">Small, safe and fast formatting library</p>
<h1>C++ Format</h1>
<p class="lead">Small, safe and fast formatting library for C++</p>
<div class="btn-group" role="group">
<a class="btn btn-success"
href="https://github.com/fmtlib/fmt/releases/download/2.0.0/cppformat-2.0.0.zip">
href="https://github.com/cppformat/cppformat/releases/download/2.0.0/cppformat-2.0.0.zip">
<span class="glyphicon glyphicon-download"></span> Download
</a>
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="https://github.com/fmtlib/fmt/releases/download/2.0.0/cppformat-2.0.0.zip">Version 2.0.0</a></li>
<li><a href="https://github.com/fmtlib/fmt/releases/download/1.1.0/cppformat-1.1.0.zip">Version 1.1.0</a></li>
<li><a href="https://github.com/fmtlib/fmt/releases/download/1.0.0/cppformat-1.0.0.zip">Version 1.0.0</a></li>
<li><a href="https://github.com/cppformat/cppformat/releases/download/2.0.0/cppformat-2.0.0.zip">Version 2.0.0</a></li>
<li><a href="https://github.com/cppformat/cppformat/releases/download/1.1.0/cppformat-1.1.0.zip">Version 1.1.0</a></li>
<li><a href="https://github.com/cppformat/cppformat/releases/download/1.0.0/cppformat-1.0.0.zip">Version 1.0.0</a></li>
</ul>
</div>
</div>

View File

@@ -4,7 +4,7 @@
API Reference
*************
All functions and classes provided by the fmt library reside
All functions and classes provided by the C++ Format library reside
in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the
namespace is usually omitted in examples.
@@ -22,11 +22,6 @@ arguments in the resulting string.
*args* is an argument list representing arbitrary arguments.
The `performance of the format API
<https://github.com/fmtlib/fmt/blob/master/README.rst#speed-tests>`_ is close
to that of glibc's ``printf`` and better than the performance of IOStreams.
For even better speed use the `write API`_.
.. _format:
.. doxygenfunction:: format(CStringRef, ArgList)
@@ -39,90 +34,9 @@ For even better speed use the `write API`_.
.. doxygenfunction:: print(std::FILE *, CStringRef, ArgList)
.. doxygenclass:: fmt::BasicFormatter
:members:
Date and time formatting
------------------------
The library supports `strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like
date and time formatting::
#include "fmt/time.h"
std::time_t t = std::time(nullptr);
// Prints "The date is 2016-04-29." (with the current date)
fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t));
The format string syntax is described in the documentation of
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
``std::ostream`` support
------------------------
The header ``fmt/ostream.h`` provides ``std::ostream`` support including
formatting of user-defined types that have overloaded ``operator<<``::
#include "fmt/ostream.h"
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"
.. doxygenfunction:: print(std::ostream&, CStringRef, ArgList)
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
Argument formatters
-------------------
It is possible to change the way arguments are formatted by providing a
custom argument formatter class::
// A custom argument formatter that formats negative integers as unsigned
// with the ``x`` format specifier.
class CustomArgFormatter :
public fmt::BasicArgFormatter<CustomArgFormatter, char> {
public:
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
fmt::FormatSpec &s, const char *fmt)
: fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}
void visit_int(int value) {
if (spec().type() == 'x')
visit_uint(value); // convert to unsigned and format
else
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_int(value);
}
};
std::string custom_format(const char *format_str, fmt::ArgList args) {
fmt::MemoryWriter writer;
// Pass custom argument formatter as a template arg to BasicFormatter.
fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
formatter.format(format_str);
return writer.str();
}
FMT_VARIADIC(std::string, custom_format, const char *)
std::string s = custom_format("{:x}", -42); // s == "ffffffd6"
.. doxygenclass:: fmt::ArgVisitor
:members:
.. doxygenclass:: fmt::BasicArgFormatter
:members:
.. doxygenclass:: fmt::ArgFormatter
.. doxygenclass:: fmt::BasicFormatter
:members:
Printf formatting functions
@@ -136,18 +50,13 @@ a POSIX extension for positional arguments.
.. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList)
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
.. doxygenfunction:: sprintf(CStringRef, ArgList)
Write API
=========
The write API provides classes for writing formatted data into character
streams. It is usually faster than the `format API`_ but, as IOStreams,
may result in larger compiled code size. The main writer class is
`~fmt::BasicMemoryWriter` which stores its output in a memory buffer and provides
direct access to it. It is possible to create custom writers that
store output elsewhere by subclassing `~fmt::BasicWriter`.
.. doxygenclass:: fmt::BasicWriter
:members:
@@ -157,13 +66,13 @@ store output elsewhere by subclassing `~fmt::BasicWriter`.
.. doxygenclass:: fmt::BasicArrayWriter
:members:
.. doxygenfunction:: bin(int)
.. doxygenfunction:: bin
.. doxygenfunction:: oct(int)
.. doxygenfunction:: oct
.. doxygenfunction:: hex(int)
.. doxygenfunction:: hex
.. doxygenfunction:: hexu(int)
.. doxygenfunction:: hexu
.. doxygenfunction:: pad(int, unsigned, Char)
@@ -191,7 +100,7 @@ Utilities
:protected-members:
:members:
System errors
System Errors
=============
.. doxygenclass:: fmt::SystemError
@@ -205,7 +114,7 @@ System errors
Custom allocators
=================
The fmt library supports custom dynamic memory allocators.
The C++ Format library supports custom dynamic memory allocators.
A custom allocator class can be specified as a template argument to
:class:`fmt::BasicMemoryWriter`::

View File

@@ -16,7 +16,7 @@ def pip_install(package, commit=None, **kwargs):
# return
package = 'git+git://github.com/{0}.git@{1}'.format(package, commit)
print('Installing {}'.format(package))
check_call(['pip', 'install', package])
check_call(['pip', 'install', '--upgrade', package])
def build_docs(version='dev'):
# Create virtualenv.
@@ -46,21 +46,21 @@ def build_docs(version='dev'):
except DistributionNotFound:
pass
# Install Sphinx and Breathe.
pip_install('sphinx-doc/sphinx',
'12b83372ac9316e8cbe86e7fed889296a4cc29ee',
check_version='1.4.1.dev20160525')
pip_install('cppformat/sphinx',
'12dde8afdb0a7bb5576e2656692c3478c69d8cc3',
check_version='1.4a0.dev-20151013')
pip_install('michaeljones/breathe',
'1c9d7f80378a92cffa755084823a78bb38ee4acc')
# Build docs.
cmd = ['doxygen', '-']
p = Popen(cmd, stdin=PIPE)
p.communicate(input=r'''
PROJECT_NAME = fmt
PROJECT_NAME = C++ Format
GENERATE_LATEX = NO
GENERATE_MAN = NO
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
INPUT = {0}/format.h {0}/ostream.h
INPUT = {0}/format.h
QUIET = YES
JAVADOC_AUTOBRIEF = YES
AUTOLINK_SUPPORT = NO
@@ -76,7 +76,7 @@ def build_docs(version='dev'):
FMT_USE_USER_DEFINED_LITERALS=1 \
FMT_API=
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
'''.format(os.path.join(os.path.dirname(doc_dir), 'fmt')).encode('UTF-8'))
'''.format(os.path.join(os.path.dirname(doc_dir), 'cppformat')).encode('UTF-8'))
if p.returncode != 0:
raise CalledProcessError(p.returncode, cmd)
check_call(['sphinx-build',
@@ -86,8 +86,8 @@ def build_docs(version='dev'):
try:
check_call(['lessc', '--clean-css',
'--include-path=' + os.path.join(doc_dir, 'bootstrap'),
os.path.join(doc_dir, 'fmt.less'),
'html/_static/fmt.css'])
os.path.join(doc_dir, 'cppformat.less'),
'html/_static/cppformat.css'])
except OSError as e:
if e.errno != errno.ENOENT:
raise

View File

@@ -46,7 +46,7 @@ source_suffix = '.rst'
#master_doc = 'contents'
# General information about the project.
project = u'fmt'
project = u'C++ Format'
copyright = u'2012-2015, Victor Zverovich'
# The version info for the project you're documenting, acts as replacement for
@@ -76,7 +76,7 @@ copyright = u'2012-2015, Victor Zverovich'
exclude_patterns = ['virtualenv']
# The reST default role (used for this markup: `text`) to use for all documents.
default_role = 'cpp:any'
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
@@ -198,7 +198,7 @@ latex_elements = {
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'format.tex', u'fmt documentation',
('index', 'format.tex', u'C++ Format Documentation',
u'Victor Zverovich', 'manual'),
]

View File

@@ -1,9 +1,9 @@
Overview
========
**fmt** (formerly cppformat) is an open-source formatting library.
C++ Format (cppformat) is an open-source formatting library for C++.
It can be used as a safe alternative to printf or as a fast
alternative to C++ IOStreams.
alternative to IOStreams.
.. raw:: html
@@ -24,8 +24,8 @@ Format API
The replacement-based Format API provides a safe alternative to ``printf``,
``sprintf`` and friends with comparable or `better performance
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
The `format string syntax <syntax.html>`_ is similar to the one used by
`str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
The `format string syntax <doc/latest/index.html#format-string-syntax>`_ is similar
to the one used by `str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
in Python:
.. code:: c++
@@ -146,10 +146,10 @@ is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is needed
Portability
-----------
The library is highly portable. Here is an incomplete list of operating systems and
C++ Format is highly portable. Here is an incomplete list of operating systems and
compilers where it has been tested and known to work:
* 64-bit (amd64) GNU/Linux with GCC 4.4.3, `4.6.3 <https://travis-ci.org/fmtlib/fmt>`_,
* 64-bit (amd64) GNU/Linux with GCC 4.4.3, `4.6.3 <https://travis-ci.org/cppformat/cppformat>`_,
4.7.2, 4.8.1 and Intel C++ Compiler (ICC) 14.0.2
* 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3
@@ -157,7 +157,7 @@ compilers where it has been tested and known to work:
* Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0
* 64-bit Windows with Visual C++ 2010, 2013 and
`2015 <https://ci.appveyor.com/project/vitaut/fmt>`_
`2015 <https://ci.appveyor.com/project/vitaut/cppformat>`_
* 32-bit Windows with Visual C++ 2010
@@ -188,16 +188,16 @@ always prints ``inf``.
Ease of Use
-----------
fmt has a small self-contained code base consisting of a single header file
C++ Format has small self-contained code base consisting of a single header file
and a single source file and no external dependencies. A permissive BSD `license
<https://github.com/fmtlib/fmt#license>`_ allows using the library both
<https://github.com/cppformat/cppformat#license>`_ allows using the library both
in open-source and commercial projects.
.. raw:: html
<a class="btn btn-success" href="https://github.com/fmtlib/fmt">GitHub Repository</a>
<a class="btn btn-success" href="https://github.com/cppformat/cppformat">GitHub Repository</a>
<div class="section footer">
<iframe src="http://ghbtns.com/github-btn.html?user=fmtlib&amp;repo=fmt&amp;type=watch&amp;count=true"
<iframe src="http://ghbtns.com/github-btn.html?user=cppformat&amp;repo=cppformat&amp;type=watch&amp;count=true"
class="github-btn" width="100" height="20"></iframe>
</div>

View File

@@ -49,10 +49,12 @@ mini-language" or interpretation of the *format_spec*.
Most built-in types support a common formatting mini-language, which is
described in the next section.
A *format_spec* field can also include nested replacement fields in certain
positions within it. These nested replacement fields can contain only an
argument index; format specifications are not allowed. This allows the
formatting of a value to be dynamically specified.
A *format_spec* field can also include nested replacement fields within it.
These nested replacement fields can contain only an argument index;
format specifications are not allowed. Formatting is performed as if the
replacement fields within the format_spec are substituted before the
*format_spec* string is interpreted. This allows the formatting of a value
to be dynamically specified.
See the :ref:`formatexamples` section for some examples.
@@ -78,8 +80,8 @@ The general form of a *standard format specifier* is:
sign: "+" | "-" | " "
width: `integer` | "{" `arg_id` "}"
precision: `integer` | "{" `arg_id` "}"
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X"
type: `int_type` | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
int_type: "b" | "B" | "d" | "o" | "x" | "X"
The *fill* character can be any character other than '{' or '}'. The presence
of a fill character is signaled by the character following it, which must be
@@ -214,10 +216,6 @@ The available integer presentation types are:
| | ``'#'`` option with this type adds the prefix ``"0X"`` |
| | to the output value. |
+---------+----------------------------------------------------------+
| ``'n'`` | Number. This is the same as ``'d'``, except that it uses |
| | the current locale setting to insert the appropriate |
| | number separator characters. |
+---------+----------------------------------------------------------+
| none | The same as ``'d'``. |
+---------+----------------------------------------------------------+
@@ -232,7 +230,7 @@ The available presentation types for floating-point values are:
+=========+==========================================================+
| ``'a'`` | Hexadecimal floating point format. Prints the number in |
| | base 16 with prefix ``"0x"`` and lower-case letters for |
| | digits above 9. Uses ``'p'`` to indicate the exponent. |
| | digits above 9. Uses 'p' to indicate the exponent. |
+---------+----------------------------------------------------------+
| ``'A'`` | Same as ``'a'`` except it uses upper-case letters for |
| | the prefix, digits above 9 and to indicate the exponent. |
@@ -264,8 +262,6 @@ The available presentation types for floating-point values are:
| none | The same as ``'g'``. |
+---------+----------------------------------------------------------+
Floating-point formatting is locale-dependent.
.. ifconfig:: False
+---------+----------------------------------------------------------+

View File

@@ -2,9 +2,9 @@
Usage
*****
To use the fmt library, add :file:`format.h` and :file:`format.cc` from
a `release archive <https://github.com/fmtlib/fmt/releases/latest>`_
or the `Git repository <https://github.com/fmtlib/fmt>`_ to your project.
To use the C++ Format library, add :file:`format.h` and :file:`format.cc` from
a `release archive <https://github.com/cppformat/cppformat/releases/latest>`_
or the `Git repository <https://github.com/cppformat/cppformat>`_ to your project.
Alternatively, you can :ref:`build the library with CMake <building>`.
If you are using Visual C++ with precompiled headers, you might need to add
@@ -19,24 +19,24 @@ before other includes in :file:`format.cc`.
Building the library
====================
The included `CMake build script`__ can be used to build the fmt
The included `CMake build script`__ can be used to build the C++ Format
library on a wide range of platforms. CMake is freely available for
download from http://www.cmake.org/download/.
__ https://github.com/fmtlib/fmt/blob/master/CMakeLists.txt
__ https://github.com/cppformat/cppformat/blob/master/CMakeLists.txt
CMake works by generating native makefiles or project files that can
be used in the compiler environment of your choice. The typical
workflow starts with::
mkdir build # Create a directory to hold the build output.
mkdir build # Create a directory to hold the build output.
cd build
cmake <path/to/fmt> # Generate native build scripts.
cmake <path/to/cppformat> # Generate native build scripts.
where :file:`{<path/to/fmt>}` is a path to the ``fmt`` repository.
where :file:`{<path/to/cppformat>}` is a path to the ``cppformat`` repository.
If you are on a \*nix system, you should now see a Makefile in the
current directory. Now you can build the library by running :command:`make`.
current directory. Now you can build C++ Format by running :command:`make`.
Once the library has been built you can invoke :command:`make test` to run
the tests.
@@ -69,22 +69,22 @@ the previous section. Then compile the ``doc`` target/project, for example::
make doc
This will generate the HTML documentation in ``doc/html``.
This will generate the HTML documenation in ``doc/html``.
Android NDK
===========
fmt provides `Android.mk file`__ that can be used to build the library
C++ Format provides `Android.mk file`__ that can be used to build the library
with `Android NDK <https://developer.android.com/tools/sdk/ndk/index.html>`_.
For an example of using fmt with Android NDK, see the
`android-ndk-example <https://github.com/fmtlib/android-ndk-example>`_
For an example of using C++ Format with Android NDK, see the
`android-ndk-example <https://github.com/cppformat/android-ndk-example>`_
repository.
__ https://github.com/fmtlib/fmt/blob/master/Android.mk
__ https://github.com/cppformat/cppformat/blob/master/Android.mk
Homebrew
========
fmt can be installed on OS X using `Homebrew <http://brew.sh/>`_::
C++ Format can be installed on OS X using `Homebrew <http://brew.sh/>`_::
brew install fmt
brew install cppformat

View File

@@ -1,93 +0,0 @@
# Define the fmt library, its includes and the needed defines.
# format.cc is added to FMT_HEADERS for the header-only configuration.
set(FMT_HEADERS format.h format.cc ostream.h ostream.cc time.h)
if (HAVE_OPEN)
set(FMT_HEADERS ${FMT_HEADERS} posix.h)
set(FMT_SOURCES ${FMT_SOURCES} posix.cc)
endif ()
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../ChangeLog.rst)
option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF)
if (FMT_CPPFORMAT)
message(WARNING "The cppformat library is deprecated, use fmt instead.")
add_library(cppformat ${FMT_SOURCES} ${FMT_HEADERS})
endif ()
# Starting with cmake 3.1 the CXX_STANDARD property can be used instead.
target_compile_options(fmt PUBLIC ${CPP11_FLAG})
if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(fmt PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
set_target_properties(fmt PROPERTIES
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE)
# Fix rpmlint warning:
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
target_link_libraries(fmt -Wl,--as-needed)
endif ()
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif ()
#------------------------------------------------------------------------------
# additionally define a header only library when cmake is new enough
if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0)
add_library(fmt-header-only INTERFACE)
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
target_include_directories(fmt-header-only INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
endif ()
# Install targets.
if (FMT_INSTALL)
include(CMakePackageConfigHelpers)
set(FMT_CMAKE_DIR lib/cmake/fmt CACHE STRING
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
set(targets_export_name fmt-targets)
set (INSTALL_TARGETS fmt)
if (TARGET fmt-header-only)
set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only)
endif ()
set(FMT_LIB_DIR lib CACHE STRING
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
VERSION ${FMT_VERSION}
COMPATIBILITY AnyNewerVersion)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
${project_config}
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
export(TARGETS ${INSTALL_TARGETS}
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
# Install version, config and target files.
install(
FILES ${project_config} ${version_config}
DESTINATION ${FMT_CMAKE_DIR})
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR})
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
DESTINATION ${FMT_LIB_DIR})
install(FILES ${FMT_HEADERS} DESTINATION include/fmt)
if (FMT_CPPFORMAT)
install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR})
endif ()
endif ()

File diff suppressed because it is too large Load Diff

View File

@@ -1,43 +0,0 @@
/*
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "ostream.h"
namespace fmt {
namespace {
// Write the content of w to os.
void write(std::ostream &os, Writer &w) {
const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
}
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
write(os, w);
}
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
write(os, w);
return static_cast<int>(w.size());
}
} // namespace fmt

View File

@@ -1,115 +0,0 @@
/*
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include "format.h"
#include <ostream>
namespace fmt {
namespace internal {
template <class Char>
class FormatBuf : public std::basic_streambuf<Char> {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
Buffer<Char> &buffer_;
Char *start_;
public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
this->setp(start_, start_ + buffer_.capacity());
}
int_type overflow(int_type ch = traits_type::eof()) {
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
size_t buf_size = size();
buffer_.resize(buf_size);
buffer_.reserve(buf_size * 2);
start_ = &buffer_[0];
start_[buf_size] = traits_type::to_char_type(ch);
this->setp(start_+ buf_size + 1, start_ + buf_size * 2);
}
return ch;
}
size_t size() const {
return to_unsigned(this->pptr() - start_);
}
};
Yes &convert(std::ostream &);
struct DummyStream : std::ostream {
DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
void operator<<(Null<>);
};
No &operator<<(std::ostream &, int);
template<typename T>
struct ConvertToIntImpl<T, true> {
// Convert to int only if T doesn't have an overloaded operator<<.
enum {
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
};
};
} // namespace internal
// Formats a value.
template <typename Char, typename ArgFormatter, typename T>
void format(BasicFormatter<Char, ArgFormatter> &f,
const Char *&format_str, const T &value) {
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::FormatBuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output << value;
BasicStringRef<Char> str(&buffer[0], format_buf.size());
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
format_str = f.format(format_str, MakeArg(str));
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt
#ifdef FMT_HEADER_ONLY
# include "ostream.cc"
#endif
#endif // FMT_OSTREAM_H_

View File

@@ -1,386 +0,0 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
#if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <errno.h>
#include <fcntl.h> // for O_RDONLY
#include <locale.h> // for locale_t
#include <stdio.h>
#include <stdlib.h> // for strtod_l
#include <cstddef>
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
#if FMT_GCC_VERSION >= 407
# define FMT_UNUSED __attribute__((unused))
#else
# define FMT_UNUSED
#endif
#ifndef FMT_USE_STATIC_ASSERT
# define FMT_USE_STATIC_ASSERT 0
#endif
#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
#else
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
# define FMT_STATIC_ASSERT(cond, message) \
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
result = (expression); \
} while (result == error_result && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt {
// An error code.
class ErrorCode {
private:
int value_;
public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class BufferedFile {
private:
FILE *file_;
friend class File;
explicit BufferedFile(FILE *f) : file_(f) {}
public:
// Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : file_(0) {}
// Destroys the object closing the file it represents if any.
~BufferedFile() FMT_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
FILE *file;
};
public:
// A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
// A "move constructor" for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
f.file_ = 0;
}
// A "move assignment operator" for moving from a temporary.
BufferedFile &operator=(Proxy p) {
close();
file_ = p.file;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
BufferedFile &operator=(BufferedFile &other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
// Returns a proxy object for moving from a temporary:
// BufferedFile file = BufferedFile(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {file_};
file_ = 0;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = 0;
}
BufferedFile& operator=(BufferedFile &&other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
#endif
// Opens a file.
BufferedFile(CStringRef filename, CStringRef mode);
// Closes the file.
void close();
// Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
int (fileno)() const;
void print(CStringRef format_str, const ArgList &args) {
fmt::print(file_, format_str, args);
}
FMT_VARIADIC(void, print, CStringRef)
};
// A file. Closed file is represented by a File object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::SystemError in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class File {
private:
int fd_; // File descriptor.
// Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
};
// Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a File object representing this file.
File(CStringRef path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
int fd;
};
public:
// A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
// A "move assignment operator" for moving from a temporary.
File &operator=(Proxy p) {
close();
fd_ = p.fd;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
File &operator=(File &other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Returns a proxy object for moving from a temporary:
// File file = File(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {fd_};
fd_ = -1;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(File);
public:
File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
File& operator=(File &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
#endif
// Destroys the object closing the file it represents if any.
~File() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
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);
// Attempts to write count bytes from the specified buffer to the file.
std::size_t write(const void *buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
static File dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
static void pipe(File &read_end, File &write_end);
// Creates a BufferedFile object associated with this file and detaches
// this File object from the file.
BufferedFile fdopen(const char *mode);
};
// Returns the memory page size.
long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
!defined(__ANDROID__) && !defined(__CYGWIN__)
# define FMT_LOCALE
#endif
#ifdef FMT_LOCALE
// A "C" numeric locale.
class Locale {
private:
# ifdef _MSC_VER
typedef _locale_t locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC };
static locale_t newlocale(int category_mask, const char *locale, locale_t) {
return _create_locale(category_mask, locale);
}
static void freelocale(locale_t locale) {
_free_locale(locale);
}
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
return _strtod_l(nptr, endptr, locale);
}
# endif
locale_t locale_;
FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
public:
typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) {
if (!locale_)
FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
}
~Locale() { freelocale(locale_); }
Type get() const { return locale_; }
// Converts string to floating-point number and advances str past the end
// of the parsed input.
double strtod(const char *&str) const {
char *end = 0;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
};
#endif // FMT_LOCALE
} // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES
namespace std {
// For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
inline fmt::File &move(fmt::File &f) { return f; }
}
#endif
#endif // FMT_POSIX_H_

View File

@@ -1,53 +0,0 @@
/*
Formatting library for C++ - time formatting
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "format.h"
#include <ctime>
namespace fmt {
template <typename ArgFormatter>
void format(BasicFormatter<char, ArgFormatter> &f,
const char *&format_str, const std::tm &tm) {
if (*format_str == ':')
++format_str;
const char *end = format_str;
while (*end && *end != '}')
++end;
if (*end != '}')
FMT_THROW(FormatError("missing '}' in format string"));
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
format.append(format_str, end + 1);
format[format.size() - 1] = '\0';
Buffer<char> &buffer = f.writer().buffer();
std::size_t start = buffer.size();
for (;;) {
std::size_t size = buffer.capacity() - start;
std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
if (count != 0) {
buffer.resize(start + count);
break;
}
if (size >= format.size() * 256) {
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
format_str = end + 1;
}
}
#endif // FMT_TIME_H_

2
format.h Normal file
View File

@@ -0,0 +1,2 @@
#include "cppformat/format.h"
#warning Including format.h from the top-level directory is deprecated.

2
posix.h Normal file
View File

@@ -0,0 +1,2 @@
#include "cppformat/posix.h"
#warning Including posix.h from the top-level directory is deprecated.

View File

@@ -24,8 +24,8 @@ else:
if platform == 'x64':
generator += ' Win64'
cmake_command.append('-G' + generator)
build_command = ['cmake', '--build', '.', '--config', config, '--', '/m:4']
test_command = ['ctest', '-C', config]
build_command = ['msbuild', '/m:4', '/p:Config=' + config, 'FORMAT.sln']
test_command = ['msbuild', 'RUN_TESTS.vcxproj']
check_call(cmake_command)
check_call(build_command)

View File

@@ -20,7 +20,3 @@ build_script:
on_failure:
- appveyor PushArtifact Testing/Temporary/LastTest.log
- appveyor AddTest test
# Uncomment this to debug AppVeyor failures.
#on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

13
support/biicode-build.py Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env python
# Build the project with Biicode.
import glob, os, shutil
from subprocess import check_call
project_dir = 'biicode_project'
check_call(['bii', 'init', project_dir])
cppformat_dir = os.path.join(project_dir, 'blocks/vitaut/cppformat')
shutil.copytree('.', cppformat_dir, ignore=shutil.ignore_patterns(project_dir))
for f in glob.glob('support/biicode/*'):
shutil.copy(f, cppformat_dir)
check_call(['bii', 'cpp:build'], cwd=project_dir)

View File

@@ -0,0 +1,19 @@
# Biicode configuration file
[paths]
# Local directories to look for headers (within block)
/
[dependencies]
# Manual adjust file implicit dependencies, add (+), remove (-), or overwrite (=)
CMakeLists.txt + cmake/FindSetEnv.cmake
format.h = format.cc
format.cc - test/* posix.cc
support/biicode/sample.cc - test/*
[mains]
# Manual adjust of files that define an executable
!test/test-main.cc
[parent]
vitaut/cppformat: 0

View File

@@ -0,0 +1,3 @@
doc/*
breathe/*
gmock/*

17
support/biicode/sample.cc Normal file
View File

@@ -0,0 +1,17 @@
#include "vitaut/cppformat/format.h"
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_;
}
};
int main() {
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
fmt::printf("\n%s", s); // uses printf format string syntax
}

View File

@@ -1,4 +1,4 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
check_required_components(fmt)
check_required_components(cppformat)

View File

@@ -1,9 +1,3 @@
# C++11 feature support detection
if (NOT FMT_USE_CPP11)
return()
endif ()
include(CheckCXXCompilerFlag)
if (FMT_USE_CPP11)
@@ -37,11 +31,6 @@ if (FMT_USE_CPP11)
endif ()
endif ()
if (CMAKE_CXX_STANDARD)
# Don't use -std compiler flag if CMAKE_CXX_STANDARD is specified.
set(CPP11_FLAG )
endif ()
set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG})
# Check if variadic templates are working and not affected by GCC bug 39653:
@@ -68,11 +57,4 @@ check_cxx_source_compiles("
class C { void operator=(const C&); };
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
SUPPORTS_TYPE_TRAITS)
# Check if user-defined literals are available
check_cxx_source_compiles("
void operator\"\" _udl(long double);
int main() {}"
SUPPORTS_USER_DEFINED_LITERALS)
set(CMAKE_REQUIRED_FLAGS )

View File

@@ -1,581 +0,0 @@
"""Pythonic command-line interface parser that will make you smile.
* http://docopt.org
* Repository and issue-tracker: https://github.com/docopt/docopt
* Licensed under terms of MIT license (see LICENSE-MIT)
* Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com
"""
import sys
import re
__all__ = ['docopt']
__version__ = '0.6.1'
class DocoptLanguageError(Exception):
"""Error in construction of usage-message by developer."""
class DocoptExit(SystemExit):
"""Exit in case user invoked program with incorrect arguments."""
usage = ''
def __init__(self, message=''):
SystemExit.__init__(self, (message + '\n' + self.usage).strip())
class Pattern(object):
def __eq__(self, other):
return repr(self) == repr(other)
def __hash__(self):
return hash(repr(self))
def fix(self):
self.fix_identities()
self.fix_repeating_arguments()
return self
def fix_identities(self, uniq=None):
"""Make pattern-tree tips point to same object if they are equal."""
if not hasattr(self, 'children'):
return self
uniq = list(set(self.flat())) if uniq is None else uniq
for i, child in enumerate(self.children):
if not hasattr(child, 'children'):
assert child in uniq
self.children[i] = uniq[uniq.index(child)]
else:
child.fix_identities(uniq)
def fix_repeating_arguments(self):
"""Fix elements that should accumulate/increment values."""
either = [list(child.children) for child in transform(self).children]
for case in either:
for e in [child for child in case if case.count(child) > 1]:
if type(e) is Argument or type(e) is Option and e.argcount:
if e.value is None:
e.value = []
elif type(e.value) is not list:
e.value = e.value.split()
if type(e) is Command or type(e) is Option and e.argcount == 0:
e.value = 0
return self
def transform(pattern):
"""Expand pattern into an (almost) equivalent one, but with single Either.
Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
Quirks: [-a] => (-a), (-a...) => (-a -a)
"""
result = []
groups = [[pattern]]
while groups:
children = groups.pop(0)
parents = [Required, Optional, OptionsShortcut, Either, OneOrMore]
if any(t in map(type, children) for t in parents):
child = [c for c in children if type(c) in parents][0]
children.remove(child)
if type(child) is Either:
for c in child.children:
groups.append([c] + children)
elif type(child) is OneOrMore:
groups.append(child.children * 2 + children)
else:
groups.append(child.children + children)
else:
result.append(children)
return Either(*[Required(*e) for e in result])
class LeafPattern(Pattern):
"""Leaf/terminal node of a pattern tree."""
def __init__(self, name, value=None):
self.name, self.value = name, value
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
def flat(self, *types):
return [self] if not types or type(self) in types else []
def match(self, left, collected=None):
collected = [] if collected is None else collected
pos, match = self.single_match(left)
if match is None:
return False, left, collected
left_ = left[:pos] + left[pos + 1:]
same_name = [a for a in collected if a.name == self.name]
if type(self.value) in (int, list):
if type(self.value) is int:
increment = 1
else:
increment = ([match.value] if type(match.value) is str
else match.value)
if not same_name:
match.value = increment
return True, left_, collected + [match]
same_name[0].value += increment
return True, left_, collected
return True, left_, collected + [match]
class BranchPattern(Pattern):
"""Branch/inner node of a pattern tree."""
def __init__(self, *children):
self.children = list(children)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__,
', '.join(repr(a) for a in self.children))
def flat(self, *types):
if type(self) in types:
return [self]
return sum([child.flat(*types) for child in self.children], [])
class Argument(LeafPattern):
def single_match(self, left):
for n, pattern in enumerate(left):
if type(pattern) is Argument:
return n, Argument(self.name, pattern.value)
return None, None
@classmethod
def parse(class_, source):
name = re.findall('(<\S*?>)', source)[0]
value = re.findall('\[default: (.*)\]', source, flags=re.I)
return class_(name, value[0] if value else None)
class Command(Argument):
def __init__(self, name, value=False):
self.name, self.value = name, value
def single_match(self, left):
for n, pattern in enumerate(left):
if type(pattern) is Argument:
if pattern.value == self.name:
return n, Command(self.name, True)
else:
break
return None, None
class Option(LeafPattern):
def __init__(self, short=None, long=None, argcount=0, value=False):
assert argcount in (0, 1)
self.short, self.long, self.argcount = short, long, argcount
self.value = None if value is False and argcount else value
@classmethod
def parse(class_, option_description):
short, long, argcount, value = None, None, 0, False
options, _, description = option_description.strip().partition(' ')
options = options.replace(',', ' ').replace('=', ' ')
for s in options.split():
if s.startswith('--'):
long = s
elif s.startswith('-'):
short = s
else:
argcount = 1
if argcount:
matched = re.findall('\[default: (.*)\]', description, flags=re.I)
value = matched[0] if matched else None
return class_(short, long, argcount, value)
def single_match(self, left):
for n, pattern in enumerate(left):
if self.name == pattern.name:
return n, pattern
return None, None
@property
def name(self):
return self.long or self.short
def __repr__(self):
return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
self.argcount, self.value)
class Required(BranchPattern):
def match(self, left, collected=None):
collected = [] if collected is None else collected
l = left
c = collected
for pattern in self.children:
matched, l, c = pattern.match(l, c)
if not matched:
return False, left, collected
return True, l, c
class Optional(BranchPattern):
def match(self, left, collected=None):
collected = [] if collected is None else collected
for pattern in self.children:
m, left, collected = pattern.match(left, collected)
return True, left, collected
class OptionsShortcut(Optional):
"""Marker/placeholder for [options] shortcut."""
class OneOrMore(BranchPattern):
def match(self, left, collected=None):
assert len(self.children) == 1
collected = [] if collected is None else collected
l = left
c = collected
l_ = None
matched = True
times = 0
while matched:
# could it be that something didn't match but changed l or c?
matched, l, c = self.children[0].match(l, c)
times += 1 if matched else 0
if l_ == l:
break
l_ = l
if times >= 1:
return True, l, c
return False, left, collected
class Either(BranchPattern):
def match(self, left, collected=None):
collected = [] if collected is None else collected
outcomes = []
for pattern in self.children:
matched, _, _ = outcome = pattern.match(left, collected)
if matched:
outcomes.append(outcome)
if outcomes:
return min(outcomes, key=lambda outcome: len(outcome[1]))
return False, left, collected
class Tokens(list):
def __init__(self, source, error=DocoptExit):
self += source.split() if hasattr(source, 'split') else source
self.error = error
@staticmethod
def from_pattern(source):
source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source)
source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s]
return Tokens(source, error=DocoptLanguageError)
def move(self):
return self.pop(0) if len(self) else None
def current(self):
return self[0] if len(self) else None
def parse_long(tokens, options):
"""long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
long, eq, value = tokens.move().partition('=')
assert long.startswith('--')
value = None if eq == value == '' else value
similar = [o for o in options if o.long == long]
if tokens.error is DocoptExit and similar == []: # if no exact match
similar = [o for o in options if o.long and o.long.startswith(long)]
if len(similar) > 1: # might be simply specified ambiguously 2+ times?
raise tokens.error('%s is not a unique prefix: %s?' %
(long, ', '.join(o.long for o in similar)))
elif len(similar) < 1:
argcount = 1 if eq == '=' else 0
o = Option(None, long, argcount)
options.append(o)
if tokens.error is DocoptExit:
o = Option(None, long, argcount, value if argcount else True)
else:
o = Option(similar[0].short, similar[0].long,
similar[0].argcount, similar[0].value)
if o.argcount == 0:
if value is not None:
raise tokens.error('%s must not have an argument' % o.long)
else:
if value is None:
if tokens.current() in [None, '--']:
raise tokens.error('%s requires argument' % o.long)
value = tokens.move()
if tokens.error is DocoptExit:
o.value = value if value is not None else True
return [o]
def parse_shorts(tokens, options):
"""shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
token = tokens.move()
assert token.startswith('-') and not token.startswith('--')
left = token.lstrip('-')
parsed = []
while left != '':
short, left = '-' + left[0], left[1:]
similar = [o for o in options if o.short == short]
if len(similar) > 1:
raise tokens.error('%s is specified ambiguously %d times' %
(short, len(similar)))
elif len(similar) < 1:
o = Option(short, None, 0)
options.append(o)
if tokens.error is DocoptExit:
o = Option(short, None, 0, True)
else: # why copying is necessary here?
o = Option(short, similar[0].long,
similar[0].argcount, similar[0].value)
value = None
if o.argcount != 0:
if left == '':
if tokens.current() in [None, '--']:
raise tokens.error('%s requires argument' % short)
value = tokens.move()
else:
value = left
left = ''
if tokens.error is DocoptExit:
o.value = value if value is not None else True
parsed.append(o)
return parsed
def parse_pattern(source, options):
tokens = Tokens.from_pattern(source)
result = parse_expr(tokens, options)
if tokens.current() is not None:
raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
return Required(*result)
def parse_expr(tokens, options):
"""expr ::= seq ( '|' seq )* ;"""
seq = parse_seq(tokens, options)
if tokens.current() != '|':
return seq
result = [Required(*seq)] if len(seq) > 1 else seq
while tokens.current() == '|':
tokens.move()
seq = parse_seq(tokens, options)
result += [Required(*seq)] if len(seq) > 1 else seq
return [Either(*result)] if len(result) > 1 else result
def parse_seq(tokens, options):
"""seq ::= ( atom [ '...' ] )* ;"""
result = []
while tokens.current() not in [None, ']', ')', '|']:
atom = parse_atom(tokens, options)
if tokens.current() == '...':
atom = [OneOrMore(*atom)]
tokens.move()
result += atom
return result
def parse_atom(tokens, options):
"""atom ::= '(' expr ')' | '[' expr ']' | 'options'
| long | shorts | argument | command ;
"""
token = tokens.current()
result = []
if token in '([':
tokens.move()
matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
result = pattern(*parse_expr(tokens, options))
if tokens.move() != matching:
raise tokens.error("unmatched '%s'" % token)
return [result]
elif token == 'options':
tokens.move()
return [OptionsShortcut()]
elif token.startswith('--') and token != '--':
return parse_long(tokens, options)
elif token.startswith('-') and token not in ('-', '--'):
return parse_shorts(tokens, options)
elif token.startswith('<') and token.endswith('>') or token.isupper():
return [Argument(tokens.move())]
else:
return [Command(tokens.move())]
def parse_argv(tokens, options, options_first=False):
"""Parse command-line argument vector.
If options_first:
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
else:
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
"""
parsed = []
while tokens.current() is not None:
if tokens.current() == '--':
return parsed + [Argument(None, v) for v in tokens]
elif tokens.current().startswith('--'):
parsed += parse_long(tokens, options)
elif tokens.current().startswith('-') and tokens.current() != '-':
parsed += parse_shorts(tokens, options)
elif options_first:
return parsed + [Argument(None, v) for v in tokens]
else:
parsed.append(Argument(None, tokens.move()))
return parsed
def parse_defaults(doc):
defaults = []
for s in parse_section('options:', doc):
# FIXME corner case "bla: options: --foo"
_, _, s = s.partition(':') # get rid of "options:"
split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:]
split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
options = [Option.parse(s) for s in split if s.startswith('-')]
defaults += options
return defaults
def parse_section(name, source):
pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
re.IGNORECASE | re.MULTILINE)
return [s.strip() for s in pattern.findall(source)]
def formal_usage(section):
_, _, section = section.partition(':') # drop "usage:"
pu = section.split()
return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
def extras(help, version, options, doc):
if help and any((o.name in ('-h', '--help')) and o.value for o in options):
print(doc.strip("\n"))
sys.exit()
if version and any(o.name == '--version' and o.value for o in options):
print(version)
sys.exit()
class Dict(dict):
def __repr__(self):
return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
def docopt(doc, argv=None, help=True, version=None, options_first=False):
"""Parse `argv` based on command-line interface described in `doc`.
`docopt` creates your command-line interface based on its
description that you pass as `doc`. Such description can contain
--options, <positional-argument>, commands, which could be
[optional], (required), (mutually | exclusive) or repeated...
Parameters
----------
doc : str
Description of your command-line interface.
argv : list of str, optional
Argument vector to be parsed. sys.argv[1:] is used if not
provided.
help : bool (default: True)
Set to False to disable automatic help on -h or --help
options.
version : any object
If passed, the object will be printed if --version is in
`argv`.
options_first : bool (default: False)
Set to True to require options precede positional arguments,
i.e. to forbid options and positional arguments intermix.
Returns
-------
args : dict
A dictionary, where keys are names of command-line elements
such as e.g. "--verbose" and "<path>", and values are the
parsed values of those elements.
Example
-------
>>> from docopt import docopt
>>> doc = '''
... Usage:
... my_program tcp <host> <port> [--timeout=<seconds>]
... my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
... my_program (-h | --help | --version)
...
... Options:
... -h, --help Show this screen and exit.
... --baud=<n> Baudrate [default: 9600]
... '''
>>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
>>> docopt(doc, argv)
{'--baud': '9600',
'--help': False,
'--timeout': '30',
'--version': False,
'<host>': '127.0.0.1',
'<port>': '80',
'serial': False,
'tcp': True}
See also
--------
* For video introduction see http://docopt.org
* Full documentation is available in README.rst as well as online
at https://github.com/docopt/docopt#readme
"""
argv = sys.argv[1:] if argv is None else argv
usage_sections = parse_section('usage:', doc)
if len(usage_sections) == 0:
raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
if len(usage_sections) > 1:
raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
DocoptExit.usage = usage_sections[0]
options = parse_defaults(doc)
pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
# [default] syntax for argument is disabled
#for a in pattern.flat(Argument):
# same_name = [d for d in arguments if d.name == a.name]
# if same_name:
# a.value = same_name[0].value
argv = parse_argv(Tokens(argv), list(options), options_first)
pattern_options = set(pattern.flat(Option))
for options_shortcut in pattern.flat(OptionsShortcut):
doc_options = parse_defaults(doc)
options_shortcut.children = list(set(doc_options) - pattern_options)
#if any_options:
# options_shortcut.children += [Option(o.short, o.long, o.argcount)
# for o in argv if type(o) is Option]
extras(help, version, argv, doc)
matched, left, collected = pattern.fix().match(argv)
if matched and left == []: # better error message if left?
return Dict((a.name, a.value) for a in (pattern.flat() + collected))
raise DocoptExit()

View File

@@ -1,13 +1,8 @@
#!/usr/bin/env python
"""Create a release.
Usage:
release.py [<branch>]
"""
# Release script
from __future__ import print_function
import datetime, docopt, fileinput, json, os, re, requests, shutil, sys, tempfile
import datetime, fileinput, json, os, re, requests, shutil, sys, tempfile
from docutils import nodes, writers, core
from subprocess import check_call
@@ -131,63 +126,58 @@ class Runner:
kwargs['cwd'] = kwargs.get('cwd', self.cwd)
check_call(args, **kwargs)
if __name__ == '__main__':
args = docopt.docopt(__doc__)
workdir = tempfile.mkdtemp()
try:
run = Runner()
fmt_dir = os.path.join(workdir, 'fmt')
branch = args.get('<branch>')
if branch is None:
branch = 'master'
run('git', 'clone', '-b', branch, 'git@github.com:fmtlib/fmt.git', fmt_dir)
workdir = tempfile.mkdtemp()
try:
run = Runner()
cppformat_dir = os.path.join(workdir, 'cppformat')
run('git', 'clone', 'git@github.com:cppformat/cppformat.git', cppformat_dir)
# Convert changelog from RST to GitHub-flavored Markdown and get the version.
changelog = 'ChangeLog.rst'
changelog_path = os.path.join(fmt_dir, changelog)
changes, version = core.publish_file(source_path=changelog_path, writer=MDWriter())
cmakelists = 'CMakeLists.txt'
for line in fileinput.input(os.path.join(fmt_dir, cmakelists), inplace=True):
prefix = 'set(FMT_VERSION '
if line.startswith(prefix):
line = prefix + version + ')\n'
sys.stdout.write(line)
# Convert changelog from RST to GitHub-flavored Markdown and get the version.
changelog = 'ChangeLog.rst'
changelog_path = os.path.join(cppformat_dir, changelog)
changes, version = core.publish_file(source_path=changelog_path, writer=MDWriter())
cmakelists = 'CMakeLists.txt'
for line in fileinput.input(os.path.join(cppformat_dir, cmakelists), inplace=True):
prefix = 'set(CPPFORMAT_VERSION '
if line.startswith(prefix):
line = prefix + version + ')\n'
sys.stdout.write(line)
# Update the version in the changelog.
title_len = 0
for line in fileinput.input(changelog_path, inplace=True):
if line.decode('utf-8').startswith(version + ' - TBD'):
line = version + ' - ' + datetime.date.today().isoformat()
title_len = len(line)
line += '\n'
elif title_len:
line = '-' * title_len + '\n'
title_len = 0
sys.stdout.write(line)
run.cwd = fmt_dir
run('git', 'checkout', '-b', 'release')
run('git', 'add', changelog, cmakelists)
run('git', 'commit', '-m', 'Update version')
# Update the version in the changelog.
title_len = 0
for line in fileinput.input(changelog_path, inplace=True):
if line.startswith(version + ' - TBD'):
line = version + ' - ' + datetime.date.today().isoformat()
title_len = len(line)
line += '\n'
elif title_len:
line = '-' * title_len + '\n'
title_len = 0
sys.stdout.write(line)
run.cwd = cppformat_dir
run('git', 'checkout', '-b', 'release')
run('git', 'add', changelog, cmakelists)
run('git', 'commit', '-m', 'Update version')
# Build the docs and package.
run('cmake', '.')
run('make', 'doc', 'package_source')
site_dir = os.path.join(workdir, 'fmtlib.github.io')
run('git', 'clone', 'git@github.com:fmtlib/fmtlib.github.io.git', site_dir)
doc_dir = os.path.join(site_dir, version)
shutil.copytree(os.path.join(fmt_dir, 'doc', 'html'), doc_dir,
ignore=shutil.ignore_patterns('.doctrees', '.buildinfo'))
run.cwd = site_dir
run('git', 'add', doc_dir)
run('git', 'commit', '-m', 'Update docs')
# Build the docs and package.
run('cmake', '.')
run('make', 'doc', 'package_source')
site_dir = os.path.join(workdir, 'cppformat.github.io')
run('git', 'clone', 'git@github.com:cppformat/cppformat.github.io.git', site_dir)
doc_dir = os.path.join(site_dir, version)
shutil.copytree(os.path.join(cppformat_dir, 'doc', 'html'), doc_dir,
ignore=shutil.ignore_patterns('.doctrees', '.buildinfo'))
run.cwd = site_dir
run('git', 'add', doc_dir)
run('git', 'commit', '-m', 'Update docs')
# Create a release on GitHub.
run('git', 'push', 'origin', 'release', cwd=fmt_dir)
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
params={'access_token': os.getenv('FMT_TOKEN')},
data=json.dumps({'tag_name': version, 'target_commitish': 'release',
'body': changes, 'draft': True}))
if r.status_code != 201:
raise Exception('Failed to create a release ' + str(r))
finally:
shutil.rmtree(workdir)
# Create a release on GitHub.
run('git', 'push', 'origin', 'release', cwd=cppformat_dir)
r = requests.post('https://api.github.com/repos/cppformat/cppformat/releases',
params={'access_token': os.getenv('CPPFORMAT_TOKEN')},
data=json.dumps({'tag_name1': version, 'target_commitish': 'release',
'body': changes, 'draft': True}))
if r.status_code != 201:
raise Exception('Failed to create a release ' + str(r))
finally:
shutil.rmtree(workdir)

View File

@@ -1,2 +1,2 @@
If you are not redirected automatically, follow the
`link to the fmt documentation <http://fmtlib.net/latest/>`_.
`link to the C++ Format documentation <http://cppformat.github.io/latest/>`_.

View File

@@ -2,15 +2,15 @@
{% block extrahead %}
<meta charset="UTF-8">
<meta http-equiv="refresh" content="1;url=http://fmtlib.net/latest/">
<meta http-equiv="refresh" content="1;url=http://cppformat.github.io/latest/">
<script type="text/javascript">
window.location.href = "http://fmtlib.net/latest/"
window.location.href = "http://cppformat.github.io/latest/"
</script>
<title>Page Redirection</title>
{% endblock %}
{% block document %}
If you are not redirected automatically, follow the <a href='http://fmtlib.net/latest/'>link to the fmt documentation</a>.
If you are not redirected automatically, follow the <a href='http://cppformat.github.io/latest/'>link to the C++ Format documentation</a>.
{% endblock %}
{% block footer %}

View File

@@ -12,15 +12,6 @@ def rmtree_if_exists(dir):
if e.errno == errno.ENOENT:
pass
def makedirs_if_not_exist(dir):
try:
os.makedirs(dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
build = os.environ['BUILD']
if build == 'Doc':
travis = 'TRAVIS' in os.environ
@@ -41,19 +32,20 @@ if build == 'Doc':
urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' +
deb_file, deb_file)
check_call(['sudo', 'dpkg', '-i', deb_file])
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
cppformat_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.insert(0, os.path.join(cppformat_dir, 'doc'))
import build
html_dir = build.build_docs()
repo = 'fmtlib.github.io'
repo = 'cppformat.github.io'
if travis and 'KEY' not in os.environ:
# Don't update the repo if building on Travis from an account that doesn't
# have push access.
print('Skipping update of ' + repo)
exit(0)
# Clone the fmtlib.github.io repo.
# Clone the cppformat.github.io repo.
rmtree_if_exists(repo)
git_url = 'https://github.com/' if travis else 'git@github.com:'
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
check_call(['git', 'clone', git_url + 'cppformat/{}.git'.format(repo)])
# Copy docs to the repo.
target_dir = os.path.join(repo, 'dev')
rmtree_if_exists(target_dir)
@@ -67,7 +59,7 @@ if build == 'Doc':
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
cmd = 'git push'
if travis:
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
cmd += ' https://$KEY@github.com/cppformat/cppformat.github.io.git master'
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
# Print the output without the key.
print(p.communicate()[0].replace(os.environ['KEY'], '$KEY'))
@@ -75,39 +67,11 @@ if build == 'Doc':
raise CalledProcessError(p.returncode, cmd)
exit(0)
standard = os.environ['STANDARD']
install_dir = os.path.join(fmt_dir, "_install")
build_dir = os.path.join(fmt_dir, "_build")
test_build_dir = os.path.join(fmt_dir, "_build_test")
# Configure library.
makedirs_if_not_exist(build_dir)
common_cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build
]
extra_cmake_flags = []
if standard != '0x':
extra_cmake_flags = ['-DCMAKE_CXX_FLAGS=-std=c++' + standard, '-DFMT_USE_CPP11=OFF']
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', fmt_dir] +
common_cmake_flags + extra_cmake_flags, cwd=build_dir)
# Build library.
check_call(['make', '-j4'], cwd=build_dir)
# Test library.
check_call(['git', 'submodule', 'update', '--init'])
check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + build, '-DFMT_PEDANTIC=ON', '.'])
check_call(['make', '-j4'])
env = os.environ.copy()
env['CTEST_OUTPUT_ON_FAILURE'] = '1'
if call(['make', 'test'], env=env, cwd=build_dir):
if call(['make', 'test'], env=env):
with open('Testing/Temporary/LastTest.log', 'r') as f:
print(f.read())
sys.exit(-1)
# Install library.
check_call(['make', 'install'], cwd=build_dir)
# Test installation.
makedirs_if_not_exist(test_build_dir)
check_call(['cmake', '-DCMAKE_CXX_FLAGS=-std=c++' + standard,
os.path.join(fmt_dir, "test", "find-package-test")] +
common_cmake_flags, cwd=test_build_dir)
check_call(['make', '-j4'], cwd=test_build_dir)

View File

@@ -19,7 +19,7 @@ class Git:
dir = tempfile.mkdtemp()
try:
git = Git(dir)
git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir)
git('clone', '-b', 'coverity', 'git@github.com:cppformat/cppformat.git', dir)
output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master')
if 'Fast-forward' not in output:
git('reset', 'HEAD', '.travis.yml')

View File

@@ -8,7 +8,6 @@
add_library(gmock STATIC
gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h)
target_compile_options(gmock PUBLIC ${CPP11_FLAG})
target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1)
target_include_directories(gmock PUBLIC .)
find_package(Threads)
@@ -39,9 +38,7 @@ set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
add_library(test-main STATIC ${TEST_MAIN_SRC})
target_compile_definitions(test-main PUBLIC
FMT_USE_FILE_DESCRIPTORS=$<BOOL:${HAVE_OPEN}>)
target_link_libraries(test-main gmock fmt)
include(CheckCXXCompilerFlag)
target_link_libraries(test-main gmock cppformat)
# Workaround GTest bug https://github.com/google/googletest/issues/705.
check_cxx_compiler_flag(
@@ -50,25 +47,17 @@ if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
target_compile_options(test-main PUBLIC -fno-delete-null-pointer-checks)
endif ()
# Use less strict pedantic flags for the tests because GMock doesn't compile
# cleanly with -pedantic and -std=c++98.
# relax pedantic flags for the tests
# TODO: fix warnings in tests to make this redundant. (e.g. -Wshadow,...)
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros)
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wno-long-long -Wno-variadic-macros)
endif ()
function(add_fmt_executable name)
add_executable(${name} ${ARGN})
if (MINGW)
target_link_libraries(${name} -static-libgcc -static-libstdc++)
endif ()
endfunction()
# Adds a test.
# Usage: add_fmt_test(name srcs...)
function(add_fmt_test name)
add_fmt_executable(${name} ${name}.cc ${ARGN})
add_executable(${name} ${name}.cc ${ARGN})
target_link_libraries(${name} test-main)
# define if certain c++ features can be used
target_compile_definitions(${name} PRIVATE
FMT_USE_TYPE_TRAITS=$<BOOL:${SUPPORTS_TYPE_TRAITS}>
@@ -83,22 +72,19 @@ add_fmt_test(assert-test)
add_fmt_test(gtest-extra-test)
add_fmt_test(format-test)
add_fmt_test(format-impl-test)
add_fmt_test(ostream-test)
add_fmt_test(printf-test)
add_fmt_test(time-test)
add_fmt_test(util-test mock-allocator.h)
add_fmt_test(macro-test)
# Enable stricter options for one test to make sure that the header is free of
# warnings.
# TODO: make all tests warning free and add this flag to PEDANTIC_COMPILE_FLAGS
if (FMT_PEDANTIC AND MSVC)
target_compile_options(format-test PRIVATE /W4)
endif ()
if (HAVE_OPEN)
add_fmt_executable(posix-mock-test
posix-mock-test.cc ../fmt/format.cc ${TEST_MAIN_SRC})
add_executable(posix-mock-test posix-mock-test.cc ../cppformat/format.cc ${TEST_MAIN_SRC})
target_include_directories(posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR})
target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1)
target_link_libraries(posix-mock-test gmock)
@@ -106,11 +92,11 @@ if (HAVE_OPEN)
add_fmt_test(posix-test)
endif ()
add_fmt_executable(header-only-test
add_executable(header-only-test
header-only-test.cc header-only-test2.cc test-main.cc)
target_link_libraries(header-only-test gmock)
if (TARGET fmt-header-only)
target_link_libraries(header-only-test fmt-header-only)
if (TARGET cppformat-header-only)
target_link_libraries(header-only-test cppformat-header-only)
else ()
target_include_directories(header-only-test PRIVATE ${PROJECT_SOURCE_DIR})
target_compile_definitions(header-only-test PRIVATE FMT_HEADER_ONLY=1)
@@ -119,16 +105,14 @@ endif ()
# Test that the library can be compiled with exceptions disabled.
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
if (HAVE_FNO_EXCEPTIONS_FLAG)
add_library(noexception-test ../fmt/format.cc)
target_include_directories(noexception-test PRIVATE ${PROJECT_SOURCE_DIR})
add_library(noexception-test ../cppformat/format.cc)
target_compile_options(noexception-test PRIVATE -fno-exceptions)
endif ()
if (FMT_PEDANTIC)
# Test that the library compiles without windows.h.
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_library(no-windows-h-test ../fmt/format.cc)
target_include_directories(no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR})
add_library(no-windows-h-test ../cppformat/format.cc)
target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0)
endif ()
@@ -137,11 +121,7 @@ if (FMT_PEDANTIC)
"${CMAKE_CURRENT_SOURCE_DIR}/compile-test"
"${CMAKE_CURRENT_BINARY_DIR}/compile-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCPP11_FLAG=${CPP11_FLAG}"
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
--build-makeprogram ${CMAKE_MAKE_PROGRAM})
# test if the targets are findable from the build directory
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
@@ -151,10 +131,8 @@ if (FMT_PEDANTIC)
"${CMAKE_CURRENT_BINARY_DIR}/find-package-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DFMT_DIR=${PROJECT_BINARY_DIR}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
--build-options "-Dcppformat_DIR=${PROJECT_BINARY_DIR}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
# test if the targets are findable when add_subdirectory is used
add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
@@ -164,7 +142,5 @@ if (FMT_PEDANTIC)
"${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
--build-options "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif ()

View File

@@ -1,13 +1,13 @@
cmake_minimum_required(VERSION 2.8.12)
project(fmt-test)
project(cppformat-test)
add_subdirectory(../.. fmt)
add_subdirectory(../.. cppformat)
add_executable(library-test "main.cc")
target_link_libraries(library-test fmt)
add_executable(library-test "main.cpp")
target_link_libraries(library-test cppformat)
if (TARGET fmt-header-only)
add_executable(header-only-test "main.cc")
target_link_libraries(header-only-test fmt-header-only)
endif ()
if (TARGET cppformat-header-only)
add_executable(header-only-test "main.cpp")
target_link_libraries(header-only-test cppformat-header-only)
endif ()

View File

@@ -1,6 +0,0 @@
#include "fmt/format.h"
int main(int argc, char** argv) {
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
}

View File

@@ -0,0 +1,8 @@
#include "cppformat/format.h"
int main(int argc, char** argv)
{
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
return 0;
}

View File

@@ -25,7 +25,7 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fmt/format.h"
#include "cppformat/format.h"
#include "gtest/gtest.h"
#if GTEST_HAS_DEATH_TEST

View File

@@ -4,12 +4,11 @@ cmake_minimum_required(VERSION 2.8)
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../..)
set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG})
function (generate_source result fragment)
set(${result} "
#define FMT_HEADER_ONLY 1
#include \"fmt/posix.h\"
#include \"cppformat/format.h\"
int main() {
${fragment}
}
@@ -20,28 +19,22 @@ function (expect_compile code)
generate_source(source "${code}")
check_cxx_source_compiles("${source}" compiles)
if (NOT compiles)
set(error_msg "Compile error for: ${code}")
message(FATAL_ERROR "Compile error for: ${code}")
endif ()
# Unset the CMake cache variable compiles. Otherwise the compile test will
# just use cached information next time it runs.
unset(compiles CACHE)
if (error_msg)
message(FATAL_ERROR ${error_msg})
endif ()
endfunction ()
function (expect_compile_error code)
generate_source(source "${code}")
check_cxx_source_compiles("${source}" compiles)
if (compiles)
set(error_msg "No compile error for: ${code}")
message(FATAL_ERROR "No compile error for: ${code}")
endif ()
# Unset the CMake cache variable compiles. Otherwise the compile test will
# just use cached information next time it runs.
unset(compiles CACHE)
if (error_msg)
message(FATAL_ERROR ${error_msg})
endif ()
endfunction ()
# check if the source file skeleton compiles
@@ -63,16 +56,4 @@ expect_compile_error("fmt::MemoryWriter() << fmt::pad(42, 5, L' ');")
# Formatting a wide character with a narrow format string is forbidden.
expect_compile_error("fmt::format(\"{}\", L'a';")
expect_compile("FMT_STATIC_ASSERT(true, \"this should never happen\");")
expect_compile_error("FMT_STATIC_ASSERT(0 > 1, \"oops\");")
# Make sure that compiler features detected in the header
# match the features detected in CMake.
if (SUPPORTS_USER_DEFINED_LITERALS)
set(supports_udl 1)
else ()
set(supports_udl 0)
endif ()
expect_compile("#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
# error
#endif")

View File

@@ -1,13 +1,13 @@
cmake_minimum_required(VERSION 2.8.12)
project(fmt-test)
project(cppformat-test)
find_package(FMT REQUIRED)
find_package(cppformat REQUIRED)
add_executable(library-test main.cc)
target_link_libraries(library-test fmt)
add_executable(library-test "main.cpp")
target_link_libraries(library-test cppformat)
if (TARGET fmt-header-only)
add_executable(header-only-test main.cc)
target_link_libraries(header-only-test fmt-header-only)
if (TARGET cppformat-header-only)
add_executable(header-only-test "main.cpp")
target_link_libraries(header-only-test cppformat-header-only)
endif ()

View File

@@ -1,6 +0,0 @@
#include "fmt/format.h"
int main(int argc, char** argv) {
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
}

View File

@@ -0,0 +1,8 @@
#include "cppformat/format.h"
int main(int argc, char** argv)
{
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
return 0;
}

View File

@@ -29,16 +29,13 @@
#include "test-assert.h"
// Include format.cc instead of format.h to test implementation-specific stuff.
#include "fmt/format.cc"
#include "cppformat/format.cc"
#include <algorithm>
#include <cstring>
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "util.h"
#undef min
#undef max
TEST(FormatTest, ArgConverter) {
@@ -62,8 +59,7 @@ TEST(FormatTest, StrError) {
char *message = 0;
char buffer[BUFFER_SIZE];
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = 0, 0), "invalid buffer");
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
"invalid buffer");
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0), "invalid buffer");
buffer[0] = 'x';
#if defined(_GNU_SOURCE) && !defined(__COVERITY__)
// Use invalid error code to make sure that safe_strerror returns an error
@@ -105,21 +101,13 @@ TEST(FormatTest, FormatErrorCode) {
fmt::format_error_code(w, 42, prefix);
EXPECT_EQ(msg, w.str());
}
int codes[] = {42, -1};
for (std::size_t i = 0, n = sizeof(codes) / sizeof(*codes); i < n; ++i) {
// Test maximum buffer size.
msg = fmt::format("error {}", codes[i]);
{
fmt::MemoryWriter w;
std::string prefix(
fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x');
fmt::format_error_code(w, codes[i], prefix);
fmt::format_error_code(w, 42, prefix);
EXPECT_EQ(prefix + sep + msg, w.str());
std::size_t size = fmt::internal::INLINE_BUFFER_SIZE;
EXPECT_EQ(size, w.size());
w.clear();
// Test with a message that doesn't fit into the buffer.
prefix += 'x';
fmt::format_error_code(w, codes[i], prefix);
EXPECT_EQ(msg, w.str());
}
}

View File

@@ -28,10 +28,12 @@
#include <cctype>
#include <cfloat>
#include <climits>
#include <clocale>
#include <cmath>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <memory>
#include <sstream>
#include <stdint.h>
#if FMT_USE_TYPE_TRAITS
@@ -43,24 +45,7 @@
// Test that the library compiles if None is defined to 0 as done by xlib.h.
#define None 0
struct LocaleMock {
static LocaleMock *instance;
MOCK_METHOD0(localeconv, lconv *());
} *LocaleMock::instance;
namespace fmt {
namespace std {
using namespace ::std;
lconv *localeconv() {
return LocaleMock::instance ?
LocaleMock::instance->localeconv() : ::std::localeconv();
}
}
}
#include "fmt/format.h"
#include "cppformat/format.h"
#include "util.h"
#include "mock-allocator.h"
#include "gtest-extra.h"
@@ -398,10 +383,30 @@ TEST(WriterTest, hexu) {
EXPECT_EQ("DEADBEEF", (MemoryWriter() << hexu(0xdeadbeefull)).str());
}
template <typename Char>
BasicWriter<Char> &operator<<(BasicWriter<Char> &f, const Date &d) {
return f << d.year() << '-' << d.month() << '-' << d.day();
}
class Date {
int year_, month_, day_;
public:
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
int year() const { return year_; }
int month() const { return month_; }
int day() const { return day_; }
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
os << d.year_ << '-' << d.month_ << '-' << d.day_;
return os;
}
friend std::wostream &operator<<(std::wostream &os, const Date &d) {
os << d.year_ << L'-' << d.month_ << L'-' << d.day_;
return os;
}
template <typename Char>
friend BasicWriter<Char> &operator<<(BasicWriter<Char> &f, const Date &d) {
return f << d.year_ << '-' << d.month_ << '-' << d.day_;
}
};
class ISO8601DateFormatter {
const Date *date_;
@@ -657,6 +662,7 @@ TEST(FormatterTest, LeftAlign) {
EXPECT_EQ("c ", format("{0:<5}", 'c'));
EXPECT_EQ("abc ", format("{0:<5}", "abc"));
EXPECT_EQ("0xface ", format("{0:<8}", reinterpret_cast<void*>(0xface)));
EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
}
TEST(FormatterTest, RightAlign) {
@@ -674,6 +680,7 @@ TEST(FormatterTest, RightAlign) {
EXPECT_EQ(" c", format("{0:>5}", 'c'));
EXPECT_EQ(" abc", format("{0:>5}", "abc"));
EXPECT_EQ(" 0xface", format("{0:>8}", reinterpret_cast<void*>(0xface)));
EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
}
TEST(FormatterTest, NumericAlign) {
@@ -699,6 +706,8 @@ TEST(FormatterTest, NumericAlign) {
FormatError, "format specifier '=' requires numeric argument");
EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast<void*>(0xface)),
FormatError, "format specifier '=' requires numeric argument");
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
FormatError, "format specifier '=' requires numeric argument");
}
TEST(FormatterTest, CenterAlign) {
@@ -716,6 +725,7 @@ TEST(FormatterTest, CenterAlign) {
EXPECT_EQ(" c ", format("{0:^5}", 'c'));
EXPECT_EQ(" abc ", format("{0:^6}", "abc"));
EXPECT_EQ(" 0xface ", format("{0:^8}", reinterpret_cast<void*>(0xface)));
EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
}
TEST(FormatterTest, Fill) {
@@ -735,6 +745,7 @@ TEST(FormatterTest, Fill) {
EXPECT_EQ("c****", format("{0:*<5}", 'c'));
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
}
TEST(FormatterTest, PlusSign) {
@@ -759,6 +770,8 @@ TEST(FormatterTest, PlusSign) {
FormatError, "format specifier '+' requires numeric argument");
EXPECT_THROW_MSG(format("{0:+}", reinterpret_cast<void*>(0x42)),
FormatError, "format specifier '+' requires numeric argument");
EXPECT_THROW_MSG(format("{0:+}", TestString()),
FormatError, "format specifier '+' requires numeric argument");
}
TEST(FormatterTest, MinusSign) {
@@ -783,6 +796,8 @@ TEST(FormatterTest, MinusSign) {
FormatError, "format specifier '-' requires numeric argument");
EXPECT_THROW_MSG(format("{0:-}", reinterpret_cast<void*>(0x42)),
FormatError, "format specifier '-' requires numeric argument");
EXPECT_THROW_MSG(format("{0:-}", TestString()),
FormatError, "format specifier '-' requires numeric argument");
}
TEST(FormatterTest, SpaceSign) {
@@ -807,6 +822,8 @@ TEST(FormatterTest, SpaceSign) {
FormatError, "format specifier ' ' requires numeric argument");
EXPECT_THROW_MSG(format("{0: }", reinterpret_cast<void*>(0x42)),
FormatError, "format specifier ' ' requires numeric argument");
EXPECT_THROW_MSG(format("{0: }", TestString()),
FormatError, "format specifier ' ' requires numeric argument");
}
TEST(FormatterTest, HashFlag) {
@@ -852,6 +869,8 @@ TEST(FormatterTest, HashFlag) {
FormatError, "format specifier '#' requires numeric argument");
EXPECT_THROW_MSG(format("{0:#}", reinterpret_cast<void*>(0x42)),
FormatError, "format specifier '#' requires numeric argument");
EXPECT_THROW_MSG(format("{0:#}", TestString()),
FormatError, "format specifier '#' requires numeric argument");
}
TEST(FormatterTest, ZeroFlag) {
@@ -872,6 +891,8 @@ TEST(FormatterTest, ZeroFlag) {
FormatError, "format specifier '0' requires numeric argument");
EXPECT_THROW_MSG(format("{0:05}", reinterpret_cast<void*>(0x42)),
FormatError, "format specifier '0' requires numeric argument");
EXPECT_THROW_MSG(format("{0:05}", TestString()),
FormatError, "format specifier '0' requires numeric argument");
}
TEST(FormatterTest, Width) {
@@ -899,6 +920,7 @@ TEST(FormatterTest, Width) {
EXPECT_EQ(" 0xcafe", format("{0:10}", reinterpret_cast<void*>(0xcafe)));
EXPECT_EQ("x ", format("{0:11}", 'x'));
EXPECT_EQ("str ", format("{0:12}", "str"));
EXPECT_EQ("test ", format("{0:13}", TestString("test")));
}
TEST(FormatterTest, RuntimeWidth) {
@@ -932,7 +954,7 @@ TEST(FormatterTest, RuntimeWidth) {
FormatError, "number is too big");
EXPECT_THROW_MSG(format("{0:{1}}", 0, -1l),
FormatError, "negative width");
if (fmt::internal::const_check(sizeof(long) > sizeof(int))) {
if (fmt::internal::check(sizeof(long) > sizeof(int))) {
long value = INT_MAX;
EXPECT_THROW_MSG(format("{0:{1}}", 0, (value + 1)),
FormatError, "number is too big");
@@ -957,6 +979,7 @@ TEST(FormatterTest, RuntimeWidth) {
format("{0:{1}}", reinterpret_cast<void*>(0xcafe), 10));
EXPECT_EQ("x ", format("{0:{1}}", 'x', 11));
EXPECT_EQ("str ", format("{0:{1}}", "str", 12));
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
}
TEST(FormatterTest, Precision) {
@@ -1016,6 +1039,7 @@ TEST(FormatterTest, Precision) {
FormatError, "precision not allowed in pointer format specifier");
EXPECT_EQ("st", format("{0:.2}", "str"));
EXPECT_EQ("te", format("{0:.2}", TestString("test")));
}
TEST(FormatterTest, RuntimePrecision) {
@@ -1051,7 +1075,7 @@ TEST(FormatterTest, RuntimePrecision) {
FormatError, "number is too big");
EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1l),
FormatError, "negative precision");
if (fmt::internal::const_check(sizeof(long) > sizeof(int))) {
if (fmt::internal::check(sizeof(long) > sizeof(int))) {
long value = INT_MAX;
EXPECT_THROW_MSG(format("{0:.{1}}", 0, (value + 1)),
FormatError, "number is too big");
@@ -1099,6 +1123,7 @@ TEST(FormatterTest, RuntimePrecision) {
FormatError, "precision not allowed in pointer format specifier");
EXPECT_EQ("st", format("{0:.{1}}", "str", 2));
EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2));
}
template <typename T>
@@ -1139,7 +1164,7 @@ TEST(FormatterTest, FormatShort) {
TEST(FormatterTest, FormatInt) {
EXPECT_THROW_MSG(format("{0:v", 42),
FormatError, "missing '}' in format string");
check_unknown_types(42, "bBdoxXn", "integer");
check_unknown_types(42, "bBdoxX", "integer");
}
TEST(FormatterTest, FormatBin) {
@@ -1223,17 +1248,6 @@ TEST(FormatterTest, FormatOct) {
EXPECT_EQ(buffer, format("{0:o}", ULONG_MAX));
}
TEST(FormatterTest, FormatIntLocale) {
ScopedMock<LocaleMock> mock;
lconv lc = {};
char sep[] = "--";
lc.thousands_sep = sep;
EXPECT_CALL(mock, localeconv()).Times(3).WillRepeatedly(testing::Return(&lc));
EXPECT_EQ("123", format("{:n}", 123));
EXPECT_EQ("1--234", format("{:n}", 1234));
EXPECT_EQ("1--234--567", format("{:n}", 1234567));
}
TEST(FormatterTest, FormatFloat) {
EXPECT_EQ("392.500000", format("{0:f}", 392.5f));
}
@@ -1297,7 +1311,7 @@ TEST(FormatterTest, FormatLongDouble) {
}
TEST(FormatterTest, FormatChar) {
const char types[] = "cbBdoxXn";
const char types[] = "cbBdoxX";
check_unknown_types('a', types, "char");
EXPECT_EQ("a", format("{0}", 'a'));
EXPECT_EQ("z", format("{0:c}", 'z'));
@@ -1343,8 +1357,6 @@ TEST(FormatterTest, FormatUCharString) {
EXPECT_EQ("test", format("{0:s}", str));
const unsigned char *const_str = str;
EXPECT_EQ("test", format("{0:s}", const_str));
unsigned char *ptr = str;
EXPECT_EQ("test", format("{0:s}", ptr));
}
TEST(FormatterTest, FormatPointer) {
@@ -1368,14 +1380,14 @@ TEST(FormatterTest, FormatCStringRef) {
EXPECT_EQ("test", format("{0}", CStringRef("test")));
}
void format(fmt::BasicFormatter<char> &f, const char *, const Date &d) {
f.writer() << d.year() << '-' << d.month() << '-' << d.day();
}
TEST(FormatterTest, FormatCustom) {
TEST(FormatterTest, FormatUsingIOStreams) {
EXPECT_EQ("a string", format("{0}", TestString("a string")));
std::string s = format("The date is {0}", Date(2012, 12, 9));
EXPECT_EQ("The date is 2012-12-9", s);
Date date(2012, 12, 9);
EXPECT_THROW_MSG(fmt::format("{:s}", date), FormatError,
"unmatched '}' in format string");
check_unknown_types(date, "s", "string");
EXPECT_EQ(L"The date is 2012-12-9",
format(L"The date is {0}", Date(2012, 12, 9)));
}
class Answer {};
@@ -1538,6 +1550,9 @@ TEST(FormatTest, Print) {
EXPECT_WRITE(stderr,
fmt::print(stderr, "Don't {}!", "panic"), "Don't panic!");
#endif
std::ostringstream os;
fmt::print(os, "Don't {}!", "panic");
EXPECT_EQ("Don't panic!", os.str());
}
#if FMT_USE_FILE_DESCRIPTORS
@@ -1623,33 +1638,23 @@ TEST(LiteralsTest, NamedArg) {
}
#endif // FMT_USE_USER_DEFINED_LITERALS
enum TestEnum { A };
enum TestEnum {};
std::ostream &operator<<(std::ostream &os, TestEnum) {
return os << "TestEnum";
}
enum TestEnum2 { A };
TEST(FormatTest, Enum) {
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
EXPECT_EQ("0", fmt::format("{}", A));
}
class MockArgFormatter :
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
public:
typedef fmt::internal::ArgFormatterBase<MockArgFormatter, char> Base;
MockArgFormatter(fmt::BasicFormatter<char, MockArgFormatter> &f,
fmt::FormatSpec &s, const char *)
: fmt::internal::ArgFormatterBase<MockArgFormatter, char>(f.writer(), s) {
EXPECT_CALL(*this, visit_int(42));
}
MOCK_METHOD1(visit_int, void (int value));
};
void custom_format(const char *format_str, fmt::ArgList args) {
fmt::MemoryWriter writer;
fmt::BasicFormatter<char, MockArgFormatter> formatter(args, writer);
formatter.format(format_str);
struct EmptyTest {};
std::ostream &operator<<(std::ostream &os, EmptyTest) {
return os << "";
}
FMT_VARIADIC(void, custom_format, const char *)
TEST(FormatTest, CustomArgFormatter) {
custom_format("{}", 42);
TEST(FormatTest, EmptyCustomOutput) {
EXPECT_EQ("", fmt::format("{}", EmptyTest()));
}

View File

@@ -10090,9 +10090,8 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// threads concurrently.
Result InvokeWith(const ArgumentTuple& args)
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
const ResultHolder *rh = static_cast<const ResultHolder*>(
this->UntypedInvokeWith(&args));
return rh ? rh->GetValueAndDelete() : Result();
return static_cast<const ResultHolder*>(
this->UntypedInvokeWith(&args))->GetValueAndDelete();
}
// Adds and returns a default action spec for this mock function.

View File

@@ -46,7 +46,7 @@ namespace {
std::string sanitize(const std::string &s) {
std::string result;
for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i)
result.push_back(static_cast<char>(*i & 0xff));
result.push_back(*i & 0xff);
return result;
}

View File

@@ -80,10 +80,10 @@ std::string OutputRedirect::restore_and_read() {
return content; // Already read.
enum { BUFFER_SIZE = 4096 };
char buffer[BUFFER_SIZE];
std::size_t count = 0;
std::streamsize count = 0;
do {
count = read_end_.read(buffer, BUFFER_SIZE);
content.append(buffer, count);
content.append(buffer, static_cast<std::size_t>(count));
} while (count != 0);
read_end_.close();
return content;
@@ -91,7 +91,8 @@ std::string OutputRedirect::restore_and_read() {
std::string read(File &f, std::size_t count) {
std::string buffer(count, '\0');
std::size_t n = 0, offset = 0;
std::streamsize n = 0;
std::size_t offset = 0;
do {
n = f.read(&buffer[offset], count - offset);
// We can't read more than size_t bytes since count has type size_t.

View File

@@ -29,16 +29,16 @@
#define FMT_GTEST_EXTRA_H_
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "fmt/format.h"
#include "cppformat/format.h"
#ifndef FMT_USE_FILE_DESCRIPTORS
# define FMT_USE_FILE_DESCRIPTORS 0
#endif
#if FMT_USE_FILE_DESCRIPTORS
# include "fmt/posix.h"
# include "cppformat/posix.h"
#endif
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
@@ -172,10 +172,4 @@ std::string read(fmt::File &f, std::size_t count);
#endif // FMT_USE_FILE_DESCRIPTORS
template <typename Mock>
struct ScopedMock : testing::StrictMock<Mock> {
ScopedMock() { Mock::instance = this; }
~ScopedMock() { Mock::instance = 0; }
};
#endif // FMT_GTEST_EXTRA_H_

View File

@@ -1,3 +1,28 @@
// Header-only configuration test
/*
Header-only configuration test
#include "fmt/format.h"
Copyright (c) 2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
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
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "cppformat/format.h"

View File

@@ -1,3 +1,28 @@
// Additional translation unit for the header-only configuration test
/*
Additional translation unit for the header-only configuration test
#include "fmt/format.h"
Copyright (c) 2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
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
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "cppformat/format.h"

View File

@@ -29,7 +29,7 @@
#include <gtest/gtest.h>
#define FMT_USE_VARIADIC_TEMPLATES 0
#include "fmt/format.h"
#include "cppformat/format.h"
#define IDENTITY(x) x
@@ -67,7 +67,7 @@ TEST(UtilTest, NArg) {
int result;
#define MAKE_TEST(func) \
void func(const char *, const fmt::ArgList &args) { \
void func(const char *format, const fmt::ArgList &args) { \
result = 0; \
for (unsigned i = 0; args[i].type; ++i) \
result += args[i].int_value; \

View File

@@ -1,192 +0,0 @@
/*
std::ostream support tests
Copyright (c) 2012-2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
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
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
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
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fmt/ostream.cc"
#include <sstream>
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "util.h"
using fmt::format;
using fmt::FormatError;
template <typename Char>
std::basic_ostream<Char> &operator<<(
std::basic_ostream<Char> &os, const BasicTestString<Char> &s) {
os << s.value();
return os;
}
std::ostream &operator<<(std::ostream &os, const Date &d) {
os << d.year() << '-' << d.month() << '-' << d.day();
return os;
}
std::wostream &operator<<(std::wostream &os, const Date &d) {
os << d.year() << L'-' << d.month() << L'-' << d.day();
return os;
}
enum TestEnum {};
std::ostream &operator<<(std::ostream &os, TestEnum) {
return os << "TestEnum";
}
enum TestEnum2 {A};
TEST(OStreamTest, Enum) {
EXPECT_FALSE(fmt::internal::ConvertToInt<TestEnum>::value);
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
EXPECT_EQ("0", fmt::format("{}", A));
}
struct TestArgFormatter : fmt::BasicArgFormatter<TestArgFormatter, char> {
TestArgFormatter(fmt::BasicFormatter<char, TestArgFormatter> &f,
fmt::FormatSpec &s, const char *fmt)
: fmt::BasicArgFormatter<TestArgFormatter, char>(f, s, fmt) {}
};
TEST(OStreamTest, CustomArg) {
fmt::MemoryWriter writer;
typedef fmt::BasicFormatter<char, TestArgFormatter> Formatter;
Formatter formatter(fmt::ArgList(), writer);
fmt::FormatSpec spec;
TestArgFormatter af(formatter, spec, "}");
af.visit(fmt::internal::MakeArg<Formatter>(TestEnum()));
EXPECT_EQ("TestEnum", writer.str());
}
TEST(OStreamTest, Format) {
EXPECT_EQ("a string", format("{0}", TestString("a string")));
std::string s = format("The date is {0}", Date(2012, 12, 9));
EXPECT_EQ("The date is 2012-12-9", s);
Date date(2012, 12, 9);
EXPECT_EQ(L"The date is 2012-12-9",
format(L"The date is {0}", Date(2012, 12, 9)));
}
TEST(OStreamTest, FormatSpecs) {
EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
FormatError, "format specifier '=' requires numeric argument");
EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
EXPECT_THROW_MSG(format("{0:+}", TestString()),
FormatError, "format specifier '+' requires numeric argument");
EXPECT_THROW_MSG(format("{0:-}", TestString()),
FormatError, "format specifier '-' requires numeric argument");
EXPECT_THROW_MSG(format("{0: }", TestString()),
FormatError, "format specifier ' ' requires numeric argument");
EXPECT_THROW_MSG(format("{0:#}", TestString()),
FormatError, "format specifier '#' requires numeric argument");
EXPECT_THROW_MSG(format("{0:05}", TestString()),
FormatError, "format specifier '0' requires numeric argument");
EXPECT_EQ("test ", format("{0:13}", TestString("test")));
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
EXPECT_EQ("te", format("{0:.2}", TestString("test")));
EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2));
}
struct EmptyTest {};
std::ostream &operator<<(std::ostream &os, EmptyTest) {
return os << "";
}
TEST(OStreamTest, EmptyCustomOutput) {
EXPECT_EQ("", fmt::format("{}", EmptyTest()));
}
TEST(OStreamTest, Print) {
std::ostringstream os;
fmt::print(os, "Don't {}!", "panic");
EXPECT_EQ("Don't panic!", os.str());
}
TEST(OStreamTest, PrintfCustom) {
EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc")));
}
TEST(OStreamTest, FPrintf) {
std::ostringstream os;
int ret = fmt::fprintf(os, "Don't %s!", "panic");
EXPECT_EQ("Don't panic!", os.str());
EXPECT_EQ(12, ret);
}
TEST(OStreamTest, WriteToOStream) {
std::ostringstream os;
fmt::MemoryWriter w;
w << "foo";
fmt::write(os, w);
EXPECT_EQ("foo", os.str());
}
TEST(OStreamTest, WriteToOStreamMaxSize) {
std::size_t max_size = std::numeric_limits<std::size_t>::max();
std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max();
if (max_size <= fmt::internal::to_unsigned(max_streamsize))
return;
class TestWriter : public fmt::BasicWriter<char> {
private:
struct TestBuffer : fmt::Buffer<char> {
explicit TestBuffer(std::size_t size) { size_ = size; }
void grow(std::size_t) {}
} buffer_;
public:
explicit TestWriter(std::size_t size)
: fmt::BasicWriter<char>(buffer_), buffer_(size) {}
} w(max_size);
struct MockStreamBuf : std::streambuf {
MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
std::streamsize xsputn(const char *s, std::streamsize n) {
const void *v = s;
return xsputn(v, n);
}
} buffer;
struct TestOStream : std::ostream {
explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {}
} os(buffer);
testing::InSequence sequence;
const char *data = 0;
std::size_t size = max_size;
do {
typedef fmt::internal::MakeUnsigned<std::streamsize>::Type UStreamSize;
UStreamSize n = std::min<UStreamSize>(
size, fmt::internal::to_unsigned(max_streamsize));
EXPECT_CALL(buffer, xsputn(data, static_cast<std::streamsize>(n)))
.WillOnce(testing::Return(max_streamsize));
data += n;
size -= static_cast<std::size_t>(n);
} while (size != 0);
fmt::write(os, w);
}

View File

@@ -29,7 +29,7 @@
#define _CRT_SECURE_NO_WARNINGS
#include "posix-mock.h"
#include "fmt/posix.cc"
#include "cppformat/posix.cc"
#include <errno.h>
#include <fcntl.h>
@@ -41,7 +41,6 @@
# undef ERROR
#endif
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "util.h"
@@ -50,9 +49,6 @@ using fmt::ErrorCode;
using fmt::File;
using testing::internal::scoped_ptr;
using testing::_;
using testing::StrEq;
using testing::Return;
namespace {
int open_count;
@@ -277,7 +273,8 @@ TEST(FileTest, Size) {
write_file("test", content);
File f("test", File::RDONLY);
EXPECT_GE(f.size(), 0);
EXPECT_EQ(content.size(), static_cast<fmt::ULongLong>(f.size()));
fmt::ULongLong file_size = f.size();
EXPECT_EQ(content.size(), file_size);
#ifdef _WIN32
fmt::MemoryWriter message;
fmt::internal::format_windows_error(
@@ -307,7 +304,7 @@ TEST(FileTest, ReadRetry) {
write_end.write("test", SIZE);
write_end.close();
char buffer[SIZE];
std::size_t count = 0;
std::streamsize count = 0;
EXPECT_RETRY(count = read_end.read(buffer, SIZE),
read, "cannot read from file");
EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count);
@@ -317,7 +314,7 @@ TEST(FileTest, WriteRetry) {
File read_end, write_end;
File::pipe(read_end, write_end);
enum { SIZE = 4 };
std::size_t count = 0;
std::streamsize count = 0;
EXPECT_RETRY(count = write_end.write("test", SIZE),
write, "cannot write to file");
write_end.close();
@@ -452,103 +449,3 @@ TEST(BufferedFileTest, FilenoNoRetry) {
EXPECT_EQ(2, fileno_count);
fileno_count = 0;
}
struct TestMock {
static TestMock *instance;
} *TestMock::instance;
TEST(ScopedMock, Scope) {
{
ScopedMock<TestMock> mock;
EXPECT_EQ(&mock, TestMock::instance);
TestMock &copy = mock;
}
EXPECT_EQ(0, TestMock::instance);
}
#ifdef FMT_LOCALE
typedef fmt::Locale::Type LocaleType;
struct LocaleMock {
static LocaleMock *instance;
MOCK_METHOD3(newlocale, LocaleType (int category_mask, const char *locale,
LocaleType base));
MOCK_METHOD1(freelocale, void (LocaleType locale));
MOCK_METHOD3(strtod_l, double (const char *nptr, char **endptr,
LocaleType locale));
} *LocaleMock::instance;
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4273)
_locale_t _create_locale(int category, const char *locale) {
return LocaleMock::instance->newlocale(category, locale, 0);
}
void _free_locale(_locale_t locale) {
LocaleMock::instance->freelocale(locale);
}
double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
}
# pragma warning(pop)
#endif
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) {
return LocaleMock::instance->newlocale(category_mask, locale, base);
}
#ifdef __APPLE__
typedef int FreeLocaleResult;
#else
typedef void FreeLocaleResult;
#endif
FreeLocaleResult freelocale(LocaleType locale) {
LocaleMock::instance->freelocale(locale);
return FreeLocaleResult();
}
double strtod_l(const char *nptr, char **endptr, LocaleType locale) {
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
}
TEST(LocaleTest, LocaleMock) {
ScopedMock<LocaleMock> mock;
LocaleType locale = reinterpret_cast<LocaleType>(11);
EXPECT_CALL(mock, newlocale(222, StrEq("foo"), locale));
newlocale(222, "foo", locale);
}
TEST(LocaleTest, Locale) {
#ifndef LC_NUMERIC_MASK
enum { LC_NUMERIC_MASK = LC_NUMERIC };
#endif
ScopedMock<LocaleMock> mock;
LocaleType impl = reinterpret_cast<LocaleType>(42);
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), 0))
.WillOnce(Return(impl));
EXPECT_CALL(mock, freelocale(impl));
fmt::Locale locale;
EXPECT_EQ(impl, locale.get());
}
TEST(LocaleTest, Strtod) {
ScopedMock<LocaleMock> mock;
EXPECT_CALL(mock, newlocale(_, _, _))
.WillOnce(Return(reinterpret_cast<LocaleType>(42)));
EXPECT_CALL(mock, freelocale(_));
fmt::Locale locale;
const char *str = "4.2";
char end = 'x';
EXPECT_CALL(mock, strtod_l(str, _, locale.get()))
.WillOnce(testing::DoAll(testing::SetArgPointee<1>(&end), Return(777)));
EXPECT_EQ(777, locale.strtod(str));
EXPECT_EQ(&end, str);
}
#endif // FMT_LOCALE

View File

@@ -25,11 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdlib> // std::exit
#include <cstring>
#include "fmt/posix.h"
#include "gtest-extra.h"
#include "cppformat/posix.h"
#include "util.h"
#ifdef fileno
@@ -69,7 +68,7 @@ void write(File &f, fmt::StringRef s) {
std::size_t num_chars_left = s.size();
const char *ptr = s.data();
do {
std::size_t count = f.write(ptr, num_chars_left);
std::streamsize count = f.write(ptr, num_chars_left);
ptr += count;
// We can't write more than size_t bytes since num_chars_left
// has type size_t.
@@ -232,24 +231,24 @@ TEST(FileTest, MoveAssignmentClosesFile) {
File OpenBufferedFile(int &fd) {
File f = open_file();
fd = f.descriptor();
return f;
return std::move(f);
}
TEST(FileTest, MoveFromTemporaryInCtor) {
int fd = 0xdead;
int fd = 0xdeadbeef;
File f(OpenBufferedFile(fd));
EXPECT_EQ(fd, f.descriptor());
}
TEST(FileTest, MoveFromTemporaryInAssignment) {
int fd = 0xdead;
int fd = 0xdeadbeef;
File f;
f = OpenBufferedFile(fd);
EXPECT_EQ(fd, f.descriptor());
}
TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
int fd = 0xdead;
int fd = 0xdeadbeef;
File f = open_file();
int old_fd = f.descriptor();
f = OpenBufferedFile(fd);
@@ -387,12 +386,3 @@ TEST(FileTest, FdopenError) {
EXPECT_SYSTEM_ERROR_NOASSERT(
f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
}
#ifdef FMT_LOCALE
TEST(LocaleTest, Strtod) {
fmt::Locale locale;
const char *start = "4.2", *ptr = start;
EXPECT_EQ(4.2, locale.strtod(ptr));
EXPECT_EQ(start + 3, ptr);
}
#endif

View File

@@ -29,7 +29,7 @@
#include <climits>
#include <cstring>
#include "fmt/format.h"
#include "cppformat/format.h"
#include "gtest-extra.h"
#include "util.h"
@@ -289,26 +289,24 @@ SPECIALIZE_MAKE_SIGNED(unsigned, int);
SPECIALIZE_MAKE_SIGNED(unsigned long, long);
SPECIALIZE_MAKE_SIGNED(fmt::ULongLong, fmt::LongLong);
// Test length format specifier ``length_spec``.
template <typename T, typename U>
void TestLength(const char *length_spec, U value) {
fmt::LongLong signed_value = 0;
fmt::ULongLong unsigned_value = 0;
fmt::LongLong signed_value = value;
fmt::ULongLong unsigned_value = value;
// Apply integer promotion to the argument.
using std::numeric_limits;
fmt::ULongLong max = numeric_limits<U>::max();
using fmt::internal::const_check;
if (const_check(max <= static_cast<unsigned>(numeric_limits<int>::max()))) {
fmt::ULongLong max = std::numeric_limits<U>::max();
using fmt::internal::check;
if (check(max <= static_cast<unsigned>(std::numeric_limits<int>::max()))) {
signed_value = static_cast<int>(value);
unsigned_value = static_cast<unsigned>(value);
} else if (const_check(max <= numeric_limits<unsigned>::max())) {
unsigned_value = static_cast<int>(value);
} else if (check(max <= std::numeric_limits<unsigned>::max())) {
signed_value = static_cast<unsigned>(value);
unsigned_value = static_cast<unsigned>(value);
}
using fmt::internal::MakeUnsigned;
if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) {
signed_value = static_cast<fmt::LongLong>(value);
unsigned_value = static_cast<typename MakeUnsigned<unsigned>::Type>(value);
signed_value = unsigned_value =
static_cast<typename MakeUnsigned<unsigned>::Type>(value);
} else {
signed_value = static_cast<typename MakeSigned<T>::Type>(value);
unsigned_value = static_cast<typename MakeUnsigned<T>::Type>(value);
@@ -338,9 +336,12 @@ void TestLength(const char *length_spec) {
TestLength<T>(length_spec, -42);
TestLength<T>(length_spec, min);
TestLength<T>(length_spec, max);
TestLength<T>(length_spec, fmt::LongLong(min) - 1);
using fmt::internal::check;
fmt::LongLong long_long_min = std::numeric_limits<fmt::LongLong>::min();
if (check(min >= 0) || check(static_cast<fmt::LongLong>(min) > long_long_min))
TestLength<T>(length_spec, fmt::LongLong(min) - 1);
fmt::ULongLong long_long_max = std::numeric_limits<fmt::LongLong>::max();
if (static_cast<fmt::ULongLong>(max) < long_long_max)
if (check(max < 0 || static_cast<fmt::ULongLong>(max) < long_long_max))
TestLength<T>(length_spec, fmt::LongLong(max) + 1);
TestLength<T>(length_spec, std::numeric_limits<short>::min());
TestLength<T>(length_spec, std::numeric_limits<unsigned short>::max());
@@ -380,20 +381,13 @@ TEST(PrintfTest, Bool) {
TEST(PrintfTest, Int) {
EXPECT_PRINTF("-42", "%d", -42);
EXPECT_PRINTF("-42", "%i", -42);
unsigned u = 0 - 42u;
unsigned u = -42;
EXPECT_PRINTF(fmt::format("{}", u), "%u", -42);
EXPECT_PRINTF(fmt::format("{:o}", u), "%o", -42);
EXPECT_PRINTF(fmt::format("{:x}", u), "%x", -42);
EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42);
}
TEST(PrintfTest, LongLong) {
// fmt::printf allows passing long long arguments to %d without length
// specifiers.
fmt::LongLong max = std::numeric_limits<fmt::LongLong>::max();
EXPECT_PRINTF(fmt::format("{}", max), "%d", max);
}
TEST(PrintfTest, Float) {
EXPECT_PRINTF("392.650000", "%f", 392.65);
EXPECT_PRINTF("392.650000", "%F", 392.65);
@@ -448,6 +442,10 @@ TEST(PrintfTest, Pointer) {
EXPECT_PRINTF("(nil)", "%p", null_str);
}
TEST(PrintfTest, Custom) {
EXPECT_PRINTF("abc", "%s", TestString("abc"));
}
TEST(PrintfTest, Location) {
// TODO: test %n
}
@@ -476,5 +474,5 @@ TEST(PrintfTest, PrintfError) {
#endif
TEST(PrintfTest, WideString) {
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", TestWString(L"abc")));
}

View File

@@ -1,5 +1,5 @@
/*
Test main function.
Tests of additional gtest macros.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.

View File

@@ -1,33 +0,0 @@
/*
Time formatting tests
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "gmock/gmock.h"
#include "fmt/time.h"
TEST(TimeTest, Format) {
std::tm tm = std::tm();
tm.tm_year = 116;
tm.tm_mon = 3;
tm.tm_mday = 25;
EXPECT_EQ("The date is 2016-04-25.",
fmt::format("The date is {:%Y-%m-%d}.", tm));
}
TEST(TimeTest, GrowBuffer) {
std::string s = "{:";
for (int i = 0; i < 30; ++i)
s += "%c";
s += "}\n";
std::time_t t = std::time(0);
fmt::format(s, *std::localtime(&t));
}
TEST(TimeTest, EmptyResult) {
EXPECT_EQ("", fmt::format("{}", std::tm()));
}

View File

@@ -47,7 +47,7 @@
# include <windows.h>
#endif
#include "fmt/format.h"
#include "cppformat/format.h"
#undef max
@@ -62,17 +62,16 @@ using testing::StrictMock;
namespace {
struct Test {};
template <typename Char>
void format(fmt::BasicFormatter<Char> &f, const Char *, Test) {
f.writer() << "test";
std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &os, Test) {
return os << "test";
}
template <typename Char, typename T>
Arg make_arg(const T &value) {
typedef fmt::internal::MakeValue< fmt::BasicFormatter<Char> > MakeValue;
Arg arg = MakeValue(value);
arg.type = static_cast<Arg::Type>(MakeValue::type(value));
Arg arg = fmt::internal::MakeValue<Char>(value);
arg.type = static_cast<Arg::Type>(
fmt::internal::MakeValue<Char>::type(value));
return arg;
}
} // namespace
@@ -333,9 +332,8 @@ TEST(MemoryBufferTest, Grow) {
void grow(std::size_t size) { Base::grow(size); }
} buffer((Allocator(&alloc)));
buffer.resize(7);
using fmt::internal::to_unsigned;
for (int i = 0; i < 7; ++i)
buffer[to_unsigned(i)] = i * i;
buffer[i] = i * i;
EXPECT_EQ(10u, buffer.capacity());
int mem[20];
mem[7] = 0xdead;
@@ -344,7 +342,7 @@ TEST(MemoryBufferTest, Grow) {
EXPECT_EQ(20u, buffer.capacity());
// Check if size elements have been copied
for (int i = 0; i < 7; ++i)
EXPECT_EQ(i * i, buffer[to_unsigned(i)]);
EXPECT_EQ(i * i, buffer[i]);
// and no more than that.
EXPECT_EQ(0xdead, buffer[7]);
EXPECT_CALL(alloc, deallocate(mem, 20));
@@ -412,7 +410,7 @@ struct ArgInfo;
template <> \
struct ArgInfo<Arg::type_code> { \
static Type get(const Arg &arg) { return arg.field; } \
}
};
ARG_INFO(INT, int, int_value);
ARG_INFO(UINT, unsigned, uint_value);
@@ -577,23 +575,6 @@ TEST(UtilTest, ArgList) {
EXPECT_EQ(Arg::NONE, args[1].type);
}
struct CustomFormatter {
typedef char Char;
};
void format(CustomFormatter &, const char *&s, const Test &) {
s = "custom_format";
}
TEST(UtilTest, MakeValueWithCustomFormatter) {
::Test t;
Arg arg = fmt::internal::MakeValue<CustomFormatter>(t);
CustomFormatter formatter;
const char *s = "";
arg.custom.format(&formatter, &t, &s);
EXPECT_STREQ("custom_format", s);
}
struct Result {
Arg arg;
@@ -604,7 +585,7 @@ struct Result {
Result(const wchar_t *s) : arg(make_arg<wchar_t>(s)) {}
};
struct TestVisitor : fmt::ArgVisitor<TestVisitor, Result> {
struct TestVisitor : fmt::internal::ArgVisitor<TestVisitor, Result> {
Result visit_int(int value) { return value; }
Result visit_uint(unsigned value) { return value; }
Result visit_long_long(fmt::LongLong value) { return value; }
@@ -613,14 +594,10 @@ struct TestVisitor : fmt::ArgVisitor<TestVisitor, Result> {
Result visit_long_double(long double value) { return value; }
Result visit_char(int value) { return static_cast<char>(value); }
Result visit_cstring(const char *s) { return s; }
Result visit_string(fmt::internal::Arg::StringValue<char> s) {
return s.value;
}
Result visit_wstring(fmt::internal::Arg::StringValue<wchar_t> s) {
return s.value;
}
Result visit_string(Arg::StringValue<char> s) { return s.value; }
Result visit_wstring(Arg::StringValue<wchar_t> s) { return s.value; }
Result visit_pointer(const void *p) { return p; }
Result visit_custom(fmt::internal::Arg::CustomValue c) {
Result visit_custom(Arg::CustomValue c) {
return *static_cast<const ::Test*>(c.value);
}
};
@@ -657,7 +634,7 @@ TEST(ArgVisitorTest, VisitAll) {
EXPECT_EQ(&t, result.arg.custom.value);
}
struct TestAnyVisitor : fmt::ArgVisitor<TestAnyVisitor, Result> {
struct TestAnyVisitor : fmt::internal::ArgVisitor<TestAnyVisitor, Result> {
template <typename T>
Result visit_any_int(T value) { return value; }
@@ -682,7 +659,7 @@ TEST(ArgVisitorTest, VisitAny) {
}
struct TestUnhandledVisitor :
fmt::ArgVisitor<TestUnhandledVisitor, const char *> {
fmt::internal::ArgVisitor<TestUnhandledVisitor, const char *> {
const char *visit_unhandled_arg() { return "test"; }
};
@@ -708,7 +685,7 @@ TEST(ArgVisitorTest, VisitUnhandledArg) {
TEST(ArgVisitorTest, VisitInvalidArg) {
Arg arg = Arg();
arg.type = static_cast<Arg::Type>(Arg::NONE);
arg.type = static_cast<Arg::Type>(Arg::CUSTOM + 1);
EXPECT_ASSERT(TestVisitor().visit(arg), "invalid argument type");
}
@@ -878,27 +855,6 @@ TEST(UtilTest, FormatWindowsError) {
EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS), actual_message.str());
}
TEST(UtilTest, FormatLongWindowsError) {
LPWSTR message = 0;
// this error code is not available on all Windows platforms and
// Windows SDKs, so do not fail the test if the error string cannot
// be retrieved.
const int provisioning_not_allowed = 0x80284013L /*TBS_E_PROVISIONING_NOT_ALLOWED*/;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
provisioning_not_allowed, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message), 0, 0) == 0) {
return;
}
fmt::internal::UTF16ToUTF8 utf8_message(message);
LocalFree(message);
fmt::MemoryWriter actual_message;
fmt::internal::format_windows_error(
actual_message, provisioning_not_allowed, "test");
EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
actual_message.str());
}
TEST(UtilTest, WindowsError) {
check_throw_error<fmt::WindowsError>(
ERROR_FILE_EXISTS, fmt::internal::format_windows_error);
@@ -915,11 +871,14 @@ TEST(UtilTest, ReportWindowsError) {
#endif // _WIN32
enum TestEnum2 {};
enum TestEnum3 {};
std::ostream &operator<<(std::ostream &, TestEnum3);
TEST(UtilTest, ConvertToInt) {
EXPECT_TRUE(fmt::internal::ConvertToInt<char>::enable_conversion);
EXPECT_FALSE(fmt::internal::ConvertToInt<const char *>::enable_conversion);
EXPECT_TRUE(fmt::internal::ConvertToInt<TestEnum2>::value);
EXPECT_FALSE(fmt::internal::ConvertToInt<TestEnum3>::value);
}
#if FMT_USE_ENUM_BASE
@@ -956,17 +915,3 @@ TEST(UtilTest, Conditional) {
fmt::internal::Conditional<false, int, char>::type *pc = &c;
(void)pc;
}
struct TestLConv {
char *thousands_sep;
};
struct EmptyLConv {};
TEST(UtilTest, ThousandsSep) {
char foo[] = "foo";
TestLConv lc = {foo};
EXPECT_EQ("foo", fmt::internal::thousands_sep(&lc).to_string());
EmptyLConv empty_lc;
EXPECT_EQ("", fmt::internal::thousands_sep(&empty_lc));
}

View File

@@ -29,7 +29,7 @@
#include <cstdio>
#include <string>
#include "fmt/posix.h"
#include "cppformat/posix.h"
enum {BUFFER_SIZE = 256};
@@ -78,7 +78,11 @@ class BasicTestString {
public:
explicit BasicTestString(const Char *value = EMPTY) : value_(value) {}
const std::basic_string<Char> &value() const { return value_; }
friend std::basic_ostream<Char> &operator<<(
std::basic_ostream<Char> &os, const BasicTestString &s) {
os << s.value_;
return os;
}
};
template <typename Char>
@@ -86,13 +90,3 @@ const Char BasicTestString<Char>::EMPTY[] = {0};
typedef BasicTestString<char> TestString;
typedef BasicTestString<wchar_t> TestWString;
class Date {
int year_, month_, day_;
public:
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
int year() const { return year_; }
int month() const { return month_; }
int day() const { return day_; }
};