Merge branch 'develop' into next

This commit is contained in:
Sebastian Messmer 2017-06-27 00:34:22 +01:00
commit d4b56406a3
29 changed files with 1949 additions and 1203 deletions

View File

@ -24,5 +24,6 @@ endif(NOT CRYFS_UPDATE_CHECKS)
add_subdirectory(vendor) add_subdirectory(vendor)
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(doc)
add_subdirectory(test) add_subdirectory(test)
add_subdirectory(cpack) add_subdirectory(cpack)

View File

@ -5,3 +5,6 @@ GPGHOMEDIR=$2
git archive --format=tgz "$1" > cryfs-$1.tar.gz git archive --format=tgz "$1" > cryfs-$1.tar.gz
gpg --homedir "$GPGHOMEDIR" --armor --detach-sign cryfs-$1.tar.gz gpg --homedir "$GPGHOMEDIR" --armor --detach-sign cryfs-$1.tar.gz
git archive --format=tar "$1" | xz -9 > cryfs-$1.tar.xz
gpg --homedir "$GPGHOMEDIR" --armor --detach-sign cryfs-$1.tar.xz

View File

@ -39,8 +39,8 @@ if(BUILDTYPE MATCHES RELEASE AND NOT BUILD_TESTING)
set(CPACK_PACKAGE_EXECUTABLES "cryfs" "CryFS") set(CPACK_PACKAGE_EXECUTABLES "cryfs" "CryFS")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils") set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
# Needs gnupg2 for postinst script # Needs gnupg2, lsb-release for postinst script
set(CPACK_DEBIAN_PACKAGE_DEPENDS "fuse, gnupg2") set(CPACK_DEBIAN_PACKAGE_DEPENDS "fuse, gnupg2, lsb-release")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.cryfs.org") set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.cryfs.org")
set(CPACK_RPM_PACKAGE_LICENSE "LGPLv3") set(CPACK_RPM_PACKAGE_LICENSE "LGPLv3")

15
doc/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
project (doc)
INCLUDE(GNUInstallDirs)
find_program(GZIP gzip)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz
COMMAND ${GZIP} -c ${CMAKE_CURRENT_SOURCE_DIR}/man/cryfs.1 > ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz
)
add_custom_target(man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
CONFIGURATIONS Release
)

216
doc/man/cryfs.1 Normal file
View File

@ -0,0 +1,216 @@
.\" cryfs(1) man page
.
.TH cryfs 1
.
.
.
.SH NAME
cryfs \- cryptographic filesystem for the cloud
.
.
.
.SH SYNOPSIS
.\" mount/create syntax
.B cryfs
[\fB\-c\fR \fIfile\fR]
[\fB\-f\fR]
[\fIoptions\fR]
.I basedir mountpoint
[\fB\-\-\fR \fIfuse-options\fR]
.br
.\" show-ciphers syntax
.B cryfs \-\-help\fR|\fB\-\-show-ciphers
.
.
.
.SH DESCRIPTION
.
.B CryFS
encrypts your files, so you can safely store them anywhere.
.PP
.
The goal of CryFS is not only to keep file contents, but also
file sizes, metadata and directory structure confidential.
CryFS uses
.B encrypted same-size blocks
to store both the files themselves and the block's relations to another.
These blocks are stored as individual files in the base directory,
which can then be synchronized with cloud services such as Dropbox.
.PP
.
The blocks are encrypted using a random key, which is stored in a
.B configuration file
encrypted by the user's passphrase.
By default, it will be stored together with the data in the base directory,
but you can choose a different location if you do not want it in your cloud
or when using a weak passphrase.
.
.
.
.SH USING CRYFS
.
.SS Selecting base and mount directories
.
While you can access your files through your
.B mount directory,
CryFS actually places them in your
.B base directory
after encrypting.
CryFS will encrypt and decrypt your files 'on the fly' as they are accessed,
so files will never be stored on the disk in unencrypted form.
.PP
.
You can choose any empty directory as your base, but your mount directory
should be outside of any cloud storage, as your cloud may try to sync your
(temporarily mounted) unencrypted files as well.
.
.SS Setup and usage of your encrypted directory
.
.TP
Creating and mounting your encrypted storage use the same command-line syntax:
.B cryfs
.I basedir mountpoint
.PP
.
If CryFS detects an encrypted storage in the given base directory, you will
be asked for the passphrase to unlock and mount it. Otherwise, CryFS will
help you with creating one, just follow the on-screen instructions.
.PP
.
.TP
After you are done working with your encrypted files, unmount your storage \
with the command
.B fusermount -u
.I mountpoint
.
.
.SS Changing your passphrase
.
As the encryption key to your CryFS storage is stored in your configuration
file, it would be possible to re-encrypt it using a different passphrase
(although this feature has not been implemented yet).
.PP
.
However, this does not change the actual encryption key of your storage, so
someone with access to the old passphrase and configuration file (for example
through the file history of your cloud or your file system) could still access
your files, even those created after the password change.
.PP
.
For this reason, the recommended way to change your passphrase is to create a
new CryFS storage with the new passphrase and move your files from the old to
the new one.
.
.
.
.SH OPTIONS
.
.SS Getting help
.
.TP
\fB\-h\fR, \fB\-\-help\fR
.
Show a help message containing short descriptions for all options.
.
.
.TP
\fB\-\-show\-ciphers\fR
.
Show a list of all supported encryption ciphers.
.
.
.SS Encryption parameters
.
.TP
\fB\-\-blocksize\fR \fIarg\fR
.
Set the block size to \fIarg\fR bytes. Defaults to
.BR 32768 .
.br
\" Intentional space
.br
A higher block size may help reducing the file count in your base directory
(especially when storing large files), but will also waste more space when
storing smaller files.
.
.
.TP
\fB\-\-cipher\fR \fIarg\fR
.
Use \fIarg\fR as the cipher for the encryption. Defaults to
.BR aes-256-gcm .
.
.
.TP
\fB\-c\fR \fIfile\fR, \fB\-\-config\fR \fIfile\fR
.
Use \fIfile\fR as configuration file for this CryFS storage instead of
\fIbasedir\fR/cryfs.config
.
.
.SS General options
.
.TP
\fB\-f\fR, \fB\-\-foreground\fI
.
Run CryFS in the foreground. Stop using CTRL-C.
.
.
.TP
\fB\-\-logfile\fR \fIfile\fR
.
Write status information to \fIfile\fR. If no logfile is given, CryFS will
write them to syslog in background mode, or to stdout in foreground mode.
.
.
.TP
\fB\-\-unmount\-idle\fR \fIarg\fR
.
Unmount automatically after \fIarg\fR minutes of inactivity.
.
.
.
.SH ENVIRONMENT
.
.TP
\fBCRYFS_FRONTEND\fR=noninteractive
.
With this option set, CryFS will only ask for the encryption passphrase once.
Instead of asking the user for parameters not specified on the command line,
it will just use the default values. CryFS will also not ask you to confirm
your passphrase when creating a new CryFS storage.
.br
\" Intentional space
.br
Set this environment variable when automating CryFS using external tools or
shell scripts.
.
.
.TP
\fBCRYFS_NO_UPDATE_CHECK\fR=true
.
By default, CryFS connects to the internet to check for known security
vulnerabilities and new versions. This option disables this.
.
.
.
.SH SEE ALSO
.
.BR mount.fuse (1),
.BR fusermount (1)
.PP
.
For more information about the design of CryFS, visit
.B https://www.cryfs.org
.PP
.
Visit the development repository at
.B https://github.com/cryfs/cryfs
for the source code and the full list of contributors to CryFS.
.
.
.
.SH AUTHORS
.
CryFS was created by Sebastian Messmer and contributors.
This man page was written by Maximilian Wende.

View File

@ -1,4 +1,5 @@
project (cryfs-cli) project (cryfs-cli)
INCLUDE(GNUInstallDirs)
set(SOURCES set(SOURCES
Cli.cpp Cli.cpp
@ -26,6 +27,6 @@ target_enable_style_warnings(${PROJECT_NAME}_bin)
target_activate_cpp14(${PROJECT_NAME}_bin) target_activate_cpp14(${PROJECT_NAME}_bin)
install(TARGETS ${PROJECT_NAME}_bin install(TARGETS ${PROJECT_NAME}_bin
DESTINATION bin DESTINATION ${CMAKE_INSTALL_BINDIR}
CONFIGURATIONS Release CONFIGURATIONS Release
) )

2
vendor/README vendored
View File

@ -1,4 +1,4 @@
This directory contains external projects, taken from the following locations: This directory contains external projects, taken from the following locations:
scrypt: http://www.tarsnap.com/scrypt.html scrypt: http://www.tarsnap.com/scrypt.html
googletest: https://github.com/google/googletest/tree/release-1.8.0 googletest: https://github.com/google/googletest/tree/release-1.8.0
spdlog: https://github.com/gabime/spdlog/tree/v0.11.0/include/spdlog spdlog: https://github.com/gabime/spdlog/tree/v0.12.0/include/spdlog

View File

@ -30,11 +30,11 @@
#endif #endif
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated)) #define SPDLOG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated) #define SPDLOG_DEPRECATED __declspec(deprecated)
#else #else
#define DEPRECATED #define SPDLOG_DEPRECATED
#endif #endif
@ -57,7 +57,7 @@ using formatter_ptr = std::shared_ptr<spdlog::formatter>;
#if defined(SPDLOG_NO_ATOMIC_LEVELS) #if defined(SPDLOG_NO_ATOMIC_LEVELS)
using level_t = details::null_atomic_int; using level_t = details::null_atomic_int;
#else #else
using level_t = std::atomic_int; using level_t = std::atomic<int>;
#endif #endif
using log_err_handler = std::function<void(const std::string &err_msg)>; using log_err_handler = std::function<void(const std::string &err_msg)>;

View File

@ -67,7 +67,7 @@ async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
{} {}
async_msg(async_msg_type m_type) :msg_type(m_type) async_msg(async_msg_type m_type) :msg_type(m_type)
{}; {}
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
{ {
@ -82,7 +82,7 @@ async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
// never copy or assign. should only be moved.. // never copy or assign. should only be moved..
async_msg(const async_msg&) = delete; async_msg(const async_msg&) = delete;
async_msg& operator=(async_msg& other) = delete; async_msg& operator=(const async_msg& other) = delete;
// construct from log_msg // construct from log_msg
async_msg(const details::log_msg& m) : async_msg(const details::log_msg& m) :
@ -229,8 +229,6 @@ inline spdlog::details::async_log_helper::~async_log_helper()
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
{ {
push_msg(async_msg(msg)); push_msg(async_msg(msg));
} }
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
@ -246,7 +244,6 @@ inline void spdlog::details::async_log_helper::push_msg(details::async_log_helpe
} }
while (!_q.enqueue(std::move(new_msg))); while (!_q.enqueue(std::move(new_msg)));
} }
} }
// optionally wait for the queue be empty and request flush from the sinks // optionally wait for the queue be empty and request flush from the sinks
@ -281,10 +278,8 @@ inline void spdlog::details::async_log_helper::worker_loop()
// return true if this thread should still be active (while no terminate msg was received) // return true if this thread should still be active (while no terminate msg was received)
inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush) inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush)
{ {
async_msg incoming_async_msg; async_msg incoming_async_msg;
if (_q.dequeue(incoming_async_msg)) if (_q.dequeue(incoming_async_msg))
{ {
last_pop = details::os::now(); last_pop = details::os::now();
@ -359,8 +354,7 @@ inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_
// yield upto 150 micros // yield upto 150 micros
if (time_since_op <= microseconds(100)) if (time_since_op <= microseconds(100))
return yield(); return std::this_thread::yield();
// sleep for 20 ms upto 200 ms // sleep for 20 ms upto 200 ms
if (time_since_op <= milliseconds(200)) if (time_since_op <= milliseconds(200))
@ -378,13 +372,7 @@ inline void spdlog::details::async_log_helper::wait_empty_q()
{ {
sleep_or_yield(details::os::now(), last_op); sleep_or_yield(details::os::now(), last_op);
} }
} }

View File

@ -31,13 +31,13 @@ inline spdlog::async_logger::async_logger(const std::string& logger_name,
} }
inline spdlog::async_logger::async_logger(const std::string& logger_name, inline spdlog::async_logger::async_logger(const std::string& logger_name,
sinks_init_list sinks, sinks_init_list sinks_list,
size_t queue_size, size_t queue_size,
const async_overflow_policy overflow_policy, const async_overflow_policy overflow_policy,
const std::function<void()>& worker_warmup_cb, const std::function<void()>& worker_warmup_cb,
const std::chrono::milliseconds& flush_interval_ms, const std::chrono::milliseconds& flush_interval_ms,
const std::function<void()>& worker_teardown_cb) : const std::function<void()>& worker_teardown_cb) :
async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {} async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {}
inline spdlog::async_logger::async_logger(const std::string& logger_name, inline spdlog::async_logger::async_logger(const std::string& logger_name,
sink_ptr single_sink, sink_ptr single_sink,

View File

@ -291,3 +291,8 @@ inline bool spdlog::logger::_should_flush_on(const details::log_msg &msg)
const auto flush_level = _flush_level.load(std::memory_order_relaxed); const auto flush_level = _flush_level.load(std::memory_order_relaxed);
return (msg.level >= flush_level) && (msg.level != level::off); return (msg.level >= flush_level) && (msg.level != level::off);
} }
inline const std::vector<spdlog::sink_ptr>& spdlog::logger::sinks() const
{
return _sinks;
}

View File

@ -10,10 +10,12 @@
#include <ctime> #include <ctime>
#include <functional> #include <functional>
#include <string> #include <string>
#include <chrono>
#include <thread>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#ifdef _WIN32 #ifdef _WIN32
@ -25,27 +27,32 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
#include <process.h> // _get_pid support
#include <io.h> // _get_osfhandle support
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <share.h> #include <share.h>
#endif #endif
#include <sys/types.h> #else // unix
#elif __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#include <unistd.h> #include <unistd.h>
#include <chrono> #include <fcntl.h>
#ifdef __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#elif __FreeBSD__ #elif __FreeBSD__
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id #include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
#else
#include <thread>
#endif #endif
#endif //unix
#ifndef __has_feature // Clang - feature checking macros.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
namespace spdlog namespace spdlog
{ {
namespace details namespace details
@ -135,6 +142,18 @@ inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL; SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL;
SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1; SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1;
inline void prevent_child_fd(FILE *f)
{
#ifdef _WIN32
auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
throw spdlog_ex("SetHandleInformation failed", errno);
#else
auto fd = fileno(f);
if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
#endif
}
//fopen_s on non windows for writing //fopen_s on non windows for writing
@ -146,13 +165,18 @@ inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode
#else #else
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
#endif #endif
return *fp == nullptr; #else //unix
#else
*fp = fopen((filename.c_str()), mode.c_str()); *fp = fopen((filename.c_str()), mode.c_str());
return *fp == nullptr;
#endif #endif
#ifdef SPDLOG_PREVENT_CHILD_FD
if(*fp != nullptr)
prevent_child_fd(*fp);
#endif
return *fp == nullptr;
} }
inline int remove(const filename_t &filename) inline int remove(const filename_t &filename)
{ {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
@ -204,9 +228,9 @@ inline size_t filesize(FILE *f)
return st.st_size; return st.st_size;
#else //windows 32 bits #else //windows 32 bits
struct _stat st; long ret = _filelength(fd);
if (_fstat(fd, &st) == 0) if (ret >= 0)
return st.st_size; return static_cast<size_t>(ret);
#endif #endif
#else // unix #else // unix
@ -215,11 +239,11 @@ inline size_t filesize(FILE *f)
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) #if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__))
struct stat64 st; struct stat64 st;
if (fstat64(fd, &st) == 0) if (fstat64(fd, &st) == 0)
return st.st_size; return static_cast<size_t>(st.st_size);
#else // unix 32 bits or osx #else // unix 32 bits or osx
struct stat st; struct stat st;
if (fstat(fd, &st) == 0) if (fstat(fd, &st) == 0)
return st.st_size; return static_cast<size_t>(st.st_size);
#endif #endif
#endif #endif
throw spdlog_ex("Failed getting file size from fd", errno); throw spdlog_ex("Failed getting file size from fd", errno);
@ -292,7 +316,7 @@ inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
//Return current thread id as size_t //Return current thread id as size_t
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013) //It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
inline size_t thread_id() inline size_t _thread_id()
{ {
#ifdef _WIN32 #ifdef _WIN32
return static_cast<size_t>(::GetCurrentThreadId()); return static_cast<size_t>(::GetCurrentThreadId());
@ -308,10 +332,21 @@ inline size_t thread_id()
#else //Default to standard C++11 (OSX and other Unix) #else //Default to standard C++11 (OSX and other Unix)
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id())); return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
#endif #endif
} }
//Return current thread id as size_t (from thread local storage)
inline size_t thread_id()
{
#if defined(_MSC_VER) && (_MSC_VER < 1900) || defined(__clang__) && !__has_feature(cxx_thread_local)
return _thread_id();
#else
static thread_local const size_t tid = _thread_id();
return tid;
#endif
}
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
@ -342,8 +377,8 @@ inline std::string errno_str(int err_num)
else else
return "Unkown error"; return "Unkown error";
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || \ #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \
((_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE) // posix version ((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version
if (strerror_r(err_num, buf, buf_size) == 0) if (strerror_r(err_num, buf, buf_size) == 0)
return std::string(buf); return std::string(buf);
@ -355,6 +390,17 @@ inline std::string errno_str(int err_num)
#endif #endif
} }
inline int pid()
{
#ifdef _WIN32
return ::_getpid();
#else
return static_cast<int>(::getpid());
#endif
}
} //os } //os
} //details } //details
} //spdlog } //spdlog

View File

@ -18,6 +18,7 @@
#include <thread> #include <thread>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <array>
namespace spdlog namespace spdlog
{ {
@ -78,42 +79,60 @@ static int to12h(const tm& t)
} }
//Abbreviated weekday name //Abbreviated weekday name
static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; using days_array = std::array<std::string, 7>;
static const days_array& days()
{
static const days_array arr{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
return arr;
}
class a_formatter:public flag_formatter class a_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << days[tm_time.tm_wday]; msg.formatted << days()[tm_time.tm_wday];
} }
}; };
//Full weekday name //Full weekday name
static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static const days_array& full_days()
{
static const days_array arr{ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
return arr;
}
class A_formatter:public flag_formatter class A_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << full_days[tm_time.tm_wday]; msg.formatted << full_days()[tm_time.tm_wday];
} }
}; };
//Abbreviated month //Abbreviated month
static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" }; using months_array = std::array<std::string, 12>;
static const months_array& months()
{
static const months_array arr{ "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
return arr;
}
class b_formatter:public flag_formatter class b_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << months[tm_time.tm_mon]; msg.formatted << months()[tm_time.tm_mon];
} }
}; };
//Full month name //Full month name
static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static const months_array& full_months()
{
static const months_array arr{ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
return arr;
}
class B_formatter:public flag_formatter class B_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << full_months[tm_time.tm_mon]; msg.formatted << full_months()[tm_time.tm_mon];
} }
}; };
@ -138,7 +157,7 @@ class c_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' '; msg.formatted << days()[tm_time.tm_wday] << ' ' << months()[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';
pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900; pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900;
} }
}; };
@ -365,6 +384,15 @@ class t_formatter:public flag_formatter
} }
}; };
// Current pid
class pid_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm&) override
{
msg.formatted << details::os::pid();
}
};
class v_formatter:public flag_formatter class v_formatter:public flag_formatter
{ {
@ -453,6 +481,8 @@ class full_formatter:public flag_formatter
} }
}; };
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -611,6 +641,10 @@ inline void spdlog::pattern_formatter::handle_flag(char flag)
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter()));
break; break;
case ('P'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::pid_formatter()));
break;
default: //Unkown flag appears as is default: //Unkown flag appears as is
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%'))); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%')));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag))); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag)));

View File

@ -12,9 +12,20 @@
#include <spdlog/details/registry.h> #include <spdlog/details/registry.h>
#include <spdlog/sinks/file_sinks.h> #include <spdlog/sinks/file_sinks.h>
#include <spdlog/sinks/stdout_sinks.h> #include <spdlog/sinks/stdout_sinks.h>
#ifdef SPDLOG_ENABLE_SYSLOG
#include <spdlog/sinks/syslog_sink.h> #include <spdlog/sinks/syslog_sink.h>
#endif
#ifdef _WIN32
#include <spdlog/sinks/wincolor_sink.h>
#else
#include <spdlog/sinks/ansicolor_sink.h> #include <spdlog/sinks/ansicolor_sink.h>
#endif
#ifdef __ANDROID__
#include <spdlog/sinks/android_sink.h> #include <spdlog/sinks/android_sink.h>
#endif
#include <chrono> #include <chrono>
#include <functional> #include <functional>
@ -69,34 +80,86 @@ inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute); return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute);
} }
// Create stdout/stderr loggers (with optinal color support)
inline std::shared_ptr<spdlog::logger> create_console_logger(const std::string& logger_name, spdlog::sink_ptr sink, bool color) //
// stdout/stderr loggers
//
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name)
{ {
if (color) //use color wrapper sink return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance());
sink = std::make_shared<spdlog::sinks::ansicolor_sink>(sink); }
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name)
{
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name)
{
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name)
{
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance());
}
//
// stdout/stderr color loggers
//
#ifdef _WIN32
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>();
return spdlog::details::registry::instance().create(logger_name, sink); return spdlog::details::registry::instance().create(logger_name, sink);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name, bool color) inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string& logger_name)
{ {
return create_console_logger(logger_name, sinks::stdout_sink_mt::instance(), color); auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_st>();
return spdlog::details::registry::instance().create(logger_name, sink);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name, bool color) inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string& logger_name)
{ {
return create_console_logger(logger_name, sinks::stdout_sink_st::instance(), color); auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_mt>();
return spdlog::details::registry::instance().create(logger_name, sink);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name, bool color)
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string& logger_name)
{ {
return create_console_logger(logger_name, sinks::stderr_sink_mt::instance(), color); auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_st>();
return spdlog::details::registry::instance().create(logger_name, sink);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name, bool color) #else //ansi terminal colors
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string& logger_name)
{ {
return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color); auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stdout_sink_mt::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
} }
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stdout_sink_st::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stderr_sink_mt::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stderr_sink_st::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
}
#endif
#ifdef SPDLOG_ENABLE_SYSLOG #ifdef SPDLOG_ENABLE_SYSLOG
// Create syslog logger // Create syslog logger
inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option) inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
@ -105,7 +168,7 @@ inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string&
} }
#endif #endif
#if defined(__ANDROID__) #ifdef __ANDROID__
inline std::shared_ptr<spdlog::logger> spdlog::android_logger(const std::string& logger_name, const std::string& tag) inline std::shared_ptr<spdlog::logger> spdlog::android_logger(const std::string& logger_name, const std::string& tag)
{ {
return create<spdlog::sinks::android_sink>(logger_name, tag); return create<spdlog::sinks::android_sink>(logger_name, tag);

View File

@ -25,9 +25,7 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
// Commented out by spdlog to use header only #include "format.h"
// #include "fmt/format.h"
// #include "fmt/printf.h"
#include <string.h> #include <string.h>
@ -73,25 +71,31 @@ using fmt::internal::Arg;
// Dummy implementations of strerror_r and strerror_s called if corresponding // Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available. // system functions are not available.
static inline fmt::internal::Null<> strerror_r(int, char *, ...) { static inline fmt::internal::Null<> strerror_r(int, char *, ...)
{
return fmt::internal::Null<>(); return fmt::internal::Null<>();
} }
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...)
{
return fmt::internal::Null<>(); return fmt::internal::Null<>();
} }
namespace fmt { namespace fmt {
FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT
FMT_FUNC FormatError::~FormatError() throw() {} {}
FMT_FUNC SystemError::~SystemError() throw() {} FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT
{}
FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT
{}
namespace { namespace {
#ifndef _MSC_VER #ifndef _MSC_VER
# define FMT_SNPRINTF snprintf # define FMT_SNPRINTF snprintf
#else // _MSC_VER #else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...)
{
va_list args; va_list args;
va_start(args, format); va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
@ -121,26 +125,31 @@ typedef void (*FormatFunc)(Writer &, int, StringRef);
// other - failure // other - failure
// Buffer should be at least of size 1. // Buffer should be at least of size 1.
int safe_strerror( int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT
{
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
class StrError { class StrError
{
private: private:
int error_code_; int error_code_;
char *&buffer_; char *&buffer_;
std::size_t buffer_size_; std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings. // A noop assignment operator to avoid bogus warnings.
void operator=(const StrError &) {} void operator=(const StrError &)
{}
// Handle the result of XSI-compliant version of strerror_r. // Handle the result of XSI-compliant version of strerror_r.
int handle(int result) { int handle(int result)
{
// glibc versions before 2.13 return result in errno. // glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result; return result == -1 ? errno : result;
} }
// Handle the result of GNU-specific version of strerror_r. // Handle the result of GNU-specific version of strerror_r.
int handle(char *message) { int handle(char *message)
{
// If the buffer is full then the message is probably truncated. // If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE; return ERANGE;
@ -149,19 +158,22 @@ int safe_strerror(
} }
// Handle the case when strerror_r is not available. // Handle the case when strerror_r is not available.
int handle(internal::Null<>) { int handle(internal::Null<>)
{
return fallback(strerror_s(buffer_, buffer_size_, error_code_)); return fallback(strerror_s(buffer_, buffer_size_, error_code_));
} }
// Fallback to strerror_s when strerror_r is not available. // Fallback to strerror_s when strerror_r is not available.
int fallback(int result) { int fallback(int result)
{
// If the buffer is full then the message is probably truncated. // If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result; ERANGE : result;
} }
// Fallback to strerror if strerror_r and strerror_s are not available. // Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) { int fallback(internal::Null<>)
{
errno = 0; errno = 0;
buffer_ = strerror(error_code_); buffer_ = strerror(error_code_);
return errno; return errno;
@ -169,10 +181,13 @@ int safe_strerror(
public: public:
StrError(int err_code, char *&buf, std::size_t buf_size) StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} : error_code_(err_code), buffer_(buf), buffer_size_(buf_size)
{}
int run() { int run()
strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. {
// Suppress a warning about unused strerror_r.
strerror_r(0, FMT_NULL, "");
return handle(strerror_r(error_code_, buffer_, buffer_size_)); return handle(strerror_r(error_code_, buffer_, buffer_size_));
} }
}; };
@ -180,7 +195,8 @@ int safe_strerror(
} }
void format_error_code(Writer &out, int error_code, void format_error_code(Writer &out, int error_code,
StringRef message) FMT_NOEXCEPT { StringRef message) FMT_NOEXCEPT
{
// Report error code making sure that the output fits into // Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc. // bad_alloc.
@ -203,7 +219,8 @@ void format_error_code(Writer &out, int error_code,
} }
void report_error(FormatFunc func, int error_code, void report_error(FormatFunc func, int error_code,
StringRef message) FMT_NOEXCEPT { StringRef message) FMT_NOEXCEPT
{
MemoryWriter full_message; MemoryWriter full_message;
func(full_message, error_code, message); func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory // Use Writer::data instead of Writer::c_str to avoid potential memory
@ -218,13 +235,15 @@ namespace internal {
// This method is used to preserve binary compatibility with fmt 3.0. // This method is used to preserve binary compatibility with fmt 3.0.
// It can be removed in 4.0. // It can be removed in 4.0.
FMT_FUNC void format_system_error( FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
{
fmt::format_system_error(out, error_code, message); fmt::format_system_error(out, error_code, message);
} }
} // namespace internal } // namespace internal
FMT_FUNC void SystemError::init( FMT_FUNC void SystemError::init(
int err_code, CStringRef format_str, ArgList args) { int err_code, CStringRef format_str, ArgList args)
{
error_code_ = err_code; error_code_ = err_code;
MemoryWriter w; MemoryWriter w;
format_system_error(w, err_code, format(format_str, args)); format_system_error(w, err_code, format(format_str, args));
@ -235,7 +254,8 @@ FMT_FUNC void SystemError::init(
template <typename T> template <typename T>
int internal::CharTraits<char>::format_float( int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format, char *buffer, std::size_t size, const char *format,
unsigned width, int precision, T value) { unsigned width, int precision, T value)
{
if (width == 0) { if (width == 0) {
return precision < 0 ? return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) : FMT_SNPRINTF(buffer, size, format, value) :
@ -249,7 +269,8 @@ int internal::CharTraits<char>::format_float(
template <typename T> template <typename T>
int internal::CharTraits<wchar_t>::format_float( int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, T value) { unsigned width, int precision, T value)
{
if (width == 0) { if (width == 0) {
return precision < 0 ? return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) : FMT_SWPRINTF(buffer, size, format, value) :
@ -294,7 +315,8 @@ const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
ULongLong(1000000000) * ULongLong(1000000000) * 10 ULongLong(1000000000) * ULongLong(1000000000) * 10
}; };
FMT_FUNC void internal::report_unknown_type(char code, const char *type) { FMT_FUNC void internal::report_unknown_type(char code, const char *type)
{
(void)type; (void)type;
if (std::isprint(static_cast<unsigned char>(code))) { if (std::isprint(static_cast<unsigned char>(code))) {
FMT_THROW(FormatError( FMT_THROW(FormatError(
@ -307,13 +329,14 @@ FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s)
{
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX) if (s.size() > INT_MAX)
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size()); int s_size = static_cast<int>(s.size());
int length = MultiByteToWideChar( int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
if (length == 0) if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1); buffer_.resize(length + 1);
@ -324,23 +347,26 @@ FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
buffer_[length] = 0; buffer_[length] = 0;
} }
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s)
{
if (int error_code = convert(s)) { if (int error_code = convert(s)) {
FMT_THROW(WindowsError(error_code, FMT_THROW(WindowsError(error_code,
"cannot convert string from UTF-16 to UTF-8")); "cannot convert string from UTF-16 to UTF-8"));
} }
} }
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s)
{
if (s.size() > INT_MAX) if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size()); int s_size = static_cast<int>(s.size());
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0) if (length == 0)
return GetLastError(); return GetLastError();
buffer_.resize(length + 1); buffer_.resize(length + 1);
length = WideCharToMultiByte( length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0) if (length == 0)
return GetLastError(); return GetLastError();
buffer_[length] = 0; buffer_[length] = 0;
@ -348,7 +374,8 @@ FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
} }
FMT_FUNC void WindowsError::init( FMT_FUNC void WindowsError::init(
int err_code, CStringRef format_str, ArgList args) { int err_code, CStringRef format_str, ArgList args)
{
error_code_ = err_code; error_code_ = err_code;
MemoryWriter w; MemoryWriter w;
internal::format_windows_error(w, err_code, format(format_str, args)); internal::format_windows_error(w, err_code, format(format_str, args));
@ -357,15 +384,17 @@ FMT_FUNC void WindowsError::init(
} }
FMT_FUNC void internal::format_windows_error( FMT_FUNC void internal::format_windows_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
{
FMT_TRY{ FMT_TRY{
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE); buffer.resize(INLINE_BUFFER_SIZE);
for (;;) { for (;;) {
wchar_t *system_message = &buffer[0]; wchar_t *system_message = &buffer[0];
int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, int result = FormatMessageW(
0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
system_message, static_cast<uint32_t>(buffer.size()), 0); FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
if (result != 0) { if (result != 0) {
UTF16ToUTF8 utf8_message; UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) { if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
@ -378,14 +407,16 @@ FMT_FUNC void internal::format_windows_error(
break; // Can't get error message, report error code instead. break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2); buffer.resize(buffer.size() * 2);
} }
} FMT_CATCH(...) {} } FMT_CATCH(...)
{}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
} }
#endif // FMT_USE_WINDOWS_H #endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error( FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
{
FMT_TRY{ FMT_TRY{
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer; internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
buffer.resize(internal::INLINE_BUFFER_SIZE); buffer.resize(internal::INLINE_BUFFER_SIZE);
@ -400,16 +431,18 @@ FMT_FUNC void format_system_error(
break; // Can't get error message, report error code instead. break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2); buffer.resize(buffer.size() * 2);
} }
} FMT_CATCH(...) {} } FMT_CATCH(...)
{}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
} }
template <typename Char> template <typename Char>
void internal::ArgMap<Char>::init(const ArgList &args) { void internal::ArgMap<Char>::init(const ArgList &args)
{
if (!map_.empty()) if (!map_.empty())
return; return;
typedef internal::NamedArg<Char> NamedArg; typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = 0; const NamedArg *named_arg = FMT_NULL;
bool use_values = bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) { if (use_values) {
@ -450,12 +483,14 @@ void internal::ArgMap<Char>::init(const ArgList &args) {
} }
template <typename Char> template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t) { void internal::FixedBuffer<Char>::grow(std::size_t)
{
FMT_THROW(std::runtime_error("buffer overflow")); FMT_THROW(std::runtime_error("buffer overflow"));
} }
FMT_FUNC Arg internal::FormatterBase::do_get_arg( FMT_FUNC Arg internal::FormatterBase::do_get_arg(
unsigned arg_index, const char *&error) { unsigned arg_index, const char *&error)
{
Arg arg = args_[arg_index]; Arg arg = args_[arg_index];
switch (arg.type) { switch (arg.type) {
case Arg::NONE: case Arg::NONE:
@ -471,30 +506,35 @@ FMT_FUNC Arg internal::FormatterBase::do_get_arg(
} }
FMT_FUNC void report_system_error( FMT_FUNC void report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT { int error_code, fmt::StringRef message) FMT_NOEXCEPT
{
// 'fmt::' is for bcc32. // 'fmt::' is for bcc32.
report_error(format_system_error, error_code, message); report_error(format_system_error, error_code, message);
} }
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error( FMT_FUNC void report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT { int error_code, fmt::StringRef message) FMT_NOEXCEPT
{
// 'fmt::' is for bcc32. // 'fmt::' is for bcc32.
report_error(internal::format_windows_error, error_code, message); report_error(internal::format_windows_error, error_code, message);
} }
#endif #endif
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args)
{
MemoryWriter w; MemoryWriter w;
w.write(format_str, args); w.write(format_str, args);
std::fwrite(w.data(), 1, w.size(), f); std::fwrite(w.data(), 1, w.size(), f);
} }
FMT_FUNC void print(CStringRef format_str, ArgList args) { FMT_FUNC void print(CStringRef format_str, ArgList args)
{
print(stdout, format_str, args); print(stdout, format_str, args);
} }
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args)
{
char escape[] = "\x1b[30m"; char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c); escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout); std::fputs(escape, stdout);
@ -502,16 +542,6 @@ FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
std::fputs(RESET_COLOR, stdout); std::fputs(RESET_COLOR, stdout);
} }
template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args);
FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
std::size_t size = w.size();
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
}
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
template struct internal::BasicData<void>; template struct internal::BasicData<void>;
@ -522,8 +552,6 @@ template void internal::FixedBuffer<char>::grow(std::size_t);
template void internal::ArgMap<char>::init(const ArgList &args); template void internal::ArgMap<char>::init(const ArgList &args);
template void PrintfFormatter<char>::format(CStringRef format);
template int internal::CharTraits<char>::format_float( template int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format, char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value); unsigned width, int precision, double value);
@ -538,8 +566,6 @@ template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::ArgMap<wchar_t>::init(const ArgList &args); template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template void PrintfFormatter<wchar_t>::format(WCStringRef format);
template int internal::CharTraits<wchar_t>::format_float( template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value); unsigned width, int precision, double value);

View File

@ -40,6 +40,9 @@
#include <vector> #include <vector>
#include <utility> #include <utility>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 30002
#ifdef _SECURE_SCL #ifdef _SECURE_SCL
# define FMT_SECURE_SCL _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL
#else #else
@ -180,20 +183,50 @@ typedef __int64 intmax_t;
# define FMT_USE_NOEXCEPT 0 # define FMT_USE_NOEXCEPT 0
#endif #endif
#ifndef FMT_NOEXCEPT
# if FMT_EXCEPTIONS
#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
FMT_MSC_VER >= 1900 FMT_MSC_VER >= 1900
# define FMT_NOEXCEPT noexcept # define FMT_DETECTED_NOEXCEPT noexcept
#else #else
# define FMT_NOEXCEPT throw() # define FMT_DETECTED_NOEXCEPT throw()
#endif #endif
#ifndef FMT_NOEXCEPT
# if FMT_EXCEPTIONS
# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
# else # else
# define FMT_NOEXCEPT # define FMT_NOEXCEPT
# endif # endif
#endif #endif
// This is needed because GCC still uses throw() in its headers when exceptions
// are disabled.
#if FMT_GCC_VERSION
# define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT
#else
# define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT
#endif
#ifndef FMT_OVERRIDE
# if (defined(FMT_USE_OVERRIDE) && FMT_USE_OVERRIDE) || FMT_HAS_FEATURE(cxx_override) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
FMT_MSC_VER >= 1900
# define FMT_OVERRIDE override
# else
# define FMT_OVERRIDE
# endif
#endif
#ifndef FMT_NULL
# if FMT_HAS_FEATURE(cxx_nullptr) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
FMT_MSC_VER >= 1600
# define FMT_NULL nullptr
# else
# define FMT_NULL NULL
# endif
#endif
// A macro to disallow the copy constructor and operator= functions // A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class // This should be used in the private: declarations for a class
#ifndef FMT_USE_DELETED_FUNCTIONS #ifndef FMT_USE_DELETED_FUNCTIONS
@ -225,6 +258,21 @@ typedef __int64 intmax_t;
(!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500)
#endif #endif
#ifndef FMT_USE_EXTERN_TEMPLATES
// Clang doesn't have a feature check for extern templates so we check
// for variadic templates which were introduced in the same version.
// For GCC according to cppreference.com they were introduced in 3.3.
# define FMT_USE_EXTERN_TEMPLATES \
((__clang__ && FMT_USE_VARIADIC_TEMPLATES) || \
(FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11))
#endif
#ifdef FMT_HEADER_ONLY
// If header only do not use extern templates.
# undef FMT_USE_EXTERN_TEMPLATES
# define FMT_USE_EXTERN_TEMPLATES 0
#endif
#ifndef FMT_ASSERT #ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message) # define FMT_ASSERT(condition, message) assert((condition) && message)
#endif #endif
@ -387,8 +435,11 @@ public:
static bool isnegative(double x) static bool isnegative(double x)
{ {
using namespace fmt::internal; using namespace fmt::internal;
if (const_check(sizeof(signbit(x)) == sizeof(int))) if (const_check(sizeof(signbit(x)) == sizeof(bool) ||
sizeof(signbit(x)) == sizeof(int)))
{
return signbit(x) != 0; return signbit(x) != 0;
}
if (x < 0) return true; if (x < 0) return true;
if (!isnotanumber(x)) return false; if (!isnotanumber(x)) return false;
int dec = 0, sign = 0; int dec = 0, sign = 0;
@ -460,7 +511,8 @@ private:
public: public:
/** Constructs a string reference object from a C string and a size. */ /** Constructs a string reference object from a C string and a size. */
BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} BasicStringRef(const Char *s, std::size_t size): data_(s), size_(size)
{}
/** /**
\rst \rst
@ -469,7 +521,8 @@ public:
\endrst \endrst
*/ */
BasicStringRef(const Char *s) BasicStringRef(const Char *s)
: data_(s), size_(std::char_traits<Char>::length(s)) {} : data_(s), size_(std::char_traits<Char>::length(s))
{}
/** /**
\rst \rst
@ -477,7 +530,8 @@ public:
\endrst \endrst
*/ */
BasicStringRef(const std::basic_string<Char> &s) BasicStringRef(const std::basic_string<Char> &s)
: data_(s.c_str()), size_(s.size()) {} : data_(s.c_str()), size_(s.size())
{}
/** /**
\rst \rst
@ -573,14 +627,16 @@ private:
public: public:
/** Constructs a string reference object from a C string. */ /** Constructs a string reference object from a C string. */
BasicCStringRef(const Char *s) : data_(s) {} BasicCStringRef(const Char *s): data_(s)
{}
/** /**
\rst \rst
Constructs a string reference from an ``std::string`` object. Constructs a string reference from an ``std::string`` object.
\endrst \endrst
*/ */
BasicCStringRef(const std::basic_string<Char> &s) : data_(s.c_str()) {} BasicCStringRef(const std::basic_string<Char> &s): data_(s.c_str())
{}
/** Returns the pointer to a C string. */ /** Returns the pointer to a C string. */
const Char *c_str() const const Char *c_str() const
@ -597,8 +653,11 @@ class FormatError : public std::runtime_error
{ {
public: public:
explicit FormatError(CStringRef message) explicit FormatError(CStringRef message)
: std::runtime_error(message.c_str()) {} : std::runtime_error(message.c_str())
~FormatError() throw(); {}
FormatError(const FormatError &ferr): std::runtime_error(ferr)
{}
~FormatError() FMT_DTOR_NOEXCEPT;
}; };
namespace internal namespace internal
@ -632,7 +691,10 @@ inline typename MakeUnsigned<Int>::Type to_unsigned(Int value)
// The number of characters to store in the MemoryBuffer object itself // The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation. // to avoid dynamic memory allocation.
enum { INLINE_BUFFER_SIZE = 500 }; enum
{
INLINE_BUFFER_SIZE = 500
};
#if FMT_SECURE_SCL #if FMT_SECURE_SCL
// Use checked iterator to avoid warnings on MSVC. // Use checked iterator to avoid warnings on MSVC.
@ -666,8 +728,9 @@ protected:
std::size_t size_; std::size_t size_;
std::size_t capacity_; std::size_t capacity_;
Buffer(T *ptr = 0, std::size_t capacity = 0) Buffer(T *ptr = FMT_NULL, std::size_t capacity = 0)
: ptr_(ptr), size_(0), capacity_(capacity) {} : ptr_(ptr), size_(0), capacity_(capacity)
{}
/** /**
\rst \rst
@ -678,7 +741,8 @@ protected:
virtual void grow(std::size_t size) = 0; virtual void grow(std::size_t size) = 0;
public: public:
virtual ~Buffer() {} virtual ~Buffer()
{}
/** Returns the size of this buffer. */ /** Returns the size of this buffer. */
std::size_t size() const std::size_t size() const
@ -713,7 +777,10 @@ public:
grow(capacity); grow(capacity);
} }
void clear() FMT_NOEXCEPT { size_ = 0; } void clear() FMT_NOEXCEPT
{
size_ = 0;
}
void push_back(const T &value) void push_back(const T &value)
{ {
@ -766,11 +833,12 @@ private:
} }
protected: protected:
void grow(std::size_t size); void grow(std::size_t size) FMT_OVERRIDE;
public: public:
explicit MemoryBuffer(const Allocator &alloc = Allocator()) explicit MemoryBuffer(const Allocator &alloc = Allocator())
: Allocator(alloc), Buffer<T>(data_, SIZE) {} : Allocator(alloc), Buffer<T>(data_, SIZE)
{}
~MemoryBuffer() ~MemoryBuffer()
{ {
deallocate(); deallocate();
@ -828,7 +896,7 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size)
std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; std::size_t new_capacity = this->capacity_ + this->capacity_ / 2;
if (size > new_capacity) if (size > new_capacity)
new_capacity = size; new_capacity = size;
T *new_ptr = this->allocate(new_capacity); T *new_ptr = this->allocate(new_capacity, FMT_NULL);
// The following code doesn't throw, so the raw pointer above doesn't leak. // The following code doesn't throw, so the raw pointer above doesn't leak.
std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_,
make_ptr(new_ptr, new_capacity)); make_ptr(new_ptr, new_capacity));
@ -848,10 +916,11 @@ template <typename Char>
class FixedBuffer: public fmt::Buffer<Char> class FixedBuffer: public fmt::Buffer<Char>
{ {
public: public:
FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {} FixedBuffer(Char *array, std::size_t size): fmt::Buffer<Char>(array, size)
{}
protected: protected:
FMT_API void grow(std::size_t size); FMT_API void grow(std::size_t size) FMT_OVERRIDE;
}; };
template <typename Char> template <typename Char>
@ -891,6 +960,15 @@ public:
const char *format, unsigned width, int precision, T value); const char *format, unsigned width, int precision, T value);
}; };
#if FMT_USE_EXTERN_TEMPLATES
extern template int CharTraits<char>::format_float<double>
(char *buffer, std::size_t size,
const char* format, unsigned width, int precision, double value);
extern template int CharTraits<char>::format_float<long double>
(char *buffer, std::size_t size,
const char* format, unsigned width, int precision, long double value);
#endif
template <> template <>
class CharTraits<wchar_t>: public BasicCharTraits<wchar_t> class CharTraits<wchar_t>: public BasicCharTraits<wchar_t>
{ {
@ -909,6 +987,15 @@ public:
const wchar_t *format, unsigned width, int precision, T value); const wchar_t *format, unsigned width, int precision, T value);
}; };
#if FMT_USE_EXTERN_TEMPLATES
extern template int CharTraits<wchar_t>::format_float<double>
(wchar_t *buffer, std::size_t size,
const wchar_t* format, unsigned width, int precision, double value);
extern template int CharTraits<wchar_t>::format_float<long double>
(wchar_t *buffer, std::size_t size,
const wchar_t* format, unsigned width, int precision, long double value);
#endif
// Checks if a number is negative - used to avoid warnings. // Checks if a number is negative - used to avoid warnings.
template <bool IsSigned> template <bool IsSigned>
struct SignChecker struct SignChecker
@ -972,13 +1059,7 @@ struct FMT_API BasicData
static const char DIGITS[]; static const char DIGITS[];
}; };
#ifndef FMT_USE_EXTERN_TEMPLATES #if FMT_USE_EXTERN_TEMPLATES
// Clang doesn't have a feature check for extern templates so we check
// for variadic templates which were introduced in the same version.
# define FMT_USE_EXTERN_TEMPLATES (__clang__ && FMT_USE_VARIADIC_TEMPLATES)
#endif
#if FMT_USE_EXTERN_TEMPLATES && !defined(FMT_HEADER_ONLY)
extern template struct BasicData<void>; extern template struct BasicData<void>;
#endif #endif
@ -1027,7 +1108,8 @@ inline unsigned count_digits(uint32_t n)
struct NoThousandsSep struct NoThousandsSep
{ {
template <typename Char> template <typename Char>
void operator()(Char *) {} void operator()(Char *)
{}
}; };
// A functor that adds a thousands separator. // A functor that adds a thousands separator.
@ -1040,7 +1122,8 @@ private:
unsigned digit_index_; unsigned digit_index_;
public: public:
explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} explicit ThousandsSep(fmt::StringRef sep): sep_(sep), digit_index_(0)
{}
template <typename Char> template <typename Char>
void operator()(Char *&buffer) void operator()(Char *&buffer)
@ -1087,7 +1170,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits,
template <typename UInt, typename Char> template <typename UInt, typename Char>
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
{ {
return format_decimal(buffer, value, num_digits, NoThousandsSep()); format_decimal(buffer, value, num_digits, NoThousandsSep());
return;
} }
#ifndef _WIN32 #ifndef _WIN32
@ -1134,7 +1218,8 @@ private:
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_; MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_;
public: public:
UTF16ToUTF8() {} UTF16ToUTF8()
{}
FMT_API explicit UTF16ToUTF8(WStringRef s); FMT_API explicit UTF16ToUTF8(WStringRef s);
operator StringRef() const operator StringRef() const
{ {
@ -1218,9 +1303,12 @@ struct Arg : Value
template <typename Char> template <typename Char>
struct NamedArg; struct NamedArg;
template <typename Char, typename T>
struct NamedArgWithType;
template <typename T = void> template <typename T = void>
struct Null {}; struct Null
{};
// A helper class template to enable or disable overloads taking wide // A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue. // characters and strings in MakeValue.
@ -1251,13 +1339,19 @@ No &convert(...);
template<typename T, bool ENABLE_CONVERSION> template<typename T, bool ENABLE_CONVERSION>
struct ConvertToIntImpl struct ConvertToIntImpl
{ {
enum { value = ENABLE_CONVERSION }; enum
{
value = ENABLE_CONVERSION
};
}; };
template<typename T, bool ENABLE_CONVERSION> template<typename T, bool ENABLE_CONVERSION>
struct ConvertToIntImpl2 struct ConvertToIntImpl2
{ {
enum { value = false }; enum
{
value = false
};
}; };
template<typename T> template<typename T>
@ -1273,8 +1367,14 @@ struct ConvertToIntImpl2<T, true>
template<typename T> template<typename T>
struct ConvertToInt struct ConvertToInt
{ {
enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) }; enum
enum { value = ConvertToIntImpl2<T, enable_conversion>::value }; {
enable_conversion = sizeof(fmt::internal::convert(get<T>())) == sizeof(Yes)
};
enum
{
value = ConvertToIntImpl2<T, enable_conversion>::value
};
}; };
#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ #define FMT_DISABLE_CONVERSION_TO_INT(Type) \
@ -1287,7 +1387,8 @@ FMT_DISABLE_CONVERSION_TO_INT(double);
FMT_DISABLE_CONVERSION_TO_INT(long double); FMT_DISABLE_CONVERSION_TO_INT(long double);
template<bool B, class T = void> template<bool B, class T = void>
struct EnableIf {}; struct EnableIf
{};
template<class T> template<class T>
struct EnableIf<true, T> struct EnableIf<true, T>
@ -1311,24 +1412,34 @@ struct Conditional<false, T, F>
template <bool> template <bool>
struct Not struct Not
{ {
enum { value = 0 }; enum
{
value = 0
};
}; };
template <> template <>
struct Not<false> struct Not<false>
{ {
enum { value = 1 }; enum
{
value = 1
};
}; };
template <typename T> template <typename T>
struct False struct False
{ {
enum { value = 0 }; enum
{
value = 0
};
}; };
template <typename T, T> struct LConvCheck template <typename T, T> struct LConvCheck
{ {
LConvCheck(int) {} LConvCheck(int)
{}
}; };
// Returns the thousands separator for the current locale. // Returns the thousands separator for the current locale.
@ -1348,7 +1459,7 @@ inline fmt::StringRef thousands_sep(...)
#define FMT_CONCAT(a, b) a##b #define FMT_CONCAT(a, b) a##b
#if FMT_GCC_VERSION >= 407 #if FMT_GCC_VERSION >= 303
# define FMT_UNUSED __attribute__((unused)) # define FMT_UNUSED __attribute__((unused))
#else #else
# define FMT_UNUSED # define FMT_UNUSED
@ -1429,7 +1540,8 @@ private:
} }
public: public:
MakeValue() {} MakeValue()
{}
#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \
MakeValue(Type value) { field = rhs; } \ MakeValue(Type value) { field = rhs; } \
@ -1548,12 +1660,22 @@ public:
{ {
pointer = &value; pointer = &value;
} }
template <typename Char_, typename T>
MakeValue(const NamedArgWithType<Char_, T> &value)
{
pointer = &value;
}
template <typename Char_> template <typename Char_>
static uint64_t type(const NamedArg<Char_> &) static uint64_t type(const NamedArg<Char_> &)
{ {
return Arg::NAMED_ARG; return Arg::NAMED_ARG;
} }
template <typename Char_, typename T>
static uint64_t type(const NamedArgWithType<Char_, T> &)
{
return Arg::NAMED_ARG;
}
}; };
template <typename Formatter> template <typename Formatter>
@ -1580,14 +1702,26 @@ struct NamedArg : Arg
template <typename T> template <typename T>
NamedArg(BasicStringRef<Char> argname, const T &value) NamedArg(BasicStringRef<Char> argname, const T &value)
: Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {} : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname)
{}
};
template <typename Char, typename T>
struct NamedArgWithType: NamedArg<Char>
{
NamedArgWithType(BasicStringRef<Char> argname, const T &value)
: NamedArg<Char>(argname, value)
{}
}; };
class RuntimeError: public std::runtime_error class RuntimeError: public std::runtime_error
{ {
protected: protected:
RuntimeError() : std::runtime_error("") {} RuntimeError(): std::runtime_error("")
~RuntimeError() throw(); {}
RuntimeError(const RuntimeError &rerr): std::runtime_error(rerr)
{}
~RuntimeError() FMT_DTOR_NOEXCEPT;
}; };
template <typename Char> template <typename Char>
@ -1614,10 +1748,7 @@ private:
internal::Arg::Type type(unsigned index) const internal::Arg::Type type(unsigned index) const
{ {
unsigned shift = index * 4; return type(types_, index);
uint64_t mask = 0xf;
return static_cast<internal::Arg::Type>(
(types_ & (mask << shift)) >> shift);
} }
template <typename Char> template <typename Char>
@ -1625,14 +1756,25 @@ private:
public: public:
// Maximum number of arguments with packed types. // Maximum number of arguments with packed types.
enum { MAX_PACKED_ARGS = 16 }; enum
{
MAX_PACKED_ARGS = 16
};
ArgList() : types_(0) {} ArgList(): types_(0)
{}
ArgList(ULongLong types, const internal::Value *values) ArgList(ULongLong types, const internal::Value *values)
: types_(types), values_(values) {} : types_(types), values_(values)
{}
ArgList(ULongLong types, const internal::Arg *args) ArgList(ULongLong types, const internal::Arg *args)
: types_(types), args_(args) {} : types_(types), args_(args)
{}
uint64_t types() const
{
return types_;
}
/** Returns the argument at specified index. */ /** Returns the argument at specified index. */
internal::Arg operator[](unsigned index) const internal::Arg operator[](unsigned index) const
@ -1663,6 +1805,14 @@ public:
} }
return args_[index]; return args_[index];
} }
static internal::Arg::Type type(uint64_t types, unsigned index)
{
unsigned shift = index * 4;
uint64_t mask = 0xf;
return static_cast<internal::Arg::Type>(
(types & (mask << shift)) >> shift);
}
}; };
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call #define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
@ -1698,7 +1848,8 @@ private:
typedef internal::Arg Arg; typedef internal::Arg Arg;
public: public:
void report_unhandled_arg() {} void report_unhandled_arg()
{}
Result visit_unhandled_arg() Result visit_unhandled_arg()
{ {
@ -1858,7 +2009,8 @@ enum
}; };
// An empty format specifier. // An empty format specifier.
struct EmptySpec {}; struct EmptySpec
{};
// A type specifier. // A type specifier.
template <char TYPE> template <char TYPE>
@ -1898,7 +2050,8 @@ struct WidthSpec
// two specialization of WidthSpec and its subclasses. // two specialization of WidthSpec and its subclasses.
wchar_t fill_; wchar_t fill_;
WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} WidthSpec(unsigned width, wchar_t fill): width_(width), fill_(fill)
{}
unsigned width() const unsigned width() const
{ {
@ -1916,7 +2069,8 @@ struct AlignSpec : WidthSpec
Alignment align_; Alignment align_;
AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT)
: WidthSpec(width, fill), align_(align) {} : WidthSpec(width, fill), align_(align)
{}
Alignment align() const Alignment align() const
{ {
@ -1933,7 +2087,8 @@ struct AlignSpec : WidthSpec
template <char TYPE> template <char TYPE>
struct AlignTypeSpec: AlignSpec struct AlignTypeSpec: AlignSpec
{ {
AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} AlignTypeSpec(unsigned width, wchar_t fill): AlignSpec(width, fill)
{}
bool flag(unsigned) const bool flag(unsigned) const
{ {
@ -1954,7 +2109,8 @@ struct FormatSpec : AlignSpec
FormatSpec( FormatSpec(
unsigned width = 0, char type = 0, wchar_t fill = ' ') unsigned width = 0, char type = 0, wchar_t fill = ' ')
: AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type)
{}
bool flag(unsigned f) const bool flag(unsigned f) const
{ {
@ -1979,7 +2135,8 @@ private:
public: public:
IntFormatSpec(T val, const SpecT &spec = SpecT()) IntFormatSpec(T val, const SpecT &spec = SpecT())
: SpecT(spec), value_(val) {} : SpecT(spec), value_(val)
{}
T value() const T value() const
{ {
@ -2154,7 +2311,7 @@ public:
if (it->first == name) if (it->first == name)
return &it->second; return &it->second;
} }
return 0; return FMT_NULL;
} }
}; };
@ -2193,13 +2350,14 @@ protected:
void write(const char *value) void write(const char *value)
{ {
Arg::StringValue<char> str = {value, value != 0 ? std::strlen(value) : 0}; Arg::StringValue<char> str = { value, value ? std::strlen(value) : 0 };
writer_.write_str(str, spec_); writer_.write_str(str, spec_);
} }
public: public:
ArgFormatterBase(BasicWriter<Char> &w, FormatSpec &s) ArgFormatterBase(BasicWriter<Char> &w, FormatSpec &s)
: writer_(w), spec_(s) {} : writer_(w), spec_(s)
{}
template <typename T> template <typename T>
void visit_any_int(T value) void visit_any_int(T value)
@ -2216,7 +2374,10 @@ public:
void visit_bool(bool value) void visit_bool(bool value)
{ {
if (spec_.type_) if (spec_.type_)
return visit_any_int(value); {
visit_any_int(value);
return;
}
write(value); write(value);
} }
@ -2233,29 +2394,29 @@ public:
typedef typename BasicWriter<Char>::CharPtr CharPtr; typedef typename BasicWriter<Char>::CharPtr CharPtr;
Char fill = internal::CharTraits<Char>::cast(spec_.fill()); Char fill = internal::CharTraits<Char>::cast(spec_.fill());
CharPtr out = CharPtr(); CharPtr out = CharPtr();
const unsigned CHAR_WIDTH = 1; const unsigned CHAR_SIZE = 1;
if (spec_.width_ > CHAR_WIDTH) if (spec_.width_ > CHAR_SIZE)
{ {
out = writer_.grow_buffer(spec_.width_); out = writer_.grow_buffer(spec_.width_);
if (spec_.align_ == ALIGN_RIGHT) if (spec_.align_ == ALIGN_RIGHT)
{ {
std::uninitialized_fill_n(out, spec_.width_ - CHAR_WIDTH, fill); std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill);
out += spec_.width_ - CHAR_WIDTH; out += spec_.width_ - CHAR_SIZE;
} }
else if (spec_.align_ == ALIGN_CENTER) else if (spec_.align_ == ALIGN_CENTER)
{ {
out = writer_.fill_padding(out, spec_.width_, out = writer_.fill_padding(out, spec_.width_,
internal::const_check(CHAR_WIDTH), fill); internal::const_check(CHAR_SIZE), fill);
} }
else else
{ {
std::uninitialized_fill_n(out + CHAR_WIDTH, std::uninitialized_fill_n(out + CHAR_SIZE,
spec_.width_ - CHAR_WIDTH, fill); spec_.width_ - CHAR_SIZE, fill);
} }
} }
else else
{ {
out = writer_.grow_buffer(CHAR_WIDTH); out = writer_.grow_buffer(CHAR_SIZE);
} }
*out = internal::CharTraits<Char>::cast(value); *out = internal::CharTraits<Char>::cast(value);
} }
@ -2380,7 +2541,8 @@ public:
BasicArgFormatter(BasicFormatter<Char, Impl> &formatter, BasicArgFormatter(BasicFormatter<Char, Impl> &formatter,
FormatSpec &spec, const Char *fmt) FormatSpec &spec, const Char *fmt)
: internal::ArgFormatterBase<Impl, Char>(formatter.writer(), spec), : internal::ArgFormatterBase<Impl, Char>(formatter.writer(), spec),
formatter_(formatter), format_(fmt) {} formatter_(formatter), format_(fmt)
{}
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c) void visit_custom(internal::Arg::CustomValue c)
@ -2397,7 +2559,8 @@ public:
/** Constructs an argument formatter object. */ /** Constructs an argument formatter object. */
ArgFormatter(BasicFormatter<Char> &formatter, ArgFormatter(BasicFormatter<Char> &formatter,
FormatSpec &spec, const Char *fmt) FormatSpec &spec, const Char *fmt)
: BasicArgFormatter<ArgFormatter<Char>, Char>(formatter, spec, fmt) {} : BasicArgFormatter<ArgFormatter<Char>, Char>(formatter, spec, fmt)
{}
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
@ -2435,7 +2598,8 @@ public:
\endrst \endrst
*/ */
BasicFormatter(const ArgList &args, BasicWriter<Char> &w) BasicFormatter(const ArgList &args, BasicWriter<Char> &w)
: internal::FormatterBase(args), writer_(w) {} : internal::FormatterBase(args), writer_(w)
{}
/** Returns a reference to the writer associated with this formatter. */ /** Returns a reference to the writer associated with this formatter. */
BasicWriter<Char> &writer() BasicWriter<Char> &writer()
@ -2530,10 +2694,12 @@ struct ArgType
{ {
uint64_t type; uint64_t type;
ArgType() : type(0) {} ArgType(): type(0)
{}
template <typename T> template <typename T>
ArgType(const T &arg) : type(make_type(arg)) {} ArgType(const T &arg) : type(make_type(arg))
{}
}; };
# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() # define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
@ -2660,7 +2826,8 @@ protected:
typedef char Char; // For FMT_VARIADIC_CTOR. typedef char Char; // For FMT_VARIADIC_CTOR.
SystemError() {} SystemError()
{}
public: public:
/** /**
@ -2687,7 +2854,7 @@ public:
} }
FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef)
~SystemError() throw(); ~SystemError() FMT_DTOR_NOEXCEPT;
int error_code() const int error_code() const
{ {
@ -2843,7 +3010,8 @@ private:
} }
template<typename T> template<typename T>
void append_float_length(Char *&, T) {} void append_float_length(Char *&, T)
{}
template <typename Impl, typename Char_> template <typename Impl, typename Char_>
friend class internal::ArgFormatterBase; friend class internal::ArgFormatterBase;
@ -2855,7 +3023,8 @@ protected:
/** /**
Constructs a ``BasicWriter`` object. Constructs a ``BasicWriter`` object.
*/ */
explicit BasicWriter(Buffer<Char> &b) : buffer_(b) {} explicit BasicWriter(Buffer<Char> &b): buffer_(b)
{}
public: public:
/** /**
@ -2863,7 +3032,8 @@ public:
Destroys a ``BasicWriter`` object. Destroys a ``BasicWriter`` object.
\endrst \endrst
*/ */
virtual ~BasicWriter() {} virtual ~BasicWriter()
{}
/** /**
Returns the total number of characters written. Returns the total number of characters written.
@ -3039,9 +3209,15 @@ public:
return *this; return *this;
} }
void clear() FMT_NOEXCEPT { buffer_.clear(); } void clear() FMT_NOEXCEPT
{
buffer_.clear();
}
Buffer<Char> &buffer() FMT_NOEXCEPT { return buffer_; } Buffer<Char> &buffer() FMT_NOEXCEPT
{
return buffer_;
}
}; };
template <typename Char> template <typename Char>
@ -3406,7 +3582,10 @@ void BasicWriter<Char>::write_double(T value, const FormatSpec &spec)
} }
// Build format string. // Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg enum
{
MAX_FORMAT_SIZE = 10
}; // longest format: %#-*.*Lg
Char format[MAX_FORMAT_SIZE]; Char format[MAX_FORMAT_SIZE];
Char *format_ptr = format; Char *format_ptr = format;
*format_ptr++ = '%'; *format_ptr++ = '%';
@ -3437,7 +3616,7 @@ void BasicWriter<Char>::write_double(T value, const FormatSpec &spec)
// Format using snprintf. // Format using snprintf.
Char fill = internal::CharTraits<Char>::cast(spec.fill()); Char fill = internal::CharTraits<Char>::cast(spec.fill());
unsigned n = 0; unsigned n = 0;
Char *start = 0; Char *start = FMT_NULL;
for (;;) for (;;)
{ {
std::size_t buffer_size = buffer_.capacity() - offset; std::size_t buffer_size = buffer_.capacity() - offset;
@ -3542,7 +3721,8 @@ private:
public: public:
explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) explicit BasicMemoryWriter(const Allocator& alloc = Allocator())
: BasicWriter<Char>(buffer_), buffer_(alloc) {} : BasicWriter<Char>(buffer_), buffer_(alloc)
{}
#if FMT_USE_RVALUE_REFERENCES #if FMT_USE_RVALUE_REFERENCES
/** /**
@ -3553,8 +3733,7 @@ public:
*/ */
BasicMemoryWriter(BasicMemoryWriter &&other) BasicMemoryWriter(BasicMemoryWriter &&other)
: BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_)) : BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_))
{ {}
}
/** /**
\rst \rst
@ -3606,7 +3785,8 @@ public:
\endrst \endrst
*/ */
BasicArrayWriter(Char *array, std::size_t size) BasicArrayWriter(Char *array, std::size_t size)
: BasicWriter<Char>(buffer_), buffer_(array, size) {} : BasicWriter<Char>(buffer_), buffer_(array, size)
{}
/** /**
\rst \rst
@ -3616,7 +3796,8 @@ public:
*/ */
template <std::size_t SIZE> template <std::size_t SIZE>
explicit BasicArrayWriter(Char(&array)[SIZE]) explicit BasicArrayWriter(Char(&array)[SIZE])
: BasicWriter<Char>(buffer_), buffer_(array, SIZE) {} : BasicWriter<Char>(buffer_), buffer_(array, SIZE)
{}
}; };
typedef BasicArrayWriter<char> ArrayWriter; typedef BasicArrayWriter<char> ArrayWriter;
@ -3678,7 +3859,10 @@ FMT_API void report_windows_error(int error_code,
#endif #endif
enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; enum Color
{
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE
};
/** /**
Formats a string and prints it to stdout using ANSI escape sequences Formats a string and prints it to stdout using ANSI escape sequences
@ -3741,7 +3925,10 @@ class FormatInt
private: private:
// Buffer should be large enough to hold all digits (digits10 + 1), // Buffer should be large enough to hold all digits (digits10 + 1),
// a sign and a null character. // a sign and a null character.
enum {BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3}; enum
{
BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3
};
mutable char buffer_[BUFFER_SIZE]; mutable char buffer_[BUFFER_SIZE];
char *str_; char *str_;
@ -3794,9 +3981,12 @@ public:
{ {
FormatSigned(value); FormatSigned(value);
} }
explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} explicit FormatInt(unsigned value): str_(format_decimal(value))
explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} {}
explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} explicit FormatInt(unsigned long value): str_(format_decimal(value))
{}
explicit FormatInt(ULongLong value): str_(format_decimal(value))
{}
/** Returns the number of characters written to the output buffer. */ /** Returns the number of characters written to the output buffer. */
std::size_t size() const std::size_t size() const
@ -3875,15 +4065,15 @@ inline void format_decimal(char *&buffer, T value)
\endrst \endrst
*/ */
template <typename T> template <typename T>
inline internal::NamedArg<char> arg(StringRef name, const T &arg) inline internal::NamedArgWithType<char, T> arg(StringRef name, const T &arg)
{ {
return internal::NamedArg<char>(name, arg); return internal::NamedArgWithType<char, T>(name, arg);
} }
template <typename T> template <typename T>
inline internal::NamedArg<wchar_t> arg(WStringRef name, const T &arg) inline internal::NamedArgWithType<wchar_t, T> arg(WStringRef name, const T &arg)
{ {
return internal::NamedArg<wchar_t>(name, arg); return internal::NamedArgWithType<wchar_t, T>(name, arg);
} }
// The following two functions are deleted intentionally to disable // The following two functions are deleted intentionally to disable
@ -4104,7 +4294,7 @@ inline internal::Arg BasicFormatter<Char, AF>::get_arg(
template <typename Char, typename AF> template <typename Char, typename AF>
inline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s) inline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s)
{ {
const char *error = 0; const char *error = FMT_NULL;
internal::Arg arg = *s < '0' || *s > '9' ? internal::Arg arg = *s < '0' || *s > '9' ?
next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error);
if (error) if (error)
@ -4126,7 +4316,7 @@ inline internal::Arg BasicFormatter<Char, AF>::parse_arg_name(const Char *&s)
c = *++s; c = *++s;
} }
while (internal::is_name_start(c) || ('0' <= c && c <= '9')); while (internal::is_name_start(c) || ('0' <= c && c <= '9'));
const char *error = 0; const char *error = FMT_NULL;
internal::Arg arg = get_arg(BasicStringRef<Char>(start, s - start), error); internal::Arg arg = get_arg(BasicStringRef<Char>(start, s - start), error);
if (error) if (error)
FMT_THROW(FormatError(error)); FMT_THROW(FormatError(error));
@ -4379,7 +4569,7 @@ struct UdlArg
const Char *str; const Char *str;
template <typename T> template <typename T>
NamedArg<Char> operator=(T &&value) const NamedArgWithType<Char, T> operator=(T &&value) const
{ {
return { str, std::forward<T>(value) }; return { str, std::forward<T>(value) };
} }

View File

@ -7,13 +7,13 @@
For the license information refer to format.h. For the license information refer to format.h.
*/ */
// Commented out by spdlog to use header only #include "ostream.h"
// #include "fmt/ostream.h"
namespace fmt { namespace fmt {
namespace internal { namespace internal {
FMT_FUNC void write(std::ostream &os, Writer &w) { FMT_FUNC void write(std::ostream &os, Writer &w)
{
const char *data = w.data(); const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size(); UnsignedStreamSize size = w.size();
@ -28,7 +28,8 @@ FMT_FUNC void write(std::ostream &os, Writer &w) {
} }
} }
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args)
{
MemoryWriter w; MemoryWriter w;
w.write(format_str, args); w.write(format_str, args);
internal::write(os, w); internal::write(os, w);

View File

@ -10,8 +10,8 @@
#ifndef FMT_OSTREAM_H_ #ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_ #define FMT_OSTREAM_H_
// Commented out by spdlog to use header only // commented out by spdlog
// #include "fmt/format.h" // #include "format.h"
#include <ostream> #include <ostream>
namespace fmt namespace fmt

View File

@ -13,7 +13,7 @@
#include <algorithm> // std::fill_n #include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits #include <limits> // std::numeric_limits
#include "fmt/ostream.h" #include "ostream.h"
namespace fmt namespace fmt
{ {
@ -83,13 +83,19 @@ public:
template <typename T, typename U> template <typename T, typename U>
struct is_same struct is_same
{ {
enum { value = 0 }; enum
{
value = 0
};
}; };
template <typename T> template <typename T>
struct is_same<T, T> struct is_same<T, T>
{ {
enum { value = 1 }; enum
{
value = 1
};
}; };
// An argument visitor that converts an integer argument to T for printf, // An argument visitor that converts an integer argument to T for printf,
@ -107,7 +113,8 @@ private:
public: public:
ArgConverter(internal::Arg &arg, wchar_t type) ArgConverter(internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {} : arg_(arg), type_(type)
{}
void visit_bool(bool value) void visit_bool(bool value)
{ {
@ -166,7 +173,8 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public: public:
explicit CharConverter(internal::Arg &arg) : arg_(arg) {} explicit CharConverter(internal::Arg &arg): arg_(arg)
{}
template <typename T> template <typename T>
void visit_any_int(T value) void visit_any_int(T value)
@ -186,7 +194,8 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public: public:
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} explicit WidthHandler(FormatSpec &spec): spec_(spec)
{}
void report_unhandled_arg() void report_unhandled_arg()
{ {
@ -248,8 +257,9 @@ public:
specifier information for standard argument types. specifier information for standard argument types.
\endrst \endrst
*/ */
BasicPrintfArgFormatter(BasicWriter<Char> &writer, FormatSpec &spec) BasicPrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: internal::ArgFormatterBase<Impl, Char>(writer, spec) {} : internal::ArgFormatterBase<Impl, Char>(w, s)
{}
/** Formats an argument of type ``bool``. */ /** Formats an argument of type ``bool``. */
void visit_bool(bool value) void visit_bool(bool value)
@ -329,7 +339,8 @@ class PrintfArgFormatter
public: public:
/** Constructs an argument formatter object. */ /** Constructs an argument formatter object. */
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {} : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s)
{}
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
@ -358,8 +369,9 @@ public:
appropriate lifetimes. appropriate lifetimes.
\endrst \endrst
*/ */
explicit PrintfFormatter(const ArgList &args, BasicWriter<Char> &w) explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
: FormatterBase(args), writer_(w) {} : FormatterBase(al), writer_(w)
{}
/** Formats stored arguments and writes the output to the writer. */ /** Formats stored arguments and writes the output to the writer. */
FMT_API void format(BasicCStringRef<Char> format_str); FMT_API void format(BasicCStringRef<Char> format_str);
@ -399,7 +411,7 @@ internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
unsigned arg_index) unsigned arg_index)
{ {
(void)s; (void)s;
const char *error = 0; const char *error = FMT_NULL;
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
if (error) if (error)
@ -639,4 +651,8 @@ inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args)
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
#ifdef FMT_HEADER_ONLY
# include "printf.cc"
#endif
#endif // FMT_PRINTF_H_ #endif // FMT_PRINTF_H_

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
// Thread safe logger // Thread safe logger (except for set_pattern(..), set_formatter(..) and set_error_handler())
// Has name, log level, vector of std::shared sink pointers and formatter // Has name, log level, vector of std::shared sink pointers and formatter
// Upon each log write the logger: // Upon each log write the logger:
// 1. Checks if its log level is enough to log the message // 1. Checks if its log level is enough to log the message
@ -68,6 +68,8 @@ public:
virtual void flush(); virtual void flush();
const std::vector<sink_ptr>& sinks() const;
protected: protected:
virtual void _sink_it(details::log_msg&); virtual void _sink_it(details::log_msg&);
virtual void _set_pattern(const std::string&); virtual void _set_pattern(const std::string&);
@ -90,5 +92,3 @@ protected:
} }
#include <spdlog/details/logger_impl.h> #include <spdlog/details/logger_impl.h>

View File

@ -33,7 +33,7 @@ public:
virtual void log(const details::log_msg& msg) override; virtual void log(const details::log_msg& msg) override;
virtual void flush() override; virtual void flush() override;
void set_color(level::level_enum level, const std::string& color); void set_color(level::level_enum color_level, const std::string& color);
/// Formatting codes /// Formatting codes
const std::string reset = "\033[00m"; const std::string reset = "\033[00m";
@ -101,9 +101,9 @@ inline void ansicolor_sink::flush()
sink_->flush(); sink_->flush();
} }
inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color) inline void ansicolor_sink::set_color(level::level_enum color_level, const std::string& color)
{ {
colors_[level] = color; colors_[color_level] = color;
} }
inline ansicolor_sink::~ansicolor_sink() inline ansicolor_sink::~ansicolor_sink()

View File

@ -29,7 +29,7 @@ template<class Mutex>
class simple_file_sink : public base_sink < Mutex > class simple_file_sink : public base_sink < Mutex >
{ {
public: public:
explicit simple_file_sink(const filename_t &filename, bool truncate = false) explicit simple_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false)
{ {
_file_helper.open(filename, truncate); _file_helper.open(filename, truncate);
} }
@ -37,14 +37,21 @@ public:
{ {
_file_helper.flush(); _file_helper.flush();
} }
void set_force_flush(bool force_flush)
{
_force_flush = force_flush;
}
protected: protected:
void _sink_it(const details::log_msg& msg) override void _sink_it(const details::log_msg& msg) override
{ {
_file_helper.write(msg); _file_helper.write(msg);
if(_force_flush)
_file_helper.flush();
} }
private: private:
details::file_helper _file_helper; details::file_helper _file_helper;
bool _force_flush;
}; };
typedef simple_file_sink<std::mutex> simple_file_sink_mt; typedef simple_file_sink<std::mutex> simple_file_sink_mt;

View File

@ -27,7 +27,7 @@ protected:
}; };
typedef null_sink<details::null_mutex> null_sink_st; typedef null_sink<details::null_mutex> null_sink_st;
typedef null_sink<std::mutex> null_sink_mt; typedef null_sink<details::null_mutex> null_sink_mt;
} }
} }

View File

@ -15,7 +15,10 @@ namespace sinks
class sink class sink
{ {
public: public:
sink(): _level( level::trace ) {} sink()
{
_level = level::trace;
}
virtual ~sink() {} virtual ~sink() {}
virtual void log(const details::log_msg& msg) = 0; virtual void log(const details::log_msg& msg) = 0;

View File

@ -22,7 +22,8 @@ class stdout_sink : public base_sink<Mutex>
{ {
using MyType = stdout_sink<Mutex>; using MyType = stdout_sink<Mutex>;
public: public:
stdout_sink() {} stdout_sink()
{}
static std::shared_ptr<MyType> instance() static std::shared_ptr<MyType> instance()
{ {
static std::shared_ptr<MyType> instance = std::make_shared<MyType>(); static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
@ -50,7 +51,8 @@ class stderr_sink : public base_sink<Mutex>
{ {
using MyType = stderr_sink<Mutex>; using MyType = stderr_sink<Mutex>;
public: public:
stderr_sink() {} stderr_sink()
{}
static std::shared_ptr<MyType> instance() static std::shared_ptr<MyType> instance()
{ {
static std::shared_ptr<MyType> instance = std::make_shared<MyType>(); static std::shared_ptr<MyType> instance = std::make_shared<MyType>();

View File

@ -0,0 +1,116 @@
//
// Copyright(c) 2016 spdlog
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/common.h>
#include <mutex>
#include <string>
#include <map>
#include <wincon.h>
namespace spdlog
{
namespace sinks
{
/*
* Windows color console sink. Uses WriteConsoleA to write to the console with colors
*/
template<class Mutex>
class wincolor_sink: public base_sink<Mutex>
{
public:
const WORD BOLD = FOREGROUND_INTENSITY;
const WORD RED = FOREGROUND_RED;
const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
wincolor_sink(HANDLE std_handle): out_handle_(std_handle)
{
colors_[level::trace] = CYAN;
colors_[level::debug] = CYAN;
colors_[level::info] = WHITE | BOLD;
colors_[level::warn] = YELLOW | BOLD;
colors_[level::err] = RED | BOLD; // red bold
colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background
colors_[level::off] = 0;
}
virtual ~wincolor_sink()
{
flush();
}
wincolor_sink(const wincolor_sink& other) = delete;
wincolor_sink& operator=(const wincolor_sink& other) = delete;
virtual void _sink_it(const details::log_msg& msg) override
{
auto color = colors_[msg.level];
auto orig_attribs = set_console_attribs(color);
WriteConsoleA(out_handle_, msg.formatted.data(), static_cast<DWORD>(msg.formatted.size()), nullptr, nullptr);
SetConsoleTextAttribute(out_handle_, orig_attribs); //reset to orig colors
}
virtual void flush() override
{
// windows console always flushed?
}
// change the color for the given level
void set_color(level::level_enum level, WORD color)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
colors_[level] = color;
}
private:
HANDLE out_handle_;
std::map<level::level_enum, WORD> colors_;
// set color and return the orig console attributes (for resetting later)
WORD set_console_attribs(WORD attribs)
{
CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;
GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info);
SetConsoleTextAttribute(out_handle_, attribs);
return orig_buffer_info.wAttributes; //return orig attribs
}
};
//
// windows color console to stdout
//
template<class Mutex>
class wincolor_stdout_sink: public wincolor_sink<Mutex>
{
public:
wincolor_stdout_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_OUTPUT_HANDLE))
{}
};
typedef wincolor_stdout_sink<std::mutex> wincolor_stdout_sink_mt;
typedef wincolor_stdout_sink<details::null_mutex> wincolor_stdout_sink_st;
//
// windows color console to stderr
//
template<class Mutex>
class wincolor_stderr_sink: public wincolor_sink<Mutex>
{
public:
wincolor_stderr_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_ERROR_HANDLE))
{}
};
typedef wincolor_stderr_sink<std::mutex> wincolor_stderr_sink_mt;
typedef wincolor_stderr_sink<details::null_mutex> wincolor_stderr_sink_st;
}
}

View File

@ -2,12 +2,13 @@
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
// spdlog main header file. // spdlog main header file.
// see example.cpp for usage example // see example.cpp for usage example
#pragma once #pragma once
#define SPDLOG_VERSION "0.12.0"
#include <spdlog/tweakme.h> #include <spdlog/tweakme.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/logger.h> #include <spdlog/logger.h>
@ -88,10 +89,17 @@ std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const fi
// //
// Create and register stdout/stderr loggers // Create and register stdout/stderr loggers
// //
std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name);
std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name);
std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name);
std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name, bool color = false); std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name);
//
// Create and register colored stdout/stderr loggers
//
std::shared_ptr<logger> stdout_color_mt(const std::string& logger_name);
std::shared_ptr<logger> stdout_color_st(const std::string& logger_name);
std::shared_ptr<logger> stderr_color_mt(const std::string& logger_name);
std::shared_ptr<logger> stderr_color_st(const std::string& logger_name);
// //

View File

@ -101,3 +101,8 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to prevent child processes from inheriting log file descriptors
//
// #define SPDLOG_PREVENT_CHILD_FD
///////////////////////////////////////////////////////////////////////////////