1    	/*
2    	 A C++ interface to POSIX functions.
3    	
4    	 Copyright (c) 2012 - 2016, Victor Zverovich
5    	 All rights reserved.
6    	
7    	 For the license information refer to format.h.
8    	 */
9    	
10   	#ifndef FMT_POSIX_H_
11   	#define FMT_POSIX_H_
12   	
13   	#if defined(__MINGW32__) || defined(__CYGWIN__)
14   	// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
15   	# undef __STRICT_ANSI__
16   	#endif
17   	
18   	#include <errno.h>
19   	#include <fcntl.h>   // for O_RDONLY
20   	#include <locale.h>  // for locale_t
21   	#include <stdio.h>
22   	#include <stdlib.h>  // for strtod_l
23   	
24   	#include <cstddef>
25   	
26   	#if defined __APPLE__ || defined(__FreeBSD__)
27   	# include <xlocale.h>  // for LC_NUMERIC_MASK on OS X
28   	#endif
29   	
30   	#include "format.h"
31   	
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   	
41   	// Calls to system functions are wrapped in FMT_SYSTEM for testability.
42   	#ifdef FMT_SYSTEM
43   	# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
44   	#else
45   	# define FMT_SYSTEM(call) call
46   	# ifdef _WIN32
47   	// Fix warnings about deprecated symbols.
48   	#  define FMT_POSIX_CALL(call) ::_##call
49   	# else
50   	#  define FMT_POSIX_CALL(call) ::call
51   	# endif
52   	#endif
53   	
54   	#if FMT_GCC_VERSION >= 407
55   	# define FMT_UNUSED __attribute__((unused))
56   	#else
57   	# define FMT_UNUSED
58   	#endif
59   	
60   	#ifndef FMT_USE_STATIC_ASSERT
61   	# define FMT_USE_STATIC_ASSERT 0
62   	#endif
63   	
64   	#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \
65   	  (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
66   	# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
67   	#else
68   	# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
69   	# define FMT_STATIC_ASSERT(cond, message) \
70   	  typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
71   	#endif
72   	
73   	// Retries the expression while it evaluates to error_result and errno
74   	// equals to EINTR.
75   	#ifndef _WIN32
76   	# define FMT_RETRY_VAL(result, expression, error_result) \
77   	  do { \
78   	    result = (expression); \
79   	  } while (result == error_result && errno == EINTR)
80   	#else
81   	# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
82   	#endif
83   	
84   	#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
85   	
86   	namespace fmt {
87   	
88   	// An error code.
89   	class ErrorCode {
90   	 private:
91   	  int value_;
92   	
93   	 public:
94   	  explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
95   	
96   	  int get() const FMT_NOEXCEPT { return value_; }
97   	};
98   	
99   	// A buffered file.
100  	class BufferedFile {
101  	 private:
102  	  FILE *file_;
103  	
104  	  friend class File;
105  	
106  	  explicit BufferedFile(FILE *f) : file_(f) {}
107  	
108  	 public:
109  	  // Constructs a BufferedFile object which doesn't represent any file.
110  	  BufferedFile() FMT_NOEXCEPT : file_(0) {}
111  	
112  	  // Destroys the object closing the file it represents if any.
113  	  ~BufferedFile() FMT_NOEXCEPT;
114  	
115  	#if !FMT_USE_RVALUE_REFERENCES
116  	  // Emulate a move constructor and a move assignment operator if rvalue
117  	  // references are not supported.
118  	
119  	 private:
120  	  // A proxy object to emulate a move constructor.
121  	  // It is private to make it impossible call operator Proxy directly.
122  	  struct Proxy {
123  	    FILE *file;
124  	  };
125  	
126  	public:
127  	  // A "move constructor" for moving from a temporary.
128  	  BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
129  	
130  	  // A "move constructor" for moving from an lvalue.
131  	  BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
132  	    f.file_ = 0;
133  	  }
134  	
135  	  // A "move assignment operator" for moving from a temporary.
136  	  BufferedFile &operator=(Proxy p) {
137  	    close();
138  	    file_ = p.file;
139  	    return *this;
140  	  }
141  	
142  	  // A "move assignment operator" for moving from an lvalue.
143  	  BufferedFile &operator=(BufferedFile &other) {
144  	    close();
145  	    file_ = other.file_;
146  	    other.file_ = 0;
147  	    return *this;
148  	  }
149  	
150  	  // Returns a proxy object for moving from a temporary:
151  	  //   BufferedFile file = BufferedFile(...);
152  	  operator Proxy() FMT_NOEXCEPT {
153  	    Proxy p = {file_};
154  	    file_ = 0;
155  	    return p;
156  	  }
157  	
158  	#else
159  	 private:
160  	  FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
161  	
162  	 public:
163  	  BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
164  	    other.file_ = 0;
165  	  }
166  	
167  	  BufferedFile& operator=(BufferedFile &&other) {
168  	    close();
169  	    file_ = other.file_;
170  	    other.file_ = 0;
171  	    return *this;
172  	  }
173  	#endif
174  	
175  	  // Opens a file.
176  	  BufferedFile(CStringRef filename, CStringRef mode);
177  	
178  	  // Closes the file.
179  	  void close();
180  	
181  	  // Returns the pointer to a FILE object representing this file.
182  	  FILE *get() const FMT_NOEXCEPT { return file_; }
183  	
184  	  // We place parentheses around fileno to workaround a bug in some versions
185  	  // of MinGW that define fileno as a macro.
186  	  int (fileno)() const;
187  	
188  	  void print(CStringRef format_str, const ArgList &args) {
189  	    fmt::print(file_, format_str, args);
190  	  }
191  	  FMT_VARIADIC(void, print, CStringRef)
192  	};
193  	
194  	// A file. Closed file is represented by a File object with descriptor -1.
195  	// Methods that are not declared with FMT_NOEXCEPT may throw
196  	// fmt::SystemError in case of failure. Note that some errors such as
197  	// closing the file multiple times will cause a crash on Windows rather
198  	// than an exception. You can get standard behavior by overriding the
199  	// invalid parameter handler with _set_invalid_parameter_handler.
200  	class File {
201  	 private:
202  	  int fd_;  // File descriptor.
203  	
204  	  // Constructs a File object with a given descriptor.
205  	  explicit File(int fd) : fd_(fd) {}
206  	
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  	  };
214  	
215  	  // Constructs a File object which doesn't represent any file.
216  	  File() FMT_NOEXCEPT : fd_(-1) {}
217  	
218  	  // Opens a file and constructs a File object representing this file.
219  	  File(CStringRef path, int oflag);
220  	
221  	#if !FMT_USE_RVALUE_REFERENCES
222  	  // Emulate a move constructor and a move assignment operator if rvalue
223  	  // references are not supported.
224  	
225  	 private:
226  	  // A proxy object to emulate a move constructor.
227  	  // It is private to make it impossible call operator Proxy directly.
228  	  struct Proxy {
229  	    int fd;
230  	  };
231  	
232  	 public:
233  	  // A "move constructor" for moving from a temporary.
234  	  File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
235  	
236  	  // A "move constructor" for moving from an lvalue.
237  	  File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
238  	    other.fd_ = -1;
239  	  }
240  	
241  	  // A "move assignment operator" for moving from a temporary.
242  	  File &operator=(Proxy p) {
243  	    close();
244  	    fd_ = p.fd;
245  	    return *this;
246  	  }
247  	
248  	  // A "move assignment operator" for moving from an lvalue.
249  	  File &operator=(File &other) {
250  	    close();
251  	    fd_ = other.fd_;
252  	    other.fd_ = -1;
253  	    return *this;
254  	  }
255  	
256  	  // Returns a proxy object for moving from a temporary:
257  	  //   File file = File(...);
258  	  operator Proxy() FMT_NOEXCEPT {
259  	    Proxy p = {fd_};
260  	    fd_ = -1;
261  	    return p;
262  	  }
263  	
264  	#else
265  	 private:
266  	  FMT_DISALLOW_COPY_AND_ASSIGN(File);
267  	
268  	 public:
269  	  File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
270  	    other.fd_ = -1;
271  	  }
272  	
273  	  File& operator=(File &&other) {
274  	    close();
(1) Event self_assign: No protection against the object assigning to itself.
275  	    fd_ = other.fd_;
276  	    other.fd_ = -1;
277  	    return *this;
278  	  }
279  	#endif
280  	
281  	  // Destroys the object closing the file it represents if any.
282  	  ~File() FMT_NOEXCEPT;
283  	
284  	  // Returns the file descriptor.
285  	  int descriptor() const FMT_NOEXCEPT { return fd_; }
286  	
287  	  // Closes the file.
288  	  void close();
289  	
290  	  // Returns the file size. The size has signed type for consistency with
291  	  // stat::st_size.
292  	  LongLong size() const;
293  	
294  	  // Attempts to read count bytes from the file into the specified buffer.
295  	  std::size_t read(void *buffer, std::size_t count);
296  	
297  	  // Attempts to write count bytes from the specified buffer to the file.
298  	  std::size_t write(const void *buffer, std::size_t count);
299  	
300  	  // Duplicates a file descriptor with the dup function and returns
301  	  // the duplicate as a file object.
302  	  static File dup(int fd);
303  	
304  	  // Makes fd be the copy of this file descriptor, closing fd first if
305  	  // necessary.
306  	  void dup2(int fd);
307  	
308  	  // Makes fd be the copy of this file descriptor, closing fd first if
309  	  // necessary.
310  	  void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
311  	
312  	  // Creates a pipe setting up read_end and write_end file objects for reading
313  	  // and writing respectively.
314  	  static void pipe(File &read_end, File &write_end);
315  	
316  	  // Creates a BufferedFile object associated with this file and detaches
317  	  // this File object from the file.
318  	  BufferedFile fdopen(const char *mode);
319  	};
320  	
321  	// Returns the memory page size.
322  	long getpagesize();
323  	
324  	#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
325  	    !defined(__ANDROID__) && !defined(__CYGWIN__)
326  	# define FMT_LOCALE
327  	#endif
328  	
329  	#ifdef FMT_LOCALE
330  	// A "C" numeric locale.
331  	class Locale {
332  	 private:
333  	# ifdef _MSC_VER
334  	  typedef _locale_t locale_t;
335  	
336  	  enum { LC_NUMERIC_MASK = LC_NUMERIC };
337  	
338  	  static locale_t newlocale(int category_mask, const char *locale, locale_t) {
339  	    return _create_locale(category_mask, locale);
340  	  }
341  	
342  	  static void freelocale(locale_t locale) {
343  	    _free_locale(locale);
344  	  }
345  	
346  	  static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
347  	    return _strtod_l(nptr, endptr, locale);
348  	  }
349  	# endif
350  	
351  	  locale_t locale_;
352  	
353  	  FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
354  	
355  	 public:
356  	  typedef locale_t Type;
357  	
358  	  Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) {
359  	    if (!locale_)
360  	      FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
361  	  }
362  	  ~Locale() { freelocale(locale_); }
363  	
364  	  Type get() const { return locale_; }
365  	
366  	  // Converts string to floating-point number and advances str past the end
367  	  // of the parsed input.
368  	  double strtod(const char *&str) const {
369  	    char *end = 0;
370  	    double result = strtod_l(str, &end, locale_);
371  	    str = end;
372  	    return result;
373  	  }
374  	};
375  	#endif  // FMT_LOCALE
376  	}  // namespace fmt
377  	
378  	#if !FMT_USE_RVALUE_REFERENCES
379  	namespace std {
380  	// For compatibility with C++98.
381  	inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
382  	inline fmt::File &move(fmt::File &f) { return f; }
383  	}
384  	#endif
385  	
386  	#endif  // FMT_POSIX_H_
387