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
19 # include <sys/stat.h>
20 # include <sys/types.h>
22 # ifdef _WRS_KERNEL // VxWorks7 kernel
23 # include <ioLib.h> // getpagesize
29 # ifndef WIN32_LEAN_AND_MEAN
30 # define WIN32_LEAN_AND_MEAN
34 # endif // FMT_USE_FCNTL
43 # define S_IRUSR _S_IREAD
46 # define S_IWUSR _S_IWRITE
64 // Return type of read and write functions.
67 // On Windows the count argument to read and write is unsigned, so convert
68 // it from size_t preventing integer overflow.
69 inline unsigned convert_rwcount(std::size_t count
) {
70 return count
<= UINT_MAX
? static_cast<unsigned>(count
) : UINT_MAX
;
73 // Return type of read and write functions.
74 using rwresult
= ssize_t
;
76 inline std::size_t convert_rwcount(std::size_t count
) { return count
; }
85 class system_message
{
86 system_message(const system_message
&) = delete;
87 void operator=(const system_message
&) = delete;
89 unsigned long result_
;
92 static bool is_whitespace(wchar_t c
) noexcept
{
93 return c
== L
' ' || c
== L
'\n' || c
== L
'\r' || c
== L
'\t' || c
== L
'\0';
97 explicit system_message(unsigned long error_code
)
98 : result_(0), message_(nullptr) {
99 result_
= FormatMessageW(
100 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
101 FORMAT_MESSAGE_IGNORE_INSERTS
,
102 nullptr, error_code
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
103 reinterpret_cast<wchar_t*>(&message_
), 0, nullptr);
105 while (result_
!= 0 && is_whitespace(message_
[result_
- 1])) {
110 ~system_message() { LocalFree(message_
); }
111 explicit operator bool() const noexcept
{ return result_
!= 0; }
112 operator basic_string_view
<wchar_t>() const noexcept
{
113 return basic_string_view
<wchar_t>(message_
, result_
);
117 class utf8_system_category final
: public std::error_category
{
119 const char* name() const noexcept override
{ return "system"; }
120 std::string
message(int error_code
) const override
{
121 auto&& msg
= system_message(error_code
);
123 auto utf8_message
= to_utf8
<wchar_t>();
124 if (utf8_message
.convert(msg
)) {
125 return utf8_message
.str();
128 return "unknown error";
132 } // namespace detail
134 FMT_API
const std::error_category
& system_category() noexcept
{
135 static const detail::utf8_system_category category
;
139 std::system_error
vwindows_error(int err_code
, string_view format_str
,
141 auto ec
= std::error_code(err_code
, system_category());
142 return std::system_error(ec
, vformat(format_str
, args
));
145 void detail::format_windows_error(detail::buffer
<char>& out
, int error_code
,
146 const char* message
) noexcept
{
148 auto&& msg
= system_message(error_code
);
150 auto utf8_message
= to_utf8
<wchar_t>();
151 if (utf8_message
.convert(msg
)) {
152 fmt::format_to(appender(out
), FMT_STRING("{}: {}"), message
,
153 string_view(utf8_message
));
159 format_error_code(out
, error_code
, message
);
162 void report_windows_error(int error_code
, const char* message
) noexcept
{
163 report_error(detail::format_windows_error
, error_code
, message
);
167 buffered_file::~buffered_file() noexcept
{
168 if (file_
&& FMT_SYSTEM(fclose(file_
)) != 0)
169 report_system_error(errno
, "cannot close file");
172 buffered_file::buffered_file(cstring_view filename
, cstring_view mode
) {
173 FMT_RETRY_VAL(file_
, FMT_SYSTEM(fopen(filename
.c_str(), mode
.c_str())),
176 FMT_THROW(system_error(errno
, FMT_STRING("cannot open file {}"),
180 void buffered_file::close() {
182 int result
= FMT_SYSTEM(fclose(file_
));
185 FMT_THROW(system_error(errno
, FMT_STRING("cannot close file")));
188 int buffered_file::descriptor() const {
189 #ifdef FMT_HAS_SYSTEM
190 // fileno is a macro on OpenBSD.
194 int fd
= FMT_POSIX_CALL(fileno(file_
));
195 #elif defined(_WIN32)
196 int fd
= _fileno(file_
);
198 int fd
= fileno(file_
);
201 FMT_THROW(system_error(errno
, FMT_STRING("cannot get file descriptor")));
210 constexpr mode_t default_open_mode
=
211 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
;
213 file::file(cstring_view path
, int oflag
) {
214 # if defined(_WIN32) && !defined(__MINGW32__)
216 auto converted
= detail::utf8_to_utf16(string_view(path
.c_str()));
217 *this = file::open_windows_file(converted
.c_str(), oflag
);
219 FMT_RETRY(fd_
, FMT_POSIX_CALL(open(path
.c_str(), oflag
, default_open_mode
)));
222 system_error(errno
, FMT_STRING("cannot open file {}"), path
.c_str()));
226 file::~file() noexcept
{
227 // Don't retry close in case of EINTR!
228 // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
229 if (fd_
!= -1 && FMT_POSIX_CALL(close(fd_
)) != 0)
230 report_system_error(errno
, "cannot close file");
234 if (fd_
== -1) return;
235 // Don't retry close in case of EINTR!
236 // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
237 int result
= FMT_POSIX_CALL(close(fd_
));
240 FMT_THROW(system_error(errno
, FMT_STRING("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
, FMT_STRING("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
))));
273 FMT_THROW(system_error(errno
, FMT_STRING("cannot read from file")));
274 return detail::to_unsigned(result
);
277 std::size_t file::write(const void* buffer
, std::size_t count
) {
279 FMT_RETRY(result
, FMT_POSIX_CALL(write(fd_
, buffer
, convert_rwcount(count
))));
281 FMT_THROW(system_error(errno
, FMT_STRING("cannot write to file")));
282 return detail::to_unsigned(result
);
285 file
file::dup(int fd
) {
286 // Don't retry as dup doesn't return EINTR.
287 // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
288 int new_fd
= FMT_POSIX_CALL(dup(fd
));
290 FMT_THROW(system_error(
291 errno
, FMT_STRING("cannot duplicate file descriptor {}"), fd
));
295 void file::dup2(int fd
) {
297 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
299 FMT_THROW(system_error(
300 errno
, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_
,
305 void file::dup2(int fd
, std::error_code
& ec
) noexcept
{
307 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
308 if (result
== -1) ec
= std::error_code(errno
, std::generic_category());
311 buffered_file
file::fdopen(const char* mode
) {
312 // Don't retry as fdopen doesn't return EINTR.
313 # if defined(__MINGW32__) && defined(_POSIX_)
314 FILE* f
= ::fdopen(fd_
, mode
);
316 FILE* f
= FMT_POSIX_CALL(fdopen(fd_
, mode
));
319 FMT_THROW(system_error(
320 errno
, FMT_STRING("cannot associate stream with file descriptor")));
327 # if defined(_WIN32) && !defined(__MINGW32__)
328 file
file::open_windows_file(wcstring_view path
, int oflag
) {
330 auto err
= _wsopen_s(&fd
, path
.c_str(), oflag
, _SH_DENYNO
, default_open_mode
);
332 FMT_THROW(system_error(err
, FMT_STRING("cannot open file {}"),
333 detail::to_utf8
<wchar_t>(path
.c_str()).c_str()));
342 // Make the default pipe capacity same as on Linux 2.6.11+.
343 enum { DEFAULT_CAPACITY
= 65536 };
344 int result
= FMT_POSIX_CALL(pipe(fds
, DEFAULT_CAPACITY
, _O_BINARY
));
346 // Don't retry as the pipe function doesn't return EINTR.
347 // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
348 int result
= FMT_POSIX_CALL(pipe(fds
));
351 FMT_THROW(system_error(errno
, FMT_STRING("cannot create pipe")));
352 // The following assignments don't throw.
353 read_end
= file(fds
[0]);
354 write_end
= file(fds
[1]);
357 # if !defined(__MSDOS__)
362 return si
.dwPageSize
;
365 long size
= FMT_POSIX_CALL(getpagesize());
367 long size
= FMT_POSIX_CALL(sysconf(_SC_PAGESIZE
));
371 FMT_THROW(system_error(errno
, FMT_STRING("cannot get memory page size")));
379 void file_buffer::grow(buffer
<char>& buf
, size_t) {
380 if (buf
.size() == buf
.capacity()) static_cast<file_buffer
&>(buf
).flush();
383 file_buffer::file_buffer(cstring_view path
, const ostream_params
& params
)
384 : buffer
<char>(grow
), file_(path
, params
.oflag
) {
385 set(new char[params
.buffer_size
], params
.buffer_size
);
388 file_buffer::file_buffer(file_buffer
&& other
) noexcept
389 : buffer
<char>(grow
, other
.data(), other
.size(), other
.capacity()),
390 file_(std::move(other
.file_
)) {
392 other
.set(nullptr, 0);
395 file_buffer::~file_buffer() {
399 } // namespace detail
401 ostream::~ostream() = default;
402 #endif // FMT_USE_FCNTL