From 52a0b02c25d2c9bff215ad541ed7bd5d8fdecacc Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Wed, 12 Apr 2023 12:32:37 -0700 Subject: [PATCH] [flang][runtime] Reset the left tab limit when flushing output When flushing output to a non-positionable tty or socket file, reset the left tab limit. Otherwise, non-advancing output to that file will contain an increasing amount of leading spaces in each flush. Also, detect newline characters in stream output, and treat them as record advancement. Differential Revision: https://reviews.llvm.org/D148157 --- flang/runtime/emit-encoded.h | 22 ++++++++++++++++++++-- flang/runtime/tools.h | 20 ++++++++++++++++++++ flang/runtime/unit.cpp | 5 +++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/flang/runtime/emit-encoded.h b/flang/runtime/emit-encoded.h index 192c7ec..864848c 100644 --- 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 @@ namespace Fortran::runtime::io { 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 @@ bool EmitEncoded(CONTEXT &to, const CHAR *data, std::size_t chars) { 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 @@ bool EmitRepeated(CONTEXT &to, char ch, std::size_t n) { 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 index a9c942d..d96d848 100644 --- 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 @@ using AccumulationType = CppTypeFor(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 index 092a0a2..af2c835 100644 --- 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 @@ bool ExternalFileUnit::SetVariableFormattedRecordLength() { } 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 @@ void ExternalFileUnit::FlushOutput(IoErrorHandler &handler) { // needs to advance frameOffsetInFile_ to prevent attempts at // impossible seeks CommitWrites(); + leftTabLimit.reset(); } } Flush(handler); -- 2.7.4