//===-- runtime/unit.h ------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // Fortran external I/O units #ifndef FORTRAN_RUNTIME_IO_UNIT_H_ #define FORTRAN_RUNTIME_IO_UNIT_H_ #include "buffer.h" #include "connection.h" #include "file.h" #include "format.h" #include "io-error.h" #include "io-stmt.h" #include "lock.h" #include "memory.h" #include "terminator.h" #include #include #include #include namespace Fortran::runtime::io { class UnitMap; class ExternalFileUnit : public ConnectionState, public OpenFile, public FileFrame { public: explicit ExternalFileUnit(int unitNumber) : unitNumber_{unitNumber} {} int unitNumber() const { return unitNumber_; } bool swapEndianness() const { return swapEndianness_; } static ExternalFileUnit *LookUp(int unit); static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &); static ExternalFileUnit &LookUpOrCreate( int unit, const Terminator &, bool &wasExtant); static ExternalFileUnit &LookUpOrCreateAnonymous( int unit, Direction, bool isUnformatted, const Terminator &); static ExternalFileUnit *LookUp(const char *path); static ExternalFileUnit &CreateNew(int unit, const Terminator &); static ExternalFileUnit *LookUpForClose(int unit); static int NewUnit(const Terminator &); static void CloseAll(IoErrorHandler &); static void FlushAll(IoErrorHandler &); void OpenUnit(OpenStatus, std::optional, Position, OwningPtr &&path, std::size_t pathLength, Convert, IoErrorHandler &); void OpenAnonymousUnit( OpenStatus, std::optional, Position, Convert, IoErrorHandler &); void CloseUnit(CloseStatus, IoErrorHandler &); void DestroyClosed(); bool SetDirection(Direction, IoErrorHandler &); template IoStatementState &BeginIoStatement(X &&...xs) { // TODO: Child data transfer statements vs. locking lock_.Take(); // dropped in EndIoStatement() A &state{u_.emplace(std::forward(xs)...)}; if constexpr (!std::is_same_v) { state.mutableModes() = ConnectionState::modes; } io_.emplace(state); return *io_; } bool Emit( const char *, std::size_t, std::size_t elementBytes, IoErrorHandler &); bool Receive(char *, std::size_t, std::size_t elementBytes, IoErrorHandler &); std::optional GetCurrentChar(IoErrorHandler &); void SetLeftTabLimit(); void BeginReadingRecord(IoErrorHandler &); void FinishReadingRecord(IoErrorHandler &); bool AdvanceRecord(IoErrorHandler &); void BackspaceRecord(IoErrorHandler &); void FlushIfTerminal(IoErrorHandler &); void Endfile(IoErrorHandler &); void Rewind(IoErrorHandler &); void EndIoStatement(); void SetPosition(std::int64_t pos) { frameOffsetInFile_ = pos; recordOffsetInFrame_ = 0; BeginRecord(); } private: static UnitMap &GetUnitMap(); const char *FrameNextInput(IoErrorHandler &, std::size_t); void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler &); void BeginSequentialVariableFormattedInputRecord(IoErrorHandler &); void BackspaceFixedRecord(IoErrorHandler &); void BackspaceVariableUnformattedRecord(IoErrorHandler &); void BackspaceVariableFormattedRecord(IoErrorHandler &); bool SetSequentialVariableFormattedRecordLength(); void DoImpliedEndfile(IoErrorHandler &); void DoEndfile(IoErrorHandler &); int unitNumber_{-1}; Direction direction_{Direction::Output}; bool impliedEndfile_{false}; // seq. output has taken place bool beganReadingRecord_{false}; Lock lock_; // When an I/O statement is in progress on this unit, holds its state. std::variant, ExternalFormattedIoStatementState, ExternalListIoStatementState, ExternalListIoStatementState, UnformattedIoStatementState, UnformattedIoStatementState, InquireUnitState, ExternalMiscIoStatementState> u_; // Points to the active alternative (if any) in u_ for use as a Cookie std::optional io_; // Subtle: The beginning of the frame can't be allowed to advance // during a single list-directed READ due to the possibility of a // multi-record CHARACTER value with a "r*" repeat count. So we // manage the frame and the current record therein separately. std::int64_t frameOffsetInFile_{0}; std::size_t recordOffsetInFrame_{0}; // of currentRecordNumber bool swapEndianness_{false}; }; } // namespace Fortran::runtime::io #endif // FORTRAN_RUNTIME_IO_UNIT_H_