1 // Formatting library for C++ - optional OS-specific functionality 2 // 3 // Copyright (c) 2012 - present, Victor Zverovich 4 // All rights reserved. 5 // 6 // For the license information refer to format.h. 7 8 #ifndef FMT_OS_H_ 9 #define FMT_OS_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 <cstddef> 19 #include <cstdio> 20 #include <cstdlib> // for strtod_l 21 22 #if defined __APPLE__ || defined(__FreeBSD__) 23 # include <xlocale.h> // for LC_NUMERIC_MASK on OS X 24 #endif 25 26 #include "format.h" 27 28 // UWP doesn't provide _pipe. 29 #if FMT_HAS_INCLUDE("winapifamily.h") 30 # include <winapifamily.h> 31 #endif 32 #if FMT_HAS_INCLUDE("fcntl.h") && \ 33 (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) 34 # include <fcntl.h> // for O_RDONLY 35 # define FMT_USE_FCNTL 1 36 #else 37 # define FMT_USE_FCNTL 0 38 #endif 39 40 #ifndef FMT_POSIX 41 # if defined(_WIN32) && !defined(__MINGW32__) 42 // Fix warnings about deprecated symbols. 43 # define FMT_POSIX(call) _##call 44 # else 45 # define FMT_POSIX(call) call 46 # endif 47 #endif 48 49 // Calls to system functions are wrapped in FMT_SYSTEM for testability. 50 #ifdef FMT_SYSTEM 51 # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) 52 #else 53 # define FMT_SYSTEM(call) call 54 # ifdef _WIN32 55 // Fix warnings about deprecated symbols. 56 # define FMT_POSIX_CALL(call) ::_##call 57 # else 58 # define FMT_POSIX_CALL(call) ::call 59 # endif 60 #endif 61 62 // Retries the expression while it evaluates to error_result and errno 63 // equals to EINTR. 64 #ifndef _WIN32 65 # define FMT_RETRY_VAL(result, expression, error_result) \ 66 do { \ 67 (result) = (expression); \ 68 } while ((result) == (error_result) && errno == EINTR) 69 #else 70 # define FMT_RETRY_VAL(result, expression, error_result) result = (expression) 71 #endif 72 73 #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) 74 75 FMT_BEGIN_NAMESPACE 76 77 /** 78 \rst 79 A reference to a null-terminated string. It can be constructed from a C 80 string or ``std::string``. 81 82 You can use one of the following type aliases for common character types: 83 84 +---------------+-----------------------------+ 85 | Type | Definition | 86 +===============+=============================+ 87 | cstring_view | basic_cstring_view<char> | 88 +---------------+-----------------------------+ 89 | wcstring_view | basic_cstring_view<wchar_t> | 90 +---------------+-----------------------------+ 91 92 This class is most useful as a parameter type to allow passing 93 different types of strings to a function, for example:: 94 95 template <typename... Args> 96 std::string format(cstring_view format_str, const Args & ... args); 97 98 format("{}", 42); 99 format(std::string("{}"), 42); 100 \endrst 101 */ 102 template <typename Char> class basic_cstring_view { 103 private: 104 const Char* data_; 105 106 public: 107 /** Constructs a string reference object from a C string. */ basic_cstring_view(const Char * s)108 basic_cstring_view(const Char* s) : data_(s) {} 109 110 /** 111 \rst 112 Constructs a string reference from an ``std::string`` object. 113 \endrst 114 */ basic_cstring_view(const std::basic_string<Char> & s)115 basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {} 116 117 /** Returns the pointer to a C string. */ c_str()118 const Char* c_str() const { return data_; } 119 }; 120 121 using cstring_view = basic_cstring_view<char>; 122 using wcstring_view = basic_cstring_view<wchar_t>; 123 124 // An error code. 125 class error_code { 126 private: 127 int value_; 128 129 public: value_(value)130 explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} 131 get()132 int get() const FMT_NOEXCEPT { return value_; } 133 }; 134 135 #ifdef _WIN32 136 namespace internal { 137 // A converter from UTF-16 to UTF-8. 138 // It is only provided for Windows since other systems support UTF-8 natively. 139 class utf16_to_utf8 { 140 private: 141 memory_buffer buffer_; 142 143 public: utf16_to_utf8()144 utf16_to_utf8() {} 145 FMT_API explicit utf16_to_utf8(wstring_view s); string_view()146 operator string_view() const { return string_view(&buffer_[0], size()); } size()147 size_t size() const { return buffer_.size() - 1; } c_str()148 const char* c_str() const { return &buffer_[0]; } str()149 std::string str() const { return std::string(&buffer_[0], size()); } 150 151 // Performs conversion returning a system error code instead of 152 // throwing exception on conversion error. This method may still throw 153 // in case of memory allocation error. 154 FMT_API int convert(wstring_view s); 155 }; 156 157 FMT_API void format_windows_error(buffer<char>& out, int error_code, 158 string_view message) FMT_NOEXCEPT; 159 } // namespace internal 160 161 /** A Windows error. */ 162 class windows_error : public system_error { 163 private: 164 FMT_API void init(int error_code, string_view format_str, format_args args); 165 166 public: 167 /** 168 \rst 169 Constructs a :class:`fmt::windows_error` object with the description 170 of the form 171 172 .. parsed-literal:: 173 *<message>*: *<system-message>* 174 175 where *<message>* is the formatted message and *<system-message>* is the 176 system message corresponding to the error code. 177 *error_code* is a Windows error code as given by ``GetLastError``. 178 If *error_code* is not a valid error code such as -1, the system message 179 will look like "error -1". 180 181 **Example**:: 182 183 // This throws a windows_error with the description 184 // cannot open file 'madeup': The system cannot find the file specified. 185 // or similar (system message may vary). 186 const char *filename = "madeup"; 187 LPOFSTRUCT of = LPOFSTRUCT(); 188 HFILE file = OpenFile(filename, &of, OF_READ); 189 if (file == HFILE_ERROR) { 190 throw fmt::windows_error(GetLastError(), 191 "cannot open file '{}'", filename); 192 } 193 \endrst 194 */ 195 template <typename... Args> windows_error(int error_code,string_view message,const Args &...args)196 windows_error(int error_code, string_view message, const Args&... args) { 197 init(error_code, message, make_format_args(args...)); 198 } 199 }; 200 201 // Reports a Windows error without throwing an exception. 202 // Can be used to report errors from destructors. 203 FMT_API void report_windows_error(int error_code, 204 string_view message) FMT_NOEXCEPT; 205 #endif // _WIN32 206 207 // A buffered file. 208 class buffered_file { 209 private: 210 FILE* file_; 211 212 friend class file; 213 buffered_file(FILE * f)214 explicit buffered_file(FILE* f) : file_(f) {} 215 216 public: 217 buffered_file(const buffered_file&) = delete; 218 void operator=(const buffered_file&) = delete; 219 220 // Constructs a buffered_file object which doesn't represent any file. buffered_file()221 buffered_file() FMT_NOEXCEPT : file_(nullptr) {} 222 223 // Destroys the object closing the file it represents if any. 224 FMT_API ~buffered_file() FMT_NOEXCEPT; 225 226 public: buffered_file(buffered_file && other)227 buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) { 228 other.file_ = nullptr; 229 } 230 231 buffered_file& operator=(buffered_file&& other) { 232 close(); 233 file_ = other.file_; 234 other.file_ = nullptr; 235 return *this; 236 } 237 238 // Opens a file. 239 FMT_API buffered_file(cstring_view filename, cstring_view mode); 240 241 // Closes the file. 242 FMT_API void close(); 243 244 // Returns the pointer to a FILE object representing this file. get()245 FILE* get() const FMT_NOEXCEPT { return file_; } 246 247 // We place parentheses around fileno to workaround a bug in some versions 248 // of MinGW that define fileno as a macro. 249 FMT_API int(fileno)() const; 250 vprint(string_view format_str,format_args args)251 void vprint(string_view format_str, format_args args) { 252 fmt::vprint(file_, format_str, args); 253 } 254 255 template <typename... Args> print(string_view format_str,const Args &...args)256 inline void print(string_view format_str, const Args&... args) { 257 vprint(format_str, make_format_args(args...)); 258 } 259 }; 260 261 #if FMT_USE_FCNTL 262 // A file. Closed file is represented by a file object with descriptor -1. 263 // Methods that are not declared with FMT_NOEXCEPT may throw 264 // fmt::system_error in case of failure. Note that some errors such as 265 // closing the file multiple times will cause a crash on Windows rather 266 // than an exception. You can get standard behavior by overriding the 267 // invalid parameter handler with _set_invalid_parameter_handler. 268 class file { 269 private: 270 int fd_; // File descriptor. 271 272 // Constructs a file object with a given descriptor. file(int fd)273 explicit file(int fd) : fd_(fd) {} 274 275 public: 276 // Possible values for the oflag argument to the constructor. 277 enum { 278 RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. 279 WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. 280 RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. 281 }; 282 283 // Constructs a file object which doesn't represent any file. file()284 file() FMT_NOEXCEPT : fd_(-1) {} 285 286 // Opens a file and constructs a file object representing this file. 287 FMT_API file(cstring_view path, int oflag); 288 289 public: 290 file(const file&) = delete; 291 void operator=(const file&) = delete; 292 file(file && other)293 file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } 294 295 file& operator=(file&& other) FMT_NOEXCEPT { 296 close(); 297 fd_ = other.fd_; 298 other.fd_ = -1; 299 return *this; 300 } 301 302 // Destroys the object closing the file it represents if any. 303 FMT_API ~file() FMT_NOEXCEPT; 304 305 // Returns the file descriptor. descriptor()306 int descriptor() const FMT_NOEXCEPT { return fd_; } 307 308 // Closes the file. 309 FMT_API void close(); 310 311 // Returns the file size. The size has signed type for consistency with 312 // stat::st_size. 313 FMT_API long long size() const; 314 315 // Attempts to read count bytes from the file into the specified buffer. 316 FMT_API std::size_t read(void* buffer, std::size_t count); 317 318 // Attempts to write count bytes from the specified buffer to the file. 319 FMT_API std::size_t write(const void* buffer, std::size_t count); 320 321 // Duplicates a file descriptor with the dup function and returns 322 // the duplicate as a file object. 323 FMT_API static file dup(int fd); 324 325 // Makes fd be the copy of this file descriptor, closing fd first if 326 // necessary. 327 FMT_API void dup2(int fd); 328 329 // Makes fd be the copy of this file descriptor, closing fd first if 330 // necessary. 331 FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT; 332 333 // Creates a pipe setting up read_end and write_end file objects for reading 334 // and writing respectively. 335 FMT_API static void pipe(file& read_end, file& write_end); 336 337 // Creates a buffered_file object associated with this file and detaches 338 // this file object from the file. 339 FMT_API buffered_file fdopen(const char* mode); 340 }; 341 342 // Returns the memory page size. 343 long getpagesize(); 344 #endif // FMT_USE_FCNTL 345 346 #ifdef FMT_LOCALE 347 // A "C" numeric locale. 348 class locale { 349 private: 350 # ifdef _WIN32 351 using locale_t = _locale_t; 352 freelocale(locale_t loc)353 static void freelocale(locale_t loc) { _free_locale(loc); } 354 strtod_l(const char * nptr,char ** endptr,_locale_t loc)355 static double strtod_l(const char* nptr, char** endptr, _locale_t loc) { 356 return _strtod_l(nptr, endptr, loc); 357 } 358 # endif 359 360 locale_t locale_; 361 362 public: 363 using type = locale_t; 364 locale(const locale&) = delete; 365 void operator=(const locale&) = delete; 366 locale()367 locale() { 368 # ifndef _WIN32 369 locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr)); 370 # else 371 locale_ = _create_locale(LC_NUMERIC, "C"); 372 # endif 373 if (!locale_) FMT_THROW(system_error(errno, "cannot create locale")); 374 } ~locale()375 ~locale() { freelocale(locale_); } 376 get()377 type get() const { return locale_; } 378 379 // Converts string to floating-point number and advances str past the end 380 // of the parsed input. strtod(const char * & str)381 double strtod(const char*& str) const { 382 char* end = nullptr; 383 double result = strtod_l(str, &end, locale_); 384 str = end; 385 return result; 386 } 387 }; 388 using Locale FMT_DEPRECATED_ALIAS = locale; 389 #endif // FMT_LOCALE 390 FMT_END_NAMESPACE 391 392 #endif // FMT_OS_H_ 393