diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h --- a/flang/runtime/connection.h +++ b/flang/runtime/connection.h @@ -26,7 +26,7 @@ // established in an OPEN statement. struct ConnectionAttributes { Access access{Access::Sequential}; // ACCESS='SEQUENTIAL', 'DIRECT', 'STREAM' - bool isUnformatted{false}; // FORM='UNFORMATTED' + std::optional isUnformatted; // FORM='UNFORMATTED' if true bool isUTF8{false}; // ENCODING='UTF-8' bool isFixedRecordLength{false}; // RECL= on OPEN std::optional recordLength; // RECL= or current record 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 @@ -155,12 +155,15 @@ unitNumber = DIR == Direction::Input ? 5 : 6; } ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( - unitNumber, DIR, false /*formatted*/, terminator)}; + unitNumber, DIR, false /*!unformatted*/, terminator)}; if (unit.access == Access::Direct) { terminator.Crash("List-directed I/O attempted on direct access file"); return nullptr; } - if (unit.isUnformatted) { + if (!unit.isUnformatted.has_value()) { + unit.isUnformatted = false; + } + if (*unit.isUnformatted) { terminator.Crash("List-directed I/O attempted on unformatted file"); return nullptr; } @@ -191,8 +194,11 @@ unitNumber = DIR == Direction::Input ? 5 : 6; } ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( - unitNumber, DIR, false /*formatted*/, terminator)}; - if (unit.isUnformatted) { + unitNumber, DIR, false /*!unformatted*/, terminator)}; + if (!unit.isUnformatted.has_value()) { + unit.isUnformatted = false; + } + if (*unit.isUnformatted) { terminator.Crash("Formatted I/O attempted on unformatted file"); return nullptr; } @@ -224,8 +230,11 @@ Terminator terminator{sourceFile, sourceLine}; ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( unitNumber, DIR, true /*unformatted*/, terminator)}; - if (!unit.isUnformatted) { - terminator.Crash("Unformatted output attempted on formatted file"); + if (!unit.isUnformatted.has_value()) { + unit.isUnformatted = true; + } + if (!*unit.isUnformatted) { + terminator.Crash("Unformatted I/O attempted on formatted file"); } IoStatementState &io{unit.BeginIoStatement>( unit, sourceFile, sourceLine)}; @@ -310,7 +319,7 @@ ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( - unitNumber, Direction::Output, false /*formatted*/, terminator)}; + unitNumber, Direction::Output, std::nullopt, terminator)}; return &unit.BeginIoStatement( unit, ExternalMiscIoStatementState::Endfile, sourceFile, sourceLine); } @@ -319,7 +328,7 @@ ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( - unitNumber, Direction::Input, false /*formatted*/, terminator)}; + unitNumber, Direction::Input, std::nullopt, terminator)}; return &unit.BeginIoStatement( unit, ExternalMiscIoStatementState::Rewind, sourceFile, sourceLine); } 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 @@ -203,10 +203,10 @@ } unit().access = *access_; } - if (!isUnformatted_) { - isUnformatted_ = unit().access != Access::Sequential; + if (!unit().isUnformatted) { + unit().isUnformatted = isUnformatted_; } - if (*isUnformatted_ != unit().isUnformatted) { + if (isUnformatted_ && *isUnformatted_ != *unit().isUnformatted) { if (wasExtant_) { SignalError("FORM= may not be changed on an open unit"); } @@ -757,7 +757,7 @@ str = unit().mayAsynchronous() ? "YES" : "NO"; break; case HashInquiryKeyword("BLANK"): - str = unit().isUnformatted ? "UNDEFINED" + str = unit().isUnformatted.value_or(true) ? "UNDEFINED" : unit().modes.editingFlags & blankZero ? "ZERO" : "NULL"; break; @@ -768,12 +768,12 @@ str = unit().swapEndianness() ? "SWAP" : "NATIVE"; break; case HashInquiryKeyword("DECIMAL"): - str = unit().isUnformatted ? "UNDEFINED" + str = unit().isUnformatted.value_or(true) ? "UNDEFINED" : unit().modes.editingFlags & decimalComma ? "COMMA" : "POINT"; break; case HashInquiryKeyword("DELIM"): - if (unit().isUnformatted) { + if (unit().isUnformatted.value_or(true)) { str = "UNDEFINED"; } else { switch (unit().modes.delim) { @@ -796,15 +796,19 @@ : "NO"; break; case HashInquiryKeyword("ENCODING"): - str = unit().isUnformatted ? "UNDEFINED" - : unit().isUTF8 ? "UTF-8" - : "ASCII"; + str = unit().isUnformatted.value_or(true) ? "UNDEFINED" + : unit().isUTF8 ? "UTF-8" + : "ASCII"; break; case HashInquiryKeyword("FORM"): - str = unit().isUnformatted ? "UNFORMATTED" : "FORMATTED"; + str = !unit().isUnformatted ? "UNKNOWN" + : *unit().isUnformatted ? "UNFORMATTED" + : "FORMATTED"; break; case HashInquiryKeyword("FORMATTED"): - str = !unit().isUnformatted ? "YES" : "NO"; + str = !unit().isUnformatted ? "UNKNOWN" + : *unit().isUnformatted ? "NO" + : "YES"; break; case HashInquiryKeyword("NAME"): str = unit().path(); @@ -813,7 +817,9 @@ } break; case HashInquiryKeyword("PAD"): - str = unit().isUnformatted ? "UNDEFINED" : unit().modes.pad ? "YES" : "NO"; + str = unit().isUnformatted.value_or(true) ? "UNDEFINED" + : unit().modes.pad ? "YES" + : "NO"; break; case HashInquiryKeyword("POSITION"): if (unit().access == Access::Direct) { @@ -837,7 +843,7 @@ str = unit().mayRead() && unit().mayWrite() ? "YES" : "NO"; break; case HashInquiryKeyword("ROUND"): - if (unit().isUnformatted) { + if (unit().isUnformatted.value_or(true)) { str = "UNDEFINED"; } else { switch (unit().modes.round) { @@ -865,7 +871,7 @@ str = unit().access == Access::Sequential ? "YES" : "NO"; break; case HashInquiryKeyword("SIGN"): - str = unit().isUnformatted ? "UNDEFINED" + str = unit().isUnformatted.value_or(true) ? "UNDEFINED" : unit().modes.editingFlags & signPlus ? "PLUS" : "SUPPRESS"; break; @@ -876,7 +882,9 @@ str = unit().mayWrite() ? "YES" : "NO"; break; case HashInquiryKeyword("UNFORMATTED"): - str = unit().isUnformatted ? "YES" : "NO"; + str = !unit().isUnformatted ? "UNKNOWN" + : *unit().isUnformatted ? "YES" + : "NO"; break; } if (str) { diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -41,8 +41,8 @@ static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &); static ExternalFileUnit &LookUpOrCreate( int unit, const Terminator &, bool &wasExtant); - static ExternalFileUnit &LookUpOrCreateAnonymous( - int unit, Direction, bool isUnformatted, const Terminator &); + static ExternalFileUnit &LookUpOrCreateAnonymous(int unit, Direction, + std::optional isUnformatted, const Terminator &); static ExternalFileUnit *LookUp(const char *path); static ExternalFileUnit &CreateNew(int unit, const Terminator &); static ExternalFileUnit *LookUpForClose(int unit); diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -53,8 +53,9 @@ return GetUnitMap().LookUpOrCreate(unit, terminator, wasExtant); } -ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous( - int unit, Direction dir, bool isUnformatted, const Terminator &terminator) { +ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous(int unit, + Direction dir, std::optional isUnformatted, + const Terminator &terminator) { bool exists{false}; ExternalFileUnit &result{ GetUnitMap().LookUpOrCreate(unit, terminator, exists)}; @@ -313,7 +314,7 @@ const char *ExternalFileUnit::FrameNextInput( IoErrorHandler &handler, std::size_t bytes) { - RUNTIME_CHECK(handler, !isUnformatted); + RUNTIME_CHECK(handler, isUnformatted.has_value() && !*isUnformatted); if (static_cast(positionInRecord + bytes) <= recordLength.value_or(positionInRecord + bytes)) { auto at{recordOffsetInFrame_ + positionInRecord}; @@ -367,10 +368,13 @@ if (got < need) { handler.SignalEnd(); } - } else if (isUnformatted) { - BeginSequentialVariableUnformattedInputRecord(handler); - } else { // formatted - BeginSequentialVariableFormattedInputRecord(handler); + } else { + RUNTIME_CHECK(handler, isUnformatted.has_value()); + if (isUnformatted.value_or(false)) { + BeginSequentialVariableUnformattedInputRecord(handler); + } else { // formatted + BeginSequentialVariableFormattedInputRecord(handler); + } } } } @@ -390,18 +394,21 @@ if (isFixedRecordLength) { frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; recordOffsetInFrame_ = 0; - } else if (isUnformatted) { - // Retain footer in frame for more efficient BACKSPACE - frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; - recordOffsetInFrame_ = sizeof(std::uint32_t); - recordLength.reset(); - } else { // formatted - if (Frame()[recordOffsetInFrame_ + *recordLength] == '\r') { - ++recordOffsetInFrame_; + } else { + RUNTIME_CHECK(handler, isUnformatted.has_value()); + if (isUnformatted.value_or(false)) { + // Retain footer in frame for more efficient BACKSPACE + frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; + recordOffsetInFrame_ = sizeof(std::uint32_t); + recordLength.reset(); + } else { // formatted + if (Frame()[recordOffsetInFrame_ + *recordLength] == '\r') { + ++recordOffsetInFrame_; + } + recordOffsetInFrame_ += *recordLength + 1; + RUNTIME_CHECK(handler, Frame()[recordOffsetInFrame_ - 1] == '\n'); + recordLength.reset(); } - recordOffsetInFrame_ += *recordLength + 1; - RUNTIME_CHECK(handler, Frame()[recordOffsetInFrame_ - 1] == '\n'); - recordLength.reset(); } } ++currentRecordNumber; @@ -414,17 +421,19 @@ return BeginReadingRecord(handler); } else { // Direction::Output bool ok{true}; + RUNTIME_CHECK(handler, isUnformatted.has_value()); if (isFixedRecordLength && recordLength) { // Pad remainder of fixed length record if (furthestPositionInRecord < *recordLength) { WriteFrame( frameOffsetInFile_, recordOffsetInFrame_ + *recordLength, handler); std::memset(Frame() + recordOffsetInFrame_ + furthestPositionInRecord, - isUnformatted ? 0 : ' ', *recordLength - furthestPositionInRecord); + isUnformatted.value_or(false) ? 0 : ' ', + *recordLength - furthestPositionInRecord); } } else { positionInRecord = furthestPositionInRecord; - if (isUnformatted) { + 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 @@ -466,10 +475,13 @@ --currentRecordNumber; if (isFixedRecordLength) { BackspaceFixedRecord(handler); - } else if (isUnformatted) { - BackspaceVariableUnformattedRecord(handler); } else { - BackspaceVariableFormattedRecord(handler); + RUNTIME_CHECK(handler, isUnformatted.has_value()); + if (isUnformatted.value_or(false)) { + BackspaceVariableUnformattedRecord(handler); + } else { + BackspaceVariableFormattedRecord(handler); + } } } }