os.h 13 KB

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