diff --git a/flang/runtime/emit-encoded.h b/flang/runtime/emit-encoded.h --- a/flang/runtime/emit-encoded.h +++ b/flang/runtime/emit-encoded.h @@ -13,6 +13,7 @@ #include "connection.h" #include "environment.h" +#include "tools.h" #include "utf.h" namespace Fortran::runtime::io { @@ -20,6 +21,20 @@ template bool EmitEncoded(CONTEXT &to, const CHAR *data, std::size_t chars) { ConnectionState &connection{to.GetConnectionState()}; + if (connection.access == Access::Stream && + connection.internalIoCharKind == 0) { + // Stream output: treat newlines as record advancements so that the left tab + // limit is correctly managed + while (const CHAR * nl{FindCharacter(data, CHAR{'\n'}, chars)}) { + auto pos{static_cast(nl - data)}; + if (!EmitEncoded(to, data, pos)) { + return false; + } + data += pos + 1; + chars -= pos + 1; + to.AdvanceRecord(); + } + } if (connection.useUTF8()) { using UnsignedChar = std::make_unsigned_t; const UnsignedChar *uData{reinterpret_cast(data)}; @@ -61,7 +76,8 @@ template bool EmitAscii(CONTEXT &to, const char *data, std::size_t chars) { ConnectionState &connection{to.GetConnectionState()}; - if (connection.internalIoCharKind <= 1) { + if (connection.internalIoCharKind <= 1 && + connection.access != Access::Stream) { return to.Emit(data, chars); } else { return EmitEncoded(to, data, chars); @@ -74,7 +90,9 @@ return true; } ConnectionState &connection{to.GetConnectionState()}; - if (connection.internalIoCharKind <= 1) { + if (connection.internalIoCharKind <= 1 && + connection.access != Access::Stream) { + // faster path, no encoding needed while (n-- > 0) { if (!to.Emit(&ch, 1)) { return false; diff --git a/flang/runtime/tools.h b/flang/runtime/tools.h --- a/flang/runtime/tools.h +++ b/flang/runtime/tools.h @@ -13,6 +13,7 @@ #include "flang/Runtime/cpp-type.h" #include "flang/Runtime/descriptor.h" #include "flang/Runtime/memory.h" +#include #include #include #include @@ -356,5 +357,24 @@ ? std::max(KIND, static_cast(sizeof(double))) : KIND>; +// memchr() for any character type +template +static inline const CHAR *FindCharacter( + const CHAR *data, CHAR ch, std::size_t chars) { + const CHAR *end{data + chars}; + for (const CHAR *p{data}; p < end; ++p) { + if (*p == ch) { + return p; + } + } + return nullptr; +} + +template <> +inline const char *FindCharacter(const char *data, char ch, std::size_t chars) { + return reinterpret_cast( + std::memchr(data, static_cast(ch), chars)); +} + } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_TOOLS_H_ diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -9,6 +9,7 @@ #include "unit.h" #include "io-error.h" #include "lock.h" +#include "tools.h" #include "unit-map.h" #include #include @@ -417,8 +418,7 @@ } else if (FrameLength() > recordOffsetInFrame_) { const char *record{Frame() + recordOffsetInFrame_}; std::size_t bytes{FrameLength() - recordOffsetInFrame_}; - if (const char *nl{ - reinterpret_cast(std::memchr(record, '\n', bytes))}) { + if (const char *nl{FindCharacter(record, '\n', bytes)}) { recordLength = nl - record; if (*recordLength > 0 && record[*recordLength - 1] == '\r') { --*recordLength; @@ -621,6 +621,7 @@ // needs to advance frameOffsetInFile_ to prevent attempts at // impossible seeks CommitWrites(); + leftTabLimit.reset(); } } Flush(handler);