1 //===-- runtime/io-error.cpp ------------------------------------*- C++ -*-===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "io-error.h" 10 #include "magic-numbers.h" 11 #include "tools.h" 12 #include <cerrno> 13 #include <cstdarg> 14 #include <cstdio> 15 #include <cstring> 16 17 namespace Fortran::runtime::io { 18 19 void IoErrorHandler::Begin(const char *sourceFileName, int sourceLine) { 20 flags_ = 0; 21 ioStat_ = 0; 22 ioMsg_.reset(); 23 SetLocation(sourceFileName, sourceLine); 24 } 25 26 void IoErrorHandler::SignalError(int iostatOrErrno, const char *msg, ...) { 27 if (iostatOrErrno == IostatEnd && (flags_ & hasEnd)) { 28 if (!ioStat_ || ioStat_ < IostatEnd) { 29 ioStat_ = IostatEnd; 30 } 31 } else if (iostatOrErrno == IostatEor && (flags_ & hasEor)) { 32 if (!ioStat_ || ioStat_ < IostatEor) { 33 ioStat_ = IostatEor; // least priority 34 } 35 } else if (iostatOrErrno != IostatOk) { 36 if (flags_ & (hasIoStat | hasErr)) { 37 if (ioStat_ <= 0) { 38 ioStat_ = iostatOrErrno; // priority over END=/EOR= 39 if (msg && (flags_ & hasIoMsg)) { 40 char buffer[256]; 41 va_list ap; 42 va_start(ap, msg); 43 std::vsnprintf(buffer, sizeof buffer, msg, ap); 44 ioMsg_ = SaveDefaultCharacter(buffer, std::strlen(buffer) + 1, *this); 45 } 46 } 47 } else if (msg) { 48 va_list ap; 49 va_start(ap, msg); 50 CrashArgs(msg, ap); 51 } else if (const char *errstr{IostatErrorString(iostatOrErrno)}) { 52 Crash(errstr); 53 } else { 54 Crash("I/O error (errno=%d): %s", iostatOrErrno, 55 std::strerror(iostatOrErrno)); 56 } 57 } 58 } 59 60 void IoErrorHandler::SignalError(int iostatOrErrno) { 61 SignalError(iostatOrErrno, nullptr); 62 } 63 64 void IoErrorHandler::SignalErrno() { SignalError(errno); } 65 66 void IoErrorHandler::SignalEnd() { SignalError(IostatEnd); } 67 68 void IoErrorHandler::SignalEor() { SignalError(IostatEor); } 69 70 bool IoErrorHandler::GetIoMsg(char *buffer, std::size_t bufferLength) { 71 const char *msg{ioMsg_.get()}; 72 if (!msg) { 73 msg = IostatErrorString(ioStat_); 74 } 75 if (msg) { 76 ToFortranDefaultCharacter(buffer, bufferLength, msg); 77 return true; 78 } 79 return ::strerror_r(ioStat_, buffer, bufferLength) == 0; 80 } 81 } 82