diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -121,10 +121,12 @@ terminator.Crash("List-directed I/O attempted on unformatted file"); return nullptr; } + IoErrorHandler handler{terminator}; + unit.SetDirection(DIR, handler); IoStatementState &io{unit.BeginIoStatement>( unit, sourceFile, sourceLine)}; if constexpr (DIR == Direction::Input) { - io.AdvanceRecord(); + unit.BeginReadingRecord(handler); } return &io; } @@ -154,11 +156,13 @@ terminator.Crash("Formatted I/O attempted on unformatted file"); return nullptr; } + IoErrorHandler handler{terminator}; + unit.SetDirection(DIR, handler); IoStatementState &io{ unit.BeginIoStatement>( unit, format, formatLength, sourceFile, sourceLine)}; if constexpr (DIR == Direction::Input) { - io.AdvanceRecord(); + unit.BeginReadingRecord(handler); } return &io; } @@ -181,17 +185,19 @@ Cookie BeginUnformattedIO( ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; - ExternalFileUnit &file{ + ExternalFileUnit &unit{ ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; - if (!file.isUnformatted) { + if (!unit.isUnformatted) { terminator.Crash("Unformatted output attempted on formatted file"); } - IoStatementState &io{file.BeginIoStatement>( - file, sourceFile, sourceLine)}; + IoStatementState &io{unit.BeginIoStatement>( + unit, sourceFile, sourceLine)}; + IoErrorHandler handler{terminator}; + unit.SetDirection(DIR, handler); if constexpr (DIR == Direction::Input) { - io.AdvanceRecord(); + unit.BeginReadingRecord(handler); } else { - if (file.access == Access::Sequential && !file.recordLength.has_value()) { + if (unit.access == Access::Sequential && !unit.isFixedRecordLength) { // Create space for (sub)record header to be completed by // UnformattedIoStatementState::EndIoStatement() io.Emit("\0\0\0\0", 4); // placeholder for record length header @@ -225,8 +231,10 @@ Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j) const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; - return IONAME(BeginOpenUnit)( - ExternalFileUnit::NewUnit(terminator), sourceFile, sourceLine); + ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreate( + ExternalFileUnit::NewUnit(terminator), terminator)}; + return &unit.BeginIoStatement( + unit, false /*wasExtant*/, sourceFile, sourceLine); } Cookie IONAME(BeginClose)( @@ -243,6 +251,42 @@ } } +Cookie IONAME(BeginFlush)( + ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { + Terminator terminator{sourceFile, sourceLine}; + ExternalFileUnit &unit{ + ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; + return &unit.BeginIoStatement( + unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine); +} + +Cookie IONAME(BeginBackspace)( + ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { + Terminator terminator{sourceFile, sourceLine}; + ExternalFileUnit &unit{ + ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; + return &unit.BeginIoStatement( + unit, ExternalMiscIoStatementState::Backspace, sourceFile, sourceLine); +} + +Cookie IONAME(BeginEndfile)( + ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { + Terminator terminator{sourceFile, sourceLine}; + ExternalFileUnit &unit{ + ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; + return &unit.BeginIoStatement( + unit, ExternalMiscIoStatementState::Endfile, sourceFile, sourceLine); +} + +Cookie IONAME(BeginRewind)( + ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { + Terminator terminator{sourceFile, sourceLine}; + ExternalFileUnit &unit{ + ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; + return &unit.BeginIoStatement( + unit, ExternalMiscIoStatementState::Rewind, sourceFile, sourceLine); +} + // Control list items void IONAME(EnableHandlers)(Cookie cookie, bool hasIoStat, bool hasErr, @@ -388,7 +432,7 @@ "REC= may not appear unless ACCESS='DIRECT'"); return false; } - if (!connection.recordLength) { + if (!connection.isFixedRecordLength || !connection.recordLength) { io.GetIoErrorHandler().SignalError("RECL= was not specified"); return false; } @@ -640,10 +684,11 @@ if (n <= 0) { io.GetIoErrorHandler().SignalError("RECL= must be greater than zero"); } - if (open->wasExtant() && open->unit().recordLength.has_value() && - *open->unit().recordLength != static_cast(n)) { + if (open->wasExtant() && open->unit().isFixedRecordLength && + open->unit().recordLength.value_or(n) != static_cast(n)) { open->SignalError("RECL= may not be changed for an open unit"); } + open->unit().isFixedRecordLength = true; open->unit().recordLength = n; return true; } @@ -754,7 +799,17 @@ if (auto *unf{io.get_if>()}) { return unf->Emit(x, length); } - io.GetIoErrorHandler().Crash("OutputUnformatted() called for an I/O " + io.GetIoErrorHandler().Crash("OutputUnformattedBlock() called for an I/O " + "statement that is not unformatted output"); + return false; +} + +bool IONAME(InputUnformattedBlock)(Cookie cookie, char *x, std::size_t length) { + IoStatementState &io{*cookie}; + if (auto *unf{io.get_if>()}) { + return unf->Receive(x, length); + } + io.GetIoErrorHandler().Crash("InputUnformattedBlock() called for an I/O " "statement that is not unformatted output"); return false; } diff --git a/flang/runtime/stop.h b/flang/runtime/stop.h --- a/flang/runtime/stop.h +++ b/flang/runtime/stop.h @@ -20,6 +20,7 @@ bool isErrorStop DEFAULT_VALUE(false), bool quiet DEFAULT_VALUE(false)); NORETURN void RTNAME(StopStatementText)(const char *, bool isErrorStop DEFAULT_VALUE(false), bool quiet DEFAULT_VALUE(false)); +void RTNAME(PauseStatement)(NO_ARGUMENTS); NORETURN void RTNAME(FailImageStatement)(NO_ARGUMENTS); NORETURN void RTNAME(ProgramEndStatement)(NO_ARGUMENTS); diff --git a/flang/runtime/stop.cpp b/flang/runtime/stop.cpp --- a/flang/runtime/stop.cpp +++ b/flang/runtime/stop.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "stop.h" +#include "file.h" #include "io-error.h" #include "terminator.h" #include "unit.h" @@ -71,6 +72,19 @@ std::exit(EXIT_FAILURE); } +void RTNAME(PauseStatement)() { + if (Fortran::runtime::io::IsATerminal(0)) { + Fortran::runtime::io::IoErrorHandler handler{"PAUSE statement"}; + Fortran::runtime::io::ExternalFileUnit::FlushAll(handler); + std::fputs("Fortran PAUSE: hit RETURN to continue:", stderr); + std::fflush(nullptr); + if (std::fgetc(stdin) == EOF) { + CloseAllExternalUnits("PAUSE statement"); + std::exit(EXIT_SUCCESS); + } + } +} + [[noreturn]] void RTNAME(FailImageStatement)() { Fortran::runtime::NotifyOtherImagesOfFailImageStatement(); CloseAllExternalUnits("FAIL IMAGE statement");