1 //===-- runtime/unit.h ------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // Fortran external I/O units 10 11 #ifndef FORTRAN_RUNTIME_IO_UNIT_H_ 12 #define FORTRAN_RUNTIME_IO_UNIT_H_ 13 14 #include "buffer.h" 15 #include "connection.h" 16 #include "file.h" 17 #include "format.h" 18 #include "io-error.h" 19 #include "io-stmt.h" 20 #include "lock.h" 21 #include "memory.h" 22 #include "terminator.h" 23 #include <cstdlib> 24 #include <cstring> 25 #include <optional> 26 #include <variant> 27 28 namespace Fortran::runtime::io { 29 30 class UnitMap; 31 32 class ExternalFileUnit : public ConnectionState, 33 public OpenFile, 34 public FileFrame<ExternalFileUnit> { 35 public: ExternalFileUnit(int unitNumber)36 explicit ExternalFileUnit(int unitNumber) : unitNumber_{unitNumber} {} unitNumber()37 int unitNumber() const { return unitNumber_; } 38 39 static ExternalFileUnit *LookUp(int unit); 40 static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &); 41 static ExternalFileUnit &LookUpOrCreate( 42 int unit, const Terminator &, bool &wasExtant); 43 static ExternalFileUnit &LookUpOrCreateAnonymous( 44 int unit, Direction, bool isUnformatted, const Terminator &); 45 static ExternalFileUnit &CreateNew(int unit, const Terminator &); 46 static ExternalFileUnit *LookUpForClose(int unit); 47 static int NewUnit(const Terminator &); 48 static void CloseAll(IoErrorHandler &); 49 static void FlushAll(IoErrorHandler &); 50 51 void OpenUnit(OpenStatus, Position, OwningPtr<char> &&path, 52 std::size_t pathLength, IoErrorHandler &); 53 void CloseUnit(CloseStatus, IoErrorHandler &); 54 void DestroyClosed(); 55 56 bool SetDirection(Direction, IoErrorHandler &); 57 58 template <typename A, typename... X> BeginIoStatement(X &&...xs)59 IoStatementState &BeginIoStatement(X &&... xs) { 60 // TODO: Child data transfer statements vs. locking 61 lock_.Take(); // dropped in EndIoStatement() 62 A &state{u_.emplace<A>(std::forward<X>(xs)...)}; 63 if constexpr (!std::is_same_v<A, OpenStatementState>) { 64 state.mutableModes() = ConnectionState::modes; 65 } 66 io_.emplace(state); 67 return *io_; 68 } 69 70 bool Emit(const char *, std::size_t, IoErrorHandler &); 71 bool Receive(char *, std::size_t, IoErrorHandler &); 72 std::optional<char32_t> GetCurrentChar(IoErrorHandler &); 73 void SetLeftTabLimit(); 74 void BeginReadingRecord(IoErrorHandler &); 75 bool AdvanceRecord(IoErrorHandler &); 76 void BackspaceRecord(IoErrorHandler &); 77 void FlushIfTerminal(IoErrorHandler &); 78 void Endfile(IoErrorHandler &); 79 void Rewind(IoErrorHandler &); 80 void EndIoStatement(); SetPosition(std::int64_t pos)81 void SetPosition(std::int64_t pos) { 82 frameOffsetInFile_ = pos; 83 recordOffsetInFrame_ = 0; 84 BeginRecord(); 85 } 86 87 private: 88 static UnitMap &GetUnitMap(); 89 const char *FrameNextInput(IoErrorHandler &, std::size_t); 90 void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler &); 91 void BeginSequentialVariableFormattedInputRecord(IoErrorHandler &); 92 void BackspaceFixedRecord(IoErrorHandler &); 93 void BackspaceVariableUnformattedRecord(IoErrorHandler &); 94 void BackspaceVariableFormattedRecord(IoErrorHandler &); 95 bool SetSequentialVariableFormattedRecordLength(); 96 void DoImpliedEndfile(IoErrorHandler &); 97 void DoEndfile(IoErrorHandler &); 98 99 int unitNumber_{-1}; 100 Direction direction_{Direction::Output}; 101 bool impliedEndfile_{false}; // seq. output has taken place 102 103 Lock lock_; 104 105 // When an I/O statement is in progress on this unit, holds its state. 106 std::variant<std::monostate, OpenStatementState, CloseStatementState, 107 ExternalFormattedIoStatementState<Direction::Output>, 108 ExternalFormattedIoStatementState<Direction::Input>, 109 ExternalListIoStatementState<Direction::Output>, 110 ExternalListIoStatementState<Direction::Input>, 111 UnformattedIoStatementState<Direction::Output>, 112 UnformattedIoStatementState<Direction::Input>, 113 ExternalMiscIoStatementState> 114 u_; 115 116 // Points to the active alternative (if any) in u_ for use as a Cookie 117 std::optional<IoStatementState> io_; 118 119 // Subtle: The beginning of the frame can't be allowed to advance 120 // during a single list-directed READ due to the possibility of a 121 // multi-record CHARACTER value with a "r*" repeat count. So we 122 // manage the frame and the current record therein separately. 123 std::int64_t frameOffsetInFile_{0}; 124 std::size_t recordOffsetInFrame_{0}; // of currentRecordNumber 125 }; 126 127 } // namespace Fortran::runtime::io 128 #endif // FORTRAN_RUNTIME_IO_UNIT_H_ 129