1651f58bfSDiana Picus //===-- runtime/io-api.cpp ------------------------------------------------===// 2352d347aSAlexis Perry // 3352d347aSAlexis Perry // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4352d347aSAlexis Perry // See https://llvm.org/LICENSE.txt for license information. 5352d347aSAlexis Perry // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6352d347aSAlexis Perry // 7352d347aSAlexis Perry //===----------------------------------------------------------------------===// 8352d347aSAlexis Perry 9f7be2518Speter klausler // Implements the I/O statement API 10f7be2518Speter klausler 11fe2ff545SPeter Klausler // template function BeginExternalListIo<> is in runtime/io-api-common.h. 12fe2ff545SPeter Klausler // APIs BeginExternalListOutput, OutputInteger{8,16,32,64,128}, 13fe2ff545SPeter Klausler // OutputReal{32,64}, OutputComplex{32,64}, OutputAscii, & EndIoStatement() 14fe2ff545SPeter Klausler // are in runtime/io-api-minimal.cpp. 15fe2ff545SPeter Klausler 16830c0b90SPeter Klausler #include "flang/Runtime/io-api.h" 17cc01194cSpeter klausler #include "descriptor-io.h" 183b635714Speter klausler #include "edit-input.h" 193b635714Speter klausler #include "edit-output.h" 2095696d56Speter klausler #include "environment.h" 21352d347aSAlexis Perry #include "format.h" 22fe2ff545SPeter Klausler #include "io-api-common.h" 23352d347aSAlexis Perry #include "io-stmt.h" 24352d347aSAlexis Perry #include "terminator.h" 2595696d56Speter klausler #include "tools.h" 26f7be2518Speter klausler #include "unit.h" 2771e0261fSSlava Zakharin #include "flang/Common/optional.h" 28830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h" 29830c0b90SPeter Klausler #include "flang/Runtime/memory.h" 30352d347aSAlexis Perry #include <cstdlib> 31352d347aSAlexis Perry #include <memory> 32352d347aSAlexis Perry 33352d347aSAlexis Perry namespace Fortran::runtime::io { 34f3c31d70SSlava Zakharin RT_EXT_API_GROUP_BEGIN 35352d347aSAlexis Perry 36f3c31d70SSlava Zakharin RT_API_ATTRS const char *InquiryKeywordHashDecode( 37675ad1bcSpeter klausler char *buffer, std::size_t n, InquiryKeywordHash hash) { 38675ad1bcSpeter klausler if (n < 1) { 39675ad1bcSpeter klausler return nullptr; 40675ad1bcSpeter klausler } 41675ad1bcSpeter klausler char *p{buffer + n}; 42675ad1bcSpeter klausler *--p = '\0'; 43675ad1bcSpeter klausler while (hash > 1) { 44675ad1bcSpeter klausler if (p < buffer) { 45675ad1bcSpeter klausler return nullptr; 46675ad1bcSpeter klausler } 47675ad1bcSpeter klausler *--p = 'A' + (hash % 26); 48675ad1bcSpeter klausler hash /= 26; 49675ad1bcSpeter klausler } 50675ad1bcSpeter klausler return hash == 1 ? p : nullptr; 51675ad1bcSpeter klausler } 52675ad1bcSpeter klausler 533b635714Speter klausler template <Direction DIR> 54f3c31d70SSlava Zakharin RT_API_ATTRS Cookie BeginInternalArrayListIO(const Descriptor &descriptor, 5595696d56Speter klausler void ** /*scratchArea*/, std::size_t /*scratchBytes*/, 5695696d56Speter klausler const char *sourceFile, int sourceLine) { 5795696d56Speter klausler Terminator oom{sourceFile, sourceLine}; 5898d576c7Speter klausler return &New<InternalListIoStatementState<DIR>>{oom}( 5998d576c7Speter klausler descriptor, sourceFile, sourceLine) 6098d576c7Speter klausler .release() 6198d576c7Speter klausler ->ioStatementState(); 6295696d56Speter klausler } 6395696d56Speter klausler 64f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalArrayListOutput)(const Descriptor &descriptor, 653b635714Speter klausler void **scratchArea, std::size_t scratchBytes, const char *sourceFile, 663b635714Speter klausler int sourceLine) { 673b635714Speter klausler return BeginInternalArrayListIO<Direction::Output>( 683b635714Speter klausler descriptor, scratchArea, scratchBytes, sourceFile, sourceLine); 693b635714Speter klausler } 703b635714Speter klausler 71f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalArrayListInput)(const Descriptor &descriptor, 723b635714Speter klausler void **scratchArea, std::size_t scratchBytes, const char *sourceFile, 733b635714Speter klausler int sourceLine) { 743b635714Speter klausler return BeginInternalArrayListIO<Direction::Input>( 753b635714Speter klausler descriptor, scratchArea, scratchBytes, sourceFile, sourceLine); 763b635714Speter klausler } 773b635714Speter klausler 783b635714Speter klausler template <Direction DIR> 79f3c31d70SSlava Zakharin RT_API_ATTRS Cookie BeginInternalArrayFormattedIO(const Descriptor &descriptor, 8027d666b9SV Donaldson const char *format, std::size_t formatLength, 8127d666b9SV Donaldson const Descriptor *formatDescriptor, void ** /*scratchArea*/, 8227d666b9SV Donaldson std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) { 8395696d56Speter klausler Terminator oom{sourceFile, sourceLine}; 84cc180f4cSPeter Klausler return &New<InternalFormattedIoStatementState<DIR>>{oom}(descriptor, format, 8527d666b9SV Donaldson formatLength, formatDescriptor, sourceFile, sourceLine) 8698d576c7Speter klausler .release() 8798d576c7Speter klausler ->ioStatementState(); 8895696d56Speter klausler } 8995696d56Speter klausler 90f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalArrayFormattedOutput)(const Descriptor &descriptor, 9127d666b9SV Donaldson const char *format, std::size_t formatLength, 9227d666b9SV Donaldson const Descriptor *formatDescriptor, void **scratchArea, 9327d666b9SV Donaldson std::size_t scratchBytes, const char *sourceFile, int sourceLine) { 943b635714Speter klausler return BeginInternalArrayFormattedIO<Direction::Output>(descriptor, format, 9527d666b9SV Donaldson formatLength, formatDescriptor, scratchArea, scratchBytes, sourceFile, 9627d666b9SV Donaldson sourceLine); 973b635714Speter klausler } 983b635714Speter klausler 99f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalArrayFormattedInput)(const Descriptor &descriptor, 10027d666b9SV Donaldson const char *format, std::size_t formatLength, 10127d666b9SV Donaldson const Descriptor *formatDescriptor, void **scratchArea, 10227d666b9SV Donaldson std::size_t scratchBytes, const char *sourceFile, int sourceLine) { 1033b635714Speter klausler return BeginInternalArrayFormattedIO<Direction::Input>(descriptor, format, 10427d666b9SV Donaldson formatLength, formatDescriptor, scratchArea, scratchBytes, sourceFile, 10527d666b9SV Donaldson sourceLine); 1063b635714Speter klausler } 1073b635714Speter klausler 1083b635714Speter klausler template <Direction DIR> 1098ebf7411SSlava Zakharin RT_API_ATTRS Cookie BeginInternalListIO( 110b30fa1c3Speter klausler std::conditional_t<DIR == Direction::Input, const char, char> *internal, 111b30fa1c3Speter klausler std::size_t internalLength, void ** /*scratchArea*/, 112b30fa1c3Speter klausler std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) { 113b30fa1c3Speter klausler Terminator oom{sourceFile, sourceLine}; 114b30fa1c3Speter klausler return &New<InternalListIoStatementState<DIR>>{oom}( 115b30fa1c3Speter klausler internal, internalLength, sourceFile, sourceLine) 116b30fa1c3Speter klausler .release() 117b30fa1c3Speter klausler ->ioStatementState(); 118b30fa1c3Speter klausler } 119b30fa1c3Speter klausler 120f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalListOutput)(char *internal, 121b30fa1c3Speter klausler std::size_t internalLength, void **scratchArea, std::size_t scratchBytes, 122b30fa1c3Speter klausler const char *sourceFile, int sourceLine) { 123b30fa1c3Speter klausler return BeginInternalListIO<Direction::Output>(internal, internalLength, 124b30fa1c3Speter klausler scratchArea, scratchBytes, sourceFile, sourceLine); 125b30fa1c3Speter klausler } 126b30fa1c3Speter klausler 127f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalListInput)(const char *internal, 128b30fa1c3Speter klausler std::size_t internalLength, void **scratchArea, std::size_t scratchBytes, 129b30fa1c3Speter klausler const char *sourceFile, int sourceLine) { 130b30fa1c3Speter klausler return BeginInternalListIO<Direction::Input>(internal, internalLength, 131b30fa1c3Speter klausler scratchArea, scratchBytes, sourceFile, sourceLine); 132b30fa1c3Speter klausler } 133b30fa1c3Speter klausler 134b30fa1c3Speter klausler template <Direction DIR> 135f3c31d70SSlava Zakharin RT_API_ATTRS Cookie BeginInternalFormattedIO( 1363b635714Speter klausler std::conditional_t<DIR == Direction::Input, const char, char> *internal, 1373b635714Speter klausler std::size_t internalLength, const char *format, std::size_t formatLength, 13827d666b9SV Donaldson const Descriptor *formatDescriptor, void ** /*scratchArea*/, 13927d666b9SV Donaldson std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) { 14095696d56Speter klausler Terminator oom{sourceFile, sourceLine}; 141cc180f4cSPeter Klausler return &New<InternalFormattedIoStatementState<DIR>>{oom}(internal, 14227d666b9SV Donaldson internalLength, format, formatLength, formatDescriptor, sourceFile, 14327d666b9SV Donaldson sourceLine) 14498d576c7Speter klausler .release() 14598d576c7Speter klausler ->ioStatementState(); 14695696d56Speter klausler } 14795696d56Speter klausler 148f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalFormattedOutput)(char *internal, 149352d347aSAlexis Perry std::size_t internalLength, const char *format, std::size_t formatLength, 15027d666b9SV Donaldson const Descriptor *formatDescriptor, void **scratchArea, 15127d666b9SV Donaldson std::size_t scratchBytes, const char *sourceFile, int sourceLine) { 1523b635714Speter klausler return BeginInternalFormattedIO<Direction::Output>(internal, internalLength, 15327d666b9SV Donaldson format, formatLength, formatDescriptor, scratchArea, scratchBytes, 15427d666b9SV Donaldson sourceFile, sourceLine); 15595696d56Speter klausler } 15695696d56Speter klausler 157f3c31d70SSlava Zakharin Cookie IODEF(BeginInternalFormattedInput)(const char *internal, 15895696d56Speter klausler std::size_t internalLength, const char *format, std::size_t formatLength, 15927d666b9SV Donaldson const Descriptor *formatDescriptor, void **scratchArea, 16027d666b9SV Donaldson std::size_t scratchBytes, const char *sourceFile, int sourceLine) { 1613b635714Speter klausler return BeginInternalFormattedIO<Direction::Input>(internal, internalLength, 16227d666b9SV Donaldson format, formatLength, formatDescriptor, scratchArea, scratchBytes, 16327d666b9SV Donaldson sourceFile, sourceLine); 1643b635714Speter klausler } 1653b635714Speter klausler 166f3c31d70SSlava Zakharin Cookie IODEF(BeginExternalListInput)( 1673b635714Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 1686a1c3efaSpeter klausler return BeginExternalListIO<Direction::Input, ExternalListIoStatementState>( 169df38f35aSPeter Klausler unitNumber, sourceFile, sourceLine); 1703b635714Speter klausler } 1713b635714Speter klausler 1723b635714Speter klausler template <Direction DIR> 173f3c31d70SSlava Zakharin RT_API_ATTRS Cookie BeginExternalFormattedIO(const char *format, 174f3c31d70SSlava Zakharin std::size_t formatLength, const Descriptor *formatDescriptor, 175f3c31d70SSlava Zakharin ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 1763b635714Speter klausler Terminator terminator{sourceFile, sourceLine}; 177cfbde714SPeter Klausler Cookie errorCookie{nullptr}; 178cfbde714SPeter Klausler ExternalFileUnit *unit{GetOrCreateUnit( 179cfbde714SPeter Klausler unitNumber, DIR, false /*!unformatted*/, terminator, errorCookie)}; 180cfbde714SPeter Klausler if (!unit) { 181cfbde714SPeter Klausler return errorCookie; 182b1856009SPeter Klausler } 183cfbde714SPeter Klausler Iostat iostat{IostatOk}; 184cfbde714SPeter Klausler if (!unit->isUnformatted.has_value()) { 185cfbde714SPeter Klausler unit->isUnformatted = false; 186cfbde714SPeter Klausler } 187cfbde714SPeter Klausler if (*unit->isUnformatted) { 188df38f35aSPeter Klausler iostat = IostatFormattedIoOnUnformattedUnit; 189b1856009SPeter Klausler } 190cfbde714SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 191df38f35aSPeter Klausler if (iostat == IostatOk) { 192df38f35aSPeter Klausler iostat = child->CheckFormattingAndDirection(false, DIR); 193df38f35aSPeter Klausler } 194df38f35aSPeter Klausler if (iostat == IostatOk) { 195df38f35aSPeter Klausler return &child->BeginIoStatement<ChildFormattedIoStatementState<DIR>>( 19627d666b9SV Donaldson *child, format, formatLength, formatDescriptor, sourceFile, 19727d666b9SV Donaldson sourceLine); 19843fadefbSpeter klausler } else { 199df38f35aSPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>( 20011f928afSPeter Klausler iostat, nullptr /* no unit */, sourceFile, sourceLine); 201df38f35aSPeter Klausler } 202df38f35aSPeter Klausler } else { 203df38f35aSPeter Klausler if (iostat == IostatOk) { 204cfbde714SPeter Klausler iostat = unit->SetDirection(DIR); 205df38f35aSPeter Klausler } 206df38f35aSPeter Klausler if (iostat == IostatOk) { 207cfbde714SPeter Klausler return &unit->BeginIoStatement<ExternalFormattedIoStatementState<DIR>>( 20827d666b9SV Donaldson terminator, *unit, format, formatLength, formatDescriptor, sourceFile, 20927d666b9SV Donaldson sourceLine); 210df38f35aSPeter Klausler } else { 211cfbde714SPeter Klausler return &unit->BeginIoStatement<ErroneousIoStatementState>( 212921316afSPeter Klausler terminator, iostat, unit, sourceFile, sourceLine); 213df38f35aSPeter Klausler } 214352d347aSAlexis Perry } 21543fadefbSpeter klausler } 216352d347aSAlexis Perry 217f3c31d70SSlava Zakharin Cookie IODEF(BeginExternalFormattedOutput)(const char *format, 21827d666b9SV Donaldson std::size_t formatLength, const Descriptor *formatDescriptor, 21927d666b9SV Donaldson ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 220cc180f4cSPeter Klausler return BeginExternalFormattedIO<Direction::Output>(format, formatLength, 22127d666b9SV Donaldson formatDescriptor, unitNumber, sourceFile, sourceLine); 22295696d56Speter klausler } 22395696d56Speter klausler 224f3c31d70SSlava Zakharin Cookie IODEF(BeginExternalFormattedInput)(const char *format, 22527d666b9SV Donaldson std::size_t formatLength, const Descriptor *formatDescriptor, 22627d666b9SV Donaldson ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 227cc180f4cSPeter Klausler return BeginExternalFormattedIO<Direction::Input>(format, formatLength, 22827d666b9SV Donaldson formatDescriptor, unitNumber, sourceFile, sourceLine); 2293b635714Speter klausler } 2303b635714Speter klausler 2313b635714Speter klausler template <Direction DIR> 232f3c31d70SSlava Zakharin RT_API_ATTRS Cookie BeginUnformattedIO( 23395696d56Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 23495696d56Speter klausler Terminator terminator{sourceFile, sourceLine}; 235cfbde714SPeter Klausler Cookie errorCookie{nullptr}; 236cfbde714SPeter Klausler ExternalFileUnit *unit{GetOrCreateUnit( 237cfbde714SPeter Klausler unitNumber, DIR, true /*unformatted*/, terminator, errorCookie)}; 238cfbde714SPeter Klausler if (!unit) { 239cfbde714SPeter Klausler return errorCookie; 240b1856009SPeter Klausler } 241cfbde714SPeter Klausler Iostat iostat{IostatOk}; 242cfbde714SPeter Klausler if (!unit->isUnformatted.has_value()) { 243cfbde714SPeter Klausler unit->isUnformatted = true; 244cfbde714SPeter Klausler } 245cfbde714SPeter Klausler if (!*unit->isUnformatted) { 246df38f35aSPeter Klausler iostat = IostatUnformattedIoOnFormattedUnit; 247b1856009SPeter Klausler } 248cfbde714SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 249df38f35aSPeter Klausler if (iostat == IostatOk) { 250df38f35aSPeter Klausler iostat = child->CheckFormattingAndDirection(true, DIR); 251df38f35aSPeter Klausler } 252df38f35aSPeter Klausler if (iostat == IostatOk) { 253df38f35aSPeter Klausler return &child->BeginIoStatement<ChildUnformattedIoStatementState<DIR>>( 254df38f35aSPeter Klausler *child, sourceFile, sourceLine); 25543fadefbSpeter klausler } else { 256df38f35aSPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>( 25711f928afSPeter Klausler iostat, nullptr /* no unit */, sourceFile, sourceLine); 258df38f35aSPeter Klausler } 259df38f35aSPeter Klausler } else { 260df38f35aSPeter Klausler if (iostat == IostatOk) { 261cfbde714SPeter Klausler iostat = unit->SetDirection(DIR); 262df38f35aSPeter Klausler } 263df38f35aSPeter Klausler if (iostat == IostatOk) { 26443fadefbSpeter klausler IoStatementState &io{ 265cfbde714SPeter Klausler unit->BeginIoStatement<ExternalUnformattedIoStatementState<DIR>>( 266921316afSPeter Klausler terminator, *unit, sourceFile, sourceLine)}; 267d879ac8aSpeter klausler if constexpr (DIR == Direction::Output) { 268cfbde714SPeter Klausler if (unit->access == Access::Sequential) { 2693b635714Speter klausler // Create space for (sub)record header to be completed by 270b03628d9Speter klausler // ExternalFileUnit::AdvanceRecord() 271cfbde714SPeter Klausler unit->recordLength.reset(); // in case of prior BACKSPACE 27295696d56Speter klausler io.Emit("\0\0\0\0", 4); // placeholder for record length header 27395696d56Speter klausler } 2743b635714Speter klausler } 27595696d56Speter klausler return &io; 276df38f35aSPeter Klausler } else { 277cfbde714SPeter Klausler return &unit->BeginIoStatement<ErroneousIoStatementState>( 278921316afSPeter Klausler terminator, iostat, unit, sourceFile, sourceLine); 279df38f35aSPeter Klausler } 28095696d56Speter klausler } 28143fadefbSpeter klausler } 28295696d56Speter klausler 283f3c31d70SSlava Zakharin Cookie IODEF(BeginUnformattedOutput)( 2843b635714Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 2853b635714Speter klausler return BeginUnformattedIO<Direction::Output>( 2863b635714Speter klausler unitNumber, sourceFile, sourceLine); 2873b635714Speter klausler } 2883b635714Speter klausler 289f3c31d70SSlava Zakharin Cookie IODEF(BeginUnformattedInput)( 2903b635714Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 2913b635714Speter klausler return BeginUnformattedIO<Direction::Input>( 2923b635714Speter klausler unitNumber, sourceFile, sourceLine); 2933b635714Speter klausler } 2943b635714Speter klausler 295f3c31d70SSlava Zakharin Cookie IODEF(BeginOpenUnit)( // OPEN(without NEWUNIT=) 29695696d56Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 2973b635714Speter klausler Terminator terminator{sourceFile, sourceLine}; 298cfbde714SPeter Klausler bool wasExtant{false}; 299cfbde714SPeter Klausler if (ExternalFileUnit * 300cfbde714SPeter Klausler unit{ExternalFileUnit::LookUpOrCreate( 301cfbde714SPeter Klausler unitNumber, terminator, wasExtant)}) { 30279f6b812SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 30379f6b812SPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>( 30479f6b812SPeter Klausler IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile, 30579f6b812SPeter Klausler sourceLine); 30679f6b812SPeter Klausler } else { 307afdbf1b7SPeter Klausler return &unit->BeginIoStatement<OpenStatementState>(terminator, *unit, 308afdbf1b7SPeter Klausler wasExtant, false /*not NEWUNIT=*/, sourceFile, sourceLine); 30979f6b812SPeter Klausler } 310cfbde714SPeter Klausler } else { 311c078e464SPeter Klausler return NoopUnit(terminator, unitNumber, IostatBadUnitNumber); 312cfbde714SPeter Klausler } 31395696d56Speter klausler } 31495696d56Speter klausler 315f3c31d70SSlava Zakharin Cookie IODEF(BeginOpenNewUnit)( // OPEN(NEWUNIT=j) 31695696d56Speter klausler const char *sourceFile, int sourceLine) { 3173b635714Speter klausler Terminator terminator{sourceFile, sourceLine}; 318c7f4c333SPeter Klausler ExternalFileUnit &unit{ 319c7f4c333SPeter Klausler ExternalFileUnit::NewUnit(terminator, false /*not child I/O*/)}; 320afdbf1b7SPeter Klausler return &unit.BeginIoStatement<OpenStatementState>(terminator, unit, 321afdbf1b7SPeter Klausler false /*was an existing file*/, true /*NEWUNIT=*/, sourceFile, 322afdbf1b7SPeter Klausler sourceLine); 32395696d56Speter klausler } 32495696d56Speter klausler 325f3c31d70SSlava Zakharin Cookie IODEF(BeginWait)(ExternalUnit unitNumber, AsynchronousId id, 326166d6ed5SPeter Klausler const char *sourceFile, int sourceLine) { 327921316afSPeter Klausler Terminator terminator{sourceFile, sourceLine}; 328166d6ed5SPeter Klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) { 329166d6ed5SPeter Klausler if (unit->Wait(id)) { 330921316afSPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator, 331166d6ed5SPeter Klausler *unit, ExternalMiscIoStatementState::Wait, sourceFile, sourceLine); 332166d6ed5SPeter Klausler } else { 333166d6ed5SPeter Klausler return &unit->BeginIoStatement<ErroneousIoStatementState>( 334921316afSPeter Klausler terminator, IostatBadWaitId, unit, sourceFile, sourceLine); 335166d6ed5SPeter Klausler } 336166d6ed5SPeter Klausler } else { 337c078e464SPeter Klausler return NoopUnit( 338c078e464SPeter Klausler terminator, unitNumber, id == 0 ? IostatOk : IostatBadWaitUnit); 339deb62f5aSPeter Klausler } 340166d6ed5SPeter Klausler } 341f3c31d70SSlava Zakharin Cookie IODEF(BeginWaitAll)( 342166d6ed5SPeter Klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 34317853928SPeter Klausler return IONAME(BeginWait)(unitNumber, 0 /*no ID=*/, sourceFile, sourceLine); 344deb62f5aSPeter Klausler } 345deb62f5aSPeter Klausler 346f3c31d70SSlava Zakharin Cookie IODEF(BeginClose)( 34795696d56Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 348921316afSPeter Klausler Terminator terminator{sourceFile, sourceLine}; 34979f6b812SPeter Klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) { 35079f6b812SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 35179f6b812SPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>( 35279f6b812SPeter Klausler IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile, 35379f6b812SPeter Klausler sourceLine); 35479f6b812SPeter Klausler } 35579f6b812SPeter Klausler } 3563b635714Speter klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUpForClose(unitNumber)}) { 35795696d56Speter klausler return &unit->BeginIoStatement<CloseStatementState>( 358921316afSPeter Klausler terminator, *unit, sourceFile, sourceLine); 35995696d56Speter klausler } else { 36095696d56Speter klausler // CLOSE(UNIT=bad unit) is just a no-op 361c078e464SPeter Klausler return NoopUnit(terminator, unitNumber); 36295696d56Speter klausler } 36395696d56Speter klausler } 36495696d56Speter klausler 365f3c31d70SSlava Zakharin Cookie IODEF(BeginFlush)( 3665d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 367921316afSPeter Klausler Terminator terminator{sourceFile, sourceLine}; 3689ddd0792SPeter Klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) { 36979f6b812SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 37079f6b812SPeter Klausler return &child->BeginIoStatement<ExternalMiscIoStatementState>( 37179f6b812SPeter Klausler *unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine); 37279f6b812SPeter Klausler } else { 373921316afSPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator, 3749ddd0792SPeter Klausler *unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine); 37579f6b812SPeter Klausler } 3769ddd0792SPeter Klausler } else { 377c078e464SPeter Klausler // FLUSH(UNIT=bad unit) is an error; an unconnected unit is a no-op 378c078e464SPeter Klausler return NoopUnit(terminator, unitNumber, 379c078e464SPeter Klausler unitNumber >= 0 ? IostatOk : IostatBadFlushUnit); 3809ddd0792SPeter Klausler } 3815d5b9682Speter klausler } 3825d5b9682Speter klausler 383f3c31d70SSlava Zakharin Cookie IODEF(BeginBackspace)( 3845d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 3855d5b9682Speter klausler Terminator terminator{sourceFile, sourceLine}; 386142db43bSPeter Klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) { 38779f6b812SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 38879f6b812SPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>( 38979f6b812SPeter Klausler IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile, 39079f6b812SPeter Klausler sourceLine); 39179f6b812SPeter Klausler } else { 392921316afSPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator, 39379f6b812SPeter Klausler *unit, ExternalMiscIoStatementState::Backspace, sourceFile, 39479f6b812SPeter Klausler sourceLine); 39579f6b812SPeter Klausler } 396142db43bSPeter Klausler } else { 397c078e464SPeter Klausler return NoopUnit(terminator, unitNumber, IostatBadBackspaceUnit); 398142db43bSPeter Klausler } 3995d5b9682Speter klausler } 4005d5b9682Speter klausler 401f3c31d70SSlava Zakharin Cookie IODEF(BeginEndfile)( 4025d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 4035d5b9682Speter klausler Terminator terminator{sourceFile, sourceLine}; 404cfbde714SPeter Klausler Cookie errorCookie{nullptr}; 405cfbde714SPeter Klausler if (ExternalFileUnit * 40671e0261fSSlava Zakharin unit{GetOrCreateUnit(unitNumber, Direction::Output, 40771e0261fSSlava Zakharin Fortran::common::nullopt, terminator, errorCookie)}) { 40879f6b812SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 40979f6b812SPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>( 41079f6b812SPeter Klausler IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile, 41179f6b812SPeter Klausler sourceLine); 41279f6b812SPeter Klausler } else { 413921316afSPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator, 414cfbde714SPeter Klausler *unit, ExternalMiscIoStatementState::Endfile, sourceFile, sourceLine); 41579f6b812SPeter Klausler } 416cfbde714SPeter Klausler } else { 417cfbde714SPeter Klausler return errorCookie; 418cfbde714SPeter Klausler } 4195d5b9682Speter klausler } 4205d5b9682Speter klausler 421f3c31d70SSlava Zakharin Cookie IODEF(BeginRewind)( 4225d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 4235d5b9682Speter klausler Terminator terminator{sourceFile, sourceLine}; 424cfbde714SPeter Klausler Cookie errorCookie{nullptr}; 425cfbde714SPeter Klausler if (ExternalFileUnit * 42671e0261fSSlava Zakharin unit{GetOrCreateUnit(unitNumber, Direction::Input, 42771e0261fSSlava Zakharin Fortran::common::nullopt, terminator, errorCookie)}) { 42879f6b812SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 42979f6b812SPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>( 43079f6b812SPeter Klausler IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile, 43179f6b812SPeter Klausler sourceLine); 43279f6b812SPeter Klausler } else { 433921316afSPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator, 434cfbde714SPeter Klausler *unit, ExternalMiscIoStatementState::Rewind, sourceFile, sourceLine); 43579f6b812SPeter Klausler } 436cfbde714SPeter Klausler } else { 437cfbde714SPeter Klausler return errorCookie; 438cfbde714SPeter Klausler } 4395d5b9682Speter klausler } 4405d5b9682Speter klausler 441f3c31d70SSlava Zakharin Cookie IODEF(BeginInquireUnit)( 442675ad1bcSpeter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { 443921316afSPeter Klausler Terminator terminator{sourceFile, sourceLine}; 444675ad1bcSpeter klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) { 445b1856009SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 446b1856009SPeter Klausler return &child->BeginIoStatement<InquireUnitState>( 447b1856009SPeter Klausler *unit, sourceFile, sourceLine); 448b1856009SPeter Klausler } else { 449675ad1bcSpeter klausler return &unit->BeginIoStatement<InquireUnitState>( 450921316afSPeter Klausler terminator, *unit, sourceFile, sourceLine); 451b1856009SPeter Klausler } 452675ad1bcSpeter klausler } else { 453675ad1bcSpeter klausler // INQUIRE(UNIT=unrecognized unit) 454921316afSPeter Klausler return &New<InquireNoUnitState>{terminator}( 455921316afSPeter Klausler sourceFile, sourceLine, unitNumber) 456675ad1bcSpeter klausler .release() 457675ad1bcSpeter klausler ->ioStatementState(); 458675ad1bcSpeter klausler } 459675ad1bcSpeter klausler } 460675ad1bcSpeter klausler 461f3c31d70SSlava Zakharin Cookie IODEF(BeginInquireFile)(const char *path, std::size_t pathLength, 462675ad1bcSpeter klausler const char *sourceFile, int sourceLine) { 463921316afSPeter Klausler Terminator terminator{sourceFile, sourceLine}; 464921316afSPeter Klausler auto trimmed{SaveDefaultCharacter( 465921316afSPeter Klausler path, TrimTrailingSpaces(path, pathLength), terminator)}; 46603c066abSPeter Klausler if (ExternalFileUnit * 46703c066abSPeter Klausler unit{ExternalFileUnit::LookUp( 468f3c31d70SSlava Zakharin trimmed.get(), Fortran::runtime::strlen(trimmed.get()))}) { 469675ad1bcSpeter klausler // INQUIRE(FILE=) to a connected unit 47079f6b812SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) { 47179f6b812SPeter Klausler return &child->BeginIoStatement<InquireUnitState>( 47279f6b812SPeter Klausler *unit, sourceFile, sourceLine); 47379f6b812SPeter Klausler } else { 474675ad1bcSpeter klausler return &unit->BeginIoStatement<InquireUnitState>( 475921316afSPeter Klausler terminator, *unit, sourceFile, sourceLine); 47679f6b812SPeter Klausler } 477675ad1bcSpeter klausler } else { 478921316afSPeter Klausler return &New<InquireUnconnectedFileState>{terminator}( 479675ad1bcSpeter klausler std::move(trimmed), sourceFile, sourceLine) 480675ad1bcSpeter klausler .release() 481675ad1bcSpeter klausler ->ioStatementState(); 482675ad1bcSpeter klausler } 483675ad1bcSpeter klausler } 484675ad1bcSpeter klausler 485f3c31d70SSlava Zakharin Cookie IODEF(BeginInquireIoLength)(const char *sourceFile, int sourceLine) { 486675ad1bcSpeter klausler Terminator oom{sourceFile, sourceLine}; 487675ad1bcSpeter klausler return &New<InquireIOLengthState>{oom}(sourceFile, sourceLine) 488675ad1bcSpeter klausler .release() 489675ad1bcSpeter klausler ->ioStatementState(); 490675ad1bcSpeter klausler } 491675ad1bcSpeter klausler 49295696d56Speter klausler // Control list items 49395696d56Speter klausler 494f3c31d70SSlava Zakharin void IODEF(EnableHandlers)(Cookie cookie, bool hasIoStat, bool hasErr, 4953b635714Speter klausler bool hasEnd, bool hasEor, bool hasIoMsg) { 49695696d56Speter klausler IoErrorHandler &handler{cookie->GetIoErrorHandler()}; 49795696d56Speter klausler if (hasIoStat) { 49895696d56Speter klausler handler.HasIoStat(); 49995696d56Speter klausler } 50095696d56Speter klausler if (hasErr) { 50195696d56Speter klausler handler.HasErrLabel(); 50295696d56Speter klausler } 50395696d56Speter klausler if (hasEnd) { 50495696d56Speter klausler handler.HasEndLabel(); 50595696d56Speter klausler } 50695696d56Speter klausler if (hasEor) { 50795696d56Speter klausler handler.HasEorLabel(); 50895696d56Speter klausler } 5093b635714Speter klausler if (hasIoMsg) { 5103b635714Speter klausler handler.HasIoMsg(); 5113b635714Speter klausler } 51295696d56Speter klausler } 51395696d56Speter klausler 514f3c31d70SSlava Zakharin static RT_API_ATTRS bool YesOrNo(const char *keyword, std::size_t length, 515f3c31d70SSlava Zakharin const char *what, IoErrorHandler &handler) { 51695696d56Speter klausler static const char *keywords[]{"YES", "NO", nullptr}; 51795696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 5181f879005STim Keith case 0: 5191f879005STim Keith return true; 5201f879005STim Keith case 1: 5211f879005STim Keith return false; 52295696d56Speter klausler default: 5233b635714Speter klausler handler.SignalError(IostatErrorInKeyword, "Invalid %s='%.*s'", what, 5243b635714Speter klausler static_cast<int>(length), keyword); 52595696d56Speter klausler return false; 52695696d56Speter klausler } 52795696d56Speter klausler } 52895696d56Speter klausler 529f3c31d70SSlava Zakharin bool IODEF(SetAdvance)(Cookie cookie, const char *keyword, std::size_t length) { 53095696d56Speter klausler IoStatementState &io{*cookie}; 531deb62f5aSPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 532deb62f5aSPeter Klausler bool nonAdvancing{!YesOrNo(keyword, length, "ADVANCE", handler)}; 533cd0a1226Speter klausler if (nonAdvancing && io.GetConnectionState().access == Access::Direct) { 534deb62f5aSPeter Klausler handler.SignalError("Non-advancing I/O attempted on direct access file"); 535cd0a1226Speter klausler } else { 53679f6b812SPeter Klausler auto *unit{io.GetExternalFileUnit()}; 53779f6b812SPeter Klausler if (unit && unit->GetChildIo()) { 53879f6b812SPeter Klausler // ADVANCE= is ignored for child I/O (12.6.4.8.3 p3) 53979f6b812SPeter Klausler } else { 540cd0a1226Speter klausler io.mutableModes().nonAdvancing = nonAdvancing; 5413b635714Speter klausler } 54279f6b812SPeter Klausler } 543deb62f5aSPeter Klausler return !handler.InError(); 54495696d56Speter klausler } 54595696d56Speter klausler 546f3c31d70SSlava Zakharin bool IODEF(SetBlank)(Cookie cookie, const char *keyword, std::size_t length) { 54795696d56Speter klausler IoStatementState &io{*cookie}; 54895696d56Speter klausler static const char *keywords[]{"NULL", "ZERO", nullptr}; 54995696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 5501f879005STim Keith case 0: 5512b0b9b2eSPeter Klausler io.mutableModes().editingFlags &= ~blankZero; 5521f879005STim Keith return true; 5531f879005STim Keith case 1: 5542b0b9b2eSPeter Klausler io.mutableModes().editingFlags |= blankZero; 5551f879005STim Keith return true; 55695696d56Speter klausler default: 5573b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 55895696d56Speter klausler "Invalid BLANK='%.*s'", static_cast<int>(length), keyword); 55995696d56Speter klausler return false; 56095696d56Speter klausler } 56195696d56Speter klausler } 56295696d56Speter klausler 563f3c31d70SSlava Zakharin bool IODEF(SetDecimal)(Cookie cookie, const char *keyword, std::size_t length) { 56495696d56Speter klausler IoStatementState &io{*cookie}; 56595696d56Speter klausler static const char *keywords[]{"COMMA", "POINT", nullptr}; 56695696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 5671f879005STim Keith case 0: 5682b0b9b2eSPeter Klausler io.mutableModes().editingFlags |= decimalComma; 5691f879005STim Keith return true; 5701f879005STim Keith case 1: 5712b0b9b2eSPeter Klausler io.mutableModes().editingFlags &= ~decimalComma; 5721f879005STim Keith return true; 57395696d56Speter klausler default: 5743b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 57595696d56Speter klausler "Invalid DECIMAL='%.*s'", static_cast<int>(length), keyword); 57695696d56Speter klausler return false; 57795696d56Speter klausler } 57895696d56Speter klausler } 57995696d56Speter klausler 580f3c31d70SSlava Zakharin bool IODEF(SetDelim)(Cookie cookie, const char *keyword, std::size_t length) { 58195696d56Speter klausler IoStatementState &io{*cookie}; 58295696d56Speter klausler static const char *keywords[]{"APOSTROPHE", "QUOTE", "NONE", nullptr}; 58395696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 5841f879005STim Keith case 0: 5852b0b9b2eSPeter Klausler io.mutableModes().delim = '\''; 5861f879005STim Keith return true; 5871f879005STim Keith case 1: 5882b0b9b2eSPeter Klausler io.mutableModes().delim = '"'; 5891f879005STim Keith return true; 5901f879005STim Keith case 2: 5912b0b9b2eSPeter Klausler io.mutableModes().delim = '\0'; 5921f879005STim Keith return true; 59395696d56Speter klausler default: 5943b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 59595696d56Speter klausler "Invalid DELIM='%.*s'", static_cast<int>(length), keyword); 59695696d56Speter klausler return false; 59795696d56Speter klausler } 59895696d56Speter klausler } 59995696d56Speter klausler 600f3c31d70SSlava Zakharin bool IODEF(SetPad)(Cookie cookie, const char *keyword, std::size_t length) { 60195696d56Speter klausler IoStatementState &io{*cookie}; 602deb62f5aSPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 603deb62f5aSPeter Klausler io.mutableModes().pad = YesOrNo(keyword, length, "PAD", handler); 604deb62f5aSPeter Klausler return !handler.InError(); 60595696d56Speter klausler } 60695696d56Speter klausler 607f3c31d70SSlava Zakharin bool IODEF(SetPos)(Cookie cookie, std::int64_t pos) { 6083b635714Speter klausler IoStatementState &io{*cookie}; 609991696c2SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 6103b635714Speter klausler if (auto *unit{io.GetExternalFileUnit()}) { 611d771245aSPeter Klausler return unit->SetStreamPos(pos, handler); 6122a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) { 613d771245aSPeter Klausler handler.Crash("SetPos() called on internal unit"); 6142a07db4cSPeter Klausler } 6153b635714Speter klausler return false; 6163b635714Speter klausler } 6173b635714Speter klausler 618f3c31d70SSlava Zakharin bool IODEF(SetRec)(Cookie cookie, std::int64_t rec) { 6193b635714Speter klausler IoStatementState &io{*cookie}; 620991696c2SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 6213b635714Speter klausler if (auto *unit{io.GetExternalFileUnit()}) { 62279f6b812SPeter Klausler if (unit->GetChildIo()) { 62379f6b812SPeter Klausler handler.SignalError( 62479f6b812SPeter Klausler IostatBadOpOnChildUnit, "REC= specifier on child I/O"); 62579f6b812SPeter Klausler } else { 626bf95854eSPeter Klausler handler.HasRec(); 627d771245aSPeter Klausler unit->SetDirectRec(rec, handler); 62879f6b812SPeter Klausler } 629d771245aSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) { 630d771245aSPeter Klausler handler.Crash("SetRec() called on internal unit"); 6313b635714Speter klausler } 6323b635714Speter klausler return true; 6333b635714Speter klausler } 63495696d56Speter klausler 635f3c31d70SSlava Zakharin bool IODEF(SetRound)(Cookie cookie, const char *keyword, std::size_t length) { 63695696d56Speter klausler IoStatementState &io{*cookie}; 63795696d56Speter klausler static const char *keywords[]{"UP", "DOWN", "ZERO", "NEAREST", "COMPATIBLE", 63895696d56Speter klausler "PROCESSOR_DEFINED", nullptr}; 63995696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 6401f879005STim Keith case 0: 6412b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundUp; 6421f879005STim Keith return true; 6431f879005STim Keith case 1: 6442b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundDown; 6451f879005STim Keith return true; 6461f879005STim Keith case 2: 6472b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundToZero; 6481f879005STim Keith return true; 6491f879005STim Keith case 3: 6502b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundNearest; 6511f879005STim Keith return true; 6521f879005STim Keith case 4: 6532b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundCompatible; 6541f879005STim Keith return true; 65595696d56Speter klausler case 5: 6562b0b9b2eSPeter Klausler io.mutableModes().round = executionEnvironment.defaultOutputRoundingMode; 65795696d56Speter klausler return true; 65895696d56Speter klausler default: 6593b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 66095696d56Speter klausler "Invalid ROUND='%.*s'", static_cast<int>(length), keyword); 66195696d56Speter klausler return false; 66295696d56Speter klausler } 66395696d56Speter klausler } 66495696d56Speter klausler 665f3c31d70SSlava Zakharin bool IODEF(SetSign)(Cookie cookie, const char *keyword, std::size_t length) { 66695696d56Speter klausler IoStatementState &io{*cookie}; 6675501c16eSPeter Klausler static const char *keywords[]{ 6685501c16eSPeter Klausler "PLUS", "SUPPRESS", "PROCESSOR_DEFINED", nullptr}; 66995696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 6701f879005STim Keith case 0: 6712b0b9b2eSPeter Klausler io.mutableModes().editingFlags |= signPlus; 6721f879005STim Keith return true; 67395696d56Speter klausler case 1: 67495696d56Speter klausler case 2: // processor default is SS 6752b0b9b2eSPeter Klausler io.mutableModes().editingFlags &= ~signPlus; 67695696d56Speter klausler return true; 67795696d56Speter klausler default: 6783b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 67995696d56Speter klausler "Invalid SIGN='%.*s'", static_cast<int>(length), keyword); 68095696d56Speter klausler return false; 68195696d56Speter klausler } 68295696d56Speter klausler } 68395696d56Speter klausler 684f3c31d70SSlava Zakharin bool IODEF(SetAccess)(Cookie cookie, const char *keyword, std::size_t length) { 68595696d56Speter klausler IoStatementState &io{*cookie}; 68695696d56Speter klausler auto *open{io.get_if<OpenStatementState>()}; 68795696d56Speter klausler if (!open) { 6888f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 6898f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 69095696d56Speter klausler io.GetIoErrorHandler().Crash( 69195696d56Speter klausler "SetAccess() called when not in an OPEN statement"); 6922a07db4cSPeter Klausler } 6932a07db4cSPeter Klausler return false; 6948db4dc86SPeter Klausler } else if (open->completedOperation()) { 6958db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 6968db4dc86SPeter Klausler "SetAccess() called after GetNewUnit() for an OPEN statement"); 69795696d56Speter klausler } 69872abc199Speter klausler static const char *keywords[]{ 69972abc199Speter klausler "SEQUENTIAL", "DIRECT", "STREAM", "APPEND", nullptr}; 70095696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 7011f879005STim Keith case 0: 702675ad1bcSpeter klausler open->set_access(Access::Sequential); 7031f879005STim Keith break; 7041f879005STim Keith case 1: 705675ad1bcSpeter klausler open->set_access(Access::Direct); 7061f879005STim Keith break; 7071f879005STim Keith case 2: 708675ad1bcSpeter klausler open->set_access(Access::Stream); 7091f879005STim Keith break; 71072abc199Speter klausler case 3: // Sun Fortran extension ACCESS=APPEND: treat as if POSITION=APPEND 71172abc199Speter klausler open->set_position(Position::Append); 71272abc199Speter klausler break; 71395696d56Speter klausler default: 7143b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid ACCESS='%.*s'", 7153b635714Speter klausler static_cast<int>(length), keyword); 71695696d56Speter klausler } 71795696d56Speter klausler return true; 71895696d56Speter klausler } 71995696d56Speter klausler 720f3c31d70SSlava Zakharin bool IODEF(SetAction)(Cookie cookie, const char *keyword, std::size_t length) { 72195696d56Speter klausler IoStatementState &io{*cookie}; 72295696d56Speter klausler auto *open{io.get_if<OpenStatementState>()}; 72395696d56Speter klausler if (!open) { 7248f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 7258f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 72695696d56Speter klausler io.GetIoErrorHandler().Crash( 72795696d56Speter klausler "SetAction() called when not in an OPEN statement"); 7282a07db4cSPeter Klausler } 7292a07db4cSPeter Klausler return false; 7308db4dc86SPeter Klausler } else if (open->completedOperation()) { 7318db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 7328db4dc86SPeter Klausler "SetAction() called after GetNewUnit() for an OPEN statement"); 73395696d56Speter klausler } 73471e0261fSSlava Zakharin Fortran::common::optional<Action> action; 73595696d56Speter klausler static const char *keywords[]{"READ", "WRITE", "READWRITE", nullptr}; 73695696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 7371f879005STim Keith case 0: 738ea4758a1Speter klausler action = Action::Read; 7391f879005STim Keith break; 7401f879005STim Keith case 1: 741ea4758a1Speter klausler action = Action::Write; 7421f879005STim Keith break; 7431f879005STim Keith case 2: 744ea4758a1Speter klausler action = Action::ReadWrite; 7451f879005STim Keith break; 74695696d56Speter klausler default: 7473b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid ACTION='%.*s'", 7483b635714Speter klausler static_cast<int>(length), keyword); 74995696d56Speter klausler return false; 75095696d56Speter klausler } 751ea4758a1Speter klausler RUNTIME_CHECK(io.GetIoErrorHandler(), action.has_value()); 75295696d56Speter klausler if (open->wasExtant()) { 753ea4758a1Speter klausler if ((*action != Action::Write) != open->unit().mayRead() || 754ea4758a1Speter klausler (*action != Action::Read) != open->unit().mayWrite()) { 7553b635714Speter klausler open->SignalError("ACTION= may not be changed on an open unit"); 75695696d56Speter klausler } 75795696d56Speter klausler } 758ea4758a1Speter klausler open->set_action(*action); 75995696d56Speter klausler return true; 76095696d56Speter klausler } 76195696d56Speter klausler 762f3c31d70SSlava Zakharin bool IODEF(SetAsynchronous)( 76395696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) { 76495696d56Speter klausler IoStatementState &io{*cookie}; 765deb62f5aSPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 766deb62f5aSPeter Klausler bool isYes{YesOrNo(keyword, length, "ASYNCHRONOUS", handler)}; 767deb62f5aSPeter Klausler if (auto *open{io.get_if<OpenStatementState>()}) { 768deb62f5aSPeter Klausler if (open->completedOperation()) { 769deb62f5aSPeter Klausler handler.Crash( 7708db4dc86SPeter Klausler "SetAsynchronous() called after GetNewUnit() for an OPEN statement"); 77195696d56Speter klausler } 772deb62f5aSPeter Klausler open->unit().set_mayAsynchronous(isYes); 773*fee393e4SPeter Klausler } else if (!isYes) { 774*fee393e4SPeter Klausler // ASYNCHRONOUS='NO' is the default, so this is a no-op 775166d6ed5SPeter Klausler } else if (auto *ext{io.get_if<ExternalIoStatementBase>()}) { 776166d6ed5SPeter Klausler if (ext->unit().mayAsynchronous()) { 777166d6ed5SPeter Klausler ext->SetAsynchronous(); 778166d6ed5SPeter Klausler } else { 779deb62f5aSPeter Klausler handler.SignalError(IostatBadAsynchronous); 78095696d56Speter klausler } 7818f3357b7SPeter Klausler } else if (!io.get_if<NoopStatementState>() && 7828f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 783*fee393e4SPeter Klausler handler.Crash("SetAsynchronous('YES') called when not in an OPEN or " 784*fee393e4SPeter Klausler "external I/O statement"); 785deb62f5aSPeter Klausler } 786deb62f5aSPeter Klausler return !handler.InError(); 78795696d56Speter klausler } 78895696d56Speter klausler 789f3c31d70SSlava Zakharin bool IODEF(SetCarriagecontrol)( 790c9637577Speter klausler Cookie cookie, const char *keyword, std::size_t length) { 791c9637577Speter klausler IoStatementState &io{*cookie}; 792c9637577Speter klausler auto *open{io.get_if<OpenStatementState>()}; 793c9637577Speter klausler if (!open) { 7948f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 7958f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 796c9637577Speter klausler io.GetIoErrorHandler().Crash( 797c9637577Speter klausler "SetCarriageControl() called when not in an OPEN statement"); 7982a07db4cSPeter Klausler } 7992a07db4cSPeter Klausler return false; 8008db4dc86SPeter Klausler } else if (open->completedOperation()) { 8018db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 8028db4dc86SPeter Klausler "SetCarriageControl() called after GetNewUnit() for an OPEN statement"); 803c9637577Speter klausler } 804c9637577Speter klausler static const char *keywords[]{"LIST", "FORTRAN", "NONE", nullptr}; 805c9637577Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 806c9637577Speter klausler case 0: 807c9637577Speter klausler return true; 808c9637577Speter klausler case 1: 809c9637577Speter klausler case 2: 810c9637577Speter klausler open->SignalError(IostatErrorInKeyword, 811c9637577Speter klausler "Unimplemented CARRIAGECONTROL='%.*s'", static_cast<int>(length), 812c9637577Speter klausler keyword); 813c9637577Speter klausler return false; 814c9637577Speter klausler default: 815c9637577Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid CARRIAGECONTROL='%.*s'", 816c9637577Speter klausler static_cast<int>(length), keyword); 817c9637577Speter klausler return false; 818c9637577Speter klausler } 819c9637577Speter klausler } 820c9637577Speter klausler 821f3c31d70SSlava Zakharin bool IODEF(SetConvert)(Cookie cookie, const char *keyword, std::size_t length) { 8228f2c5c43Speter klausler IoStatementState &io{*cookie}; 8238f2c5c43Speter klausler auto *open{io.get_if<OpenStatementState>()}; 8248f2c5c43Speter klausler if (!open) { 8258f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 8268f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 8278f2c5c43Speter klausler io.GetIoErrorHandler().Crash( 8288f2c5c43Speter klausler "SetConvert() called when not in an OPEN statement"); 8292a07db4cSPeter Klausler } 8302a07db4cSPeter Klausler return false; 8318db4dc86SPeter Klausler } else if (open->completedOperation()) { 8328db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 8338db4dc86SPeter Klausler "SetConvert() called after GetNewUnit() for an OPEN statement"); 8348f2c5c43Speter klausler } 8358f2c5c43Speter klausler if (auto convert{GetConvertFromString(keyword, length)}) { 8368f2c5c43Speter klausler open->set_convert(*convert); 8378f2c5c43Speter klausler return true; 8388f2c5c43Speter klausler } else { 8398f2c5c43Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid CONVERT='%.*s'", 8408f2c5c43Speter klausler static_cast<int>(length), keyword); 8418f2c5c43Speter klausler return false; 8428f2c5c43Speter klausler } 8438f2c5c43Speter klausler } 8448f2c5c43Speter klausler 845f3c31d70SSlava Zakharin bool IODEF(SetEncoding)( 84695696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) { 84795696d56Speter klausler IoStatementState &io{*cookie}; 84895696d56Speter klausler auto *open{io.get_if<OpenStatementState>()}; 84995696d56Speter klausler if (!open) { 8508f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 8518f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 85295696d56Speter klausler io.GetIoErrorHandler().Crash( 85395696d56Speter klausler "SetEncoding() called when not in an OPEN statement"); 8542a07db4cSPeter Klausler } 8552a07db4cSPeter Klausler return false; 8568db4dc86SPeter Klausler } else if (open->completedOperation()) { 8578db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 8588db4dc86SPeter Klausler "SetEncoding() called after GetNewUnit() for an OPEN statement"); 85995696d56Speter klausler } 860c9b31daeSPeter Klausler // Allow the encoding to be changed on an open unit -- it's 861c9b31daeSPeter Klausler // useful and safe. 86295696d56Speter klausler static const char *keywords[]{"UTF-8", "DEFAULT", nullptr}; 86395696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 8641f879005STim Keith case 0: 865c9b31daeSPeter Klausler open->unit().isUTF8 = true; 8661f879005STim Keith break; 8671f879005STim Keith case 1: 868c9b31daeSPeter Klausler open->unit().isUTF8 = false; 8691f879005STim Keith break; 87095696d56Speter klausler default: 8713b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid ENCODING='%.*s'", 8723b635714Speter klausler static_cast<int>(length), keyword); 87395696d56Speter klausler } 87495696d56Speter klausler return true; 87595696d56Speter klausler } 87695696d56Speter klausler 877f3c31d70SSlava Zakharin bool IODEF(SetForm)(Cookie cookie, const char *keyword, std::size_t length) { 87895696d56Speter klausler IoStatementState &io{*cookie}; 87995696d56Speter klausler auto *open{io.get_if<OpenStatementState>()}; 88095696d56Speter klausler if (!open) { 8818f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 8828f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 88395696d56Speter klausler io.GetIoErrorHandler().Crash( 884c9637577Speter klausler "SetForm() called when not in an OPEN statement"); 8852a07db4cSPeter Klausler } 8868db4dc86SPeter Klausler } else if (open->completedOperation()) { 8878db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 8888db4dc86SPeter Klausler "SetForm() called after GetNewUnit() for an OPEN statement"); 88995696d56Speter klausler } 89095696d56Speter klausler static const char *keywords[]{"FORMATTED", "UNFORMATTED", nullptr}; 89195696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) { 8921f879005STim Keith case 0: 893675ad1bcSpeter klausler open->set_isUnformatted(false); 8941f879005STim Keith break; 8951f879005STim Keith case 1: 896675ad1bcSpeter klausler open->set_isUnformatted(true); 8971f879005STim Keith break; 89895696d56Speter klausler default: 8993b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid FORM='%.*s'", 9003b635714Speter klausler static_cast<int>(length), keyword); 90195696d56Speter klausler } 90295696d56Speter klausler return true; 90395696d56Speter klausler } 90495696d56Speter klausler 905f3c31d70SSlava Zakharin bool IODEF(SetPosition)( 90695696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) { 90795696d56Speter klausler IoStatementState &io{*cookie}; 90895696d56Speter klausler auto *open{io.get_if<OpenStatementState>()}; 90995696d56Speter klausler if (!open) { 9108f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 9118f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 91295696d56Speter klausler io.GetIoErrorHandler().Crash( 91395696d56Speter klausler "SetPosition() called when not in an OPEN statement"); 9142a07db4cSPeter Klausler } 9152a07db4cSPeter Klausler return false; 9168db4dc86SPeter Klausler } else if (open->completedOperation()) { 9178db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 9188db4dc86SPeter Klausler "SetPosition() called after GetNewUnit() for an OPEN statement"); 91995696d56Speter klausler } 92095696d56Speter klausler static const char *positions[]{"ASIS", "REWIND", "APPEND", nullptr}; 92195696d56Speter klausler switch (IdentifyValue(keyword, length, positions)) { 9221f879005STim Keith case 0: 9231f879005STim Keith open->set_position(Position::AsIs); 9241f879005STim Keith return true; 9251f879005STim Keith case 1: 9261f879005STim Keith open->set_position(Position::Rewind); 9271f879005STim Keith return true; 9281f879005STim Keith case 2: 9291f879005STim Keith open->set_position(Position::Append); 9301f879005STim Keith return true; 93195696d56Speter klausler default: 9323b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 93395696d56Speter klausler "Invalid POSITION='%.*s'", static_cast<int>(length), keyword); 93495696d56Speter klausler } 93595696d56Speter klausler return true; 93695696d56Speter klausler } 93795696d56Speter klausler 938f3c31d70SSlava Zakharin bool IODEF(SetRecl)(Cookie cookie, std::size_t n) { 93995696d56Speter klausler IoStatementState &io{*cookie}; 94095696d56Speter klausler auto *open{io.get_if<OpenStatementState>()}; 94195696d56Speter klausler if (!open) { 9428f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 9438f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 94495696d56Speter klausler io.GetIoErrorHandler().Crash( 94595696d56Speter klausler "SetRecl() called when not in an OPEN statement"); 9462a07db4cSPeter Klausler } 9472a07db4cSPeter Klausler return false; 9488db4dc86SPeter Klausler } else if (open->completedOperation()) { 9498db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 9508db4dc86SPeter Klausler "SetRecl() called after GetNewUnit() for an OPEN statement"); 95195696d56Speter klausler } 9525f11d38dSPeter Klausler if (static_cast<std::int64_t>(n) <= 0) { 9533b635714Speter klausler io.GetIoErrorHandler().SignalError("RECL= must be greater than zero"); 954e847b303SPeter Klausler return false; 955e847b303SPeter Klausler } else if (open->wasExtant() && 956e847b303SPeter Klausler open->unit().openRecl.value_or(0) != static_cast<std::int64_t>(n)) { 9573b635714Speter klausler open->SignalError("RECL= may not be changed for an open unit"); 958e847b303SPeter Klausler return false; 959e847b303SPeter Klausler } else { 96006ca9f24SPeter Klausler open->unit().openRecl = n; 96195696d56Speter klausler return true; 96295696d56Speter klausler } 963e847b303SPeter Klausler } 96495696d56Speter klausler 965f3c31d70SSlava Zakharin bool IODEF(SetStatus)(Cookie cookie, const char *keyword, std::size_t length) { 96695696d56Speter klausler IoStatementState &io{*cookie}; 96795696d56Speter klausler if (auto *open{io.get_if<OpenStatementState>()}) { 9688db4dc86SPeter Klausler if (open->completedOperation()) { 9698db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 9708db4dc86SPeter Klausler "SetStatus() called after GetNewUnit() for an OPEN statement"); 9718db4dc86SPeter Klausler } 97295696d56Speter klausler static const char *statuses[]{ 97395696d56Speter klausler "OLD", "NEW", "SCRATCH", "REPLACE", "UNKNOWN", nullptr}; 97495696d56Speter klausler switch (IdentifyValue(keyword, length, statuses)) { 9751f879005STim Keith case 0: 9761f879005STim Keith open->set_status(OpenStatus::Old); 9771f879005STim Keith return true; 9781f879005STim Keith case 1: 9791f879005STim Keith open->set_status(OpenStatus::New); 9801f879005STim Keith return true; 9811f879005STim Keith case 2: 9821f879005STim Keith open->set_status(OpenStatus::Scratch); 9831f879005STim Keith return true; 9841f879005STim Keith case 3: 9851f879005STim Keith open->set_status(OpenStatus::Replace); 9861f879005STim Keith return true; 9871f879005STim Keith case 4: 9881f879005STim Keith open->set_status(OpenStatus::Unknown); 9891f879005STim Keith return true; 99095696d56Speter klausler default: 9913b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 99295696d56Speter klausler "Invalid STATUS='%.*s'", static_cast<int>(length), keyword); 99395696d56Speter klausler } 99495696d56Speter klausler return false; 99595696d56Speter klausler } 99695696d56Speter klausler if (auto *close{io.get_if<CloseStatementState>()}) { 99795696d56Speter klausler static const char *statuses[]{"KEEP", "DELETE", nullptr}; 99895696d56Speter klausler switch (IdentifyValue(keyword, length, statuses)) { 9991f879005STim Keith case 0: 10001f879005STim Keith close->set_status(CloseStatus::Keep); 10011f879005STim Keith return true; 10021f879005STim Keith case 1: 10031f879005STim Keith close->set_status(CloseStatus::Delete); 10041f879005STim Keith return true; 100595696d56Speter klausler default: 10063b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword, 100795696d56Speter klausler "Invalid STATUS='%.*s'", static_cast<int>(length), keyword); 100895696d56Speter klausler } 100995696d56Speter klausler return false; 101095696d56Speter klausler } 10112a07db4cSPeter Klausler if (io.get_if<NoopStatementState>() || 10122a07db4cSPeter Klausler io.get_if<ErroneousIoStatementState>()) { 101395696d56Speter klausler return true; // don't bother validating STATUS= in a no-op CLOSE 101495696d56Speter klausler } 101595696d56Speter klausler io.GetIoErrorHandler().Crash( 101695696d56Speter klausler "SetStatus() called when not in an OPEN or CLOSE statement"); 101795696d56Speter klausler } 101895696d56Speter klausler 1019f3c31d70SSlava Zakharin bool IODEF(SetFile)(Cookie cookie, const char *path, std::size_t chars) { 102095696d56Speter klausler IoStatementState &io{*cookie}; 102195696d56Speter klausler if (auto *open{io.get_if<OpenStatementState>()}) { 10228db4dc86SPeter Klausler if (open->completedOperation()) { 10238db4dc86SPeter Klausler io.GetIoErrorHandler().Crash( 10248db4dc86SPeter Klausler "SetFile() called after GetNewUnit() for an OPEN statement"); 10258db4dc86SPeter Klausler } 1026675ad1bcSpeter klausler open->set_path(path, chars); 102795696d56Speter klausler return true; 10288f3357b7SPeter Klausler } else if (!io.get_if<NoopStatementState>() && 10298f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 103095696d56Speter klausler io.GetIoErrorHandler().Crash( 103195696d56Speter klausler "SetFile() called when not in an OPEN statement"); 10322a07db4cSPeter Klausler } 103395696d56Speter klausler return false; 103495696d56Speter klausler } 103595696d56Speter klausler 1036f3c31d70SSlava Zakharin bool IODEF(GetNewUnit)(Cookie cookie, int &unit, int kind) { 103795696d56Speter klausler IoStatementState &io{*cookie}; 103895696d56Speter klausler auto *open{io.get_if<OpenStatementState>()}; 103995696d56Speter klausler if (!open) { 10408f3357b7SPeter Klausler if (!io.get_if<NoopStatementState>() && 10418f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 104295696d56Speter klausler io.GetIoErrorHandler().Crash( 104395696d56Speter klausler "GetNewUnit() called when not in an OPEN statement"); 10442a07db4cSPeter Klausler } 10452a07db4cSPeter Klausler return false; 10468db4dc86SPeter Klausler } else if (!open->InError()) { 10478db4dc86SPeter Klausler open->CompleteOperation(); 10488db4dc86SPeter Klausler } 10498db4dc86SPeter Klausler if (open->InError()) { 10508db4dc86SPeter Klausler // A failed OPEN(NEWUNIT=n) does not modify 'n' 10518db4dc86SPeter Klausler return false; 105295696d56Speter klausler } 105373b193aeSPeter Klausler std::int64_t result{open->unit().unitNumber()}; 105473b193aeSPeter Klausler if (!SetInteger(unit, kind, result)) { 1055e3550f19SPeter Steinfeld open->SignalError("GetNewUnit(): bad INTEGER kind(%d) or out-of-range " 105673b193aeSPeter Klausler "value(%jd) for result", 105773b193aeSPeter Klausler kind, static_cast<std::intmax_t>(result)); 105895696d56Speter klausler } 105995696d56Speter klausler return true; 106095696d56Speter klausler } 106195696d56Speter klausler 106295696d56Speter klausler // Data transfers 106395696d56Speter klausler 1064f3c31d70SSlava Zakharin bool IODEF(OutputDescriptor)(Cookie cookie, const Descriptor &descriptor) { 1065cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor); 106695696d56Speter klausler } 106795696d56Speter klausler 1068f3c31d70SSlava Zakharin bool IODEF(InputDescriptor)(Cookie cookie, const Descriptor &descriptor) { 1069cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 10708f2c5c43Speter klausler } 10718f2c5c43Speter klausler 1072f3c31d70SSlava Zakharin bool IODEF(InputInteger)(Cookie cookie, std::int64_t &n, int kind) { 10732a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputInteger")) { 10742a07db4cSPeter Klausler return false; 10752a07db4cSPeter Klausler } 10763ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1077cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1078cc01194cSpeter klausler descriptor.Establish( 1079cc01194cSpeter klausler TypeCategory::Integer, kind, reinterpret_cast<void *>(&n), 0); 1080cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 10813bc2ae95Speter klausler } 10823bc2ae95Speter klausler 1083f3c31d70SSlava Zakharin bool IODEF(InputReal32)(Cookie cookie, float &x) { 10842a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal32")) { 10852a07db4cSPeter Klausler return false; 10862a07db4cSPeter Klausler } 10873ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1088cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1089cc01194cSpeter klausler descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0); 1090cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 10913b635714Speter klausler } 10923b635714Speter klausler 1093f3c31d70SSlava Zakharin bool IODEF(InputReal64)(Cookie cookie, double &x) { 10942a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal64")) { 10952a07db4cSPeter Klausler return false; 10962a07db4cSPeter Klausler } 10973ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1098cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1099cc01194cSpeter klausler descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0); 1100cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 11013bc2ae95Speter klausler } 11023bc2ae95Speter klausler 1103f3c31d70SSlava Zakharin bool IODEF(InputComplex32)(Cookie cookie, float z[2]) { 11042a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex32")) { 11052a07db4cSPeter Klausler return false; 11062a07db4cSPeter Klausler } 11073ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1108cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1109cc01194cSpeter klausler descriptor.Establish( 1110cc01194cSpeter klausler TypeCategory::Complex, 4, reinterpret_cast<void *>(z), 0); 1111cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 11123bc2ae95Speter klausler } 11133bc2ae95Speter klausler 1114f3c31d70SSlava Zakharin bool IODEF(InputComplex64)(Cookie cookie, double z[2]) { 11152a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex64")) { 11162a07db4cSPeter Klausler return false; 11172a07db4cSPeter Klausler } 11183ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1119cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1120cc01194cSpeter klausler descriptor.Establish( 1121cc01194cSpeter klausler TypeCategory::Complex, 8, reinterpret_cast<void *>(z), 0); 1122cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 1123f7be2518Speter klausler } 1124f7be2518Speter klausler 1125f3c31d70SSlava Zakharin bool IODEF(OutputCharacter)( 1126cdfb95adSpeter klausler Cookie cookie, const char *x, std::size_t length, int kind) { 11272a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputCharacter")) { 11282a07db4cSPeter Klausler return false; 11292a07db4cSPeter Klausler } 11303ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1131cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1132cc01194cSpeter klausler descriptor.Establish( 1133cdfb95adSpeter klausler kind, length, reinterpret_cast<void *>(const_cast<char *>(x)), 0); 1134cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor); 1135f7be2518Speter klausler } 11363b635714Speter klausler 1137f3c31d70SSlava Zakharin bool IODEF(InputCharacter)( 1138cdfb95adSpeter klausler Cookie cookie, char *x, std::size_t length, int kind) { 11392a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputCharacter")) { 11402a07db4cSPeter Klausler return false; 11412a07db4cSPeter Klausler } 11423ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1143cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1144cdfb95adSpeter klausler descriptor.Establish(kind, length, reinterpret_cast<void *>(x), 0); 1145cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 114695696d56Speter klausler } 1147f7be2518Speter klausler 1148f3c31d70SSlava Zakharin bool IODEF(InputAscii)(Cookie cookie, char *x, std::size_t length) { 1149cea8b8a7SPeter Klausler return IONAME(InputCharacter)(cookie, x, length, 1); 1150cdfb95adSpeter klausler } 1151cdfb95adSpeter klausler 1152f3c31d70SSlava Zakharin bool IODEF(InputLogical)(Cookie cookie, bool &truth) { 11532a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputLogical")) { 11542a07db4cSPeter Klausler return false; 11552a07db4cSPeter Klausler } 11563ada883fSPeter Klausler StaticDescriptor<0> staticDescriptor; 1157cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()}; 1158cc01194cSpeter klausler descriptor.Establish( 1159cdfb95adSpeter klausler TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0); 1160cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor); 11613b635714Speter klausler } 11623b635714Speter klausler 1163f3c31d70SSlava Zakharin bool IODEF(OutputDerivedType)(Cookie cookie, const Descriptor &descriptor, 11647cf1608bSPeter Klausler const NonTbpDefinedIoTable *table) { 11657cf1608bSPeter Klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor, table); 116609b00ab4SPeter Klausler } 116709b00ab4SPeter Klausler 1168f3c31d70SSlava Zakharin bool IODEF(InputDerivedType)(Cookie cookie, const Descriptor &descriptor, 11697cf1608bSPeter Klausler const NonTbpDefinedIoTable *table) { 11707cf1608bSPeter Klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor, table); 117109b00ab4SPeter Klausler } 117209b00ab4SPeter Klausler 1173f3c31d70SSlava Zakharin std::size_t IODEF(GetSize)(Cookie cookie) { 11744393e377Speter klausler IoStatementState &io{*cookie}; 11758db4dc86SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 11768db4dc86SPeter Klausler if (!handler.InError()) { 11778db4dc86SPeter Klausler io.CompleteOperation(); 11788db4dc86SPeter Klausler } 11794393e377Speter klausler if (const auto *formatted{ 11804393e377Speter klausler io.get_if<FormattedIoStatementState<Direction::Input>>()}) { 11814393e377Speter klausler return formatted->GetEditDescriptorChars(); 11828f3357b7SPeter Klausler } else if (!io.get_if<NoopStatementState>() && 11838f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 11842a07db4cSPeter Klausler handler.Crash("GetIoSize() called for an I/O statement that is not a " 11852a07db4cSPeter Klausler "formatted READ()"); 11864393e377Speter klausler } 11874393e377Speter klausler return 0; 11884393e377Speter klausler } 11894393e377Speter klausler 1190f3c31d70SSlava Zakharin std::size_t IODEF(GetIoLength)(Cookie cookie) { 11914393e377Speter klausler IoStatementState &io{*cookie}; 11928db4dc86SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 11938db4dc86SPeter Klausler if (!handler.InError()) { 11948db4dc86SPeter Klausler io.CompleteOperation(); 11958db4dc86SPeter Klausler } 11964393e377Speter klausler if (const auto *inq{io.get_if<InquireIOLengthState>()}) { 11974393e377Speter klausler return inq->bytes(); 11988f3357b7SPeter Klausler } else if (!io.get_if<NoopStatementState>() && 11998f3357b7SPeter Klausler !io.get_if<ErroneousIoStatementState>()) { 12008db4dc86SPeter Klausler handler.Crash("GetIoLength() called for an I/O statement that is not " 12018db4dc86SPeter Klausler "INQUIRE(IOLENGTH=)"); 12022a07db4cSPeter Klausler } 12034393e377Speter klausler return 0; 12044393e377Speter klausler } 12054393e377Speter klausler 1206f3c31d70SSlava Zakharin void IODEF(GetIoMsg)(Cookie cookie, char *msg, std::size_t length) { 12078db4dc86SPeter Klausler IoStatementState &io{*cookie}; 12088db4dc86SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()}; 12098db4dc86SPeter Klausler if (!handler.InError()) { 12108db4dc86SPeter Klausler io.CompleteOperation(); 12118db4dc86SPeter Klausler } 1212e81c96d6Speter klausler if (handler.InError()) { // leave "msg" alone when no error 12133b635714Speter klausler handler.GetIoMsg(msg, length); 12143b635714Speter klausler } 1215f7be2518Speter klausler } 1216f7be2518Speter klausler 1217f3c31d70SSlava Zakharin AsynchronousId IODEF(GetAsynchronousId)(Cookie cookie) { 12184679132aSjeanPerier IoStatementState &io{*cookie}; 12194679132aSjeanPerier IoErrorHandler &handler{io.GetIoErrorHandler()}; 12204679132aSjeanPerier if (auto *ext{io.get_if<ExternalIoStatementBase>()}) { 12214679132aSjeanPerier return ext->asynchronousID(); 12224679132aSjeanPerier } else if (!io.get_if<NoopStatementState>() && 12234679132aSjeanPerier !io.get_if<ErroneousIoStatementState>()) { 12244679132aSjeanPerier handler.Crash( 12254679132aSjeanPerier "GetAsynchronousId() called when not in an external I/O statement"); 12264679132aSjeanPerier } 12274679132aSjeanPerier return 0; 12284679132aSjeanPerier } 12294679132aSjeanPerier 1230f3c31d70SSlava Zakharin bool IODEF(InquireCharacter)(Cookie cookie, InquiryKeywordHash inquiry, 1231675ad1bcSpeter klausler char *result, std::size_t length) { 1232675ad1bcSpeter klausler IoStatementState &io{*cookie}; 1233675ad1bcSpeter klausler return io.Inquire(inquiry, result, length); 1234675ad1bcSpeter klausler } 1235675ad1bcSpeter klausler 1236f3c31d70SSlava Zakharin bool IODEF(InquireLogical)( 1237675ad1bcSpeter klausler Cookie cookie, InquiryKeywordHash inquiry, bool &result) { 1238675ad1bcSpeter klausler IoStatementState &io{*cookie}; 1239675ad1bcSpeter klausler return io.Inquire(inquiry, result); 1240675ad1bcSpeter klausler } 1241675ad1bcSpeter klausler 1242f3c31d70SSlava Zakharin bool IODEF(InquirePendingId)(Cookie cookie, AsynchronousId id, bool &result) { 1243675ad1bcSpeter klausler IoStatementState &io{*cookie}; 1244675ad1bcSpeter klausler return io.Inquire(HashInquiryKeyword("PENDING"), id, result); 1245675ad1bcSpeter klausler } 1246675ad1bcSpeter klausler 1247f3c31d70SSlava Zakharin bool IODEF(InquireInteger64)( 1248675ad1bcSpeter klausler Cookie cookie, InquiryKeywordHash inquiry, std::int64_t &result, int kind) { 1249675ad1bcSpeter klausler IoStatementState &io{*cookie}; 1250e468f075SPeter Klausler std::int64_t n{0}; // safe "undefined" value 1251675ad1bcSpeter klausler if (io.Inquire(inquiry, n)) { 125273b193aeSPeter Klausler if (SetInteger(result, kind, n)) { 1253675ad1bcSpeter klausler return true; 1254675ad1bcSpeter klausler } 125573b193aeSPeter Klausler io.GetIoErrorHandler().SignalError( 1256e3550f19SPeter Steinfeld "InquireInteger64(): bad INTEGER kind(%d) or out-of-range " 1257e468f075SPeter Klausler "value(%jd) for result", 125873b193aeSPeter Klausler kind, static_cast<std::intmax_t>(n)); 125973b193aeSPeter Klausler } 1260675ad1bcSpeter klausler return false; 1261675ad1bcSpeter klausler } 1262675ad1bcSpeter klausler 1263c58c64d0SJean Perier template <typename INT> 1264f3c31d70SSlava Zakharin static RT_API_ATTRS enum Iostat CheckUnitNumberInRangeImpl(INT unit, 1265f3c31d70SSlava Zakharin bool handleError, char *ioMsg, std::size_t ioMsgLength, 1266f3c31d70SSlava Zakharin const char *sourceFile, int sourceLine) { 12679cfa899bSJean Perier static_assert(sizeof(INT) >= sizeof(ExternalUnit), 12689cfa899bSJean Perier "only intended to be used when the INT to ExternalUnit conversion is " 12699cfa899bSJean Perier "narrowing"); 1270c58c64d0SJean Perier if (unit != static_cast<ExternalUnit>(unit)) { 1271c58c64d0SJean Perier Terminator oom{sourceFile, sourceLine}; 1272c58c64d0SJean Perier IoErrorHandler errorHandler{oom}; 1273c58c64d0SJean Perier if (handleError) { 1274c58c64d0SJean Perier errorHandler.HasIoStat(); 1275c58c64d0SJean Perier if (ioMsg) { 1276c58c64d0SJean Perier errorHandler.HasIoMsg(); 1277c58c64d0SJean Perier } 1278c58c64d0SJean Perier } 1279c58c64d0SJean Perier // Only provide the bad unit number in the message if SignalError can print 1280c58c64d0SJean Perier // it accurately. Otherwise, the generic IostatUnitOverflow message will be 1281c58c64d0SJean Perier // used. 12821c35c1a7SPeter Klausler if constexpr (sizeof(INT) > sizeof(std::intmax_t)) { 12831c35c1a7SPeter Klausler errorHandler.SignalError(IostatUnitOverflow); 12841c35c1a7SPeter Klausler } else if (static_cast<std::intmax_t>(unit) == unit) { 1285c58c64d0SJean Perier errorHandler.SignalError(IostatUnitOverflow, 1286c58c64d0SJean Perier "UNIT number %jd is out of range", static_cast<std::intmax_t>(unit)); 1287c58c64d0SJean Perier } else { 1288c58c64d0SJean Perier errorHandler.SignalError(IostatUnitOverflow); 1289c58c64d0SJean Perier } 1290c58c64d0SJean Perier if (ioMsg) { 1291c58c64d0SJean Perier errorHandler.GetIoMsg(ioMsg, ioMsgLength); 1292c58c64d0SJean Perier } 1293c58c64d0SJean Perier return static_cast<enum Iostat>(errorHandler.GetIoStat()); 1294c58c64d0SJean Perier } 1295c58c64d0SJean Perier return IostatOk; 1296c58c64d0SJean Perier } 1297c58c64d0SJean Perier 1298f3c31d70SSlava Zakharin enum Iostat IODEF(CheckUnitNumberInRange64)(std::int64_t unit, bool handleError, 1299f3c31d70SSlava Zakharin char *ioMsg, std::size_t ioMsgLength, const char *sourceFile, 1300f3c31d70SSlava Zakharin int sourceLine) { 1301c58c64d0SJean Perier return CheckUnitNumberInRangeImpl( 1302c58c64d0SJean Perier unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine); 1303c58c64d0SJean Perier } 1304c58c64d0SJean Perier 1305c58c64d0SJean Perier #ifdef __SIZEOF_INT128__ 1306f3c31d70SSlava Zakharin enum Iostat IODEF(CheckUnitNumberInRange128)(common::int128_t unit, 1307c58c64d0SJean Perier bool handleError, char *ioMsg, std::size_t ioMsgLength, 1308c58c64d0SJean Perier const char *sourceFile, int sourceLine) { 1309c58c64d0SJean Perier return CheckUnitNumberInRangeImpl( 1310c58c64d0SJean Perier unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine); 1311c58c64d0SJean Perier } 1312c58c64d0SJean Perier #endif 1313c58c64d0SJean Perier 131486e511bcSSlava Zakharin RT_EXT_API_GROUP_END 13151f879005STim Keith } // namespace Fortran::runtime::io 1316