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 #if defined(__MINGW32__) || defined(__CYGWIN__)
12 // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
13 #  undef __STRICT_ANSI__
14 #endif
15 
16 #include <cerrno>
17 #include <clocale>  // for locale_t
18 #include <cstddef>
19 #include <cstdio>
20 #include <cstdlib>  // for strtod_l
21 
22 #if defined __APPLE__ || defined(__FreeBSD__)
23 #  include <xlocale.h>  // for LC_NUMERIC_MASK on OS X
24 #endif
25 
26 #include "format.h"
27 
28 // UWP doesn't provide _pipe.
29 #if FMT_HAS_INCLUDE("winapifamily.h")
30 #  include <winapifamily.h>
31 #endif
32 #if FMT_HAS_INCLUDE("fcntl.h") && \
33     (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
34 #  include <fcntl.h>  // for O_RDONLY
35 #  define FMT_USE_FCNTL 1
36 #else
37 #  define FMT_USE_FCNTL 0
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_POSIX_CALL(call) FMT_SYSTEM(call)
52 #else
53 #  define FMT_SYSTEM(call) call
54 #  ifdef _WIN32
55 // Fix warnings about deprecated symbols.
56 #    define FMT_POSIX_CALL(call) ::_##call
57 #  else
58 #    define FMT_POSIX_CALL(call) ::call
59 #  endif
60 #endif
61 
62 // Retries the expression while it evaluates to error_result and errno
63 // equals to EINTR.
64 #ifndef _WIN32
65 #  define FMT_RETRY_VAL(result, expression, error_result) \
66     do {                                                  \
67       (result) = (expression);                            \
68     } while ((result) == (error_result) && errno == EINTR)
69 #else
70 #  define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
71 #endif
72 
73 #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
74 
75 FMT_BEGIN_NAMESPACE
76 
77 /**
78   \rst
79   A reference to a null-terminated string. It can be constructed from a C
80   string or ``std::string``.
81 
82   You can use one of the following type aliases for common character types:
83 
84   +---------------+-----------------------------+
85   | Type          | Definition                  |
86   +===============+=============================+
87   | cstring_view  | basic_cstring_view<char>    |
88   +---------------+-----------------------------+
89   | wcstring_view | basic_cstring_view<wchar_t> |
90   +---------------+-----------------------------+
91 
92   This class is most useful as a parameter type to allow passing
93   different types of strings to a function, for example::
94 
95     template <typename... Args>
96     std::string format(cstring_view format_str, const Args & ... args);
97 
98     format("{}", 42);
99     format(std::string("{}"), 42);
100   \endrst
101  */
102 template <typename Char> class basic_cstring_view {
103  private:
104   const Char* data_;
105 
106  public:
107   /** Constructs a string reference object from a C string. */
basic_cstring_view(const Char * s)108   basic_cstring_view(const Char* s) : data_(s) {}
109 
110   /**
111     \rst
112     Constructs a string reference from an ``std::string`` object.
113     \endrst
114    */
basic_cstring_view(const std::basic_string<Char> & s)115   basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
116 
117   /** Returns the pointer to a C string. */
c_str()118   const Char* c_str() const { return data_; }
119 };
120 
121 using cstring_view = basic_cstring_view<char>;
122 using wcstring_view = basic_cstring_view<wchar_t>;
123 
124 // An error code.
125 class error_code {
126  private:
127   int value_;
128 
129  public:
value_(value)130   explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
131 
get()132   int get() const FMT_NOEXCEPT { return value_; }
133 };
134 
135 #ifdef _WIN32
136 namespace internal {
137 // A converter from UTF-16 to UTF-8.
138 // It is only provided for Windows since other systems support UTF-8 natively.
139 class utf16_to_utf8 {
140  private:
141   memory_buffer buffer_;
142 
143  public:
utf16_to_utf8()144   utf16_to_utf8() {}
145   FMT_API explicit utf16_to_utf8(wstring_view s);
string_view()146   operator string_view() const { return string_view(&buffer_[0], size()); }
size()147   size_t size() const { return buffer_.size() - 1; }
c_str()148   const char* c_str() const { return &buffer_[0]; }
str()149   std::string str() const { return std::string(&buffer_[0], size()); }
150 
151   // Performs conversion returning a system error code instead of
152   // throwing exception on conversion error. This method may still throw
153   // in case of memory allocation error.
154   FMT_API int convert(wstring_view s);
155 };
156 
157 FMT_API void format_windows_error(buffer<char>& out, int error_code,
158                                   string_view message) FMT_NOEXCEPT;
159 }  // namespace internal
160 
161 /** A Windows error. */
162 class windows_error : public system_error {
163  private:
164   FMT_API void init(int error_code, string_view format_str, format_args args);
165 
166  public:
167   /**
168    \rst
169    Constructs a :class:`fmt::windows_error` object with the description
170    of the form
171 
172    .. parsed-literal::
173      *<message>*: *<system-message>*
174 
175    where *<message>* is the formatted message and *<system-message>* is the
176    system message corresponding to the error code.
177    *error_code* is a Windows error code as given by ``GetLastError``.
178    If *error_code* is not a valid error code such as -1, the system message
179    will look like "error -1".
180 
181    **Example**::
182 
183      // This throws a windows_error with the description
184      //   cannot open file 'madeup': The system cannot find the file specified.
185      // or similar (system message may vary).
186      const char *filename = "madeup";
187      LPOFSTRUCT of = LPOFSTRUCT();
188      HFILE file = OpenFile(filename, &of, OF_READ);
189      if (file == HFILE_ERROR) {
190        throw fmt::windows_error(GetLastError(),
191                                 "cannot open file '{}'", filename);
192      }
193    \endrst
194   */
195   template <typename... Args>
windows_error(int error_code,string_view message,const Args &...args)196   windows_error(int error_code, string_view message, const Args&... args) {
197     init(error_code, message, make_format_args(args...));
198   }
199 };
200 
201 // Reports a Windows error without throwing an exception.
202 // Can be used to report errors from destructors.
203 FMT_API void report_windows_error(int error_code,
204                                   string_view message) FMT_NOEXCEPT;
205 #endif  // _WIN32
206 
207 // A buffered file.
208 class buffered_file {
209  private:
210   FILE* file_;
211 
212   friend class file;
213 
buffered_file(FILE * f)214   explicit buffered_file(FILE* f) : file_(f) {}
215 
216  public:
217   buffered_file(const buffered_file&) = delete;
218   void operator=(const buffered_file&) = delete;
219 
220   // Constructs a buffered_file object which doesn't represent any file.
buffered_file()221   buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
222 
223   // Destroys the object closing the file it represents if any.
224   FMT_API ~buffered_file() FMT_NOEXCEPT;
225 
226  public:
buffered_file(buffered_file && other)227   buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
228     other.file_ = nullptr;
229   }
230 
231   buffered_file& operator=(buffered_file&& other) {
232     close();
233     file_ = other.file_;
234     other.file_ = nullptr;
235     return *this;
236   }
237 
238   // Opens a file.
239   FMT_API buffered_file(cstring_view filename, cstring_view mode);
240 
241   // Closes the file.
242   FMT_API void close();
243 
244   // Returns the pointer to a FILE object representing this file.
get()245   FILE* get() const FMT_NOEXCEPT { return file_; }
246 
247   // We place parentheses around fileno to workaround a bug in some versions
248   // of MinGW that define fileno as a macro.
249   FMT_API int(fileno)() const;
250 
vprint(string_view format_str,format_args args)251   void vprint(string_view format_str, format_args args) {
252     fmt::vprint(file_, format_str, args);
253   }
254 
255   template <typename... Args>
print(string_view format_str,const Args &...args)256   inline void print(string_view format_str, const Args&... args) {
257     vprint(format_str, make_format_args(args...));
258   }
259 };
260 
261 #if FMT_USE_FCNTL
262 // A file. Closed file is represented by a file object with descriptor -1.
263 // Methods that are not declared with FMT_NOEXCEPT may throw
264 // fmt::system_error in case of failure. Note that some errors such as
265 // closing the file multiple times will cause a crash on Windows rather
266 // than an exception. You can get standard behavior by overriding the
267 // invalid parameter handler with _set_invalid_parameter_handler.
268 class file {
269  private:
270   int fd_;  // File descriptor.
271 
272   // Constructs a file object with a given descriptor.
file(int fd)273   explicit file(int fd) : fd_(fd) {}
274 
275  public:
276   // Possible values for the oflag argument to the constructor.
277   enum {
278     RDONLY = FMT_POSIX(O_RDONLY),  // Open for reading only.
279     WRONLY = FMT_POSIX(O_WRONLY),  // Open for writing only.
280     RDWR = FMT_POSIX(O_RDWR)       // Open for reading and writing.
281   };
282 
283   // Constructs a file object which doesn't represent any file.
file()284   file() FMT_NOEXCEPT : fd_(-1) {}
285 
286   // Opens a file and constructs a file object representing this file.
287   FMT_API file(cstring_view path, int oflag);
288 
289  public:
290   file(const file&) = delete;
291   void operator=(const file&) = delete;
292 
file(file && other)293   file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
294 
295   file& operator=(file&& other) FMT_NOEXCEPT {
296     close();
297     fd_ = other.fd_;
298     other.fd_ = -1;
299     return *this;
300   }
301 
302   // Destroys the object closing the file it represents if any.
303   FMT_API ~file() FMT_NOEXCEPT;
304 
305   // Returns the file descriptor.
descriptor()306   int descriptor() const FMT_NOEXCEPT { return fd_; }
307 
308   // Closes the file.
309   FMT_API void close();
310 
311   // Returns the file size. The size has signed type for consistency with
312   // stat::st_size.
313   FMT_API long long size() const;
314 
315   // Attempts to read count bytes from the file into the specified buffer.
316   FMT_API std::size_t read(void* buffer, std::size_t count);
317 
318   // Attempts to write count bytes from the specified buffer to the file.
319   FMT_API std::size_t write(const void* buffer, std::size_t count);
320 
321   // Duplicates a file descriptor with the dup function and returns
322   // the duplicate as a file object.
323   FMT_API static file dup(int fd);
324 
325   // Makes fd be the copy of this file descriptor, closing fd first if
326   // necessary.
327   FMT_API void dup2(int fd);
328 
329   // Makes fd be the copy of this file descriptor, closing fd first if
330   // necessary.
331   FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT;
332 
333   // Creates a pipe setting up read_end and write_end file objects for reading
334   // and writing respectively.
335   FMT_API static void pipe(file& read_end, file& write_end);
336 
337   // Creates a buffered_file object associated with this file and detaches
338   // this file object from the file.
339   FMT_API buffered_file fdopen(const char* mode);
340 };
341 
342 // Returns the memory page size.
343 long getpagesize();
344 #endif  // FMT_USE_FCNTL
345 
346 #ifdef FMT_LOCALE
347 // A "C" numeric locale.
348 class locale {
349  private:
350 #  ifdef _WIN32
351   using locale_t = _locale_t;
352 
freelocale(locale_t loc)353   static void freelocale(locale_t loc) { _free_locale(loc); }
354 
strtod_l(const char * nptr,char ** endptr,_locale_t loc)355   static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
356     return _strtod_l(nptr, endptr, loc);
357   }
358 #  endif
359 
360   locale_t locale_;
361 
362  public:
363   using type = locale_t;
364   locale(const locale&) = delete;
365   void operator=(const locale&) = delete;
366 
locale()367   locale() {
368 #  ifndef _WIN32
369     locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
370 #  else
371     locale_ = _create_locale(LC_NUMERIC, "C");
372 #  endif
373     if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
374   }
~locale()375   ~locale() { freelocale(locale_); }
376 
get()377   type get() const { return locale_; }
378 
379   // Converts string to floating-point number and advances str past the end
380   // of the parsed input.
strtod(const char * & str)381   double strtod(const char*& str) const {
382     char* end = nullptr;
383     double result = strtod_l(str, &end, locale_);
384     str = end;
385     return result;
386   }
387 };
388 using Locale FMT_DEPRECATED_ALIAS = locale;
389 #endif  // FMT_LOCALE
390 FMT_END_NAMESPACE
391 
392 #endif  // FMT_OS_H_
393