xref: /aosp_15_r20/external/fmtlib/include/fmt/os.h (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1 // Formatting library for C++ - optional OS-specific functionality
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMT_OS_H_
9 #define FMT_OS_H_
10 
11 #include "format.h"
12 
13 #ifndef FMT_MODULE
14 #  include <cerrno>
15 #  include <cstddef>
16 #  include <cstdio>
17 #  include <system_error>  // std::system_error
18 
19 #  if FMT_HAS_INCLUDE(<xlocale.h>)
20 #    include <xlocale.h>  // LC_NUMERIC_MASK on macOS
21 #  endif
22 #endif  // FMT_MODULE
23 
24 #ifndef FMT_USE_FCNTL
25 // UWP doesn't provide _pipe.
26 #  if FMT_HAS_INCLUDE("winapifamily.h")
27 #    include <winapifamily.h>
28 #  endif
29 #  if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
30        defined(__linux__)) &&                              \
31       (!defined(WINAPI_FAMILY) ||                          \
32        (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
33 #    include <fcntl.h>  // for O_RDONLY
34 #    define FMT_USE_FCNTL 1
35 #  else
36 #    define FMT_USE_FCNTL 0
37 #  endif
38 #endif
39 
40 #ifndef FMT_POSIX
41 #  if defined(_WIN32) && !defined(__MINGW32__)
42 // Fix warnings about deprecated symbols.
43 #    define FMT_POSIX(call) _##call
44 #  else
45 #    define FMT_POSIX(call) call
46 #  endif
47 #endif
48 
49 // Calls to system functions are wrapped in FMT_SYSTEM for testability.
50 #ifdef FMT_SYSTEM
51 #  define FMT_HAS_SYSTEM
52 #  define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
53 #else
54 #  define FMT_SYSTEM(call) ::call
55 #  ifdef _WIN32
56 // Fix warnings about deprecated symbols.
57 #    define FMT_POSIX_CALL(call) ::_##call
58 #  else
59 #    define FMT_POSIX_CALL(call) ::call
60 #  endif
61 #endif
62 
63 // Retries the expression while it evaluates to error_result and errno
64 // equals to EINTR.
65 #ifndef _WIN32
66 #  define FMT_RETRY_VAL(result, expression, error_result) \
67     do {                                                  \
68       (result) = (expression);                            \
69     } while ((result) == (error_result) && errno == EINTR)
70 #else
71 #  define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
72 #endif
73 
74 #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
75 
76 FMT_BEGIN_NAMESPACE
77 FMT_BEGIN_EXPORT
78 
79 /**
80  * A reference to a null-terminated string. It can be constructed from a C
81  * string or `std::string`.
82  *
83  * You can use one of the following type aliases for common character types:
84  *
85  * +---------------+-----------------------------+
86  * | Type          | Definition                  |
87  * +===============+=============================+
88  * | cstring_view  | basic_cstring_view<char>    |
89  * +---------------+-----------------------------+
90  * | wcstring_view | basic_cstring_view<wchar_t> |
91  * +---------------+-----------------------------+
92  *
93  * This class is most useful as a parameter type for functions that wrap C APIs.
94  */
95 template <typename Char> class basic_cstring_view {
96  private:
97   const Char* data_;
98 
99  public:
100   /// Constructs a string reference object from a C string.
basic_cstring_view(const Char * s)101   basic_cstring_view(const Char* s) : data_(s) {}
102 
103   /// Constructs a string reference from an `std::string` object.
basic_cstring_view(const std::basic_string<Char> & s)104   basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
105 
106   /// Returns the pointer to a C string.
107   auto c_str() const -> const Char* { return data_; }
108 };
109 
110 using cstring_view = basic_cstring_view<char>;
111 using wcstring_view = basic_cstring_view<wchar_t>;
112 
113 #ifdef _WIN32
114 FMT_API const std::error_category& system_category() noexcept;
115 
116 namespace detail {
117 FMT_API void format_windows_error(buffer<char>& out, int error_code,
118                                   const char* message) noexcept;
119 }
120 
121 FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
122                                          format_args args);
123 
124 /**
125  * Constructs a `std::system_error` object with the description of the form
126  *
127  *     <message>: <system-message>
128  *
129  * where `<message>` is the formatted message and `<system-message>` is the
130  * system message corresponding to the error code.
131  * `error_code` is a Windows error code as given by `GetLastError`.
132  * If `error_code` is not a valid error code such as -1, the system message
133  * will look like "error -1".
134  *
135  * **Example**:
136  *
137  *     // This throws a system_error with the description
138  *     //   cannot open file 'madeup': The system cannot find the file
139  * specified.
140  *     // or similar (system message may vary).
141  *     const char *filename = "madeup";
142  *     LPOFSTRUCT of = LPOFSTRUCT();
143  *     HFILE file = OpenFile(filename, &of, OF_READ);
144  *     if (file == HFILE_ERROR) {
145  *       throw fmt::windows_error(GetLastError(),
146  *                                "cannot open file '{}'", filename);
147  *     }
148  */
149 template <typename... T>
150 auto windows_error(int error_code, string_view message, const T&... args)
151     -> std::system_error {
152   return vwindows_error(error_code, message, vargs<T...>{{args...}});
153 }
154 
155 // Reports a Windows error without throwing an exception.
156 // Can be used to report errors from destructors.
157 FMT_API void report_windows_error(int error_code, const char* message) noexcept;
158 #else
159 inline auto system_category() noexcept -> const std::error_category& {
160   return std::system_category();
161 }
162 #endif  // _WIN32
163 
164 // std::system is not available on some platforms such as iOS (#2248).
165 #ifdef __OSX__
166 template <typename S, typename... Args, typename Char = char_t<S>>
say(const S & fmt,Args &&...args)167 void say(const S& fmt, Args&&... args) {
168   std::system(format("say \"{}\"", format(fmt, args...)).c_str());
169 }
170 #endif
171 
172 // A buffered file.
173 class buffered_file {
174  private:
175   FILE* file_;
176 
177   friend class file;
178 
buffered_file(FILE * f)179   inline explicit buffered_file(FILE* f) : file_(f) {}
180 
181  public:
182   buffered_file(const buffered_file&) = delete;
183   void operator=(const buffered_file&) = delete;
184 
185   // Constructs a buffered_file object which doesn't represent any file.
buffered_file()186   inline buffered_file() noexcept : file_(nullptr) {}
187 
188   // Destroys the object closing the file it represents if any.
189   FMT_API ~buffered_file() noexcept;
190 
191  public:
buffered_file(buffered_file && other)192   inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
193     other.file_ = nullptr;
194   }
195 
196   inline auto operator=(buffered_file&& other) -> buffered_file& {
197     close();
198     file_ = other.file_;
199     other.file_ = nullptr;
200     return *this;
201   }
202 
203   // Opens a file.
204   FMT_API buffered_file(cstring_view filename, cstring_view mode);
205 
206   // Closes the file.
207   FMT_API void close();
208 
209   // Returns the pointer to a FILE object representing this file.
210   inline auto get() const noexcept -> FILE* { return file_; }
211 
212   FMT_API auto descriptor() const -> int;
213 
214   template <typename... T>
print(string_view fmt,const T &...args)215   inline void print(string_view fmt, const T&... args) {
216     fmt::vargs<T...> vargs = {{args...}};
217     detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs)
218                                : fmt::vprint(file_, fmt, vargs);
219   }
220 };
221 
222 #if FMT_USE_FCNTL
223 
224 // A file. Closed file is represented by a file object with descriptor -1.
225 // Methods that are not declared with noexcept may throw
226 // fmt::system_error in case of failure. Note that some errors such as
227 // closing the file multiple times will cause a crash on Windows rather
228 // than an exception. You can get standard behavior by overriding the
229 // invalid parameter handler with _set_invalid_parameter_handler.
230 class FMT_API file {
231  private:
232   int fd_;  // File descriptor.
233 
234   // Constructs a file object with a given descriptor.
file(int fd)235   explicit file(int fd) : fd_(fd) {}
236 
237   friend struct pipe;
238 
239  public:
240   // Possible values for the oflag argument to the constructor.
241   enum {
242     RDONLY = FMT_POSIX(O_RDONLY),  // Open for reading only.
243     WRONLY = FMT_POSIX(O_WRONLY),  // Open for writing only.
244     RDWR = FMT_POSIX(O_RDWR),      // Open for reading and writing.
245     CREATE = FMT_POSIX(O_CREAT),   // Create if the file doesn't exist.
246     APPEND = FMT_POSIX(O_APPEND),  // Open in append mode.
247     TRUNC = FMT_POSIX(O_TRUNC)     // Truncate the content of the file.
248   };
249 
250   // Constructs a file object which doesn't represent any file.
file()251   inline file() noexcept : fd_(-1) {}
252 
253   // Opens a file and constructs a file object representing this file.
254   file(cstring_view path, int oflag);
255 
256  public:
257   file(const file&) = delete;
258   void operator=(const file&) = delete;
259 
file(file && other)260   inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
261 
262   // Move assignment is not noexcept because close may throw.
263   inline auto operator=(file&& other) -> file& {
264     close();
265     fd_ = other.fd_;
266     other.fd_ = -1;
267     return *this;
268   }
269 
270   // Destroys the object closing the file it represents if any.
271   ~file() noexcept;
272 
273   // Returns the file descriptor.
274   inline auto descriptor() const noexcept -> int { return fd_; }
275 
276   // Closes the file.
277   void close();
278 
279   // Returns the file size. The size has signed type for consistency with
280   // stat::st_size.
281   auto size() const -> long long;
282 
283   // Attempts to read count bytes from the file into the specified buffer.
284   auto read(void* buffer, size_t count) -> size_t;
285 
286   // Attempts to write count bytes from the specified buffer to the file.
287   auto write(const void* buffer, size_t count) -> size_t;
288 
289   // Duplicates a file descriptor with the dup function and returns
290   // the duplicate as a file object.
291   static auto dup(int fd) -> file;
292 
293   // Makes fd be the copy of this file descriptor, closing fd first if
294   // necessary.
295   void dup2(int fd);
296 
297   // Makes fd be the copy of this file descriptor, closing fd first if
298   // necessary.
299   void dup2(int fd, std::error_code& ec) noexcept;
300 
301   // Creates a buffered_file object associated with this file and detaches
302   // this file object from the file.
303   auto fdopen(const char* mode) -> buffered_file;
304 
305 #  if defined(_WIN32) && !defined(__MINGW32__)
306   // Opens a file and constructs a file object representing this file by
307   // wcstring_view filename. Windows only.
308   static file open_windows_file(wcstring_view path, int oflag);
309 #  endif
310 };
311 
312 struct FMT_API pipe {
313   file read_end;
314   file write_end;
315 
316   // Creates a pipe setting up read_end and write_end file objects for reading
317   // and writing respectively.
318   pipe();
319 };
320 
321 // Returns the memory page size.
322 auto getpagesize() -> long;
323 
324 namespace detail {
325 
326 struct buffer_size {
327   constexpr buffer_size() = default;
328   size_t value = 0;
329   FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size {
330     auto bs = buffer_size();
331     bs.value = val;
332     return bs;
333   }
334 };
335 
336 struct ostream_params {
337   int oflag = file::WRONLY | file::CREATE | file::TRUNC;
338   size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
339 
ostream_paramsostream_params340   constexpr ostream_params() {}
341 
342   template <typename... T>
ostream_paramsostream_params343   ostream_params(T... params, int new_oflag) : ostream_params(params...) {
344     oflag = new_oflag;
345   }
346 
347   template <typename... T>
ostream_paramsostream_params348   ostream_params(T... params, detail::buffer_size bs)
349       : ostream_params(params...) {
350     this->buffer_size = bs.value;
351   }
352 
353 // Intel has a bug that results in failure to deduce a constructor
354 // for empty parameter packs.
355 #  if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
ostream_paramsostream_params356   ostream_params(int new_oflag) : oflag(new_oflag) {}
ostream_paramsostream_params357   ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
358 #  endif
359 };
360 
361 }  // namespace detail
362 
363 FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size();
364 
365 /// A fast buffered output stream for writing from a single thread. Writing from
366 /// multiple threads without external synchronization may result in a data race.
367 class FMT_API ostream : private detail::buffer<char> {
368  private:
369   file file_;
370 
371   ostream(cstring_view path, const detail::ostream_params& params);
372 
373   static void grow(buffer<char>& buf, size_t);
374 
375  public:
376   ostream(ostream&& other) noexcept;
377   ~ostream();
378 
writer()379   operator writer() {
380     detail::buffer<char>& buf = *this;
381     return buf;
382   }
383 
flush()384   inline void flush() {
385     if (size() == 0) return;
386     file_.write(data(), size() * sizeof(data()[0]));
387     clear();
388   }
389 
390   template <typename... T>
391   friend auto output_file(cstring_view path, T... params) -> ostream;
392 
close()393   inline void close() {
394     flush();
395     file_.close();
396   }
397 
398   /// Formats `args` according to specifications in `fmt` and writes the
399   /// output to the file.
print(format_string<T...> fmt,T &&...args)400   template <typename... T> void print(format_string<T...> fmt, T&&... args) {
401     vformat_to(appender(*this), fmt.str, vargs<T...>{{args...}});
402   }
403 };
404 
405 /**
406  * Opens a file for writing. Supported parameters passed in `params`:
407  *
408  * - `<integer>`: Flags passed to [open](
409  *   https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html)
410  *   (`file::WRONLY | file::CREATE | file::TRUNC` by default)
411  * - `buffer_size=<integer>`: Output buffer size
412  *
413  * **Example**:
414  *
415  *     auto out = fmt::output_file("guide.txt");
416  *     out.print("Don't {}", "Panic");
417  */
418 template <typename... T>
419 inline auto output_file(cstring_view path, T... params) -> ostream {
420   return {path, detail::ostream_params(params...)};
421 }
422 #endif  // FMT_USE_FCNTL
423 
424 FMT_END_EXPORT
425 FMT_END_NAMESPACE
426 
427 #endif  // FMT_OS_H_
428