1 //===-- runtime/io-stmt.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 // Representations of the state of an I/O statement in progress
11 #ifndef FORTRAN_RUNTIME_IO_STMT_H_
12 #define FORTRAN_RUNTIME_IO_STMT_H_
14 #include "connection.h"
17 #include "internal-unit.h"
19 #include "flang/Common/optional.h"
20 #include "flang/Common/reference-wrapper.h"
21 #include "flang/Common/visit.h"
22 #include "flang/Runtime/descriptor.h"
23 #include "flang/Runtime/io-api.h"
24 #include <flang/Common/variant.h>
26 #include <type_traits>
28 namespace Fortran::runtime::io
{
30 class ExternalFileUnit
;
33 class OpenStatementState
;
34 class InquireUnitState
;
35 class InquireNoUnitState
;
36 class InquireUnconnectedFileState
;
37 class InquireIOLengthState
;
38 class ExternalMiscIoStatementState
;
39 class CloseStatementState
;
40 class NoopStatementState
; // CLOSE or FLUSH on unknown unit
41 class ErroneousIoStatementState
;
43 template <Direction
, typename CHAR
= char>
44 class InternalFormattedIoStatementState
;
45 template <Direction
> class InternalListIoStatementState
;
46 template <Direction
, typename CHAR
= char>
47 class ExternalFormattedIoStatementState
;
48 template <Direction
> class ExternalListIoStatementState
;
49 template <Direction
> class ExternalUnformattedIoStatementState
;
50 template <Direction
, typename CHAR
= char> class ChildFormattedIoStatementState
;
51 template <Direction
> class ChildListIoStatementState
;
52 template <Direction
> class ChildUnformattedIoStatementState
;
54 struct InputStatementState
{};
55 struct OutputStatementState
{};
56 template <Direction D
>
57 using IoDirectionState
= std::conditional_t
<D
== Direction::Input
,
58 InputStatementState
, OutputStatementState
>;
60 // Common state for all kinds of formatted I/O
61 template <Direction D
> class FormattedIoStatementState
{};
62 template <> class FormattedIoStatementState
<Direction::Input
> {
64 RT_API_ATTRS
std::size_t GetEditDescriptorChars() const;
65 RT_API_ATTRS
void GotChar(int);
68 // Account of characters read for edit descriptors (i.e., formatted I/O
69 // with a FORMAT, not list-directed or NAMELIST), not including padding.
70 std::size_t chars_
{0}; // for READ(SIZE=)
73 // The Cookie type in the I/O API is a pointer (for C) to this class.
74 class IoStatementState
{
76 template <typename A
> explicit RT_API_ATTRS
IoStatementState(A
&x
) : u_
{x
} {}
78 // These member functions each project themselves into the active alternative.
79 // They're used by per-data-item routines in the I/O API (e.g., OutputReal64)
80 // to interact with the state of the I/O statement in progress.
81 // This design avoids virtual member functions and function pointers,
82 // which may not have good support in some runtime environments.
84 // CompleteOperation() is the last opportunity to raise an I/O error.
85 // It is called by EndIoStatement(), but it can be invoked earlier to
86 // catch errors for (e.g.) GetIoMsg() and GetNewUnit(). If called
87 // more than once, it is a no-op.
88 RT_API_ATTRS
void CompleteOperation();
89 // Completes an I/O statement and reclaims storage.
90 RT_API_ATTRS
int EndIoStatement();
92 RT_API_ATTRS
bool Emit(
93 const char *, std::size_t bytes
, std::size_t elementBytes
= 0);
94 RT_API_ATTRS
bool Receive(char *, std::size_t, std::size_t elementBytes
= 0);
95 RT_API_ATTRS
std::size_t GetNextInputBytes(const char *&);
96 RT_API_ATTRS
std::size_t ViewBytesInRecord(const char *&, bool forward
) const;
97 RT_API_ATTRS
bool AdvanceRecord(int = 1);
98 RT_API_ATTRS
void BackspaceRecord();
99 RT_API_ATTRS
void HandleRelativePosition(std::int64_t byteOffset
);
100 RT_API_ATTRS
void HandleAbsolutePosition(
101 std::int64_t byteOffset
); // for r* in list I/O
102 RT_API_ATTRS
Fortran::common::optional
<DataEdit
> GetNextDataEdit(
104 RT_API_ATTRS ExternalFileUnit
*
105 GetExternalFileUnit() const; // null if internal unit
106 RT_API_ATTRS
bool BeginReadingRecord();
107 RT_API_ATTRS
void FinishReadingRecord();
108 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, char *, std::size_t);
109 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, bool &);
110 RT_API_ATTRS
bool Inquire(
111 InquiryKeywordHash
, std::int64_t, bool &); // PENDING=
112 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t &);
113 RT_API_ATTRS
std::int64_t InquirePos();
114 RT_API_ATTRS
void GotChar(signed int = 1); // for READ(SIZE=); can be <0
116 RT_API_ATTRS MutableModes
&mutableModes();
117 RT_API_ATTRS ConnectionState
&GetConnectionState();
118 RT_API_ATTRS IoErrorHandler
&GetIoErrorHandler() const;
120 // N.B.: this also works with base classes
121 template <typename A
> RT_API_ATTRS A
*get_if() const {
122 return common::visit(
124 if constexpr (std::is_convertible_v
<decltype(x
.get()), A
&>) {
132 // Vacant after the end of the current record
133 RT_API_ATTRS
Fortran::common::optional
<char32_t
> GetCurrentChar(
134 std::size_t &byteCount
);
136 // The result of CueUpInput() and the "remaining" arguments to SkipSpaces()
137 // and NextInField() are always in units of bytes, not characters; the
138 // distinction matters for internal input from CHARACTER(KIND=2 and 4).
140 // For fixed-width fields, return the number of remaining bytes.
141 // Skip over leading blanks.
142 RT_API_ATTRS
Fortran::common::optional
<int> CueUpInput(const DataEdit
&edit
) {
143 Fortran::common::optional
<int> remaining
;
144 if (edit
.IsListDirected()) {
145 std::size_t byteCount
{0};
146 GetNextNonBlank(byteCount
);
148 if (edit
.width
.value_or(0) > 0) {
149 remaining
= *edit
.width
;
150 if (int bytesPerChar
{GetConnectionState().internalIoCharKind
};
152 *remaining
*= bytesPerChar
;
155 SkipSpaces(remaining
);
160 RT_API_ATTRS
Fortran::common::optional
<char32_t
> SkipSpaces(
161 Fortran::common::optional
<int> &remaining
) {
162 while (!remaining
|| *remaining
> 0) {
163 std::size_t byteCount
{0};
164 if (auto ch
{GetCurrentChar(byteCount
)}) {
165 if (*ch
!= ' ' && *ch
!= '\t') {
169 if (static_cast<std::size_t>(*remaining
) < byteCount
) {
173 *remaining
-= byteCount
;
175 HandleRelativePosition(byteCount
);
180 return Fortran::common::nullopt
;
183 // Acquires the next input character, respecting any applicable field width
184 // or separator character.
185 RT_API_ATTRS
Fortran::common::optional
<char32_t
> NextInField(
186 Fortran::common::optional
<int> &remaining
, const DataEdit
&);
188 // Detect and signal any end-of-record condition after input.
189 // Returns true if at EOR and remaining input should be padded with blanks.
190 RT_API_ATTRS
bool CheckForEndOfRecord(std::size_t afterReading
);
192 // Skips spaces, advances records, and ignores NAMELIST comments
193 RT_API_ATTRS
Fortran::common::optional
<char32_t
> GetNextNonBlank(
194 std::size_t &byteCount
) {
195 auto ch
{GetCurrentChar(byteCount
)};
196 bool inNamelist
{mutableModes().inNamelist
};
197 while (!ch
|| *ch
== ' ' || *ch
== '\t' || *ch
== '\n' ||
198 (inNamelist
&& *ch
== '!')) {
199 if (ch
&& (*ch
== ' ' || *ch
== '\t' || *ch
== '\n')) {
200 HandleRelativePosition(byteCount
);
201 } else if (!AdvanceRecord()) {
202 return Fortran::common::nullopt
;
204 ch
= GetCurrentChar(byteCount
);
209 template <Direction D
>
210 RT_API_ATTRS
bool CheckFormattedStmtType(const char *name
) {
211 if (get_if
<FormattedIoStatementState
<D
>>()) {
214 auto &handler
{GetIoErrorHandler()};
215 if (!handler
.InError()) {
216 handler
.Crash("%s called for I/O statement that is not formatted %s",
217 name
, D
== Direction::Output
? "output" : "input");
224 std::variant
<Fortran::common::reference_wrapper
<OpenStatementState
>,
225 Fortran::common::reference_wrapper
<CloseStatementState
>,
226 Fortran::common::reference_wrapper
<NoopStatementState
>,
227 Fortran::common::reference_wrapper
<
228 InternalFormattedIoStatementState
<Direction::Output
>>,
229 Fortran::common::reference_wrapper
<
230 InternalFormattedIoStatementState
<Direction::Input
>>,
231 Fortran::common::reference_wrapper
<
232 InternalListIoStatementState
<Direction::Output
>>,
233 Fortran::common::reference_wrapper
<
234 InternalListIoStatementState
<Direction::Input
>>,
235 Fortran::common::reference_wrapper
<
236 ExternalFormattedIoStatementState
<Direction::Output
>>,
237 Fortran::common::reference_wrapper
<
238 ExternalFormattedIoStatementState
<Direction::Input
>>,
239 Fortran::common::reference_wrapper
<
240 ExternalListIoStatementState
<Direction::Output
>>,
241 Fortran::common::reference_wrapper
<
242 ExternalListIoStatementState
<Direction::Input
>>,
243 Fortran::common::reference_wrapper
<
244 ExternalUnformattedIoStatementState
<Direction::Output
>>,
245 Fortran::common::reference_wrapper
<
246 ExternalUnformattedIoStatementState
<Direction::Input
>>,
247 Fortran::common::reference_wrapper
<
248 ChildFormattedIoStatementState
<Direction::Output
>>,
249 Fortran::common::reference_wrapper
<
250 ChildFormattedIoStatementState
<Direction::Input
>>,
251 Fortran::common::reference_wrapper
<
252 ChildListIoStatementState
<Direction::Output
>>,
253 Fortran::common::reference_wrapper
<
254 ChildListIoStatementState
<Direction::Input
>>,
255 Fortran::common::reference_wrapper
<
256 ChildUnformattedIoStatementState
<Direction::Output
>>,
257 Fortran::common::reference_wrapper
<
258 ChildUnformattedIoStatementState
<Direction::Input
>>,
259 Fortran::common::reference_wrapper
<InquireUnitState
>,
260 Fortran::common::reference_wrapper
<InquireNoUnitState
>,
261 Fortran::common::reference_wrapper
<InquireUnconnectedFileState
>,
262 Fortran::common::reference_wrapper
<InquireIOLengthState
>,
263 Fortran::common::reference_wrapper
<ExternalMiscIoStatementState
>,
264 Fortran::common::reference_wrapper
<ErroneousIoStatementState
>>
268 // Base class for all per-I/O statement state classes.
269 class IoStatementBase
: public IoErrorHandler
{
271 using IoErrorHandler::IoErrorHandler
;
273 RT_API_ATTRS
bool completedOperation() const { return completedOperation_
; }
275 RT_API_ATTRS
void CompleteOperation() { completedOperation_
= true; }
276 RT_API_ATTRS
int EndIoStatement() { return GetIoStat(); }
278 // These are default no-op backstops that can be overridden by descendants.
279 RT_API_ATTRS
bool Emit(
280 const char *, std::size_t bytes
, std::size_t elementBytes
= 0);
281 RT_API_ATTRS
bool Receive(
282 char *, std::size_t bytes
, std::size_t elementBytes
= 0);
283 RT_API_ATTRS
std::size_t GetNextInputBytes(const char *&);
284 RT_API_ATTRS
std::size_t ViewBytesInRecord(const char *&, bool forward
) const;
285 RT_API_ATTRS
bool AdvanceRecord(int);
286 RT_API_ATTRS
void BackspaceRecord();
287 RT_API_ATTRS
void HandleRelativePosition(std::int64_t);
288 RT_API_ATTRS
void HandleAbsolutePosition(std::int64_t);
289 RT_API_ATTRS
Fortran::common::optional
<DataEdit
> GetNextDataEdit(
290 IoStatementState
&, int maxRepeat
= 1);
291 RT_API_ATTRS ExternalFileUnit
*GetExternalFileUnit() const;
292 RT_API_ATTRS
bool BeginReadingRecord();
293 RT_API_ATTRS
void FinishReadingRecord();
294 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, char *, std::size_t);
295 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, bool &);
296 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t, bool &);
297 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t &);
298 RT_API_ATTRS
std::int64_t InquirePos();
300 RT_API_ATTRS
void BadInquiryKeywordHashCrash(InquiryKeywordHash
);
302 RT_API_ATTRS
void ReportUnsupportedChildIo() const {
303 Crash("not yet implemented: child IO");
307 bool completedOperation_
{false};
310 // Common state for list-directed & NAMELIST I/O, both internal & external
311 template <Direction
> class ListDirectedStatementState
;
313 class ListDirectedStatementState
<Direction::Output
>
314 : public FormattedIoStatementState
<Direction::Output
> {
316 RT_API_ATTRS
bool EmitLeadingSpaceOrAdvance(
317 IoStatementState
&, std::size_t = 1, bool isCharacter
= false);
318 RT_API_ATTRS
Fortran::common::optional
<DataEdit
> GetNextDataEdit(
319 IoStatementState
&, int maxRepeat
= 1);
320 RT_API_ATTRS
bool lastWasUndelimitedCharacter() const {
321 return lastWasUndelimitedCharacter_
;
323 RT_API_ATTRS
void set_lastWasUndelimitedCharacter(bool yes
= true) {
324 lastWasUndelimitedCharacter_
= yes
;
328 bool lastWasUndelimitedCharacter_
{false};
331 class ListDirectedStatementState
<Direction::Input
>
332 : public FormattedIoStatementState
<Direction::Input
> {
334 RT_API_ATTRS
bool inNamelistSequence() const { return inNamelistSequence_
; }
335 RT_API_ATTRS
int EndIoStatement();
337 // Skips value separators, handles repetition and null values.
338 // Vacant when '/' appears; present with descriptor == ListDirectedNullValue
339 // when a null value appears.
340 RT_API_ATTRS
Fortran::common::optional
<DataEdit
> GetNextDataEdit(
341 IoStatementState
&, int maxRepeat
= 1);
343 // Each NAMELIST input item is treated like a distinct list-directed
344 // input statement. This member function resets some state so that
345 // repetition and null values work correctly for each successive
346 // NAMELIST input item.
347 RT_API_ATTRS
void ResetForNextNamelistItem(bool inNamelistSequence
) {
349 if (repeatPosition_
) {
350 repeatPosition_
->Cancel();
353 realPart_
= imaginaryPart_
= false;
354 inNamelistSequence_
= inNamelistSequence
;
358 int remaining_
{0}; // for "r*" repetition
359 Fortran::common::optional
<SavedPosition
> repeatPosition_
;
360 bool eatComma_
{false}; // consume comma after previously read item
361 bool hitSlash_
{false}; // once '/' is seen, nullify further items
362 bool realPart_
{false};
363 bool imaginaryPart_
{false};
364 bool inNamelistSequence_
{false};
367 template <Direction
DIR>
368 class InternalIoStatementState
: public IoStatementBase
,
369 public IoDirectionState
<DIR> {
372 std::conditional_t
<DIR == Direction::Input
, const char *, char *>;
373 RT_API_ATTRS
InternalIoStatementState(Buffer
, std::size_t,
374 const char *sourceFile
= nullptr, int sourceLine
= 0);
375 RT_API_ATTRS
InternalIoStatementState(
376 const Descriptor
&, const char *sourceFile
= nullptr, int sourceLine
= 0);
377 RT_API_ATTRS
int EndIoStatement();
379 RT_API_ATTRS
bool Emit(
380 const char *data
, std::size_t bytes
, std::size_t elementBytes
= 0);
381 RT_API_ATTRS
std::size_t GetNextInputBytes(const char *&);
382 RT_API_ATTRS
bool AdvanceRecord(int = 1);
383 RT_API_ATTRS
void BackspaceRecord();
384 RT_API_ATTRS ConnectionState
&GetConnectionState() { return unit_
; }
385 RT_API_ATTRS MutableModes
&mutableModes() { return unit_
.modes
; }
386 RT_API_ATTRS
void HandleRelativePosition(std::int64_t);
387 RT_API_ATTRS
void HandleAbsolutePosition(std::int64_t);
388 RT_API_ATTRS
std::int64_t InquirePos();
392 InternalDescriptorUnit
<DIR> unit_
;
395 template <Direction
DIR, typename CHAR
>
396 class InternalFormattedIoStatementState
397 : public InternalIoStatementState
<DIR>,
398 public FormattedIoStatementState
<DIR> {
400 using CharType
= CHAR
;
401 using typename InternalIoStatementState
<DIR>::Buffer
;
402 RT_API_ATTRS
InternalFormattedIoStatementState(Buffer internal
,
403 std::size_t internalLength
, const CharType
*format
,
404 std::size_t formatLength
, const Descriptor
*formatDescriptor
= nullptr,
405 const char *sourceFile
= nullptr, int sourceLine
= 0);
406 RT_API_ATTRS
InternalFormattedIoStatementState(const Descriptor
&,
407 const CharType
*format
, std::size_t formatLength
,
408 const Descriptor
*formatDescriptor
= nullptr,
409 const char *sourceFile
= nullptr, int sourceLine
= 0);
410 RT_API_ATTRS IoStatementState
&ioStatementState() {
411 return ioStatementState_
;
413 RT_API_ATTRS
void CompleteOperation();
414 RT_API_ATTRS
int EndIoStatement();
415 RT_API_ATTRS
Fortran::common::optional
<DataEdit
> GetNextDataEdit(
416 IoStatementState
&, int maxRepeat
= 1) {
417 return format_
.GetNextDataEdit(*this, maxRepeat
);
421 IoStatementState ioStatementState_
; // points to *this
422 using InternalIoStatementState
<DIR>::unit_
;
423 // format_ *must* be last; it may be partial someday
424 FormatControl
<InternalFormattedIoStatementState
> format_
;
427 template <Direction
DIR>
428 class InternalListIoStatementState
: public InternalIoStatementState
<DIR>,
429 public ListDirectedStatementState
<DIR> {
431 using typename InternalIoStatementState
<DIR>::Buffer
;
432 RT_API_ATTRS
InternalListIoStatementState(Buffer internal
,
433 std::size_t internalLength
, const char *sourceFile
= nullptr,
435 RT_API_ATTRS
InternalListIoStatementState(
436 const Descriptor
&, const char *sourceFile
= nullptr, int sourceLine
= 0);
437 RT_API_ATTRS IoStatementState
&ioStatementState() {
438 return ioStatementState_
;
440 using ListDirectedStatementState
<DIR>::GetNextDataEdit
;
441 RT_API_ATTRS
void CompleteOperation();
442 RT_API_ATTRS
int EndIoStatement();
445 IoStatementState ioStatementState_
; // points to *this
446 using InternalIoStatementState
<DIR>::unit_
;
449 class ExternalIoStatementBase
: public IoStatementBase
{
451 RT_API_ATTRS
ExternalIoStatementBase(
452 ExternalFileUnit
&, const char *sourceFile
= nullptr, int sourceLine
= 0);
453 RT_API_ATTRS ExternalFileUnit
&unit() { return unit_
; }
454 RT_API_ATTRS
const ExternalFileUnit
&unit() const { return unit_
; }
455 RT_API_ATTRS MutableModes
&mutableModes();
456 RT_API_ATTRS ConnectionState
&GetConnectionState();
457 RT_API_ATTRS
int asynchronousID() const { return asynchronousID_
; }
458 RT_API_ATTRS
void set_destroy(bool yes
= true) { destroy_
= yes
; }
459 RT_API_ATTRS
int EndIoStatement();
460 RT_API_ATTRS ExternalFileUnit
*GetExternalFileUnit() const { return &unit_
; }
461 RT_API_ATTRS
void SetAsynchronous();
462 RT_API_ATTRS
std::int64_t InquirePos();
465 ExternalFileUnit
&unit_
;
466 int asynchronousID_
{-1};
467 bool destroy_
{false};
470 template <Direction
DIR>
471 class ExternalIoStatementState
: public ExternalIoStatementBase
,
472 public IoDirectionState
<DIR> {
474 RT_API_ATTRS
ExternalIoStatementState(
475 ExternalFileUnit
&, const char *sourceFile
= nullptr, int sourceLine
= 0);
476 RT_API_ATTRS MutableModes
&mutableModes() { return mutableModes_
; }
477 RT_API_ATTRS
void CompleteOperation();
478 RT_API_ATTRS
int EndIoStatement();
479 RT_API_ATTRS
bool Emit(
480 const char *, std::size_t bytes
, std::size_t elementBytes
= 0);
481 RT_API_ATTRS
std::size_t GetNextInputBytes(const char *&);
482 RT_API_ATTRS
std::size_t ViewBytesInRecord(const char *&, bool forward
) const;
483 RT_API_ATTRS
bool AdvanceRecord(int = 1);
484 RT_API_ATTRS
void BackspaceRecord();
485 RT_API_ATTRS
void HandleRelativePosition(std::int64_t);
486 RT_API_ATTRS
void HandleAbsolutePosition(std::int64_t);
487 RT_API_ATTRS
bool BeginReadingRecord();
488 RT_API_ATTRS
void FinishReadingRecord();
491 // These are forked from ConnectionState's modes at the beginning
492 // of each formatted I/O statement so they may be overridden by control
493 // edit descriptors during the statement.
494 MutableModes mutableModes_
;
497 template <Direction
DIR, typename CHAR
>
498 class ExternalFormattedIoStatementState
499 : public ExternalIoStatementState
<DIR>,
500 public FormattedIoStatementState
<DIR> {
502 using CharType
= CHAR
;
503 RT_API_ATTRS
ExternalFormattedIoStatementState(ExternalFileUnit
&,
504 const CharType
*format
, std::size_t formatLength
,
505 const Descriptor
*formatDescriptor
= nullptr,
506 const char *sourceFile
= nullptr, int sourceLine
= 0);
507 RT_API_ATTRS
void CompleteOperation();
508 RT_API_ATTRS
int EndIoStatement();
509 RT_API_ATTRS
Fortran::common::optional
<DataEdit
> GetNextDataEdit(
510 IoStatementState
&, int maxRepeat
= 1) {
511 return format_
.GetNextDataEdit(*this, maxRepeat
);
515 FormatControl
<ExternalFormattedIoStatementState
> format_
;
518 template <Direction
DIR>
519 class ExternalListIoStatementState
: public ExternalIoStatementState
<DIR>,
520 public ListDirectedStatementState
<DIR> {
522 using ExternalIoStatementState
<DIR>::ExternalIoStatementState
;
523 using ListDirectedStatementState
<DIR>::GetNextDataEdit
;
524 RT_API_ATTRS
int EndIoStatement();
527 template <Direction
DIR>
528 class ExternalUnformattedIoStatementState
529 : public ExternalIoStatementState
<DIR> {
531 using ExternalIoStatementState
<DIR>::ExternalIoStatementState
;
532 RT_API_ATTRS
bool Receive(char *, std::size_t, std::size_t elementBytes
= 0);
535 template <Direction
DIR>
536 class ChildIoStatementState
: public IoStatementBase
,
537 public IoDirectionState
<DIR> {
539 RT_API_ATTRS
ChildIoStatementState(
540 ChildIo
&, const char *sourceFile
= nullptr, int sourceLine
= 0);
541 RT_API_ATTRS ChildIo
&child() { return child_
; }
542 RT_API_ATTRS MutableModes
&mutableModes();
543 RT_API_ATTRS ConnectionState
&GetConnectionState();
544 RT_API_ATTRS ExternalFileUnit
*GetExternalFileUnit() const;
545 RT_API_ATTRS
int EndIoStatement();
546 RT_API_ATTRS
bool Emit(
547 const char *, std::size_t bytes
, std::size_t elementBytes
= 0);
548 RT_API_ATTRS
std::size_t GetNextInputBytes(const char *&);
549 RT_API_ATTRS
std::size_t ViewBytesInRecord(const char *&, bool forward
) const;
550 RT_API_ATTRS
void HandleRelativePosition(std::int64_t);
551 RT_API_ATTRS
void HandleAbsolutePosition(std::int64_t);
557 template <Direction
DIR, typename CHAR
>
558 class ChildFormattedIoStatementState
: public ChildIoStatementState
<DIR>,
559 public FormattedIoStatementState
<DIR> {
561 using CharType
= CHAR
;
562 RT_API_ATTRS
ChildFormattedIoStatementState(ChildIo
&, const CharType
*format
,
563 std::size_t formatLength
, const Descriptor
*formatDescriptor
= nullptr,
564 const char *sourceFile
= nullptr, int sourceLine
= 0);
565 RT_API_ATTRS MutableModes
&mutableModes() { return mutableModes_
; }
566 RT_API_ATTRS
void CompleteOperation();
567 RT_API_ATTRS
int EndIoStatement();
568 RT_API_ATTRS
bool AdvanceRecord(int = 1);
569 RT_API_ATTRS
Fortran::common::optional
<DataEdit
> GetNextDataEdit(
570 IoStatementState
&, int maxRepeat
= 1) {
571 return format_
.GetNextDataEdit(*this, maxRepeat
);
575 MutableModes mutableModes_
;
576 FormatControl
<ChildFormattedIoStatementState
> format_
;
579 template <Direction
DIR>
580 class ChildListIoStatementState
: public ChildIoStatementState
<DIR>,
581 public ListDirectedStatementState
<DIR> {
583 using ChildIoStatementState
<DIR>::ChildIoStatementState
;
584 using ListDirectedStatementState
<DIR>::GetNextDataEdit
;
585 RT_API_ATTRS
int EndIoStatement();
588 template <Direction
DIR>
589 class ChildUnformattedIoStatementState
: public ChildIoStatementState
<DIR> {
591 using ChildIoStatementState
<DIR>::ChildIoStatementState
;
592 RT_API_ATTRS
bool Receive(char *, std::size_t, std::size_t elementBytes
= 0);
596 class OpenStatementState
: public ExternalIoStatementBase
{
598 RT_API_ATTRS
OpenStatementState(ExternalFileUnit
&unit
, bool wasExtant
,
599 bool isNewUnit
, const char *sourceFile
= nullptr, int sourceLine
= 0)
600 : ExternalIoStatementBase
{unit
, sourceFile
, sourceLine
},
601 wasExtant_
{wasExtant
}, isNewUnit_
{isNewUnit
} {}
602 RT_API_ATTRS
bool wasExtant() const { return wasExtant_
; }
603 RT_API_ATTRS
void set_status(OpenStatus status
) {
606 RT_API_ATTRS
void set_path(const char *, std::size_t); // FILE=
607 RT_API_ATTRS
void set_position(Position position
) {
608 position_
= position
;
610 RT_API_ATTRS
void set_action(Action action
) { action_
= action
; } // ACTION=
611 RT_API_ATTRS
void set_convert(Convert convert
) {
614 RT_API_ATTRS
void set_access(Access access
) { access_
= access
; } // ACCESS=
615 RT_API_ATTRS
void set_isUnformatted(bool yes
= true) {
616 isUnformatted_
= yes
;
619 RT_API_ATTRS
void CompleteOperation();
620 RT_API_ATTRS
int EndIoStatement();
625 Fortran::common::optional
<OpenStatus
> status_
;
626 Fortran::common::optional
<Position
> position_
;
627 Fortran::common::optional
<Action
> action_
;
628 Convert convert_
{Convert::Unknown
};
629 OwningPtr
<char> path_
;
630 std::size_t pathLength_
;
631 Fortran::common::optional
<bool> isUnformatted_
;
632 Fortran::common::optional
<Access
> access_
;
635 class CloseStatementState
: public ExternalIoStatementBase
{
637 RT_API_ATTRS
CloseStatementState(ExternalFileUnit
&unit
,
638 const char *sourceFile
= nullptr, int sourceLine
= 0)
639 : ExternalIoStatementBase
{unit
, sourceFile
, sourceLine
} {}
640 RT_API_ATTRS
void set_status(CloseStatus status
) { status_
= status
; }
641 RT_API_ATTRS
int EndIoStatement();
644 CloseStatus status_
{CloseStatus::Keep
};
647 // For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit),
648 // and recoverable BACKSPACE(bad unit)
649 class NoUnitIoStatementState
: public IoStatementBase
{
651 RT_API_ATTRS IoStatementState
&ioStatementState() {
652 return ioStatementState_
;
654 RT_API_ATTRS MutableModes
&mutableModes() { return connection_
.modes
; }
655 RT_API_ATTRS ConnectionState
&GetConnectionState() { return connection_
; }
656 RT_API_ATTRS
int badUnitNumber() const { return badUnitNumber_
; }
657 RT_API_ATTRS
void CompleteOperation();
658 RT_API_ATTRS
int EndIoStatement();
661 template <typename A
>
662 RT_API_ATTRS
NoUnitIoStatementState(A
&stmt
, const char *sourceFile
= nullptr,
663 int sourceLine
= 0, int badUnitNumber
= -1)
664 : IoStatementBase
{sourceFile
, sourceLine
}, ioStatementState_
{stmt
},
665 badUnitNumber_
{badUnitNumber
} {}
668 IoStatementState ioStatementState_
; // points to *this
669 ConnectionState connection_
;
673 class NoopStatementState
: public NoUnitIoStatementState
{
675 RT_API_ATTRS
NoopStatementState(
676 const char *sourceFile
= nullptr, int sourceLine
= 0, int unitNumber
= -1)
677 : NoUnitIoStatementState
{*this, sourceFile
, sourceLine
, unitNumber
} {}
678 RT_API_ATTRS
void set_status(CloseStatus
) {} // discards
681 extern template class InternalIoStatementState
<Direction::Output
>;
682 extern template class InternalIoStatementState
<Direction::Input
>;
683 extern template class InternalFormattedIoStatementState
<Direction::Output
>;
684 extern template class InternalFormattedIoStatementState
<Direction::Input
>;
685 extern template class InternalListIoStatementState
<Direction::Output
>;
686 extern template class InternalListIoStatementState
<Direction::Input
>;
687 extern template class ExternalIoStatementState
<Direction::Output
>;
688 extern template class ExternalIoStatementState
<Direction::Input
>;
689 extern template class ExternalFormattedIoStatementState
<Direction::Output
>;
690 extern template class ExternalFormattedIoStatementState
<Direction::Input
>;
691 extern template class ExternalListIoStatementState
<Direction::Output
>;
692 extern template class ExternalListIoStatementState
<Direction::Input
>;
693 extern template class ExternalUnformattedIoStatementState
<Direction::Output
>;
694 extern template class ExternalUnformattedIoStatementState
<Direction::Input
>;
695 extern template class ChildIoStatementState
<Direction::Output
>;
696 extern template class ChildIoStatementState
<Direction::Input
>;
697 extern template class ChildFormattedIoStatementState
<Direction::Output
>;
698 extern template class ChildFormattedIoStatementState
<Direction::Input
>;
699 extern template class ChildListIoStatementState
<Direction::Output
>;
700 extern template class ChildListIoStatementState
<Direction::Input
>;
701 extern template class ChildUnformattedIoStatementState
<Direction::Output
>;
702 extern template class ChildUnformattedIoStatementState
<Direction::Input
>;
704 extern template class FormatControl
<
705 InternalFormattedIoStatementState
<Direction::Output
>>;
706 extern template class FormatControl
<
707 InternalFormattedIoStatementState
<Direction::Input
>>;
708 extern template class FormatControl
<
709 ExternalFormattedIoStatementState
<Direction::Output
>>;
710 extern template class FormatControl
<
711 ExternalFormattedIoStatementState
<Direction::Input
>>;
712 extern template class FormatControl
<
713 ChildFormattedIoStatementState
<Direction::Output
>>;
714 extern template class FormatControl
<
715 ChildFormattedIoStatementState
<Direction::Input
>>;
717 class InquireUnitState
: public ExternalIoStatementBase
{
719 RT_API_ATTRS
InquireUnitState(ExternalFileUnit
&unit
,
720 const char *sourceFile
= nullptr, int sourceLine
= 0);
721 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, char *, std::size_t);
722 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, bool &);
723 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t, bool &);
724 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t &);
727 class InquireNoUnitState
: public NoUnitIoStatementState
{
729 RT_API_ATTRS
InquireNoUnitState(const char *sourceFile
= nullptr,
730 int sourceLine
= 0, int badUnitNumber
= -1);
731 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, char *, std::size_t);
732 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, bool &);
733 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t, bool &);
734 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t &);
737 class InquireUnconnectedFileState
: public NoUnitIoStatementState
{
739 RT_API_ATTRS
InquireUnconnectedFileState(OwningPtr
<char> &&path
,
740 const char *sourceFile
= nullptr, int sourceLine
= 0);
741 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, char *, std::size_t);
742 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, bool &);
743 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t, bool &);
744 RT_API_ATTRS
bool Inquire(InquiryKeywordHash
, std::int64_t &);
747 OwningPtr
<char> path_
; // trimmed and NUL terminated
750 class InquireIOLengthState
: public NoUnitIoStatementState
,
751 public OutputStatementState
{
753 RT_API_ATTRS
InquireIOLengthState(
754 const char *sourceFile
= nullptr, int sourceLine
= 0);
755 RT_API_ATTRS
std::size_t bytes() const { return bytes_
; }
756 RT_API_ATTRS
bool Emit(
757 const char *, std::size_t bytes
, std::size_t elementBytes
= 0);
760 std::size_t bytes_
{0};
763 class ExternalMiscIoStatementState
: public ExternalIoStatementBase
{
765 enum Which
{ Flush
, Backspace
, Endfile
, Rewind
, Wait
};
766 RT_API_ATTRS
ExternalMiscIoStatementState(ExternalFileUnit
&unit
, Which which
,
767 const char *sourceFile
= nullptr, int sourceLine
= 0)
768 : ExternalIoStatementBase
{unit
, sourceFile
, sourceLine
}, which_
{which
} {}
769 RT_API_ATTRS
void CompleteOperation();
770 RT_API_ATTRS
int EndIoStatement();
776 class ErroneousIoStatementState
: public IoStatementBase
{
778 explicit RT_API_ATTRS
ErroneousIoStatementState(Iostat iostat
,
779 ExternalFileUnit
*unit
= nullptr, const char *sourceFile
= nullptr,
781 : IoStatementBase
{sourceFile
, sourceLine
}, unit_
{unit
} {
782 SetPendingError(iostat
);
784 RT_API_ATTRS
int EndIoStatement();
785 RT_API_ATTRS ConnectionState
&GetConnectionState() { return connection_
; }
786 RT_API_ATTRS MutableModes
&mutableModes() { return connection_
.modes
; }
789 ConnectionState connection_
;
790 ExternalFileUnit
*unit_
{nullptr};
793 } // namespace Fortran::runtime::io
794 #endif // FORTRAN_RUNTIME_IO_STMT_H_