A recent runtime I/O change[1] was meant to improve the handling of input from external files missing a terminal newline on their last records; the change was "triggered" by the wrong circumstances and causing reads that should have pulled more data into the buffer to be treated as EOFs. So fix that, and also don't retain input data in the buffer once an input record has been finished unless it's known that list-directed or NAMELIST input of a repeated input item may need to backspace a non-positionable external unit to return to the beginning of the repeated item. [1] 6578893a0453384346f149479f8574dfff977ace Differential Revision: https://reviews.llvm.org/D108164
71 lines
2.8 KiB
C++
71 lines
2.8 KiB
C++
//===-- runtime/connection.h ------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Fortran I/O connection state (abstracted over internal & external units)
|
|
|
|
#ifndef FORTRAN_RUNTIME_IO_CONNECTION_H_
|
|
#define FORTRAN_RUNTIME_IO_CONNECTION_H_
|
|
|
|
#include "format.h"
|
|
#include <cinttypes>
|
|
#include <optional>
|
|
|
|
namespace Fortran::runtime::io {
|
|
|
|
enum class Direction { Output, Input };
|
|
enum class Access { Sequential, Direct, Stream };
|
|
|
|
inline bool IsRecordFile(Access a) { return a != Access::Stream; }
|
|
|
|
// These characteristics of a connection are immutable after being
|
|
// established in an OPEN statement.
|
|
struct ConnectionAttributes {
|
|
Access access{Access::Sequential}; // ACCESS='SEQUENTIAL', 'DIRECT', 'STREAM'
|
|
std::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true
|
|
bool isUTF8{false}; // ENCODING='UTF-8'
|
|
bool isFixedRecordLength{false}; // RECL= on OPEN
|
|
std::optional<std::int64_t> recordLength; // RECL= or current record
|
|
};
|
|
|
|
struct ConnectionState : public ConnectionAttributes {
|
|
bool IsAtEOF() const; // true when read has hit EOF or endfile record
|
|
std::size_t RemainingSpaceInRecord() const;
|
|
bool NeedAdvance(std::size_t) const;
|
|
void HandleAbsolutePosition(std::int64_t);
|
|
void HandleRelativePosition(std::int64_t);
|
|
|
|
void BeginRecord() {
|
|
positionInRecord = 0;
|
|
furthestPositionInRecord = 0;
|
|
leftTabLimit.reset();
|
|
}
|
|
|
|
// 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
|
|
std::int64_t furthestPositionInRecord{0}; // max(position+bytes)
|
|
|
|
// Set at end of non-advancing I/O data transfer
|
|
std::optional<std::int64_t> leftTabLimit; // offset in current record
|
|
|
|
// currentRecordNumber value captured after ENDFILE/REWIND/BACKSPACE statement
|
|
// or an end-of-file READ condition on a sequential access file
|
|
std::optional<std::int64_t> endfileRecordNumber;
|
|
|
|
// Set when processing repeated items during list-directed & NAMELIST input
|
|
// in order to keep a span of records in frame on a non-positionable file,
|
|
// so that backspacing to the beginning of the repeated item doesn't require
|
|
// repositioning the external storage medium when that's impossible.
|
|
std::optional<std::int64_t> resumptionRecordNumber;
|
|
|
|
// Mutable modes set at OPEN() that can be overridden in READ/WRITE & FORMAT
|
|
MutableModes modes; // BLANK=, DECIMAL=, SIGN=, ROUND=, PAD=, DELIM=, kP
|
|
};
|
|
} // namespace Fortran::runtime::io
|
|
#endif // FORTRAN_RUNTIME_IO_CONNECTION_H_
|