• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // A C++ interface to POSIX functions.
2 //
3 // Copyright (c) 2012 - 2016, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMT_POSIX_H_
9 #define FMT_POSIX_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 <cstdio>
19 #include <cstdlib>  // for strtod_l
20 
21 #include <cstddef>
22 
23 #if defined __APPLE__ || defined(__FreeBSD__)
24 #  include <xlocale.h>  // for LC_NUMERIC_MASK on OS X
25 #endif
26 
27 #include "format.h"
28 
29 // UWP doesn't provide _pipe.
30 #if FMT_HAS_INCLUDE("winapifamily.h")
31 #  include <winapifamily.h>
32 #endif
33 #if FMT_HAS_INCLUDE("fcntl.h") && \
34     (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
35 #  include <fcntl.h>  // for O_RDONLY
36 #  define FMT_USE_FCNTL 1
37 #else
38 #  define FMT_USE_FCNTL 0
39 #endif
40 
41 #ifndef FMT_POSIX
42 #  if defined(_WIN32) && !defined(__MINGW32__)
43 // Fix warnings about deprecated symbols.
44 #    define FMT_POSIX(call) _##call
45 #  else
46 #    define FMT_POSIX(call) call
47 #  endif
48 #endif
49 
50 // Calls to system functions are wrapped in FMT_SYSTEM for testability.
51 #ifdef FMT_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 
78 /**
79   \rst
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 to allow passing
94   different types of strings to a function, for example::
95 
96     template <typename... Args>
97     std::string format(cstring_view format_str, const Args & ... args);
98 
99     format("{}", 42);
100     format(std::string("{}"), 42);
101   \endrst
102  */
103 template <typename Char> class basic_cstring_view {
104  private:
105   const Char* data_;
106 
107  public:
108   /** Constructs a string reference object from a C string. */
basic_cstring_view(const Char * s)109   basic_cstring_view(const Char* s) : data_(s) {}
110 
111   /**
112     \rst
113     Constructs a string reference from an ``std::string`` object.
114     \endrst
115    */
basic_cstring_view(const std::basic_string<Char> & s)116   basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
117 
118   /** Returns the pointer to a C string. */
c_str()119   const Char* c_str() const { return data_; }
120 };
121 
122 using cstring_view = basic_cstring_view<char>;
123 using wcstring_view = basic_cstring_view<wchar_t>;
124 
125 // An error code.
126 class error_code {
127  private:
128   int value_;
129 
130  public:
value_(value)131   explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
132 
get()133   int get() const FMT_NOEXCEPT { return value_; }
134 };
135 
136 // A buffered file.
137 class buffered_file {
138  private:
139   FILE* file_;
140 
141   friend class file;
142 
buffered_file(FILE * f)143   explicit buffered_file(FILE* f) : file_(f) {}
144 
145  public:
146   buffered_file(const buffered_file&) = delete;
147   void operator=(const buffered_file&) = delete;
148 
149   // Constructs a buffered_file object which doesn't represent any file.
buffered_file()150   buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
151 
152   // Destroys the object closing the file it represents if any.
153   FMT_API ~buffered_file() FMT_NOEXCEPT;
154 
155  public:
buffered_file(buffered_file && other)156   buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
157     other.file_ = nullptr;
158   }
159 
160   buffered_file& operator=(buffered_file&& other) {
161     close();
162     file_ = other.file_;
163     other.file_ = nullptr;
164     return *this;
165   }
166 
167   // Opens a file.
168   FMT_API buffered_file(cstring_view filename, cstring_view mode);
169 
170   // Closes the file.
171   FMT_API void close();
172 
173   // Returns the pointer to a FILE object representing this file.
get()174   FILE* get() const FMT_NOEXCEPT { return file_; }
175 
176   // We place parentheses around fileno to workaround a bug in some versions
177   // of MinGW that define fileno as a macro.
178   FMT_API int(fileno)() const;
179 
vprint(string_view format_str,format_args args)180   void vprint(string_view format_str, format_args args) {
181     fmt::vprint(file_, format_str, args);
182   }
183 
184   template <typename... Args>
print(string_view format_str,const Args &...args)185   inline void print(string_view format_str, const Args&... args) {
186     vprint(format_str, make_format_args(args...));
187   }
188 };
189 
190 #if FMT_USE_FCNTL
191 // A file. Closed file is represented by a file object with descriptor -1.
192 // Methods that are not declared with FMT_NOEXCEPT may throw
193 // fmt::system_error in case of failure. Note that some errors such as
194 // closing the file multiple times will cause a crash on Windows rather
195 // than an exception. You can get standard behavior by overriding the
196 // invalid parameter handler with _set_invalid_parameter_handler.
197 class file {
198  private:
199   int fd_;  // File descriptor.
200 
201   // Constructs a file object with a given descriptor.
file(int fd)202   explicit file(int fd) : fd_(fd) {}
203 
204  public:
205   // Possible values for the oflag argument to the constructor.
206   enum {
207     RDONLY = FMT_POSIX(O_RDONLY),  // Open for reading only.
208     WRONLY = FMT_POSIX(O_WRONLY),  // Open for writing only.
209     RDWR = FMT_POSIX(O_RDWR)       // Open for reading and writing.
210   };
211 
212   // Constructs a file object which doesn't represent any file.
file()213   file() FMT_NOEXCEPT : fd_(-1) {}
214 
215   // Opens a file and constructs a file object representing this file.
216   FMT_API file(cstring_view path, int oflag);
217 
218  public:
219   file(const file&) = delete;
220   void operator=(const file&) = delete;
221 
file(file && other)222   file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
223 
224   file& operator=(file&& other) FMT_NOEXCEPT {
225     close();
226     fd_ = other.fd_;
227     other.fd_ = -1;
228     return *this;
229   }
230 
231   // Destroys the object closing the file it represents if any.
232   FMT_API ~file() FMT_NOEXCEPT;
233 
234   // Returns the file descriptor.
descriptor()235   int descriptor() const FMT_NOEXCEPT { return fd_; }
236 
237   // Closes the file.
238   FMT_API void close();
239 
240   // Returns the file size. The size has signed type for consistency with
241   // stat::st_size.
242   FMT_API long long size() const;
243 
244   // Attempts to read count bytes from the file into the specified buffer.
245   FMT_API std::size_t read(void* buffer, std::size_t count);
246 
247   // Attempts to write count bytes from the specified buffer to the file.
248   FMT_API std::size_t write(const void* buffer, std::size_t count);
249 
250   // Duplicates a file descriptor with the dup function and returns
251   // the duplicate as a file object.
252   FMT_API static file dup(int fd);
253 
254   // Makes fd be the copy of this file descriptor, closing fd first if
255   // necessary.
256   FMT_API void dup2(int fd);
257 
258   // Makes fd be the copy of this file descriptor, closing fd first if
259   // necessary.
260   FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT;
261 
262   // Creates a pipe setting up read_end and write_end file objects for reading
263   // and writing respectively.
264   FMT_API static void pipe(file& read_end, file& write_end);
265 
266   // Creates a buffered_file object associated with this file and detaches
267   // this file object from the file.
268   FMT_API buffered_file fdopen(const char* mode);
269 };
270 
271 // Returns the memory page size.
272 long getpagesize();
273 #endif  // FMT_USE_FCNTL
274 
275 #ifdef FMT_LOCALE
276 // A "C" numeric locale.
277 class Locale {
278  private:
279 #  ifdef _WIN32
280   using locale_t = _locale_t;
281 
282   enum { LC_NUMERIC_MASK = LC_NUMERIC };
283 
newlocale(int category_mask,const char * locale,locale_t)284   static locale_t newlocale(int category_mask, const char* locale, locale_t) {
285     return _create_locale(category_mask, locale);
286   }
287 
freelocale(locale_t locale)288   static void freelocale(locale_t locale) { _free_locale(locale); }
289 
strtod_l(const char * nptr,char ** endptr,_locale_t locale)290   static double strtod_l(const char* nptr, char** endptr, _locale_t locale) {
291     return _strtod_l(nptr, endptr, locale);
292   }
293 #  endif
294 
295   locale_t locale_;
296 
297  public:
298   using type = locale_t;
299   Locale(const Locale&) = delete;
300   void operator=(const Locale&) = delete;
301 
Locale()302   Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) {
303     if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
304   }
~Locale()305   ~Locale() { freelocale(locale_); }
306 
get()307   type get() const { return locale_; }
308 
309   // Converts string to floating-point number and advances str past the end
310   // of the parsed input.
strtod(const char * & str)311   double strtod(const char*& str) const {
312     char* end = nullptr;
313     double result = strtod_l(str, &end, locale_);
314     str = end;
315     return result;
316   }
317 };
318 #endif  // FMT_LOCALE
319 FMT_END_NAMESPACE
320 
321 #endif  // FMT_POSIX_H_
322