llvm-project
1314 строк · 45.1 Кб
1//===-- runtime/io-api.cpp ------------------------------------------------===//
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// Implements the I/O statement API
10
11// template function BeginExternalListIo<> is in runtime/io-api-common.h.
12// APIs BeginExternalListOutput, OutputInteger{8,16,32,64,128},
13// OutputReal{32,64}, OutputComplex{32,64}, OutputAscii, & EndIoStatement()
14// are in runtime/io-api-minimal.cpp.
15
16#include "flang/Runtime/io-api.h"17#include "descriptor-io.h"18#include "edit-input.h"19#include "edit-output.h"20#include "environment.h"21#include "format.h"22#include "io-api-common.h"23#include "io-stmt.h"24#include "terminator.h"25#include "tools.h"26#include "unit.h"27#include "flang/Common/optional.h"28#include "flang/Runtime/descriptor.h"29#include "flang/Runtime/memory.h"30#include <cstdlib>31#include <memory>32
33namespace Fortran::runtime::io {34RT_EXT_API_GROUP_BEGIN
35
36RT_API_ATTRS const char *InquiryKeywordHashDecode(37char *buffer, std::size_t n, InquiryKeywordHash hash) {38if (n < 1) {39return nullptr;40}41char *p{buffer + n};42*--p = '\0';43while (hash > 1) {44if (p < buffer) {45return nullptr;46}47*--p = 'A' + (hash % 26);48hash /= 26;49}50return hash == 1 ? p : nullptr;51}
52
53template <Direction DIR>54RT_API_ATTRS Cookie BeginInternalArrayListIO(const Descriptor &descriptor,55void ** /*scratchArea*/, std::size_t /*scratchBytes*/,56const char *sourceFile, int sourceLine) {57Terminator oom{sourceFile, sourceLine};58return &New<InternalListIoStatementState<DIR>>{oom}(59descriptor, sourceFile, sourceLine)60.release()61->ioStatementState();62}
63
64Cookie IODEF(BeginInternalArrayListOutput)(const Descriptor &descriptor,65void **scratchArea, std::size_t scratchBytes, const char *sourceFile,66int sourceLine) {67return BeginInternalArrayListIO<Direction::Output>(68descriptor, scratchArea, scratchBytes, sourceFile, sourceLine);69}
70
71Cookie IODEF(BeginInternalArrayListInput)(const Descriptor &descriptor,72void **scratchArea, std::size_t scratchBytes, const char *sourceFile,73int sourceLine) {74return BeginInternalArrayListIO<Direction::Input>(75descriptor, scratchArea, scratchBytes, sourceFile, sourceLine);76}
77
78template <Direction DIR>79RT_API_ATTRS Cookie BeginInternalArrayFormattedIO(const Descriptor &descriptor,80const char *format, std::size_t formatLength,81const Descriptor *formatDescriptor, void ** /*scratchArea*/,82std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {83Terminator oom{sourceFile, sourceLine};84return &New<InternalFormattedIoStatementState<DIR>>{oom}(descriptor, format,85formatLength, formatDescriptor, sourceFile, sourceLine)86.release()87->ioStatementState();88}
89
90Cookie IODEF(BeginInternalArrayFormattedOutput)(const Descriptor &descriptor,91const char *format, std::size_t formatLength,92const Descriptor *formatDescriptor, void **scratchArea,93std::size_t scratchBytes, const char *sourceFile, int sourceLine) {94return BeginInternalArrayFormattedIO<Direction::Output>(descriptor, format,95formatLength, formatDescriptor, scratchArea, scratchBytes, sourceFile,96sourceLine);97}
98
99Cookie IODEF(BeginInternalArrayFormattedInput)(const Descriptor &descriptor,100const char *format, std::size_t formatLength,101const Descriptor *formatDescriptor, void **scratchArea,102std::size_t scratchBytes, const char *sourceFile, int sourceLine) {103return BeginInternalArrayFormattedIO<Direction::Input>(descriptor, format,104formatLength, formatDescriptor, scratchArea, scratchBytes, sourceFile,105sourceLine);106}
107
108template <Direction DIR>109RT_API_ATTRS Cookie BeginInternalListIO(110std::conditional_t<DIR == Direction::Input, const char, char> *internal,111std::size_t internalLength, void ** /*scratchArea*/,112std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {113Terminator oom{sourceFile, sourceLine};114return &New<InternalListIoStatementState<DIR>>{oom}(115internal, internalLength, sourceFile, sourceLine)116.release()117->ioStatementState();118}
119
120Cookie IODEF(BeginInternalListOutput)(char *internal,121std::size_t internalLength, void **scratchArea, std::size_t scratchBytes,122const char *sourceFile, int sourceLine) {123return BeginInternalListIO<Direction::Output>(internal, internalLength,124scratchArea, scratchBytes, sourceFile, sourceLine);125}
126
127Cookie IODEF(BeginInternalListInput)(const char *internal,128std::size_t internalLength, void **scratchArea, std::size_t scratchBytes,129const char *sourceFile, int sourceLine) {130return BeginInternalListIO<Direction::Input>(internal, internalLength,131scratchArea, scratchBytes, sourceFile, sourceLine);132}
133
134template <Direction DIR>135RT_API_ATTRS Cookie BeginInternalFormattedIO(136std::conditional_t<DIR == Direction::Input, const char, char> *internal,137std::size_t internalLength, const char *format, std::size_t formatLength,138const Descriptor *formatDescriptor, void ** /*scratchArea*/,139std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {140Terminator oom{sourceFile, sourceLine};141return &New<InternalFormattedIoStatementState<DIR>>{oom}(internal,142internalLength, format, formatLength, formatDescriptor, sourceFile,143sourceLine)144.release()145->ioStatementState();146}
147
148Cookie IODEF(BeginInternalFormattedOutput)(char *internal,149std::size_t internalLength, const char *format, std::size_t formatLength,150const Descriptor *formatDescriptor, void **scratchArea,151std::size_t scratchBytes, const char *sourceFile, int sourceLine) {152return BeginInternalFormattedIO<Direction::Output>(internal, internalLength,153format, formatLength, formatDescriptor, scratchArea, scratchBytes,154sourceFile, sourceLine);155}
156
157Cookie IODEF(BeginInternalFormattedInput)(const char *internal,158std::size_t internalLength, const char *format, std::size_t formatLength,159const Descriptor *formatDescriptor, void **scratchArea,160std::size_t scratchBytes, const char *sourceFile, int sourceLine) {161return BeginInternalFormattedIO<Direction::Input>(internal, internalLength,162format, formatLength, formatDescriptor, scratchArea, scratchBytes,163sourceFile, sourceLine);164}
165
166Cookie IODEF(BeginExternalListInput)(167ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {168return BeginExternalListIO<Direction::Input, ExternalListIoStatementState>(169unitNumber, sourceFile, sourceLine);170}
171
172template <Direction DIR>173RT_API_ATTRS Cookie BeginExternalFormattedIO(const char *format,174std::size_t formatLength, const Descriptor *formatDescriptor,175ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {176Terminator terminator{sourceFile, sourceLine};177Cookie errorCookie{nullptr};178ExternalFileUnit *unit{GetOrCreateUnit(179unitNumber, DIR, false /*!unformatted*/, terminator, errorCookie)};180if (!unit) {181return errorCookie;182}183Iostat iostat{IostatOk};184if (!unit->isUnformatted.has_value()) {185unit->isUnformatted = false;186}187if (*unit->isUnformatted) {188iostat = IostatFormattedIoOnUnformattedUnit;189}190if (ChildIo * child{unit->GetChildIo()}) {191if (iostat == IostatOk) {192iostat = child->CheckFormattingAndDirection(false, DIR);193}194if (iostat == IostatOk) {195return &child->BeginIoStatement<ChildFormattedIoStatementState<DIR>>(196*child, format, formatLength, formatDescriptor, sourceFile,197sourceLine);198} else {199return &child->BeginIoStatement<ErroneousIoStatementState>(200iostat, nullptr /* no unit */, sourceFile, sourceLine);201}202} else {203if (iostat == IostatOk) {204iostat = unit->SetDirection(DIR);205}206if (iostat == IostatOk) {207return &unit->BeginIoStatement<ExternalFormattedIoStatementState<DIR>>(208terminator, *unit, format, formatLength, formatDescriptor, sourceFile,209sourceLine);210} else {211return &unit->BeginIoStatement<ErroneousIoStatementState>(212terminator, iostat, unit, sourceFile, sourceLine);213}214}215}
216
217Cookie IODEF(BeginExternalFormattedOutput)(const char *format,218std::size_t formatLength, const Descriptor *formatDescriptor,219ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {220return BeginExternalFormattedIO<Direction::Output>(format, formatLength,221formatDescriptor, unitNumber, sourceFile, sourceLine);222}
223
224Cookie IODEF(BeginExternalFormattedInput)(const char *format,225std::size_t formatLength, const Descriptor *formatDescriptor,226ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {227return BeginExternalFormattedIO<Direction::Input>(format, formatLength,228formatDescriptor, unitNumber, sourceFile, sourceLine);229}
230
231template <Direction DIR>232RT_API_ATTRS Cookie BeginUnformattedIO(233ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {234Terminator terminator{sourceFile, sourceLine};235Cookie errorCookie{nullptr};236ExternalFileUnit *unit{GetOrCreateUnit(237unitNumber, DIR, true /*unformatted*/, terminator, errorCookie)};238if (!unit) {239return errorCookie;240}241Iostat iostat{IostatOk};242if (!unit->isUnformatted.has_value()) {243unit->isUnformatted = true;244}245if (!*unit->isUnformatted) {246iostat = IostatUnformattedIoOnFormattedUnit;247}248if (ChildIo * child{unit->GetChildIo()}) {249if (iostat == IostatOk) {250iostat = child->CheckFormattingAndDirection(true, DIR);251}252if (iostat == IostatOk) {253return &child->BeginIoStatement<ChildUnformattedIoStatementState<DIR>>(254*child, sourceFile, sourceLine);255} else {256return &child->BeginIoStatement<ErroneousIoStatementState>(257iostat, nullptr /* no unit */, sourceFile, sourceLine);258}259} else {260if (iostat == IostatOk) {261iostat = unit->SetDirection(DIR);262}263if (iostat == IostatOk) {264IoStatementState &io{265unit->BeginIoStatement<ExternalUnformattedIoStatementState<DIR>>(266terminator, *unit, sourceFile, sourceLine)};267if constexpr (DIR == Direction::Output) {268if (unit->access == Access::Sequential) {269// Create space for (sub)record header to be completed by270// ExternalFileUnit::AdvanceRecord()271unit->recordLength.reset(); // in case of prior BACKSPACE272io.Emit("\0\0\0\0", 4); // placeholder for record length header273}274}275return &io;276} else {277return &unit->BeginIoStatement<ErroneousIoStatementState>(278terminator, iostat, unit, sourceFile, sourceLine);279}280}281}
282
283Cookie IODEF(BeginUnformattedOutput)(284ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {285return BeginUnformattedIO<Direction::Output>(286unitNumber, sourceFile, sourceLine);287}
288
289Cookie IODEF(BeginUnformattedInput)(290ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {291return BeginUnformattedIO<Direction::Input>(292unitNumber, sourceFile, sourceLine);293}
294
295Cookie IODEF(BeginOpenUnit)( // OPEN(without NEWUNIT=)296ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {297Terminator terminator{sourceFile, sourceLine};298bool wasExtant{false};299if (ExternalFileUnit *300unit{ExternalFileUnit::LookUpOrCreate(301unitNumber, terminator, wasExtant)}) {302if (ChildIo * child{unit->GetChildIo()}) {303return &child->BeginIoStatement<ErroneousIoStatementState>(304IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,305sourceLine);306} else {307return &unit->BeginIoStatement<OpenStatementState>(terminator, *unit,308wasExtant, false /*not NEWUNIT=*/, sourceFile, sourceLine);309}310} else {311return NoopUnit(terminator, unitNumber, IostatBadUnitNumber);312}313}
314
315Cookie IODEF(BeginOpenNewUnit)( // OPEN(NEWUNIT=j)316const char *sourceFile, int sourceLine) {317Terminator terminator{sourceFile, sourceLine};318ExternalFileUnit &unit{319ExternalFileUnit::NewUnit(terminator, false /*not child I/O*/)};320return &unit.BeginIoStatement<OpenStatementState>(terminator, unit,321false /*was an existing file*/, true /*NEWUNIT=*/, sourceFile,322sourceLine);323}
324
325Cookie IODEF(BeginWait)(ExternalUnit unitNumber, AsynchronousId id,326const char *sourceFile, int sourceLine) {327Terminator terminator{sourceFile, sourceLine};328if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {329if (unit->Wait(id)) {330return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,331*unit, ExternalMiscIoStatementState::Wait, sourceFile, sourceLine);332} else {333return &unit->BeginIoStatement<ErroneousIoStatementState>(334terminator, IostatBadWaitId, unit, sourceFile, sourceLine);335}336} else {337return NoopUnit(338terminator, unitNumber, id == 0 ? IostatOk : IostatBadWaitUnit);339}340}
341Cookie IODEF(BeginWaitAll)(342ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {343return IONAME(BeginWait)(unitNumber, 0 /*no ID=*/, sourceFile, sourceLine);344}
345
346Cookie IODEF(BeginClose)(347ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {348Terminator terminator{sourceFile, sourceLine};349if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {350if (ChildIo * child{unit->GetChildIo()}) {351return &child->BeginIoStatement<ErroneousIoStatementState>(352IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,353sourceLine);354}355}356if (ExternalFileUnit * unit{ExternalFileUnit::LookUpForClose(unitNumber)}) {357return &unit->BeginIoStatement<CloseStatementState>(358terminator, *unit, sourceFile, sourceLine);359} else {360// CLOSE(UNIT=bad unit) is just a no-op361return NoopUnit(terminator, unitNumber);362}363}
364
365Cookie IODEF(BeginFlush)(366ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {367Terminator terminator{sourceFile, sourceLine};368if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {369if (ChildIo * child{unit->GetChildIo()}) {370return &child->BeginIoStatement<ExternalMiscIoStatementState>(371*unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine);372} else {373return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,374*unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine);375}376} else {377// FLUSH(UNIT=bad unit) is an error; an unconnected unit is a no-op378return NoopUnit(terminator, unitNumber,379unitNumber >= 0 ? IostatOk : IostatBadFlushUnit);380}381}
382
383Cookie IODEF(BeginBackspace)(384ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {385Terminator terminator{sourceFile, sourceLine};386if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {387if (ChildIo * child{unit->GetChildIo()}) {388return &child->BeginIoStatement<ErroneousIoStatementState>(389IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,390sourceLine);391} else {392return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,393*unit, ExternalMiscIoStatementState::Backspace, sourceFile,394sourceLine);395}396} else {397return NoopUnit(terminator, unitNumber, IostatBadBackspaceUnit);398}399}
400
401Cookie IODEF(BeginEndfile)(402ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {403Terminator terminator{sourceFile, sourceLine};404Cookie errorCookie{nullptr};405if (ExternalFileUnit *406unit{GetOrCreateUnit(unitNumber, Direction::Output,407Fortran::common::nullopt, terminator, errorCookie)}) {408if (ChildIo * child{unit->GetChildIo()}) {409return &child->BeginIoStatement<ErroneousIoStatementState>(410IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,411sourceLine);412} else {413return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,414*unit, ExternalMiscIoStatementState::Endfile, sourceFile, sourceLine);415}416} else {417return errorCookie;418}419}
420
421Cookie IODEF(BeginRewind)(422ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {423Terminator terminator{sourceFile, sourceLine};424Cookie errorCookie{nullptr};425if (ExternalFileUnit *426unit{GetOrCreateUnit(unitNumber, Direction::Input,427Fortran::common::nullopt, terminator, errorCookie)}) {428if (ChildIo * child{unit->GetChildIo()}) {429return &child->BeginIoStatement<ErroneousIoStatementState>(430IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,431sourceLine);432} else {433return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,434*unit, ExternalMiscIoStatementState::Rewind, sourceFile, sourceLine);435}436} else {437return errorCookie;438}439}
440
441Cookie IODEF(BeginInquireUnit)(442ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {443Terminator terminator{sourceFile, sourceLine};444if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {445if (ChildIo * child{unit->GetChildIo()}) {446return &child->BeginIoStatement<InquireUnitState>(447*unit, sourceFile, sourceLine);448} else {449return &unit->BeginIoStatement<InquireUnitState>(450terminator, *unit, sourceFile, sourceLine);451}452} else {453// INQUIRE(UNIT=unrecognized unit)454return &New<InquireNoUnitState>{terminator}(455sourceFile, sourceLine, unitNumber)456.release()457->ioStatementState();458}459}
460
461Cookie IODEF(BeginInquireFile)(const char *path, std::size_t pathLength,462const char *sourceFile, int sourceLine) {463Terminator terminator{sourceFile, sourceLine};464auto trimmed{SaveDefaultCharacter(465path, TrimTrailingSpaces(path, pathLength), terminator)};466if (ExternalFileUnit *467unit{ExternalFileUnit::LookUp(468trimmed.get(), Fortran::runtime::strlen(trimmed.get()))}) {469// INQUIRE(FILE=) to a connected unit470if (ChildIo * child{unit->GetChildIo()}) {471return &child->BeginIoStatement<InquireUnitState>(472*unit, sourceFile, sourceLine);473} else {474return &unit->BeginIoStatement<InquireUnitState>(475terminator, *unit, sourceFile, sourceLine);476}477} else {478return &New<InquireUnconnectedFileState>{terminator}(479std::move(trimmed), sourceFile, sourceLine)480.release()481->ioStatementState();482}483}
484
485Cookie IODEF(BeginInquireIoLength)(const char *sourceFile, int sourceLine) {486Terminator oom{sourceFile, sourceLine};487return &New<InquireIOLengthState>{oom}(sourceFile, sourceLine)488.release()489->ioStatementState();490}
491
492// Control list items
493
494void IODEF(EnableHandlers)(Cookie cookie, bool hasIoStat, bool hasErr,495bool hasEnd, bool hasEor, bool hasIoMsg) {496IoErrorHandler &handler{cookie->GetIoErrorHandler()};497if (hasIoStat) {498handler.HasIoStat();499}500if (hasErr) {501handler.HasErrLabel();502}503if (hasEnd) {504handler.HasEndLabel();505}506if (hasEor) {507handler.HasEorLabel();508}509if (hasIoMsg) {510handler.HasIoMsg();511}512}
513
514static RT_API_ATTRS bool YesOrNo(const char *keyword, std::size_t length,515const char *what, IoErrorHandler &handler) {516static const char *keywords[]{"YES", "NO", nullptr};517switch (IdentifyValue(keyword, length, keywords)) {518case 0:519return true;520case 1:521return false;522default:523handler.SignalError(IostatErrorInKeyword, "Invalid %s='%.*s'", what,524static_cast<int>(length), keyword);525return false;526}527}
528
529bool IODEF(SetAdvance)(Cookie cookie, const char *keyword, std::size_t length) {530IoStatementState &io{*cookie};531IoErrorHandler &handler{io.GetIoErrorHandler()};532bool nonAdvancing{!YesOrNo(keyword, length, "ADVANCE", handler)};533if (nonAdvancing && io.GetConnectionState().access == Access::Direct) {534handler.SignalError("Non-advancing I/O attempted on direct access file");535} else {536auto *unit{io.GetExternalFileUnit()};537if (unit && unit->GetChildIo()) {538// ADVANCE= is ignored for child I/O (12.6.4.8.3 p3)539} else {540io.mutableModes().nonAdvancing = nonAdvancing;541}542}543return !handler.InError();544}
545
546bool IODEF(SetBlank)(Cookie cookie, const char *keyword, std::size_t length) {547IoStatementState &io{*cookie};548static const char *keywords[]{"NULL", "ZERO", nullptr};549switch (IdentifyValue(keyword, length, keywords)) {550case 0:551io.mutableModes().editingFlags &= ~blankZero;552return true;553case 1:554io.mutableModes().editingFlags |= blankZero;555return true;556default:557io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,558"Invalid BLANK='%.*s'", static_cast<int>(length), keyword);559return false;560}561}
562
563bool IODEF(SetDecimal)(Cookie cookie, const char *keyword, std::size_t length) {564IoStatementState &io{*cookie};565static const char *keywords[]{"COMMA", "POINT", nullptr};566switch (IdentifyValue(keyword, length, keywords)) {567case 0:568io.mutableModes().editingFlags |= decimalComma;569return true;570case 1:571io.mutableModes().editingFlags &= ~decimalComma;572return true;573default:574io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,575"Invalid DECIMAL='%.*s'", static_cast<int>(length), keyword);576return false;577}578}
579
580bool IODEF(SetDelim)(Cookie cookie, const char *keyword, std::size_t length) {581IoStatementState &io{*cookie};582static const char *keywords[]{"APOSTROPHE", "QUOTE", "NONE", nullptr};583switch (IdentifyValue(keyword, length, keywords)) {584case 0:585io.mutableModes().delim = '\'';586return true;587case 1:588io.mutableModes().delim = '"';589return true;590case 2:591io.mutableModes().delim = '\0';592return true;593default:594io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,595"Invalid DELIM='%.*s'", static_cast<int>(length), keyword);596return false;597}598}
599
600bool IODEF(SetPad)(Cookie cookie, const char *keyword, std::size_t length) {601IoStatementState &io{*cookie};602IoErrorHandler &handler{io.GetIoErrorHandler()};603io.mutableModes().pad = YesOrNo(keyword, length, "PAD", handler);604return !handler.InError();605}
606
607bool IODEF(SetPos)(Cookie cookie, std::int64_t pos) {608IoStatementState &io{*cookie};609IoErrorHandler &handler{io.GetIoErrorHandler()};610if (auto *unit{io.GetExternalFileUnit()}) {611return unit->SetStreamPos(pos, handler);612} else if (!io.get_if<ErroneousIoStatementState>()) {613handler.Crash("SetPos() called on internal unit");614}615return false;616}
617
618bool IODEF(SetRec)(Cookie cookie, std::int64_t rec) {619IoStatementState &io{*cookie};620IoErrorHandler &handler{io.GetIoErrorHandler()};621if (auto *unit{io.GetExternalFileUnit()}) {622if (unit->GetChildIo()) {623handler.SignalError(624IostatBadOpOnChildUnit, "REC= specifier on child I/O");625} else {626unit->SetDirectRec(rec, handler);627}628} else if (!io.get_if<ErroneousIoStatementState>()) {629handler.Crash("SetRec() called on internal unit");630}631return true;632}
633
634bool IODEF(SetRound)(Cookie cookie, const char *keyword, std::size_t length) {635IoStatementState &io{*cookie};636static const char *keywords[]{"UP", "DOWN", "ZERO", "NEAREST", "COMPATIBLE",637"PROCESSOR_DEFINED", nullptr};638switch (IdentifyValue(keyword, length, keywords)) {639case 0:640io.mutableModes().round = decimal::RoundUp;641return true;642case 1:643io.mutableModes().round = decimal::RoundDown;644return true;645case 2:646io.mutableModes().round = decimal::RoundToZero;647return true;648case 3:649io.mutableModes().round = decimal::RoundNearest;650return true;651case 4:652io.mutableModes().round = decimal::RoundCompatible;653return true;654case 5:655io.mutableModes().round = executionEnvironment.defaultOutputRoundingMode;656return true;657default:658io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,659"Invalid ROUND='%.*s'", static_cast<int>(length), keyword);660return false;661}662}
663
664bool IODEF(SetSign)(Cookie cookie, const char *keyword, std::size_t length) {665IoStatementState &io{*cookie};666static const char *keywords[]{667"PLUS", "SUPPRESS", "PROCESSOR_DEFINED", nullptr};668switch (IdentifyValue(keyword, length, keywords)) {669case 0:670io.mutableModes().editingFlags |= signPlus;671return true;672case 1:673case 2: // processor default is SS674io.mutableModes().editingFlags &= ~signPlus;675return true;676default:677io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,678"Invalid SIGN='%.*s'", static_cast<int>(length), keyword);679return false;680}681}
682
683bool IODEF(SetAccess)(Cookie cookie, const char *keyword, std::size_t length) {684IoStatementState &io{*cookie};685auto *open{io.get_if<OpenStatementState>()};686if (!open) {687if (!io.get_if<NoopStatementState>() &&688!io.get_if<ErroneousIoStatementState>()) {689io.GetIoErrorHandler().Crash(690"SetAccess() called when not in an OPEN statement");691}692return false;693} else if (open->completedOperation()) {694io.GetIoErrorHandler().Crash(695"SetAccess() called after GetNewUnit() for an OPEN statement");696}697static const char *keywords[]{698"SEQUENTIAL", "DIRECT", "STREAM", "APPEND", nullptr};699switch (IdentifyValue(keyword, length, keywords)) {700case 0:701open->set_access(Access::Sequential);702break;703case 1:704open->set_access(Access::Direct);705break;706case 2:707open->set_access(Access::Stream);708break;709case 3: // Sun Fortran extension ACCESS=APPEND: treat as if POSITION=APPEND710open->set_position(Position::Append);711break;712default:713open->SignalError(IostatErrorInKeyword, "Invalid ACCESS='%.*s'",714static_cast<int>(length), keyword);715}716return true;717}
718
719bool IODEF(SetAction)(Cookie cookie, const char *keyword, std::size_t length) {720IoStatementState &io{*cookie};721auto *open{io.get_if<OpenStatementState>()};722if (!open) {723if (!io.get_if<NoopStatementState>() &&724!io.get_if<ErroneousIoStatementState>()) {725io.GetIoErrorHandler().Crash(726"SetAction() called when not in an OPEN statement");727}728return false;729} else if (open->completedOperation()) {730io.GetIoErrorHandler().Crash(731"SetAction() called after GetNewUnit() for an OPEN statement");732}733Fortran::common::optional<Action> action;734static const char *keywords[]{"READ", "WRITE", "READWRITE", nullptr};735switch (IdentifyValue(keyword, length, keywords)) {736case 0:737action = Action::Read;738break;739case 1:740action = Action::Write;741break;742case 2:743action = Action::ReadWrite;744break;745default:746open->SignalError(IostatErrorInKeyword, "Invalid ACTION='%.*s'",747static_cast<int>(length), keyword);748return false;749}750RUNTIME_CHECK(io.GetIoErrorHandler(), action.has_value());751if (open->wasExtant()) {752if ((*action != Action::Write) != open->unit().mayRead() ||753(*action != Action::Read) != open->unit().mayWrite()) {754open->SignalError("ACTION= may not be changed on an open unit");755}756}757open->set_action(*action);758return true;759}
760
761bool IODEF(SetAsynchronous)(762Cookie cookie, const char *keyword, std::size_t length) {763IoStatementState &io{*cookie};764IoErrorHandler &handler{io.GetIoErrorHandler()};765bool isYes{YesOrNo(keyword, length, "ASYNCHRONOUS", handler)};766if (auto *open{io.get_if<OpenStatementState>()}) {767if (open->completedOperation()) {768handler.Crash(769"SetAsynchronous() called after GetNewUnit() for an OPEN statement");770}771open->unit().set_mayAsynchronous(isYes);772} else if (auto *ext{io.get_if<ExternalIoStatementBase>()}) {773if (isYes) {774if (ext->unit().mayAsynchronous()) {775ext->SetAsynchronous();776} else {777handler.SignalError(IostatBadAsynchronous);778}779}780} else if (!io.get_if<NoopStatementState>() &&781!io.get_if<ErroneousIoStatementState>()) {782handler.Crash("SetAsynchronous() called when not in an OPEN or external "783"I/O statement");784}785return !handler.InError();786}
787
788bool IODEF(SetCarriagecontrol)(789Cookie cookie, const char *keyword, std::size_t length) {790IoStatementState &io{*cookie};791auto *open{io.get_if<OpenStatementState>()};792if (!open) {793if (!io.get_if<NoopStatementState>() &&794!io.get_if<ErroneousIoStatementState>()) {795io.GetIoErrorHandler().Crash(796"SetCarriageControl() called when not in an OPEN statement");797}798return false;799} else if (open->completedOperation()) {800io.GetIoErrorHandler().Crash(801"SetCarriageControl() called after GetNewUnit() for an OPEN statement");802}803static const char *keywords[]{"LIST", "FORTRAN", "NONE", nullptr};804switch (IdentifyValue(keyword, length, keywords)) {805case 0:806return true;807case 1:808case 2:809open->SignalError(IostatErrorInKeyword,810"Unimplemented CARRIAGECONTROL='%.*s'", static_cast<int>(length),811keyword);812return false;813default:814open->SignalError(IostatErrorInKeyword, "Invalid CARRIAGECONTROL='%.*s'",815static_cast<int>(length), keyword);816return false;817}818}
819
820bool IODEF(SetConvert)(Cookie cookie, const char *keyword, std::size_t length) {821IoStatementState &io{*cookie};822auto *open{io.get_if<OpenStatementState>()};823if (!open) {824if (!io.get_if<NoopStatementState>() &&825!io.get_if<ErroneousIoStatementState>()) {826io.GetIoErrorHandler().Crash(827"SetConvert() called when not in an OPEN statement");828}829return false;830} else if (open->completedOperation()) {831io.GetIoErrorHandler().Crash(832"SetConvert() called after GetNewUnit() for an OPEN statement");833}834if (auto convert{GetConvertFromString(keyword, length)}) {835open->set_convert(*convert);836return true;837} else {838open->SignalError(IostatErrorInKeyword, "Invalid CONVERT='%.*s'",839static_cast<int>(length), keyword);840return false;841}842}
843
844bool IODEF(SetEncoding)(845Cookie cookie, const char *keyword, std::size_t length) {846IoStatementState &io{*cookie};847auto *open{io.get_if<OpenStatementState>()};848if (!open) {849if (!io.get_if<NoopStatementState>() &&850!io.get_if<ErroneousIoStatementState>()) {851io.GetIoErrorHandler().Crash(852"SetEncoding() called when not in an OPEN statement");853}854return false;855} else if (open->completedOperation()) {856io.GetIoErrorHandler().Crash(857"SetEncoding() called after GetNewUnit() for an OPEN statement");858}859// Allow the encoding to be changed on an open unit -- it's860// useful and safe.861static const char *keywords[]{"UTF-8", "DEFAULT", nullptr};862switch (IdentifyValue(keyword, length, keywords)) {863case 0:864open->unit().isUTF8 = true;865break;866case 1:867open->unit().isUTF8 = false;868break;869default:870open->SignalError(IostatErrorInKeyword, "Invalid ENCODING='%.*s'",871static_cast<int>(length), keyword);872}873return true;874}
875
876bool IODEF(SetForm)(Cookie cookie, const char *keyword, std::size_t length) {877IoStatementState &io{*cookie};878auto *open{io.get_if<OpenStatementState>()};879if (!open) {880if (!io.get_if<NoopStatementState>() &&881!io.get_if<ErroneousIoStatementState>()) {882io.GetIoErrorHandler().Crash(883"SetForm() called when not in an OPEN statement");884}885} else if (open->completedOperation()) {886io.GetIoErrorHandler().Crash(887"SetForm() called after GetNewUnit() for an OPEN statement");888}889static const char *keywords[]{"FORMATTED", "UNFORMATTED", nullptr};890switch (IdentifyValue(keyword, length, keywords)) {891case 0:892open->set_isUnformatted(false);893break;894case 1:895open->set_isUnformatted(true);896break;897default:898open->SignalError(IostatErrorInKeyword, "Invalid FORM='%.*s'",899static_cast<int>(length), keyword);900}901return true;902}
903
904bool IODEF(SetPosition)(905Cookie cookie, const char *keyword, std::size_t length) {906IoStatementState &io{*cookie};907auto *open{io.get_if<OpenStatementState>()};908if (!open) {909if (!io.get_if<NoopStatementState>() &&910!io.get_if<ErroneousIoStatementState>()) {911io.GetIoErrorHandler().Crash(912"SetPosition() called when not in an OPEN statement");913}914return false;915} else if (open->completedOperation()) {916io.GetIoErrorHandler().Crash(917"SetPosition() called after GetNewUnit() for an OPEN statement");918}919static const char *positions[]{"ASIS", "REWIND", "APPEND", nullptr};920switch (IdentifyValue(keyword, length, positions)) {921case 0:922open->set_position(Position::AsIs);923return true;924case 1:925open->set_position(Position::Rewind);926return true;927case 2:928open->set_position(Position::Append);929return true;930default:931io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,932"Invalid POSITION='%.*s'", static_cast<int>(length), keyword);933}934return true;935}
936
937bool IODEF(SetRecl)(Cookie cookie, std::size_t n) {938IoStatementState &io{*cookie};939auto *open{io.get_if<OpenStatementState>()};940if (!open) {941if (!io.get_if<NoopStatementState>() &&942!io.get_if<ErroneousIoStatementState>()) {943io.GetIoErrorHandler().Crash(944"SetRecl() called when not in an OPEN statement");945}946return false;947} else if (open->completedOperation()) {948io.GetIoErrorHandler().Crash(949"SetRecl() called after GetNewUnit() for an OPEN statement");950}951if (n <= 0) {952io.GetIoErrorHandler().SignalError("RECL= must be greater than zero");953return false;954} else if (open->wasExtant() &&955open->unit().openRecl.value_or(0) != static_cast<std::int64_t>(n)) {956open->SignalError("RECL= may not be changed for an open unit");957return false;958} else {959open->unit().openRecl = n;960return true;961}962}
963
964bool IODEF(SetStatus)(Cookie cookie, const char *keyword, std::size_t length) {965IoStatementState &io{*cookie};966if (auto *open{io.get_if<OpenStatementState>()}) {967if (open->completedOperation()) {968io.GetIoErrorHandler().Crash(969"SetStatus() called after GetNewUnit() for an OPEN statement");970}971static const char *statuses[]{972"OLD", "NEW", "SCRATCH", "REPLACE", "UNKNOWN", nullptr};973switch (IdentifyValue(keyword, length, statuses)) {974case 0:975open->set_status(OpenStatus::Old);976return true;977case 1:978open->set_status(OpenStatus::New);979return true;980case 2:981open->set_status(OpenStatus::Scratch);982return true;983case 3:984open->set_status(OpenStatus::Replace);985return true;986case 4:987open->set_status(OpenStatus::Unknown);988return true;989default:990io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,991"Invalid STATUS='%.*s'", static_cast<int>(length), keyword);992}993return false;994}995if (auto *close{io.get_if<CloseStatementState>()}) {996static const char *statuses[]{"KEEP", "DELETE", nullptr};997switch (IdentifyValue(keyword, length, statuses)) {998case 0:999close->set_status(CloseStatus::Keep);1000return true;1001case 1:1002close->set_status(CloseStatus::Delete);1003return true;1004default:1005io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,1006"Invalid STATUS='%.*s'", static_cast<int>(length), keyword);1007}1008return false;1009}1010if (io.get_if<NoopStatementState>() ||1011io.get_if<ErroneousIoStatementState>()) {1012return true; // don't bother validating STATUS= in a no-op CLOSE1013}1014io.GetIoErrorHandler().Crash(1015"SetStatus() called when not in an OPEN or CLOSE statement");1016}
1017
1018bool IODEF(SetFile)(Cookie cookie, const char *path, std::size_t chars) {1019IoStatementState &io{*cookie};1020if (auto *open{io.get_if<OpenStatementState>()}) {1021if (open->completedOperation()) {1022io.GetIoErrorHandler().Crash(1023"SetFile() called after GetNewUnit() for an OPEN statement");1024}1025open->set_path(path, chars);1026return true;1027} else if (!io.get_if<NoopStatementState>() &&1028!io.get_if<ErroneousIoStatementState>()) {1029io.GetIoErrorHandler().Crash(1030"SetFile() called when not in an OPEN statement");1031}1032return false;1033}
1034
1035bool IODEF(GetNewUnit)(Cookie cookie, int &unit, int kind) {1036IoStatementState &io{*cookie};1037auto *open{io.get_if<OpenStatementState>()};1038if (!open) {1039if (!io.get_if<NoopStatementState>() &&1040!io.get_if<ErroneousIoStatementState>()) {1041io.GetIoErrorHandler().Crash(1042"GetNewUnit() called when not in an OPEN statement");1043}1044return false;1045} else if (!open->InError()) {1046open->CompleteOperation();1047}1048if (open->InError()) {1049// A failed OPEN(NEWUNIT=n) does not modify 'n'1050return false;1051}1052std::int64_t result{open->unit().unitNumber()};1053if (!SetInteger(unit, kind, result)) {1054open->SignalError("GetNewUnit(): bad INTEGER kind(%d) or out-of-range "1055"value(%jd) for result",1056kind, static_cast<std::intmax_t>(result));1057}1058return true;1059}
1060
1061// Data transfers
1062
1063bool IODEF(OutputDescriptor)(Cookie cookie, const Descriptor &descriptor) {1064return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);1065}
1066
1067bool IODEF(InputDescriptor)(Cookie cookie, const Descriptor &descriptor) {1068return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1069}
1070
1071bool IODEF(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {1072if (!cookie->CheckFormattedStmtType<Direction::Input>("InputInteger")) {1073return false;1074}1075StaticDescriptor<0> staticDescriptor;1076Descriptor &descriptor{staticDescriptor.descriptor()};1077descriptor.Establish(1078TypeCategory::Integer, kind, reinterpret_cast<void *>(&n), 0);1079return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1080}
1081
1082bool IODEF(InputReal32)(Cookie cookie, float &x) {1083if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal32")) {1084return false;1085}1086StaticDescriptor<0> staticDescriptor;1087Descriptor &descriptor{staticDescriptor.descriptor()};1088descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);1089return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1090}
1091
1092bool IODEF(InputReal64)(Cookie cookie, double &x) {1093if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal64")) {1094return false;1095}1096StaticDescriptor<0> staticDescriptor;1097Descriptor &descriptor{staticDescriptor.descriptor()};1098descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);1099return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1100}
1101
1102bool IODEF(InputComplex32)(Cookie cookie, float z[2]) {1103if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex32")) {1104return false;1105}1106StaticDescriptor<0> staticDescriptor;1107Descriptor &descriptor{staticDescriptor.descriptor()};1108descriptor.Establish(1109TypeCategory::Complex, 4, reinterpret_cast<void *>(z), 0);1110return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1111}
1112
1113bool IODEF(InputComplex64)(Cookie cookie, double z[2]) {1114if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex64")) {1115return false;1116}1117StaticDescriptor<0> staticDescriptor;1118Descriptor &descriptor{staticDescriptor.descriptor()};1119descriptor.Establish(1120TypeCategory::Complex, 8, reinterpret_cast<void *>(z), 0);1121return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1122}
1123
1124bool IODEF(OutputCharacter)(1125Cookie cookie, const char *x, std::size_t length, int kind) {1126if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputCharacter")) {1127return false;1128}1129StaticDescriptor<0> staticDescriptor;1130Descriptor &descriptor{staticDescriptor.descriptor()};1131descriptor.Establish(1132kind, length, reinterpret_cast<void *>(const_cast<char *>(x)), 0);1133return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);1134}
1135
1136bool IODEF(InputCharacter)(1137Cookie cookie, char *x, std::size_t length, int kind) {1138if (!cookie->CheckFormattedStmtType<Direction::Input>("InputCharacter")) {1139return false;1140}1141StaticDescriptor<0> staticDescriptor;1142Descriptor &descriptor{staticDescriptor.descriptor()};1143descriptor.Establish(kind, length, reinterpret_cast<void *>(x), 0);1144return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1145}
1146
1147bool IODEF(InputAscii)(Cookie cookie, char *x, std::size_t length) {1148return IONAME(InputCharacter)(cookie, x, length, 1);1149}
1150
1151bool IODEF(InputLogical)(Cookie cookie, bool &truth) {1152if (!cookie->CheckFormattedStmtType<Direction::Input>("InputLogical")) {1153return false;1154}1155StaticDescriptor<0> staticDescriptor;1156Descriptor &descriptor{staticDescriptor.descriptor()};1157descriptor.Establish(1158TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0);1159return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);1160}
1161
1162bool IODEF(OutputDerivedType)(Cookie cookie, const Descriptor &descriptor,1163const NonTbpDefinedIoTable *table) {1164return descr::DescriptorIO<Direction::Output>(*cookie, descriptor, table);1165}
1166
1167bool IODEF(InputDerivedType)(Cookie cookie, const Descriptor &descriptor,1168const NonTbpDefinedIoTable *table) {1169return descr::DescriptorIO<Direction::Input>(*cookie, descriptor, table);1170}
1171
1172std::size_t IODEF(GetSize)(Cookie cookie) {1173IoStatementState &io{*cookie};1174IoErrorHandler &handler{io.GetIoErrorHandler()};1175if (!handler.InError()) {1176io.CompleteOperation();1177}1178if (const auto *formatted{1179io.get_if<FormattedIoStatementState<Direction::Input>>()}) {1180return formatted->GetEditDescriptorChars();1181} else if (!io.get_if<NoopStatementState>() &&1182!io.get_if<ErroneousIoStatementState>()) {1183handler.Crash("GetIoSize() called for an I/O statement that is not a "1184"formatted READ()");1185}1186return 0;1187}
1188
1189std::size_t IODEF(GetIoLength)(Cookie cookie) {1190IoStatementState &io{*cookie};1191IoErrorHandler &handler{io.GetIoErrorHandler()};1192if (!handler.InError()) {1193io.CompleteOperation();1194}1195if (const auto *inq{io.get_if<InquireIOLengthState>()}) {1196return inq->bytes();1197} else if (!io.get_if<NoopStatementState>() &&1198!io.get_if<ErroneousIoStatementState>()) {1199handler.Crash("GetIoLength() called for an I/O statement that is not "1200"INQUIRE(IOLENGTH=)");1201}1202return 0;1203}
1204
1205void IODEF(GetIoMsg)(Cookie cookie, char *msg, std::size_t length) {1206IoStatementState &io{*cookie};1207IoErrorHandler &handler{io.GetIoErrorHandler()};1208if (!handler.InError()) {1209io.CompleteOperation();1210}1211if (handler.InError()) { // leave "msg" alone when no error1212handler.GetIoMsg(msg, length);1213}1214}
1215
1216AsynchronousId IODEF(GetAsynchronousId)(Cookie cookie) {1217IoStatementState &io{*cookie};1218IoErrorHandler &handler{io.GetIoErrorHandler()};1219if (auto *ext{io.get_if<ExternalIoStatementBase>()}) {1220return ext->asynchronousID();1221} else if (!io.get_if<NoopStatementState>() &&1222!io.get_if<ErroneousIoStatementState>()) {1223handler.Crash(1224"GetAsynchronousId() called when not in an external I/O statement");1225}1226return 0;1227}
1228
1229bool IODEF(InquireCharacter)(Cookie cookie, InquiryKeywordHash inquiry,1230char *result, std::size_t length) {1231IoStatementState &io{*cookie};1232return io.Inquire(inquiry, result, length);1233}
1234
1235bool IODEF(InquireLogical)(1236Cookie cookie, InquiryKeywordHash inquiry, bool &result) {1237IoStatementState &io{*cookie};1238return io.Inquire(inquiry, result);1239}
1240
1241bool IODEF(InquirePendingId)(Cookie cookie, AsynchronousId id, bool &result) {1242IoStatementState &io{*cookie};1243return io.Inquire(HashInquiryKeyword("PENDING"), id, result);1244}
1245
1246bool IODEF(InquireInteger64)(1247Cookie cookie, InquiryKeywordHash inquiry, std::int64_t &result, int kind) {1248IoStatementState &io{*cookie};1249std::int64_t n{0}; // safe "undefined" value1250if (io.Inquire(inquiry, n)) {1251if (SetInteger(result, kind, n)) {1252return true;1253}1254io.GetIoErrorHandler().SignalError(1255"InquireInteger64(): bad INTEGER kind(%d) or out-of-range "1256"value(%jd) for result",1257kind, static_cast<std::intmax_t>(n));1258}1259return false;1260}
1261
1262template <typename INT>1263static RT_API_ATTRS enum Iostat CheckUnitNumberInRangeImpl(INT unit,1264bool handleError, char *ioMsg, std::size_t ioMsgLength,1265const char *sourceFile, int sourceLine) {1266static_assert(sizeof(INT) >= sizeof(ExternalUnit),1267"only intended to be used when the INT to ExternalUnit conversion is "1268"narrowing");1269if (unit != static_cast<ExternalUnit>(unit)) {1270Terminator oom{sourceFile, sourceLine};1271IoErrorHandler errorHandler{oom};1272if (handleError) {1273errorHandler.HasIoStat();1274if (ioMsg) {1275errorHandler.HasIoMsg();1276}1277}1278// Only provide the bad unit number in the message if SignalError can print1279// it accurately. Otherwise, the generic IostatUnitOverflow message will be1280// used.1281if constexpr (sizeof(INT) > sizeof(std::intmax_t)) {1282errorHandler.SignalError(IostatUnitOverflow);1283} else if (static_cast<std::intmax_t>(unit) == unit) {1284errorHandler.SignalError(IostatUnitOverflow,1285"UNIT number %jd is out of range", static_cast<std::intmax_t>(unit));1286} else {1287errorHandler.SignalError(IostatUnitOverflow);1288}1289if (ioMsg) {1290errorHandler.GetIoMsg(ioMsg, ioMsgLength);1291}1292return static_cast<enum Iostat>(errorHandler.GetIoStat());1293}1294return IostatOk;1295}
1296
1297enum Iostat IODEF(CheckUnitNumberInRange64)(std::int64_t unit, bool handleError,1298char *ioMsg, std::size_t ioMsgLength, const char *sourceFile,1299int sourceLine) {1300return CheckUnitNumberInRangeImpl(1301unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine);1302}
1303
1304#ifdef __SIZEOF_INT128__1305enum Iostat IODEF(CheckUnitNumberInRange128)(common::int128_t unit,1306bool handleError, char *ioMsg, std::size_t ioMsgLength,1307const char *sourceFile, int sourceLine) {1308return CheckUnitNumberInRangeImpl(1309unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine);1310}
1311#endif1312
1313RT_EXT_API_GROUP_END
1314} // namespace Fortran::runtime::io1315