//===-- 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/Common/optional.h"
#include "flang/Common/reference-wrapper.h"
#include "flang/Common/visit.h"
#include "flang/Runtime/descriptor.h"
#include "flang/Runtime/io-api.h"
#include <flang/Common/variant.h>
#include <functional>
#include <type_traits>
namespace Fortran::runtime::io {
class ExternalFileUnit;
class ChildIo;
class OpenStatementState;
class InquireUnitState;
class InquireNoUnitState;
class InquireUnconnectedFileState;
class InquireIOLengthState;
class ExternalMiscIoStatementState;
class CloseStatementState;
class NoopStatementState; // CLOSE or FLUSH on unknown unit
class ErroneousIoStatementState;
template <Direction, typename CHAR = char>
class InternalFormattedIoStatementState;
template <Direction> 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:
RT_API_ATTRS std::size_t GetEditDescriptorChars() const;
RT_API_ATTRS 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 RT_API_ATTRS 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.
// CompleteOperation() is the last opportunity to raise an I/O error.
// It is called by EndIoStatement(), but it can be invoked earlier to
// catch errors for (e.g.) GetIoMsg() and GetNewUnit(). If called
// more than once, it is a no-op.
RT_API_ATTRS void CompleteOperation();
// Completes an I/O statement and reclaims storage.
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS bool Emit(
const char *, std::size_t bytes, std::size_t elementBytes = 0);
RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const;
RT_API_ATTRS bool AdvanceRecord(int = 1);
RT_API_ATTRS void BackspaceRecord();
RT_API_ATTRS void HandleRelativePosition(std::int64_t byteOffset);
RT_API_ATTRS void HandleAbsolutePosition(
std::int64_t byteOffset); // for r* in list I/O
RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
int maxRepeat = 1);
RT_API_ATTRS ExternalFileUnit *
GetExternalFileUnit() const; // null if internal unit
RT_API_ATTRS bool BeginReadingRecord();
RT_API_ATTRS void FinishReadingRecord();
RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
RT_API_ATTRS bool Inquire(
InquiryKeywordHash, std::int64_t, bool &); // PENDING=
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
RT_API_ATTRS std::int64_t InquirePos();
RT_API_ATTRS void GotChar(signed int = 1); // for READ(SIZE=); can be <0
RT_API_ATTRS MutableModes &mutableModes();
RT_API_ATTRS ConnectionState &GetConnectionState();
RT_API_ATTRS IoErrorHandler &GetIoErrorHandler() const;
// N.B.: this also works with base classes
template <typename A> RT_API_ATTRS A *get_if() const {
return common::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
RT_API_ATTRS Fortran::common::optional<char32_t> GetCurrentChar(
std::size_t &byteCount);
// The result of CueUpInput() and the "remaining" arguments to SkipSpaces()
// and NextInField() are always in units of bytes, not characters; the
// distinction matters for internal input from CHARACTER(KIND=2 and 4).
// For fixed-width fields, return the number of remaining bytes.
// Skip over leading blanks.
RT_API_ATTRS Fortran::common::optional<int> CueUpInput(const DataEdit &edit) {
Fortran::common::optional<int> remaining;
if (edit.IsListDirected()) {
std::size_t byteCount{0};
GetNextNonBlank(byteCount);
} else {
if (edit.width.value_or(0) > 0) {
remaining = *edit.width;
if (int bytesPerChar{GetConnectionState().internalIoCharKind};
bytesPerChar > 1) {
*remaining *= bytesPerChar;
}
}
SkipSpaces(remaining);
}
return remaining;
}
RT_API_ATTRS Fortran::common::optional<char32_t> SkipSpaces(
Fortran::common::optional<int> &remaining) {
while (!remaining || *remaining > 0) {
std::size_t byteCount{0};
if (auto ch{GetCurrentChar(byteCount)}) {
if (*ch != ' ' && *ch != '\t') {
return ch;
}
if (remaining) {
if (static_cast<std::size_t>(*remaining) < byteCount) {
break;
}
GotChar(byteCount);
*remaining -= byteCount;
}
HandleRelativePosition(byteCount);
} else {
break;
}
}
return Fortran::common::nullopt;
}
// Acquires the next input character, respecting any applicable field width
// or separator character.
RT_API_ATTRS Fortran::common::optional<char32_t> NextInField(
Fortran::common::optional<int> &remaining, const DataEdit &);
// Detect and signal any end-of-record condition after input.
// Returns true if at EOR and remaining input should be padded with blanks.
RT_API_ATTRS bool CheckForEndOfRecord(std::size_t afterReading);
// Skips spaces, advances records, and ignores NAMELIST comments
RT_API_ATTRS Fortran::common::optional<char32_t> GetNextNonBlank(
std::size_t &byteCount) {
auto ch{GetCurrentChar(byteCount)};
bool inNamelist{mutableModes().inNamelist};
while (!ch || *ch == ' ' || *ch == '\t' || (inNamelist && *ch == '!')) {
if (ch && (*ch == ' ' || *ch == '\t')) {
HandleRelativePosition(byteCount);
} else if (!AdvanceRecord()) {
return Fortran::common::nullopt;
}
ch = GetCurrentChar(byteCount);
}
return ch;
}
template <Direction D>
RT_API_ATTRS bool CheckFormattedStmtType(const char *name) {
if (get_if<FormattedIoStatementState<D>>()) {
return true;
} else {
auto &handler{GetIoErrorHandler()};
if (!handler.InError()) {
handler.Crash("%s called for I/O statement that is not formatted %s",
name, D == Direction::Output ? "output" : "input");
}
return false;
}
}
private:
std::variant<Fortran::common::reference_wrapper<OpenStatementState>,
Fortran::common::reference_wrapper<CloseStatementState>,
Fortran::common::reference_wrapper<NoopStatementState>,
Fortran::common::reference_wrapper<
InternalFormattedIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
InternalFormattedIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<
InternalListIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
InternalListIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<
ExternalFormattedIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
ExternalFormattedIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<
ExternalListIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
ExternalListIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<
ExternalUnformattedIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
ExternalUnformattedIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<
ChildFormattedIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
ChildFormattedIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<
ChildListIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
ChildListIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<
ChildUnformattedIoStatementState<Direction::Output>>,
Fortran::common::reference_wrapper<
ChildUnformattedIoStatementState<Direction::Input>>,
Fortran::common::reference_wrapper<InquireUnitState>,
Fortran::common::reference_wrapper<InquireNoUnitState>,
Fortran::common::reference_wrapper<InquireUnconnectedFileState>,
Fortran::common::reference_wrapper<InquireIOLengthState>,
Fortran::common::reference_wrapper<ExternalMiscIoStatementState>,
Fortran::common::reference_wrapper<ErroneousIoStatementState>>
u_;
};
// Base class for all per-I/O statement state classes.
class IoStatementBase : public IoErrorHandler {
public:
using IoErrorHandler::IoErrorHandler;
RT_API_ATTRS bool completedOperation() const { return completedOperation_; }
RT_API_ATTRS void CompleteOperation() { completedOperation_ = true; }
RT_API_ATTRS int EndIoStatement() { return GetIoStat(); }
// These are default no-op backstops that can be overridden by descendants.
RT_API_ATTRS bool Emit(
const char *, std::size_t bytes, std::size_t elementBytes = 0);
RT_API_ATTRS bool Receive(
char *, std::size_t bytes, std::size_t elementBytes = 0);
RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const;
RT_API_ATTRS bool AdvanceRecord(int);
RT_API_ATTRS void BackspaceRecord();
RT_API_ATTRS void HandleRelativePosition(std::int64_t);
RT_API_ATTRS void HandleAbsolutePosition(std::int64_t);
RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
IoStatementState &, int maxRepeat = 1);
RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const;
RT_API_ATTRS bool BeginReadingRecord();
RT_API_ATTRS void FinishReadingRecord();
RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
RT_API_ATTRS std::int64_t InquirePos();
RT_API_ATTRS void BadInquiryKeywordHashCrash(InquiryKeywordHash);
RT_API_ATTRS void ReportUnsupportedChildIo() const {
Crash("not yet implemented: child IO");
}
protected:
bool completedOperation_{false};
};
// 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:
RT_API_ATTRS bool EmitLeadingSpaceOrAdvance(
IoStatementState &, std::size_t = 1, bool isCharacter = false);
RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
IoStatementState &, int maxRepeat = 1);
RT_API_ATTRS bool lastWasUndelimitedCharacter() const {
return lastWasUndelimitedCharacter_;
}
RT_API_ATTRS void set_lastWasUndelimitedCharacter(bool yes = true) {
lastWasUndelimitedCharacter_ = yes;
}
private:
bool lastWasUndelimitedCharacter_{false};
};
template <>
class ListDirectedStatementState<Direction::Input>
: public FormattedIoStatementState<Direction::Input> {
public:
RT_API_ATTRS bool inNamelistSequence() const { return inNamelistSequence_; }
RT_API_ATTRS int EndIoStatement();
// Skips value separators, handles repetition and null values.
// Vacant when '/' appears; present with descriptor == ListDirectedNullValue
// when a null value appears.
RT_API_ATTRS Fortran::common::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.
RT_API_ATTRS void ResetForNextNamelistItem(bool inNamelistSequence) {
remaining_ = 0;
if (repeatPosition_) {
repeatPosition_->Cancel();
}
eatComma_ = false;
realPart_ = imaginaryPart_ = false;
inNamelistSequence_ = inNamelistSequence;
}
private:
int remaining_{0}; // for "r*" repetition
Fortran::common::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};
bool inNamelistSequence_{false};
};
template <Direction DIR>
class InternalIoStatementState : public IoStatementBase,
public IoDirectionState<DIR> {
public:
using Buffer =
std::conditional_t<DIR == Direction::Input, const char *, char *>;
RT_API_ATTRS InternalIoStatementState(Buffer, std::size_t,
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS InternalIoStatementState(
const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS bool Emit(
const char *data, std::size_t bytes, std::size_t elementBytes = 0);
RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
RT_API_ATTRS bool AdvanceRecord(int = 1);
RT_API_ATTRS void BackspaceRecord();
RT_API_ATTRS ConnectionState &GetConnectionState() { return unit_; }
RT_API_ATTRS MutableModes &mutableModes() { return unit_.modes; }
RT_API_ATTRS void HandleRelativePosition(std::int64_t);
RT_API_ATTRS void HandleAbsolutePosition(std::int64_t);
RT_API_ATTRS std::int64_t InquirePos();
protected:
bool free_{true};
InternalDescriptorUnit<DIR> unit_;
};
template <Direction DIR, typename CHAR>
class InternalFormattedIoStatementState
: public InternalIoStatementState<DIR>,
public FormattedIoStatementState<DIR> {
public:
using CharType = CHAR;
using typename InternalIoStatementState<DIR>::Buffer;
RT_API_ATTRS InternalFormattedIoStatementState(Buffer internal,
std::size_t internalLength, const CharType *format,
std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS InternalFormattedIoStatementState(const Descriptor &,
const CharType *format, std::size_t formatLength,
const Descriptor *formatDescriptor = nullptr,
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS IoStatementState &ioStatementState() {
return ioStatementState_;
}
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
IoStatementState &, int maxRepeat = 1) {
return format_.GetNextDataEdit(*this, maxRepeat);
}
private:
IoStatementState ioStatementState_; // points to *this
using InternalIoStatementState<DIR>::unit_;
// format_ *must* be last; it may be partial someday
FormatControl<InternalFormattedIoStatementState> format_;
};
template <Direction DIR>
class InternalListIoStatementState : public InternalIoStatementState<DIR>,
public ListDirectedStatementState<DIR> {
public:
using typename InternalIoStatementState<DIR>::Buffer;
RT_API_ATTRS InternalListIoStatementState(Buffer internal,
std::size_t internalLength, const char *sourceFile = nullptr,
int sourceLine = 0);
RT_API_ATTRS InternalListIoStatementState(
const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS IoStatementState &ioStatementState() {
return ioStatementState_;
}
using ListDirectedStatementState<DIR>::GetNextDataEdit;
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
private:
IoStatementState ioStatementState_; // points to *this
using InternalIoStatementState<DIR>::unit_;
};
class ExternalIoStatementBase : public IoStatementBase {
public:
RT_API_ATTRS ExternalIoStatementBase(
ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS ExternalFileUnit &unit() { return unit_; }
RT_API_ATTRS const ExternalFileUnit &unit() const { return unit_; }
RT_API_ATTRS MutableModes &mutableModes();
RT_API_ATTRS ConnectionState &GetConnectionState();
RT_API_ATTRS int asynchronousID() const { return asynchronousID_; }
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const { return &unit_; }
RT_API_ATTRS void SetAsynchronous();
RT_API_ATTRS std::int64_t InquirePos();
private:
ExternalFileUnit &unit_;
int asynchronousID_{-1};
};
template <Direction DIR>
class ExternalIoStatementState : public ExternalIoStatementBase,
public IoDirectionState<DIR> {
public:
RT_API_ATTRS ExternalIoStatementState(
ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS MutableModes &mutableModes() { return mutableModes_; }
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS bool Emit(
const char *, std::size_t bytes, std::size_t elementBytes = 0);
RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const;
RT_API_ATTRS bool AdvanceRecord(int = 1);
RT_API_ATTRS void BackspaceRecord();
RT_API_ATTRS void HandleRelativePosition(std::int64_t);
RT_API_ATTRS void HandleAbsolutePosition(std::int64_t);
RT_API_ATTRS bool BeginReadingRecord();
RT_API_ATTRS 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;
RT_API_ATTRS ExternalFormattedIoStatementState(ExternalFileUnit &,
const CharType *format, std::size_t formatLength,
const Descriptor *formatDescriptor = nullptr,
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS Fortran::common::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;
RT_API_ATTRS int EndIoStatement();
};
template <Direction DIR>
class ExternalUnformattedIoStatementState
: public ExternalIoStatementState<DIR> {
public:
using ExternalIoStatementState<DIR>::ExternalIoStatementState;
RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
};
template <Direction DIR>
class ChildIoStatementState : public IoStatementBase,
public IoDirectionState<DIR> {
public:
RT_API_ATTRS ChildIoStatementState(
ChildIo &, const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS ChildIo &child() { return child_; }
RT_API_ATTRS MutableModes &mutableModes();
RT_API_ATTRS ConnectionState &GetConnectionState();
RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const;
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS bool Emit(
const char *, std::size_t bytes, std::size_t elementBytes = 0);
RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const;
RT_API_ATTRS void HandleRelativePosition(std::int64_t);
RT_API_ATTRS 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;
RT_API_ATTRS ChildFormattedIoStatementState(ChildIo &, const CharType *format,
std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS MutableModes &mutableModes() { return mutableModes_; }
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS bool AdvanceRecord(int = 1);
RT_API_ATTRS Fortran::common::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;
RT_API_ATTRS int EndIoStatement();
};
template <Direction DIR>
class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> {
public:
using ChildIoStatementState<DIR>::ChildIoStatementState;
RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
};
// OPEN
class OpenStatementState : public ExternalIoStatementBase {
public:
RT_API_ATTRS OpenStatementState(ExternalFileUnit &unit, bool wasExtant,
bool isNewUnit, const char *sourceFile = nullptr, int sourceLine = 0)
: ExternalIoStatementBase{unit, sourceFile, sourceLine},
wasExtant_{wasExtant}, isNewUnit_{isNewUnit} {}
RT_API_ATTRS bool wasExtant() const { return wasExtant_; }
RT_API_ATTRS void set_status(OpenStatus status) {
status_ = status;
} // STATUS=
RT_API_ATTRS void set_path(const char *, std::size_t); // FILE=
RT_API_ATTRS void set_position(Position position) {
position_ = position;
} // POSITION=
RT_API_ATTRS void set_action(Action action) { action_ = action; } // ACTION=
RT_API_ATTRS void set_convert(Convert convert) {
convert_ = convert;
} // CONVERT=
RT_API_ATTRS void set_access(Access access) { access_ = access; } // ACCESS=
RT_API_ATTRS void set_isUnformatted(bool yes = true) {
isUnformatted_ = yes;
} // FORM=
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
private:
bool wasExtant_;
bool isNewUnit_;
Fortran::common::optional<OpenStatus> status_;
Fortran::common::optional<Position> position_;
Fortran::common::optional<Action> action_;
Convert convert_{Convert::Unknown};
OwningPtr<char> path_;
std::size_t pathLength_;
Fortran::common::optional<bool> isUnformatted_;
Fortran::common::optional<Access> access_;
};
class CloseStatementState : public ExternalIoStatementBase {
public:
RT_API_ATTRS CloseStatementState(ExternalFileUnit &unit,
const char *sourceFile = nullptr, int sourceLine = 0)
: ExternalIoStatementBase{unit, sourceFile, sourceLine} {}
RT_API_ATTRS void set_status(CloseStatus status) { status_ = status; }
RT_API_ATTRS int EndIoStatement();
private:
CloseStatus status_{CloseStatus::Keep};
};
// For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit),
// and recoverable BACKSPACE(bad unit)
class NoUnitIoStatementState : public IoStatementBase {
public:
RT_API_ATTRS IoStatementState &ioStatementState() {
return ioStatementState_;
}
RT_API_ATTRS MutableModes &mutableModes() { return connection_.modes; }
RT_API_ATTRS ConnectionState &GetConnectionState() { return connection_; }
RT_API_ATTRS int badUnitNumber() const { return badUnitNumber_; }
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
protected:
template <typename A>
RT_API_ATTRS NoUnitIoStatementState(A &stmt, const char *sourceFile = nullptr,
int sourceLine = 0, int badUnitNumber = -1)
: IoStatementBase{sourceFile, sourceLine}, ioStatementState_{stmt},
badUnitNumber_{badUnitNumber} {}
private:
IoStatementState ioStatementState_; // points to *this
ConnectionState connection_;
int badUnitNumber_;
};
class NoopStatementState : public NoUnitIoStatementState {
public:
RT_API_ATTRS NoopStatementState(
const char *sourceFile = nullptr, int sourceLine = 0, int unitNumber = -1)
: NoUnitIoStatementState{*this, sourceFile, sourceLine, unitNumber} {}
RT_API_ATTRS 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:
RT_API_ATTRS InquireUnitState(ExternalFileUnit &unit,
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
};
class InquireNoUnitState : public NoUnitIoStatementState {
public:
RT_API_ATTRS InquireNoUnitState(const char *sourceFile = nullptr,
int sourceLine = 0, int badUnitNumber = -1);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
};
class InquireUnconnectedFileState : public NoUnitIoStatementState {
public:
RT_API_ATTRS InquireUnconnectedFileState(OwningPtr<char> &&path,
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
private:
OwningPtr<char> path_; // trimmed and NUL terminated
};
class InquireIOLengthState : public NoUnitIoStatementState,
public OutputStatementState {
public:
RT_API_ATTRS InquireIOLengthState(
const char *sourceFile = nullptr, int sourceLine = 0);
RT_API_ATTRS std::size_t bytes() const { return bytes_; }
RT_API_ATTRS bool Emit(
const char *, std::size_t bytes, std::size_t elementBytes = 0);
private:
std::size_t bytes_{0};
};
class ExternalMiscIoStatementState : public ExternalIoStatementBase {
public:
enum Which { Flush, Backspace, Endfile, Rewind, Wait };
RT_API_ATTRS ExternalMiscIoStatementState(ExternalFileUnit &unit, Which which,
const char *sourceFile = nullptr, int sourceLine = 0)
: ExternalIoStatementBase{unit, sourceFile, sourceLine}, which_{which} {}
RT_API_ATTRS void CompleteOperation();
RT_API_ATTRS int EndIoStatement();
private:
Which which_;
};
class ErroneousIoStatementState : public IoStatementBase {
public:
explicit RT_API_ATTRS ErroneousIoStatementState(Iostat iostat,
ExternalFileUnit *unit = nullptr, const char *sourceFile = nullptr,
int sourceLine = 0)
: IoStatementBase{sourceFile, sourceLine}, unit_{unit} {
SetPendingError(iostat);
}
RT_API_ATTRS int EndIoStatement();
RT_API_ATTRS ConnectionState &GetConnectionState() { return connection_; }
RT_API_ATTRS MutableModes &mutableModes() { return connection_.modes; }
private:
ConnectionState connection_;
ExternalFileUnit *unit_{nullptr};
};
} // namespace Fortran::runtime::io
#endif // FORTRAN_RUNTIME_IO_STMT_H_