| //===-- 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() && connection.recordLength && |
| connection.positionInRecord >= *connection.recordLength) { |
| IoErrorHandler &handler{GetIoErrorHandler()}; |
| if (mutableModes().nonAdvancing) { |
| handler.SignalEor(); |
| } else if (connection.isFixedRecordLength && !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_ |