1 //===-- runtime/unit.h ------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Fortran external I/O units
11 #ifndef FORTRAN_RUNTIME_IO_UNIT_H_
12 #define FORTRAN_RUNTIME_IO_UNIT_H_
15 #include "connection.h"
16 #include "environment.h"
22 #include "terminator.h"
23 #include "flang/Common/constexpr-bitset.h"
24 #include "flang/Runtime/memory.h"
30 namespace Fortran::runtime::io
{
35 class ExternalFileUnit
: public ConnectionState
,
37 public FileFrame
<ExternalFileUnit
> {
39 explicit ExternalFileUnit(int unitNumber
) : unitNumber_
{unitNumber
} {
40 isUTF8
= executionEnvironment
.defaultUTF8
;
41 asyncIdAvailable_
.set();
42 asyncIdAvailable_
.reset(0);
44 ~ExternalFileUnit() {}
46 int unitNumber() const { return unitNumber_
; }
47 bool swapEndianness() const { return swapEndianness_
; }
48 bool createdForInternalChildIo() const { return createdForInternalChildIo_
; }
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
&);
62 void OpenUnit(std::optional
<OpenStatus
>, std::optional
<Action
>, Position
,
63 OwningPtr
<char> &&path
, std::size_t pathLength
, Convert
,
65 void OpenAnonymousUnit(std::optional
<OpenStatus
>, std::optional
<Action
>,
66 Position
, Convert
, IoErrorHandler
&);
67 void CloseUnit(CloseStatus
, IoErrorHandler
&);
70 Iostat
SetDirection(Direction
);
72 template <typename A
, typename
... X
>
73 IoStatementState
&BeginIoStatement(const Terminator
&terminator
, X
&&...xs
) {
74 // Take lock_ and hold it until EndIoStatement().
76 if (!lock_
.TakeIfNoDeadlock()) {
77 terminator
.Crash("Recursive I/O attempted on unit %d", unitNumber_
);
82 A
&state
{u_
.emplace
<A
>(std::forward
<X
>(xs
)...)};
83 if constexpr (!std::is_same_v
<A
, OpenStatementState
>) {
84 state
.mutableModes() = ConnectionState::modes
;
86 directAccessRecWasSet_
= false;
92 const char *, std::size_t, std::size_t elementBytes
, IoErrorHandler
&);
93 bool Receive(char *, std::size_t, std::size_t elementBytes
, IoErrorHandler
&);
94 std::size_t GetNextInputBytes(const char *&, IoErrorHandler
&);
95 bool BeginReadingRecord(IoErrorHandler
&);
96 void FinishReadingRecord(IoErrorHandler
&);
97 bool AdvanceRecord(IoErrorHandler
&);
98 void BackspaceRecord(IoErrorHandler
&);
99 void FlushOutput(IoErrorHandler
&);
100 void FlushIfTerminal(IoErrorHandler
&);
101 void Endfile(IoErrorHandler
&);
102 void Rewind(IoErrorHandler
&);
103 void EndIoStatement();
104 bool SetStreamPos(std::int64_t, IoErrorHandler
&); // one-based, for POS=
105 bool SetDirectRec(std::int64_t, IoErrorHandler
&); // one-based, for REC=
106 std::int64_t InquirePos() const {
107 // 12.6.2.11 defines POS=1 as the beginning of file
108 return frameOffsetInFile_
+ recordOffsetInFrame_
+ positionInRecord
+ 1;
111 ChildIo
*GetChildIo() { return child_
.get(); }
112 ChildIo
&PushChildIo(IoStatementState
&);
113 void PopChildIo(ChildIo
&);
115 int GetAsynchronousId(IoErrorHandler
&);
119 static UnitMap
&CreateUnitMap();
120 static UnitMap
&GetUnitMap();
121 const char *FrameNextInput(IoErrorHandler
&, std::size_t);
122 void SetPosition(std::int64_t, IoErrorHandler
&); // zero-based
123 void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler
&);
124 void BeginVariableFormattedInputRecord(IoErrorHandler
&);
125 void BackspaceFixedRecord(IoErrorHandler
&);
126 void BackspaceVariableUnformattedRecord(IoErrorHandler
&);
127 void BackspaceVariableFormattedRecord(IoErrorHandler
&);
128 bool SetVariableFormattedRecordLength();
129 void DoImpliedEndfile(IoErrorHandler
&);
130 void DoEndfile(IoErrorHandler
&);
132 bool CheckDirectAccess(IoErrorHandler
&);
133 void HitEndOnRead(IoErrorHandler
&);
134 std::int32_t ReadHeaderOrFooter(std::int64_t frameOffset
);
139 Direction direction_
{Direction::Output
};
140 bool impliedEndfile_
{false}; // sequential/stream output has taken place
141 bool beganReadingRecord_
{false};
142 bool directAccessRecWasSet_
{false}; // REC= appeared
143 // Subtle: The beginning of the frame can't be allowed to advance
144 // during a single list-directed READ due to the possibility of a
145 // multi-record CHARACTER value with a "r*" repeat count. So we
146 // manage the frame and the current record therein separately.
147 std::int64_t frameOffsetInFile_
{0};
148 std::size_t recordOffsetInFrame_
{0}; // of currentRecordNumber
149 bool swapEndianness_
{false};
150 bool createdForInternalChildIo_
{false};
151 common::BitSet
<64> asyncIdAvailable_
;
153 // When a synchronous I/O statement is in progress on this unit, holds its
155 std::variant
<std::monostate
, OpenStatementState
, CloseStatementState
,
156 ExternalFormattedIoStatementState
<Direction::Output
>,
157 ExternalFormattedIoStatementState
<Direction::Input
>,
158 ExternalListIoStatementState
<Direction::Output
>,
159 ExternalListIoStatementState
<Direction::Input
>,
160 ExternalUnformattedIoStatementState
<Direction::Output
>,
161 ExternalUnformattedIoStatementState
<Direction::Input
>, InquireUnitState
,
162 ExternalMiscIoStatementState
, ErroneousIoStatementState
>
165 // Points to the active alternative (if any) in u_ for use as a Cookie
166 std::optional
<IoStatementState
> io_
;
168 // A stack of child I/O pseudo-units for user-defined derived type
169 // I/O that have this unit number.
170 OwningPtr
<ChildIo
> child_
;
173 // A pseudo-unit for child I/O statements in user-defined derived type
174 // I/O subroutines; it forwards operations to the parent I/O statement,
175 // which can also be a child I/O statement.
178 ChildIo(IoStatementState
&parent
, OwningPtr
<ChildIo
> &&previous
)
179 : parent_
{parent
}, previous_
{std::move(previous
)} {}
181 IoStatementState
&parent() const { return parent_
; }
183 void EndIoStatement();
185 template <typename A
, typename
... X
>
186 IoStatementState
&BeginIoStatement(X
&&...xs
) {
187 A
&state
{u_
.emplace
<A
>(std::forward
<X
>(xs
)...)};
192 OwningPtr
<ChildIo
> AcquirePrevious() { return std::move(previous_
); }
194 Iostat
CheckFormattingAndDirection(bool unformatted
, Direction
);
197 IoStatementState
&parent_
;
198 OwningPtr
<ChildIo
> previous_
;
199 std::variant
<std::monostate
,
200 ChildFormattedIoStatementState
<Direction::Output
>,
201 ChildFormattedIoStatementState
<Direction::Input
>,
202 ChildListIoStatementState
<Direction::Output
>,
203 ChildListIoStatementState
<Direction::Input
>,
204 ChildUnformattedIoStatementState
<Direction::Output
>,
205 ChildUnformattedIoStatementState
<Direction::Input
>, InquireUnitState
,
206 ErroneousIoStatementState
, ExternalMiscIoStatementState
>
208 std::optional
<IoStatementState
> io_
;
211 } // namespace Fortran::runtime::io
212 #endif // FORTRAN_RUNTIME_IO_UNIT_H_