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 // Returns true if an existing unit was closed
63 bool OpenUnit(std::optional
<OpenStatus
>, std::optional
<Action
>, Position
,
64 OwningPtr
<char> &&path
, std::size_t pathLength
, Convert
,
66 void OpenAnonymousUnit(std::optional
<OpenStatus
>, std::optional
<Action
>,
67 Position
, Convert
, IoErrorHandler
&);
68 void CloseUnit(CloseStatus
, IoErrorHandler
&);
71 Iostat
SetDirection(Direction
);
73 template <typename A
, typename
... X
>
74 IoStatementState
&BeginIoStatement(const Terminator
&terminator
, X
&&...xs
) {
75 // Take lock_ and hold it until EndIoStatement().
77 if (!lock_
.TakeIfNoDeadlock()) {
78 terminator
.Crash("Recursive I/O attempted on unit %d", unitNumber_
);
83 A
&state
{u_
.emplace
<A
>(std::forward
<X
>(xs
)...)};
84 if constexpr (!std::is_same_v
<A
, OpenStatementState
>) {
85 state
.mutableModes() = ConnectionState::modes
;
87 directAccessRecWasSet_
= false;
93 const char *, std::size_t, std::size_t elementBytes
, IoErrorHandler
&);
94 bool Receive(char *, std::size_t, std::size_t elementBytes
, IoErrorHandler
&);
95 std::size_t GetNextInputBytes(const char *&, IoErrorHandler
&);
96 bool BeginReadingRecord(IoErrorHandler
&);
97 void FinishReadingRecord(IoErrorHandler
&);
98 bool AdvanceRecord(IoErrorHandler
&);
99 void BackspaceRecord(IoErrorHandler
&);
100 void FlushOutput(IoErrorHandler
&);
101 void FlushIfTerminal(IoErrorHandler
&);
102 void Endfile(IoErrorHandler
&);
103 void Rewind(IoErrorHandler
&);
104 void EndIoStatement();
105 bool SetStreamPos(std::int64_t, IoErrorHandler
&); // one-based, for POS=
106 bool SetDirectRec(std::int64_t, IoErrorHandler
&); // one-based, for REC=
107 std::int64_t InquirePos() const {
108 // 12.6.2.11 defines POS=1 as the beginning of file
109 return frameOffsetInFile_
+ recordOffsetInFrame_
+ positionInRecord
+ 1;
112 ChildIo
*GetChildIo() { return child_
.get(); }
113 ChildIo
&PushChildIo(IoStatementState
&);
114 void PopChildIo(ChildIo
&);
116 int GetAsynchronousId(IoErrorHandler
&);
120 static UnitMap
&CreateUnitMap();
121 static UnitMap
&GetUnitMap();
122 const char *FrameNextInput(IoErrorHandler
&, std::size_t);
123 void SetPosition(std::int64_t, IoErrorHandler
&); // zero-based
124 void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler
&);
125 void BeginVariableFormattedInputRecord(IoErrorHandler
&);
126 void BackspaceFixedRecord(IoErrorHandler
&);
127 void BackspaceVariableUnformattedRecord(IoErrorHandler
&);
128 void BackspaceVariableFormattedRecord(IoErrorHandler
&);
129 bool SetVariableFormattedRecordLength();
130 void DoImpliedEndfile(IoErrorHandler
&);
131 void DoEndfile(IoErrorHandler
&);
133 bool CheckDirectAccess(IoErrorHandler
&);
134 void HitEndOnRead(IoErrorHandler
&);
135 std::int32_t ReadHeaderOrFooter(std::int64_t frameOffset
);
140 Direction direction_
{Direction::Output
};
141 bool impliedEndfile_
{false}; // sequential/stream output has taken place
142 bool beganReadingRecord_
{false};
143 bool directAccessRecWasSet_
{false}; // REC= appeared
144 // Subtle: The beginning of the frame can't be allowed to advance
145 // during a single list-directed READ due to the possibility of a
146 // multi-record CHARACTER value with a "r*" repeat count. So we
147 // manage the frame and the current record therein separately.
148 std::int64_t frameOffsetInFile_
{0};
149 std::size_t recordOffsetInFrame_
{0}; // of currentRecordNumber
150 bool swapEndianness_
{false};
151 bool createdForInternalChildIo_
{false};
152 common::BitSet
<64> asyncIdAvailable_
;
154 // When a synchronous I/O statement is in progress on this unit, holds its
156 std::variant
<std::monostate
, OpenStatementState
, CloseStatementState
,
157 ExternalFormattedIoStatementState
<Direction::Output
>,
158 ExternalFormattedIoStatementState
<Direction::Input
>,
159 ExternalListIoStatementState
<Direction::Output
>,
160 ExternalListIoStatementState
<Direction::Input
>,
161 ExternalUnformattedIoStatementState
<Direction::Output
>,
162 ExternalUnformattedIoStatementState
<Direction::Input
>, InquireUnitState
,
163 ExternalMiscIoStatementState
, ErroneousIoStatementState
>
166 // Points to the active alternative (if any) in u_ for use as a Cookie
167 std::optional
<IoStatementState
> io_
;
169 // A stack of child I/O pseudo-units for defined I/O that have this
171 OwningPtr
<ChildIo
> child_
;
174 // A pseudo-unit for child I/O statements in defined I/O subroutines;
175 // it forwards operations to the parent I/O statement, which might also
176 // be a child I/O statement.
179 ChildIo(IoStatementState
&parent
, OwningPtr
<ChildIo
> &&previous
)
180 : parent_
{parent
}, previous_
{std::move(previous
)} {}
182 IoStatementState
&parent() const { return parent_
; }
184 void EndIoStatement();
186 template <typename A
, typename
... X
>
187 IoStatementState
&BeginIoStatement(X
&&...xs
) {
188 A
&state
{u_
.emplace
<A
>(std::forward
<X
>(xs
)...)};
193 OwningPtr
<ChildIo
> AcquirePrevious() { return std::move(previous_
); }
195 Iostat
CheckFormattingAndDirection(bool unformatted
, Direction
);
198 IoStatementState
&parent_
;
199 OwningPtr
<ChildIo
> previous_
;
200 std::variant
<std::monostate
,
201 ChildFormattedIoStatementState
<Direction::Output
>,
202 ChildFormattedIoStatementState
<Direction::Input
>,
203 ChildListIoStatementState
<Direction::Output
>,
204 ChildListIoStatementState
<Direction::Input
>,
205 ChildUnformattedIoStatementState
<Direction::Output
>,
206 ChildUnformattedIoStatementState
<Direction::Input
>, InquireUnitState
,
207 ErroneousIoStatementState
, ExternalMiscIoStatementState
>
209 std::optional
<IoStatementState
> io_
;
212 } // namespace Fortran::runtime::io
213 #endif // FORTRAN_RUNTIME_IO_UNIT_H_