xref: /aosp_15_r20/external/fmtlib/src/os.cc (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1*5c90c05cSAndroid Build Coastguard Worker // Formatting library for C++ - optional OS-specific functionality
2*5c90c05cSAndroid Build Coastguard Worker //
3*5c90c05cSAndroid Build Coastguard Worker // Copyright (c) 2012 - 2016, Victor Zverovich
4*5c90c05cSAndroid Build Coastguard Worker // All rights reserved.
5*5c90c05cSAndroid Build Coastguard Worker //
6*5c90c05cSAndroid Build Coastguard Worker // For the license information refer to format.h.
7*5c90c05cSAndroid Build Coastguard Worker 
8*5c90c05cSAndroid Build Coastguard Worker // Disable bogus MSVC warnings.
9*5c90c05cSAndroid Build Coastguard Worker #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
10*5c90c05cSAndroid Build Coastguard Worker #  define _CRT_SECURE_NO_WARNINGS
11*5c90c05cSAndroid Build Coastguard Worker #endif
12*5c90c05cSAndroid Build Coastguard Worker 
13*5c90c05cSAndroid Build Coastguard Worker #include "fmt/os.h"
14*5c90c05cSAndroid Build Coastguard Worker 
15*5c90c05cSAndroid Build Coastguard Worker #ifndef FMT_MODULE
16*5c90c05cSAndroid Build Coastguard Worker #  include <climits>
17*5c90c05cSAndroid Build Coastguard Worker 
18*5c90c05cSAndroid Build Coastguard Worker #  if FMT_USE_FCNTL
19*5c90c05cSAndroid Build Coastguard Worker #    include <sys/stat.h>
20*5c90c05cSAndroid Build Coastguard Worker #    include <sys/types.h>
21*5c90c05cSAndroid Build Coastguard Worker 
22*5c90c05cSAndroid Build Coastguard Worker #    ifdef _WRS_KERNEL    // VxWorks7 kernel
23*5c90c05cSAndroid Build Coastguard Worker #      include <ioLib.h>  // getpagesize
24*5c90c05cSAndroid Build Coastguard Worker #    endif
25*5c90c05cSAndroid Build Coastguard Worker 
26*5c90c05cSAndroid Build Coastguard Worker #    ifndef _WIN32
27*5c90c05cSAndroid Build Coastguard Worker #      include <unistd.h>
28*5c90c05cSAndroid Build Coastguard Worker #    else
29*5c90c05cSAndroid Build Coastguard Worker #      ifndef WIN32_LEAN_AND_MEAN
30*5c90c05cSAndroid Build Coastguard Worker #        define WIN32_LEAN_AND_MEAN
31*5c90c05cSAndroid Build Coastguard Worker #      endif
32*5c90c05cSAndroid Build Coastguard Worker #      include <io.h>
33*5c90c05cSAndroid Build Coastguard Worker #    endif  // _WIN32
34*5c90c05cSAndroid Build Coastguard Worker #  endif    // FMT_USE_FCNTL
35*5c90c05cSAndroid Build Coastguard Worker 
36*5c90c05cSAndroid Build Coastguard Worker #  ifdef _WIN32
37*5c90c05cSAndroid Build Coastguard Worker #    include <windows.h>
38*5c90c05cSAndroid Build Coastguard Worker #  endif
39*5c90c05cSAndroid Build Coastguard Worker #endif
40*5c90c05cSAndroid Build Coastguard Worker 
41*5c90c05cSAndroid Build Coastguard Worker #ifdef _WIN32
42*5c90c05cSAndroid Build Coastguard Worker #  ifndef S_IRUSR
43*5c90c05cSAndroid Build Coastguard Worker #    define S_IRUSR _S_IREAD
44*5c90c05cSAndroid Build Coastguard Worker #  endif
45*5c90c05cSAndroid Build Coastguard Worker #  ifndef S_IWUSR
46*5c90c05cSAndroid Build Coastguard Worker #    define S_IWUSR _S_IWRITE
47*5c90c05cSAndroid Build Coastguard Worker #  endif
48*5c90c05cSAndroid Build Coastguard Worker #  ifndef S_IRGRP
49*5c90c05cSAndroid Build Coastguard Worker #    define S_IRGRP 0
50*5c90c05cSAndroid Build Coastguard Worker #  endif
51*5c90c05cSAndroid Build Coastguard Worker #  ifndef S_IWGRP
52*5c90c05cSAndroid Build Coastguard Worker #    define S_IWGRP 0
53*5c90c05cSAndroid Build Coastguard Worker #  endif
54*5c90c05cSAndroid Build Coastguard Worker #  ifndef S_IROTH
55*5c90c05cSAndroid Build Coastguard Worker #    define S_IROTH 0
56*5c90c05cSAndroid Build Coastguard Worker #  endif
57*5c90c05cSAndroid Build Coastguard Worker #  ifndef S_IWOTH
58*5c90c05cSAndroid Build Coastguard Worker #    define S_IWOTH 0
59*5c90c05cSAndroid Build Coastguard Worker #  endif
60*5c90c05cSAndroid Build Coastguard Worker #endif
61*5c90c05cSAndroid Build Coastguard Worker 
62*5c90c05cSAndroid Build Coastguard Worker namespace {
63*5c90c05cSAndroid Build Coastguard Worker #ifdef _WIN32
64*5c90c05cSAndroid Build Coastguard Worker // Return type of read and write functions.
65*5c90c05cSAndroid Build Coastguard Worker using rwresult = int;
66*5c90c05cSAndroid Build Coastguard Worker 
67*5c90c05cSAndroid Build Coastguard Worker // On Windows the count argument to read and write is unsigned, so convert
68*5c90c05cSAndroid Build Coastguard Worker // it from size_t preventing integer overflow.
convert_rwcount(std::size_t count)69*5c90c05cSAndroid Build Coastguard Worker inline unsigned convert_rwcount(std::size_t count) {
70*5c90c05cSAndroid Build Coastguard Worker   return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
71*5c90c05cSAndroid Build Coastguard Worker }
72*5c90c05cSAndroid Build Coastguard Worker #elif FMT_USE_FCNTL
73*5c90c05cSAndroid Build Coastguard Worker // Return type of read and write functions.
74*5c90c05cSAndroid Build Coastguard Worker using rwresult = ssize_t;
75*5c90c05cSAndroid Build Coastguard Worker 
76*5c90c05cSAndroid Build Coastguard Worker inline std::size_t convert_rwcount(std::size_t count) { return count; }
77*5c90c05cSAndroid Build Coastguard Worker #endif
78*5c90c05cSAndroid Build Coastguard Worker }  // namespace
79*5c90c05cSAndroid Build Coastguard Worker 
80*5c90c05cSAndroid Build Coastguard Worker FMT_BEGIN_NAMESPACE
81*5c90c05cSAndroid Build Coastguard Worker 
82*5c90c05cSAndroid Build Coastguard Worker #ifdef _WIN32
83*5c90c05cSAndroid Build Coastguard Worker namespace detail {
84*5c90c05cSAndroid Build Coastguard Worker 
85*5c90c05cSAndroid Build Coastguard Worker class system_message {
86*5c90c05cSAndroid Build Coastguard Worker   system_message(const system_message&) = delete;
87*5c90c05cSAndroid Build Coastguard Worker   void operator=(const system_message&) = delete;
88*5c90c05cSAndroid Build Coastguard Worker 
89*5c90c05cSAndroid Build Coastguard Worker   unsigned long result_;
90*5c90c05cSAndroid Build Coastguard Worker   wchar_t* message_;
91*5c90c05cSAndroid Build Coastguard Worker 
is_whitespace(wchar_t c)92*5c90c05cSAndroid Build Coastguard Worker   static bool is_whitespace(wchar_t c) noexcept {
93*5c90c05cSAndroid Build Coastguard Worker     return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
94*5c90c05cSAndroid Build Coastguard Worker   }
95*5c90c05cSAndroid Build Coastguard Worker 
96*5c90c05cSAndroid Build Coastguard Worker  public:
system_message(unsigned long error_code)97*5c90c05cSAndroid Build Coastguard Worker   explicit system_message(unsigned long error_code)
98*5c90c05cSAndroid Build Coastguard Worker       : result_(0), message_(nullptr) {
99*5c90c05cSAndroid Build Coastguard Worker     result_ = FormatMessageW(
100*5c90c05cSAndroid Build Coastguard Worker         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
101*5c90c05cSAndroid Build Coastguard Worker             FORMAT_MESSAGE_IGNORE_INSERTS,
102*5c90c05cSAndroid Build Coastguard Worker         nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
103*5c90c05cSAndroid Build Coastguard Worker         reinterpret_cast<wchar_t*>(&message_), 0, nullptr);
104*5c90c05cSAndroid Build Coastguard Worker     if (result_ != 0) {
105*5c90c05cSAndroid Build Coastguard Worker       while (result_ != 0 && is_whitespace(message_[result_ - 1])) {
106*5c90c05cSAndroid Build Coastguard Worker         --result_;
107*5c90c05cSAndroid Build Coastguard Worker       }
108*5c90c05cSAndroid Build Coastguard Worker     }
109*5c90c05cSAndroid Build Coastguard Worker   }
~system_message()110*5c90c05cSAndroid Build Coastguard Worker   ~system_message() { LocalFree(message_); }
operator bool() const111*5c90c05cSAndroid Build Coastguard Worker   explicit operator bool() const noexcept { return result_ != 0; }
operator basic_string_view<wchar_t>() const112*5c90c05cSAndroid Build Coastguard Worker   operator basic_string_view<wchar_t>() const noexcept {
113*5c90c05cSAndroid Build Coastguard Worker     return basic_string_view<wchar_t>(message_, result_);
114*5c90c05cSAndroid Build Coastguard Worker   }
115*5c90c05cSAndroid Build Coastguard Worker };
116*5c90c05cSAndroid Build Coastguard Worker 
117*5c90c05cSAndroid Build Coastguard Worker class utf8_system_category final : public std::error_category {
118*5c90c05cSAndroid Build Coastguard Worker  public:
name() const119*5c90c05cSAndroid Build Coastguard Worker   const char* name() const noexcept override { return "system"; }
message(int error_code) const120*5c90c05cSAndroid Build Coastguard Worker   std::string message(int error_code) const override {
121*5c90c05cSAndroid Build Coastguard Worker     auto&& msg = system_message(error_code);
122*5c90c05cSAndroid Build Coastguard Worker     if (msg) {
123*5c90c05cSAndroid Build Coastguard Worker       auto utf8_message = to_utf8<wchar_t>();
124*5c90c05cSAndroid Build Coastguard Worker       if (utf8_message.convert(msg)) {
125*5c90c05cSAndroid Build Coastguard Worker         return utf8_message.str();
126*5c90c05cSAndroid Build Coastguard Worker       }
127*5c90c05cSAndroid Build Coastguard Worker     }
128*5c90c05cSAndroid Build Coastguard Worker     return "unknown error";
129*5c90c05cSAndroid Build Coastguard Worker   }
130*5c90c05cSAndroid Build Coastguard Worker };
131*5c90c05cSAndroid Build Coastguard Worker 
132*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
133*5c90c05cSAndroid Build Coastguard Worker 
system_category()134*5c90c05cSAndroid Build Coastguard Worker FMT_API const std::error_category& system_category() noexcept {
135*5c90c05cSAndroid Build Coastguard Worker   static const detail::utf8_system_category category;
136*5c90c05cSAndroid Build Coastguard Worker   return category;
137*5c90c05cSAndroid Build Coastguard Worker }
138*5c90c05cSAndroid Build Coastguard Worker 
vwindows_error(int err_code,string_view format_str,format_args args)139*5c90c05cSAndroid Build Coastguard Worker std::system_error vwindows_error(int err_code, string_view format_str,
140*5c90c05cSAndroid Build Coastguard Worker                                  format_args args) {
141*5c90c05cSAndroid Build Coastguard Worker   auto ec = std::error_code(err_code, system_category());
142*5c90c05cSAndroid Build Coastguard Worker   return std::system_error(ec, vformat(format_str, args));
143*5c90c05cSAndroid Build Coastguard Worker }
144*5c90c05cSAndroid Build Coastguard Worker 
format_windows_error(detail::buffer<char> & out,int error_code,const char * message)145*5c90c05cSAndroid Build Coastguard Worker void detail::format_windows_error(detail::buffer<char>& out, int error_code,
146*5c90c05cSAndroid Build Coastguard Worker                                   const char* message) noexcept {
147*5c90c05cSAndroid Build Coastguard Worker   FMT_TRY {
148*5c90c05cSAndroid Build Coastguard Worker     auto&& msg = system_message(error_code);
149*5c90c05cSAndroid Build Coastguard Worker     if (msg) {
150*5c90c05cSAndroid Build Coastguard Worker       auto utf8_message = to_utf8<wchar_t>();
151*5c90c05cSAndroid Build Coastguard Worker       if (utf8_message.convert(msg)) {
152*5c90c05cSAndroid Build Coastguard Worker         fmt::format_to(appender(out), FMT_STRING("{}: {}"), message,
153*5c90c05cSAndroid Build Coastguard Worker                        string_view(utf8_message));
154*5c90c05cSAndroid Build Coastguard Worker         return;
155*5c90c05cSAndroid Build Coastguard Worker       }
156*5c90c05cSAndroid Build Coastguard Worker     }
157*5c90c05cSAndroid Build Coastguard Worker   }
158*5c90c05cSAndroid Build Coastguard Worker   FMT_CATCH(...) {}
159*5c90c05cSAndroid Build Coastguard Worker   format_error_code(out, error_code, message);
160*5c90c05cSAndroid Build Coastguard Worker }
161*5c90c05cSAndroid Build Coastguard Worker 
report_windows_error(int error_code,const char * message)162*5c90c05cSAndroid Build Coastguard Worker void report_windows_error(int error_code, const char* message) noexcept {
163*5c90c05cSAndroid Build Coastguard Worker   do_report_error(detail::format_windows_error, error_code, message);
164*5c90c05cSAndroid Build Coastguard Worker }
165*5c90c05cSAndroid Build Coastguard Worker #endif  // _WIN32
166*5c90c05cSAndroid Build Coastguard Worker 
~buffered_file()167*5c90c05cSAndroid Build Coastguard Worker buffered_file::~buffered_file() noexcept {
168*5c90c05cSAndroid Build Coastguard Worker   if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
169*5c90c05cSAndroid Build Coastguard Worker     report_system_error(errno, "cannot close file");
170*5c90c05cSAndroid Build Coastguard Worker }
171*5c90c05cSAndroid Build Coastguard Worker 
buffered_file(cstring_view filename,cstring_view mode)172*5c90c05cSAndroid Build Coastguard Worker buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
173*5c90c05cSAndroid Build Coastguard Worker   FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
174*5c90c05cSAndroid Build Coastguard Worker                 nullptr);
175*5c90c05cSAndroid Build Coastguard Worker   if (!file_)
176*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"),
177*5c90c05cSAndroid Build Coastguard Worker                            filename.c_str()));
178*5c90c05cSAndroid Build Coastguard Worker }
179*5c90c05cSAndroid Build Coastguard Worker 
close()180*5c90c05cSAndroid Build Coastguard Worker void buffered_file::close() {
181*5c90c05cSAndroid Build Coastguard Worker   if (!file_) return;
182*5c90c05cSAndroid Build Coastguard Worker   int result = FMT_SYSTEM(fclose(file_));
183*5c90c05cSAndroid Build Coastguard Worker   file_ = nullptr;
184*5c90c05cSAndroid Build Coastguard Worker   if (result != 0)
185*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
186*5c90c05cSAndroid Build Coastguard Worker }
187*5c90c05cSAndroid Build Coastguard Worker 
descriptor() const188*5c90c05cSAndroid Build Coastguard Worker int buffered_file::descriptor() const {
189*5c90c05cSAndroid Build Coastguard Worker #ifdef FMT_HAS_SYSTEM
190*5c90c05cSAndroid Build Coastguard Worker   // fileno is a macro on OpenBSD.
191*5c90c05cSAndroid Build Coastguard Worker #  ifdef fileno
192*5c90c05cSAndroid Build Coastguard Worker #    undef fileno
193*5c90c05cSAndroid Build Coastguard Worker #  endif
194*5c90c05cSAndroid Build Coastguard Worker   int fd = FMT_POSIX_CALL(fileno(file_));
195*5c90c05cSAndroid Build Coastguard Worker #elif defined(_WIN32)
196*5c90c05cSAndroid Build Coastguard Worker   int fd = _fileno(file_);
197*5c90c05cSAndroid Build Coastguard Worker #else
198*5c90c05cSAndroid Build Coastguard Worker   int fd = fileno(file_);
199*5c90c05cSAndroid Build Coastguard Worker #endif
200*5c90c05cSAndroid Build Coastguard Worker   if (fd == -1)
201*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor")));
202*5c90c05cSAndroid Build Coastguard Worker   return fd;
203*5c90c05cSAndroid Build Coastguard Worker }
204*5c90c05cSAndroid Build Coastguard Worker 
205*5c90c05cSAndroid Build Coastguard Worker #if FMT_USE_FCNTL
206*5c90c05cSAndroid Build Coastguard Worker #  ifdef _WIN32
207*5c90c05cSAndroid Build Coastguard Worker using mode_t = int;
208*5c90c05cSAndroid Build Coastguard Worker #  endif
209*5c90c05cSAndroid Build Coastguard Worker 
210*5c90c05cSAndroid Build Coastguard Worker constexpr mode_t default_open_mode =
211*5c90c05cSAndroid Build Coastguard Worker     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
212*5c90c05cSAndroid Build Coastguard Worker 
file(cstring_view path,int oflag)213*5c90c05cSAndroid Build Coastguard Worker file::file(cstring_view path, int oflag) {
214*5c90c05cSAndroid Build Coastguard Worker #  if defined(_WIN32) && !defined(__MINGW32__)
215*5c90c05cSAndroid Build Coastguard Worker   fd_ = -1;
216*5c90c05cSAndroid Build Coastguard Worker   auto converted = detail::utf8_to_utf16(string_view(path.c_str()));
217*5c90c05cSAndroid Build Coastguard Worker   *this = file::open_windows_file(converted.c_str(), oflag);
218*5c90c05cSAndroid Build Coastguard Worker #  else
219*5c90c05cSAndroid Build Coastguard Worker   FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode)));
220*5c90c05cSAndroid Build Coastguard Worker   if (fd_ == -1)
221*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(
222*5c90c05cSAndroid Build Coastguard Worker         system_error(errno, FMT_STRING("cannot open file {}"), path.c_str()));
223*5c90c05cSAndroid Build Coastguard Worker #  endif
224*5c90c05cSAndroid Build Coastguard Worker }
225*5c90c05cSAndroid Build Coastguard Worker 
~file()226*5c90c05cSAndroid Build Coastguard Worker file::~file() noexcept {
227*5c90c05cSAndroid Build Coastguard Worker   // Don't retry close in case of EINTR!
228*5c90c05cSAndroid Build Coastguard Worker   // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
229*5c90c05cSAndroid Build Coastguard Worker   if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
230*5c90c05cSAndroid Build Coastguard Worker     report_system_error(errno, "cannot close file");
231*5c90c05cSAndroid Build Coastguard Worker }
232*5c90c05cSAndroid Build Coastguard Worker 
close()233*5c90c05cSAndroid Build Coastguard Worker void file::close() {
234*5c90c05cSAndroid Build Coastguard Worker   if (fd_ == -1) return;
235*5c90c05cSAndroid Build Coastguard Worker   // Don't retry close in case of EINTR!
236*5c90c05cSAndroid Build Coastguard Worker   // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
237*5c90c05cSAndroid Build Coastguard Worker   int result = FMT_POSIX_CALL(close(fd_));
238*5c90c05cSAndroid Build Coastguard Worker   fd_ = -1;
239*5c90c05cSAndroid Build Coastguard Worker   if (result != 0)
240*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
241*5c90c05cSAndroid Build Coastguard Worker }
242*5c90c05cSAndroid Build Coastguard Worker 
size() const243*5c90c05cSAndroid Build Coastguard Worker long long file::size() const {
244*5c90c05cSAndroid Build Coastguard Worker #  ifdef _WIN32
245*5c90c05cSAndroid Build Coastguard Worker   // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
246*5c90c05cSAndroid Build Coastguard Worker   // is less than 0x0500 as is the case with some default MinGW builds.
247*5c90c05cSAndroid Build Coastguard Worker   // Both functions support large file sizes.
248*5c90c05cSAndroid Build Coastguard Worker   DWORD size_upper = 0;
249*5c90c05cSAndroid Build Coastguard Worker   HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
250*5c90c05cSAndroid Build Coastguard Worker   DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
251*5c90c05cSAndroid Build Coastguard Worker   if (size_lower == INVALID_FILE_SIZE) {
252*5c90c05cSAndroid Build Coastguard Worker     DWORD error = GetLastError();
253*5c90c05cSAndroid Build Coastguard Worker     if (error != NO_ERROR)
254*5c90c05cSAndroid Build Coastguard Worker       FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
255*5c90c05cSAndroid Build Coastguard Worker   }
256*5c90c05cSAndroid Build Coastguard Worker   unsigned long long long_size = size_upper;
257*5c90c05cSAndroid Build Coastguard Worker   return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
258*5c90c05cSAndroid Build Coastguard Worker #  else
259*5c90c05cSAndroid Build Coastguard Worker   using Stat = struct stat;
260*5c90c05cSAndroid Build Coastguard Worker   Stat file_stat = Stat();
261*5c90c05cSAndroid Build Coastguard Worker   if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
262*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes")));
263*5c90c05cSAndroid Build Coastguard Worker   static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
264*5c90c05cSAndroid Build Coastguard Worker                 "return type of file::size is not large enough");
265*5c90c05cSAndroid Build Coastguard Worker   return file_stat.st_size;
266*5c90c05cSAndroid Build Coastguard Worker #  endif
267*5c90c05cSAndroid Build Coastguard Worker }
268*5c90c05cSAndroid Build Coastguard Worker 
read(void * buffer,std::size_t count)269*5c90c05cSAndroid Build Coastguard Worker std::size_t file::read(void* buffer, std::size_t count) {
270*5c90c05cSAndroid Build Coastguard Worker   rwresult result = 0;
271*5c90c05cSAndroid Build Coastguard Worker   FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
272*5c90c05cSAndroid Build Coastguard Worker   if (result < 0)
273*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot read from file")));
274*5c90c05cSAndroid Build Coastguard Worker   return detail::to_unsigned(result);
275*5c90c05cSAndroid Build Coastguard Worker }
276*5c90c05cSAndroid Build Coastguard Worker 
write(const void * buffer,std::size_t count)277*5c90c05cSAndroid Build Coastguard Worker std::size_t file::write(const void* buffer, std::size_t count) {
278*5c90c05cSAndroid Build Coastguard Worker   rwresult result = 0;
279*5c90c05cSAndroid Build Coastguard Worker   FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
280*5c90c05cSAndroid Build Coastguard Worker   if (result < 0)
281*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
282*5c90c05cSAndroid Build Coastguard Worker   return detail::to_unsigned(result);
283*5c90c05cSAndroid Build Coastguard Worker }
284*5c90c05cSAndroid Build Coastguard Worker 
dup(int fd)285*5c90c05cSAndroid Build Coastguard Worker file file::dup(int fd) {
286*5c90c05cSAndroid Build Coastguard Worker   // Don't retry as dup doesn't return EINTR.
287*5c90c05cSAndroid Build Coastguard Worker   // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
288*5c90c05cSAndroid Build Coastguard Worker   int new_fd = FMT_POSIX_CALL(dup(fd));
289*5c90c05cSAndroid Build Coastguard Worker   if (new_fd == -1)
290*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(
291*5c90c05cSAndroid Build Coastguard Worker         errno, FMT_STRING("cannot duplicate file descriptor {}"), fd));
292*5c90c05cSAndroid Build Coastguard Worker   return file(new_fd);
293*5c90c05cSAndroid Build Coastguard Worker }
294*5c90c05cSAndroid Build Coastguard Worker 
dup2(int fd)295*5c90c05cSAndroid Build Coastguard Worker void file::dup2(int fd) {
296*5c90c05cSAndroid Build Coastguard Worker   int result = 0;
297*5c90c05cSAndroid Build Coastguard Worker   FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
298*5c90c05cSAndroid Build Coastguard Worker   if (result == -1) {
299*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(
300*5c90c05cSAndroid Build Coastguard Worker         errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_,
301*5c90c05cSAndroid Build Coastguard Worker         fd));
302*5c90c05cSAndroid Build Coastguard Worker   }
303*5c90c05cSAndroid Build Coastguard Worker }
304*5c90c05cSAndroid Build Coastguard Worker 
dup2(int fd,std::error_code & ec)305*5c90c05cSAndroid Build Coastguard Worker void file::dup2(int fd, std::error_code& ec) noexcept {
306*5c90c05cSAndroid Build Coastguard Worker   int result = 0;
307*5c90c05cSAndroid Build Coastguard Worker   FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
308*5c90c05cSAndroid Build Coastguard Worker   if (result == -1) ec = std::error_code(errno, std::generic_category());
309*5c90c05cSAndroid Build Coastguard Worker }
310*5c90c05cSAndroid Build Coastguard Worker 
fdopen(const char * mode)311*5c90c05cSAndroid Build Coastguard Worker buffered_file file::fdopen(const char* mode) {
312*5c90c05cSAndroid Build Coastguard Worker // Don't retry as fdopen doesn't return EINTR.
313*5c90c05cSAndroid Build Coastguard Worker #  if defined(__MINGW32__) && defined(_POSIX_)
314*5c90c05cSAndroid Build Coastguard Worker   FILE* f = ::fdopen(fd_, mode);
315*5c90c05cSAndroid Build Coastguard Worker #  else
316*5c90c05cSAndroid Build Coastguard Worker   FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
317*5c90c05cSAndroid Build Coastguard Worker #  endif
318*5c90c05cSAndroid Build Coastguard Worker   if (!f) {
319*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(
320*5c90c05cSAndroid Build Coastguard Worker         errno, FMT_STRING("cannot associate stream with file descriptor")));
321*5c90c05cSAndroid Build Coastguard Worker   }
322*5c90c05cSAndroid Build Coastguard Worker   buffered_file bf(f);
323*5c90c05cSAndroid Build Coastguard Worker   fd_ = -1;
324*5c90c05cSAndroid Build Coastguard Worker   return bf;
325*5c90c05cSAndroid Build Coastguard Worker }
326*5c90c05cSAndroid Build Coastguard Worker 
327*5c90c05cSAndroid Build Coastguard Worker #  if defined(_WIN32) && !defined(__MINGW32__)
open_windows_file(wcstring_view path,int oflag)328*5c90c05cSAndroid Build Coastguard Worker file file::open_windows_file(wcstring_view path, int oflag) {
329*5c90c05cSAndroid Build Coastguard Worker   int fd = -1;
330*5c90c05cSAndroid Build Coastguard Worker   auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode);
331*5c90c05cSAndroid Build Coastguard Worker   if (fd == -1) {
332*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"),
333*5c90c05cSAndroid Build Coastguard Worker                            detail::to_utf8<wchar_t>(path.c_str()).c_str()));
334*5c90c05cSAndroid Build Coastguard Worker   }
335*5c90c05cSAndroid Build Coastguard Worker   return file(fd);
336*5c90c05cSAndroid Build Coastguard Worker }
337*5c90c05cSAndroid Build Coastguard Worker #  endif
338*5c90c05cSAndroid Build Coastguard Worker 
pipe()339*5c90c05cSAndroid Build Coastguard Worker pipe::pipe() {
340*5c90c05cSAndroid Build Coastguard Worker   int fds[2] = {};
341*5c90c05cSAndroid Build Coastguard Worker #  ifdef _WIN32
342*5c90c05cSAndroid Build Coastguard Worker   // Make the default pipe capacity same as on Linux 2.6.11+.
343*5c90c05cSAndroid Build Coastguard Worker   enum { DEFAULT_CAPACITY = 65536 };
344*5c90c05cSAndroid Build Coastguard Worker   int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
345*5c90c05cSAndroid Build Coastguard Worker #  else
346*5c90c05cSAndroid Build Coastguard Worker   // Don't retry as the pipe function doesn't return EINTR.
347*5c90c05cSAndroid Build Coastguard Worker   // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
348*5c90c05cSAndroid Build Coastguard Worker   int result = FMT_POSIX_CALL(pipe(fds));
349*5c90c05cSAndroid Build Coastguard Worker #  endif
350*5c90c05cSAndroid Build Coastguard Worker   if (result != 0)
351*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe")));
352*5c90c05cSAndroid Build Coastguard Worker   // The following assignments don't throw.
353*5c90c05cSAndroid Build Coastguard Worker   read_end = file(fds[0]);
354*5c90c05cSAndroid Build Coastguard Worker   write_end = file(fds[1]);
355*5c90c05cSAndroid Build Coastguard Worker }
356*5c90c05cSAndroid Build Coastguard Worker 
357*5c90c05cSAndroid Build Coastguard Worker #  if !defined(__MSDOS__)
getpagesize()358*5c90c05cSAndroid Build Coastguard Worker long getpagesize() {
359*5c90c05cSAndroid Build Coastguard Worker #    ifdef _WIN32
360*5c90c05cSAndroid Build Coastguard Worker   SYSTEM_INFO si;
361*5c90c05cSAndroid Build Coastguard Worker   GetSystemInfo(&si);
362*5c90c05cSAndroid Build Coastguard Worker   return si.dwPageSize;
363*5c90c05cSAndroid Build Coastguard Worker #    else
364*5c90c05cSAndroid Build Coastguard Worker #      ifdef _WRS_KERNEL
365*5c90c05cSAndroid Build Coastguard Worker   long size = FMT_POSIX_CALL(getpagesize());
366*5c90c05cSAndroid Build Coastguard Worker #      else
367*5c90c05cSAndroid Build Coastguard Worker   long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
368*5c90c05cSAndroid Build Coastguard Worker #      endif
369*5c90c05cSAndroid Build Coastguard Worker 
370*5c90c05cSAndroid Build Coastguard Worker   if (size < 0)
371*5c90c05cSAndroid Build Coastguard Worker     FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size")));
372*5c90c05cSAndroid Build Coastguard Worker   return size;
373*5c90c05cSAndroid Build Coastguard Worker #    endif
374*5c90c05cSAndroid Build Coastguard Worker }
375*5c90c05cSAndroid Build Coastguard Worker #  endif
376*5c90c05cSAndroid Build Coastguard Worker 
grow(buffer<char> & buf,size_t)377*5c90c05cSAndroid Build Coastguard Worker void ostream::grow(buffer<char>& buf, size_t) {
378*5c90c05cSAndroid Build Coastguard Worker   if (buf.size() == buf.capacity()) static_cast<ostream&>(buf).flush();
379*5c90c05cSAndroid Build Coastguard Worker }
380*5c90c05cSAndroid Build Coastguard Worker 
ostream(cstring_view path,const detail::ostream_params & params)381*5c90c05cSAndroid Build Coastguard Worker ostream::ostream(cstring_view path, const detail::ostream_params& params)
382*5c90c05cSAndroid Build Coastguard Worker     : buffer<char>(grow), file_(path, params.oflag) {
383*5c90c05cSAndroid Build Coastguard Worker   set(new char[params.buffer_size], params.buffer_size);
384*5c90c05cSAndroid Build Coastguard Worker }
385*5c90c05cSAndroid Build Coastguard Worker 
ostream(ostream && other)386*5c90c05cSAndroid Build Coastguard Worker ostream::ostream(ostream&& other) noexcept
387*5c90c05cSAndroid Build Coastguard Worker     : buffer<char>(grow, other.data(), other.size(), other.capacity()),
388*5c90c05cSAndroid Build Coastguard Worker       file_(std::move(other.file_)) {
389*5c90c05cSAndroid Build Coastguard Worker   other.clear();
390*5c90c05cSAndroid Build Coastguard Worker   other.set(nullptr, 0);
391*5c90c05cSAndroid Build Coastguard Worker }
392*5c90c05cSAndroid Build Coastguard Worker 
~ostream()393*5c90c05cSAndroid Build Coastguard Worker ostream::~ostream() {
394*5c90c05cSAndroid Build Coastguard Worker   flush();
395*5c90c05cSAndroid Build Coastguard Worker   delete[] data();
396*5c90c05cSAndroid Build Coastguard Worker }
397*5c90c05cSAndroid Build Coastguard Worker #endif  // FMT_USE_FCNTL
398*5c90c05cSAndroid Build Coastguard Worker FMT_END_NAMESPACE
399