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.

478 lines
14 KiB

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