xref: /llvm-project-15.0.7/flang/runtime/unit.h (revision eca86cb2)
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 "environment.h"
17 #include "file.h"
18 #include "format.h"
19 #include "io-error.h"
20 #include "io-stmt.h"
21 #include "lock.h"
22 #include "terminator.h"
23 #include "flang/Common/constexpr-bitset.h"
24 #include "flang/Runtime/memory.h"
25 #include <cstdlib>
26 #include <cstring>
27 #include <optional>
28 #include <variant>
29 
30 namespace Fortran::runtime::io {
31 
32 class UnitMap;
33 class ChildIo;
34 
35 class ExternalFileUnit : public ConnectionState,
36                          public OpenFile,
37                          public FileFrame<ExternalFileUnit> {
38 public:
39   explicit ExternalFileUnit(int unitNumber) : unitNumber_{unitNumber} {
40     isUTF8 = executionEnvironment.defaultUTF8;
41     asyncIdAvailable_.set();
42     asyncIdAvailable_.reset(0);
43   }
44   ~ExternalFileUnit() {}
45 
46   int unitNumber() const { return unitNumber_; }
47   bool swapEndianness() const { return swapEndianness_; }
48   bool createdForInternalChildIo() const { return createdForInternalChildIo_; }
49 
50   static ExternalFileUnit *LookUp(int unit);
51   static ExternalFileUnit *LookUpOrCreate(
52       int unit, const Terminator &, bool &wasExtant);
53   static ExternalFileUnit *LookUpOrCreateAnonymous(int unit, Direction,
54       std::optional<bool> isUnformatted, const Terminator &);
55   static ExternalFileUnit *LookUp(const char *path, std::size_t pathLen);
56   static ExternalFileUnit &CreateNew(int unit, const Terminator &);
57   static ExternalFileUnit *LookUpForClose(int unit);
58   static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo);
59   static void CloseAll(IoErrorHandler &);
60   static void FlushAll(IoErrorHandler &);
61 
62   void OpenUnit(std::optional<OpenStatus>, std::optional<Action>, Position,
63       OwningPtr<char> &&path, std::size_t pathLength, Convert,
64       IoErrorHandler &);
65   void OpenAnonymousUnit(std::optional<OpenStatus>, std::optional<Action>,
66       Position, Convert, IoErrorHandler &);
67   void CloseUnit(CloseStatus, IoErrorHandler &);
68   void DestroyClosed();
69 
70   Iostat SetDirection(Direction);
71 
72   template <typename A, typename... X>
73   IoStatementState &BeginIoStatement(X &&...xs) {
74     lock_.Take(); // dropped in EndIoStatement()
75     A &state{u_.emplace<A>(std::forward<X>(xs)...)};
76     if constexpr (!std::is_same_v<A, OpenStatementState>) {
77       state.mutableModes() = ConnectionState::modes;
78     }
79     directAccessRecWasSet_ = false;
80     io_.emplace(state);
81     return *io_;
82   }
83 
84   bool Emit(
85       const char *, std::size_t, std::size_t elementBytes, IoErrorHandler &);
86   bool Receive(char *, std::size_t, std::size_t elementBytes, IoErrorHandler &);
87   std::size_t GetNextInputBytes(const char *&, IoErrorHandler &);
88   bool BeginReadingRecord(IoErrorHandler &);
89   void FinishReadingRecord(IoErrorHandler &);
90   bool AdvanceRecord(IoErrorHandler &);
91   void BackspaceRecord(IoErrorHandler &);
92   void FlushOutput(IoErrorHandler &);
93   void FlushIfTerminal(IoErrorHandler &);
94   void Endfile(IoErrorHandler &);
95   void Rewind(IoErrorHandler &);
96   void EndIoStatement();
97   void SetPosition(std::int64_t, IoErrorHandler &); // zero-based
98   std::int64_t InquirePos() const {
99     // 12.6.2.11 defines POS=1 as the beginning of file
100     return frameOffsetInFile_ + recordOffsetInFrame_ + positionInRecord + 1;
101   }
102 
103   ChildIo *GetChildIo() { return child_.get(); }
104   ChildIo &PushChildIo(IoStatementState &);
105   void PopChildIo(ChildIo &);
106 
107   int GetAsynchronousId(IoErrorHandler &);
108   bool Wait(int);
109 
110 private:
111   static UnitMap &GetUnitMap();
112   const char *FrameNextInput(IoErrorHandler &, std::size_t);
113   void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler &);
114   void BeginVariableFormattedInputRecord(IoErrorHandler &);
115   void BackspaceFixedRecord(IoErrorHandler &);
116   void BackspaceVariableUnformattedRecord(IoErrorHandler &);
117   void BackspaceVariableFormattedRecord(IoErrorHandler &);
118   bool SetVariableFormattedRecordLength();
119   void DoImpliedEndfile(IoErrorHandler &);
120   void DoEndfile(IoErrorHandler &);
121   void CommitWrites();
122   bool CheckDirectAccess(IoErrorHandler &);
123   void HitEndOnRead(IoErrorHandler &);
124 
125   Lock lock_;
126 
127   int unitNumber_{-1};
128   Direction direction_{Direction::Output};
129   bool impliedEndfile_{false}; // sequential/stream output has taken place
130   bool beganReadingRecord_{false};
131   bool directAccessRecWasSet_{false}; // REC= appeared
132   // Subtle: The beginning of the frame can't be allowed to advance
133   // during a single list-directed READ due to the possibility of a
134   // multi-record CHARACTER value with a "r*" repeat count.  So we
135   // manage the frame and the current record therein separately.
136   std::int64_t frameOffsetInFile_{0};
137   std::size_t recordOffsetInFrame_{0}; // of currentRecordNumber
138   bool swapEndianness_{false};
139   bool createdForInternalChildIo_{false};
140   common::BitSet<64> asyncIdAvailable_;
141 
142   // When a synchronous I/O statement is in progress on this unit, holds its
143   // state.
144   std::variant<std::monostate, OpenStatementState, CloseStatementState,
145       ExternalFormattedIoStatementState<Direction::Output>,
146       ExternalFormattedIoStatementState<Direction::Input>,
147       ExternalListIoStatementState<Direction::Output>,
148       ExternalListIoStatementState<Direction::Input>,
149       ExternalUnformattedIoStatementState<Direction::Output>,
150       ExternalUnformattedIoStatementState<Direction::Input>, InquireUnitState,
151       ExternalMiscIoStatementState, ErroneousIoStatementState>
152       u_;
153 
154   // Points to the active alternative (if any) in u_ for use as a Cookie
155   std::optional<IoStatementState> io_;
156 
157   // A stack of child I/O pseudo-units for user-defined derived type
158   // I/O that have this unit number.
159   OwningPtr<ChildIo> child_;
160 };
161 
162 // A pseudo-unit for child I/O statements in user-defined derived type
163 // I/O subroutines; it forwards operations to the parent I/O statement,
164 // which can also be a child I/O statement.
165 class ChildIo {
166 public:
167   ChildIo(IoStatementState &parent, OwningPtr<ChildIo> &&previous)
168       : parent_{parent}, previous_{std::move(previous)} {}
169 
170   IoStatementState &parent() const { return parent_; }
171 
172   void EndIoStatement();
173 
174   template <typename A, typename... X>
175   IoStatementState &BeginIoStatement(X &&...xs) {
176     A &state{u_.emplace<A>(std::forward<X>(xs)...)};
177     io_.emplace(state);
178     return *io_;
179   }
180 
181   OwningPtr<ChildIo> AcquirePrevious() { return std::move(previous_); }
182 
183   Iostat CheckFormattingAndDirection(bool unformatted, Direction);
184 
185 private:
186   IoStatementState &parent_;
187   OwningPtr<ChildIo> previous_;
188   std::variant<std::monostate,
189       ChildFormattedIoStatementState<Direction::Output>,
190       ChildFormattedIoStatementState<Direction::Input>,
191       ChildListIoStatementState<Direction::Output>,
192       ChildListIoStatementState<Direction::Input>,
193       ChildUnformattedIoStatementState<Direction::Output>,
194       ChildUnformattedIoStatementState<Direction::Input>, InquireUnitState,
195       ErroneousIoStatementState>
196       u_;
197   std::optional<IoStatementState> io_;
198 };
199 
200 } // namespace Fortran::runtime::io
201 #endif // FORTRAN_RUNTIME_IO_UNIT_H_
202