1//===-- runtime/io-stmt.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// Representations of the state of an I/O statement in progress
10
11#ifndef FORTRAN_RUNTIME_IO_STMT_H_
12#define FORTRAN_RUNTIME_IO_STMT_H_
13
14#include "connection.h"
15#include "file.h"
16#include "format.h"
17#include "internal-unit.h"
18#include "io-error.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>
25#include <functional>
26#include <type_traits>
27
28namespace Fortran::runtime::io {
29
30class ExternalFileUnit;
31class ChildIo;
32
33class OpenStatementState;
34class InquireUnitState;
35class InquireNoUnitState;
36class InquireUnconnectedFileState;
37class InquireIOLengthState;
38class ExternalMiscIoStatementState;
39class CloseStatementState;
40class NoopStatementState; // CLOSE or FLUSH on unknown unit
41class ErroneousIoStatementState;
42
43template <Direction, typename CHAR = char>
44class InternalFormattedIoStatementState;
45template <Direction> class InternalListIoStatementState;
46template <Direction, typename CHAR = char>
47class ExternalFormattedIoStatementState;
48template <Direction> class ExternalListIoStatementState;
49template <Direction> class ExternalUnformattedIoStatementState;
50template <Direction, typename CHAR = char> class ChildFormattedIoStatementState;
51template <Direction> class ChildListIoStatementState;
52template <Direction> class ChildUnformattedIoStatementState;
53
54struct InputStatementState {};
55struct OutputStatementState {};
56template <Direction D>
57using IoDirectionState = std::conditional_t<D == Direction::Input,
58 InputStatementState, OutputStatementState>;
59
60// Common state for all kinds of formatted I/O
61template <Direction D> class FormattedIoStatementState {};
62template <> class FormattedIoStatementState<Direction::Input> {
63public:
64 RT_API_ATTRS std::size_t GetEditDescriptorChars() const;
65 RT_API_ATTRS void GotChar(int);
66
67private:
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=)
71};
72
73// The Cookie type in the I/O API is a pointer (for C) to this class.
74class IoStatementState {
75public:
76 template <typename A> explicit RT_API_ATTRS IoStatementState(A &x) : u_{x} {}
77
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.
83
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();
91
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 bool AdvanceRecord(int = 1);
97 RT_API_ATTRS void BackspaceRecord();
98 RT_API_ATTRS void HandleRelativePosition(std::int64_t byteOffset);
99 RT_API_ATTRS void HandleAbsolutePosition(
100 std::int64_t byteOffset); // for r* in list I/O
101 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
102 int maxRepeat = 1);
103 RT_API_ATTRS ExternalFileUnit *
104 GetExternalFileUnit() const; // null if internal unit
105 RT_API_ATTRS bool BeginReadingRecord();
106 RT_API_ATTRS void FinishReadingRecord();
107 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
108 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
109 RT_API_ATTRS bool Inquire(
110 InquiryKeywordHash, std::int64_t, bool &); // PENDING=
111 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
112 RT_API_ATTRS std::int64_t InquirePos();
113 RT_API_ATTRS void GotChar(signed int = 1); // for READ(SIZE=); can be <0
114
115 RT_API_ATTRS MutableModes &mutableModes();
116 RT_API_ATTRS ConnectionState &GetConnectionState();
117 RT_API_ATTRS IoErrorHandler &GetIoErrorHandler() const;
118
119 // N.B.: this also works with base classes
120 template <typename A> RT_API_ATTRS A *get_if() const {
121 return common::visit(
122 [](auto &x) -> A * {
123 if constexpr (std::is_convertible_v<decltype(x.get()), A &>) {
124 return &x.get();
125 }
126 return nullptr;
127 },
128 u_);
129 }
130
131 // Vacant after the end of the current record
132 RT_API_ATTRS Fortran::common::optional<char32_t> GetCurrentChar(
133 std::size_t &byteCount);
134
135 // The "remaining" arguments to CueUpInput(), SkipSpaces(), & NextInField()
136 // are always in units of bytes, not characters; the distinction matters
137 // for internal input from CHARACTER(KIND=2 and 4).
138
139 // For fixed-width fields, return the number of remaining bytes.
140 // Skip over leading blanks.
141 RT_API_ATTRS Fortran::common::optional<int> CueUpInput(const DataEdit &edit) {
142 Fortran::common::optional<int> remaining;
143 if (edit.IsListDirected()) {
144 std::size_t byteCount{0};
145 GetNextNonBlank(byteCount);
146 } else {
147 if (edit.width.value_or(0) > 0) {
148 remaining = *edit.width;
149 if (int bytesPerChar{GetConnectionState().internalIoCharKind};
150 bytesPerChar > 1) {
151 *remaining *= bytesPerChar;
152 }
153 }
154 SkipSpaces(remaining);
155 }
156 return remaining;
157 }
158
159 RT_API_ATTRS Fortran::common::optional<char32_t> SkipSpaces(
160 Fortran::common::optional<int> &remaining) {
161 while (!remaining || *remaining > 0) {
162 std::size_t byteCount{0};
163 if (auto ch{GetCurrentChar(byteCount)}) {
164 if (*ch != ' ' && *ch != '\t') {
165 return ch;
166 }
167 if (remaining) {
168 if (static_cast<std::size_t>(*remaining) < byteCount) {
169 break;
170 }
171 GotChar(byteCount);
172 *remaining -= byteCount;
173 }
174 HandleRelativePosition(byteCount);
175 } else {
176 break;
177 }
178 }
179 return Fortran::common::nullopt;
180 }
181
182 // Acquires the next input character, respecting any applicable field width
183 // or separator character.
184 RT_API_ATTRS Fortran::common::optional<char32_t> NextInField(
185 Fortran::common::optional<int> &remaining, const DataEdit &);
186
187 // Detect and signal any end-of-record condition after input.
188 // Returns true if at EOR and remaining input should be padded with blanks.
189 RT_API_ATTRS bool CheckForEndOfRecord(std::size_t afterReading);
190
191 // Skips spaces, advances records, and ignores NAMELIST comments
192 RT_API_ATTRS Fortran::common::optional<char32_t> GetNextNonBlank(
193 std::size_t &byteCount) {
194 auto ch{GetCurrentChar(byteCount)};
195 bool inNamelist{mutableModes().inNamelist};
196 while (!ch || *ch == ' ' || *ch == '\t' || (inNamelist && *ch == '!')) {
197 if (ch && (*ch == ' ' || *ch == '\t')) {
198 HandleRelativePosition(byteCount);
199 } else if (!AdvanceRecord()) {
200 return Fortran::common::nullopt;
201 }
202 ch = GetCurrentChar(byteCount);
203 }
204 return ch;
205 }
206
207 template <Direction D>
208 RT_API_ATTRS bool CheckFormattedStmtType(const char *name) {
209 if (get_if<FormattedIoStatementState<D>>()) {
210 return true;
211 } else {
212 auto &handler{GetIoErrorHandler()};
213 if (!handler.InError()) {
214 handler.Crash("%s called for I/O statement that is not formatted %s",
215 name, D == Direction::Output ? "output" : "input");
216 }
217 return false;
218 }
219 }
220
221private:
222 std::variant<Fortran::common::reference_wrapper<OpenStatementState>,
223 Fortran::common::reference_wrapper<CloseStatementState>,
224 Fortran::common::reference_wrapper<NoopStatementState>,
225 Fortran::common::reference_wrapper<
226 InternalFormattedIoStatementState<Direction::Output>>,
227 Fortran::common::reference_wrapper<
228 InternalFormattedIoStatementState<Direction::Input>>,
229 Fortran::common::reference_wrapper<
230 InternalListIoStatementState<Direction::Output>>,
231 Fortran::common::reference_wrapper<
232 InternalListIoStatementState<Direction::Input>>,
233 Fortran::common::reference_wrapper<
234 ExternalFormattedIoStatementState<Direction::Output>>,
235 Fortran::common::reference_wrapper<
236 ExternalFormattedIoStatementState<Direction::Input>>,
237 Fortran::common::reference_wrapper<
238 ExternalListIoStatementState<Direction::Output>>,
239 Fortran::common::reference_wrapper<
240 ExternalListIoStatementState<Direction::Input>>,
241 Fortran::common::reference_wrapper<
242 ExternalUnformattedIoStatementState<Direction::Output>>,
243 Fortran::common::reference_wrapper<
244 ExternalUnformattedIoStatementState<Direction::Input>>,
245 Fortran::common::reference_wrapper<
246 ChildFormattedIoStatementState<Direction::Output>>,
247 Fortran::common::reference_wrapper<
248 ChildFormattedIoStatementState<Direction::Input>>,
249 Fortran::common::reference_wrapper<
250 ChildListIoStatementState<Direction::Output>>,
251 Fortran::common::reference_wrapper<
252 ChildListIoStatementState<Direction::Input>>,
253 Fortran::common::reference_wrapper<
254 ChildUnformattedIoStatementState<Direction::Output>>,
255 Fortran::common::reference_wrapper<
256 ChildUnformattedIoStatementState<Direction::Input>>,
257 Fortran::common::reference_wrapper<InquireUnitState>,
258 Fortran::common::reference_wrapper<InquireNoUnitState>,
259 Fortran::common::reference_wrapper<InquireUnconnectedFileState>,
260 Fortran::common::reference_wrapper<InquireIOLengthState>,
261 Fortran::common::reference_wrapper<ExternalMiscIoStatementState>,
262 Fortran::common::reference_wrapper<ErroneousIoStatementState>>
263 u_;
264};
265
266// Base class for all per-I/O statement state classes.
267class IoStatementBase : public IoErrorHandler {
268public:
269 using IoErrorHandler::IoErrorHandler;
270
271 RT_API_ATTRS bool completedOperation() const { return completedOperation_; }
272
273 RT_API_ATTRS void CompleteOperation() { completedOperation_ = true; }
274 RT_API_ATTRS int EndIoStatement() { return GetIoStat(); }
275
276 // These are default no-op backstops that can be overridden by descendants.
277 RT_API_ATTRS bool Emit(
278 const char *, std::size_t bytes, std::size_t elementBytes = 0);
279 RT_API_ATTRS bool Receive(
280 char *, std::size_t bytes, std::size_t elementBytes = 0);
281 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
282 RT_API_ATTRS bool AdvanceRecord(int);
283 RT_API_ATTRS void BackspaceRecord();
284 RT_API_ATTRS void HandleRelativePosition(std::int64_t);
285 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t);
286 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
287 IoStatementState &, int maxRepeat = 1);
288 RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const;
289 RT_API_ATTRS bool BeginReadingRecord();
290 RT_API_ATTRS void FinishReadingRecord();
291 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
292 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
293 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
294 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
295 RT_API_ATTRS std::int64_t InquirePos();
296
297 RT_API_ATTRS void BadInquiryKeywordHashCrash(InquiryKeywordHash);
298
299 RT_API_ATTRS void ReportUnsupportedChildIo() const {
300 Crash("not yet implemented: child IO");
301 }
302
303protected:
304 bool completedOperation_{false};
305};
306
307// Common state for list-directed & NAMELIST I/O, both internal & external
308template <Direction> class ListDirectedStatementState;
309template <>
310class ListDirectedStatementState<Direction::Output>
311 : public FormattedIoStatementState<Direction::Output> {
312public:
313 RT_API_ATTRS bool EmitLeadingSpaceOrAdvance(
314 IoStatementState &, std::size_t = 1, bool isCharacter = false);
315 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
316 IoStatementState &, int maxRepeat = 1);
317 RT_API_ATTRS bool lastWasUndelimitedCharacter() const {
318 return lastWasUndelimitedCharacter_;
319 }
320 RT_API_ATTRS void set_lastWasUndelimitedCharacter(bool yes = true) {
321 lastWasUndelimitedCharacter_ = yes;
322 }
323
324private:
325 bool lastWasUndelimitedCharacter_{false};
326};
327template <>
328class ListDirectedStatementState<Direction::Input>
329 : public FormattedIoStatementState<Direction::Input> {
330public:
331 RT_API_ATTRS bool inNamelistSequence() const { return inNamelistSequence_; }
332 RT_API_ATTRS int EndIoStatement();
333
334 // Skips value separators, handles repetition and null values.
335 // Vacant when '/' appears; present with descriptor == ListDirectedNullValue
336 // when a null value appears.
337 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
338 IoStatementState &, int maxRepeat = 1);
339
340 // Each NAMELIST input item is treated like a distinct list-directed
341 // input statement. This member function resets some state so that
342 // repetition and null values work correctly for each successive
343 // NAMELIST input item.
344 RT_API_ATTRS void ResetForNextNamelistItem(bool inNamelistSequence) {
345 remaining_ = 0;
346 if (repeatPosition_) {
347 repeatPosition_->Cancel();
348 }
349 eatComma_ = false;
350 realPart_ = imaginaryPart_ = false;
351 inNamelistSequence_ = inNamelistSequence;
352 }
353
354private:
355 int remaining_{0}; // for "r*" repetition
356 Fortran::common::optional<SavedPosition> repeatPosition_;
357 bool eatComma_{false}; // consume comma after previously read item
358 bool hitSlash_{false}; // once '/' is seen, nullify further items
359 bool realPart_{false};
360 bool imaginaryPart_{false};
361 bool inNamelistSequence_{false};
362};
363
364template <Direction DIR>
365class InternalIoStatementState : public IoStatementBase,
366 public IoDirectionState<DIR> {
367public:
368 using Buffer =
369 std::conditional_t<DIR == Direction::Input, const char *, char *>;
370 RT_API_ATTRS InternalIoStatementState(Buffer, std::size_t,
371 const char *sourceFile = nullptr, int sourceLine = 0);
372 RT_API_ATTRS InternalIoStatementState(
373 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
374 RT_API_ATTRS int EndIoStatement();
375
376 RT_API_ATTRS bool Emit(
377 const char *data, std::size_t bytes, std::size_t elementBytes = 0);
378 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
379 RT_API_ATTRS bool AdvanceRecord(int = 1);
380 RT_API_ATTRS void BackspaceRecord();
381 RT_API_ATTRS ConnectionState &GetConnectionState() { return unit_; }
382 RT_API_ATTRS MutableModes &mutableModes() { return unit_.modes; }
383 RT_API_ATTRS void HandleRelativePosition(std::int64_t);
384 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t);
385 RT_API_ATTRS std::int64_t InquirePos();
386
387protected:
388 bool free_{true};
389 InternalDescriptorUnit<DIR> unit_;
390};
391
392template <Direction DIR, typename CHAR>
393class InternalFormattedIoStatementState
394 : public InternalIoStatementState<DIR>,
395 public FormattedIoStatementState<DIR> {
396public:
397 using CharType = CHAR;
398 using typename InternalIoStatementState<DIR>::Buffer;
399 RT_API_ATTRS InternalFormattedIoStatementState(Buffer internal,
400 std::size_t internalLength, const CharType *format,
401 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
402 const char *sourceFile = nullptr, int sourceLine = 0);
403 RT_API_ATTRS InternalFormattedIoStatementState(const Descriptor &,
404 const CharType *format, std::size_t formatLength,
405 const Descriptor *formatDescriptor = nullptr,
406 const char *sourceFile = nullptr, int sourceLine = 0);
407 RT_API_ATTRS IoStatementState &ioStatementState() {
408 return ioStatementState_;
409 }
410 RT_API_ATTRS void CompleteOperation();
411 RT_API_ATTRS int EndIoStatement();
412 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
413 IoStatementState &, int maxRepeat = 1) {
414 return format_.GetNextDataEdit(*this, maxRepeat);
415 }
416
417private:
418 IoStatementState ioStatementState_; // points to *this
419 using InternalIoStatementState<DIR>::unit_;
420 // format_ *must* be last; it may be partial someday
421 FormatControl<InternalFormattedIoStatementState> format_;
422};
423
424template <Direction DIR>
425class InternalListIoStatementState : public InternalIoStatementState<DIR>,
426 public ListDirectedStatementState<DIR> {
427public:
428 using typename InternalIoStatementState<DIR>::Buffer;
429 RT_API_ATTRS InternalListIoStatementState(Buffer internal,
430 std::size_t internalLength, const char *sourceFile = nullptr,
431 int sourceLine = 0);
432 RT_API_ATTRS InternalListIoStatementState(
433 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
434 RT_API_ATTRS IoStatementState &ioStatementState() {
435 return ioStatementState_;
436 }
437 using ListDirectedStatementState<DIR>::GetNextDataEdit;
438 RT_API_ATTRS void CompleteOperation();
439 RT_API_ATTRS int EndIoStatement();
440
441private:
442 IoStatementState ioStatementState_; // points to *this
443 using InternalIoStatementState<DIR>::unit_;
444};
445
446class ExternalIoStatementBase : public IoStatementBase {
447public:
448 RT_API_ATTRS ExternalIoStatementBase(
449 ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
450 RT_API_ATTRS ExternalFileUnit &unit() { return unit_; }
451 RT_API_ATTRS MutableModes &mutableModes();
452 RT_API_ATTRS ConnectionState &GetConnectionState();
453 RT_API_ATTRS int asynchronousID() const { return asynchronousID_; }
454 RT_API_ATTRS int EndIoStatement();
455 RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const { return &unit_; }
456 RT_API_ATTRS void SetAsynchronous();
457 RT_API_ATTRS std::int64_t InquirePos();
458
459private:
460 ExternalFileUnit &unit_;
461 int asynchronousID_{-1};
462};
463
464template <Direction DIR>
465class ExternalIoStatementState : public ExternalIoStatementBase,
466 public IoDirectionState<DIR> {
467public:
468 RT_API_ATTRS ExternalIoStatementState(
469 ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
470 RT_API_ATTRS MutableModes &mutableModes() { return mutableModes_; }
471 RT_API_ATTRS void CompleteOperation();
472 RT_API_ATTRS int EndIoStatement();
473 RT_API_ATTRS bool Emit(
474 const char *, std::size_t bytes, std::size_t elementBytes = 0);
475 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
476 RT_API_ATTRS bool AdvanceRecord(int = 1);
477 RT_API_ATTRS void BackspaceRecord();
478 RT_API_ATTRS void HandleRelativePosition(std::int64_t);
479 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t);
480 RT_API_ATTRS bool BeginReadingRecord();
481 RT_API_ATTRS void FinishReadingRecord();
482
483private:
484 // These are forked from ConnectionState's modes at the beginning
485 // of each formatted I/O statement so they may be overridden by control
486 // edit descriptors during the statement.
487 MutableModes mutableModes_;
488};
489
490template <Direction DIR, typename CHAR>
491class ExternalFormattedIoStatementState
492 : public ExternalIoStatementState<DIR>,
493 public FormattedIoStatementState<DIR> {
494public:
495 using CharType = CHAR;
496 RT_API_ATTRS ExternalFormattedIoStatementState(ExternalFileUnit &,
497 const CharType *format, std::size_t formatLength,
498 const Descriptor *formatDescriptor = nullptr,
499 const char *sourceFile = nullptr, int sourceLine = 0);
500 RT_API_ATTRS void CompleteOperation();
501 RT_API_ATTRS int EndIoStatement();
502 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
503 IoStatementState &, int maxRepeat = 1) {
504 return format_.GetNextDataEdit(*this, maxRepeat);
505 }
506
507private:
508 FormatControl<ExternalFormattedIoStatementState> format_;
509};
510
511template <Direction DIR>
512class ExternalListIoStatementState : public ExternalIoStatementState<DIR>,
513 public ListDirectedStatementState<DIR> {
514public:
515 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
516 using ListDirectedStatementState<DIR>::GetNextDataEdit;
517 RT_API_ATTRS int EndIoStatement();
518};
519
520template <Direction DIR>
521class ExternalUnformattedIoStatementState
522 : public ExternalIoStatementState<DIR> {
523public:
524 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
525 RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
526};
527
528template <Direction DIR>
529class ChildIoStatementState : public IoStatementBase,
530 public IoDirectionState<DIR> {
531public:
532 RT_API_ATTRS ChildIoStatementState(
533 ChildIo &, const char *sourceFile = nullptr, int sourceLine = 0);
534 RT_API_ATTRS ChildIo &child() { return child_; }
535 RT_API_ATTRS MutableModes &mutableModes();
536 RT_API_ATTRS ConnectionState &GetConnectionState();
537 RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const;
538 RT_API_ATTRS int EndIoStatement();
539 RT_API_ATTRS bool Emit(
540 const char *, std::size_t bytes, std::size_t elementBytes = 0);
541 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&);
542 RT_API_ATTRS void HandleRelativePosition(std::int64_t);
543 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t);
544
545private:
546 ChildIo &child_;
547};
548
549template <Direction DIR, typename CHAR>
550class ChildFormattedIoStatementState : public ChildIoStatementState<DIR>,
551 public FormattedIoStatementState<DIR> {
552public:
553 using CharType = CHAR;
554 RT_API_ATTRS ChildFormattedIoStatementState(ChildIo &, const CharType *format,
555 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
556 const char *sourceFile = nullptr, int sourceLine = 0);
557 RT_API_ATTRS MutableModes &mutableModes() { return mutableModes_; }
558 RT_API_ATTRS void CompleteOperation();
559 RT_API_ATTRS int EndIoStatement();
560 RT_API_ATTRS bool AdvanceRecord(int = 1);
561 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit(
562 IoStatementState &, int maxRepeat = 1) {
563 return format_.GetNextDataEdit(*this, maxRepeat);
564 }
565
566private:
567 MutableModes mutableModes_;
568 FormatControl<ChildFormattedIoStatementState> format_;
569};
570
571template <Direction DIR>
572class ChildListIoStatementState : public ChildIoStatementState<DIR>,
573 public ListDirectedStatementState<DIR> {
574public:
575 using ChildIoStatementState<DIR>::ChildIoStatementState;
576 using ListDirectedStatementState<DIR>::GetNextDataEdit;
577 RT_API_ATTRS int EndIoStatement();
578};
579
580template <Direction DIR>
581class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> {
582public:
583 using ChildIoStatementState<DIR>::ChildIoStatementState;
584 RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
585};
586
587// OPEN
588class OpenStatementState : public ExternalIoStatementBase {
589public:
590 RT_API_ATTRS OpenStatementState(ExternalFileUnit &unit, bool wasExtant,
591 bool isNewUnit, const char *sourceFile = nullptr, int sourceLine = 0)
592 : ExternalIoStatementBase{unit, sourceFile, sourceLine},
593 wasExtant_{wasExtant}, isNewUnit_{isNewUnit} {}
594 RT_API_ATTRS bool wasExtant() const { return wasExtant_; }
595 RT_API_ATTRS void set_status(OpenStatus status) {
596 status_ = status;
597 } // STATUS=
598 RT_API_ATTRS void set_path(const char *, std::size_t); // FILE=
599 RT_API_ATTRS void set_position(Position position) {
600 position_ = position;
601 } // POSITION=
602 RT_API_ATTRS void set_action(Action action) { action_ = action; } // ACTION=
603 RT_API_ATTRS void set_convert(Convert convert) {
604 convert_ = convert;
605 } // CONVERT=
606 RT_API_ATTRS void set_access(Access access) { access_ = access; } // ACCESS=
607 RT_API_ATTRS void set_isUnformatted(bool yes = true) {
608 isUnformatted_ = yes;
609 } // FORM=
610
611 RT_API_ATTRS void CompleteOperation();
612 RT_API_ATTRS int EndIoStatement();
613
614private:
615 bool wasExtant_;
616 bool isNewUnit_;
617 Fortran::common::optional<OpenStatus> status_;
618 Fortran::common::optional<Position> position_;
619 Fortran::common::optional<Action> action_;
620 Convert convert_{Convert::Unknown};
621 OwningPtr<char> path_;
622 std::size_t pathLength_;
623 Fortran::common::optional<bool> isUnformatted_;
624 Fortran::common::optional<Access> access_;
625};
626
627class CloseStatementState : public ExternalIoStatementBase {
628public:
629 RT_API_ATTRS CloseStatementState(ExternalFileUnit &unit,
630 const char *sourceFile = nullptr, int sourceLine = 0)
631 : ExternalIoStatementBase{unit, sourceFile, sourceLine} {}
632 RT_API_ATTRS void set_status(CloseStatus status) { status_ = status; }
633 RT_API_ATTRS int EndIoStatement();
634
635private:
636 CloseStatus status_{CloseStatus::Keep};
637};
638
639// For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit),
640// and recoverable BACKSPACE(bad unit)
641class NoUnitIoStatementState : public IoStatementBase {
642public:
643 RT_API_ATTRS IoStatementState &ioStatementState() {
644 return ioStatementState_;
645 }
646 RT_API_ATTRS MutableModes &mutableModes() { return connection_.modes; }
647 RT_API_ATTRS ConnectionState &GetConnectionState() { return connection_; }
648 RT_API_ATTRS int badUnitNumber() const { return badUnitNumber_; }
649 RT_API_ATTRS void CompleteOperation();
650 RT_API_ATTRS int EndIoStatement();
651
652protected:
653 template <typename A>
654 RT_API_ATTRS NoUnitIoStatementState(A &stmt, const char *sourceFile = nullptr,
655 int sourceLine = 0, int badUnitNumber = -1)
656 : IoStatementBase{sourceFile, sourceLine}, ioStatementState_{stmt},
657 badUnitNumber_{badUnitNumber} {}
658
659private:
660 IoStatementState ioStatementState_; // points to *this
661 ConnectionState connection_;
662 int badUnitNumber_;
663};
664
665class NoopStatementState : public NoUnitIoStatementState {
666public:
667 RT_API_ATTRS NoopStatementState(
668 const char *sourceFile = nullptr, int sourceLine = 0, int unitNumber = -1)
669 : NoUnitIoStatementState{*this, sourceFile, sourceLine, unitNumber} {}
670 RT_API_ATTRS void set_status(CloseStatus) {} // discards
671};
672
673extern template class InternalIoStatementState<Direction::Output>;
674extern template class InternalIoStatementState<Direction::Input>;
675extern template class InternalFormattedIoStatementState<Direction::Output>;
676extern template class InternalFormattedIoStatementState<Direction::Input>;
677extern template class InternalListIoStatementState<Direction::Output>;
678extern template class InternalListIoStatementState<Direction::Input>;
679extern template class ExternalIoStatementState<Direction::Output>;
680extern template class ExternalIoStatementState<Direction::Input>;
681extern template class ExternalFormattedIoStatementState<Direction::Output>;
682extern template class ExternalFormattedIoStatementState<Direction::Input>;
683extern template class ExternalListIoStatementState<Direction::Output>;
684extern template class ExternalListIoStatementState<Direction::Input>;
685extern template class ExternalUnformattedIoStatementState<Direction::Output>;
686extern template class ExternalUnformattedIoStatementState<Direction::Input>;
687extern template class ChildIoStatementState<Direction::Output>;
688extern template class ChildIoStatementState<Direction::Input>;
689extern template class ChildFormattedIoStatementState<Direction::Output>;
690extern template class ChildFormattedIoStatementState<Direction::Input>;
691extern template class ChildListIoStatementState<Direction::Output>;
692extern template class ChildListIoStatementState<Direction::Input>;
693extern template class ChildUnformattedIoStatementState<Direction::Output>;
694extern template class ChildUnformattedIoStatementState<Direction::Input>;
695
696extern template class FormatControl<
697 InternalFormattedIoStatementState<Direction::Output>>;
698extern template class FormatControl<
699 InternalFormattedIoStatementState<Direction::Input>>;
700extern template class FormatControl<
701 ExternalFormattedIoStatementState<Direction::Output>>;
702extern template class FormatControl<
703 ExternalFormattedIoStatementState<Direction::Input>>;
704extern template class FormatControl<
705 ChildFormattedIoStatementState<Direction::Output>>;
706extern template class FormatControl<
707 ChildFormattedIoStatementState<Direction::Input>>;
708
709class InquireUnitState : public ExternalIoStatementBase {
710public:
711 RT_API_ATTRS InquireUnitState(ExternalFileUnit &unit,
712 const char *sourceFile = nullptr, int sourceLine = 0);
713 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
714 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
715 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
716 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
717};
718
719class InquireNoUnitState : public NoUnitIoStatementState {
720public:
721 RT_API_ATTRS InquireNoUnitState(const char *sourceFile = nullptr,
722 int sourceLine = 0, int badUnitNumber = -1);
723 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
724 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
725 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
726 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
727};
728
729class InquireUnconnectedFileState : public NoUnitIoStatementState {
730public:
731 RT_API_ATTRS InquireUnconnectedFileState(OwningPtr<char> &&path,
732 const char *sourceFile = nullptr, int sourceLine = 0);
733 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t);
734 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &);
735 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
736 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &);
737
738private:
739 OwningPtr<char> path_; // trimmed and NUL terminated
740};
741
742class InquireIOLengthState : public NoUnitIoStatementState,
743 public OutputStatementState {
744public:
745 RT_API_ATTRS InquireIOLengthState(
746 const char *sourceFile = nullptr, int sourceLine = 0);
747 RT_API_ATTRS std::size_t bytes() const { return bytes_; }
748 RT_API_ATTRS bool Emit(
749 const char *, std::size_t bytes, std::size_t elementBytes = 0);
750
751private:
752 std::size_t bytes_{0};
753};
754
755class ExternalMiscIoStatementState : public ExternalIoStatementBase {
756public:
757 enum Which { Flush, Backspace, Endfile, Rewind, Wait };
758 RT_API_ATTRS ExternalMiscIoStatementState(ExternalFileUnit &unit, Which which,
759 const char *sourceFile = nullptr, int sourceLine = 0)
760 : ExternalIoStatementBase{unit, sourceFile, sourceLine}, which_{which} {}
761 RT_API_ATTRS void CompleteOperation();
762 RT_API_ATTRS int EndIoStatement();
763
764private:
765 Which which_;
766};
767
768class ErroneousIoStatementState : public IoStatementBase {
769public:
770 explicit RT_API_ATTRS ErroneousIoStatementState(Iostat iostat,
771 ExternalFileUnit *unit = nullptr, const char *sourceFile = nullptr,
772 int sourceLine = 0)
773 : IoStatementBase{sourceFile, sourceLine}, unit_{unit} {
774 SetPendingError(iostat);
775 }
776 RT_API_ATTRS int EndIoStatement();
777 RT_API_ATTRS ConnectionState &GetConnectionState() { return connection_; }
778 RT_API_ATTRS MutableModes &mutableModes() { return connection_.modes; }
779
780private:
781 ConnectionState connection_;
782 ExternalFileUnit *unit_{nullptr};
783};
784
785} // namespace Fortran::runtime::io
786#endif // FORTRAN_RUNTIME_IO_STMT_H_
787

source code of flang/runtime/io-stmt.h