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