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