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 <errno.h>
17 #include <fcntl.h> // for O_RDONLY
18 #include <locale.h> // for locale_t
19 #include <stdio.h>
20 #include <stdlib.h> // for strtod_l
21
22 #include <cstddef>
23
24 #if defined __APPLE__ || defined(__FreeBSD__)
25 #include <xlocale.h> // for LC_NUMERIC_MASK on OS X
26 #endif
27
28 #include "format.h"
29
30 #ifndef FMT_POSIX
31 #if defined(_WIN32) && !defined(__MINGW32__)
32 // Fix warnings about deprecated symbols.
33 #define FMT_POSIX(call) _##call
34 #else
35 #define FMT_POSIX(call) call
36 #endif
37 #endif
38
39 // Calls to system functions are wrapped in FMT_SYSTEM for testability.
40 #ifdef FMT_SYSTEM
41 #define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
42 #else
43 #define FMT_SYSTEM(call) call
44 #ifdef _WIN32
45 // Fix warnings about deprecated symbols.
46 #define FMT_POSIX_CALL(call) ::_##call
47 #else
48 #define FMT_POSIX_CALL(call) ::call
49 #endif
50 #endif
51
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 { \
58 result = (expression); \
59 } while (result == error_result && errno == EINTR)
60 #else
61 #define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
62 #endif
63
64 #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
65
66 FMT_BEGIN_NAMESPACE
67
68 /**
69 \rst
70 A reference to a null-terminated string. It can be constructed from a C
71 string or ``std::string``.
72
73 You can use one of the following typedefs for common character types:
74
75 +---------------+-----------------------------+
76 | Type | Definition |
77 +===============+=============================+
78 | cstring_view | basic_cstring_view<char> |
79 +---------------+-----------------------------+
80 | wcstring_view | basic_cstring_view<wchar_t> |
81 +---------------+-----------------------------+
82
83 This class is most useful as a parameter type to allow passing
84 different types of strings to a function, for example::
85
86 template <typename... Args>
87 std::string format(cstring_view format_str, const Args & ... args);
88
89 format("{}", 42);
90 format(std::string("{}"), 42);
91 \endrst
92 */
93 template<typename Char>
94 class basic_cstring_view
95 {
96 private:
97 const Char *data_;
98
99 public:
100 /** Constructs a string reference object from a C string. */
basic_cstring_view(const Char *s)101 basic_cstring_view(const Char *s)
102 : data_(s)
103 {
104 }
105
106 /**
107 \rst
108 Constructs a string reference from an ``std::string`` object.
109 \endrst
110 */
basic_cstring_view(const std::basic_string<Char> &s)111 basic_cstring_view(const std::basic_string<Char> &s)
112 : data_(s.c_str())
113 {
114 }
115
116 /** Returns the pointer to a C string. */
c_str() const117 const Char *c_str() const
118 {
119 return data_;
120 }
121 };
122
123 typedef basic_cstring_view<char> cstring_view;
124 typedef basic_cstring_view<wchar_t> wcstring_view;
125
126 // An error code.
127 class error_code
128 {
129 private:
130 int value_;
131
132 public:
value_(value)133 explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
134
135 int get() const FMT_NOEXCEPT
136 {
137 return value_;
138 }
139 };
140
141 // A buffered file.
142 class buffered_file
143 {
144 private:
145 FILE *file_;
146
147 friend class file;
148
buffered_file(FILE *f)149 explicit buffered_file(FILE *f)
150 : file_(f)
151 {
152 }
153
154 public:
155 // Constructs a buffered_file object which doesn't represent any file.
file_(FMT_NULL)156 buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
157
158 // Destroys the object closing the file it represents if any.
159 FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT;
160
161 #if !FMT_USE_RVALUE_REFERENCES
162 // Emulate a move constructor and a move assignment operator if rvalue
163 // references are not supported.
164
165 private:
166 // A proxy object to emulate a move constructor.
167 // It is private to make it impossible call operator Proxy directly.
168 struct Proxy
169 {
170 FILE *file;
171 };
172
173 public:
174 // A "move constructor" for moving from a temporary.
file_(p.file)175 buffered_file(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
176
177 // A "move constructor" for moving from an lvalue.
file_(f.file_)178 buffered_file(buffered_file &f) FMT_NOEXCEPT : file_(f.file_)
179 {
180 f.file_ = FMT_NULL;
181 }
182
183 // A "move assignment operator" for moving from a temporary.
operator =(Proxy p)184 buffered_file &operator=(Proxy p)
185 {
186 close();
187 file_ = p.file;
188 return *this;
189 }
190
191 // A "move assignment operator" for moving from an lvalue.
operator =(buffered_file &other)192 buffered_file &operator=(buffered_file &other)
193 {
194 close();
195 file_ = other.file_;
196 other.file_ = FMT_NULL;
197 return *this;
198 }
199
200 // Returns a proxy object for moving from a temporary:
201 // buffered_file file = buffered_file(...);
202 operator Proxy() FMT_NOEXCEPT
203 {
204 Proxy p = {file_};
205 file_ = FMT_NULL;
206 return p;
207 }
208
209 #else
210 private:
211 FMT_DISALLOW_COPY_AND_ASSIGN(buffered_file);
212
213 public:
file_(other.file_)214 buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_)
215 {
216 other.file_ = FMT_NULL;
217 }
218
operator =(buffered_file &&other)219 buffered_file &operator=(buffered_file &&other)
220 {
221 close();
222 file_ = other.file_;
223 other.file_ = FMT_NULL;
224 return *this;
225 }
226 #endif
227
228 // Opens a file.
229 FMT_API buffered_file(cstring_view filename, cstring_view mode);
230
231 // Closes the file.
232 FMT_API void close();
233
234 // Returns the pointer to a FILE object representing this file.
235 FILE *get() const FMT_NOEXCEPT
236 {
237 return file_;
238 }
239
240 // We place parentheses around fileno to workaround a bug in some versions
241 // of MinGW that define fileno as a macro.
242 FMT_API int(fileno)() const;
243
vprint(string_view format_str, format_args args)244 void vprint(string_view format_str, format_args args)
245 {
246 fmt::vprint(file_, format_str, args);
247 }
248
249 template<typename... Args>
print(string_view format_str, const Args &... args)250 inline void print(string_view format_str, const Args &... args)
251 {
252 vprint(format_str, make_format_args(args...));
253 }
254 };
255
256 // A file. Closed file is represented by a file object with descriptor -1.
257 // Methods that are not declared with FMT_NOEXCEPT may throw
258 // fmt::system_error in case of failure. Note that some errors such as
259 // closing the file multiple times will cause a crash on Windows rather
260 // than an exception. You can get standard behavior by overriding the
261 // invalid parameter handler with _set_invalid_parameter_handler.
262 class file
263 {
264 private:
265 int fd_; // File descriptor.
266
267 // Constructs a file object with a given descriptor.
file(int fd)268 explicit file(int fd)
269 : fd_(fd)
270 {
271 }
272
273 public:
274 // Possible values for the oflag argument to the constructor.
275 enum
276 {
277 RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
278 WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
279 RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
280 };
281
282 // Constructs a file object which doesn't represent any file.
283 file() FMT_NOEXCEPT : fd_(-1) {}
284
285 // Opens a file and constructs a file object representing this file.
286 FMT_API file(cstring_view path, int oflag);
287
288 #if !FMT_USE_RVALUE_REFERENCES
289 // Emulate a move constructor and a move assignment operator if rvalue
290 // references are not supported.
291
292 private:
293 // A proxy object to emulate a move constructor.
294 // It is private to make it impossible call operator Proxy directly.
295 struct Proxy
296 {
297 int fd;
298 };
299
300 public:
301 // A "move constructor" for moving from a temporary.
fd_(p.fd)302 file(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
303
304 // A "move constructor" for moving from an lvalue.
fd_(other.fd_)305 file(file &other) FMT_NOEXCEPT : fd_(other.fd_)
306 {
307 other.fd_ = -1;
308 }
309
310 // A "move assignment operator" for moving from a temporary.
operator =(Proxy p)311 file &operator=(Proxy p)
312 {
313 close();
314 fd_ = p.fd;
315 return *this;
316 }
317
318 // A "move assignment operator" for moving from an lvalue.
operator =(file &other)319 file &operator=(file &other)
320 {
321 close();
322 fd_ = other.fd_;
323 other.fd_ = -1;
324 return *this;
325 }
326
327 // Returns a proxy object for moving from a temporary:
328 // file f = file(...);
329 operator Proxy() FMT_NOEXCEPT
330 {
331 Proxy p = {fd_};
332 fd_ = -1;
333 return p;
334 }
335
336 #else
337 private:
338 FMT_DISALLOW_COPY_AND_ASSIGN(file);
339
340 public:
fd_(other.fd_)341 file(file &&other) FMT_NOEXCEPT : fd_(other.fd_)
342 {
343 other.fd_ = -1;
344 }
345
operator =(file &&other)346 file &operator=(file &&other)
347 {
348 close();
349 fd_ = other.fd_;
350 other.fd_ = -1;
351 return *this;
352 }
353 #endif
354
355 // Destroys the object closing the file it represents if any.
356 FMT_API ~file() FMT_DTOR_NOEXCEPT;
357
358 // Returns the file descriptor.
359 int descriptor() const FMT_NOEXCEPT
360 {
361 return fd_;
362 }
363
364 // Closes the file.
365 FMT_API void close();
366
367 // Returns the file size. The size has signed type for consistency with
368 // stat::st_size.
369 FMT_API long long size() const;
370
371 // Attempts to read count bytes from the file into the specified buffer.
372 FMT_API std::size_t read(void *buffer, std::size_t count);
373
374 // Attempts to write count bytes from the specified buffer to the file.
375 FMT_API std::size_t write(const void *buffer, std::size_t count);
376
377 // Duplicates a file descriptor with the dup function and returns
378 // the duplicate as a file object.
379 FMT_API static file dup(int fd);
380
381 // Makes fd be the copy of this file descriptor, closing fd first if
382 // necessary.
383 FMT_API void dup2(int fd);
384
385 // Makes fd be the copy of this file descriptor, closing fd first if
386 // necessary.
387 FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;
388
389 // Creates a pipe setting up read_end and write_end file objects for reading
390 // and writing respectively.
391 FMT_API static void pipe(file &read_end, file &write_end);
392
393 // Creates a buffered_file object associated with this file and detaches
394 // this file object from the file.
395 FMT_API buffered_file fdopen(const char *mode);
396 };
397
398 // Returns the memory page size.
399 long getpagesize();
400
401 #if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__)
402 #define FMT_LOCALE
403 #endif
404
405 #ifdef FMT_LOCALE
406 // A "C" numeric locale.
407 class Locale
408 {
409 private:
410 #ifdef _MSC_VER
411 typedef _locale_t locale_t;
412
413 enum
414 {
415 LC_NUMERIC_MASK = LC_NUMERIC
416 };
417
newlocale(int category_mask, const char *locale, locale_t)418 static locale_t newlocale(int category_mask, const char *locale, locale_t)
419 {
420 return _create_locale(category_mask, locale);
421 }
422
freelocale(locale_t locale)423 static void freelocale(locale_t locale)
424 {
425 _free_locale(locale);
426 }
427
strtod_l(const char *nptr, char **endptr, _locale_t locale)428 static double strtod_l(const char *nptr, char **endptr, _locale_t locale)
429 {
430 return _strtod_l(nptr, endptr, locale);
431 }
432 #endif
433
434 locale_t locale_;
435
436 FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
437
438 public:
439 typedef locale_t Type;
440
Locale()441 Locale()
442 : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL))
443 {
444 if (!locale_)
445 FMT_THROW(system_error(errno, "cannot create locale"));
446 }
~Locale()447 ~Locale()
448 {
449 freelocale(locale_);
450 }
451
get() const452 Type get() const
453 {
454 return locale_;
455 }
456
457 // Converts string to floating-point number and advances str past the end
458 // of the parsed input.
strtod(const char *&str) const459 double strtod(const char *&str) const
460 {
461 char *end = FMT_NULL;
462 double result = strtod_l(str, &end, locale_);
463 str = end;
464 return result;
465 }
466 };
467 #endif // FMT_LOCALE
468 FMT_END_NAMESPACE
469
470 #if !FMT_USE_RVALUE_REFERENCES
471 namespace std {
472 // For compatibility with C++98.
move(fmt::buffered_file &f)473 inline fmt::buffered_file &move(fmt::buffered_file &f)
474 {
475 return f;
476 }
move(fmt::file &f)477 inline fmt::file &move(fmt::file &f)
478 {
479 return f;
480 }
481 } // namespace std
482 #endif
483
484 #endif // FMT_POSIX_H_
485