1 // Formatting library for C++ - optional OS-specific functionality
3 // Copyright (c) 2012 - 2016, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
8 // Disable bogus MSVC warnings.
9 #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
10 # define _CRT_SECURE_NO_WARNINGS
18 # include <sys/stat.h>
19 # include <sys/types.h>
24 # ifndef WIN32_LEAN_AND_MEAN
25 # define WIN32_LEAN_AND_MEAN
29 # define O_CREAT _O_CREAT
30 # define O_TRUNC _O_TRUNC
33 # define S_IRUSR _S_IREAD
37 # define S_IWUSR _S_IWRITE
41 # define _SH_DENYNO 0x40
44 #endif // FMT_USE_FCNTL
56 // Return type of read and write functions.
59 // On Windows the count argument to read and write is unsigned, so convert
60 // it from size_t preventing integer overflow.
61 inline unsigned convert_rwcount(std::size_t count
) {
62 return count
<= UINT_MAX
? static_cast<unsigned>(count
) : UINT_MAX
;
65 // Return type of read and write functions.
66 using rwresult
= ssize_t
;
68 inline std::size_t convert_rwcount(std::size_t count
) { return count
; }
75 detail::utf16_to_utf8::utf16_to_utf8(basic_string_view
<wchar_t> s
) {
76 if (int error_code
= convert(s
)) {
77 FMT_THROW(windows_error(error_code
,
78 "cannot convert string from UTF-16 to UTF-8"));
82 int detail::utf16_to_utf8::convert(basic_string_view
<wchar_t> s
) {
83 if (s
.size() > INT_MAX
) return ERROR_INVALID_PARAMETER
;
84 int s_size
= static_cast<int>(s
.size());
86 // WideCharToMultiByte does not support zero length, handle separately.
92 int length
= WideCharToMultiByte(CP_UTF8
, 0, s
.data(), s_size
, nullptr, 0,
94 if (length
== 0) return GetLastError();
95 buffer_
.resize(length
+ 1);
96 length
= WideCharToMultiByte(CP_UTF8
, 0, s
.data(), s_size
, &buffer_
[0],
97 length
, nullptr, nullptr);
98 if (length
== 0) return GetLastError();
105 class system_message
{
106 system_message(const system_message
&) = delete;
107 void operator=(const system_message
&) = delete;
109 unsigned long result_
;
112 static bool is_whitespace(wchar_t c
) FMT_NOEXCEPT
{
113 return c
== L
' ' || c
== L
'\n' || c
== L
'\r' || c
== L
'\t' || c
== L
'\0';
117 explicit system_message(unsigned long error_code
)
118 : result_(0), message_(nullptr) {
119 result_
= FormatMessageW(
120 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
121 FORMAT_MESSAGE_IGNORE_INSERTS
,
122 nullptr, error_code
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
123 reinterpret_cast<wchar_t*>(&message_
), 0, nullptr);
125 while (result_
!= 0 && is_whitespace(message_
[result_
- 1])) {
130 ~system_message() { LocalFree(message_
); }
131 explicit operator bool() const FMT_NOEXCEPT
{ return result_
!= 0; }
132 operator basic_string_view
<wchar_t>() const FMT_NOEXCEPT
{
133 return basic_string_view
<wchar_t>(message_
, result_
);
137 class utf8_system_category final
: public std::error_category
{
139 const char* name() const FMT_NOEXCEPT override
{ return "system"; }
140 std::string
message(int error_code
) const override
{
141 system_message
msg(error_code
);
143 utf16_to_utf8 utf8_message
;
144 if (utf8_message
.convert(msg
) == ERROR_SUCCESS
) {
145 return utf8_message
.str();
148 return "unknown error";
152 } // namespace detail
154 FMT_API
const std::error_category
& system_category() FMT_NOEXCEPT
{
155 static const detail::utf8_system_category category
;
159 std::system_error
vwindows_error(int err_code
, string_view format_str
,
161 auto ec
= std::error_code(err_code
, system_category());
162 return std::system_error(ec
, vformat(format_str
, args
));
165 void detail::format_windows_error(detail::buffer
<char>& out
, int error_code
,
166 const char* message
) FMT_NOEXCEPT
{
168 system_message
msg(error_code
);
170 utf16_to_utf8 utf8_message
;
171 if (utf8_message
.convert(msg
) == ERROR_SUCCESS
) {
172 format_to(buffer_appender
<char>(out
), "{}: {}", message
, utf8_message
);
178 format_error_code(out
, error_code
, message
);
181 void report_windows_error(int error_code
, const char* message
) FMT_NOEXCEPT
{
182 report_error(detail::format_windows_error
, error_code
, message
);
186 buffered_file::~buffered_file() FMT_NOEXCEPT
{
187 if (file_
&& FMT_SYSTEM(fclose(file_
)) != 0)
188 report_system_error(errno
, "cannot close file");
191 buffered_file::buffered_file(cstring_view filename
, cstring_view mode
) {
192 FMT_RETRY_VAL(file_
, FMT_SYSTEM(fopen(filename
.c_str(), mode
.c_str())),
195 FMT_THROW(system_error(errno
, "cannot open file {}", filename
.c_str()));
198 void buffered_file::close() {
200 int result
= FMT_SYSTEM(fclose(file_
));
202 if (result
!= 0) FMT_THROW(system_error(errno
, "cannot close file"));
205 // A macro used to prevent expansion of fileno on broken versions of MinGW.
208 int buffered_file::fileno() const {
209 int fd
= FMT_POSIX_CALL(fileno
FMT_ARGS(file_
));
210 if (fd
== -1) FMT_THROW(system_error(errno
, "cannot get file descriptor"));
215 file::file(cstring_view path
, int oflag
) {
216 int mode
= S_IRUSR
| S_IWUSR
;
217 # if defined(_WIN32) && !defined(__MINGW32__)
219 FMT_POSIX_CALL(sopen_s(&fd_
, path
.c_str(), oflag
, _SH_DENYNO
, mode
));
221 FMT_RETRY(fd_
, FMT_POSIX_CALL(open(path
.c_str(), oflag
, mode
)));
224 FMT_THROW(system_error(errno
, "cannot open file {}", path
.c_str()));
227 file::~file() FMT_NOEXCEPT
{
228 // Don't retry close in case of EINTR!
229 // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
230 if (fd_
!= -1 && FMT_POSIX_CALL(close(fd_
)) != 0)
231 report_system_error(errno
, "cannot close file");
235 if (fd_
== -1) return;
236 // Don't retry close in case of EINTR!
237 // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
238 int result
= FMT_POSIX_CALL(close(fd_
));
240 if (result
!= 0) FMT_THROW(system_error(errno
, "cannot close file"));
243 long long file::size() const {
245 // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
246 // is less than 0x0500 as is the case with some default MinGW builds.
247 // Both functions support large file sizes.
248 DWORD size_upper
= 0;
249 HANDLE handle
= reinterpret_cast<HANDLE
>(_get_osfhandle(fd_
));
250 DWORD size_lower
= FMT_SYSTEM(GetFileSize(handle
, &size_upper
));
251 if (size_lower
== INVALID_FILE_SIZE
) {
252 DWORD error
= GetLastError();
253 if (error
!= NO_ERROR
)
254 FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
256 unsigned long long long_size
= size_upper
;
257 return (long_size
<< sizeof(DWORD
) * CHAR_BIT
) | size_lower
;
259 using Stat
= struct stat
;
260 Stat file_stat
= Stat();
261 if (FMT_POSIX_CALL(fstat(fd_
, &file_stat
)) == -1)
262 FMT_THROW(system_error(errno
, "cannot get file attributes"));
263 static_assert(sizeof(long long) >= sizeof(file_stat
.st_size
),
264 "return type of file::size is not large enough");
265 return file_stat
.st_size
;
269 std::size_t file::read(void* buffer
, std::size_t count
) {
271 FMT_RETRY(result
, FMT_POSIX_CALL(read(fd_
, buffer
, convert_rwcount(count
))));
272 if (result
< 0) FMT_THROW(system_error(errno
, "cannot read from file"));
273 return detail::to_unsigned(result
);
276 std::size_t file::write(const void* buffer
, std::size_t count
) {
278 FMT_RETRY(result
, FMT_POSIX_CALL(write(fd_
, buffer
, convert_rwcount(count
))));
279 if (result
< 0) FMT_THROW(system_error(errno
, "cannot write to file"));
280 return detail::to_unsigned(result
);
283 file
file::dup(int fd
) {
284 // Don't retry as dup doesn't return EINTR.
285 // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
286 int new_fd
= FMT_POSIX_CALL(dup(fd
));
288 FMT_THROW(system_error(errno
, "cannot duplicate file descriptor {}", fd
));
292 void file::dup2(int fd
) {
294 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
296 FMT_THROW(system_error(errno
, "cannot duplicate file descriptor {} to {}",
301 void file::dup2(int fd
, std::error_code
& ec
) FMT_NOEXCEPT
{
303 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
304 if (result
== -1) ec
= std::error_code(errno
, std::generic_category());
307 void file::pipe(file
& read_end
, file
& write_end
) {
308 // Close the descriptors first to make sure that assignments don't throw
309 // and there are no leaks.
314 // Make the default pipe capacity same as on Linux 2.6.11+.
315 enum { DEFAULT_CAPACITY
= 65536 };
316 int result
= FMT_POSIX_CALL(pipe(fds
, DEFAULT_CAPACITY
, _O_BINARY
));
318 // Don't retry as the pipe function doesn't return EINTR.
319 // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
320 int result
= FMT_POSIX_CALL(pipe(fds
));
322 if (result
!= 0) FMT_THROW(system_error(errno
, "cannot create pipe"));
323 // The following assignments don't throw because read_fd and write_fd
325 read_end
= file(fds
[0]);
326 write_end
= file(fds
[1]);
329 buffered_file
file::fdopen(const char* mode
) {
330 // Don't retry as fdopen doesn't return EINTR.
331 # if defined(__MINGW32__) && defined(_POSIX_)
332 FILE* f
= ::fdopen(fd_
, mode
);
334 FILE* f
= FMT_POSIX_CALL(fdopen(fd_
, mode
));
338 system_error(errno
, "cannot associate stream with file descriptor"));
348 return si
.dwPageSize
;
350 long size
= FMT_POSIX_CALL(sysconf(_SC_PAGESIZE
));
351 if (size
< 0) FMT_THROW(system_error(errno
, "cannot get memory page size"));
356 FMT_API
void ostream::grow(size_t) {
357 if (this->size() == this->capacity()) flush();
359 #endif // FMT_USE_FCNTL