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

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