093b39ca5 Update docs for meson (#4291) 2c3a5698e Simplify a copying the fill from basic_specs fc1b0f348 Clarify use of FMT_THROW in a comment 1d066890c Resolve C4702 unreachable code warnings dad323751 Fix a bug when copying the fill from basic_specs 880e1494d Improve xchar support for std::bitset formatter e3ddede6c Update version e9ec4fdc8 Bump version feb72126b Readd FMT_NO_UNIQUE_ADDRESS 8d517e54c Update changelog 563fc74ae Update changelog 3e04222d5 Restore ABI compatibility with 11.0.2 853df39d0 Mention compile-time formatting 11742a09c Clarify that format_string should be used instead of fstring da24fac10 Document fstring 5fa4bdd75 Define CMake components to allow docs to be installed separately (#4276) 3c8aad8df Update the release script 0e8aad961 Update version debe784aa Update changelog f6d112567 Update changelog 73d0d3f75 Fix github API call 08f60f1ef Update changelog faf3f8408 Bump version f3a41441d Replace requests with urllib 3f33cb21d Update changelog b07a90386 Update changelog a6fba5177 Update changelog 25e292998 Update changelog 00ab2e98b Update changelog a3ef285ae Always inline const_check to improve debug codegen in clang 28d1abc9d Update changelog 90704b9ef Update changelog 86dae01c2 Fix compatibility with older versions of VS (#4271) d8a79eafd Document formatting of bit-fields and fields of packed structs 7c3d0152e Use the _MSVC_STL_UPDATE macro to detect STL (#4267) 7c50da538 Allow getting size of dynamic format arg store (#4270) 873670ba3 Make parameter basic_memory_buffer<char, SIZE>& buf of to_string const 735d4cc05 Update changelog 141380172 Allow disabling <filesystem> by define FMT_CPP_LIB_FILESYSTEM=0 (#4259) 4302d7429 Update changelog 0f51ea79d Update changelog 9600fee02 Include <filesystem> only if FMT_CPP_LIB_FILESYSTEM is set (#4258) 47a66c5ec Bump msys2/setup-msys2 from 2.24.0 to 2.25.0 (#4250) 385c01dc7 Allow bit_cast to work for 80bit long double (#4246) df249d8ad Remove an old workaround dfad80d1c Remove an old workaround 536cabd56 Export all range join overloads (#4239) b1a054706 Remove more MSVC 2015 workarounds and fix string_view checks bfd95392c Remove MSVC 2015 workaround 9ced61bca Replace std::forward for clang-tidy (#4236) 75e5be6ad Sort specifiers a169d7fa4 Fix chrono formatting syntax doc (#4235) a6c45dfea Fix modular build a35389b3c Corrently handle buffer flush 5a3576acc Implement fmt::join for tuple-like objects (#4230) 542600013 Suppress MSVC warnings "C4127: conditional expression is constant" by used const_check (#4233) 720da57ba Remove reference to unused intrinsic 680db66c3 Explicitly export symbols from detail 56ce41ef6 Remove initializer_list dependency cf50e4d6a Fix const[expr] in context API 6580d7b80 Cleanup the format API 7e73566ce Minor cleanup 8523dba2d Make constexpr precede explicit consistently e3d3b24fc Minor cleanup 1521bba70 Use consistent types for argument count 00649552a Bump github/codeql-action from 3.26.6 to 3.27.0 (#4223) 4b8e2838f More cleanup 7d4662f7a Remove FMT_BUILTIN_CTZ 27110bc47 Minor cleanup 68f315376 Fix narrowing conversion warning in struct fstring (#4210) 168df9a06 Implement fmt::format_to into std::vector<char> (#4211) 4daa3d591 Fix error: cannot use 'try' with exceptions disabled in Win LLVM Clang (#4208) e9eaa27e5 Add std::exception to the docs 2b6a786e3 Use standard context in print a16ff5787 Add support for code units > 0xFFFF in fill 601be1cbe Add support for code units > 0xFFFF in fill 58c185b63 Changing type of data_ to size_t to avoid compilation warnings (#4200) a0a9ba2af Fix hashes cc2ba8f9e Cleanup cifuzz action a18d42b20 Simplify lint (#4197) 4046f9727 Fix -Wmissing-noreturn warning (#4194) 6bdc12a19 detail_exported -> detail 786a4b096 Cleanup fixed_string 2cb3b7c64 Update README.md e9cba6905 Update README.md 02537548f Cleanup an example c68c5fa7c Test FMT_BUILTIN_TYPES 22701d5f6 Address build failures when using Tip-of-Tree clang. (#4187) e62c41ffb Conform `std::iterator_traits<fmt::appender>` to [iterator.traits]/1 (#4185) 18792893d Silencing Wextra-semi warning (#4188) c90bc9186 Bump actions/checkout from 4.1.6 to 4.2.0 (#4182) c95722ad6 Improve naming consistency db06b0df8 Use countl_zero in bigint b9ec48d9c Cleanup bigint 3faf6f181 Add min_of/max_of d64b100a3 Relax constexpr ff9ee0461 Fix handling FMT_BUILTIN_TYPES 1c5883bef Test nondeterministic conversion to format string cacc3108c Don't assume repeated evaluation of string literal produce the same pointer fade652ad Require clang >=15 for _BitInt support (#4176) 96dca569a Module linkage fixes for shared build (#4169) 891c9a73a Cleanup format API 9282222b7 Export more e5b20ff0d Deprecate detail::locale_ref ff9222354 Simplify locale handling 80c4d42c6 Cleanup format.h git-subtree-dir: external/fmt git-subtree-split: 093b39ca5eea129b111060839602bcfaf295125a
428 lines
12 KiB
C++
428 lines
12 KiB
C++
// Formatting library for C++ - optional OS-specific functionality
|
|
//
|
|
// Copyright (c) 2012 - present, Victor Zverovich
|
|
// All rights reserved.
|
|
//
|
|
// For the license information refer to format.h.
|
|
|
|
#ifndef FMT_OS_H_
|
|
#define FMT_OS_H_
|
|
|
|
#include "format.h"
|
|
|
|
#ifndef FMT_MODULE
|
|
# include <cerrno>
|
|
# include <cstddef>
|
|
# include <cstdio>
|
|
# include <system_error> // std::system_error
|
|
|
|
# if FMT_HAS_INCLUDE(<xlocale.h>)
|
|
# include <xlocale.h> // LC_NUMERIC_MASK on macOS
|
|
# endif
|
|
#endif // FMT_MODULE
|
|
|
|
#ifndef FMT_USE_FCNTL
|
|
// UWP doesn't provide _pipe.
|
|
# if FMT_HAS_INCLUDE("winapifamily.h")
|
|
# include <winapifamily.h>
|
|
# endif
|
|
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
|
defined(__linux__)) && \
|
|
(!defined(WINAPI_FAMILY) || \
|
|
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
|
# include <fcntl.h> // for O_RDONLY
|
|
# define FMT_USE_FCNTL 1
|
|
# else
|
|
# define FMT_USE_FCNTL 0
|
|
# endif
|
|
#endif
|
|
|
|
#ifndef FMT_POSIX
|
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
|
// Fix warnings about deprecated symbols.
|
|
# define FMT_POSIX(call) _##call
|
|
# else
|
|
# define FMT_POSIX(call) call
|
|
# endif
|
|
#endif
|
|
|
|
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
|
#ifdef FMT_SYSTEM
|
|
# define FMT_HAS_SYSTEM
|
|
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
|
#else
|
|
# define FMT_SYSTEM(call) ::call
|
|
# ifdef _WIN32
|
|
// Fix warnings about deprecated symbols.
|
|
# define FMT_POSIX_CALL(call) ::_##call
|
|
# else
|
|
# define FMT_POSIX_CALL(call) ::call
|
|
# endif
|
|
#endif
|
|
|
|
// Retries the expression while it evaluates to error_result and errno
|
|
// equals to EINTR.
|
|
#ifndef _WIN32
|
|
# define FMT_RETRY_VAL(result, expression, error_result) \
|
|
do { \
|
|
(result) = (expression); \
|
|
} while ((result) == (error_result) && errno == EINTR)
|
|
#else
|
|
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
|
#endif
|
|
|
|
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
|
|
|
FMT_BEGIN_NAMESPACE
|
|
FMT_BEGIN_EXPORT
|
|
|
|
/**
|
|
* A reference to a null-terminated string. It can be constructed from a C
|
|
* string or `std::string`.
|
|
*
|
|
* You can use one of the following type aliases for common character types:
|
|
*
|
|
* +---------------+-----------------------------+
|
|
* | Type | Definition |
|
|
* +===============+=============================+
|
|
* | cstring_view | basic_cstring_view<char> |
|
|
* +---------------+-----------------------------+
|
|
* | wcstring_view | basic_cstring_view<wchar_t> |
|
|
* +---------------+-----------------------------+
|
|
*
|
|
* This class is most useful as a parameter type for functions that wrap C APIs.
|
|
*/
|
|
template <typename Char> class basic_cstring_view {
|
|
private:
|
|
const Char* data_;
|
|
|
|
public:
|
|
/// Constructs a string reference object from a C string.
|
|
basic_cstring_view(const Char* s) : data_(s) {}
|
|
|
|
/// Constructs a string reference from an `std::string` object.
|
|
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
|
|
|
|
/// Returns the pointer to a C string.
|
|
auto c_str() const -> const Char* { return data_; }
|
|
};
|
|
|
|
using cstring_view = basic_cstring_view<char>;
|
|
using wcstring_view = basic_cstring_view<wchar_t>;
|
|
|
|
#ifdef _WIN32
|
|
FMT_API const std::error_category& system_category() noexcept;
|
|
|
|
namespace detail {
|
|
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
|
const char* message) noexcept;
|
|
}
|
|
|
|
FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
|
|
format_args args);
|
|
|
|
/**
|
|
* Constructs a `std::system_error` object with the description of the form
|
|
*
|
|
* <message>: <system-message>
|
|
*
|
|
* where `<message>` is the formatted message and `<system-message>` is the
|
|
* system message corresponding to the error code.
|
|
* `error_code` is a Windows error code as given by `GetLastError`.
|
|
* If `error_code` is not a valid error code such as -1, the system message
|
|
* will look like "error -1".
|
|
*
|
|
* **Example**:
|
|
*
|
|
* // This throws a system_error with the description
|
|
* // cannot open file 'madeup': The system cannot find the file
|
|
* specified.
|
|
* // or similar (system message may vary).
|
|
* const char *filename = "madeup";
|
|
* LPOFSTRUCT of = LPOFSTRUCT();
|
|
* HFILE file = OpenFile(filename, &of, OF_READ);
|
|
* if (file == HFILE_ERROR) {
|
|
* throw fmt::windows_error(GetLastError(),
|
|
* "cannot open file '{}'", filename);
|
|
* }
|
|
*/
|
|
template <typename... T>
|
|
auto windows_error(int error_code, string_view message, const T&... args)
|
|
-> std::system_error {
|
|
return vwindows_error(error_code, message, vargs<T...>{{args...}});
|
|
}
|
|
|
|
// Reports a Windows error without throwing an exception.
|
|
// Can be used to report errors from destructors.
|
|
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
|
#else
|
|
inline auto system_category() noexcept -> const std::error_category& {
|
|
return std::system_category();
|
|
}
|
|
#endif // _WIN32
|
|
|
|
// std::system is not available on some platforms such as iOS (#2248).
|
|
#ifdef __OSX__
|
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
|
void say(const S& fmt, Args&&... args) {
|
|
std::system(format("say \"{}\"", format(fmt, args...)).c_str());
|
|
}
|
|
#endif
|
|
|
|
// A buffered file.
|
|
class buffered_file {
|
|
private:
|
|
FILE* file_;
|
|
|
|
friend class file;
|
|
|
|
inline explicit buffered_file(FILE* f) : file_(f) {}
|
|
|
|
public:
|
|
buffered_file(const buffered_file&) = delete;
|
|
void operator=(const buffered_file&) = delete;
|
|
|
|
// Constructs a buffered_file object which doesn't represent any file.
|
|
inline buffered_file() noexcept : file_(nullptr) {}
|
|
|
|
// Destroys the object closing the file it represents if any.
|
|
FMT_API ~buffered_file() noexcept;
|
|
|
|
public:
|
|
inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
|
other.file_ = nullptr;
|
|
}
|
|
|
|
inline auto operator=(buffered_file&& other) -> buffered_file& {
|
|
close();
|
|
file_ = other.file_;
|
|
other.file_ = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
// Opens a file.
|
|
FMT_API buffered_file(cstring_view filename, cstring_view mode);
|
|
|
|
// Closes the file.
|
|
FMT_API void close();
|
|
|
|
// Returns the pointer to a FILE object representing this file.
|
|
inline auto get() const noexcept -> FILE* { return file_; }
|
|
|
|
FMT_API auto descriptor() const -> int;
|
|
|
|
template <typename... T>
|
|
inline void print(string_view fmt, const T&... args) {
|
|
fmt::vargs<T...> vargs = {{args...}};
|
|
detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs)
|
|
: fmt::vprint(file_, fmt, vargs);
|
|
}
|
|
};
|
|
|
|
#if FMT_USE_FCNTL
|
|
|
|
// A file. Closed file is represented by a file object with descriptor -1.
|
|
// Methods that are not declared with noexcept may throw
|
|
// fmt::system_error in case of failure. Note that some errors such as
|
|
// closing the file multiple times will cause a crash on Windows rather
|
|
// than an exception. You can get standard behavior by overriding the
|
|
// invalid parameter handler with _set_invalid_parameter_handler.
|
|
class FMT_API file {
|
|
private:
|
|
int fd_; // File descriptor.
|
|
|
|
// Constructs a file object with a given descriptor.
|
|
explicit file(int fd) : fd_(fd) {}
|
|
|
|
friend struct pipe;
|
|
|
|
public:
|
|
// Possible values for the oflag argument to the constructor.
|
|
enum {
|
|
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
|
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
|
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
|
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
|
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
|
|
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
|
|
};
|
|
|
|
// Constructs a file object which doesn't represent any file.
|
|
inline file() noexcept : fd_(-1) {}
|
|
|
|
// Opens a file and constructs a file object representing this file.
|
|
file(cstring_view path, int oflag);
|
|
|
|
public:
|
|
file(const file&) = delete;
|
|
void operator=(const file&) = delete;
|
|
|
|
inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
|
|
|
|
// Move assignment is not noexcept because close may throw.
|
|
inline auto operator=(file&& other) -> file& {
|
|
close();
|
|
fd_ = other.fd_;
|
|
other.fd_ = -1;
|
|
return *this;
|
|
}
|
|
|
|
// Destroys the object closing the file it represents if any.
|
|
~file() noexcept;
|
|
|
|
// Returns the file descriptor.
|
|
inline auto descriptor() const noexcept -> int { return fd_; }
|
|
|
|
// Closes the file.
|
|
void close();
|
|
|
|
// Returns the file size. The size has signed type for consistency with
|
|
// stat::st_size.
|
|
auto size() const -> long long;
|
|
|
|
// Attempts to read count bytes from the file into the specified buffer.
|
|
auto read(void* buffer, size_t count) -> size_t;
|
|
|
|
// Attempts to write count bytes from the specified buffer to the file.
|
|
auto write(const void* buffer, size_t count) -> size_t;
|
|
|
|
// Duplicates a file descriptor with the dup function and returns
|
|
// the duplicate as a file object.
|
|
static auto dup(int fd) -> file;
|
|
|
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
|
// necessary.
|
|
void dup2(int fd);
|
|
|
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
|
// necessary.
|
|
void dup2(int fd, std::error_code& ec) noexcept;
|
|
|
|
// Creates a buffered_file object associated with this file and detaches
|
|
// this file object from the file.
|
|
auto fdopen(const char* mode) -> buffered_file;
|
|
|
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
|
// Opens a file and constructs a file object representing this file by
|
|
// wcstring_view filename. Windows only.
|
|
static file open_windows_file(wcstring_view path, int oflag);
|
|
# endif
|
|
};
|
|
|
|
struct FMT_API pipe {
|
|
file read_end;
|
|
file write_end;
|
|
|
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
|
// and writing respectively.
|
|
pipe();
|
|
};
|
|
|
|
// Returns the memory page size.
|
|
auto getpagesize() -> long;
|
|
|
|
namespace detail {
|
|
|
|
struct buffer_size {
|
|
constexpr buffer_size() = default;
|
|
size_t value = 0;
|
|
FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size {
|
|
auto bs = buffer_size();
|
|
bs.value = val;
|
|
return bs;
|
|
}
|
|
};
|
|
|
|
struct ostream_params {
|
|
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
|
|
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
|
|
|
constexpr ostream_params() {}
|
|
|
|
template <typename... T>
|
|
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
|
|
oflag = new_oflag;
|
|
}
|
|
|
|
template <typename... T>
|
|
ostream_params(T... params, detail::buffer_size bs)
|
|
: ostream_params(params...) {
|
|
this->buffer_size = bs.value;
|
|
}
|
|
|
|
// Intel has a bug that results in failure to deduce a constructor
|
|
// for empty parameter packs.
|
|
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
|
|
ostream_params(int new_oflag) : oflag(new_oflag) {}
|
|
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
|
|
# endif
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size();
|
|
|
|
/// A fast buffered output stream for writing from a single thread. Writing from
|
|
/// multiple threads without external synchronization may result in a data race.
|
|
class FMT_API ostream : private detail::buffer<char> {
|
|
private:
|
|
file file_;
|
|
|
|
ostream(cstring_view path, const detail::ostream_params& params);
|
|
|
|
static void grow(buffer<char>& buf, size_t);
|
|
|
|
public:
|
|
ostream(ostream&& other) noexcept;
|
|
~ostream();
|
|
|
|
operator writer() {
|
|
detail::buffer<char>& buf = *this;
|
|
return buf;
|
|
}
|
|
|
|
inline void flush() {
|
|
if (size() == 0) return;
|
|
file_.write(data(), size() * sizeof(data()[0]));
|
|
clear();
|
|
}
|
|
|
|
template <typename... T>
|
|
friend auto output_file(cstring_view path, T... params) -> ostream;
|
|
|
|
inline void close() {
|
|
flush();
|
|
file_.close();
|
|
}
|
|
|
|
/// Formats `args` according to specifications in `fmt` and writes the
|
|
/// output to the file.
|
|
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
|
|
vformat_to(appender(*this), fmt.str, vargs<T...>{{args...}});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Opens a file for writing. Supported parameters passed in `params`:
|
|
*
|
|
* - `<integer>`: Flags passed to [open](
|
|
* https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html)
|
|
* (`file::WRONLY | file::CREATE | file::TRUNC` by default)
|
|
* - `buffer_size=<integer>`: Output buffer size
|
|
*
|
|
* **Example**:
|
|
*
|
|
* auto out = fmt::output_file("guide.txt");
|
|
* out.print("Don't {}", "Panic");
|
|
*/
|
|
template <typename... T>
|
|
inline auto output_file(cstring_view path, T... params) -> ostream {
|
|
return {path, detail::ostream_params(params...)};
|
|
}
|
|
#endif // FMT_USE_FCNTL
|
|
|
|
FMT_END_EXPORT
|
|
FMT_END_NAMESPACE
|
|
|
|
#endif // FMT_OS_H_
|