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_; } swapEndianness()38 bool swapEndianness() const { return swapEndianness_; } 39 40 static ExternalFileUnit *LookUp(int unit); 41 static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &); 42 static ExternalFileUnit &LookUpOrCreate( 43 int unit, const Terminator &, bool &wasExtant); 44 static ExternalFileUnit &LookUpOrCreateAnonymous( 45 int unit, Direction, bool isUnformatted, const Terminator &); 46 static ExternalFileUnit *LookUp(const char *path); 47 static ExternalFileUnit &CreateNew(int unit, const Terminator &); 48 static ExternalFileUnit *LookUpForClose(int unit); 49 static int NewUnit(const Terminator &); 50 static void CloseAll(IoErrorHandler &); 51 static void FlushAll(IoErrorHandler &); 52 53 void OpenUnit(OpenStatus, std::optional<Action>, Position, 54 OwningPtr<char> &&path, std::size_t pathLength, Convert, 55 IoErrorHandler &); 56 void OpenAnonymousUnit( 57 OpenStatus, std::optional<Action>, Position, Convert, IoErrorHandler &); 58 void CloseUnit(CloseStatus, IoErrorHandler &); 59 void DestroyClosed(); 60 61 bool SetDirection(Direction, IoErrorHandler &); 62 63 template <typename A, typename... X> BeginIoStatement(X &&...xs)64 IoStatementState &BeginIoStatement(X &&...xs) { 65 // TODO: Child data transfer statements vs. locking 66 lock_.Take(); // dropped in EndIoStatement() 67 A &state{u_.emplace<A>(std::forward<X>(xs)...)}; 68 if constexpr (!std::is_same_v<A, OpenStatementState>) { 69 state.mutableModes() = ConnectionState::modes; 70 } 71 io_.emplace(state); 72 return *io_; 73 } 74 75 bool Emit( 76 const char *, std::size_t, std::size_t elementBytes, IoErrorHandler &); 77 bool Receive(char *, std::size_t, std::size_t elementBytes, IoErrorHandler &); 78 std::optional<char32_t> GetCurrentChar(IoErrorHandler &); 79 void SetLeftTabLimit(); 80 void BeginReadingRecord(IoErrorHandler &); 81 void FinishReadingRecord(IoErrorHandler &); 82 bool AdvanceRecord(IoErrorHandler &); 83 void BackspaceRecord(IoErrorHandler &); 84 void FlushIfTerminal(IoErrorHandler &); 85 void Endfile(IoErrorHandler &); 86 void Rewind(IoErrorHandler &); 87 void EndIoStatement(); SetPosition(std::int64_t pos)88 void SetPosition(std::int64_t pos) { 89 frameOffsetInFile_ = pos; 90 recordOffsetInFrame_ = 0; 91 BeginRecord(); 92 } 93 94 private: 95 static UnitMap &GetUnitMap(); 96 const char *FrameNextInput(IoErrorHandler &, std::size_t); 97 void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler &); 98 void BeginSequentialVariableFormattedInputRecord(IoErrorHandler &); 99 void BackspaceFixedRecord(IoErrorHandler &); 100 void BackspaceVariableUnformattedRecord(IoErrorHandler &); 101 void BackspaceVariableFormattedRecord(IoErrorHandler &); 102 bool SetSequentialVariableFormattedRecordLength(); 103 void DoImpliedEndfile(IoErrorHandler &); 104 void DoEndfile(IoErrorHandler &); 105 106 int unitNumber_{-1}; 107 Direction direction_{Direction::Output}; 108 bool impliedEndfile_{false}; // seq. output has taken place 109 bool beganReadingRecord_{false}; 110 111 Lock lock_; 112 113 // When an I/O statement is in progress on this unit, holds its state. 114 std::variant<std::monostate, OpenStatementState, CloseStatementState, 115 ExternalFormattedIoStatementState<Direction::Output>, 116 ExternalFormattedIoStatementState<Direction::Input>, 117 ExternalListIoStatementState<Direction::Output>, 118 ExternalListIoStatementState<Direction::Input>, 119 UnformattedIoStatementState<Direction::Output>, 120 UnformattedIoStatementState<Direction::Input>, InquireUnitState, 121 ExternalMiscIoStatementState> 122 u_; 123 124 // Points to the active alternative (if any) in u_ for use as a Cookie 125 std::optional<IoStatementState> io_; 126 127 // Subtle: The beginning of the frame can't be allowed to advance 128 // during a single list-directed READ due to the possibility of a 129 // multi-record CHARACTER value with a "r*" repeat count. So we 130 // manage the frame and the current record therein separately. 131 std::int64_t frameOffsetInFile_{0}; 132 std::size_t recordOffsetInFrame_{0}; // of currentRecordNumber 133 134 bool swapEndianness_{false}; 135 }; 136 137 } // namespace Fortran::runtime::io 138 #endif // FORTRAN_RUNTIME_IO_UNIT_H_ 139