[AArch64,ELF] Restrict MOVZ/MOVK to non-PIC large code model (#70178)
[llvm-project.git] / flang / runtime / io-stmt.h
blobd4ceb83265246bd77b671469c57f0bb1b6cedd8c
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);
96 void HandleAbsolutePosition(std::int64_t); // 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 // For fixed-width fields, return the number of remaining characters.
128 // Skip over leading blanks.
129 std::optional<int> CueUpInput(const DataEdit &edit) {
130 std::optional<int> remaining;
131 if (edit.IsListDirected()) {
132 std::size_t byteCount{0};
133 GetNextNonBlank(byteCount);
134 } else {
135 if (edit.width.value_or(0) > 0) {
136 remaining = *edit.width;
138 SkipSpaces(remaining);
140 return remaining;
143 std::optional<char32_t> SkipSpaces(std::optional<int> &remaining) {
144 while (!remaining || *remaining > 0) {
145 std::size_t byteCount{0};
146 if (auto ch{GetCurrentChar(byteCount)}) {
147 if (*ch != ' ' && *ch != '\t') {
148 return ch;
150 if (remaining) {
151 if (static_cast<std::size_t>(*remaining) < byteCount) {
152 break;
154 GotChar(byteCount);
155 *remaining -= byteCount;
157 HandleRelativePosition(byteCount);
158 } else {
159 break;
162 return std::nullopt;
165 // Acquires the next input character, respecting any applicable field width
166 // or separator character.
167 std::optional<char32_t> NextInField(
168 std::optional<int> &remaining, const DataEdit &);
170 // Detect and signal any end-of-record condition after input.
171 // Returns true if at EOR and remaining input should be padded with blanks.
172 bool CheckForEndOfRecord(std::size_t afterReading);
174 // Skips spaces, advances records, and ignores NAMELIST comments
175 std::optional<char32_t> GetNextNonBlank(std::size_t &byteCount) {
176 auto ch{GetCurrentChar(byteCount)};
177 bool inNamelist{mutableModes().inNamelist};
178 while (!ch || *ch == ' ' || *ch == '\t' || (inNamelist && *ch == '!')) {
179 if (ch && (*ch == ' ' || *ch == '\t')) {
180 HandleRelativePosition(byteCount);
181 } else if (!AdvanceRecord()) {
182 return std::nullopt;
184 ch = GetCurrentChar(byteCount);
186 return ch;
189 template <Direction D> bool CheckFormattedStmtType(const char *name) {
190 if (get_if<FormattedIoStatementState<D>>()) {
191 return true;
192 } else {
193 auto &handler{GetIoErrorHandler()};
194 if (!handler.InError()) {
195 handler.Crash("%s called for I/O statement that is not formatted %s",
196 name, D == Direction::Output ? "output" : "input");
198 return false;
202 private:
203 std::variant<std::reference_wrapper<OpenStatementState>,
204 std::reference_wrapper<CloseStatementState>,
205 std::reference_wrapper<NoopStatementState>,
206 std::reference_wrapper<
207 InternalFormattedIoStatementState<Direction::Output>>,
208 std::reference_wrapper<
209 InternalFormattedIoStatementState<Direction::Input>>,
210 std::reference_wrapper<InternalListIoStatementState<Direction::Output>>,
211 std::reference_wrapper<InternalListIoStatementState<Direction::Input>>,
212 std::reference_wrapper<
213 ExternalFormattedIoStatementState<Direction::Output>>,
214 std::reference_wrapper<
215 ExternalFormattedIoStatementState<Direction::Input>>,
216 std::reference_wrapper<ExternalListIoStatementState<Direction::Output>>,
217 std::reference_wrapper<ExternalListIoStatementState<Direction::Input>>,
218 std::reference_wrapper<
219 ExternalUnformattedIoStatementState<Direction::Output>>,
220 std::reference_wrapper<
221 ExternalUnformattedIoStatementState<Direction::Input>>,
222 std::reference_wrapper<ChildFormattedIoStatementState<Direction::Output>>,
223 std::reference_wrapper<ChildFormattedIoStatementState<Direction::Input>>,
224 std::reference_wrapper<ChildListIoStatementState<Direction::Output>>,
225 std::reference_wrapper<ChildListIoStatementState<Direction::Input>>,
226 std::reference_wrapper<
227 ChildUnformattedIoStatementState<Direction::Output>>,
228 std::reference_wrapper<
229 ChildUnformattedIoStatementState<Direction::Input>>,
230 std::reference_wrapper<InquireUnitState>,
231 std::reference_wrapper<InquireNoUnitState>,
232 std::reference_wrapper<InquireUnconnectedFileState>,
233 std::reference_wrapper<InquireIOLengthState>,
234 std::reference_wrapper<ExternalMiscIoStatementState>,
235 std::reference_wrapper<ErroneousIoStatementState>>
239 // Base class for all per-I/O statement state classes.
240 class IoStatementBase : public IoErrorHandler {
241 public:
242 using IoErrorHandler::IoErrorHandler;
244 bool completedOperation() const { return completedOperation_; }
246 void CompleteOperation() { completedOperation_ = true; }
247 int EndIoStatement() { return GetIoStat(); }
249 // These are default no-op backstops that can be overridden by descendants.
250 bool Emit(const char *, std::size_t bytes, std::size_t elementBytes = 0);
251 bool Receive(char *, std::size_t bytes, std::size_t elementBytes = 0);
252 std::size_t GetNextInputBytes(const char *&);
253 bool AdvanceRecord(int);
254 void BackspaceRecord();
255 void HandleRelativePosition(std::int64_t);
256 void HandleAbsolutePosition(std::int64_t);
257 std::optional<DataEdit> GetNextDataEdit(
258 IoStatementState &, int maxRepeat = 1);
259 ExternalFileUnit *GetExternalFileUnit() const;
260 bool BeginReadingRecord();
261 void FinishReadingRecord();
262 bool Inquire(InquiryKeywordHash, char *, std::size_t);
263 bool Inquire(InquiryKeywordHash, bool &);
264 bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
265 bool Inquire(InquiryKeywordHash, std::int64_t &);
266 std::int64_t InquirePos();
268 void BadInquiryKeywordHashCrash(InquiryKeywordHash);
270 protected:
271 bool completedOperation_{false};
274 // Common state for list-directed & NAMELIST I/O, both internal & external
275 template <Direction> class ListDirectedStatementState;
276 template <>
277 class ListDirectedStatementState<Direction::Output>
278 : public FormattedIoStatementState<Direction::Output> {
279 public:
280 bool EmitLeadingSpaceOrAdvance(
281 IoStatementState &, std::size_t = 1, bool isCharacter = false);
282 std::optional<DataEdit> GetNextDataEdit(
283 IoStatementState &, int maxRepeat = 1);
284 bool lastWasUndelimitedCharacter() const {
285 return lastWasUndelimitedCharacter_;
287 void set_lastWasUndelimitedCharacter(bool yes = true) {
288 lastWasUndelimitedCharacter_ = yes;
291 private:
292 bool lastWasUndelimitedCharacter_{false};
294 template <>
295 class ListDirectedStatementState<Direction::Input>
296 : public FormattedIoStatementState<Direction::Input> {
297 public:
298 bool inNamelistSequence() const { return inNamelistSequence_; }
300 // Skips value separators, handles repetition and null values.
301 // Vacant when '/' appears; present with descriptor == ListDirectedNullValue
302 // when a null value appears.
303 std::optional<DataEdit> GetNextDataEdit(
304 IoStatementState &, int maxRepeat = 1);
306 // Each NAMELIST input item is treated like a distinct list-directed
307 // input statement. This member function resets some state so that
308 // repetition and null values work correctly for each successive
309 // NAMELIST input item.
310 void ResetForNextNamelistItem(bool inNamelistSequence) {
311 remaining_ = 0;
312 eatComma_ = false;
313 realPart_ = imaginaryPart_ = false;
314 inNamelistSequence_ = inNamelistSequence;
317 private:
318 int remaining_{0}; // for "r*" repetition
319 std::optional<SavedPosition> repeatPosition_;
320 bool eatComma_{false}; // consume comma after previously read item
321 bool hitSlash_{false}; // once '/' is seen, nullify further items
322 bool realPart_{false};
323 bool imaginaryPart_{false};
324 bool inNamelistSequence_{false};
327 template <Direction DIR>
328 class InternalIoStatementState : public IoStatementBase,
329 public IoDirectionState<DIR> {
330 public:
331 using Buffer =
332 std::conditional_t<DIR == Direction::Input, const char *, char *>;
333 InternalIoStatementState(Buffer, std::size_t,
334 const char *sourceFile = nullptr, int sourceLine = 0);
335 InternalIoStatementState(
336 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
337 int EndIoStatement();
339 bool Emit(const char *data, std::size_t bytes, std::size_t elementBytes = 0);
340 std::size_t GetNextInputBytes(const char *&);
341 bool AdvanceRecord(int = 1);
342 void BackspaceRecord();
343 ConnectionState &GetConnectionState() { return unit_; }
344 MutableModes &mutableModes() { return unit_.modes; }
345 void HandleRelativePosition(std::int64_t);
346 void HandleAbsolutePosition(std::int64_t);
347 std::int64_t InquirePos();
349 protected:
350 bool free_{true};
351 InternalDescriptorUnit<DIR> unit_;
354 template <Direction DIR, typename CHAR>
355 class InternalFormattedIoStatementState
356 : public InternalIoStatementState<DIR>,
357 public FormattedIoStatementState<DIR> {
358 public:
359 using CharType = CHAR;
360 using typename InternalIoStatementState<DIR>::Buffer;
361 InternalFormattedIoStatementState(Buffer internal, std::size_t internalLength,
362 const CharType *format, std::size_t formatLength,
363 const Descriptor *formatDescriptor = nullptr,
364 const char *sourceFile = nullptr, int sourceLine = 0);
365 InternalFormattedIoStatementState(const Descriptor &, const CharType *format,
366 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
367 const char *sourceFile = nullptr, int sourceLine = 0);
368 IoStatementState &ioStatementState() { return ioStatementState_; }
369 void CompleteOperation();
370 int EndIoStatement();
371 std::optional<DataEdit> GetNextDataEdit(
372 IoStatementState &, int maxRepeat = 1) {
373 return format_.GetNextDataEdit(*this, maxRepeat);
376 private:
377 IoStatementState ioStatementState_; // points to *this
378 using InternalIoStatementState<DIR>::unit_;
379 // format_ *must* be last; it may be partial someday
380 FormatControl<InternalFormattedIoStatementState> format_;
383 template <Direction DIR>
384 class InternalListIoStatementState : public InternalIoStatementState<DIR>,
385 public ListDirectedStatementState<DIR> {
386 public:
387 using typename InternalIoStatementState<DIR>::Buffer;
388 InternalListIoStatementState(Buffer internal, std::size_t internalLength,
389 const char *sourceFile = nullptr, int sourceLine = 0);
390 InternalListIoStatementState(
391 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
392 IoStatementState &ioStatementState() { return ioStatementState_; }
393 using ListDirectedStatementState<DIR>::GetNextDataEdit;
395 private:
396 IoStatementState ioStatementState_; // points to *this
397 using InternalIoStatementState<DIR>::unit_;
400 class ExternalIoStatementBase : public IoStatementBase {
401 public:
402 ExternalIoStatementBase(
403 ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
404 ExternalFileUnit &unit() { return unit_; }
405 MutableModes &mutableModes();
406 ConnectionState &GetConnectionState();
407 int asynchronousID() const { return asynchronousID_; }
408 int EndIoStatement();
409 ExternalFileUnit *GetExternalFileUnit() const { return &unit_; }
410 void SetAsynchronous();
411 std::int64_t InquirePos();
413 private:
414 ExternalFileUnit &unit_;
415 int asynchronousID_{-1};
418 template <Direction DIR>
419 class ExternalIoStatementState : public ExternalIoStatementBase,
420 public IoDirectionState<DIR> {
421 public:
422 ExternalIoStatementState(
423 ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
424 MutableModes &mutableModes() { return mutableModes_; }
425 void CompleteOperation();
426 int EndIoStatement();
427 bool Emit(const char *, std::size_t bytes, std::size_t elementBytes = 0);
428 std::size_t GetNextInputBytes(const char *&);
429 bool AdvanceRecord(int = 1);
430 void BackspaceRecord();
431 void HandleRelativePosition(std::int64_t);
432 void HandleAbsolutePosition(std::int64_t);
433 bool BeginReadingRecord();
434 void FinishReadingRecord();
436 private:
437 // These are forked from ConnectionState's modes at the beginning
438 // of each formatted I/O statement so they may be overridden by control
439 // edit descriptors during the statement.
440 MutableModes mutableModes_;
443 template <Direction DIR, typename CHAR>
444 class ExternalFormattedIoStatementState
445 : public ExternalIoStatementState<DIR>,
446 public FormattedIoStatementState<DIR> {
447 public:
448 using CharType = CHAR;
449 ExternalFormattedIoStatementState(ExternalFileUnit &, const CharType *format,
450 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
451 const char *sourceFile = nullptr, int sourceLine = 0);
452 void CompleteOperation();
453 int EndIoStatement();
454 std::optional<DataEdit> GetNextDataEdit(
455 IoStatementState &, int maxRepeat = 1) {
456 return format_.GetNextDataEdit(*this, maxRepeat);
459 private:
460 FormatControl<ExternalFormattedIoStatementState> format_;
463 template <Direction DIR>
464 class ExternalListIoStatementState : public ExternalIoStatementState<DIR>,
465 public ListDirectedStatementState<DIR> {
466 public:
467 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
468 using ListDirectedStatementState<DIR>::GetNextDataEdit;
471 template <Direction DIR>
472 class ExternalUnformattedIoStatementState
473 : public ExternalIoStatementState<DIR> {
474 public:
475 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
476 bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
479 template <Direction DIR>
480 class ChildIoStatementState : public IoStatementBase,
481 public IoDirectionState<DIR> {
482 public:
483 ChildIoStatementState(
484 ChildIo &, const char *sourceFile = nullptr, int sourceLine = 0);
485 ChildIo &child() { return child_; }
486 MutableModes &mutableModes();
487 ConnectionState &GetConnectionState();
488 ExternalFileUnit *GetExternalFileUnit() const;
489 int EndIoStatement();
490 bool Emit(const char *, std::size_t bytes, std::size_t elementBytes = 0);
491 std::size_t GetNextInputBytes(const char *&);
492 void HandleRelativePosition(std::int64_t);
493 void HandleAbsolutePosition(std::int64_t);
495 private:
496 ChildIo &child_;
499 template <Direction DIR, typename CHAR>
500 class ChildFormattedIoStatementState : public ChildIoStatementState<DIR>,
501 public FormattedIoStatementState<DIR> {
502 public:
503 using CharType = CHAR;
504 ChildFormattedIoStatementState(ChildIo &, const CharType *format,
505 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
506 const char *sourceFile = nullptr, int sourceLine = 0);
507 MutableModes &mutableModes() { return mutableModes_; }
508 void CompleteOperation();
509 int EndIoStatement();
510 bool AdvanceRecord(int = 1);
511 std::optional<DataEdit> GetNextDataEdit(
512 IoStatementState &, int maxRepeat = 1) {
513 return format_.GetNextDataEdit(*this, maxRepeat);
516 private:
517 MutableModes mutableModes_;
518 FormatControl<ChildFormattedIoStatementState> format_;
521 template <Direction DIR>
522 class ChildListIoStatementState : public ChildIoStatementState<DIR>,
523 public ListDirectedStatementState<DIR> {
524 public:
525 using ChildIoStatementState<DIR>::ChildIoStatementState;
526 using ListDirectedStatementState<DIR>::GetNextDataEdit;
529 template <Direction DIR>
530 class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> {
531 public:
532 using ChildIoStatementState<DIR>::ChildIoStatementState;
533 bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
536 // OPEN
537 class OpenStatementState : public ExternalIoStatementBase {
538 public:
539 OpenStatementState(ExternalFileUnit &unit, bool wasExtant, bool isNewUnit,
540 const char *sourceFile = nullptr, int sourceLine = 0)
541 : ExternalIoStatementBase{unit, sourceFile, sourceLine},
542 wasExtant_{wasExtant}, isNewUnit_{isNewUnit} {}
543 bool wasExtant() const { return wasExtant_; }
544 void set_status(OpenStatus status) { status_ = status; } // STATUS=
545 void set_path(const char *, std::size_t); // FILE=
546 void set_position(Position position) { position_ = position; } // POSITION=
547 void set_action(Action action) { action_ = action; } // ACTION=
548 void set_convert(Convert convert) { convert_ = convert; } // CONVERT=
549 void set_access(Access access) { access_ = access; } // ACCESS=
550 void set_isUnformatted(bool yes = true) { isUnformatted_ = yes; } // FORM=
552 void CompleteOperation();
553 int EndIoStatement();
555 private:
556 bool wasExtant_;
557 bool isNewUnit_;
558 std::optional<OpenStatus> status_;
559 std::optional<Position> position_;
560 std::optional<Action> action_;
561 Convert convert_{Convert::Unknown};
562 OwningPtr<char> path_;
563 std::size_t pathLength_;
564 std::optional<bool> isUnformatted_;
565 std::optional<Access> access_;
568 class CloseStatementState : public ExternalIoStatementBase {
569 public:
570 CloseStatementState(ExternalFileUnit &unit, const char *sourceFile = nullptr,
571 int sourceLine = 0)
572 : ExternalIoStatementBase{unit, sourceFile, sourceLine} {}
573 void set_status(CloseStatus status) { status_ = status; }
574 int EndIoStatement();
576 private:
577 CloseStatus status_{CloseStatus::Keep};
580 // For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit),
581 // and recoverable BACKSPACE(bad unit)
582 class NoUnitIoStatementState : public IoStatementBase {
583 public:
584 IoStatementState &ioStatementState() { return ioStatementState_; }
585 MutableModes &mutableModes() { return connection_.modes; }
586 ConnectionState &GetConnectionState() { return connection_; }
587 int badUnitNumber() const { return badUnitNumber_; }
588 void CompleteOperation();
589 int EndIoStatement();
591 protected:
592 template <typename A>
593 NoUnitIoStatementState(A &stmt, const char *sourceFile = nullptr,
594 int sourceLine = 0, int badUnitNumber = -1)
595 : IoStatementBase{sourceFile, sourceLine}, ioStatementState_{stmt},
596 badUnitNumber_{badUnitNumber} {}
598 private:
599 IoStatementState ioStatementState_; // points to *this
600 ConnectionState connection_;
601 int badUnitNumber_;
604 class NoopStatementState : public NoUnitIoStatementState {
605 public:
606 NoopStatementState(
607 const char *sourceFile = nullptr, int sourceLine = 0, int unitNumber = -1)
608 : NoUnitIoStatementState{*this, sourceFile, sourceLine, unitNumber} {}
609 void set_status(CloseStatus) {} // discards
612 extern template class InternalIoStatementState<Direction::Output>;
613 extern template class InternalIoStatementState<Direction::Input>;
614 extern template class InternalFormattedIoStatementState<Direction::Output>;
615 extern template class InternalFormattedIoStatementState<Direction::Input>;
616 extern template class InternalListIoStatementState<Direction::Output>;
617 extern template class InternalListIoStatementState<Direction::Input>;
618 extern template class ExternalIoStatementState<Direction::Output>;
619 extern template class ExternalIoStatementState<Direction::Input>;
620 extern template class ExternalFormattedIoStatementState<Direction::Output>;
621 extern template class ExternalFormattedIoStatementState<Direction::Input>;
622 extern template class ExternalListIoStatementState<Direction::Output>;
623 extern template class ExternalListIoStatementState<Direction::Input>;
624 extern template class ExternalUnformattedIoStatementState<Direction::Output>;
625 extern template class ExternalUnformattedIoStatementState<Direction::Input>;
626 extern template class ChildIoStatementState<Direction::Output>;
627 extern template class ChildIoStatementState<Direction::Input>;
628 extern template class ChildFormattedIoStatementState<Direction::Output>;
629 extern template class ChildFormattedIoStatementState<Direction::Input>;
630 extern template class ChildListIoStatementState<Direction::Output>;
631 extern template class ChildListIoStatementState<Direction::Input>;
632 extern template class ChildUnformattedIoStatementState<Direction::Output>;
633 extern template class ChildUnformattedIoStatementState<Direction::Input>;
635 extern template class FormatControl<
636 InternalFormattedIoStatementState<Direction::Output>>;
637 extern template class FormatControl<
638 InternalFormattedIoStatementState<Direction::Input>>;
639 extern template class FormatControl<
640 ExternalFormattedIoStatementState<Direction::Output>>;
641 extern template class FormatControl<
642 ExternalFormattedIoStatementState<Direction::Input>>;
643 extern template class FormatControl<
644 ChildFormattedIoStatementState<Direction::Output>>;
645 extern template class FormatControl<
646 ChildFormattedIoStatementState<Direction::Input>>;
648 class InquireUnitState : public ExternalIoStatementBase {
649 public:
650 InquireUnitState(ExternalFileUnit &unit, const char *sourceFile = nullptr,
651 int sourceLine = 0);
652 bool Inquire(InquiryKeywordHash, char *, std::size_t);
653 bool Inquire(InquiryKeywordHash, bool &);
654 bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
655 bool Inquire(InquiryKeywordHash, std::int64_t &);
658 class InquireNoUnitState : public NoUnitIoStatementState {
659 public:
660 InquireNoUnitState(const char *sourceFile = nullptr, int sourceLine = 0,
661 int badUnitNumber = -1);
662 bool Inquire(InquiryKeywordHash, char *, std::size_t);
663 bool Inquire(InquiryKeywordHash, bool &);
664 bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
665 bool Inquire(InquiryKeywordHash, std::int64_t &);
668 class InquireUnconnectedFileState : public NoUnitIoStatementState {
669 public:
670 InquireUnconnectedFileState(OwningPtr<char> &&path,
671 const char *sourceFile = nullptr, int sourceLine = 0);
672 bool Inquire(InquiryKeywordHash, char *, std::size_t);
673 bool Inquire(InquiryKeywordHash, bool &);
674 bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
675 bool Inquire(InquiryKeywordHash, std::int64_t &);
677 private:
678 OwningPtr<char> path_; // trimmed and NUL terminated
681 class InquireIOLengthState : public NoUnitIoStatementState,
682 public OutputStatementState {
683 public:
684 InquireIOLengthState(const char *sourceFile = nullptr, int sourceLine = 0);
685 std::size_t bytes() const { return bytes_; }
686 bool Emit(const char *, std::size_t bytes, std::size_t elementBytes = 0);
688 private:
689 std::size_t bytes_{0};
692 class ExternalMiscIoStatementState : public ExternalIoStatementBase {
693 public:
694 enum Which { Flush, Backspace, Endfile, Rewind, Wait };
695 ExternalMiscIoStatementState(ExternalFileUnit &unit, Which which,
696 const char *sourceFile = nullptr, int sourceLine = 0)
697 : ExternalIoStatementBase{unit, sourceFile, sourceLine}, which_{which} {}
698 void CompleteOperation();
699 int EndIoStatement();
701 private:
702 Which which_;
705 class ErroneousIoStatementState : public IoStatementBase {
706 public:
707 explicit ErroneousIoStatementState(Iostat iostat,
708 ExternalFileUnit *unit = nullptr, const char *sourceFile = nullptr,
709 int sourceLine = 0)
710 : IoStatementBase{sourceFile, sourceLine}, unit_{unit} {
711 SetPendingError(iostat);
713 int EndIoStatement();
714 ConnectionState &GetConnectionState() { return connection_; }
715 MutableModes &mutableModes() { return connection_.modes; }
717 private:
718 ConnectionState connection_;
719 ExternalFileUnit *unit_{nullptr};
722 } // namespace Fortran::runtime::io
723 #endif // FORTRAN_RUNTIME_IO_STMT_H_