Skip to content

Commit

Permalink
[flang][runtime] Reset the left tab limit when flushing output
Browse files Browse the repository at this point in the history
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
  • Loading branch information
klausler committed Apr 13, 2023
1 parent fc4494d commit 52a0b02
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 4 deletions.
22 changes: 20 additions & 2 deletions flang/runtime/emit-encoded.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,28 @@

#include "connection.h"
#include "environment.h"
#include "tools.h"
#include "utf.h"

namespace Fortran::runtime::io {

template <typename CONTEXT, typename CHAR>
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<std::size_t>(nl - data)};
if (!EmitEncoded(to, data, pos)) {
return false;
}
data += pos + 1;
chars -= pos + 1;
to.AdvanceRecord();
}
}
if (connection.useUTF8<CHAR>()) {
using UnsignedChar = std::make_unsigned_t<CHAR>;
const UnsignedChar *uData{reinterpret_cast<const UnsignedChar *>(data)};
Expand Down Expand Up @@ -61,7 +76,8 @@ bool EmitEncoded(CONTEXT &to, const CHAR *data, std::size_t chars) {
template <typename CONTEXT>
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);
Expand All @@ -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;
Expand Down
20 changes: 20 additions & 0 deletions flang/runtime/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "flang/Runtime/cpp-type.h"
#include "flang/Runtime/descriptor.h"
#include "flang/Runtime/memory.h"
#include <cstring>
#include <functional>
#include <map>
#include <type_traits>
Expand Down Expand Up @@ -356,5 +357,24 @@ using AccumulationType = CppTypeFor<CAT,
? std::max(KIND, static_cast<int>(sizeof(double)))
: KIND>;

// memchr() for any character type
template <typename CHAR>
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<const char *>(
std::memchr(data, static_cast<int>(ch), chars));
}

} // namespace Fortran::runtime
#endif // FORTRAN_RUNTIME_TOOLS_H_
5 changes: 3 additions & 2 deletions flang/runtime/unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "unit.h"
#include "io-error.h"
#include "lock.h"
#include "tools.h"
#include "unit-map.h"
#include <cstdio>
#include <limits>
Expand Down Expand Up @@ -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<const char *>(std::memchr(record, '\n', bytes))}) {
if (const char *nl{FindCharacter(record, '\n', bytes)}) {
recordLength = nl - record;
if (*recordLength > 0 && record[*recordLength - 1] == '\r') {
--*recordLength;
Expand Down Expand Up @@ -621,6 +621,7 @@ void ExternalFileUnit::FlushOutput(IoErrorHandler &handler) {
// needs to advance frameOffsetInFile_ to prevent attempts at
// impossible seeks
CommitWrites();
leftTabLimit.reset();
}
}
Flush(handler);
Expand Down

0 comments on commit 52a0b02

Please sign in to comment.