xref: /llvm-project/flang/runtime/io-api-common.h (revision a8f2d185b252e9a4b5676d29194d78eaf14ed219)
1 //===-- 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_RUNTIME_IO_API_COMMON_H_
10 #define FLANG_RUNTIME_IO_API_COMMON_H_
11 
12 #include "io-stmt.h"
13 #include "terminator.h"
14 #include "unit.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 
GetOrCreateUnit(int unitNumber,Direction direction,Fortran::common::optional<bool> isUnformatted,const Terminator & terminator,Cookie & errorCookie)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>
BeginExternalListIO(int unitNumber,const char * sourceFile,int sourceLine,A &&...xs)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_RUNTIME_IO_API_COMMON_H_
98