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