//===-- 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 #include #include 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 class InternalFormattedIoStatementState; template class InternalListIoStatementState; template class ExternalFormattedIoStatementState; template class ExternalListIoStatementState; template class ExternalUnformattedIoStatementState; template class ChildFormattedIoStatementState; template class ChildListIoStatementState; template class ChildUnformattedIoStatementState; struct InputStatementState {}; struct OutputStatementState {}; template using IoDirectionState = std::conditional_t; // Common state for all kinds of formatted I/O template class FormattedIoStatementState {}; template <> class FormattedIoStatementState { 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 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 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 RT_API_ATTRS A *get_if() const { return common::visit( [](auto &x) -> A * { if constexpr (std::is_convertible_v) { return &x.get(); } return nullptr; }, u_); } // Vacant after the end of the current record RT_API_ATTRS Fortran::common::optional 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 CueUpInput(const DataEdit &edit) { Fortran::common::optional 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 SkipSpaces( Fortran::common::optional &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(*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 NextInField( Fortran::common::optional &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 GetNextNonBlank( std::size_t &byteCount) { auto ch{GetCurrentChar(byteCount)}; bool inNamelist{mutableModes().inNamelist}; while (!ch || *ch == ' ' || *ch == '\t' || *ch == '\n' || (inNamelist && *ch == '!')) { if (ch && (*ch == ' ' || *ch == '\t' || *ch == '\n')) { HandleRelativePosition(byteCount); } else if (!AdvanceRecord()) { return Fortran::common::nullopt; } ch = GetCurrentChar(byteCount); } return ch; } template RT_API_ATTRS bool CheckFormattedStmtType(const char *name) { if (get_if>()) { 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, Fortran::common::reference_wrapper, Fortran::common::reference_wrapper< InternalFormattedIoStatementState>, Fortran::common::reference_wrapper< InternalFormattedIoStatementState>, Fortran::common::reference_wrapper< InternalListIoStatementState>, Fortran::common::reference_wrapper< InternalListIoStatementState>, Fortran::common::reference_wrapper< ExternalFormattedIoStatementState>, Fortran::common::reference_wrapper< ExternalFormattedIoStatementState>, Fortran::common::reference_wrapper< ExternalListIoStatementState>, Fortran::common::reference_wrapper< ExternalListIoStatementState>, Fortran::common::reference_wrapper< ExternalUnformattedIoStatementState>, Fortran::common::reference_wrapper< ExternalUnformattedIoStatementState>, Fortran::common::reference_wrapper< ChildFormattedIoStatementState>, Fortran::common::reference_wrapper< ChildFormattedIoStatementState>, Fortran::common::reference_wrapper< ChildListIoStatementState>, Fortran::common::reference_wrapper< ChildListIoStatementState>, Fortran::common::reference_wrapper< ChildUnformattedIoStatementState>, Fortran::common::reference_wrapper< ChildUnformattedIoStatementState>, Fortran::common::reference_wrapper, Fortran::common::reference_wrapper, Fortran::common::reference_wrapper, Fortran::common::reference_wrapper, Fortran::common::reference_wrapper, Fortran::common::reference_wrapper> 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 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 class ListDirectedStatementState; template <> class ListDirectedStatementState : public FormattedIoStatementState { public: RT_API_ATTRS bool EmitLeadingSpaceOrAdvance( IoStatementState &, std::size_t = 1, bool isCharacter = false); RT_API_ATTRS Fortran::common::optional 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 : public FormattedIoStatementState { 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 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 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 class InternalIoStatementState : public IoStatementBase, public IoDirectionState { public: using Buffer = std::conditional_t; 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 unit_; }; template class InternalFormattedIoStatementState : public InternalIoStatementState, public FormattedIoStatementState { public: using CharType = CHAR; using typename InternalIoStatementState::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 GetNextDataEdit( IoStatementState &, int maxRepeat = 1) { return format_.GetNextDataEdit(*this, maxRepeat); } private: IoStatementState ioStatementState_; // points to *this using InternalIoStatementState::unit_; // format_ *must* be last; it may be partial someday FormatControl format_; }; template class InternalListIoStatementState : public InternalIoStatementState, public ListDirectedStatementState { public: using typename InternalIoStatementState::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::GetNextDataEdit; RT_API_ATTRS void CompleteOperation(); RT_API_ATTRS int EndIoStatement(); private: IoStatementState ioStatementState_; // points to *this using InternalIoStatementState::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 void set_destroy(bool yes = true) { destroy_ = yes; } 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}; bool destroy_{false}; }; template class ExternalIoStatementState : public ExternalIoStatementBase, public IoDirectionState { 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 class ExternalFormattedIoStatementState : public ExternalIoStatementState, public FormattedIoStatementState { 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 GetNextDataEdit( IoStatementState &, int maxRepeat = 1) { return format_.GetNextDataEdit(*this, maxRepeat); } private: FormatControl format_; }; template class ExternalListIoStatementState : public ExternalIoStatementState, public ListDirectedStatementState { public: using ExternalIoStatementState::ExternalIoStatementState; using ListDirectedStatementState::GetNextDataEdit; RT_API_ATTRS int EndIoStatement(); }; template class ExternalUnformattedIoStatementState : public ExternalIoStatementState { public: using ExternalIoStatementState::ExternalIoStatementState; RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0); }; template class ChildIoStatementState : public IoStatementBase, public IoDirectionState { 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 class ChildFormattedIoStatementState : public ChildIoStatementState, public FormattedIoStatementState { 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 GetNextDataEdit( IoStatementState &, int maxRepeat = 1) { return format_.GetNextDataEdit(*this, maxRepeat); } private: MutableModes mutableModes_; FormatControl format_; }; template class ChildListIoStatementState : public ChildIoStatementState, public ListDirectedStatementState { public: using ChildIoStatementState::ChildIoStatementState; using ListDirectedStatementState::GetNextDataEdit; RT_API_ATTRS int EndIoStatement(); }; template class ChildUnformattedIoStatementState : public ChildIoStatementState { public: using ChildIoStatementState::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 status_; Fortran::common::optional position_; Fortran::common::optional action_; Convert convert_{Convert::Unknown}; OwningPtr path_; std::size_t pathLength_; Fortran::common::optional isUnformatted_; Fortran::common::optional 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 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; extern template class InternalIoStatementState; extern template class InternalFormattedIoStatementState; extern template class InternalFormattedIoStatementState; extern template class InternalListIoStatementState; extern template class InternalListIoStatementState; extern template class ExternalIoStatementState; extern template class ExternalIoStatementState; extern template class ExternalFormattedIoStatementState; extern template class ExternalFormattedIoStatementState; extern template class ExternalListIoStatementState; extern template class ExternalListIoStatementState; extern template class ExternalUnformattedIoStatementState; extern template class ExternalUnformattedIoStatementState; extern template class ChildIoStatementState; extern template class ChildIoStatementState; extern template class ChildFormattedIoStatementState; extern template class ChildFormattedIoStatementState; extern template class ChildListIoStatementState; extern template class ChildListIoStatementState; extern template class ChildUnformattedIoStatementState; extern template class ChildUnformattedIoStatementState; extern template class FormatControl< InternalFormattedIoStatementState>; extern template class FormatControl< InternalFormattedIoStatementState>; extern template class FormatControl< ExternalFormattedIoStatementState>; extern template class FormatControl< ExternalFormattedIoStatementState>; extern template class FormatControl< ChildFormattedIoStatementState>; extern template class FormatControl< ChildFormattedIoStatementState>; 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 &&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 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_