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