You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

455 lines
13 KiB

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