1 // Formatting library for C++ - optional OS-specific functionality
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
14 #include <system_error> // std::system_error
16 #if defined __APPLE__ || defined(__FreeBSD__)
17 # include <xlocale.h> // for LC_NUMERIC_MASK on OS X
23 // UWP doesn't provide _pipe.
24 # if FMT_HAS_INCLUDE("winapifamily.h")
25 # include <winapifamily.h>
27 # if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
28 defined(__linux__)) && \
29 (!defined(WINAPI_FAMILY) || \
30 (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
31 # include <fcntl.h> // for O_RDONLY
32 # define FMT_USE_FCNTL 1
34 # define FMT_USE_FCNTL 0
39 # if defined(_WIN32) && !defined(__MINGW32__)
40 // Fix warnings about deprecated symbols.
41 # define FMT_POSIX(call) _##call
43 # define FMT_POSIX(call) call
47 // Calls to system functions are wrapped in FMT_SYSTEM for testability.
49 # define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
51 # define FMT_SYSTEM(call) ::call
53 // Fix warnings about deprecated symbols.
54 # define FMT_POSIX_CALL(call) ::_##call
56 # define FMT_POSIX_CALL(call) ::call
60 // Retries the expression while it evaluates to error_result and errno
63 # define FMT_RETRY_VAL(result, expression, error_result) \
65 (result) = (expression); \
66 } while ((result) == (error_result) && errno == EINTR)
68 # define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
71 #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
74 FMT_MODULE_EXPORT_BEGIN
78 A reference to a null-terminated string. It can be constructed from a C
79 string or ``std::string``.
81 You can use one of the following type aliases for common character types:
83 +---------------+-----------------------------+
85 +===============+=============================+
86 | cstring_view | basic_cstring_view<char> |
87 +---------------+-----------------------------+
88 | wcstring_view | basic_cstring_view<wchar_t> |
89 +---------------+-----------------------------+
91 This class is most useful as a parameter type to allow passing
92 different types of strings to a function, for example::
94 template <typename... Args>
95 std::string format(cstring_view format_str, const Args & ... args);
98 format(std::string("{}"), 42);
101 template <typename Char
> class basic_cstring_view
{
106 /** Constructs a string reference object from a C string. */
107 basic_cstring_view(const Char
* s
) : data_(s
) {}
111 Constructs a string reference from an ``std::string`` object.
114 basic_cstring_view(const std::basic_string
<Char
>& s
) : data_(s
.c_str()) {}
116 /** Returns the pointer to a C string. */
117 const Char
* c_str() const { return data_
; }
120 using cstring_view
= basic_cstring_view
<char>;
121 using wcstring_view
= basic_cstring_view
<wchar_t>;
123 template <typename Char
> struct formatter
<std::error_code
, Char
> {
124 template <typename ParseContext
>
125 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> decltype(ctx
.begin()) {
129 template <typename FormatContext
>
130 FMT_CONSTEXPR
auto format(const std::error_code
& ec
, FormatContext
& ctx
) const
131 -> decltype(ctx
.out()) {
132 auto out
= ctx
.out();
133 out
= detail::write_bytes(out
, ec
.category().name(),
134 basic_format_specs
<Char
>());
135 out
= detail::write
<Char
>(out
, Char(':'));
136 out
= detail::write
<Char
>(out
, ec
.value());
142 FMT_API
const std::error_category
& system_category() noexcept
;
144 FMT_BEGIN_DETAIL_NAMESPACE
145 // A converter from UTF-16 to UTF-8.
146 // It is only provided for Windows since other systems support UTF-8 natively.
147 class utf16_to_utf8
{
149 memory_buffer buffer_
;
153 FMT_API
explicit utf16_to_utf8(basic_string_view
<wchar_t> s
);
154 operator string_view() const { return string_view(&buffer_
[0], size()); }
155 size_t size() const { return buffer_
.size() - 1; }
156 const char* c_str() const { return &buffer_
[0]; }
157 std::string
str() const { return std::string(&buffer_
[0], size()); }
159 // Performs conversion returning a system error code instead of
160 // throwing exception on conversion error. This method may still throw
161 // in case of memory allocation error.
162 FMT_API
int convert(basic_string_view
<wchar_t> s
);
165 FMT_API
void format_windows_error(buffer
<char>& out
, int error_code
,
166 const char* message
) noexcept
;
167 FMT_END_DETAIL_NAMESPACE
169 FMT_API
std::system_error
vwindows_error(int error_code
, string_view format_str
,
174 Constructs a :class:`std::system_error` object with the description
178 *<message>*: *<system-message>*
180 where *<message>* is the formatted message and *<system-message>* is the
181 system message corresponding to the error code.
182 *error_code* is a Windows error code as given by ``GetLastError``.
183 If *error_code* is not a valid error code such as -1, the system message
184 will look like "error -1".
188 // This throws a system_error with the description
189 // cannot open file 'madeup': The system cannot find the file specified.
190 // or similar (system message may vary).
191 const char *filename = "madeup";
192 LPOFSTRUCT of = LPOFSTRUCT();
193 HFILE file = OpenFile(filename, &of, OF_READ);
194 if (file == HFILE_ERROR) {
195 throw fmt::windows_error(GetLastError(),
196 "cannot open file '{}'", filename);
200 template <typename
... Args
>
201 std::system_error
windows_error(int error_code
, string_view message
,
202 const Args
&... args
) {
203 return vwindows_error(error_code
, message
, fmt::make_format_args(args
...));
206 // Reports a Windows error without throwing an exception.
207 // Can be used to report errors from destructors.
208 FMT_API
void report_windows_error(int error_code
, const char* message
) noexcept
;
210 inline const std::error_category
& system_category() noexcept
{
211 return std::system_category();
215 // std::system is not available on some platforms such as iOS (#2248).
217 template <typename S
, typename
... Args
, typename Char
= char_t
<S
>>
218 void say(const S
& format_str
, Args
&&... args
) {
219 std::system(format("say \"{}\"", format(format_str
, args
...)).c_str());
224 class buffered_file
{
230 explicit buffered_file(FILE* f
) : file_(f
) {}
233 buffered_file(const buffered_file
&) = delete;
234 void operator=(const buffered_file
&) = delete;
236 // Constructs a buffered_file object which doesn't represent any file.
237 buffered_file() noexcept
: file_(nullptr) {}
239 // Destroys the object closing the file it represents if any.
240 FMT_API
~buffered_file() noexcept
;
243 buffered_file(buffered_file
&& other
) noexcept
: file_(other
.file_
) {
244 other
.file_
= nullptr;
247 buffered_file
& operator=(buffered_file
&& other
) {
250 other
.file_
= nullptr;
255 FMT_API
buffered_file(cstring_view filename
, cstring_view mode
);
258 FMT_API
void close();
260 // Returns the pointer to a FILE object representing this file.
261 FILE* get() const noexcept
{ return file_
; }
263 FMT_API
int descriptor() const;
265 void vprint(string_view format_str
, format_args args
) {
266 fmt::vprint(file_
, format_str
, args
);
269 template <typename
... Args
>
270 inline void print(string_view format_str
, const Args
&... args
) {
271 vprint(format_str
, fmt::make_format_args(args
...));
276 // A file. Closed file is represented by a file object with descriptor -1.
277 // Methods that are not declared with noexcept may throw
278 // fmt::system_error in case of failure. Note that some errors such as
279 // closing the file multiple times will cause a crash on Windows rather
280 // than an exception. You can get standard behavior by overriding the
281 // invalid parameter handler with _set_invalid_parameter_handler.
284 int fd_
; // File descriptor.
286 // Constructs a file object with a given descriptor.
287 explicit file(int fd
) : fd_(fd
) {}
290 // Possible values for the oflag argument to the constructor.
292 RDONLY
= FMT_POSIX(O_RDONLY
), // Open for reading only.
293 WRONLY
= FMT_POSIX(O_WRONLY
), // Open for writing only.
294 RDWR
= FMT_POSIX(O_RDWR
), // Open for reading and writing.
295 CREATE
= FMT_POSIX(O_CREAT
), // Create if the file doesn't exist.
296 APPEND
= FMT_POSIX(O_APPEND
), // Open in append mode.
297 TRUNC
= FMT_POSIX(O_TRUNC
) // Truncate the content of the file.
300 // Constructs a file object which doesn't represent any file.
301 file() noexcept
: fd_(-1) {}
303 // Opens a file and constructs a file object representing this file.
304 file(cstring_view path
, int oflag
);
307 file(const file
&) = delete;
308 void operator=(const file
&) = delete;
310 file(file
&& other
) noexcept
: fd_(other
.fd_
) { other
.fd_
= -1; }
312 // Move assignment is not noexcept because close may throw.
313 file
& operator=(file
&& other
) {
320 // Destroys the object closing the file it represents if any.
323 // Returns the file descriptor.
324 int descriptor() const noexcept
{ return fd_
; }
329 // Returns the file size. The size has signed type for consistency with
331 long long size() const;
333 // Attempts to read count bytes from the file into the specified buffer.
334 size_t read(void* buffer
, size_t count
);
336 // Attempts to write count bytes from the specified buffer to the file.
337 size_t write(const void* buffer
, size_t count
);
339 // Duplicates a file descriptor with the dup function and returns
340 // the duplicate as a file object.
341 static file
dup(int fd
);
343 // Makes fd be the copy of this file descriptor, closing fd first if
347 // Makes fd be the copy of this file descriptor, closing fd first if
349 void dup2(int fd
, std::error_code
& ec
) noexcept
;
351 // Creates a pipe setting up read_end and write_end file objects for reading
352 // and writing respectively.
353 static void pipe(file
& read_end
, file
& write_end
);
355 // Creates a buffered_file object associated with this file and detaches
356 // this file object from the file.
357 buffered_file
fdopen(const char* mode
);
360 // Returns the memory page size.
363 FMT_BEGIN_DETAIL_NAMESPACE
366 buffer_size() = default;
368 buffer_size
operator=(size_t val
) const {
369 auto bs
= buffer_size();
375 struct ostream_params
{
376 int oflag
= file::WRONLY
| file::CREATE
| file::TRUNC
;
377 size_t buffer_size
= BUFSIZ
> 32768 ? BUFSIZ
: 32768;
381 template <typename
... T
>
382 ostream_params(T
... params
, int new_oflag
) : ostream_params(params
...) {
386 template <typename
... T
>
387 ostream_params(T
... params
, detail::buffer_size bs
)
388 : ostream_params(params
...) {
389 this->buffer_size
= bs
.value
;
392 // Intel has a bug that results in failure to deduce a constructor
393 // for empty parameter packs.
394 # if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
395 ostream_params(int new_oflag
) : oflag(new_oflag
) {}
396 ostream_params(detail::buffer_size bs
) : buffer_size(bs
.value
) {}
400 FMT_END_DETAIL_NAMESPACE
402 // Added {} below to work around default constructor error known to
403 // occur in Xcode versions 7.2.1 and 8.2.1.
404 constexpr detail::buffer_size buffer_size
{};
406 /** A fast output stream which is not thread-safe. */
407 class FMT_API ostream final
: private detail::buffer
<char> {
411 void grow(size_t) override
;
413 ostream(cstring_view path
, const detail::ostream_params
& params
)
414 : file_(path
, params
.oflag
) {
415 set(new char[params
.buffer_size
], params
.buffer_size
);
419 ostream(ostream
&& other
)
420 : detail::buffer
<char>(other
.data(), other
.size(), other
.capacity()),
421 file_(std::move(other
.file_
)) {
423 other
.set(nullptr, 0);
431 if (size() == 0) return;
432 file_
.write(data(), size());
436 template <typename
... T
>
437 friend ostream
output_file(cstring_view path
, T
... params
);
445 Formats ``args`` according to specifications in ``fmt`` and writes the
448 template <typename
... T
> void print(format_string
<T
...> fmt
, T
&&... args
) {
449 vformat_to(detail::buffer_appender
<char>(*this), fmt
,
450 fmt::make_format_args(args
...));
456 Opens a file for writing. Supported parameters passed in *params*:
458 * ``<integer>``: Flags passed to `open
459 <https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
460 (``file::WRONLY | file::CREATE | file::TRUNC`` by default)
461 * ``buffer_size=<integer>``: Output buffer size
465 auto out = fmt::output_file("guide.txt");
466 out.print("Don't {}", "Panic");
469 template <typename
... T
>
470 inline ostream
output_file(cstring_view path
, T
... params
) {
471 return {path
, detail::ostream_params(params
...)};
473 #endif // FMT_USE_FCNTL
475 FMT_MODULE_EXPORT_END