summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrzej Warzynski <andrzej.warzynski@arm.com>2022-02-03 15:15:53 +0000
committerAndrzej Warzynski <andrzej.warzynski@arm.com>2022-02-03 15:19:42 +0000
commit4e53e283744b1a314948b1ca139c09811121f70e (patch)
tree96ec4d9c0e6bc7b00a38888a5997ae57a527cb0d
parent449aa4ccc1ebd4ab910dcb2d31210452a88ddd51 (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.h2
-rw-r--r--flang/runtime/connection.h7
-rw-r--r--flang/runtime/edit-input.cpp36
-rw-r--r--flang/runtime/file.h1
-rw-r--r--flang/runtime/io-api.cpp22
-rw-r--r--flang/runtime/io-stmt.cpp64
-rw-r--r--flang/runtime/io-stmt.h57
-rw-r--r--flang/runtime/iostat.cpp4
-rw-r--r--flang/runtime/unit.cpp116
-rw-r--r--flang/runtime/unit.h14
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_;