#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)};
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);
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;
#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>
? 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_
#include "unit.h"
#include "io-error.h"
#include "lock.h"
+#include "tools.h"
#include "unit-map.h"
#include <cstdio>
#include <limits>
} 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;
// needs to advance frameOffsetInFile_ to prevent attempts at
// impossible seeks
CommitWrites();
+ leftTabLimit.reset();
}
}
Flush(handler);