diff options
author | Andrzej Warzynski <andrzej.warzynski@arm.com> | 2022-02-03 15:15:53 +0000 |
---|---|---|
committer | Andrzej Warzynski <andrzej.warzynski@arm.com> | 2022-02-03 15:19:42 +0000 |
commit | 4e53e283744b1a314948b1ca139c09811121f70e (patch) | |
tree | 96ec4d9c0e6bc7b00a38888a5997ae57a527cb0d | |
parent | 449aa4ccc1ebd4ab910dcb2d31210452a88ddd51 (diff) |
Revert "[flang] Debugging of ACCESS='STREAM' I/O"
This reverts commit be9946b877add0db906090d22840b213c3f41dd2.
This change has caused Flang's Windows buildbot to start failing:
* https://lab.llvm.org/buildbot/#/builders/172/builds/7664
-rw-r--r-- | flang/include/flang/Runtime/iostat.h | 2 | ||||
-rw-r--r-- | flang/runtime/connection.h | 7 | ||||
-rw-r--r-- | flang/runtime/edit-input.cpp | 36 | ||||
-rw-r--r-- | flang/runtime/file.h | 1 | ||||
-rw-r--r-- | flang/runtime/io-api.cpp | 22 | ||||
-rw-r--r-- | flang/runtime/io-stmt.cpp | 64 | ||||
-rw-r--r-- | flang/runtime/io-stmt.h | 57 | ||||
-rw-r--r-- | flang/runtime/iostat.cpp | 4 | ||||
-rw-r--r-- | flang/runtime/unit.cpp | 116 | ||||
-rw-r--r-- | flang/runtime/unit.h | 14 |
10 files changed, 143 insertions, 180 deletions
diff --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h index 07a25c420425..ec1c6a2abdbe 100644 --- a/flang/include/flang/Runtime/iostat.h +++ b/flang/include/flang/Runtime/iostat.h @@ -45,7 +45,7 @@ enum Iostat { IostatInternalWriteOverrun, IostatErrorInFormat, IostatErrorInKeyword, - IostatEndfileDirect, + IostatEndfileNonSequential, IostatEndfileUnwritable, IostatOpenBadRecl, IostatOpenUnknownSize, diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h index b36f7d1eef36..c812312de91d 100644 --- a/flang/runtime/connection.h +++ b/flang/runtime/connection.h @@ -22,6 +22,8 @@ class IoStatementState; enum class Direction { Output, Input }; enum class Access { Sequential, Direct, Stream }; +inline bool IsRecordFile(Access a) { return a != Access::Stream; } + // These characteristics of a connection are immutable after being // established in an OPEN statement. struct ConnectionAttributes { @@ -29,11 +31,6 @@ struct ConnectionAttributes { std::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true bool isUTF8{false}; // ENCODING='UTF-8' std::optional<std::int64_t> openRecl; // RECL= on OPEN - - bool IsRecordFile() const { - // Formatted stream files are viewed as having records, at least on input - return access != Access::Stream || !isUnformatted.value_or(true); - } }; struct ConnectionState : public ConnectionAttributes { diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp index 2e9cd80aa6f9..3460661cc427 100644 --- a/flang/runtime/edit-input.cpp +++ b/flang/runtime/edit-input.cpp @@ -19,7 +19,7 @@ static bool EditBOZInput(IoStatementState &io, const DataEdit &edit, void *n, std::optional<int> remaining; std::optional<char32_t> next{io.PrepareInput(edit, remaining)}; common::UnsignedInt128 value{0}; - for (; next; next = io.NextInField(remaining, edit)) { + for (; next; next = io.NextInField(remaining)) { char32_t ch{*next}; if (ch == ' ' || ch == '\t') { continue; @@ -63,7 +63,7 @@ static bool ScanNumericPrefix(IoStatementState &io, const DataEdit &edit, if (negative || *next == '+') { io.GotChar(); io.SkipSpaces(remaining); - next = io.NextInField(remaining, edit); + next = io.NextInField(remaining, GetDecimalPoint(edit)); } } return negative; @@ -101,7 +101,7 @@ bool EditIntegerInput( bool negate{ScanNumericPrefix(io, edit, next, remaining)}; common::UnsignedInt128 value{0}; bool any{negate}; - for (; next; next = io.NextInField(remaining, edit)) { + for (; next; next = io.NextInField(remaining)) { char32_t ch{*next}; if (ch == ' ' || ch == '\t') { if (edit.modes.editingFlags & blankZero) { @@ -167,7 +167,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io, // Subtle: a blank field of digits could be followed by 'E' or 'D', for (; next && ((*next >= 'a' && *next <= 'z') || (*next >= 'A' && *next <= 'Z')); - next = io.NextInField(remaining, edit)) { + next = io.NextInField(remaining)) { if (*next >= 'a' && *next <= 'z') { Put(*next - 'a' + 'A'); } else { @@ -176,7 +176,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io, } if (next && *next == '(') { // NaN(...) while (next && *next != ')') { - next = io.NextInField(remaining, edit); + next = io.NextInField(remaining); } } exponent = 0; @@ -185,7 +185,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io, Put('.'); // input field is normalized to a fraction auto start{got}; bool bzMode{(edit.modes.editingFlags & blankZero) != 0}; - for (; next; next = io.NextInField(remaining, edit)) { + for (; next; next = io.NextInField(remaining, decimal)) { char32_t ch{*next}; if (ch == ' ' || ch == '\t') { if (bzMode) { @@ -214,7 +214,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io, // Optional exponent letter. Blanks are allowed between the // optional exponent letter and the exponent value. io.SkipSpaces(remaining); - next = io.NextInField(remaining, edit); + next = io.NextInField(remaining); } // The default exponent is -kP, but the scale factor doesn't affect // an explicit exponent. @@ -224,9 +224,9 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io, (bzMode && (*next == ' ' || *next == '\t')))) { bool negExpo{*next == '-'}; if (negExpo || *next == '+') { - next = io.NextInField(remaining, edit); + next = io.NextInField(remaining); } - for (exponent = 0; next; next = io.NextInField(remaining, edit)) { + for (exponent = 0; next; next = io.NextInField(remaining)) { if (*next >= '0' && *next <= '9') { exponent = 10 * exponent + *next - '0'; } else if (bzMode && (*next == ' ' || *next == '\t')) { @@ -257,7 +257,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io, // input value. if (edit.descriptor == DataEdit::ListDirectedImaginaryPart) { if (next && (*next == ' ' || *next == '\t')) { - next = io.NextInField(remaining, edit); + next = io.NextInField(remaining); } if (!next) { // NextInField fails on separators like ')' next = io.GetCurrentChar(); @@ -267,7 +267,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io, } } else if (remaining) { while (next && (*next == ' ' || *next == '\t')) { - next = io.NextInField(remaining, edit); + next = io.NextInField(remaining); } if (next) { return 0; // error: unused nonblank character in fixed-width field @@ -457,7 +457,7 @@ bool EditLogicalInput(IoStatementState &io, const DataEdit &edit, bool &x) { std::optional<int> remaining; std::optional<char32_t> next{io.PrepareInput(edit, remaining)}; if (next && *next == '.') { // skip optional period - next = io.NextInField(remaining, edit); + next = io.NextInField(remaining); } if (!next) { io.GetIoErrorHandler().SignalError("Empty LOGICAL input field"); @@ -480,7 +480,7 @@ bool EditLogicalInput(IoStatementState &io, const DataEdit &edit, bool &x) { if (remaining) { // ignore the rest of the field io.HandleRelativePosition(*remaining); } else if (edit.descriptor == DataEdit::ListDirected) { - while (io.NextInField(remaining, edit)) { // discard rest of field + while (io.NextInField(remaining)) { // discard rest of field } } return true; @@ -520,7 +520,7 @@ static bool EditDelimitedCharacterInput( } static bool EditListDirectedDefaultCharacterInput( - IoStatementState &io, char *x, std::size_t length, const DataEdit &edit) { + IoStatementState &io, char *x, std::size_t length) { auto ch{io.GetCurrentChar()}; if (ch && (*ch == '\'' || *ch == '"')) { io.HandleRelativePosition(1); @@ -532,7 +532,8 @@ static bool EditListDirectedDefaultCharacterInput( // Undelimited list-directed character input: stop at a value separator // or the end of the current record. std::optional<int> remaining{length}; - while (std::optional<char32_t> next{io.NextInField(remaining, edit)}) { + for (std::optional<char32_t> next{io.NextInField(remaining)}; next; + next = io.NextInField(remaining)) { switch (*next) { case ' ': case '\t': @@ -554,7 +555,7 @@ bool EditDefaultCharacterInput( IoStatementState &io, const DataEdit &edit, char *x, std::size_t length) { switch (edit.descriptor) { case DataEdit::ListDirected: - return EditListDirectedDefaultCharacterInput(io, x, length, edit); + return EditListDirectedDefaultCharacterInput(io, x, length); case 'A': case 'G': break; @@ -575,7 +576,8 @@ bool EditDefaultCharacterInput( // characters. When the variable is wider than the field, there's // trailing padding. std::int64_t skip{*remaining - static_cast<std::int64_t>(length)}; - while (std::optional<char32_t> next{io.NextInField(remaining, edit)}) { + for (std::optional<char32_t> next{io.NextInField(remaining)}; next; + next = io.NextInField(remaining)) { if (skip > 0) { --skip; io.GotChar(-1); diff --git a/flang/runtime/file.h b/flang/runtime/file.h index c61ed798289c..137d643f74ae 100644 --- a/flang/runtime/file.h +++ b/flang/runtime/file.h @@ -35,6 +35,7 @@ public: bool mayPosition() const { return mayPosition_; } bool mayAsynchronous() const { return mayAsynchronous_; } void set_mayAsynchronous(bool yes) { mayAsynchronous_ = yes; } + FileOffset position() const { return position_; } bool isTerminal() const { return isTerminal_; } std::optional<FileOffset> knownSize() const { return knownSize_; } diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp index 8c999edba5c9..345577d2d675 100644 --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -524,17 +524,18 @@ bool IONAME(SetPad)(Cookie cookie, const char *keyword, std::size_t length) { bool IONAME(SetPos)(Cookie cookie, std::int64_t pos) { IoStatementState &io{*cookie}; ConnectionState &connection{io.GetConnectionState()}; - IoErrorHandler &handler{io.GetIoErrorHandler()}; if (connection.access != Access::Stream) { - handler.SignalError("POS= may not appear unless ACCESS='STREAM'"); + io.GetIoErrorHandler().SignalError( + "POS= may not appear unless ACCESS='STREAM'"); return false; } - if (pos < 1) { // POS=1 is beginning of file (12.6.2.11) - handler.SignalError("POS=%zd is invalid", static_cast<std::intmax_t>(pos)); + if (pos < 1) { + io.GetIoErrorHandler().SignalError( + "POS=%zd is invalid", static_cast<std::intmax_t>(pos)); return false; } if (auto *unit{io.GetExternalFileUnit()}) { - unit->SetPosition(pos - 1, handler); + unit->SetPosition(pos); return true; } io.GetIoErrorHandler().Crash("SetPos() on internal unit"); @@ -544,22 +545,23 @@ bool IONAME(SetPos)(Cookie cookie, std::int64_t pos) { bool IONAME(SetRec)(Cookie cookie, std::int64_t rec) { IoStatementState &io{*cookie}; ConnectionState &connection{io.GetConnectionState()}; - IoErrorHandler &handler{io.GetIoErrorHandler()}; if (connection.access != Access::Direct) { - handler.SignalError("REC= may not appear unless ACCESS='DIRECT'"); + io.GetIoErrorHandler().SignalError( + "REC= may not appear unless ACCESS='DIRECT'"); return false; } if (!connection.openRecl) { - handler.SignalError("RECL= was not specified"); + io.GetIoErrorHandler().SignalError("RECL= was not specified"); return false; } if (rec < 1) { - handler.SignalError("REC=%zd is invalid", static_cast<std::intmax_t>(rec)); + io.GetIoErrorHandler().SignalError( + "REC=%zd is invalid", static_cast<std::intmax_t>(rec)); return false; } connection.currentRecordNumber = rec; if (auto *unit{io.GetExternalFileUnit()}) { - unit->SetPosition((rec - 1) * *connection.openRecl, handler); + unit->SetPosition((rec - 1) * *connection.openRecl); } return true; } diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp index 7d447bafa880..52d0a1ebe6a3 100644 --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -268,7 +268,7 @@ ExternalIoStatementState<DIR>::ExternalIoStatementState( : ExternalIoStatementBase{unit, sourceFile, sourceLine}, mutableModes_{ unit.modes} { if constexpr (DIR == Direction::Output) { - // If the last statement was a non-advancing IO input statement, the unit + // If the last statement was a non advancing IO input statement, the unit // furthestPositionInRecord was not advanced, but the positionInRecord may // have been advanced. Advance furthestPositionInRecord here to avoid // overwriting the part of the record that has been read with blanks. @@ -505,66 +505,6 @@ bool IoStatementState::EmitField( } } -std::optional<char32_t> IoStatementState::NextInField( - std::optional<int> &remaining, const DataEdit &edit) { - if (!remaining) { // Stream, list-directed, or NAMELIST - if (auto next{GetCurrentChar()}) { - if (edit.IsListDirected()) { - // list-directed or NAMELIST: check for separators - switch (*next) { - case ' ': - case '\t': - case ';': - case '/': - case '(': - case ')': - case '\'': - case '"': - case '*': - case '\n': // for stream access - return std::nullopt; - case ',': - if (edit.modes.editingFlags & decimalComma) { - break; - } else { - return std::nullopt; - } - default: - break; - } - } - HandleRelativePosition(1); - GotChar(); - return next; - } - } else if (*remaining > 0) { - if (auto next{GetCurrentChar()}) { - --*remaining; - HandleRelativePosition(1); - GotChar(); - return next; - } - const ConnectionState &connection{GetConnectionState()}; - if (!connection.IsAtEOF()) { - if (auto length{connection.EffectiveRecordLength()}) { - if (connection.positionInRecord >= *length) { - IoErrorHandler &handler{GetIoErrorHandler()}; - if (mutableModes().nonAdvancing) { - handler.SignalEor(); - } else if (connection.openRecl && !connection.modes.pad) { - handler.SignalError(IostatRecordReadOverrun); - } - if (connection.modes.pad) { // PAD='YES' - --*remaining; - return std::optional<char32_t>{' '}; - } - } - } - } - } - return std::nullopt; -} - bool IoStatementState::Inquire( InquiryKeywordHash inquiry, char *out, std::size_t chars) { return std::visit( @@ -1120,7 +1060,7 @@ bool InquireUnitState::Inquire( result = unit().IsConnected() ? unit().unitNumber() : -1; return true; case HashInquiryKeyword("POS"): - result = unit().InquirePos(); + result = unit().position(); return true; case HashInquiryKeyword("RECL"): if (!unit().IsConnected()) { diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h index 59d4e50460fb..93b3bed73294 100644 --- a/flang/runtime/io-stmt.h +++ b/flang/runtime/io-stmt.h @@ -142,7 +142,7 @@ public: } SkipSpaces(remaining); } - return NextInField(remaining, edit); + return NextInField(remaining); } std::optional<char32_t> SkipSpaces(std::optional<int> &remaining) { @@ -163,10 +163,59 @@ public: return std::nullopt; } - // Acquires the next input character, respecting any applicable field width - // or separator character. std::optional<char32_t> NextInField( - std::optional<int> &remaining, const DataEdit &); + std::optional<int> &remaining, char32_t decimal = '.') { + if (!remaining) { // list-directed or NAMELIST: check for separators + if (auto next{GetCurrentChar()}) { + if (*next == decimal) { // can be ',' + HandleRelativePosition(1); + return next; + } + switch (*next) { + case ' ': + case '\t': + case ',': + case ';': + case '/': + case '(': + case ')': + case '\'': + case '"': + case '*': + case '\n': // for stream access + break; + default: + HandleRelativePosition(1); + return next; + } + } + } else if (*remaining > 0) { + if (auto next{GetCurrentChar()}) { + --*remaining; + HandleRelativePosition(1); + GotChar(); + return next; + } + const ConnectionState &connection{GetConnectionState()}; + if (!connection.IsAtEOF()) { + if (auto length{connection.EffectiveRecordLength()}) { + if (connection.positionInRecord >= *length) { + IoErrorHandler &handler{GetIoErrorHandler()}; + if (mutableModes().nonAdvancing) { + handler.SignalEor(); + } else if (connection.openRecl && !connection.modes.pad) { + handler.SignalError(IostatRecordReadOverrun); + } + if (connection.modes.pad) { // PAD='YES' + --*remaining; + return std::optional<char32_t>{' '}; + } + } + } + } + } + return std::nullopt; + } // Skips spaces, advances records, and ignores NAMELIST comments std::optional<char32_t> GetNextNonBlank() { diff --git a/flang/runtime/iostat.cpp b/flang/runtime/iostat.cpp index 58e3f1b387e1..d58ad6261ac6 100644 --- a/flang/runtime/iostat.cpp +++ b/flang/runtime/iostat.cpp @@ -33,8 +33,8 @@ const char *IostatErrorString(int iostat) { return "Invalid FORMAT"; case IostatErrorInKeyword: return "Bad keyword argument value"; - case IostatEndfileDirect: - return "ENDFILE on direct-access file"; + case IostatEndfileNonSequential: + return "ENDFILE on non-sequential file"; case IostatEndfileUnwritable: return "ENDFILE on read-only file"; case IostatOpenBadRecl: diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp index 3fbb397d996b..363565da6833 100644 --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -151,7 +151,7 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status, if (totalBytes && access == Access::Direct && openRecl.value_or(0) > 0) { endfileRecordNumber = 1 + (*totalBytes / *openRecl); } - if (position == Position::Append && access != Access::Stream) { + if (position == Position::Append) { if (!endfileRecordNumber) { // Fake it so that we can backspace relative from the end endfileRecordNumber = std::numeric_limits<std::int64_t>::max() - 2; @@ -348,10 +348,8 @@ bool ExternalFileUnit::Receive(char *data, std::size_t bytes, furthestPositionInRecord = furthestAfter; return true; } else { - handler.SignalEnd(); - if (access == Access::Sequential) { - endfileRecordNumber = currentRecordNumber; - } + // EOF or error: can be handled & has been signaled + endfileRecordNumber = currentRecordNumber; return false; } } @@ -385,20 +383,18 @@ const char *ExternalFileUnit::FrameNextInput( auto at{recordOffsetInFrame_ + positionInRecord}; auto need{static_cast<std::size_t>(at + bytes)}; auto got{ReadFrame(frameOffsetInFile_, need, handler)}; - SetVariableFormattedRecordLength(); + SetSequentialVariableFormattedRecordLength(); if (got >= need) { return Frame() + at; } handler.SignalEnd(); - if (access == Access::Sequential) { - endfileRecordNumber = currentRecordNumber; - } + endfileRecordNumber = currentRecordNumber; } return nullptr; } -bool ExternalFileUnit::SetVariableFormattedRecordLength() { - if (recordLength || access == Access::Direct) { +bool ExternalFileUnit::SetSequentialVariableFormattedRecordLength() { + if (recordLength || access != Access::Sequential) { return true; } else if (FrameLength() > recordOffsetInFrame_) { const char *record{Frame() + recordOffsetInFrame_}; @@ -434,24 +430,22 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) { recordLength.reset(); handler.SignalEnd(); } - } else { + } else if (access == Access::Sequential) { recordLength.reset(); if (IsAtEOF()) { handler.SignalEnd(); } else { RUNTIME_CHECK(handler, isUnformatted.has_value()); - if (*isUnformatted) { - if (access == Access::Sequential) { - BeginSequentialVariableUnformattedInputRecord(handler); - } - } else { // formatted sequential or stream - BeginVariableFormattedInputRecord(handler); + if (isUnformatted.value_or(false)) { + BeginSequentialVariableUnformattedInputRecord(handler); + } else { // formatted + BeginSequentialVariableFormattedInputRecord(handler); } } } } RUNTIME_CHECK(handler, - recordLength.has_value() || !IsRecordFile() || handler.InError()); + recordLength.has_value() || !IsRecordFile(access) || handler.InError()); return !handler.InError(); } @@ -459,15 +453,14 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) { RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_); beganReadingRecord_ = false; if (handler.InError() && handler.GetIoStat() != IostatEor) { - // Avoid bogus crashes in END/ERR circumstances; but - // still increment the current record number so that - // an attempted read of an endfile record, followed by - // a BACKSPACE, will still be at EOF. - ++currentRecordNumber; - } else if (IsRecordFile()) { + // avoid bogus crashes in END/ERR circumstances + } else if (access == Access::Sequential) { RUNTIME_CHECK(handler, recordLength.has_value()); recordOffsetInFrame_ += *recordLength; - if (access != Access::Direct) { + if (openRecl && access == Access::Direct) { + frameOffsetInFile_ += recordOffsetInFrame_; + recordOffsetInFrame_ = 0; + } else { RUNTIME_CHECK(handler, isUnformatted.has_value()); recordLength.reset(); if (isUnformatted.value_or(false)) { @@ -489,12 +482,8 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) { } } } - ++currentRecordNumber; - } else { // unformatted stream - furthestPositionInRecord = - std::max(furthestPositionInRecord, positionInRecord); - frameOffsetInFile_ += recordOffsetInFrame_ + furthestPositionInRecord; } + ++currentRecordNumber; BeginRecord(); } @@ -505,10 +494,8 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) { } else { // Direction::Output bool ok{true}; RUNTIME_CHECK(handler, isUnformatted.has_value()); - positionInRecord = furthestPositionInRecord; - if (access == Access::Direct) { - if (furthestPositionInRecord < - openRecl.value_or(furthestPositionInRecord)) { + if (openRecl && access == Access::Direct) { + if (furthestPositionInRecord < *openRecl) { // Pad remainder of fixed length record WriteFrame( frameOffsetInFile_, recordOffsetInFrame_ + *openRecl, handler); @@ -517,8 +504,9 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) { *openRecl - furthestPositionInRecord); furthestPositionInRecord = *openRecl; } - } else if (*isUnformatted) { - if (access == Access::Sequential) { + } else { + positionInRecord = furthestPositionInRecord; + if (isUnformatted.value_or(false)) { // Append the length of a sequential unformatted variable-length record // as its footer, then overwrite the reserved first four bytes of the // record with its length as its header. These four bytes were skipped @@ -535,32 +523,27 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) { Emit(reinterpret_cast<const char *>(&length), sizeof length, sizeof length, handler); } else { - // Unformatted stream: nothing to do + // Terminate formatted variable length record + ok = ok && Emit("\n", 1, 1, handler); // TODO: Windows CR+LF } - } else { - // Terminate formatted variable length record - ok = ok && Emit("\n", 1, 1, handler); // TODO: Windows CR+LF } if (IsAfterEndfile()) { return false; } CommitWrites(); + impliedEndfile_ = true; ++currentRecordNumber; - if (access != Access::Direct) { - impliedEndfile_ = IsRecordFile(); - if (IsAtEOF()) { - endfileRecordNumber.reset(); - } + if (IsAtEOF()) { + endfileRecordNumber.reset(); } return ok; } } void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) { - if (access == Access::Direct || !IsRecordFile()) { + if (access != Access::Sequential) { handler.SignalError(IostatBackspaceNonSequential, - "BACKSPACE(UNIT=%d) on direct-access file or unformatted stream", - unitNumber()); + "BACKSPACE(UNIT=%d) on non-sequential file", unitNumber()); } else { if (IsAfterEndfile()) { // BACKSPACE after explicit ENDFILE @@ -607,9 +590,9 @@ void ExternalFileUnit::FlushIfTerminal(IoErrorHandler &handler) { } void ExternalFileUnit::Endfile(IoErrorHandler &handler) { - if (access == Access::Direct) { - handler.SignalError(IostatEndfileDirect, - "ENDFILE(UNIT=%d) on direct-access file", unitNumber()); + if (access != Access::Sequential) { + handler.SignalError(IostatEndfileNonSequential, + "ENDFILE(UNIT=%d) on non-sequential file", unitNumber()); } else if (!mayWrite()) { handler.SignalError(IostatEndfileUnwritable, "ENDFILE(UNIT=%d) on read-only file", unitNumber()); @@ -617,11 +600,9 @@ void ExternalFileUnit::Endfile(IoErrorHandler &handler) { // ENDFILE after ENDFILE } else { DoEndfile(handler); - if (access == Access::Sequential) { - // Explicit ENDFILE leaves position *after* the endfile record - RUNTIME_CHECK(handler, endfileRecordNumber.has_value()); - currentRecordNumber = *endfileRecordNumber + 1; - } + // Explicit ENDFILE leaves position *after* the endfile record + RUNTIME_CHECK(handler, endfileRecordNumber.has_value()); + currentRecordNumber = *endfileRecordNumber + 1; } } @@ -630,18 +611,12 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) { handler.SignalError(IostatRewindNonSequential, "REWIND(UNIT=%d) on non-sequential file", unitNumber()); } else { - SetPosition(0, handler); + DoImpliedEndfile(handler); + SetPosition(0); currentRecordNumber = 1; } } -void ExternalFileUnit::SetPosition(std::int64_t pos, IoErrorHandler &handler) { - DoImpliedEndfile(handler); - frameOffsetInFile_ = pos; - recordOffsetInFrame_ = 0; - BeginRecord(); -} - void ExternalFileUnit::EndIoStatement() { io_.reset(); u_.emplace<std::monostate>(); @@ -690,7 +665,7 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord( positionInRecord = sizeof header; } -void ExternalFileUnit::BeginVariableFormattedInputRecord( +void ExternalFileUnit::BeginSequentialVariableFormattedInputRecord( IoErrorHandler &handler) { if (this == defaultInput) { if (defaultOutput) { @@ -715,7 +690,7 @@ void ExternalFileUnit::BeginVariableFormattedInputRecord( } break; } - } while (!SetVariableFormattedRecordLength()); + } while (!SetSequentialVariableFormattedRecordLength()); } void ExternalFileUnit::BackspaceFixedRecord(IoErrorHandler &handler) { @@ -808,17 +783,14 @@ void ExternalFileUnit::BackspaceVariableFormattedRecord( void ExternalFileUnit::DoImpliedEndfile(IoErrorHandler &handler) { if (impliedEndfile_) { impliedEndfile_ = false; - if (access != Access::Direct && IsRecordFile() && mayPosition()) { + if (access == Access::Sequential && mayPosition()) { DoEndfile(handler); } } } void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) { - if (access == Access::Sequential) { - endfileRecordNumber = currentRecordNumber; - } - FlushOutput(handler); + endfileRecordNumber = currentRecordNumber; Truncate(frameOffsetInFile_ + recordOffsetInFrame_, handler); BeginRecord(); impliedEndfile_ = false; diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h index da6bc4b23d71..b7f4e271c01f 100644 --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -90,10 +90,10 @@ public: void Endfile(IoErrorHandler &); void Rewind(IoErrorHandler &); void EndIoStatement(); - void SetPosition(std::int64_t, IoErrorHandler &); // zero-based - std::int64_t InquirePos() const { - // 12.6.2.11 defines POS=1 as the beginning of file - return frameOffsetInFile_ + 1; + void SetPosition(std::int64_t pos) { + frameOffsetInFile_ = pos; + recordOffsetInFrame_ = 0; + BeginRecord(); } ChildIo *GetChildIo() { return child_.get(); } @@ -104,18 +104,18 @@ private: static UnitMap &GetUnitMap(); const char *FrameNextInput(IoErrorHandler &, std::size_t); void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler &); - void BeginVariableFormattedInputRecord(IoErrorHandler &); + void BeginSequentialVariableFormattedInputRecord(IoErrorHandler &); void BackspaceFixedRecord(IoErrorHandler &); void BackspaceVariableUnformattedRecord(IoErrorHandler &); void BackspaceVariableFormattedRecord(IoErrorHandler &); - bool SetVariableFormattedRecordLength(); + bool SetSequentialVariableFormattedRecordLength(); void DoImpliedEndfile(IoErrorHandler &); void DoEndfile(IoErrorHandler &); void CommitWrites(); int unitNumber_{-1}; Direction direction_{Direction::Output}; - bool impliedEndfile_{false}; // sequential/stream output has taken place + bool impliedEndfile_{false}; // seq. output has taken place bool beganReadingRecord_{false}; Lock lock_; |