diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h --- a/flang/runtime/connection.h +++ b/flang/runtime/connection.h @@ -17,6 +17,8 @@ namespace Fortran::runtime::io { +class IoStatementState; + enum class Direction { Output, Input }; enum class Access { Sequential, Direct, Stream }; @@ -57,40 +59,25 @@ // or an end-of-file READ condition on a sequential access file std::optional endfileRecordNumber; + // Mutable modes set at OPEN() that can be overridden in READ/WRITE & FORMAT + MutableModes modes; // BLANK=, DECIMAL=, SIGN=, ROUND=, PAD=, DELIM=, kP + // Set when processing repeated items during list-directed & NAMELIST input // in order to keep a span of records in frame on a non-positionable file, // so that backspacing to the beginning of the repeated item doesn't require // repositioning the external storage medium when that's impossible. - std::optional resumptionRecordNumber; - - // Mutable modes set at OPEN() that can be overridden in READ/WRITE & FORMAT - MutableModes modes; // BLANK=, DECIMAL=, SIGN=, ROUND=, PAD=, DELIM=, kP + bool pinnedFrame{false}; }; // Utility class for capturing and restoring a position in an input stream. class SavedPosition { public: - explicit SavedPosition(ConnectionState &c) - : connection_{c}, positionInRecord_{c.positionInRecord}, - furthestPositionInRecord_{c.furthestPositionInRecord}, - leftTabLimit_{c.leftTabLimit}, previousResumptionRecordNumber_{ - c.resumptionRecordNumber} { - c.resumptionRecordNumber = c.currentRecordNumber; - } - ~SavedPosition() { - connection_.currentRecordNumber = *connection_.resumptionRecordNumber; - connection_.resumptionRecordNumber = previousResumptionRecordNumber_; - connection_.leftTabLimit = leftTabLimit_; - connection_.furthestPositionInRecord = furthestPositionInRecord_; - connection_.positionInRecord = positionInRecord_; - } + explicit SavedPosition(IoStatementState &); + ~SavedPosition(); private: - ConnectionState &connection_; - std::int64_t positionInRecord_; - std::int64_t furthestPositionInRecord_; - std::optional leftTabLimit_; - std::optional previousResumptionRecordNumber_; + IoStatementState &io_; + ConnectionState saved_; }; } // namespace Fortran::runtime::io diff --git a/flang/runtime/connection.cpp b/flang/runtime/connection.cpp --- a/flang/runtime/connection.cpp +++ b/flang/runtime/connection.cpp @@ -8,6 +8,7 @@ #include "connection.h" #include "environment.h" +#include "io-stmt.h" #include namespace Fortran::runtime::io { @@ -33,4 +34,21 @@ void ConnectionState::HandleRelativePosition(std::int64_t n) { positionInRecord = std::max(leftTabLimit.value_or(0), positionInRecord + n); } + +SavedPosition::SavedPosition(IoStatementState &io) : io_{io} { + ConnectionState &conn{io_.GetConnectionState()}; + saved_ = conn; + conn.pinnedFrame = true; +} + +SavedPosition::~SavedPosition() { + ConnectionState &conn{io_.GetConnectionState()}; + while (conn.currentRecordNumber > saved_.currentRecordNumber) { + io_.BackspaceRecord(); + } + conn.leftTabLimit = saved_.leftTabLimit; + conn.furthestPositionInRecord = saved_.furthestPositionInRecord; + conn.positionInRecord = saved_.positionInRecord; + conn.pinnedFrame = saved_.pinnedFrame; +} } // namespace Fortran::runtime::io diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h --- a/flang/runtime/io-stmt.h +++ b/flang/runtime/io-stmt.h @@ -241,7 +241,7 @@ private: int remaining_{0}; // for "r*" repetition - std::int64_t repeatPositionInRecord_; + std::optional repeatPosition_; bool eatComma_{false}; // consume comma after previously read item bool hitSlash_{false}; // once '/' is seen, nullify further items bool realPart_{false}; diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -680,14 +680,8 @@ comma = ';'; } if (remaining_ > 0 && !realPart_) { // "r*c" repetition in progress - RUNTIME_CHECK( - io.GetIoErrorHandler(), connection.resumptionRecordNumber.has_value()); - while (connection.currentRecordNumber > - connection.resumptionRecordNumber.value_or( - connection.currentRecordNumber)) { - io.BackspaceRecord(); - } - connection.HandleAbsolutePosition(repeatPositionInRecord_); + RUNTIME_CHECK(io.GetIoErrorHandler(), repeatPosition_.has_value()); + repeatPosition_.reset(); // restores the saved position if (!imaginaryPart_) { edit.repeat = std::min(remaining_, maxRepeat); auto ch{io.GetCurrentChar()}; @@ -697,8 +691,8 @@ } } remaining_ -= edit.repeat; - if (remaining_ <= 0) { - connection.resumptionRecordNumber.reset(); + if (remaining_ > 0) { + repeatPosition_.emplace(io); } return edit; } @@ -761,11 +755,8 @@ edit.repeat = std::min(r, maxRepeat); remaining_ = r - edit.repeat; if (remaining_ > 0) { - connection.resumptionRecordNumber = connection.currentRecordNumber; - } else { - connection.resumptionRecordNumber.reset(); + repeatPosition_.emplace(io); } - repeatPositionInRecord_ = connection.positionInRecord; } else { // not a repetition count, just an integer value; rewind connection.positionInRecord = start; } diff --git a/flang/runtime/namelist.cpp b/flang/runtime/namelist.cpp --- a/flang/runtime/namelist.cpp +++ b/flang/runtime/namelist.cpp @@ -359,7 +359,7 @@ if (io.get_if>()) { ConnectionState &connection{io.GetConnectionState()}; if (connection.modes.inNamelist) { - SavedPosition savedPosition{connection}; + SavedPosition savedPosition{io}; if (auto ch{io.GetNextNonBlank()}) { if (IsLegalIdStart(*ch)) { do { @@ -368,7 +368,7 @@ } while (ch && IsLegalIdChar(*ch)); ch = io.GetNextNonBlank(); // TODO: how to deal with NaN(...) ambiguity? - return ch && (ch == '=' || ch == '(' || ch == '%'); + return ch && (*ch == '=' || *ch == '(' || *ch == '%'); } } } diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -406,30 +406,30 @@ // avoid bogus crashes in END/ERR circumstances } else if (access == Access::Sequential) { RUNTIME_CHECK(handler, recordLength.has_value()); + recordOffsetInFrame_ += *recordLength; if (isFixedRecordLength && access == Access::Direct) { - frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; + frameOffsetInFile_ += recordOffsetInFrame_; recordOffsetInFrame_ = 0; } else { RUNTIME_CHECK(handler, isUnformatted.has_value()); + recordLength.reset(); if (isUnformatted.value_or(false)) { // Retain footer in frame for more efficient BACKSPACE - frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; + frameOffsetInFile_ += recordOffsetInFrame_; recordOffsetInFrame_ = sizeof(std::uint32_t); - recordLength.reset(); } else { // formatted - if (FrameLength() > recordOffsetInFrame_ + *recordLength && - Frame()[recordOffsetInFrame_ + *recordLength] == '\r') { + if (FrameLength() > recordOffsetInFrame_ && + Frame()[recordOffsetInFrame_] == '\r') { ++recordOffsetInFrame_; } if (FrameLength() >= recordOffsetInFrame_ && - Frame()[recordOffsetInFrame_ + *recordLength] == '\n') { + Frame()[recordOffsetInFrame_] == '\n') { ++recordOffsetInFrame_; } - if (!resumptionRecordNumber || mayPosition()) { - frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; + if (!pinnedFrame || mayPosition()) { + frameOffsetInFile_ += recordOffsetInFrame_; recordOffsetInFrame_ = 0; } - recordLength.reset(); } } }