Revert "[lli] Revisit Orc debug output tests" (#79055)
[llvm-project.git] / flang / runtime / io-stmt.h
blob0b6bcbd9af025ae6af2768a128d31a8770de6837
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 //===----------------------------------------------------------------------===//
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"
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>
26 namespace Fortran::runtime::io {
28 class ExternalFileUnit;
29 class ChildIo;
31 class OpenStatementState;
32 class InquireUnitState;
33 class InquireNoUnitState;
34 class InquireUnconnectedFileState;
35 class InquireIOLengthState;
36 class ExternalMiscIoStatementState;
37 class CloseStatementState;
38 class NoopStatementState; // CLOSE or FLUSH on unknown unit
39 class ErroneousIoStatementState;
41 template <Direction, typename CHAR = char>
42 class InternalFormattedIoStatementState;
43 template <Direction> class InternalListIoStatementState;
44 template <Direction, typename CHAR = char>
45 class ExternalFormattedIoStatementState;
46 template <Direction> class ExternalListIoStatementState;
47 template <Direction> class ExternalUnformattedIoStatementState;
48 template <Direction, typename CHAR = char> class ChildFormattedIoStatementState;
49 template <Direction> class ChildListIoStatementState;
50 template <Direction> class ChildUnformattedIoStatementState;
52 struct InputStatementState {};
53 struct OutputStatementState {};
54 template <Direction D>
55 using IoDirectionState = std::conditional_t<D == Direction::Input,
56 InputStatementState, OutputStatementState>;
58 // Common state for all kinds of formatted I/O
59 template <Direction D> class FormattedIoStatementState {};
60 template <> class FormattedIoStatementState<Direction::Input> {
61 public:
62 std::size_t GetEditDescriptorChars() const;
63 void GotChar(int);
65 private:
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=)
71 // The Cookie type in the I/O API is a pointer (for C) to this class.
72 class IoStatementState {
73 public:
74 template <typename A> explicit IoStatementState(A &x) : u_{x} {}
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.
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();
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
108 MutableModes &mutableModes();
109 ConnectionState &GetConnectionState();
110 IoErrorHandler &GetIoErrorHandler() const;
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();
119 return nullptr;
121 u_);
124 // Vacant after the end of the current record
125 std::optional<char32_t> GetCurrentChar(std::size_t &byteCount);
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).
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(0) > 0) {
140 remaining = *edit.width;
141 if (int bytesPerChar{GetConnectionState().internalIoCharKind};
142 bytesPerChar > 1) {
143 *remaining *= bytesPerChar;
146 SkipSpaces(remaining);
148 return remaining;
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;
158 if (remaining) {
159 if (static_cast<std::size_t>(*remaining) < byteCount) {
160 break;
162 GotChar(byteCount);
163 *remaining -= byteCount;
165 HandleRelativePosition(byteCount);
166 } else {
167 break;
170 return std::nullopt;
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 &);
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);
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(byteCount);
189 } else if (!AdvanceRecord()) {
190 return std::nullopt;
192 ch = GetCurrentChar(byteCount);
194 return ch;
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");
206 return false;
210 private:
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>>
247 // Base class for all per-I/O statement state classes.
248 class IoStatementBase : public IoErrorHandler {
249 public:
250 using IoErrorHandler::IoErrorHandler;
252 bool completedOperation() const { return completedOperation_; }
254 void CompleteOperation() { completedOperation_ = true; }
255 int EndIoStatement() { return GetIoStat(); }
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();
276 void BadInquiryKeywordHashCrash(InquiryKeywordHash);
278 protected:
279 bool completedOperation_{false};
282 // Common state for list-directed & NAMELIST I/O, both internal & external
283 template <Direction> class ListDirectedStatementState;
284 template <>
285 class ListDirectedStatementState<Direction::Output>
286 : public FormattedIoStatementState<Direction::Output> {
287 public:
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_;
295 void set_lastWasUndelimitedCharacter(bool yes = true) {
296 lastWasUndelimitedCharacter_ = yes;
299 private:
300 bool lastWasUndelimitedCharacter_{false};
302 template <>
303 class ListDirectedStatementState<Direction::Input>
304 : public FormattedIoStatementState<Direction::Input> {
305 public:
306 bool inNamelistSequence() const { return inNamelistSequence_; }
307 int EndIoStatement();
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);
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();
324 eatComma_ = false;
325 realPart_ = imaginaryPart_ = false;
326 inNamelistSequence_ = inNamelistSequence;
329 private:
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};
339 template <Direction DIR>
340 class InternalIoStatementState : public IoStatementBase,
341 public IoDirectionState<DIR> {
342 public:
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();
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();
361 protected:
362 bool free_{true};
363 InternalDescriptorUnit<DIR> unit_;
366 template <Direction DIR, typename CHAR>
367 class InternalFormattedIoStatementState
368 : public InternalIoStatementState<DIR>,
369 public FormattedIoStatementState<DIR> {
370 public:
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);
388 private:
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_;
395 template <Direction DIR>
396 class InternalListIoStatementState : public InternalIoStatementState<DIR>,
397 public ListDirectedStatementState<DIR> {
398 public:
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();
408 private:
409 IoStatementState ioStatementState_; // points to *this
410 using InternalIoStatementState<DIR>::unit_;
413 class ExternalIoStatementBase : public IoStatementBase {
414 public:
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();
426 private:
427 ExternalFileUnit &unit_;
428 int asynchronousID_{-1};
431 template <Direction DIR>
432 class ExternalIoStatementState : public ExternalIoStatementBase,
433 public IoDirectionState<DIR> {
434 public:
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();
449 private:
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_;
456 template <Direction DIR, typename CHAR>
457 class ExternalFormattedIoStatementState
458 : public ExternalIoStatementState<DIR>,
459 public FormattedIoStatementState<DIR> {
460 public:
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);
472 private:
473 FormatControl<ExternalFormattedIoStatementState> format_;
476 template <Direction DIR>
477 class ExternalListIoStatementState : public ExternalIoStatementState<DIR>,
478 public ListDirectedStatementState<DIR> {
479 public:
480 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
481 using ListDirectedStatementState<DIR>::GetNextDataEdit;
482 int EndIoStatement();
485 template <Direction DIR>
486 class ExternalUnformattedIoStatementState
487 : public ExternalIoStatementState<DIR> {
488 public:
489 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
490 bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
493 template <Direction DIR>
494 class ChildIoStatementState : public IoStatementBase,
495 public IoDirectionState<DIR> {
496 public:
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);
509 private:
510 ChildIo &child_;
513 template <Direction DIR, typename CHAR>
514 class ChildFormattedIoStatementState : public ChildIoStatementState<DIR>,
515 public FormattedIoStatementState<DIR> {
516 public:
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);
530 private:
531 MutableModes mutableModes_;
532 FormatControl<ChildFormattedIoStatementState> format_;
535 template <Direction DIR>
536 class ChildListIoStatementState : public ChildIoStatementState<DIR>,
537 public ListDirectedStatementState<DIR> {
538 public:
539 using ChildIoStatementState<DIR>::ChildIoStatementState;
540 using ListDirectedStatementState<DIR>::GetNextDataEdit;
541 int EndIoStatement();
544 template <Direction DIR>
545 class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> {
546 public:
547 using ChildIoStatementState<DIR>::ChildIoStatementState;
548 bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
551 // OPEN
552 class OpenStatementState : public ExternalIoStatementBase {
553 public:
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=
567 void CompleteOperation();
568 int EndIoStatement();
570 private:
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_;
583 class CloseStatementState : public ExternalIoStatementBase {
584 public:
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();
591 private:
592 CloseStatus status_{CloseStatus::Keep};
595 // For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit),
596 // and recoverable BACKSPACE(bad unit)
597 class NoUnitIoStatementState : public IoStatementBase {
598 public:
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();
606 protected:
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} {}
613 private:
614 IoStatementState ioStatementState_; // points to *this
615 ConnectionState connection_;
616 int badUnitNumber_;
619 class NoopStatementState : public NoUnitIoStatementState {
620 public:
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
627 extern template class InternalIoStatementState<Direction::Output>;
628 extern template class InternalIoStatementState<Direction::Input>;
629 extern template class InternalFormattedIoStatementState<Direction::Output>;
630 extern template class InternalFormattedIoStatementState<Direction::Input>;
631 extern template class InternalListIoStatementState<Direction::Output>;
632 extern template class InternalListIoStatementState<Direction::Input>;
633 extern template class ExternalIoStatementState<Direction::Output>;
634 extern template class ExternalIoStatementState<Direction::Input>;
635 extern template class ExternalFormattedIoStatementState<Direction::Output>;
636 extern template class ExternalFormattedIoStatementState<Direction::Input>;
637 extern template class ExternalListIoStatementState<Direction::Output>;
638 extern template class ExternalListIoStatementState<Direction::Input>;
639 extern template class ExternalUnformattedIoStatementState<Direction::Output>;
640 extern template class ExternalUnformattedIoStatementState<Direction::Input>;
641 extern template class ChildIoStatementState<Direction::Output>;
642 extern template class ChildIoStatementState<Direction::Input>;
643 extern template class ChildFormattedIoStatementState<Direction::Output>;
644 extern template class ChildFormattedIoStatementState<Direction::Input>;
645 extern template class ChildListIoStatementState<Direction::Output>;
646 extern template class ChildListIoStatementState<Direction::Input>;
647 extern template class ChildUnformattedIoStatementState<Direction::Output>;
648 extern template class ChildUnformattedIoStatementState<Direction::Input>;
650 extern template class FormatControl<
651 InternalFormattedIoStatementState<Direction::Output>>;
652 extern template class FormatControl<
653 InternalFormattedIoStatementState<Direction::Input>>;
654 extern template class FormatControl<
655 ExternalFormattedIoStatementState<Direction::Output>>;
656 extern template class FormatControl<
657 ExternalFormattedIoStatementState<Direction::Input>>;
658 extern template class FormatControl<
659 ChildFormattedIoStatementState<Direction::Output>>;
660 extern template class FormatControl<
661 ChildFormattedIoStatementState<Direction::Input>>;
663 class InquireUnitState : public ExternalIoStatementBase {
664 public:
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 &);
673 class InquireNoUnitState : public NoUnitIoStatementState {
674 public:
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 &);
683 class InquireUnconnectedFileState : public NoUnitIoStatementState {
684 public:
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 &);
692 private:
693 OwningPtr<char> path_; // trimmed and NUL terminated
696 class InquireIOLengthState : public NoUnitIoStatementState,
697 public OutputStatementState {
698 public:
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);
703 private:
704 std::size_t bytes_{0};
707 class ExternalMiscIoStatementState : public ExternalIoStatementBase {
708 public:
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();
716 private:
717 Which which_;
720 class ErroneousIoStatementState : public IoStatementBase {
721 public:
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);
728 int EndIoStatement();
729 ConnectionState &GetConnectionState() { return connection_; }
730 MutableModes &mutableModes() { return connection_.modes; }
732 private:
733 ConnectionState connection_;
734 ExternalFileUnit *unit_{nullptr};
737 } // namespace Fortran::runtime::io
738 #endif // FORTRAN_RUNTIME_IO_STMT_H_