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
13 #include "cpp-common/vendor/fmt/os.h"
18 # include <sys/stat.h>
19 # include <sys/types.h>
21 # ifdef _WRS_KERNEL // VxWorks7 kernel
22 # include <ioLib.h> // getpagesize
28 # ifndef WIN32_LEAN_AND_MEAN
29 # define WIN32_LEAN_AND_MEAN
34 # define S_IRUSR _S_IREAD
37 # define S_IWUSR _S_IWRITE
52 #endif // FMT_USE_FCNTL
60 // Return type of read and write functions.
63 // On Windows the count argument to read and write is unsigned, so convert
64 // it from size_t preventing integer overflow.
65 inline unsigned convert_rwcount(std::size_t count
) {
66 return count
<= UINT_MAX
? static_cast<unsigned>(count
) : UINT_MAX
;
69 // Return type of read and write functions.
70 using rwresult
= ssize_t
;
72 inline std::size_t convert_rwcount(std::size_t count
) { return count
; }
81 class system_message
{
82 system_message(const system_message
&) = delete;
83 void operator=(const system_message
&) = delete;
85 unsigned long result_
;
88 static bool is_whitespace(wchar_t c
) noexcept
{
89 return c
== L
' ' || c
== L
'\n' || c
== L
'\r' || c
== L
'\t' || c
== L
'\0';
93 explicit system_message(unsigned long error_code
)
94 : result_(0), message_(nullptr) {
95 result_
= FormatMessageW(
96 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
97 FORMAT_MESSAGE_IGNORE_INSERTS
,
98 nullptr, error_code
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
99 reinterpret_cast<wchar_t*>(&message_
), 0, nullptr);
101 while (result_
!= 0 && is_whitespace(message_
[result_
- 1])) {
106 ~system_message() { LocalFree(message_
); }
107 explicit operator bool() const noexcept
{ return result_
!= 0; }
108 operator basic_string_view
<wchar_t>() const noexcept
{
109 return basic_string_view
<wchar_t>(message_
, result_
);
113 class utf8_system_category final
: public std::error_category
{
115 const char* name() const noexcept override
{ return "system"; }
116 std::string
message(int error_code
) const override
{
117 auto&& msg
= system_message(error_code
);
119 auto utf8_message
= to_utf8
<wchar_t>();
120 if (utf8_message
.convert(msg
)) {
121 return utf8_message
.str();
124 return "unknown error";
128 } // namespace detail
130 FMT_API
const std::error_category
& system_category() noexcept
{
131 static const detail::utf8_system_category category
;
135 std::system_error
vwindows_error(int err_code
, string_view format_str
,
137 auto ec
= std::error_code(err_code
, system_category());
138 return std::system_error(ec
, vformat(format_str
, args
));
141 void detail::format_windows_error(detail::buffer
<char>& out
, int error_code
,
142 const char* message
) noexcept
{
144 auto&& msg
= system_message(error_code
);
146 auto utf8_message
= to_utf8
<wchar_t>();
147 if (utf8_message
.convert(msg
)) {
148 fmt::format_to(appender(out
), FMT_STRING("{}: {}"), message
,
149 string_view(utf8_message
));
155 format_error_code(out
, error_code
, message
);
158 void report_windows_error(int error_code
, const char* message
) noexcept
{
159 report_error(detail::format_windows_error
, error_code
, message
);
163 buffered_file::~buffered_file() noexcept
{
164 if (file_
&& FMT_SYSTEM(fclose(file_
)) != 0)
165 report_system_error(errno
, "cannot close file");
168 buffered_file::buffered_file(cstring_view filename
, cstring_view mode
) {
169 FMT_RETRY_VAL(file_
, FMT_SYSTEM(fopen(filename
.c_str(), mode
.c_str())),
172 FMT_THROW(system_error(errno
, FMT_STRING("cannot open file {}"),
176 void buffered_file::close() {
178 int result
= FMT_SYSTEM(fclose(file_
));
181 FMT_THROW(system_error(errno
, FMT_STRING("cannot close file")));
184 int buffered_file::descriptor() const {
185 #ifdef fileno // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL.
186 int fd
= fileno(file_
);
188 int fd
= FMT_POSIX_CALL(fileno(file_
));
191 FMT_THROW(system_error(errno
, FMT_STRING("cannot get file descriptor")));
199 constexpr mode_t default_open_mode
=
200 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
;
202 file::file(cstring_view path
, int oflag
) {
203 # if defined(_WIN32) && !defined(__MINGW32__)
205 auto converted
= detail::utf8_to_utf16(string_view(path
.c_str()));
206 *this = file::open_windows_file(converted
.c_str(), oflag
);
208 FMT_RETRY(fd_
, FMT_POSIX_CALL(open(path
.c_str(), oflag
, default_open_mode
)));
211 system_error(errno
, FMT_STRING("cannot open file {}"), path
.c_str()));
215 file::~file() noexcept
{
216 // Don't retry close in case of EINTR!
217 // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
218 if (fd_
!= -1 && FMT_POSIX_CALL(close(fd_
)) != 0)
219 report_system_error(errno
, "cannot close file");
223 if (fd_
== -1) return;
224 // Don't retry close in case of EINTR!
225 // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
226 int result
= FMT_POSIX_CALL(close(fd_
));
229 FMT_THROW(system_error(errno
, FMT_STRING("cannot close file")));
232 long long file::size() const {
234 // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
235 // is less than 0x0500 as is the case with some default MinGW builds.
236 // Both functions support large file sizes.
237 DWORD size_upper
= 0;
238 HANDLE handle
= reinterpret_cast<HANDLE
>(_get_osfhandle(fd_
));
239 DWORD size_lower
= FMT_SYSTEM(GetFileSize(handle
, &size_upper
));
240 if (size_lower
== INVALID_FILE_SIZE
) {
241 DWORD error
= GetLastError();
242 if (error
!= NO_ERROR
)
243 FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
245 unsigned long long long_size
= size_upper
;
246 return (long_size
<< sizeof(DWORD
) * CHAR_BIT
) | size_lower
;
248 using Stat
= struct stat
;
249 Stat file_stat
= Stat();
250 if (FMT_POSIX_CALL(fstat(fd_
, &file_stat
)) == -1)
251 FMT_THROW(system_error(errno
, FMT_STRING("cannot get file attributes")));
252 static_assert(sizeof(long long) >= sizeof(file_stat
.st_size
),
253 "return type of file::size is not large enough");
254 return file_stat
.st_size
;
258 std::size_t file::read(void* buffer
, std::size_t count
) {
260 FMT_RETRY(result
, FMT_POSIX_CALL(read(fd_
, buffer
, convert_rwcount(count
))));
262 FMT_THROW(system_error(errno
, FMT_STRING("cannot read from file")));
263 return detail::to_unsigned(result
);
266 std::size_t file::write(const void* buffer
, std::size_t count
) {
268 FMT_RETRY(result
, FMT_POSIX_CALL(write(fd_
, buffer
, convert_rwcount(count
))));
270 FMT_THROW(system_error(errno
, FMT_STRING("cannot write to file")));
271 return detail::to_unsigned(result
);
274 file
file::dup(int fd
) {
275 // Don't retry as dup doesn't return EINTR.
276 // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
277 int new_fd
= FMT_POSIX_CALL(dup(fd
));
279 FMT_THROW(system_error(
280 errno
, FMT_STRING("cannot duplicate file descriptor {}"), fd
));
284 void file::dup2(int fd
) {
286 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
288 FMT_THROW(system_error(
289 errno
, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_
,
294 void file::dup2(int fd
, std::error_code
& ec
) noexcept
{
296 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
297 if (result
== -1) ec
= std::error_code(errno
, std::generic_category());
300 void file::pipe(file
& read_end
, file
& write_end
) {
301 // Close the descriptors first to make sure that assignments don't throw
302 // and there are no leaks.
307 // Make the default pipe capacity same as on Linux 2.6.11+.
308 enum { DEFAULT_CAPACITY
= 65536 };
309 int result
= FMT_POSIX_CALL(pipe(fds
, DEFAULT_CAPACITY
, _O_BINARY
));
311 // Don't retry as the pipe function doesn't return EINTR.
312 // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
313 int result
= FMT_POSIX_CALL(pipe(fds
));
316 FMT_THROW(system_error(errno
, FMT_STRING("cannot create pipe")));
317 // The following assignments don't throw because read_fd and write_fd
319 read_end
= file(fds
[0]);
320 write_end
= file(fds
[1]);
323 buffered_file
file::fdopen(const char* mode
) {
324 // Don't retry as fdopen doesn't return EINTR.
325 # if defined(__MINGW32__) && defined(_POSIX_)
326 FILE* f
= ::fdopen(fd_
, mode
);
328 FILE* f
= FMT_POSIX_CALL(fdopen(fd_
, mode
));
331 FMT_THROW(system_error(
332 errno
, FMT_STRING("cannot associate stream with file descriptor")));
339 # if defined(_WIN32) && !defined(__MINGW32__)
340 file
file::open_windows_file(wcstring_view path
, int oflag
) {
342 auto err
= _wsopen_s(&fd
, path
.c_str(), oflag
, _SH_DENYNO
, default_open_mode
);
344 FMT_THROW(system_error(err
, FMT_STRING("cannot open file {}"),
345 detail::to_utf8
<wchar_t>(path
.c_str()).c_str()));
351 # if !defined(__MSDOS__)
356 return si
.dwPageSize
;
359 long size
= FMT_POSIX_CALL(getpagesize());
361 long size
= FMT_POSIX_CALL(sysconf(_SC_PAGESIZE
));
365 FMT_THROW(system_error(errno
, FMT_STRING("cannot get memory page size")));
373 void file_buffer::grow(size_t) {
374 if (this->size() == this->capacity()) flush();
377 file_buffer::file_buffer(cstring_view path
,
378 const detail::ostream_params
& params
)
379 : file_(path
, params
.oflag
) {
380 set(new char[params
.buffer_size
], params
.buffer_size
);
383 file_buffer::file_buffer(file_buffer
&& other
)
384 : detail::buffer
<char>(other
.data(), other
.size(), other
.capacity()),
385 file_(std::move(other
.file_
)) {
387 other
.set(nullptr, 0);
390 file_buffer::~file_buffer() {
394 } // namespace detail
396 ostream::~ostream() = default;
397 #endif // FMT_USE_FCNTL