1 //===-- runtime/io-error.cpp ----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
12 #include "flang/Runtime/magic-numbers.h"
18 namespace Fortran::runtime::io
{
20 void IoErrorHandler::SignalError(int iostatOrErrno
, const char *msg
, ...) {
21 if (iostatOrErrno
== IostatEnd
&& (flags_
& hasEnd
)) {
22 if (ioStat_
== IostatOk
|| ioStat_
< IostatEnd
) {
25 } else if (iostatOrErrno
== IostatEor
&& (flags_
& hasEor
)) {
26 if (ioStat_
== IostatOk
|| ioStat_
< IostatEor
) {
27 ioStat_
= IostatEor
; // least priority
29 } else if (iostatOrErrno
!= IostatOk
) {
30 if (flags_
& (hasIoStat
| hasIoMsg
| hasErr
)) {
32 ioStat_
= iostatOrErrno
; // priority over END=/EOR=
33 if (msg
&& (flags_
& hasIoMsg
)) {
37 std::vsnprintf(buffer
, sizeof buffer
, msg
, ap
);
38 ioMsg_
= SaveDefaultCharacter(buffer
, std::strlen(buffer
) + 1, *this);
47 } else if (const char *errstr
{IostatErrorString(iostatOrErrno
)}) {
50 Crash("I/O error (errno=%d): %s", iostatOrErrno
,
51 std::strerror(iostatOrErrno
));
56 void IoErrorHandler::SignalError(int iostatOrErrno
) {
57 SignalError(iostatOrErrno
, nullptr);
60 void IoErrorHandler::Forward(
61 int ioStatOrErrno
, const char *msg
, std::size_t length
) {
62 if (ioStat_
!= IostatOk
&& msg
&& (flags_
& hasIoMsg
)) {
63 ioMsg_
= SaveDefaultCharacter(msg
, length
, *this);
65 if (ioStatOrErrno
!= IostatOk
&& msg
) {
66 SignalError(ioStatOrErrno
, "%.*s", static_cast<int>(length
), msg
);
68 SignalError(ioStatOrErrno
);
72 void IoErrorHandler::SignalErrno() { SignalError(errno
); }
74 void IoErrorHandler::SignalEnd() { SignalError(IostatEnd
); }
76 void IoErrorHandler::SignalEor() { SignalError(IostatEor
); }
78 void IoErrorHandler::SignalPendingError() {
79 int error
{pendingError_
};
80 pendingError_
= IostatOk
;
84 bool IoErrorHandler::GetIoMsg(char *buffer
, std::size_t bufferLength
) {
85 const char *msg
{ioMsg_
.get()};
87 msg
= IostatErrorString(ioStat_
== IostatOk
? pendingError_
: ioStat_
);
90 ToFortranDefaultCharacter(buffer
, bufferLength
, msg
);
94 // Following code is taken from llvm/lib/Support/Errno.cpp
95 // in LLVM v9.0.1 with inadequate modification for Fortran,
99 // strerror_r is thread-safe.
100 #if defined(__GLIBC__) && defined(_GNU_SOURCE)
101 // glibc defines its own incompatible version of strerror_r
102 // which may not use the buffer supplied.
103 msg
= ::strerror_r(ioStat_
, buffer
, bufferLength
);
105 ok
= ::strerror_r(ioStat_
, buffer
, bufferLength
) == 0;
107 #elif HAVE_DECL_STRERROR_S // "Windows Secure API"
108 ok
= ::strerror_s(buffer
, bufferLength
, ioStat_
) == 0;
110 // Copy the thread un-safe result of strerror into
111 // the buffer as fast as possible to minimize impact
112 // of collision of strerror in multiple threads.
113 msg
= strerror(ioStat_
);
115 // Strange that this system doesn't even have strerror
119 ToFortranDefaultCharacter(buffer
, bufferLength
, msg
);
122 std::size_t copied
{std::strlen(buffer
)};
123 if (copied
< bufferLength
) {
124 std::memset(buffer
+ copied
, ' ', bufferLength
- copied
);
131 } // namespace Fortran::runtime::io