xref: /llvm-project-15.0.7/flang/runtime/unit.h (revision d771245a)
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:
ExternalFileUnit(int unitNumber)39   explicit ExternalFileUnit(int unitNumber) : unitNumber_{unitNumber} {
40     isUTF8 = executionEnvironment.defaultUTF8;
41     asyncIdAvailable_.set();
42     asyncIdAvailable_.reset(0);
43   }
~ExternalFileUnit()44   ~ExternalFileUnit() {}
45 
unitNumber()46   int unitNumber() const { return unitNumber_; }
swapEndianness()47   bool swapEndianness() const { return swapEndianness_; }
createdForInternalChildIo()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>
BeginIoStatement(X &&...xs)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   bool SetStreamPos(std::int64_t, IoErrorHandler &); // one-based, for POS=
98   bool SetDirectRec(std::int64_t, IoErrorHandler &); // one-based, for REC=
InquirePos()99   std::int64_t InquirePos() const {
100     // 12.6.2.11 defines POS=1 as the beginning of file
101     return frameOffsetInFile_ + recordOffsetInFrame_ + positionInRecord + 1;
102   }
103 
GetChildIo()104   ChildIo *GetChildIo() { return child_.get(); }
105   ChildIo &PushChildIo(IoStatementState &);
106   void PopChildIo(ChildIo &);
107 
108   int GetAsynchronousId(IoErrorHandler &);
109   bool Wait(int);
110 
111 private:
112   static UnitMap &GetUnitMap();
113   const char *FrameNextInput(IoErrorHandler &, std::size_t);
114   void SetPosition(std::int64_t, IoErrorHandler &); // zero-based
115   void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler &);
116   void BeginVariableFormattedInputRecord(IoErrorHandler &);
117   void BackspaceFixedRecord(IoErrorHandler &);
118   void BackspaceVariableUnformattedRecord(IoErrorHandler &);
119   void BackspaceVariableFormattedRecord(IoErrorHandler &);
120   bool SetVariableFormattedRecordLength();
121   void DoImpliedEndfile(IoErrorHandler &);
122   void DoEndfile(IoErrorHandler &);
123   void CommitWrites();
124   bool CheckDirectAccess(IoErrorHandler &);
125   void HitEndOnRead(IoErrorHandler &);
126 
127   Lock lock_;
128 
129   int unitNumber_{-1};
130   Direction direction_{Direction::Output};
131   bool impliedEndfile_{false}; // sequential/stream output has taken place
132   bool beganReadingRecord_{false};
133   bool directAccessRecWasSet_{false}; // REC= appeared
134   // Subtle: The beginning of the frame can't be allowed to advance
135   // during a single list-directed READ due to the possibility of a
136   // multi-record CHARACTER value with a "r*" repeat count.  So we
137   // manage the frame and the current record therein separately.
138   std::int64_t frameOffsetInFile_{0};
139   std::size_t recordOffsetInFrame_{0}; // of currentRecordNumber
140   bool swapEndianness_{false};
141   bool createdForInternalChildIo_{false};
142   common::BitSet<64> asyncIdAvailable_;
143 
144   // When a synchronous I/O statement is in progress on this unit, holds its
145   // state.
146   std::variant<std::monostate, OpenStatementState, CloseStatementState,
147       ExternalFormattedIoStatementState<Direction::Output>,
148       ExternalFormattedIoStatementState<Direction::Input>,
149       ExternalListIoStatementState<Direction::Output>,
150       ExternalListIoStatementState<Direction::Input>,
151       ExternalUnformattedIoStatementState<Direction::Output>,
152       ExternalUnformattedIoStatementState<Direction::Input>, InquireUnitState,
153       ExternalMiscIoStatementState, ErroneousIoStatementState>
154       u_;
155 
156   // Points to the active alternative (if any) in u_ for use as a Cookie
157   std::optional<IoStatementState> io_;
158 
159   // A stack of child I/O pseudo-units for user-defined derived type
160   // I/O that have this unit number.
161   OwningPtr<ChildIo> child_;
162 };
163 
164 // A pseudo-unit for child I/O statements in user-defined derived type
165 // I/O subroutines; it forwards operations to the parent I/O statement,
166 // which can also be a child I/O statement.
167 class ChildIo {
168 public:
ChildIo(IoStatementState & parent,OwningPtr<ChildIo> && previous)169   ChildIo(IoStatementState &parent, OwningPtr<ChildIo> &&previous)
170       : parent_{parent}, previous_{std::move(previous)} {}
171 
parent()172   IoStatementState &parent() const { return parent_; }
173 
174   void EndIoStatement();
175 
176   template <typename A, typename... X>
BeginIoStatement(X &&...xs)177   IoStatementState &BeginIoStatement(X &&...xs) {
178     A &state{u_.emplace<A>(std::forward<X>(xs)...)};
179     io_.emplace(state);
180     return *io_;
181   }
182 
AcquirePrevious()183   OwningPtr<ChildIo> AcquirePrevious() { return std::move(previous_); }
184 
185   Iostat CheckFormattingAndDirection(bool unformatted, Direction);
186 
187 private:
188   IoStatementState &parent_;
189   OwningPtr<ChildIo> previous_;
190   std::variant<std::monostate,
191       ChildFormattedIoStatementState<Direction::Output>,
192       ChildFormattedIoStatementState<Direction::Input>,
193       ChildListIoStatementState<Direction::Output>,
194       ChildListIoStatementState<Direction::Input>,
195       ChildUnformattedIoStatementState<Direction::Output>,
196       ChildUnformattedIoStatementState<Direction::Input>, InquireUnitState,
197       ErroneousIoStatementState>
198       u_;
199   std::optional<IoStatementState> io_;
200 };
201 
202 } // namespace Fortran::runtime::io
203 #endif // FORTRAN_RUNTIME_IO_UNIT_H_
204