[memprof] Use LineLocation in a unit test (NFC) (#116917)
[llvm-project.git] / flang / runtime / io-stmt.h
blob1f1419b249e5e51b7374a8517a464810b350c41d
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/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>
28 namespace Fortran::runtime::io {
30 class ExternalFileUnit;
31 class ChildIo;
33 class OpenStatementState;
34 class InquireUnitState;
35 class InquireNoUnitState;
36 class InquireUnconnectedFileState;
37 class InquireIOLengthState;
38 class ExternalMiscIoStatementState;
39 class CloseStatementState;
40 class NoopStatementState; // CLOSE or FLUSH on unknown unit
41 class ErroneousIoStatementState;
43 template <Direction, typename CHAR = char>
44 class InternalFormattedIoStatementState;
45 template <Direction> class InternalListIoStatementState;
46 template <Direction, typename CHAR = char>
47 class ExternalFormattedIoStatementState;
48 template <Direction> class ExternalListIoStatementState;
49 template <Direction> class ExternalUnformattedIoStatementState;
50 template <Direction, typename CHAR = char> class ChildFormattedIoStatementState;
51 template <Direction> class ChildListIoStatementState;
52 template <Direction> class ChildUnformattedIoStatementState;
54 struct InputStatementState {};
55 struct OutputStatementState {};
56 template <Direction D>
57 using IoDirectionState = std::conditional_t<D == Direction::Input,
58 InputStatementState, OutputStatementState>;
60 // Common state for all kinds of formatted I/O
61 template <Direction D> class FormattedIoStatementState {};
62 template <> class FormattedIoStatementState<Direction::Input> {
63 public:
64 RT_API_ATTRS std::size_t GetEditDescriptorChars() const;
65 RT_API_ATTRS void GotChar(int);
67 private:
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=)
73 // The Cookie type in the I/O API is a pointer (for C) to this class.
74 class IoStatementState {
75 public:
76 template <typename A> explicit RT_API_ATTRS IoStatementState(A &x) : u_{x} {}
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.
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();
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
116 RT_API_ATTRS MutableModes &mutableModes();
117 RT_API_ATTRS ConnectionState &GetConnectionState();
118 RT_API_ATTRS IoErrorHandler &GetIoErrorHandler() const;
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();
127 return nullptr;
129 u_);
132 // Vacant after the end of the current record
133 RT_API_ATTRS Fortran::common::optional<char32_t> GetCurrentChar(
134 std::size_t &byteCount);
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).
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;
155 SkipSpaces(remaining);
157 return remaining;
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;
168 if (remaining) {
169 if (static_cast<std::size_t>(*remaining) < byteCount) {
170 break;
172 GotChar(byteCount);
173 *remaining -= byteCount;
175 HandleRelativePosition(byteCount);
176 } else {
177 break;
180 return Fortran::common::nullopt;
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 &);
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);
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;
204 ch = GetCurrentChar(byteCount);
206 return ch;
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");
219 return false;
223 private:
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<
228 InternalFormattedIoStatementState<Direction::Output>>,
229 Fortran::common::reference_wrapper<
230 InternalFormattedIoStatementState<Direction::Input>>,
231 Fortran::common::reference_wrapper<
232 InternalListIoStatementState<Direction::Output>>,
233 Fortran::common::reference_wrapper<
234 InternalListIoStatementState<Direction::Input>>,
235 Fortran::common::reference_wrapper<
236 ExternalFormattedIoStatementState<Direction::Output>>,
237 Fortran::common::reference_wrapper<
238 ExternalFormattedIoStatementState<Direction::Input>>,
239 Fortran::common::reference_wrapper<
240 ExternalListIoStatementState<Direction::Output>>,
241 Fortran::common::reference_wrapper<
242 ExternalListIoStatementState<Direction::Input>>,
243 Fortran::common::reference_wrapper<
244 ExternalUnformattedIoStatementState<Direction::Output>>,
245 Fortran::common::reference_wrapper<
246 ExternalUnformattedIoStatementState<Direction::Input>>,
247 Fortran::common::reference_wrapper<
248 ChildFormattedIoStatementState<Direction::Output>>,
249 Fortran::common::reference_wrapper<
250 ChildFormattedIoStatementState<Direction::Input>>,
251 Fortran::common::reference_wrapper<
252 ChildListIoStatementState<Direction::Output>>,
253 Fortran::common::reference_wrapper<
254 ChildListIoStatementState<Direction::Input>>,
255 Fortran::common::reference_wrapper<
256 ChildUnformattedIoStatementState<Direction::Output>>,
257 Fortran::common::reference_wrapper<
258 ChildUnformattedIoStatementState<Direction::Input>>,
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>>
268 // Base class for all per-I/O statement state classes.
269 class IoStatementBase : public IoErrorHandler {
270 public:
271 using IoErrorHandler::IoErrorHandler;
273 RT_API_ATTRS bool completedOperation() const { return completedOperation_; }
275 RT_API_ATTRS void CompleteOperation() { completedOperation_ = true; }
276 RT_API_ATTRS int EndIoStatement() { return GetIoStat(); }
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();
300 RT_API_ATTRS void BadInquiryKeywordHashCrash(InquiryKeywordHash);
302 RT_API_ATTRS void ReportUnsupportedChildIo() const {
303 Crash("not yet implemented: child IO");
306 protected:
307 bool completedOperation_{false};
310 // Common state for list-directed & NAMELIST I/O, both internal & external
311 template <Direction> class ListDirectedStatementState;
312 template <>
313 class ListDirectedStatementState<Direction::Output>
314 : public FormattedIoStatementState<Direction::Output> {
315 public:
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_;
323 RT_API_ATTRS void set_lastWasUndelimitedCharacter(bool yes = true) {
324 lastWasUndelimitedCharacter_ = yes;
327 private:
328 bool lastWasUndelimitedCharacter_{false};
330 template <>
331 class ListDirectedStatementState<Direction::Input>
332 : public FormattedIoStatementState<Direction::Input> {
333 public:
334 RT_API_ATTRS bool inNamelistSequence() const { return inNamelistSequence_; }
335 RT_API_ATTRS int EndIoStatement();
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);
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();
352 eatComma_ = false;
353 realPart_ = imaginaryPart_ = false;
354 inNamelistSequence_ = inNamelistSequence;
357 private:
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};
367 template <Direction DIR>
368 class InternalIoStatementState : public IoStatementBase,
369 public IoDirectionState<DIR> {
370 public:
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();
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();
390 protected:
391 bool free_{true};
392 InternalDescriptorUnit<DIR> unit_;
395 template <Direction DIR, typename CHAR>
396 class InternalFormattedIoStatementState
397 : public InternalIoStatementState<DIR>,
398 public FormattedIoStatementState<DIR> {
399 public:
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);
406 RT_API_ATTRS InternalFormattedIoStatementState(const Descriptor &,
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_;
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);
420 private:
421 IoStatementState ioStatementState_; // points to *this
422 using InternalIoStatementState<DIR>::unit_;
423 // format_ *must* be last; it may be partial someday
424 FormatControl<InternalFormattedIoStatementState> format_;
427 template <Direction DIR>
428 class InternalListIoStatementState : public InternalIoStatementState<DIR>,
429 public ListDirectedStatementState<DIR> {
430 public:
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_;
440 using ListDirectedStatementState<DIR>::GetNextDataEdit;
441 RT_API_ATTRS void CompleteOperation();
442 RT_API_ATTRS int EndIoStatement();
444 private:
445 IoStatementState ioStatementState_; // points to *this
446 using InternalIoStatementState<DIR>::unit_;
449 class ExternalIoStatementBase : public IoStatementBase {
450 public:
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();
464 private:
465 ExternalFileUnit &unit_;
466 int asynchronousID_{-1};
467 bool destroy_{false};
470 template <Direction DIR>
471 class ExternalIoStatementState : public ExternalIoStatementBase,
472 public IoDirectionState<DIR> {
473 public:
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();
490 private:
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_;
497 template <Direction DIR, typename CHAR>
498 class ExternalFormattedIoStatementState
499 : public ExternalIoStatementState<DIR>,
500 public FormattedIoStatementState<DIR> {
501 public:
502 using CharType = CHAR;
503 RT_API_ATTRS ExternalFormattedIoStatementState(ExternalFileUnit &,
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);
514 private:
515 FormatControl<ExternalFormattedIoStatementState> format_;
518 template <Direction DIR>
519 class ExternalListIoStatementState : public ExternalIoStatementState<DIR>,
520 public ListDirectedStatementState<DIR> {
521 public:
522 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
523 using ListDirectedStatementState<DIR>::GetNextDataEdit;
524 RT_API_ATTRS int EndIoStatement();
527 template <Direction DIR>
528 class ExternalUnformattedIoStatementState
529 : public ExternalIoStatementState<DIR> {
530 public:
531 using ExternalIoStatementState<DIR>::ExternalIoStatementState;
532 RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
535 template <Direction DIR>
536 class ChildIoStatementState : public IoStatementBase,
537 public IoDirectionState<DIR> {
538 public:
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);
553 private:
554 ChildIo &child_;
557 template <Direction DIR, typename CHAR>
558 class ChildFormattedIoStatementState : public ChildIoStatementState<DIR>,
559 public FormattedIoStatementState<DIR> {
560 public:
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);
574 private:
575 MutableModes mutableModes_;
576 FormatControl<ChildFormattedIoStatementState> format_;
579 template <Direction DIR>
580 class ChildListIoStatementState : public ChildIoStatementState<DIR>,
581 public ListDirectedStatementState<DIR> {
582 public:
583 using ChildIoStatementState<DIR>::ChildIoStatementState;
584 using ListDirectedStatementState<DIR>::GetNextDataEdit;
585 RT_API_ATTRS int EndIoStatement();
588 template <Direction DIR>
589 class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> {
590 public:
591 using ChildIoStatementState<DIR>::ChildIoStatementState;
592 RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
595 // OPEN
596 class OpenStatementState : public ExternalIoStatementBase {
597 public:
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=
619 RT_API_ATTRS void CompleteOperation();
620 RT_API_ATTRS int EndIoStatement();
622 private:
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_;
635 class CloseStatementState : public ExternalIoStatementBase {
636 public:
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();
643 private:
644 CloseStatus status_{CloseStatus::Keep};
647 // For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit),
648 // and recoverable BACKSPACE(bad unit)
649 class NoUnitIoStatementState : public IoStatementBase {
650 public:
651 RT_API_ATTRS IoStatementState &ioStatementState() {
652 return ioStatementState_;
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();
660 protected:
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} {}
667 private:
668 IoStatementState ioStatementState_; // points to *this
669 ConnectionState connection_;
670 int badUnitNumber_;
673 class NoopStatementState : public NoUnitIoStatementState {
674 public:
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
681 extern template class InternalIoStatementState<Direction::Output>;
682 extern template class InternalIoStatementState<Direction::Input>;
683 extern template class InternalFormattedIoStatementState<Direction::Output>;
684 extern template class InternalFormattedIoStatementState<Direction::Input>;
685 extern template class InternalListIoStatementState<Direction::Output>;
686 extern template class InternalListIoStatementState<Direction::Input>;
687 extern template class ExternalIoStatementState<Direction::Output>;
688 extern template class ExternalIoStatementState<Direction::Input>;
689 extern template class ExternalFormattedIoStatementState<Direction::Output>;
690 extern template class ExternalFormattedIoStatementState<Direction::Input>;
691 extern template class ExternalListIoStatementState<Direction::Output>;
692 extern template class ExternalListIoStatementState<Direction::Input>;
693 extern template class ExternalUnformattedIoStatementState<Direction::Output>;
694 extern template class ExternalUnformattedIoStatementState<Direction::Input>;
695 extern template class ChildIoStatementState<Direction::Output>;
696 extern template class ChildIoStatementState<Direction::Input>;
697 extern template class ChildFormattedIoStatementState<Direction::Output>;
698 extern template class ChildFormattedIoStatementState<Direction::Input>;
699 extern template class ChildListIoStatementState<Direction::Output>;
700 extern template class ChildListIoStatementState<Direction::Input>;
701 extern template class ChildUnformattedIoStatementState<Direction::Output>;
702 extern template class ChildUnformattedIoStatementState<Direction::Input>;
704 extern template class FormatControl<
705 InternalFormattedIoStatementState<Direction::Output>>;
706 extern template class FormatControl<
707 InternalFormattedIoStatementState<Direction::Input>>;
708 extern template class FormatControl<
709 ExternalFormattedIoStatementState<Direction::Output>>;
710 extern template class FormatControl<
711 ExternalFormattedIoStatementState<Direction::Input>>;
712 extern template class FormatControl<
713 ChildFormattedIoStatementState<Direction::Output>>;
714 extern template class FormatControl<
715 ChildFormattedIoStatementState<Direction::Input>>;
717 class InquireUnitState : public ExternalIoStatementBase {
718 public:
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 &);
727 class InquireNoUnitState : public NoUnitIoStatementState {
728 public:
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 &);
737 class InquireUnconnectedFileState : public NoUnitIoStatementState {
738 public:
739 RT_API_ATTRS InquireUnconnectedFileState(OwningPtr<char> &&path,
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 &);
746 private:
747 OwningPtr<char> path_; // trimmed and NUL terminated
750 class InquireIOLengthState : public NoUnitIoStatementState,
751 public OutputStatementState {
752 public:
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);
759 private:
760 std::size_t bytes_{0};
763 class ExternalMiscIoStatementState : public ExternalIoStatementBase {
764 public:
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();
772 private:
773 Which which_;
776 class ErroneousIoStatementState : public IoStatementBase {
777 public:
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);
784 RT_API_ATTRS int EndIoStatement();
785 RT_API_ATTRS ConnectionState &GetConnectionState() { return connection_; }
786 RT_API_ATTRS MutableModes &mutableModes() { return connection_.modes; }
788 private:
789 ConnectionState connection_;
790 ExternalFileUnit *unit_{nullptr};
793 } // namespace Fortran::runtime::io
794 #endif // FORTRAN_RUNTIME_IO_STMT_H_