Home | History | Annotate | Download | only in fmt
      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 // Retries the expression while it evaluates to error_result and errno
     55 // equals to EINTR.
     56 #ifndef _WIN32
     57 # define FMT_RETRY_VAL(result, expression, error_result) \
     58   do { \
     59     result = (expression); \
     60   } while (result == error_result && errno == EINTR)
     61 #else
     62 # define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
     63 #endif
     64 
     65 #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
     66 
     67 namespace fmt {
     68 
     69 // An error code.
     70 class ErrorCode {
     71  private:
     72   int value_;
     73 
     74  public:
     75   explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
     76 
     77   int get() const FMT_NOEXCEPT { return value_; }
     78 };
     79 
     80 // A buffered file.
     81 class BufferedFile {
     82  private:
     83   FILE *file_;
     84 
     85   friend class File;
     86 
     87   explicit BufferedFile(FILE *f) : file_(f) {}
     88 
     89  public:
     90   // Constructs a BufferedFile object which doesn't represent any file.
     91   BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}
     92 
     93   // Destroys the object closing the file it represents if any.
     94   ~BufferedFile() FMT_NOEXCEPT;
     95 
     96 #if !FMT_USE_RVALUE_REFERENCES
     97   // Emulate a move constructor and a move assignment operator if rvalue
     98   // references are not supported.
     99 
    100  private:
    101   // A proxy object to emulate a move constructor.
    102   // It is private to make it impossible call operator Proxy directly.
    103   struct Proxy {
    104     FILE *file;
    105   };
    106 
    107 public:
    108   // A "move constructor" for moving from a temporary.
    109   BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
    110 
    111   // A "move constructor" for moving from an lvalue.
    112   BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
    113     f.file_ = FMT_NULL;
    114   }
    115 
    116   // A "move assignment operator" for moving from a temporary.
    117   BufferedFile &operator=(Proxy p) {
    118     close();
    119     file_ = p.file;
    120     return *this;
    121   }
    122 
    123   // A "move assignment operator" for moving from an lvalue.
    124   BufferedFile &operator=(BufferedFile &other) {
    125     close();
    126     file_ = other.file_;
    127     other.file_ = FMT_NULL;
    128     return *this;
    129   }
    130 
    131   // Returns a proxy object for moving from a temporary:
    132   //   BufferedFile file = BufferedFile(...);
    133   operator Proxy() FMT_NOEXCEPT {
    134     Proxy p = {file_};
    135     file_ = FMT_NULL;
    136     return p;
    137   }
    138 
    139 #else
    140  private:
    141   FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
    142 
    143  public:
    144   BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
    145     other.file_ = FMT_NULL;
    146   }
    147 
    148   BufferedFile& operator=(BufferedFile &&other) {
    149     close();
    150     file_ = other.file_;
    151     other.file_ = FMT_NULL;
    152     return *this;
    153   }
    154 #endif
    155 
    156   // Opens a file.
    157   BufferedFile(CStringRef filename, CStringRef mode);
    158 
    159   // Closes the file.
    160   void close();
    161 
    162   // Returns the pointer to a FILE object representing this file.
    163   FILE *get() const FMT_NOEXCEPT { return file_; }
    164 
    165   // We place parentheses around fileno to workaround a bug in some versions
    166   // of MinGW that define fileno as a macro.
    167   int (fileno)() const;
    168 
    169   void print(CStringRef format_str, const ArgList &args) {
    170     fmt::print(file_, format_str, args);
    171   }
    172   FMT_VARIADIC(void, print, CStringRef)
    173 };
    174 
    175 // A file. Closed file is represented by a File object with descriptor -1.
    176 // Methods that are not declared with FMT_NOEXCEPT may throw
    177 // fmt::SystemError in case of failure. Note that some errors such as
    178 // closing the file multiple times will cause a crash on Windows rather
    179 // than an exception. You can get standard behavior by overriding the
    180 // invalid parameter handler with _set_invalid_parameter_handler.
    181 class File {
    182  private:
    183   int fd_;  // File descriptor.
    184 
    185   // Constructs a File object with a given descriptor.
    186   explicit File(int fd) : fd_(fd) {}
    187 
    188  public:
    189   // Possible values for the oflag argument to the constructor.
    190   enum {
    191     RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
    192     WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
    193     RDWR   = FMT_POSIX(O_RDWR)    // Open for reading and writing.
    194   };
    195 
    196   // Constructs a File object which doesn't represent any file.
    197   File() FMT_NOEXCEPT : fd_(-1) {}
    198 
    199   // Opens a file and constructs a File object representing this file.
    200   File(CStringRef path, int oflag);
    201 
    202 #if !FMT_USE_RVALUE_REFERENCES
    203   // Emulate a move constructor and a move assignment operator if rvalue
    204   // references are not supported.
    205 
    206  private:
    207   // A proxy object to emulate a move constructor.
    208   // It is private to make it impossible call operator Proxy directly.
    209   struct Proxy {
    210     int fd;
    211   };
    212 
    213  public:
    214   // A "move constructor" for moving from a temporary.
    215   File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
    216 
    217   // A "move constructor" for moving from an lvalue.
    218   File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
    219     other.fd_ = -1;
    220   }
    221 
    222   // A "move assignment operator" for moving from a temporary.
    223   File &operator=(Proxy p) {
    224     close();
    225     fd_ = p.fd;
    226     return *this;
    227   }
    228 
    229   // A "move assignment operator" for moving from an lvalue.
    230   File &operator=(File &other) {
    231     close();
    232     fd_ = other.fd_;
    233     other.fd_ = -1;
    234     return *this;
    235   }
    236 
    237   // Returns a proxy object for moving from a temporary:
    238   //   File file = File(...);
    239   operator Proxy() FMT_NOEXCEPT {
    240     Proxy p = {fd_};
    241     fd_ = -1;
    242     return p;
    243   }
    244 
    245 #else
    246  private:
    247   FMT_DISALLOW_COPY_AND_ASSIGN(File);
    248 
    249  public:
    250   File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
    251     other.fd_ = -1;
    252   }
    253 
    254   File& operator=(File &&other) {
    255     close();
    256     fd_ = other.fd_;
    257     other.fd_ = -1;
    258     return *this;
    259   }
    260 #endif
    261 
    262   // Destroys the object closing the file it represents if any.
    263   ~File() FMT_NOEXCEPT;
    264 
    265   // Returns the file descriptor.
    266   int descriptor() const FMT_NOEXCEPT { return fd_; }
    267 
    268   // Closes the file.
    269   void close();
    270 
    271   // Returns the file size. The size has signed type for consistency with
    272   // stat::st_size.
    273   LongLong size() const;
    274 
    275   // Attempts to read count bytes from the file into the specified buffer.
    276   std::size_t read(void *buffer, std::size_t count);
    277 
    278   // Attempts to write count bytes from the specified buffer to the file.
    279   std::size_t write(const void *buffer, std::size_t count);
    280 
    281   // Duplicates a file descriptor with the dup function and returns
    282   // the duplicate as a file object.
    283   static File dup(int fd);
    284 
    285   // Makes fd be the copy of this file descriptor, closing fd first if
    286   // necessary.
    287   void dup2(int fd);
    288 
    289   // Makes fd be the copy of this file descriptor, closing fd first if
    290   // necessary.
    291   void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
    292 
    293   // Creates a pipe setting up read_end and write_end file objects for reading
    294   // and writing respectively.
    295   static void pipe(File &read_end, File &write_end);
    296 
    297   // Creates a BufferedFile object associated with this file and detaches
    298   // this File object from the file.
    299   BufferedFile fdopen(const char *mode);
    300 };
    301 
    302 // Returns the memory page size.
    303 long getpagesize();
    304 
    305 #if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
    306     !defined(__ANDROID__) && !defined(__CYGWIN__)
    307 # define FMT_LOCALE
    308 #endif
    309 
    310 #ifdef FMT_LOCALE
    311 // A "C" numeric locale.
    312 class Locale {
    313  private:
    314 # ifdef _MSC_VER
    315   typedef _locale_t locale_t;
    316 
    317   enum { LC_NUMERIC_MASK = LC_NUMERIC };
    318 
    319   static locale_t newlocale(int category_mask, const char *locale, locale_t) {
    320     return _create_locale(category_mask, locale);
    321   }
    322 
    323   static void freelocale(locale_t locale) {
    324     _free_locale(locale);
    325   }
    326 
    327   static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
    328     return _strtod_l(nptr, endptr, locale);
    329   }
    330 # endif
    331 
    332   locale_t locale_;
    333 
    334   FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
    335 
    336  public:
    337   typedef locale_t Type;
    338 
    339   Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
    340     if (!locale_)
    341       FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
    342   }
    343   ~Locale() { freelocale(locale_); }
    344 
    345   Type get() const { return locale_; }
    346 
    347   // Converts string to floating-point number and advances str past the end
    348   // of the parsed input.
    349   double strtod(const char *&str) const {
    350     char *end = FMT_NULL;
    351     double result = strtod_l(str, &end, locale_);
    352     str = end;
    353     return result;
    354   }
    355 };
    356 #endif  // FMT_LOCALE
    357 }  // namespace fmt
    358 
    359 #if !FMT_USE_RVALUE_REFERENCES
    360 namespace std {
    361 // For compatibility with C++98.
    362 inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
    363 inline fmt::File &move(fmt::File &f) { return f; }
    364 }
    365 #endif
    366 
    367 #endif  // FMT_POSIX_H_
    368