forked from OSchip/llvm-project
722 lines
26 KiB
C++
722 lines
26 KiB
C++
//===-- runtime/io-stmt.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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Representations of the state of an I/O statement in progress
|
|
|
|
#ifndef FORTRAN_RUNTIME_IO_STMT_H_
|
|
#define FORTRAN_RUNTIME_IO_STMT_H_
|
|
|
|
#include "connection.h"
|
|
#include "file.h"
|
|
#include "format.h"
|
|
#include "internal-unit.h"
|
|
#include "io-error.h"
|
|
#include "flang/Runtime/descriptor.h"
|
|
#include "flang/Runtime/io-api.h"
|
|
#include <functional>
|
|
#include <type_traits>
|
|
#include <variant>
|
|
|
|
namespace Fortran::runtime::io {
|
|
|
|
class ExternalFileUnit;
|
|
class ChildIo;
|
|
|
|
class OpenStatementState;
|
|
class InquireUnitState;
|
|
class InquireNoUnitState;
|
|
class InquireUnconnectedFileState;
|
|
class InquireIOLengthState;
|
|
class ExternalMiscIoStatementState;
|
|
class CloseStatementState;
|
|
class NoopCloseStatementState;
|
|
|
|
template <Direction, typename CHAR = char>
|
|
class InternalFormattedIoStatementState;
|
|
template <Direction, typename CHAR = char> class InternalListIoStatementState;
|
|
template <Direction, typename CHAR = char>
|
|
class ExternalFormattedIoStatementState;
|
|
template <Direction> class ExternalListIoStatementState;
|
|
template <Direction> class ExternalUnformattedIoStatementState;
|
|
template <Direction, typename CHAR = char> class ChildFormattedIoStatementState;
|
|
template <Direction> class ChildListIoStatementState;
|
|
template <Direction> class ChildUnformattedIoStatementState;
|
|
|
|
struct InputStatementState {};
|
|
struct OutputStatementState {};
|
|
template <Direction D>
|
|
using IoDirectionState = std::conditional_t<D == Direction::Input,
|
|
InputStatementState, OutputStatementState>;
|
|
|
|
// Common state for all kinds of formatted I/O
|
|
template <Direction D> class FormattedIoStatementState {};
|
|
template <> class FormattedIoStatementState<Direction::Input> {
|
|
public:
|
|
std::size_t GetEditDescriptorChars() const;
|
|
void GotChar(int);
|
|
|
|
private:
|
|
// Account of characters read for edit descriptors (i.e., formatted I/O
|
|
// with a FORMAT, not list-directed or NAMELIST), not including padding.
|
|
std::size_t chars_{0}; // for READ(SIZE=)
|
|
};
|
|
|
|
// The Cookie type in the I/O API is a pointer (for C) to this class.
|
|
class IoStatementState {
|
|
public:
|
|
template <typename A> explicit IoStatementState(A &x) : u_{x} {}
|
|
|
|
// These member functions each project themselves into the active alternative.
|
|
// They're used by per-data-item routines in the I/O API (e.g., OutputReal64)
|
|
// to interact with the state of the I/O statement in progress.
|
|
// This design avoids virtual member functions and function pointers,
|
|
// which may not have good support in some runtime environments.
|
|
int EndIoStatement();
|
|
bool Emit(const char *, std::size_t, std::size_t elementBytes);
|
|
bool Emit(const char *, std::size_t);
|
|
bool Emit(const char16_t *, std::size_t chars);
|
|
bool Emit(const char32_t *, std::size_t chars);
|
|
bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
|
|
std::size_t GetNextInputBytes(const char *&);
|
|
bool AdvanceRecord(int = 1);
|
|
void BackspaceRecord();
|
|
void HandleRelativePosition(std::int64_t);
|
|
void HandleAbsolutePosition(std::int64_t); // for r* in list I/O
|
|
std::optional<DataEdit> GetNextDataEdit(int = 1);
|
|
ExternalFileUnit *GetExternalFileUnit() const; // null if internal unit
|
|
bool BeginReadingRecord();
|
|
void FinishReadingRecord();
|
|
bool Inquire(InquiryKeywordHash, char *, std::size_t);
|
|
bool Inquire(InquiryKeywordHash, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t, bool &); // PENDING=
|
|
bool Inquire(InquiryKeywordHash, std::int64_t &);
|
|
void GotChar(signed int = 1); // for READ(SIZE=); can be <0
|
|
|
|
MutableModes &mutableModes();
|
|
ConnectionState &GetConnectionState();
|
|
IoErrorHandler &GetIoErrorHandler() const;
|
|
|
|
// N.B.: this also works with base classes
|
|
template <typename A> A *get_if() const {
|
|
return std::visit(
|
|
[](auto &x) -> A * {
|
|
if constexpr (std::is_convertible_v<decltype(x.get()), A &>) {
|
|
return &x.get();
|
|
}
|
|
return nullptr;
|
|
},
|
|
u_);
|
|
}
|
|
|
|
// Vacant after the end of the current record
|
|
std::optional<char32_t> GetCurrentChar() {
|
|
const char *p{nullptr};
|
|
std::size_t bytes{GetNextInputBytes(p)};
|
|
if (bytes == 0) {
|
|
return std::nullopt;
|
|
} else {
|
|
// TODO: UTF-8 decoding; may have to get more bytes in a loop
|
|
return *p;
|
|
}
|
|
}
|
|
|
|
bool EmitRepeated(char, std::size_t);
|
|
bool EmitField(const char *, std::size_t length, std::size_t width);
|
|
|
|
// For fixed-width fields, initialize the number of remaining characters.
|
|
// Skip over leading blanks, then return the first non-blank character (if
|
|
// any).
|
|
std::optional<char32_t> PrepareInput(
|
|
const DataEdit &edit, std::optional<int> &remaining) {
|
|
remaining.reset();
|
|
if (edit.descriptor == DataEdit::ListDirected) {
|
|
GetNextNonBlank();
|
|
} else {
|
|
if (edit.width.value_or(0) > 0) {
|
|
remaining = *edit.width;
|
|
}
|
|
SkipSpaces(remaining);
|
|
}
|
|
return NextInField(remaining);
|
|
}
|
|
|
|
std::optional<char32_t> SkipSpaces(std::optional<int> &remaining) {
|
|
while (!remaining || *remaining > 0) {
|
|
if (auto ch{GetCurrentChar()}) {
|
|
if (*ch != ' ' && *ch != '\t') {
|
|
return ch;
|
|
}
|
|
HandleRelativePosition(1);
|
|
if (remaining) {
|
|
GotChar();
|
|
--*remaining;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<char32_t> NextInField(std::optional<int> &remaining) {
|
|
if (!remaining) { // list-directed or NAMELIST: check for separators
|
|
if (auto next{GetCurrentChar()}) {
|
|
switch (*next) {
|
|
case ' ':
|
|
case '\t':
|
|
case ',':
|
|
case ';':
|
|
case '/':
|
|
case '(':
|
|
case ')':
|
|
case '\'':
|
|
case '"':
|
|
case '*':
|
|
case '\n': // for stream access
|
|
break;
|
|
default:
|
|
HandleRelativePosition(1);
|
|
return next;
|
|
}
|
|
}
|
|
} else if (*remaining > 0) {
|
|
if (auto next{GetCurrentChar()}) {
|
|
--*remaining;
|
|
HandleRelativePosition(1);
|
|
GotChar();
|
|
return next;
|
|
}
|
|
const ConnectionState &connection{GetConnectionState()};
|
|
if (!connection.IsAtEOF()) {
|
|
if (auto length{connection.EffectiveRecordLength()}) {
|
|
if (connection.positionInRecord >= *length) {
|
|
IoErrorHandler &handler{GetIoErrorHandler()};
|
|
if (mutableModes().nonAdvancing) {
|
|
handler.SignalEor();
|
|
} else if (connection.openRecl && !connection.modes.pad) {
|
|
handler.SignalError(IostatRecordReadOverrun);
|
|
}
|
|
if (connection.modes.pad) { // PAD='YES'
|
|
--*remaining;
|
|
return std::optional<char32_t>{' '};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
// Skips spaces, advances records, and ignores NAMELIST comments
|
|
std::optional<char32_t> GetNextNonBlank() {
|
|
auto ch{GetCurrentChar()};
|
|
bool inNamelist{GetConnectionState().modes.inNamelist};
|
|
while (!ch || *ch == ' ' || *ch == '\t' || (inNamelist && *ch == '!')) {
|
|
if (ch && (*ch == ' ' || *ch == '\t')) {
|
|
HandleRelativePosition(1);
|
|
} else if (!AdvanceRecord()) {
|
|
return std::nullopt;
|
|
}
|
|
ch = GetCurrentChar();
|
|
}
|
|
return ch;
|
|
}
|
|
|
|
template <Direction D> void CheckFormattedStmtType(const char *name) {
|
|
if (!get_if<FormattedIoStatementState<D>>()) {
|
|
GetIoErrorHandler().Crash(
|
|
"%s called for I/O statement that is not formatted %s", name,
|
|
D == Direction::Output ? "output" : "input");
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::variant<std::reference_wrapper<OpenStatementState>,
|
|
std::reference_wrapper<CloseStatementState>,
|
|
std::reference_wrapper<NoopCloseStatementState>,
|
|
std::reference_wrapper<
|
|
InternalFormattedIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<
|
|
InternalFormattedIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<InternalListIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<InternalListIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<
|
|
ExternalFormattedIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<
|
|
ExternalFormattedIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<ExternalListIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<ExternalListIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<
|
|
ExternalUnformattedIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<
|
|
ExternalUnformattedIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<ChildFormattedIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<ChildFormattedIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<ChildListIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<ChildListIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<
|
|
ChildUnformattedIoStatementState<Direction::Output>>,
|
|
std::reference_wrapper<
|
|
ChildUnformattedIoStatementState<Direction::Input>>,
|
|
std::reference_wrapper<InquireUnitState>,
|
|
std::reference_wrapper<InquireNoUnitState>,
|
|
std::reference_wrapper<InquireUnconnectedFileState>,
|
|
std::reference_wrapper<InquireIOLengthState>,
|
|
std::reference_wrapper<ExternalMiscIoStatementState>>
|
|
u_;
|
|
};
|
|
|
|
// Base class for all per-I/O statement state classes.
|
|
struct IoStatementBase : public IoErrorHandler {
|
|
using IoErrorHandler::IoErrorHandler;
|
|
|
|
// These are default no-op backstops that can be overridden by descendants.
|
|
int EndIoStatement();
|
|
bool Emit(const char *, std::size_t, std::size_t elementBytes);
|
|
bool Emit(const char *, std::size_t);
|
|
bool Emit(const char16_t *, std::size_t chars);
|
|
bool Emit(const char32_t *, std::size_t chars);
|
|
bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
|
|
std::size_t GetNextInputBytes(const char *&);
|
|
bool AdvanceRecord(int);
|
|
void BackspaceRecord();
|
|
void HandleRelativePosition(std::int64_t);
|
|
void HandleAbsolutePosition(std::int64_t);
|
|
std::optional<DataEdit> GetNextDataEdit(IoStatementState &, int = 1);
|
|
ExternalFileUnit *GetExternalFileUnit() const;
|
|
bool BeginReadingRecord();
|
|
void FinishReadingRecord();
|
|
bool Inquire(InquiryKeywordHash, char *, std::size_t);
|
|
bool Inquire(InquiryKeywordHash, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t &);
|
|
|
|
void BadInquiryKeywordHashCrash(InquiryKeywordHash);
|
|
};
|
|
|
|
// Common state for list-directed & NAMELIST I/O, both internal & external
|
|
template <Direction> class ListDirectedStatementState;
|
|
template <>
|
|
class ListDirectedStatementState<Direction::Output>
|
|
: public FormattedIoStatementState<Direction::Output> {
|
|
public:
|
|
bool EmitLeadingSpaceOrAdvance(
|
|
IoStatementState &, std::size_t = 1, bool isCharacter = false);
|
|
std::optional<DataEdit> GetNextDataEdit(
|
|
IoStatementState &, int maxRepeat = 1);
|
|
bool lastWasUndelimitedCharacter() const {
|
|
return lastWasUndelimitedCharacter_;
|
|
}
|
|
void set_lastWasUndelimitedCharacter(bool yes = true) {
|
|
lastWasUndelimitedCharacter_ = yes;
|
|
}
|
|
|
|
private:
|
|
bool lastWasUndelimitedCharacter_{false};
|
|
};
|
|
template <>
|
|
class ListDirectedStatementState<Direction::Input>
|
|
: public FormattedIoStatementState<Direction::Input> {
|
|
public:
|
|
// Skips value separators, handles repetition and null values.
|
|
// Vacant when '/' appears; present with descriptor == ListDirectedNullValue
|
|
// when a null value appears.
|
|
std::optional<DataEdit> GetNextDataEdit(
|
|
IoStatementState &, int maxRepeat = 1);
|
|
|
|
// Each NAMELIST input item is treated like a distinct list-directed
|
|
// input statement. This member function resets some state so that
|
|
// repetition and null values work correctly for each successive
|
|
// NAMELIST input item.
|
|
void ResetForNextNamelistItem() {
|
|
remaining_ = 0;
|
|
eatComma_ = false;
|
|
realPart_ = imaginaryPart_ = false;
|
|
}
|
|
|
|
private:
|
|
int remaining_{0}; // for "r*" repetition
|
|
std::optional<SavedPosition> repeatPosition_;
|
|
bool eatComma_{false}; // consume comma after previously read item
|
|
bool hitSlash_{false}; // once '/' is seen, nullify further items
|
|
bool realPart_{false};
|
|
bool imaginaryPart_{false};
|
|
};
|
|
|
|
template <Direction DIR, typename CHAR = char>
|
|
class InternalIoStatementState : public IoStatementBase,
|
|
public IoDirectionState<DIR> {
|
|
public:
|
|
using CharType = CHAR;
|
|
using Buffer =
|
|
std::conditional_t<DIR == Direction::Input, const CharType *, CharType *>;
|
|
InternalIoStatementState(Buffer, std::size_t,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
InternalIoStatementState(
|
|
const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
int EndIoStatement();
|
|
|
|
using IoStatementBase::Emit;
|
|
bool Emit(
|
|
const CharType *data, std::size_t chars /* not necessarily bytes */);
|
|
std::size_t GetNextInputBytes(const char *&);
|
|
bool AdvanceRecord(int = 1);
|
|
void BackspaceRecord();
|
|
ConnectionState &GetConnectionState() { return unit_; }
|
|
MutableModes &mutableModes() { return unit_.modes; }
|
|
void HandleRelativePosition(std::int64_t);
|
|
void HandleAbsolutePosition(std::int64_t);
|
|
|
|
protected:
|
|
bool free_{true};
|
|
InternalDescriptorUnit<DIR> unit_;
|
|
};
|
|
|
|
template <Direction DIR, typename CHAR>
|
|
class InternalFormattedIoStatementState
|
|
: public InternalIoStatementState<DIR, CHAR>,
|
|
public FormattedIoStatementState<DIR> {
|
|
public:
|
|
using CharType = CHAR;
|
|
using typename InternalIoStatementState<DIR, CharType>::Buffer;
|
|
InternalFormattedIoStatementState(Buffer internal, std::size_t internalLength,
|
|
const CharType *format, std::size_t formatLength,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
InternalFormattedIoStatementState(const Descriptor &, const CharType *format,
|
|
std::size_t formatLength, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
IoStatementState &ioStatementState() { return ioStatementState_; }
|
|
int EndIoStatement();
|
|
std::optional<DataEdit> GetNextDataEdit(
|
|
IoStatementState &, int maxRepeat = 1) {
|
|
return format_.GetNextDataEdit(*this, maxRepeat);
|
|
}
|
|
|
|
private:
|
|
IoStatementState ioStatementState_; // points to *this
|
|
using InternalIoStatementState<DIR, CharType>::unit_;
|
|
// format_ *must* be last; it may be partial someday
|
|
FormatControl<InternalFormattedIoStatementState> format_;
|
|
};
|
|
|
|
template <Direction DIR, typename CHAR>
|
|
class InternalListIoStatementState : public InternalIoStatementState<DIR, CHAR>,
|
|
public ListDirectedStatementState<DIR> {
|
|
public:
|
|
using CharType = CHAR;
|
|
using typename InternalIoStatementState<DIR, CharType>::Buffer;
|
|
InternalListIoStatementState(Buffer internal, std::size_t internalLength,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
InternalListIoStatementState(
|
|
const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
IoStatementState &ioStatementState() { return ioStatementState_; }
|
|
using ListDirectedStatementState<DIR>::GetNextDataEdit;
|
|
|
|
private:
|
|
IoStatementState ioStatementState_; // points to *this
|
|
using InternalIoStatementState<DIR, CharType>::unit_;
|
|
};
|
|
|
|
class ExternalIoStatementBase : public IoStatementBase {
|
|
public:
|
|
ExternalIoStatementBase(
|
|
ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
ExternalFileUnit &unit() { return unit_; }
|
|
MutableModes &mutableModes();
|
|
ConnectionState &GetConnectionState();
|
|
int EndIoStatement();
|
|
ExternalFileUnit *GetExternalFileUnit() const { return &unit_; }
|
|
|
|
private:
|
|
ExternalFileUnit &unit_;
|
|
};
|
|
|
|
template <Direction DIR>
|
|
class ExternalIoStatementState : public ExternalIoStatementBase,
|
|
public IoDirectionState<DIR> {
|
|
public:
|
|
ExternalIoStatementState(
|
|
ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
MutableModes &mutableModes() { return mutableModes_; }
|
|
int EndIoStatement();
|
|
bool Emit(const char *, std::size_t, std::size_t elementBytes);
|
|
bool Emit(const char *, std::size_t);
|
|
bool Emit(const char16_t *, std::size_t chars /* not bytes */);
|
|
bool Emit(const char32_t *, std::size_t chars /* not bytes */);
|
|
std::size_t GetNextInputBytes(const char *&);
|
|
bool AdvanceRecord(int = 1);
|
|
void BackspaceRecord();
|
|
void HandleRelativePosition(std::int64_t);
|
|
void HandleAbsolutePosition(std::int64_t);
|
|
bool BeginReadingRecord();
|
|
void FinishReadingRecord();
|
|
|
|
private:
|
|
// These are forked from ConnectionState's modes at the beginning
|
|
// of each formatted I/O statement so they may be overridden by control
|
|
// edit descriptors during the statement.
|
|
MutableModes mutableModes_;
|
|
};
|
|
|
|
template <Direction DIR, typename CHAR>
|
|
class ExternalFormattedIoStatementState
|
|
: public ExternalIoStatementState<DIR>,
|
|
public FormattedIoStatementState<DIR> {
|
|
public:
|
|
using CharType = CHAR;
|
|
ExternalFormattedIoStatementState(ExternalFileUnit &, const CharType *format,
|
|
std::size_t formatLength, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
int EndIoStatement();
|
|
std::optional<DataEdit> GetNextDataEdit(
|
|
IoStatementState &, int maxRepeat = 1) {
|
|
return format_.GetNextDataEdit(*this, maxRepeat);
|
|
}
|
|
|
|
private:
|
|
FormatControl<ExternalFormattedIoStatementState> format_;
|
|
};
|
|
|
|
template <Direction DIR>
|
|
class ExternalListIoStatementState : public ExternalIoStatementState<DIR>,
|
|
public ListDirectedStatementState<DIR> {
|
|
public:
|
|
using ExternalIoStatementState<DIR>::ExternalIoStatementState;
|
|
using ListDirectedStatementState<DIR>::GetNextDataEdit;
|
|
};
|
|
|
|
template <Direction DIR>
|
|
class ExternalUnformattedIoStatementState
|
|
: public ExternalIoStatementState<DIR> {
|
|
public:
|
|
using ExternalIoStatementState<DIR>::ExternalIoStatementState;
|
|
bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
|
|
};
|
|
|
|
template <Direction DIR>
|
|
class ChildIoStatementState : public IoStatementBase,
|
|
public IoDirectionState<DIR> {
|
|
public:
|
|
ChildIoStatementState(
|
|
ChildIo &, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
ChildIo &child() { return child_; }
|
|
MutableModes &mutableModes();
|
|
ConnectionState &GetConnectionState();
|
|
ExternalFileUnit *GetExternalFileUnit() const;
|
|
int EndIoStatement();
|
|
bool Emit(const char *, std::size_t, std::size_t elementBytes);
|
|
bool Emit(const char *, std::size_t);
|
|
bool Emit(const char16_t *, std::size_t chars /* not bytes */);
|
|
bool Emit(const char32_t *, std::size_t chars /* not bytes */);
|
|
std::size_t GetNextInputBytes(const char *&);
|
|
void HandleRelativePosition(std::int64_t);
|
|
void HandleAbsolutePosition(std::int64_t);
|
|
|
|
private:
|
|
ChildIo &child_;
|
|
};
|
|
|
|
template <Direction DIR, typename CHAR>
|
|
class ChildFormattedIoStatementState : public ChildIoStatementState<DIR>,
|
|
public FormattedIoStatementState<DIR> {
|
|
public:
|
|
using CharType = CHAR;
|
|
ChildFormattedIoStatementState(ChildIo &, const CharType *format,
|
|
std::size_t formatLength, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
MutableModes &mutableModes() { return mutableModes_; }
|
|
int EndIoStatement();
|
|
bool AdvanceRecord(int = 1);
|
|
std::optional<DataEdit> GetNextDataEdit(
|
|
IoStatementState &, int maxRepeat = 1) {
|
|
return format_.GetNextDataEdit(*this, maxRepeat);
|
|
}
|
|
|
|
private:
|
|
MutableModes mutableModes_;
|
|
FormatControl<ChildFormattedIoStatementState> format_;
|
|
};
|
|
|
|
template <Direction DIR>
|
|
class ChildListIoStatementState : public ChildIoStatementState<DIR>,
|
|
public ListDirectedStatementState<DIR> {
|
|
public:
|
|
using ChildIoStatementState<DIR>::ChildIoStatementState;
|
|
using ListDirectedStatementState<DIR>::GetNextDataEdit;
|
|
};
|
|
|
|
template <Direction DIR>
|
|
class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> {
|
|
public:
|
|
using ChildIoStatementState<DIR>::ChildIoStatementState;
|
|
bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
|
|
};
|
|
|
|
// OPEN
|
|
class OpenStatementState : public ExternalIoStatementBase {
|
|
public:
|
|
OpenStatementState(ExternalFileUnit &unit, bool wasExtant,
|
|
const char *sourceFile = nullptr, int sourceLine = 0)
|
|
: ExternalIoStatementBase{unit, sourceFile, sourceLine}, wasExtant_{
|
|
wasExtant} {}
|
|
bool wasExtant() const { return wasExtant_; }
|
|
void set_status(OpenStatus status) { status_ = status; } // STATUS=
|
|
void set_path(const char *, std::size_t); // FILE=
|
|
void set_position(Position position) { position_ = position; } // POSITION=
|
|
void set_action(Action action) { action_ = action; } // ACTION=
|
|
void set_convert(Convert convert) { convert_ = convert; } // CONVERT=
|
|
void set_access(Access access) { access_ = access; } // ACCESS=
|
|
void set_isUnformatted(bool yes = true) { isUnformatted_ = yes; } // FORM=
|
|
int EndIoStatement();
|
|
|
|
private:
|
|
bool wasExtant_;
|
|
std::optional<OpenStatus> status_;
|
|
Position position_{Position::AsIs};
|
|
std::optional<Action> action_;
|
|
Convert convert_{Convert::Native};
|
|
OwningPtr<char> path_;
|
|
std::size_t pathLength_;
|
|
std::optional<bool> isUnformatted_;
|
|
std::optional<Access> access_;
|
|
};
|
|
|
|
class CloseStatementState : public ExternalIoStatementBase {
|
|
public:
|
|
CloseStatementState(ExternalFileUnit &unit, const char *sourceFile = nullptr,
|
|
int sourceLine = 0)
|
|
: ExternalIoStatementBase{unit, sourceFile, sourceLine} {}
|
|
void set_status(CloseStatus status) { status_ = status; }
|
|
int EndIoStatement();
|
|
|
|
private:
|
|
CloseStatus status_{CloseStatus::Keep};
|
|
};
|
|
|
|
// For CLOSE(bad unit) and INQUIRE(unconnected unit)
|
|
class NoUnitIoStatementState : public IoStatementBase {
|
|
public:
|
|
IoStatementState &ioStatementState() { return ioStatementState_; }
|
|
MutableModes &mutableModes() { return connection_.modes; }
|
|
ConnectionState &GetConnectionState() { return connection_; }
|
|
int EndIoStatement();
|
|
|
|
protected:
|
|
template <typename A>
|
|
NoUnitIoStatementState(const char *sourceFile, int sourceLine, A &stmt)
|
|
: IoStatementBase{sourceFile, sourceLine}, ioStatementState_{stmt} {}
|
|
|
|
private:
|
|
IoStatementState ioStatementState_; // points to *this
|
|
ConnectionState connection_;
|
|
};
|
|
|
|
class NoopCloseStatementState : public NoUnitIoStatementState {
|
|
public:
|
|
NoopCloseStatementState(const char *sourceFile, int sourceLine)
|
|
: NoUnitIoStatementState{sourceFile, sourceLine, *this} {}
|
|
void set_status(CloseStatus) {} // discards
|
|
};
|
|
|
|
extern template class InternalIoStatementState<Direction::Output>;
|
|
extern template class InternalIoStatementState<Direction::Input>;
|
|
extern template class InternalFormattedIoStatementState<Direction::Output>;
|
|
extern template class InternalFormattedIoStatementState<Direction::Input>;
|
|
extern template class InternalListIoStatementState<Direction::Output>;
|
|
extern template class InternalListIoStatementState<Direction::Input>;
|
|
extern template class ExternalIoStatementState<Direction::Output>;
|
|
extern template class ExternalIoStatementState<Direction::Input>;
|
|
extern template class ExternalFormattedIoStatementState<Direction::Output>;
|
|
extern template class ExternalFormattedIoStatementState<Direction::Input>;
|
|
extern template class ExternalListIoStatementState<Direction::Output>;
|
|
extern template class ExternalListIoStatementState<Direction::Input>;
|
|
extern template class ExternalUnformattedIoStatementState<Direction::Output>;
|
|
extern template class ExternalUnformattedIoStatementState<Direction::Input>;
|
|
extern template class ChildIoStatementState<Direction::Output>;
|
|
extern template class ChildIoStatementState<Direction::Input>;
|
|
extern template class ChildFormattedIoStatementState<Direction::Output>;
|
|
extern template class ChildFormattedIoStatementState<Direction::Input>;
|
|
extern template class ChildListIoStatementState<Direction::Output>;
|
|
extern template class ChildListIoStatementState<Direction::Input>;
|
|
extern template class ChildUnformattedIoStatementState<Direction::Output>;
|
|
extern template class ChildUnformattedIoStatementState<Direction::Input>;
|
|
|
|
extern template class FormatControl<
|
|
InternalFormattedIoStatementState<Direction::Output>>;
|
|
extern template class FormatControl<
|
|
InternalFormattedIoStatementState<Direction::Input>>;
|
|
extern template class FormatControl<
|
|
ExternalFormattedIoStatementState<Direction::Output>>;
|
|
extern template class FormatControl<
|
|
ExternalFormattedIoStatementState<Direction::Input>>;
|
|
extern template class FormatControl<
|
|
ChildFormattedIoStatementState<Direction::Output>>;
|
|
extern template class FormatControl<
|
|
ChildFormattedIoStatementState<Direction::Input>>;
|
|
|
|
class InquireUnitState : public ExternalIoStatementBase {
|
|
public:
|
|
InquireUnitState(ExternalFileUnit &unit, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
bool Inquire(InquiryKeywordHash, char *, std::size_t);
|
|
bool Inquire(InquiryKeywordHash, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t &);
|
|
};
|
|
|
|
class InquireNoUnitState : public NoUnitIoStatementState {
|
|
public:
|
|
InquireNoUnitState(const char *sourceFile = nullptr, int sourceLine = 0);
|
|
bool Inquire(InquiryKeywordHash, char *, std::size_t);
|
|
bool Inquire(InquiryKeywordHash, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t &);
|
|
};
|
|
|
|
class InquireUnconnectedFileState : public NoUnitIoStatementState {
|
|
public:
|
|
InquireUnconnectedFileState(OwningPtr<char> &&path,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
bool Inquire(InquiryKeywordHash, char *, std::size_t);
|
|
bool Inquire(InquiryKeywordHash, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
|
|
bool Inquire(InquiryKeywordHash, std::int64_t &);
|
|
|
|
private:
|
|
OwningPtr<char> path_; // trimmed and NUL terminated
|
|
};
|
|
|
|
class InquireIOLengthState : public NoUnitIoStatementState,
|
|
public OutputStatementState {
|
|
public:
|
|
InquireIOLengthState(const char *sourceFile = nullptr, int sourceLine = 0);
|
|
std::size_t bytes() const { return bytes_; }
|
|
bool Emit(const char *, std::size_t, std::size_t elementBytes);
|
|
bool Emit(const char *, std::size_t);
|
|
bool Emit(const char16_t *, std::size_t chars);
|
|
bool Emit(const char32_t *, std::size_t chars);
|
|
|
|
private:
|
|
std::size_t bytes_{0};
|
|
};
|
|
|
|
class ExternalMiscIoStatementState : public ExternalIoStatementBase {
|
|
public:
|
|
enum Which { Flush, Backspace, Endfile, Rewind };
|
|
ExternalMiscIoStatementState(ExternalFileUnit &unit, Which which,
|
|
const char *sourceFile = nullptr, int sourceLine = 0)
|
|
: ExternalIoStatementBase{unit, sourceFile, sourceLine}, which_{which} {}
|
|
int EndIoStatement();
|
|
|
|
private:
|
|
Which which_;
|
|
};
|
|
|
|
} // namespace Fortran::runtime::io
|
|
#endif // FORTRAN_RUNTIME_IO_STMT_H_
|