1 | //===-- lib/runtime/io-api-common.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 | #ifndef FLANG_RT_RUNTIME_IO_API_COMMON_H_ |
10 | #define FLANG_RT_RUNTIME_IO_API_COMMON_H_ |
11 | |
12 | #include "unit.h" |
13 | #include "flang-rt/runtime/io-stmt.h" |
14 | #include "flang-rt/runtime/terminator.h" |
15 | #include "flang/Common/api-attrs.h" |
16 | #include "flang/Common/optional.h" |
17 | #include "flang/Runtime/io-api.h" |
18 | |
19 | namespace Fortran::runtime::io { |
20 | |
21 | static inline RT_API_ATTRS Cookie NoopUnit(const Terminator &terminator, |
22 | int unitNumber, enum Iostat iostat = IostatOk) { |
23 | Cookie cookie{&New<NoopStatementState>{terminator}( |
24 | terminator.sourceFileName(), terminator.sourceLine(), unitNumber) |
25 | .release() |
26 | ->ioStatementState()}; |
27 | if (iostat != IostatOk) { |
28 | cookie->GetIoErrorHandler().SetPendingError(iostat); |
29 | } |
30 | return cookie; |
31 | } |
32 | |
33 | static inline RT_API_ATTRS ExternalFileUnit *GetOrCreateUnit(int unitNumber, |
34 | Direction direction, Fortran::common::optional<bool> isUnformatted, |
35 | const Terminator &terminator, Cookie &errorCookie) { |
36 | IoErrorHandler handler{terminator}; |
37 | handler.HasIoStat(); |
38 | if (ExternalFileUnit * |
39 | unit{ExternalFileUnit::LookUpOrCreateAnonymous( |
40 | unitNumber, direction, isUnformatted, handler)}) { |
41 | errorCookie = nullptr; |
42 | return unit; |
43 | } else { |
44 | auto iostat{static_cast<enum Iostat>(handler.GetIoStat())}; |
45 | errorCookie = NoopUnit(terminator, unitNumber, |
46 | iostat != IostatOk ? iostat : IostatBadUnitNumber); |
47 | return nullptr; |
48 | } |
49 | } |
50 | |
51 | template <Direction DIR, template <Direction> class STATE, typename... A> |
52 | RT_API_ATTRS Cookie BeginExternalListIO( |
53 | int unitNumber, const char *sourceFile, int sourceLine, A &&...xs) { |
54 | Terminator terminator{sourceFile, sourceLine}; |
55 | Cookie errorCookie{nullptr}; |
56 | ExternalFileUnit *unit{GetOrCreateUnit( |
57 | unitNumber, DIR, false /*!unformatted*/, terminator, errorCookie)}; |
58 | if (!unit) { |
59 | return errorCookie; |
60 | } |
61 | if (!unit->isUnformatted.has_value()) { |
62 | unit->isUnformatted = false; |
63 | } |
64 | Iostat iostat{IostatOk}; |
65 | if (*unit->isUnformatted) { |
66 | iostat = IostatFormattedIoOnUnformattedUnit; |
67 | } |
68 | if (ChildIo * child{unit->GetChildIo()}) { |
69 | if (iostat == IostatOk) { |
70 | iostat = child->CheckFormattingAndDirection(false, DIR); |
71 | } |
72 | if (iostat == IostatOk) { |
73 | return &child->BeginIoStatement<ChildListIoStatementState<DIR>>( |
74 | *child, sourceFile, sourceLine); |
75 | } else { |
76 | return &child->BeginIoStatement<ErroneousIoStatementState>( |
77 | iostat, nullptr /* no unit */, sourceFile, sourceLine); |
78 | } |
79 | } else { |
80 | if (iostat == IostatOk && unit->access == Access::Direct) { |
81 | iostat = IostatListIoOnDirectAccessUnit; |
82 | } |
83 | if (iostat == IostatOk) { |
84 | iostat = unit->SetDirection(DIR); |
85 | } |
86 | if (iostat == IostatOk) { |
87 | return &unit->BeginIoStatement<STATE<DIR>>( |
88 | terminator, std::forward<A>(xs)..., *unit, sourceFile, sourceLine); |
89 | } else { |
90 | return &unit->BeginIoStatement<ErroneousIoStatementState>( |
91 | terminator, iostat, unit, sourceFile, sourceLine); |
92 | } |
93 | } |
94 | } |
95 | |
96 | } // namespace Fortran::runtime::io |
97 | #endif // FLANG_RT_RUNTIME_IO_API_COMMON_H_ |
98 | |