From cea8b8a72d877a796c1e97fca2adae8a85bb36a1 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Wed, 27 Apr 2022 13:28:59 -0700 Subject: [PATCH] [flang][runtime] Don't pad CHARACTER input at end of record unless PAD='YES' When formatted CHARACTER input runs into the end of an input record, the runtime usually fills the remainder of the variable with spaces, but this should be conditional, and not done when PAD='NO'. And while here, add some better comments to two members of connection.h to make their non-obvious relationship more clear. Differential Revision: https://reviews.llvm.org/D125053 --- flang/runtime/connection.h | 12 ++++++++++-- flang/runtime/edit-input.cpp | 12 +++++------- flang/runtime/io-api.cpp | 2 +- flang/unittests/Runtime/ExternalIOTest.cpp | 5 +++-- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h index a19c49f..ba880b2 100644 --- a/flang/runtime/connection.h +++ b/flang/runtime/connection.h @@ -66,9 +66,17 @@ struct ConnectionState : public ConnectionAttributes { std::optional recordLength; - // Positions in a record file (sequential or direct, not stream) std::int64_t currentRecordNumber{1}; // 1 is first - std::int64_t positionInRecord{0}; // offset in current record + + // positionInRecord is the 0-based offset in the current recurd to/from + // which the next data transfer will occur. It can be past + // furthestPositionInRecord if moved by an X or T or TR control edit + // descriptor. + std::int64_t positionInRecord{0}; + + // furthestPositionInRecord is the 0-based offset of the greatest + // position in the current record to/from which any data transfer has + // occurred, plus one. It can be viewed as a count of bytes processed. std::int64_t furthestPositionInRecord{0}; // max(position+bytes) // Set at end of non-advancing I/O data transfer diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp index b694749..2e8ea3f 100644 --- a/flang/runtime/edit-input.cpp +++ b/flang/runtime/edit-input.cpp @@ -679,11 +679,10 @@ bool EditCharacterInput( remaining = *edit.width; } // When the field is wider than the variable, we drop the leading - // characters. When the variable is wider than the field, there's + // characters. When the variable is wider than the field, there can be // trailing padding. const char *input{nullptr}; std::size_t ready{0}; - bool hitEnd{false}; // Skip leading bytes. // These bytes don't count towards INQUIRE(IOLENGTH=). std::size_t skip{remaining > length ? remaining - length : 0}; @@ -692,8 +691,10 @@ bool EditCharacterInput( if (ready == 0) { ready = io.GetNextInputBytes(input); if (ready == 0) { - hitEnd = true; - break; + if (io.CheckForEndOfRecord()) { + std::fill_n(x, length, ' '); // PAD='YES' + } + return !io.GetIoErrorHandler().InError(); } } std::size_t chunk; @@ -731,9 +732,6 @@ bool EditCharacterInput( } // Pad the remainder of the input variable, if any. std::fill_n(x, length, ' '); - if (hitEnd) { - io.CheckForEndOfRecord(); // signal any needed error - } return true; } diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp index 43e49da..d5ef844 100644 --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -1176,7 +1176,7 @@ bool IONAME(InputCharacter)( } bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) { - return IONAME(InputCharacter(cookie, x, length, 1)); + return IONAME(InputCharacter)(cookie, x, length, 1); } bool IONAME(OutputLogical)(Cookie cookie, bool truth) { diff --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp index 87b1ef9..a129204 100644 --- a/flang/unittests/Runtime/ExternalIOTest.cpp +++ b/flang/unittests/Runtime/ExternalIOTest.cpp @@ -544,8 +544,9 @@ TEST(ExternalIOTests, TestNonAvancingInput) { fmt.data(), fmt.length(), unit, __FILE__, __LINE__); IONAME(EnableHandlers)(io, true, false, false, false, false); ASSERT_TRUE(IONAME(SetAdvance)(io, "NO", 2)) << "SetAdvance(NO)" << j; - ASSERT_TRUE( - IONAME(InputAscii)(io, inputItem.item.data(), inputItem.item.length())) + bool result{ + IONAME(InputAscii)(io, inputItem.item.data(), inputItem.item.length())}; + ASSERT_EQ(result, inputItem.expectedIoStat == IostatOk) << "InputAscii() " << j; ASSERT_EQ(IONAME(EndIoStatement)(io), inputItem.expectedIoStat) << "EndIoStatement() for Read " << j; -- 2.7.4