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