1651f58bfSDiana Picus //===-- runtime/io-api.cpp ------------------------------------------------===//
2352d347aSAlexis Perry //
3352d347aSAlexis Perry // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4352d347aSAlexis Perry // See https://llvm.org/LICENSE.txt for license information.
5352d347aSAlexis Perry // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6352d347aSAlexis Perry //
7352d347aSAlexis Perry //===----------------------------------------------------------------------===//
8352d347aSAlexis Perry
9f7be2518Speter klausler // Implements the I/O statement API
10f7be2518Speter klausler
11830c0b90SPeter Klausler #include "flang/Runtime/io-api.h"
12cc01194cSpeter klausler #include "descriptor-io.h"
133b635714Speter klausler #include "edit-input.h"
143b635714Speter klausler #include "edit-output.h"
1595696d56Speter klausler #include "environment.h"
16352d347aSAlexis Perry #include "format.h"
17352d347aSAlexis Perry #include "io-stmt.h"
18352d347aSAlexis Perry #include "terminator.h"
1995696d56Speter klausler #include "tools.h"
20f7be2518Speter klausler #include "unit.h"
21830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
22830c0b90SPeter Klausler #include "flang/Runtime/memory.h"
23352d347aSAlexis Perry #include <cstdlib>
24352d347aSAlexis Perry #include <memory>
25352d347aSAlexis Perry
26352d347aSAlexis Perry namespace Fortran::runtime::io {
27352d347aSAlexis Perry
InquiryKeywordHashDecode(char * buffer,std::size_t n,InquiryKeywordHash hash)28675ad1bcSpeter klausler const char *InquiryKeywordHashDecode(
29675ad1bcSpeter klausler char *buffer, std::size_t n, InquiryKeywordHash hash) {
30675ad1bcSpeter klausler if (n < 1) {
31675ad1bcSpeter klausler return nullptr;
32675ad1bcSpeter klausler }
33675ad1bcSpeter klausler char *p{buffer + n};
34675ad1bcSpeter klausler *--p = '\0';
35675ad1bcSpeter klausler while (hash > 1) {
36675ad1bcSpeter klausler if (p < buffer) {
37675ad1bcSpeter klausler return nullptr;
38675ad1bcSpeter klausler }
39675ad1bcSpeter klausler *--p = 'A' + (hash % 26);
40675ad1bcSpeter klausler hash /= 26;
41675ad1bcSpeter klausler }
42675ad1bcSpeter klausler return hash == 1 ? p : nullptr;
43675ad1bcSpeter klausler }
44675ad1bcSpeter klausler
453b635714Speter klausler template <Direction DIR>
BeginInternalArrayListIO(const Descriptor & descriptor,void **,std::size_t,const char * sourceFile,int sourceLine)463b635714Speter klausler Cookie BeginInternalArrayListIO(const Descriptor &descriptor,
4795696d56Speter klausler void ** /*scratchArea*/, std::size_t /*scratchBytes*/,
4895696d56Speter klausler const char *sourceFile, int sourceLine) {
4995696d56Speter klausler Terminator oom{sourceFile, sourceLine};
5098d576c7Speter klausler return &New<InternalListIoStatementState<DIR>>{oom}(
5198d576c7Speter klausler descriptor, sourceFile, sourceLine)
5298d576c7Speter klausler .release()
5398d576c7Speter klausler ->ioStatementState();
5495696d56Speter klausler }
5595696d56Speter klausler
IONAME(BeginInternalArrayListOutput)563b635714Speter klausler Cookie IONAME(BeginInternalArrayListOutput)(const Descriptor &descriptor,
573b635714Speter klausler void **scratchArea, std::size_t scratchBytes, const char *sourceFile,
583b635714Speter klausler int sourceLine) {
593b635714Speter klausler return BeginInternalArrayListIO<Direction::Output>(
603b635714Speter klausler descriptor, scratchArea, scratchBytes, sourceFile, sourceLine);
613b635714Speter klausler }
623b635714Speter klausler
IONAME(BeginInternalArrayListInput)633b635714Speter klausler Cookie IONAME(BeginInternalArrayListInput)(const Descriptor &descriptor,
643b635714Speter klausler void **scratchArea, std::size_t scratchBytes, const char *sourceFile,
653b635714Speter klausler int sourceLine) {
663b635714Speter klausler return BeginInternalArrayListIO<Direction::Input>(
673b635714Speter klausler descriptor, scratchArea, scratchBytes, sourceFile, sourceLine);
683b635714Speter klausler }
693b635714Speter klausler
703b635714Speter klausler template <Direction DIR>
BeginInternalArrayFormattedIO(const Descriptor & descriptor,const char * format,std::size_t formatLength,void **,std::size_t,const char * sourceFile,int sourceLine)713b635714Speter klausler Cookie BeginInternalArrayFormattedIO(const Descriptor &descriptor,
7295696d56Speter klausler const char *format, std::size_t formatLength, void ** /*scratchArea*/,
7395696d56Speter klausler std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {
7495696d56Speter klausler Terminator oom{sourceFile, sourceLine};
7598d576c7Speter klausler return &New<InternalFormattedIoStatementState<DIR>>{oom}(
7698d576c7Speter klausler descriptor, format, formatLength, sourceFile, sourceLine)
7798d576c7Speter klausler .release()
7898d576c7Speter klausler ->ioStatementState();
7995696d56Speter klausler }
8095696d56Speter klausler
IONAME(BeginInternalArrayFormattedOutput)813b635714Speter klausler Cookie IONAME(BeginInternalArrayFormattedOutput)(const Descriptor &descriptor,
823b635714Speter klausler const char *format, std::size_t formatLength, void **scratchArea,
833b635714Speter klausler std::size_t scratchBytes, const char *sourceFile, int sourceLine) {
843b635714Speter klausler return BeginInternalArrayFormattedIO<Direction::Output>(descriptor, format,
853b635714Speter klausler formatLength, scratchArea, scratchBytes, sourceFile, sourceLine);
863b635714Speter klausler }
873b635714Speter klausler
IONAME(BeginInternalArrayFormattedInput)883b635714Speter klausler Cookie IONAME(BeginInternalArrayFormattedInput)(const Descriptor &descriptor,
893b635714Speter klausler const char *format, std::size_t formatLength, void **scratchArea,
903b635714Speter klausler std::size_t scratchBytes, const char *sourceFile, int sourceLine) {
913b635714Speter klausler return BeginInternalArrayFormattedIO<Direction::Input>(descriptor, format,
923b635714Speter klausler formatLength, scratchArea, scratchBytes, sourceFile, sourceLine);
933b635714Speter klausler }
943b635714Speter klausler
953b635714Speter klausler template <Direction DIR>
BeginInternalListIO(std::conditional_t<DIR==Direction::Input,const char,char> * internal,std::size_t internalLength,void **,std::size_t,const char * sourceFile,int sourceLine)96b30fa1c3Speter klausler Cookie BeginInternalListIO(
97b30fa1c3Speter klausler std::conditional_t<DIR == Direction::Input, const char, char> *internal,
98b30fa1c3Speter klausler std::size_t internalLength, void ** /*scratchArea*/,
99b30fa1c3Speter klausler std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {
100b30fa1c3Speter klausler Terminator oom{sourceFile, sourceLine};
101b30fa1c3Speter klausler return &New<InternalListIoStatementState<DIR>>{oom}(
102b30fa1c3Speter klausler internal, internalLength, sourceFile, sourceLine)
103b30fa1c3Speter klausler .release()
104b30fa1c3Speter klausler ->ioStatementState();
105b30fa1c3Speter klausler }
106b30fa1c3Speter klausler
IONAME(BeginInternalListOutput)107b30fa1c3Speter klausler Cookie IONAME(BeginInternalListOutput)(char *internal,
108b30fa1c3Speter klausler std::size_t internalLength, void **scratchArea, std::size_t scratchBytes,
109b30fa1c3Speter klausler const char *sourceFile, int sourceLine) {
110b30fa1c3Speter klausler return BeginInternalListIO<Direction::Output>(internal, internalLength,
111b30fa1c3Speter klausler scratchArea, scratchBytes, sourceFile, sourceLine);
112b30fa1c3Speter klausler }
113b30fa1c3Speter klausler
IONAME(BeginInternalListInput)114b30fa1c3Speter klausler Cookie IONAME(BeginInternalListInput)(const char *internal,
115b30fa1c3Speter klausler std::size_t internalLength, void **scratchArea, std::size_t scratchBytes,
116b30fa1c3Speter klausler const char *sourceFile, int sourceLine) {
117b30fa1c3Speter klausler return BeginInternalListIO<Direction::Input>(internal, internalLength,
118b30fa1c3Speter klausler scratchArea, scratchBytes, sourceFile, sourceLine);
119b30fa1c3Speter klausler }
120b30fa1c3Speter klausler
121b30fa1c3Speter klausler template <Direction DIR>
BeginInternalFormattedIO(std::conditional_t<DIR==Direction::Input,const char,char> * internal,std::size_t internalLength,const char * format,std::size_t formatLength,void **,std::size_t,const char * sourceFile,int sourceLine)1223b635714Speter klausler Cookie BeginInternalFormattedIO(
1233b635714Speter klausler std::conditional_t<DIR == Direction::Input, const char, char> *internal,
1243b635714Speter klausler std::size_t internalLength, const char *format, std::size_t formatLength,
1253b635714Speter klausler void ** /*scratchArea*/, std::size_t /*scratchBytes*/,
1263b635714Speter klausler const char *sourceFile, int sourceLine) {
12795696d56Speter klausler Terminator oom{sourceFile, sourceLine};
12898d576c7Speter klausler return &New<InternalFormattedIoStatementState<DIR>>{oom}(
12998d576c7Speter klausler internal, internalLength, format, formatLength, sourceFile, sourceLine)
13098d576c7Speter klausler .release()
13198d576c7Speter klausler ->ioStatementState();
13295696d56Speter klausler }
13395696d56Speter klausler
IONAME(BeginInternalFormattedOutput)134352d347aSAlexis Perry Cookie IONAME(BeginInternalFormattedOutput)(char *internal,
135352d347aSAlexis Perry std::size_t internalLength, const char *format, std::size_t formatLength,
1363b635714Speter klausler void **scratchArea, std::size_t scratchBytes, const char *sourceFile,
1373b635714Speter klausler int sourceLine) {
1383b635714Speter klausler return BeginInternalFormattedIO<Direction::Output>(internal, internalLength,
1393b635714Speter klausler format, formatLength, scratchArea, scratchBytes, sourceFile, sourceLine);
14095696d56Speter klausler }
14195696d56Speter klausler
IONAME(BeginInternalFormattedInput)1423b635714Speter klausler Cookie IONAME(BeginInternalFormattedInput)(const char *internal,
14395696d56Speter klausler std::size_t internalLength, const char *format, std::size_t formatLength,
1443b635714Speter klausler void **scratchArea, std::size_t scratchBytes, const char *sourceFile,
1453b635714Speter klausler int sourceLine) {
1463b635714Speter klausler return BeginInternalFormattedIO<Direction::Input>(internal, internalLength,
1473b635714Speter klausler format, formatLength, scratchArea, scratchBytes, sourceFile, sourceLine);
1483b635714Speter klausler }
1493b635714Speter klausler
NoopUnit(const Terminator & terminator,int unitNumber,enum Iostat iostat=IostatOk)150*c078e464SPeter Klausler static Cookie NoopUnit(const Terminator &terminator, int unitNumber,
151*c078e464SPeter Klausler enum Iostat iostat = IostatOk) {
152*c078e464SPeter Klausler Cookie cookie{&New<NoopStatementState>{terminator}(
153*c078e464SPeter Klausler terminator.sourceFileName(), terminator.sourceLine(), unitNumber)
154*c078e464SPeter Klausler .release()
155*c078e464SPeter Klausler ->ioStatementState()};
156*c078e464SPeter Klausler if (iostat != IostatOk) {
157*c078e464SPeter Klausler cookie->GetIoErrorHandler().SetPendingError(iostat);
158*c078e464SPeter Klausler }
159*c078e464SPeter Klausler return cookie;
160*c078e464SPeter Klausler }
161*c078e464SPeter Klausler
GetOrCreateUnit(int unitNumber,Direction direction,std::optional<bool> isUnformatted,const Terminator & terminator,Cookie & errorCookie)162cfbde714SPeter Klausler static ExternalFileUnit *GetOrCreateUnit(int unitNumber, Direction direction,
163cfbde714SPeter Klausler std::optional<bool> isUnformatted, const Terminator &terminator,
164cfbde714SPeter Klausler Cookie &errorCookie) {
165cfbde714SPeter Klausler if (ExternalFileUnit *
166cfbde714SPeter Klausler unit{ExternalFileUnit::LookUpOrCreateAnonymous(
167cfbde714SPeter Klausler unitNumber, direction, isUnformatted, terminator)}) {
168cfbde714SPeter Klausler errorCookie = nullptr;
169cfbde714SPeter Klausler return unit;
170cfbde714SPeter Klausler } else {
171*c078e464SPeter Klausler errorCookie = NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
172cfbde714SPeter Klausler return nullptr;
173cfbde714SPeter Klausler }
174cfbde714SPeter Klausler }
175cfbde714SPeter Klausler
1766a1c3efaSpeter klausler template <Direction DIR, template <Direction> class STATE, typename... A>
BeginExternalListIO(int unitNumber,const char * sourceFile,int sourceLine,A &&...xs)177df38f35aSPeter Klausler Cookie BeginExternalListIO(
178df38f35aSPeter Klausler int unitNumber, const char *sourceFile, int sourceLine, A &&...xs) {
1793b635714Speter klausler Terminator terminator{sourceFile, sourceLine};
1803b635714Speter klausler if (unitNumber == DefaultUnit) {
1813b635714Speter klausler unitNumber = DIR == Direction::Input ? 5 : 6;
1823b635714Speter klausler }
183cfbde714SPeter Klausler Cookie errorCookie{nullptr};
184cfbde714SPeter Klausler ExternalFileUnit *unit{GetOrCreateUnit(
185cfbde714SPeter Klausler unitNumber, DIR, false /*!unformatted*/, terminator, errorCookie)};
186cfbde714SPeter Klausler if (!unit) {
187cfbde714SPeter Klausler return errorCookie;
188cfbde714SPeter Klausler }
189cfbde714SPeter Klausler if (!unit->isUnformatted.has_value()) {
190cfbde714SPeter Klausler unit->isUnformatted = false;
191b1856009SPeter Klausler }
192df38f35aSPeter Klausler Iostat iostat{IostatOk};
193cfbde714SPeter Klausler if (*unit->isUnformatted) {
194df38f35aSPeter Klausler iostat = IostatFormattedIoOnUnformattedUnit;
195b1856009SPeter Klausler }
196cfbde714SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) {
197df38f35aSPeter Klausler if (iostat == IostatOk) {
198df38f35aSPeter Klausler iostat = child->CheckFormattingAndDirection(false, DIR);
1993b635714Speter klausler }
200df38f35aSPeter Klausler if (iostat == IostatOk) {
201df38f35aSPeter Klausler return &child->BeginIoStatement<ChildListIoStatementState<DIR>>(
202df38f35aSPeter Klausler *child, sourceFile, sourceLine);
203df38f35aSPeter Klausler } else {
204df38f35aSPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>(
20511f928afSPeter Klausler iostat, nullptr /* no unit */, sourceFile, sourceLine);
206df38f35aSPeter Klausler }
207df38f35aSPeter Klausler } else {
208cfbde714SPeter Klausler if (iostat == IostatOk && unit->access == Access::Direct) {
209df38f35aSPeter Klausler iostat = IostatListIoOnDirectAccessUnit;
210df38f35aSPeter Klausler }
211df38f35aSPeter Klausler if (iostat == IostatOk) {
212cfbde714SPeter Klausler iostat = unit->SetDirection(DIR);
213df38f35aSPeter Klausler }
214df38f35aSPeter Klausler if (iostat == IostatOk) {
215cfbde714SPeter Klausler return &unit->BeginIoStatement<STATE<DIR>>(
216cfbde714SPeter Klausler std::forward<A>(xs)..., *unit, sourceFile, sourceLine);
217df38f35aSPeter Klausler } else {
218cfbde714SPeter Klausler return &unit->BeginIoStatement<ErroneousIoStatementState>(
219cfbde714SPeter Klausler iostat, unit, sourceFile, sourceLine);
220df38f35aSPeter Klausler }
22195696d56Speter klausler }
22243fadefbSpeter klausler }
22395696d56Speter klausler
IONAME(BeginExternalListOutput)22495696d56Speter klausler Cookie IONAME(BeginExternalListOutput)(
22595696d56Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
2266a1c3efaSpeter klausler return BeginExternalListIO<Direction::Output, ExternalListIoStatementState>(
227df38f35aSPeter Klausler unitNumber, sourceFile, sourceLine);
22895696d56Speter klausler }
2293b635714Speter klausler
IONAME(BeginExternalListInput)2303b635714Speter klausler Cookie IONAME(BeginExternalListInput)(
2313b635714Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
2326a1c3efaSpeter klausler return BeginExternalListIO<Direction::Input, ExternalListIoStatementState>(
233df38f35aSPeter Klausler unitNumber, sourceFile, sourceLine);
2343b635714Speter klausler }
2353b635714Speter klausler
2363b635714Speter klausler template <Direction DIR>
BeginExternalFormattedIO(const char * format,std::size_t formatLength,ExternalUnit unitNumber,const char * sourceFile,int sourceLine)2373b635714Speter klausler Cookie BeginExternalFormattedIO(const char *format, std::size_t formatLength,
2383b635714Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
2393b635714Speter klausler Terminator terminator{sourceFile, sourceLine};
2403b635714Speter klausler if (unitNumber == DefaultUnit) {
2413b635714Speter klausler unitNumber = DIR == Direction::Input ? 5 : 6;
2423b635714Speter klausler }
243cfbde714SPeter Klausler Cookie errorCookie{nullptr};
244cfbde714SPeter Klausler ExternalFileUnit *unit{GetOrCreateUnit(
245cfbde714SPeter Klausler unitNumber, DIR, false /*!unformatted*/, terminator, errorCookie)};
246cfbde714SPeter Klausler if (!unit) {
247cfbde714SPeter Klausler return errorCookie;
248b1856009SPeter Klausler }
249cfbde714SPeter Klausler Iostat iostat{IostatOk};
250cfbde714SPeter Klausler if (!unit->isUnformatted.has_value()) {
251cfbde714SPeter Klausler unit->isUnformatted = false;
252cfbde714SPeter Klausler }
253cfbde714SPeter Klausler if (*unit->isUnformatted) {
254df38f35aSPeter Klausler iostat = IostatFormattedIoOnUnformattedUnit;
255b1856009SPeter Klausler }
256cfbde714SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) {
257df38f35aSPeter Klausler if (iostat == IostatOk) {
258df38f35aSPeter Klausler iostat = child->CheckFormattingAndDirection(false, DIR);
259df38f35aSPeter Klausler }
260df38f35aSPeter Klausler if (iostat == IostatOk) {
261df38f35aSPeter Klausler return &child->BeginIoStatement<ChildFormattedIoStatementState<DIR>>(
262df38f35aSPeter Klausler *child, format, formatLength, sourceFile, sourceLine);
26343fadefbSpeter klausler } else {
264df38f35aSPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>(
26511f928afSPeter Klausler iostat, nullptr /* no unit */, sourceFile, sourceLine);
266df38f35aSPeter Klausler }
267df38f35aSPeter Klausler } else {
268df38f35aSPeter Klausler if (iostat == IostatOk) {
269cfbde714SPeter Klausler iostat = unit->SetDirection(DIR);
270df38f35aSPeter Klausler }
271df38f35aSPeter Klausler if (iostat == IostatOk) {
272cfbde714SPeter Klausler return &unit->BeginIoStatement<ExternalFormattedIoStatementState<DIR>>(
273cfbde714SPeter Klausler *unit, format, formatLength, sourceFile, sourceLine);
274df38f35aSPeter Klausler } else {
275cfbde714SPeter Klausler return &unit->BeginIoStatement<ErroneousIoStatementState>(
276cfbde714SPeter Klausler iostat, unit, sourceFile, sourceLine);
277df38f35aSPeter Klausler }
278352d347aSAlexis Perry }
27943fadefbSpeter klausler }
280352d347aSAlexis Perry
IONAME(BeginExternalFormattedOutput)281f7be2518Speter klausler Cookie IONAME(BeginExternalFormattedOutput)(const char *format,
282f7be2518Speter klausler std::size_t formatLength, ExternalUnit unitNumber, const char *sourceFile,
283f7be2518Speter klausler int sourceLine) {
2843b635714Speter klausler return BeginExternalFormattedIO<Direction::Output>(
2853b635714Speter klausler format, formatLength, unitNumber, sourceFile, sourceLine);
28695696d56Speter klausler }
28795696d56Speter klausler
IONAME(BeginExternalFormattedInput)2883b635714Speter klausler Cookie IONAME(BeginExternalFormattedInput)(const char *format,
2893b635714Speter klausler std::size_t formatLength, ExternalUnit unitNumber, const char *sourceFile,
2903b635714Speter klausler int sourceLine) {
2913b635714Speter klausler return BeginExternalFormattedIO<Direction::Input>(
2923b635714Speter klausler format, formatLength, unitNumber, sourceFile, sourceLine);
2933b635714Speter klausler }
2943b635714Speter klausler
2953b635714Speter klausler template <Direction DIR>
BeginUnformattedIO(ExternalUnit unitNumber,const char * sourceFile,int sourceLine)2963b635714Speter klausler Cookie BeginUnformattedIO(
29795696d56Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
29895696d56Speter klausler Terminator terminator{sourceFile, sourceLine};
299cfbde714SPeter Klausler Cookie errorCookie{nullptr};
300cfbde714SPeter Klausler ExternalFileUnit *unit{GetOrCreateUnit(
301cfbde714SPeter Klausler unitNumber, DIR, true /*unformatted*/, terminator, errorCookie)};
302cfbde714SPeter Klausler if (!unit) {
303cfbde714SPeter Klausler return errorCookie;
304b1856009SPeter Klausler }
305cfbde714SPeter Klausler Iostat iostat{IostatOk};
306cfbde714SPeter Klausler if (!unit->isUnformatted.has_value()) {
307cfbde714SPeter Klausler unit->isUnformatted = true;
308cfbde714SPeter Klausler }
309cfbde714SPeter Klausler if (!*unit->isUnformatted) {
310df38f35aSPeter Klausler iostat = IostatUnformattedIoOnFormattedUnit;
311b1856009SPeter Klausler }
312cfbde714SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) {
313df38f35aSPeter Klausler if (iostat == IostatOk) {
314df38f35aSPeter Klausler iostat = child->CheckFormattingAndDirection(true, DIR);
315df38f35aSPeter Klausler }
316df38f35aSPeter Klausler if (iostat == IostatOk) {
317df38f35aSPeter Klausler return &child->BeginIoStatement<ChildUnformattedIoStatementState<DIR>>(
318df38f35aSPeter Klausler *child, sourceFile, sourceLine);
31943fadefbSpeter klausler } else {
320df38f35aSPeter Klausler return &child->BeginIoStatement<ErroneousIoStatementState>(
32111f928afSPeter Klausler iostat, nullptr /* no unit */, sourceFile, sourceLine);
322df38f35aSPeter Klausler }
323df38f35aSPeter Klausler } else {
324df38f35aSPeter Klausler if (iostat == IostatOk) {
325cfbde714SPeter Klausler iostat = unit->SetDirection(DIR);
326df38f35aSPeter Klausler }
327df38f35aSPeter Klausler if (iostat == IostatOk) {
32843fadefbSpeter klausler IoStatementState &io{
329cfbde714SPeter Klausler unit->BeginIoStatement<ExternalUnformattedIoStatementState<DIR>>(
330cfbde714SPeter Klausler *unit, sourceFile, sourceLine)};
331d879ac8aSpeter klausler if constexpr (DIR == Direction::Output) {
332cfbde714SPeter Klausler if (unit->access == Access::Sequential) {
3333b635714Speter klausler // Create space for (sub)record header to be completed by
334b03628d9Speter klausler // ExternalFileUnit::AdvanceRecord()
335cfbde714SPeter Klausler unit->recordLength.reset(); // in case of prior BACKSPACE
33695696d56Speter klausler io.Emit("\0\0\0\0", 4); // placeholder for record length header
33795696d56Speter klausler }
3383b635714Speter klausler }
33995696d56Speter klausler return &io;
340df38f35aSPeter Klausler } else {
341cfbde714SPeter Klausler return &unit->BeginIoStatement<ErroneousIoStatementState>(
342cfbde714SPeter Klausler iostat, unit, sourceFile, sourceLine);
343df38f35aSPeter Klausler }
34495696d56Speter klausler }
34543fadefbSpeter klausler }
34695696d56Speter klausler
IONAME(BeginUnformattedOutput)3473b635714Speter klausler Cookie IONAME(BeginUnformattedOutput)(
3483b635714Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
3493b635714Speter klausler return BeginUnformattedIO<Direction::Output>(
3503b635714Speter klausler unitNumber, sourceFile, sourceLine);
3513b635714Speter klausler }
3523b635714Speter klausler
IONAME(BeginUnformattedInput)3533b635714Speter klausler Cookie IONAME(BeginUnformattedInput)(
3543b635714Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
3553b635714Speter klausler return BeginUnformattedIO<Direction::Input>(
3563b635714Speter klausler unitNumber, sourceFile, sourceLine);
3573b635714Speter klausler }
3583b635714Speter klausler
IONAME(BeginOpenUnit)35995696d56Speter klausler Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=)
36095696d56Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
3613b635714Speter klausler Terminator terminator{sourceFile, sourceLine};
362cfbde714SPeter Klausler bool wasExtant{false};
363cfbde714SPeter Klausler if (ExternalFileUnit *
364cfbde714SPeter Klausler unit{ExternalFileUnit::LookUpOrCreate(
365cfbde714SPeter Klausler unitNumber, terminator, wasExtant)}) {
366cfbde714SPeter Klausler return &unit->BeginIoStatement<OpenStatementState>(
367cfbde714SPeter Klausler *unit, wasExtant, sourceFile, sourceLine);
368cfbde714SPeter Klausler } else {
369*c078e464SPeter Klausler return NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
370cfbde714SPeter Klausler }
37195696d56Speter klausler }
37295696d56Speter klausler
IONAME(BeginOpenNewUnit)37395696d56Speter klausler Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j)
37495696d56Speter klausler const char *sourceFile, int sourceLine) {
3753b635714Speter klausler Terminator terminator{sourceFile, sourceLine};
376c7f4c333SPeter Klausler ExternalFileUnit &unit{
377c7f4c333SPeter Klausler ExternalFileUnit::NewUnit(terminator, false /*not child I/O*/)};
3785d5b9682Speter klausler return &unit.BeginIoStatement<OpenStatementState>(
379bd43fa29Speter klausler unit, false /*was an existing file*/, sourceFile, sourceLine);
38095696d56Speter klausler }
38195696d56Speter klausler
IONAME(BeginWait)382166d6ed5SPeter Klausler Cookie IONAME(BeginWait)(ExternalUnit unitNumber, AsynchronousId id,
383166d6ed5SPeter Klausler const char *sourceFile, int sourceLine) {
384166d6ed5SPeter Klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
385166d6ed5SPeter Klausler if (unit->Wait(id)) {
386166d6ed5SPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
387166d6ed5SPeter Klausler *unit, ExternalMiscIoStatementState::Wait, sourceFile, sourceLine);
388166d6ed5SPeter Klausler } else {
389166d6ed5SPeter Klausler return &unit->BeginIoStatement<ErroneousIoStatementState>(
390166d6ed5SPeter Klausler IostatBadWaitId, unit, sourceFile, sourceLine);
391166d6ed5SPeter Klausler }
392166d6ed5SPeter Klausler } else {
393*c078e464SPeter Klausler Terminator terminator{sourceFile, sourceLine};
394*c078e464SPeter Klausler return NoopUnit(
395*c078e464SPeter Klausler terminator, unitNumber, id == 0 ? IostatOk : IostatBadWaitUnit);
396deb62f5aSPeter Klausler }
397166d6ed5SPeter Klausler }
IONAME(BeginWaitAll)398166d6ed5SPeter Klausler Cookie IONAME(BeginWaitAll)(
399166d6ed5SPeter Klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
40017853928SPeter Klausler return IONAME(BeginWait)(unitNumber, 0 /*no ID=*/, sourceFile, sourceLine);
401deb62f5aSPeter Klausler }
402deb62f5aSPeter Klausler
IONAME(BeginClose)40395696d56Speter klausler Cookie IONAME(BeginClose)(
40495696d56Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
4053b635714Speter klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUpForClose(unitNumber)}) {
40695696d56Speter klausler return &unit->BeginIoStatement<CloseStatementState>(
40795696d56Speter klausler *unit, sourceFile, sourceLine);
40895696d56Speter klausler } else {
40995696d56Speter klausler // CLOSE(UNIT=bad unit) is just a no-op
410*c078e464SPeter Klausler Terminator terminator{sourceFile, sourceLine};
411*c078e464SPeter Klausler return NoopUnit(terminator, unitNumber);
41295696d56Speter klausler }
41395696d56Speter klausler }
41495696d56Speter klausler
IONAME(BeginFlush)4155d5b9682Speter klausler Cookie IONAME(BeginFlush)(
4165d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
4179ddd0792SPeter Klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
4189ddd0792SPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
4199ddd0792SPeter Klausler *unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine);
4209ddd0792SPeter Klausler } else {
421*c078e464SPeter Klausler // FLUSH(UNIT=bad unit) is an error; an unconnected unit is a no-op
422*c078e464SPeter Klausler Terminator terminator{sourceFile, sourceLine};
423*c078e464SPeter Klausler return NoopUnit(terminator, unitNumber,
424*c078e464SPeter Klausler unitNumber >= 0 ? IostatOk : IostatBadFlushUnit);
4259ddd0792SPeter Klausler }
4265d5b9682Speter klausler }
4275d5b9682Speter klausler
IONAME(BeginBackspace)4285d5b9682Speter klausler Cookie IONAME(BeginBackspace)(
4295d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
4305d5b9682Speter klausler Terminator terminator{sourceFile, sourceLine};
431142db43bSPeter Klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
432142db43bSPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
433142db43bSPeter Klausler *unit, ExternalMiscIoStatementState::Backspace, sourceFile, sourceLine);
434142db43bSPeter Klausler } else {
435*c078e464SPeter Klausler return NoopUnit(terminator, unitNumber, IostatBadBackspaceUnit);
436142db43bSPeter Klausler }
4375d5b9682Speter klausler }
4385d5b9682Speter klausler
IONAME(BeginEndfile)4395d5b9682Speter klausler Cookie IONAME(BeginEndfile)(
4405d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
4415d5b9682Speter klausler Terminator terminator{sourceFile, sourceLine};
442cfbde714SPeter Klausler Cookie errorCookie{nullptr};
443cfbde714SPeter Klausler if (ExternalFileUnit *
444cfbde714SPeter Klausler unit{GetOrCreateUnit(unitNumber, Direction::Output, std::nullopt,
445cfbde714SPeter Klausler terminator, errorCookie)}) {
446cfbde714SPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
447cfbde714SPeter Klausler *unit, ExternalMiscIoStatementState::Endfile, sourceFile, sourceLine);
448cfbde714SPeter Klausler } else {
449cfbde714SPeter Klausler return errorCookie;
450cfbde714SPeter Klausler }
4515d5b9682Speter klausler }
4525d5b9682Speter klausler
IONAME(BeginRewind)4535d5b9682Speter klausler Cookie IONAME(BeginRewind)(
4545d5b9682Speter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
4555d5b9682Speter klausler Terminator terminator{sourceFile, sourceLine};
456cfbde714SPeter Klausler Cookie errorCookie{nullptr};
457cfbde714SPeter Klausler if (ExternalFileUnit *
458cfbde714SPeter Klausler unit{GetOrCreateUnit(unitNumber, Direction::Input, std::nullopt,
459cfbde714SPeter Klausler terminator, errorCookie)}) {
460cfbde714SPeter Klausler return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
461cfbde714SPeter Klausler *unit, ExternalMiscIoStatementState::Rewind, sourceFile, sourceLine);
462cfbde714SPeter Klausler } else {
463cfbde714SPeter Klausler return errorCookie;
464cfbde714SPeter Klausler }
4655d5b9682Speter klausler }
4665d5b9682Speter klausler
IONAME(BeginInquireUnit)467675ad1bcSpeter klausler Cookie IONAME(BeginInquireUnit)(
468675ad1bcSpeter klausler ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
469675ad1bcSpeter klausler if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
470b1856009SPeter Klausler if (ChildIo * child{unit->GetChildIo()}) {
471b1856009SPeter Klausler return &child->BeginIoStatement<InquireUnitState>(
472b1856009SPeter Klausler *unit, sourceFile, sourceLine);
473b1856009SPeter Klausler } else {
474675ad1bcSpeter klausler return &unit->BeginIoStatement<InquireUnitState>(
475675ad1bcSpeter klausler *unit, sourceFile, sourceLine);
476b1856009SPeter Klausler }
477675ad1bcSpeter klausler } else {
478675ad1bcSpeter klausler // INQUIRE(UNIT=unrecognized unit)
479675ad1bcSpeter klausler Terminator oom{sourceFile, sourceLine};
480d90e866aSPeter Klausler return &New<InquireNoUnitState>{oom}(sourceFile, sourceLine, unitNumber)
481675ad1bcSpeter klausler .release()
482675ad1bcSpeter klausler ->ioStatementState();
483675ad1bcSpeter klausler }
484675ad1bcSpeter klausler }
485675ad1bcSpeter klausler
IONAME(BeginInquireFile)486675ad1bcSpeter klausler Cookie IONAME(BeginInquireFile)(const char *path, std::size_t pathLength,
487675ad1bcSpeter klausler const char *sourceFile, int sourceLine) {
488675ad1bcSpeter klausler Terminator oom{sourceFile, sourceLine};
489675ad1bcSpeter klausler auto trimmed{
490675ad1bcSpeter klausler SaveDefaultCharacter(path, TrimTrailingSpaces(path, pathLength), oom)};
49103c066abSPeter Klausler if (ExternalFileUnit *
49203c066abSPeter Klausler unit{ExternalFileUnit::LookUp(
49303c066abSPeter Klausler trimmed.get(), std::strlen(trimmed.get()))}) {
494675ad1bcSpeter klausler // INQUIRE(FILE=) to a connected unit
495675ad1bcSpeter klausler return &unit->BeginIoStatement<InquireUnitState>(
496675ad1bcSpeter klausler *unit, sourceFile, sourceLine);
497675ad1bcSpeter klausler } else {
498675ad1bcSpeter klausler return &New<InquireUnconnectedFileState>{oom}(
499675ad1bcSpeter klausler std::move(trimmed), sourceFile, sourceLine)
500675ad1bcSpeter klausler .release()
501675ad1bcSpeter klausler ->ioStatementState();
502675ad1bcSpeter klausler }
503675ad1bcSpeter klausler }
504675ad1bcSpeter klausler
IONAME(BeginInquireIoLength)505675ad1bcSpeter klausler Cookie IONAME(BeginInquireIoLength)(const char *sourceFile, int sourceLine) {
506675ad1bcSpeter klausler Terminator oom{sourceFile, sourceLine};
507675ad1bcSpeter klausler return &New<InquireIOLengthState>{oom}(sourceFile, sourceLine)
508675ad1bcSpeter klausler .release()
509675ad1bcSpeter klausler ->ioStatementState();
510675ad1bcSpeter klausler }
511675ad1bcSpeter klausler
51295696d56Speter klausler // Control list items
51395696d56Speter klausler
IONAME(EnableHandlers)5143b635714Speter klausler void IONAME(EnableHandlers)(Cookie cookie, bool hasIoStat, bool hasErr,
5153b635714Speter klausler bool hasEnd, bool hasEor, bool hasIoMsg) {
51695696d56Speter klausler IoErrorHandler &handler{cookie->GetIoErrorHandler()};
51795696d56Speter klausler if (hasIoStat) {
51895696d56Speter klausler handler.HasIoStat();
51995696d56Speter klausler }
52095696d56Speter klausler if (hasErr) {
52195696d56Speter klausler handler.HasErrLabel();
52295696d56Speter klausler }
52395696d56Speter klausler if (hasEnd) {
52495696d56Speter klausler handler.HasEndLabel();
52595696d56Speter klausler }
52695696d56Speter klausler if (hasEor) {
52795696d56Speter klausler handler.HasEorLabel();
52895696d56Speter klausler }
5293b635714Speter klausler if (hasIoMsg) {
5303b635714Speter klausler handler.HasIoMsg();
5313b635714Speter klausler }
53295696d56Speter klausler }
53395696d56Speter klausler
YesOrNo(const char * keyword,std::size_t length,const char * what,IoErrorHandler & handler)53495696d56Speter klausler static bool YesOrNo(const char *keyword, std::size_t length, const char *what,
5353b635714Speter klausler IoErrorHandler &handler) {
53695696d56Speter klausler static const char *keywords[]{"YES", "NO", nullptr};
53795696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
5381f879005STim Keith case 0:
5391f879005STim Keith return true;
5401f879005STim Keith case 1:
5411f879005STim Keith return false;
54295696d56Speter klausler default:
5433b635714Speter klausler handler.SignalError(IostatErrorInKeyword, "Invalid %s='%.*s'", what,
5443b635714Speter klausler static_cast<int>(length), keyword);
54595696d56Speter klausler return false;
54695696d56Speter klausler }
54795696d56Speter klausler }
54895696d56Speter klausler
IONAME(SetAdvance)54995696d56Speter klausler bool IONAME(SetAdvance)(
55095696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) {
55195696d56Speter klausler IoStatementState &io{*cookie};
552deb62f5aSPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
553deb62f5aSPeter Klausler bool nonAdvancing{!YesOrNo(keyword, length, "ADVANCE", handler)};
554cd0a1226Speter klausler if (nonAdvancing && io.GetConnectionState().access == Access::Direct) {
555deb62f5aSPeter Klausler handler.SignalError("Non-advancing I/O attempted on direct access file");
556cd0a1226Speter klausler } else {
557cd0a1226Speter klausler io.mutableModes().nonAdvancing = nonAdvancing;
5583b635714Speter klausler }
559deb62f5aSPeter Klausler return !handler.InError();
56095696d56Speter klausler }
56195696d56Speter klausler
IONAME(SetBlank)56295696d56Speter klausler bool IONAME(SetBlank)(Cookie cookie, const char *keyword, std::size_t length) {
56395696d56Speter klausler IoStatementState &io{*cookie};
56495696d56Speter klausler static const char *keywords[]{"NULL", "ZERO", nullptr};
56595696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
5661f879005STim Keith case 0:
5672b0b9b2eSPeter Klausler io.mutableModes().editingFlags &= ~blankZero;
5681f879005STim Keith return true;
5691f879005STim Keith case 1:
5702b0b9b2eSPeter Klausler io.mutableModes().editingFlags |= blankZero;
5711f879005STim Keith return true;
57295696d56Speter klausler default:
5733b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
57495696d56Speter klausler "Invalid BLANK='%.*s'", static_cast<int>(length), keyword);
57595696d56Speter klausler return false;
57695696d56Speter klausler }
57795696d56Speter klausler }
57895696d56Speter klausler
IONAME(SetDecimal)57995696d56Speter klausler bool IONAME(SetDecimal)(
58095696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) {
58195696d56Speter klausler IoStatementState &io{*cookie};
58295696d56Speter klausler static const char *keywords[]{"COMMA", "POINT", nullptr};
58395696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
5841f879005STim Keith case 0:
5852b0b9b2eSPeter Klausler io.mutableModes().editingFlags |= decimalComma;
5861f879005STim Keith return true;
5871f879005STim Keith case 1:
5882b0b9b2eSPeter Klausler io.mutableModes().editingFlags &= ~decimalComma;
5891f879005STim Keith return true;
59095696d56Speter klausler default:
5913b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
59295696d56Speter klausler "Invalid DECIMAL='%.*s'", static_cast<int>(length), keyword);
59395696d56Speter klausler return false;
59495696d56Speter klausler }
59595696d56Speter klausler }
59695696d56Speter klausler
IONAME(SetDelim)59795696d56Speter klausler bool IONAME(SetDelim)(Cookie cookie, const char *keyword, std::size_t length) {
59895696d56Speter klausler IoStatementState &io{*cookie};
59995696d56Speter klausler static const char *keywords[]{"APOSTROPHE", "QUOTE", "NONE", nullptr};
60095696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
6011f879005STim Keith case 0:
6022b0b9b2eSPeter Klausler io.mutableModes().delim = '\'';
6031f879005STim Keith return true;
6041f879005STim Keith case 1:
6052b0b9b2eSPeter Klausler io.mutableModes().delim = '"';
6061f879005STim Keith return true;
6071f879005STim Keith case 2:
6082b0b9b2eSPeter Klausler io.mutableModes().delim = '\0';
6091f879005STim Keith return true;
61095696d56Speter klausler default:
6113b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
61295696d56Speter klausler "Invalid DELIM='%.*s'", static_cast<int>(length), keyword);
61395696d56Speter klausler return false;
61495696d56Speter klausler }
61595696d56Speter klausler }
61695696d56Speter klausler
IONAME(SetPad)61795696d56Speter klausler bool IONAME(SetPad)(Cookie cookie, const char *keyword, std::size_t length) {
61895696d56Speter klausler IoStatementState &io{*cookie};
619deb62f5aSPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
620deb62f5aSPeter Klausler io.mutableModes().pad = YesOrNo(keyword, length, "PAD", handler);
621deb62f5aSPeter Klausler return !handler.InError();
62295696d56Speter klausler }
62395696d56Speter klausler
IONAME(SetPos)6243b635714Speter klausler bool IONAME(SetPos)(Cookie cookie, std::int64_t pos) {
6253b635714Speter klausler IoStatementState &io{*cookie};
626991696c2SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
6273b635714Speter klausler if (auto *unit{io.GetExternalFileUnit()}) {
628d771245aSPeter Klausler return unit->SetStreamPos(pos, handler);
6292a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
630d771245aSPeter Klausler handler.Crash("SetPos() called on internal unit");
6312a07db4cSPeter Klausler }
6323b635714Speter klausler return false;
6333b635714Speter klausler }
6343b635714Speter klausler
IONAME(SetRec)6353b635714Speter klausler bool IONAME(SetRec)(Cookie cookie, std::int64_t rec) {
6363b635714Speter klausler IoStatementState &io{*cookie};
637991696c2SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
6383b635714Speter klausler if (auto *unit{io.GetExternalFileUnit()}) {
639d771245aSPeter Klausler unit->SetDirectRec(rec, handler);
640d771245aSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
641d771245aSPeter Klausler handler.Crash("SetRec() called on internal unit");
6423b635714Speter klausler }
6433b635714Speter klausler return true;
6443b635714Speter klausler }
64595696d56Speter klausler
IONAME(SetRound)64695696d56Speter klausler bool IONAME(SetRound)(Cookie cookie, const char *keyword, std::size_t length) {
64795696d56Speter klausler IoStatementState &io{*cookie};
64895696d56Speter klausler static const char *keywords[]{"UP", "DOWN", "ZERO", "NEAREST", "COMPATIBLE",
64995696d56Speter klausler "PROCESSOR_DEFINED", nullptr};
65095696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
6511f879005STim Keith case 0:
6522b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundUp;
6531f879005STim Keith return true;
6541f879005STim Keith case 1:
6552b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundDown;
6561f879005STim Keith return true;
6571f879005STim Keith case 2:
6582b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundToZero;
6591f879005STim Keith return true;
6601f879005STim Keith case 3:
6612b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundNearest;
6621f879005STim Keith return true;
6631f879005STim Keith case 4:
6642b0b9b2eSPeter Klausler io.mutableModes().round = decimal::RoundCompatible;
6651f879005STim Keith return true;
66695696d56Speter klausler case 5:
6672b0b9b2eSPeter Klausler io.mutableModes().round = executionEnvironment.defaultOutputRoundingMode;
66895696d56Speter klausler return true;
66995696d56Speter klausler default:
6703b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
67195696d56Speter klausler "Invalid ROUND='%.*s'", static_cast<int>(length), keyword);
67295696d56Speter klausler return false;
67395696d56Speter klausler }
67495696d56Speter klausler }
67595696d56Speter klausler
IONAME(SetSign)67695696d56Speter klausler bool IONAME(SetSign)(Cookie cookie, const char *keyword, std::size_t length) {
67795696d56Speter klausler IoStatementState &io{*cookie};
6785501c16eSPeter Klausler static const char *keywords[]{
6795501c16eSPeter Klausler "PLUS", "SUPPRESS", "PROCESSOR_DEFINED", nullptr};
68095696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
6811f879005STim Keith case 0:
6822b0b9b2eSPeter Klausler io.mutableModes().editingFlags |= signPlus;
6831f879005STim Keith return true;
68495696d56Speter klausler case 1:
68595696d56Speter klausler case 2: // processor default is SS
6862b0b9b2eSPeter Klausler io.mutableModes().editingFlags &= ~signPlus;
68795696d56Speter klausler return true;
68895696d56Speter klausler default:
6893b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
69095696d56Speter klausler "Invalid SIGN='%.*s'", static_cast<int>(length), keyword);
69195696d56Speter klausler return false;
69295696d56Speter klausler }
69395696d56Speter klausler }
69495696d56Speter klausler
IONAME(SetAccess)69595696d56Speter klausler bool IONAME(SetAccess)(Cookie cookie, const char *keyword, std::size_t length) {
69695696d56Speter klausler IoStatementState &io{*cookie};
69795696d56Speter klausler auto *open{io.get_if<OpenStatementState>()};
69895696d56Speter klausler if (!open) {
6992a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
70095696d56Speter klausler io.GetIoErrorHandler().Crash(
70195696d56Speter klausler "SetAccess() called when not in an OPEN statement");
7022a07db4cSPeter Klausler }
7032a07db4cSPeter Klausler return false;
7048db4dc86SPeter Klausler } else if (open->completedOperation()) {
7058db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
7068db4dc86SPeter Klausler "SetAccess() called after GetNewUnit() for an OPEN statement");
70795696d56Speter klausler }
70872abc199Speter klausler static const char *keywords[]{
70972abc199Speter klausler "SEQUENTIAL", "DIRECT", "STREAM", "APPEND", nullptr};
71095696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
7111f879005STim Keith case 0:
712675ad1bcSpeter klausler open->set_access(Access::Sequential);
7131f879005STim Keith break;
7141f879005STim Keith case 1:
715675ad1bcSpeter klausler open->set_access(Access::Direct);
7161f879005STim Keith break;
7171f879005STim Keith case 2:
718675ad1bcSpeter klausler open->set_access(Access::Stream);
7191f879005STim Keith break;
72072abc199Speter klausler case 3: // Sun Fortran extension ACCESS=APPEND: treat as if POSITION=APPEND
72172abc199Speter klausler open->set_position(Position::Append);
72272abc199Speter klausler break;
72395696d56Speter klausler default:
7243b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid ACCESS='%.*s'",
7253b635714Speter klausler static_cast<int>(length), keyword);
72695696d56Speter klausler }
72795696d56Speter klausler return true;
72895696d56Speter klausler }
72995696d56Speter klausler
IONAME(SetAction)73095696d56Speter klausler bool IONAME(SetAction)(Cookie cookie, const char *keyword, std::size_t length) {
73195696d56Speter klausler IoStatementState &io{*cookie};
73295696d56Speter klausler auto *open{io.get_if<OpenStatementState>()};
73395696d56Speter klausler if (!open) {
7342a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
73595696d56Speter klausler io.GetIoErrorHandler().Crash(
73695696d56Speter klausler "SetAction() called when not in an OPEN statement");
7372a07db4cSPeter Klausler }
7382a07db4cSPeter Klausler return false;
7398db4dc86SPeter Klausler } else if (open->completedOperation()) {
7408db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
7418db4dc86SPeter Klausler "SetAction() called after GetNewUnit() for an OPEN statement");
74295696d56Speter klausler }
743ea4758a1Speter klausler std::optional<Action> action;
74495696d56Speter klausler static const char *keywords[]{"READ", "WRITE", "READWRITE", nullptr};
74595696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
7461f879005STim Keith case 0:
747ea4758a1Speter klausler action = Action::Read;
7481f879005STim Keith break;
7491f879005STim Keith case 1:
750ea4758a1Speter klausler action = Action::Write;
7511f879005STim Keith break;
7521f879005STim Keith case 2:
753ea4758a1Speter klausler action = Action::ReadWrite;
7541f879005STim Keith break;
75595696d56Speter klausler default:
7563b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid ACTION='%.*s'",
7573b635714Speter klausler static_cast<int>(length), keyword);
75895696d56Speter klausler return false;
75995696d56Speter klausler }
760ea4758a1Speter klausler RUNTIME_CHECK(io.GetIoErrorHandler(), action.has_value());
76195696d56Speter klausler if (open->wasExtant()) {
762ea4758a1Speter klausler if ((*action != Action::Write) != open->unit().mayRead() ||
763ea4758a1Speter klausler (*action != Action::Read) != open->unit().mayWrite()) {
7643b635714Speter klausler open->SignalError("ACTION= may not be changed on an open unit");
76595696d56Speter klausler }
76695696d56Speter klausler }
767ea4758a1Speter klausler open->set_action(*action);
76895696d56Speter klausler return true;
76995696d56Speter klausler }
77095696d56Speter klausler
IONAME(SetAsynchronous)77195696d56Speter klausler bool IONAME(SetAsynchronous)(
77295696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) {
77395696d56Speter klausler IoStatementState &io{*cookie};
774deb62f5aSPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
775deb62f5aSPeter Klausler bool isYes{YesOrNo(keyword, length, "ASYNCHRONOUS", handler)};
776deb62f5aSPeter Klausler if (auto *open{io.get_if<OpenStatementState>()}) {
777deb62f5aSPeter Klausler if (open->completedOperation()) {
778deb62f5aSPeter Klausler handler.Crash(
7798db4dc86SPeter Klausler "SetAsynchronous() called after GetNewUnit() for an OPEN statement");
78095696d56Speter klausler }
781deb62f5aSPeter Klausler open->unit().set_mayAsynchronous(isYes);
782166d6ed5SPeter Klausler } else if (auto *ext{io.get_if<ExternalIoStatementBase>()}) {
783166d6ed5SPeter Klausler if (isYes) {
784166d6ed5SPeter Klausler if (ext->unit().mayAsynchronous()) {
785166d6ed5SPeter Klausler ext->SetAsynchronous();
786166d6ed5SPeter Klausler } else {
787deb62f5aSPeter Klausler handler.SignalError(IostatBadAsynchronous);
78895696d56Speter klausler }
789166d6ed5SPeter Klausler }
7902a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
791deb62f5aSPeter Klausler handler.Crash("SetAsynchronous() called when not in an OPEN or external "
792deb62f5aSPeter Klausler "I/O statement");
793deb62f5aSPeter Klausler }
794deb62f5aSPeter Klausler return !handler.InError();
79595696d56Speter klausler }
79695696d56Speter klausler
IONAME(SetCarriagecontrol)797c9637577Speter klausler bool IONAME(SetCarriagecontrol)(
798c9637577Speter klausler Cookie cookie, const char *keyword, std::size_t length) {
799c9637577Speter klausler IoStatementState &io{*cookie};
800c9637577Speter klausler auto *open{io.get_if<OpenStatementState>()};
801c9637577Speter klausler if (!open) {
8022a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
803c9637577Speter klausler io.GetIoErrorHandler().Crash(
804c9637577Speter klausler "SetCarriageControl() called when not in an OPEN statement");
8052a07db4cSPeter Klausler }
8062a07db4cSPeter Klausler return false;
8078db4dc86SPeter Klausler } else if (open->completedOperation()) {
8088db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
8098db4dc86SPeter Klausler "SetCarriageControl() called after GetNewUnit() for an OPEN statement");
810c9637577Speter klausler }
811c9637577Speter klausler static const char *keywords[]{"LIST", "FORTRAN", "NONE", nullptr};
812c9637577Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
813c9637577Speter klausler case 0:
814c9637577Speter klausler return true;
815c9637577Speter klausler case 1:
816c9637577Speter klausler case 2:
817c9637577Speter klausler open->SignalError(IostatErrorInKeyword,
818c9637577Speter klausler "Unimplemented CARRIAGECONTROL='%.*s'", static_cast<int>(length),
819c9637577Speter klausler keyword);
820c9637577Speter klausler return false;
821c9637577Speter klausler default:
822c9637577Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid CARRIAGECONTROL='%.*s'",
823c9637577Speter klausler static_cast<int>(length), keyword);
824c9637577Speter klausler return false;
825c9637577Speter klausler }
826c9637577Speter klausler }
827c9637577Speter klausler
IONAME(SetConvert)8288f2c5c43Speter klausler bool IONAME(SetConvert)(
8298f2c5c43Speter klausler Cookie cookie, const char *keyword, std::size_t length) {
8308f2c5c43Speter klausler IoStatementState &io{*cookie};
8318f2c5c43Speter klausler auto *open{io.get_if<OpenStatementState>()};
8328f2c5c43Speter klausler if (!open) {
8332a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
8348f2c5c43Speter klausler io.GetIoErrorHandler().Crash(
8358f2c5c43Speter klausler "SetConvert() called when not in an OPEN statement");
8362a07db4cSPeter Klausler }
8372a07db4cSPeter Klausler return false;
8388db4dc86SPeter Klausler } else if (open->completedOperation()) {
8398db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
8408db4dc86SPeter Klausler "SetConvert() called after GetNewUnit() for an OPEN statement");
8418f2c5c43Speter klausler }
8428f2c5c43Speter klausler if (auto convert{GetConvertFromString(keyword, length)}) {
8438f2c5c43Speter klausler open->set_convert(*convert);
8448f2c5c43Speter klausler return true;
8458f2c5c43Speter klausler } else {
8468f2c5c43Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid CONVERT='%.*s'",
8478f2c5c43Speter klausler static_cast<int>(length), keyword);
8488f2c5c43Speter klausler return false;
8498f2c5c43Speter klausler }
8508f2c5c43Speter klausler }
8518f2c5c43Speter klausler
IONAME(SetEncoding)85295696d56Speter klausler bool IONAME(SetEncoding)(
85395696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) {
85495696d56Speter klausler IoStatementState &io{*cookie};
85595696d56Speter klausler auto *open{io.get_if<OpenStatementState>()};
85695696d56Speter klausler if (!open) {
8572a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
85895696d56Speter klausler io.GetIoErrorHandler().Crash(
85995696d56Speter klausler "SetEncoding() called when not in an OPEN statement");
8602a07db4cSPeter Klausler }
8612a07db4cSPeter Klausler return false;
8628db4dc86SPeter Klausler } else if (open->completedOperation()) {
8638db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
8648db4dc86SPeter Klausler "SetEncoding() called after GetNewUnit() for an OPEN statement");
86595696d56Speter klausler }
86695696d56Speter klausler bool isUTF8{false};
86795696d56Speter klausler static const char *keywords[]{"UTF-8", "DEFAULT", nullptr};
86895696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
8691f879005STim Keith case 0:
8701f879005STim Keith isUTF8 = true;
8711f879005STim Keith break;
8721f879005STim Keith case 1:
8731f879005STim Keith isUTF8 = false;
8741f879005STim Keith break;
87595696d56Speter klausler default:
8763b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid ENCODING='%.*s'",
8773b635714Speter klausler static_cast<int>(length), keyword);
87895696d56Speter klausler }
87995696d56Speter klausler if (isUTF8 != open->unit().isUTF8) {
88095696d56Speter klausler if (open->wasExtant()) {
8813b635714Speter klausler open->SignalError("ENCODING= may not be changed on an open unit");
88295696d56Speter klausler }
88395696d56Speter klausler open->unit().isUTF8 = isUTF8;
88495696d56Speter klausler }
88595696d56Speter klausler return true;
88695696d56Speter klausler }
88795696d56Speter klausler
IONAME(SetForm)88895696d56Speter klausler bool IONAME(SetForm)(Cookie cookie, const char *keyword, std::size_t length) {
88995696d56Speter klausler IoStatementState &io{*cookie};
89095696d56Speter klausler auto *open{io.get_if<OpenStatementState>()};
89195696d56Speter klausler if (!open) {
8922a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
89395696d56Speter klausler io.GetIoErrorHandler().Crash(
894c9637577Speter klausler "SetForm() called when not in an OPEN statement");
8952a07db4cSPeter Klausler }
8968db4dc86SPeter Klausler } else if (open->completedOperation()) {
8978db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
8988db4dc86SPeter Klausler "SetForm() called after GetNewUnit() for an OPEN statement");
89995696d56Speter klausler }
90095696d56Speter klausler static const char *keywords[]{"FORMATTED", "UNFORMATTED", nullptr};
90195696d56Speter klausler switch (IdentifyValue(keyword, length, keywords)) {
9021f879005STim Keith case 0:
903675ad1bcSpeter klausler open->set_isUnformatted(false);
9041f879005STim Keith break;
9051f879005STim Keith case 1:
906675ad1bcSpeter klausler open->set_isUnformatted(true);
9071f879005STim Keith break;
90895696d56Speter klausler default:
9093b635714Speter klausler open->SignalError(IostatErrorInKeyword, "Invalid FORM='%.*s'",
9103b635714Speter klausler static_cast<int>(length), keyword);
91195696d56Speter klausler }
91295696d56Speter klausler return true;
91395696d56Speter klausler }
91495696d56Speter klausler
IONAME(SetPosition)91595696d56Speter klausler bool IONAME(SetPosition)(
91695696d56Speter klausler Cookie cookie, const char *keyword, std::size_t length) {
91795696d56Speter klausler IoStatementState &io{*cookie};
91895696d56Speter klausler auto *open{io.get_if<OpenStatementState>()};
91995696d56Speter klausler if (!open) {
9202a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
92195696d56Speter klausler io.GetIoErrorHandler().Crash(
92295696d56Speter klausler "SetPosition() called when not in an OPEN statement");
9232a07db4cSPeter Klausler }
9242a07db4cSPeter Klausler return false;
9258db4dc86SPeter Klausler } else if (open->completedOperation()) {
9268db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
9278db4dc86SPeter Klausler "SetPosition() called after GetNewUnit() for an OPEN statement");
92895696d56Speter klausler }
92995696d56Speter klausler static const char *positions[]{"ASIS", "REWIND", "APPEND", nullptr};
93095696d56Speter klausler switch (IdentifyValue(keyword, length, positions)) {
9311f879005STim Keith case 0:
9321f879005STim Keith open->set_position(Position::AsIs);
9331f879005STim Keith return true;
9341f879005STim Keith case 1:
9351f879005STim Keith open->set_position(Position::Rewind);
9361f879005STim Keith return true;
9371f879005STim Keith case 2:
9381f879005STim Keith open->set_position(Position::Append);
9391f879005STim Keith return true;
94095696d56Speter klausler default:
9413b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
94295696d56Speter klausler "Invalid POSITION='%.*s'", static_cast<int>(length), keyword);
94395696d56Speter klausler }
94495696d56Speter klausler return true;
94595696d56Speter klausler }
94695696d56Speter klausler
IONAME(SetRecl)94795696d56Speter klausler bool IONAME(SetRecl)(Cookie cookie, std::size_t n) {
94895696d56Speter klausler IoStatementState &io{*cookie};
94995696d56Speter klausler auto *open{io.get_if<OpenStatementState>()};
95095696d56Speter klausler if (!open) {
9512a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
95295696d56Speter klausler io.GetIoErrorHandler().Crash(
95395696d56Speter klausler "SetRecl() called when not in an OPEN statement");
9542a07db4cSPeter Klausler }
9552a07db4cSPeter Klausler return false;
9568db4dc86SPeter Klausler } else if (open->completedOperation()) {
9578db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
9588db4dc86SPeter Klausler "SetRecl() called after GetNewUnit() for an OPEN statement");
95995696d56Speter klausler }
9603b635714Speter klausler if (n <= 0) {
9613b635714Speter klausler io.GetIoErrorHandler().SignalError("RECL= must be greater than zero");
962e847b303SPeter Klausler return false;
963e847b303SPeter Klausler } else if (open->wasExtant() &&
964e847b303SPeter Klausler open->unit().openRecl.value_or(0) != static_cast<std::int64_t>(n)) {
9653b635714Speter klausler open->SignalError("RECL= may not be changed for an open unit");
966e847b303SPeter Klausler return false;
967e847b303SPeter Klausler } else {
96806ca9f24SPeter Klausler open->unit().openRecl = n;
96995696d56Speter klausler return true;
97095696d56Speter klausler }
971e847b303SPeter Klausler }
97295696d56Speter klausler
IONAME(SetStatus)97395696d56Speter klausler bool IONAME(SetStatus)(Cookie cookie, const char *keyword, std::size_t length) {
97495696d56Speter klausler IoStatementState &io{*cookie};
97595696d56Speter klausler if (auto *open{io.get_if<OpenStatementState>()}) {
9768db4dc86SPeter Klausler if (open->completedOperation()) {
9778db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
9788db4dc86SPeter Klausler "SetStatus() called after GetNewUnit() for an OPEN statement");
9798db4dc86SPeter Klausler }
98095696d56Speter klausler static const char *statuses[]{
98195696d56Speter klausler "OLD", "NEW", "SCRATCH", "REPLACE", "UNKNOWN", nullptr};
98295696d56Speter klausler switch (IdentifyValue(keyword, length, statuses)) {
9831f879005STim Keith case 0:
9841f879005STim Keith open->set_status(OpenStatus::Old);
9851f879005STim Keith return true;
9861f879005STim Keith case 1:
9871f879005STim Keith open->set_status(OpenStatus::New);
9881f879005STim Keith return true;
9891f879005STim Keith case 2:
9901f879005STim Keith open->set_status(OpenStatus::Scratch);
9911f879005STim Keith return true;
9921f879005STim Keith case 3:
9931f879005STim Keith open->set_status(OpenStatus::Replace);
9941f879005STim Keith return true;
9951f879005STim Keith case 4:
9961f879005STim Keith open->set_status(OpenStatus::Unknown);
9971f879005STim Keith return true;
99895696d56Speter klausler default:
9993b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
100095696d56Speter klausler "Invalid STATUS='%.*s'", static_cast<int>(length), keyword);
100195696d56Speter klausler }
100295696d56Speter klausler return false;
100395696d56Speter klausler }
100495696d56Speter klausler if (auto *close{io.get_if<CloseStatementState>()}) {
100595696d56Speter klausler static const char *statuses[]{"KEEP", "DELETE", nullptr};
100695696d56Speter klausler switch (IdentifyValue(keyword, length, statuses)) {
10071f879005STim Keith case 0:
10081f879005STim Keith close->set_status(CloseStatus::Keep);
10091f879005STim Keith return true;
10101f879005STim Keith case 1:
10111f879005STim Keith close->set_status(CloseStatus::Delete);
10121f879005STim Keith return true;
101395696d56Speter klausler default:
10143b635714Speter klausler io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
101595696d56Speter klausler "Invalid STATUS='%.*s'", static_cast<int>(length), keyword);
101695696d56Speter klausler }
101795696d56Speter klausler return false;
101895696d56Speter klausler }
10192a07db4cSPeter Klausler if (io.get_if<NoopStatementState>() ||
10202a07db4cSPeter Klausler io.get_if<ErroneousIoStatementState>()) {
102195696d56Speter klausler return true; // don't bother validating STATUS= in a no-op CLOSE
102295696d56Speter klausler }
102395696d56Speter klausler io.GetIoErrorHandler().Crash(
102495696d56Speter klausler "SetStatus() called when not in an OPEN or CLOSE statement");
102595696d56Speter klausler }
102695696d56Speter klausler
IONAME(SetFile)1027675ad1bcSpeter klausler bool IONAME(SetFile)(Cookie cookie, const char *path, std::size_t chars) {
102895696d56Speter klausler IoStatementState &io{*cookie};
102995696d56Speter klausler if (auto *open{io.get_if<OpenStatementState>()}) {
10308db4dc86SPeter Klausler if (open->completedOperation()) {
10318db4dc86SPeter Klausler io.GetIoErrorHandler().Crash(
10328db4dc86SPeter Klausler "SetFile() called after GetNewUnit() for an OPEN statement");
10338db4dc86SPeter Klausler }
1034675ad1bcSpeter klausler open->set_path(path, chars);
103595696d56Speter klausler return true;
10362a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
103795696d56Speter klausler io.GetIoErrorHandler().Crash(
103895696d56Speter klausler "SetFile() called when not in an OPEN statement");
10392a07db4cSPeter Klausler }
104095696d56Speter klausler return false;
104195696d56Speter klausler }
104295696d56Speter klausler
IONAME(GetNewUnit)104395696d56Speter klausler bool IONAME(GetNewUnit)(Cookie cookie, int &unit, int kind) {
104495696d56Speter klausler IoStatementState &io{*cookie};
104595696d56Speter klausler auto *open{io.get_if<OpenStatementState>()};
104695696d56Speter klausler if (!open) {
10472a07db4cSPeter Klausler if (!io.get_if<ErroneousIoStatementState>()) {
104895696d56Speter klausler io.GetIoErrorHandler().Crash(
104995696d56Speter klausler "GetNewUnit() called when not in an OPEN statement");
10502a07db4cSPeter Klausler }
10512a07db4cSPeter Klausler return false;
10528db4dc86SPeter Klausler } else if (!open->InError()) {
10538db4dc86SPeter Klausler open->CompleteOperation();
10548db4dc86SPeter Klausler }
10558db4dc86SPeter Klausler if (open->InError()) {
10568db4dc86SPeter Klausler // A failed OPEN(NEWUNIT=n) does not modify 'n'
10578db4dc86SPeter Klausler return false;
105895696d56Speter klausler }
105973b193aeSPeter Klausler std::int64_t result{open->unit().unitNumber()};
106073b193aeSPeter Klausler if (!SetInteger(unit, kind, result)) {
1061e3550f19SPeter Steinfeld open->SignalError("GetNewUnit(): bad INTEGER kind(%d) or out-of-range "
106273b193aeSPeter Klausler "value(%jd) for result",
106373b193aeSPeter Klausler kind, static_cast<std::intmax_t>(result));
106495696d56Speter klausler }
106595696d56Speter klausler return true;
106695696d56Speter klausler }
106795696d56Speter klausler
106895696d56Speter klausler // Data transfers
106995696d56Speter klausler
IONAME(OutputDescriptor)1070cc01194cSpeter klausler bool IONAME(OutputDescriptor)(Cookie cookie, const Descriptor &descriptor) {
1071cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
107295696d56Speter klausler }
107395696d56Speter klausler
IONAME(InputDescriptor)1074cc01194cSpeter klausler bool IONAME(InputDescriptor)(Cookie cookie, const Descriptor &descriptor) {
1075cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
10768f2c5c43Speter klausler }
10778f2c5c43Speter klausler
IONAME(OutputUnformattedBlock)10788f2c5c43Speter klausler bool IONAME(OutputUnformattedBlock)(Cookie cookie, const char *x,
10798f2c5c43Speter klausler std::size_t length, std::size_t elementBytes) {
108095696d56Speter klausler IoStatementState &io{*cookie};
108143fadefbSpeter klausler if (auto *unf{io.get_if<
108243fadefbSpeter klausler ExternalUnformattedIoStatementState<Direction::Output>>()}) {
10838f2c5c43Speter klausler return unf->Emit(x, length, elementBytes);
10844393e377Speter klausler } else if (auto *inq{io.get_if<InquireIOLengthState>()}) {
10854393e377Speter klausler return inq->Emit(x, length, elementBytes);
10862a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
10875d5b9682Speter klausler io.GetIoErrorHandler().Crash("OutputUnformattedBlock() called for an I/O "
10885d5b9682Speter klausler "statement that is not unformatted output");
10892a07db4cSPeter Klausler }
10905d5b9682Speter klausler return false;
10915d5b9682Speter klausler }
10925d5b9682Speter klausler
IONAME(InputUnformattedBlock)10938f2c5c43Speter klausler bool IONAME(InputUnformattedBlock)(
10948f2c5c43Speter klausler Cookie cookie, char *x, std::size_t length, std::size_t elementBytes) {
10955d5b9682Speter klausler IoStatementState &io{*cookie};
10968db4dc86SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
1097d879ac8aSpeter klausler io.BeginReadingRecord();
10988db4dc86SPeter Klausler if (handler.InError()) {
1099e81c96d6Speter klausler return false;
1100e81c96d6Speter klausler }
110143fadefbSpeter klausler if (auto *unf{
110243fadefbSpeter klausler io.get_if<ExternalUnformattedIoStatementState<Direction::Input>>()}) {
11038f2c5c43Speter klausler return unf->Receive(x, length, elementBytes);
11042a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
11058db4dc86SPeter Klausler handler.Crash("InputUnformattedBlock() called for an I/O statement that is "
11068db4dc86SPeter Klausler "not unformatted input");
11072a07db4cSPeter Klausler }
110895696d56Speter klausler return false;
1109f7be2518Speter klausler }
1110f7be2518Speter klausler
IONAME(OutputInteger8)1111f65f830eSpeter klausler bool IONAME(OutputInteger8)(Cookie cookie, std::int8_t n) {
11122a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger8")) {
11132a07db4cSPeter Klausler return false;
11142a07db4cSPeter Klausler }
1115f65f830eSpeter klausler StaticDescriptor staticDescriptor;
1116f65f830eSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1117f65f830eSpeter klausler descriptor.Establish(
1118f65f830eSpeter klausler TypeCategory::Integer, 1, reinterpret_cast<void *>(&n), 0);
1119f65f830eSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1120f65f830eSpeter klausler }
1121f65f830eSpeter klausler
IONAME(OutputInteger16)1122f65f830eSpeter klausler bool IONAME(OutputInteger16)(Cookie cookie, std::int16_t n) {
11232a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger16")) {
11242a07db4cSPeter Klausler return false;
11252a07db4cSPeter Klausler }
1126f65f830eSpeter klausler StaticDescriptor staticDescriptor;
1127f65f830eSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1128f65f830eSpeter klausler descriptor.Establish(
1129f65f830eSpeter klausler TypeCategory::Integer, 2, reinterpret_cast<void *>(&n), 0);
1130f65f830eSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1131f65f830eSpeter klausler }
1132f65f830eSpeter klausler
IONAME(OutputInteger32)1133f65f830eSpeter klausler bool IONAME(OutputInteger32)(Cookie cookie, std::int32_t n) {
11342a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger32")) {
11352a07db4cSPeter Klausler return false;
11362a07db4cSPeter Klausler }
1137f65f830eSpeter klausler StaticDescriptor staticDescriptor;
1138f65f830eSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1139f65f830eSpeter klausler descriptor.Establish(
1140f65f830eSpeter klausler TypeCategory::Integer, 4, reinterpret_cast<void *>(&n), 0);
1141f65f830eSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1142f65f830eSpeter klausler }
1143f65f830eSpeter klausler
IONAME(OutputInteger64)1144f7be2518Speter klausler bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) {
11452a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger64")) {
11462a07db4cSPeter Klausler return false;
11472a07db4cSPeter Klausler }
1148cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1149cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1150cc01194cSpeter klausler descriptor.Establish(
1151f65f830eSpeter klausler TypeCategory::Integer, 8, reinterpret_cast<void *>(&n), 0);
1152cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
11533b635714Speter klausler }
11543b635714Speter klausler
1155f65f830eSpeter klausler #ifdef __SIZEOF_INT128__
IONAME(OutputInteger128)1156f65f830eSpeter klausler bool IONAME(OutputInteger128)(Cookie cookie, common::int128_t n) {
11572a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger128")) {
11582a07db4cSPeter Klausler return false;
11592a07db4cSPeter Klausler }
1160f65f830eSpeter klausler StaticDescriptor staticDescriptor;
1161f65f830eSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1162f65f830eSpeter klausler descriptor.Establish(
1163f65f830eSpeter klausler TypeCategory::Integer, 16, reinterpret_cast<void *>(&n), 0);
1164f65f830eSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1165f65f830eSpeter klausler }
1166f65f830eSpeter klausler #endif
1167f65f830eSpeter klausler
IONAME(InputInteger)11683b635714Speter klausler bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
11692a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputInteger")) {
11702a07db4cSPeter Klausler return false;
11712a07db4cSPeter Klausler }
1172cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1173cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1174cc01194cSpeter klausler descriptor.Establish(
1175cc01194cSpeter klausler TypeCategory::Integer, kind, reinterpret_cast<void *>(&n), 0);
1176cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
11773bc2ae95Speter klausler }
11783bc2ae95Speter klausler
IONAME(OutputReal32)11793bc2ae95Speter klausler bool IONAME(OutputReal32)(Cookie cookie, float x) {
11802a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputReal32")) {
11812a07db4cSPeter Klausler return false;
11822a07db4cSPeter Klausler }
1183cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1184cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1185cc01194cSpeter klausler descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
1186cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
11873bc2ae95Speter klausler }
11883bc2ae95Speter klausler
IONAME(OutputReal64)11893bc2ae95Speter klausler bool IONAME(OutputReal64)(Cookie cookie, double x) {
11902a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputReal64")) {
11912a07db4cSPeter Klausler return false;
11922a07db4cSPeter Klausler }
1193cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1194cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1195cc01194cSpeter klausler descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
1196cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
11974b9b64d5SZachary Selk }
11984b9b64d5SZachary Selk
IONAME(InputReal32)11994b9b64d5SZachary Selk bool IONAME(InputReal32)(Cookie cookie, float &x) {
12002a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal32")) {
12012a07db4cSPeter Klausler return false;
12022a07db4cSPeter Klausler }
1203cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1204cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1205cc01194cSpeter klausler descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
1206cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
12073b635714Speter klausler }
12083b635714Speter klausler
IONAME(InputReal64)12093b635714Speter klausler bool IONAME(InputReal64)(Cookie cookie, double &x) {
12102a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal64")) {
12112a07db4cSPeter Klausler return false;
12122a07db4cSPeter Klausler }
1213cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1214cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1215cc01194cSpeter klausler descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
1216cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
12173bc2ae95Speter klausler }
12183bc2ae95Speter klausler
IONAME(OutputComplex32)1219cc01194cSpeter klausler bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) {
12202a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex32")) {
12212a07db4cSPeter Klausler return false;
12222a07db4cSPeter Klausler }
1223cc01194cSpeter klausler float z[2]{r, i};
1224cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1225cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1226cc01194cSpeter klausler descriptor.Establish(
1227cc01194cSpeter klausler TypeCategory::Complex, 4, reinterpret_cast<void *>(&z), 0);
1228cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
12293bc2ae95Speter klausler }
12303bc2ae95Speter klausler
IONAME(OutputComplex64)1231cc01194cSpeter klausler bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) {
12322a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex64")) {
12332a07db4cSPeter Klausler return false;
12342a07db4cSPeter Klausler }
1235cc01194cSpeter klausler double z[2]{r, i};
1236cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1237cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1238cc01194cSpeter klausler descriptor.Establish(
1239cc01194cSpeter klausler TypeCategory::Complex, 8, reinterpret_cast<void *>(&z), 0);
1240cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
12413bc2ae95Speter klausler }
12423bc2ae95Speter klausler
IONAME(InputComplex32)1243cc01194cSpeter klausler bool IONAME(InputComplex32)(Cookie cookie, float z[2]) {
12442a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex32")) {
12452a07db4cSPeter Klausler return false;
12462a07db4cSPeter Klausler }
1247cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1248cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1249cc01194cSpeter klausler descriptor.Establish(
1250cc01194cSpeter klausler TypeCategory::Complex, 4, reinterpret_cast<void *>(z), 0);
1251cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
12523bc2ae95Speter klausler }
12533bc2ae95Speter klausler
IONAME(InputComplex64)1254cc01194cSpeter klausler bool IONAME(InputComplex64)(Cookie cookie, double z[2]) {
12552a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex64")) {
12562a07db4cSPeter Klausler return false;
12572a07db4cSPeter Klausler }
1258cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1259cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1260cc01194cSpeter klausler descriptor.Establish(
1261cc01194cSpeter klausler TypeCategory::Complex, 8, reinterpret_cast<void *>(z), 0);
1262cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
1263f7be2518Speter klausler }
1264f7be2518Speter klausler
IONAME(OutputCharacter)1265cdfb95adSpeter klausler bool IONAME(OutputCharacter)(
1266cdfb95adSpeter klausler Cookie cookie, const char *x, std::size_t length, int kind) {
12672a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputCharacter")) {
12682a07db4cSPeter Klausler return false;
12692a07db4cSPeter Klausler }
1270cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1271cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1272cc01194cSpeter klausler descriptor.Establish(
1273cdfb95adSpeter klausler kind, length, reinterpret_cast<void *>(const_cast<char *>(x)), 0);
1274cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1275f7be2518Speter klausler }
12763b635714Speter klausler
IONAME(OutputAscii)1277cdfb95adSpeter klausler bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
1278cdfb95adSpeter klausler return IONAME(OutputCharacter(cookie, x, length, 1));
1279cdfb95adSpeter klausler }
1280cdfb95adSpeter klausler
IONAME(InputCharacter)1281cdfb95adSpeter klausler bool IONAME(InputCharacter)(
1282cdfb95adSpeter klausler Cookie cookie, char *x, std::size_t length, int kind) {
12832a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputCharacter")) {
12842a07db4cSPeter Klausler return false;
12852a07db4cSPeter Klausler }
1286cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1287cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1288cdfb95adSpeter klausler descriptor.Establish(kind, length, reinterpret_cast<void *>(x), 0);
1289cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
129095696d56Speter klausler }
1291f7be2518Speter klausler
IONAME(InputAscii)1292cdfb95adSpeter klausler bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) {
1293cea8b8a7SPeter Klausler return IONAME(InputCharacter)(cookie, x, length, 1);
1294cdfb95adSpeter klausler }
1295cdfb95adSpeter klausler
IONAME(OutputLogical)1296f7be2518Speter klausler bool IONAME(OutputLogical)(Cookie cookie, bool truth) {
12972a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputLogical")) {
12982a07db4cSPeter Klausler return false;
12992a07db4cSPeter Klausler }
1300cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1301cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1302cc01194cSpeter klausler descriptor.Establish(
1303cdfb95adSpeter klausler TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0);
1304cc01194cSpeter klausler return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
130595696d56Speter klausler }
13063b635714Speter klausler
IONAME(InputLogical)13073b635714Speter klausler bool IONAME(InputLogical)(Cookie cookie, bool &truth) {
13082a07db4cSPeter Klausler if (!cookie->CheckFormattedStmtType<Direction::Input>("InputLogical")) {
13092a07db4cSPeter Klausler return false;
13102a07db4cSPeter Klausler }
1311cc01194cSpeter klausler StaticDescriptor staticDescriptor;
1312cc01194cSpeter klausler Descriptor &descriptor{staticDescriptor.descriptor()};
1313cc01194cSpeter klausler descriptor.Establish(
1314cdfb95adSpeter klausler TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0);
1315cc01194cSpeter klausler return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
13163b635714Speter klausler }
13173b635714Speter klausler
IONAME(GetSize)13184393e377Speter klausler std::size_t IONAME(GetSize)(Cookie cookie) {
13194393e377Speter klausler IoStatementState &io{*cookie};
13208db4dc86SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
13218db4dc86SPeter Klausler if (!handler.InError()) {
13228db4dc86SPeter Klausler io.CompleteOperation();
13238db4dc86SPeter Klausler }
13244393e377Speter klausler if (const auto *formatted{
13254393e377Speter klausler io.get_if<FormattedIoStatementState<Direction::Input>>()}) {
13264393e377Speter klausler return formatted->GetEditDescriptorChars();
13272a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
13282a07db4cSPeter Klausler handler.Crash("GetIoSize() called for an I/O statement that is not a "
13292a07db4cSPeter Klausler "formatted READ()");
13304393e377Speter klausler }
13314393e377Speter klausler return 0;
13324393e377Speter klausler }
13334393e377Speter klausler
IONAME(GetIoLength)13344393e377Speter klausler std::size_t IONAME(GetIoLength)(Cookie cookie) {
13354393e377Speter klausler IoStatementState &io{*cookie};
13368db4dc86SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
13378db4dc86SPeter Klausler if (!handler.InError()) {
13388db4dc86SPeter Klausler io.CompleteOperation();
13398db4dc86SPeter Klausler }
13404393e377Speter klausler if (const auto *inq{io.get_if<InquireIOLengthState>()}) {
13414393e377Speter klausler return inq->bytes();
13422a07db4cSPeter Klausler } else if (!io.get_if<ErroneousIoStatementState>()) {
13438db4dc86SPeter Klausler handler.Crash("GetIoLength() called for an I/O statement that is not "
13448db4dc86SPeter Klausler "INQUIRE(IOLENGTH=)");
13452a07db4cSPeter Klausler }
13464393e377Speter klausler return 0;
13474393e377Speter klausler }
13484393e377Speter klausler
IONAME(GetIoMsg)13493b635714Speter klausler void IONAME(GetIoMsg)(Cookie cookie, char *msg, std::size_t length) {
13508db4dc86SPeter Klausler IoStatementState &io{*cookie};
13518db4dc86SPeter Klausler IoErrorHandler &handler{io.GetIoErrorHandler()};
13528db4dc86SPeter Klausler if (!handler.InError()) {
13538db4dc86SPeter Klausler io.CompleteOperation();
13548db4dc86SPeter Klausler }
1355e81c96d6Speter klausler if (handler.InError()) { // leave "msg" alone when no error
13563b635714Speter klausler handler.GetIoMsg(msg, length);
13573b635714Speter klausler }
1358f7be2518Speter klausler }
1359f7be2518Speter klausler
IONAME(InquireCharacter)1360675ad1bcSpeter klausler bool IONAME(InquireCharacter)(Cookie cookie, InquiryKeywordHash inquiry,
1361675ad1bcSpeter klausler char *result, std::size_t length) {
1362675ad1bcSpeter klausler IoStatementState &io{*cookie};
1363675ad1bcSpeter klausler return io.Inquire(inquiry, result, length);
1364675ad1bcSpeter klausler }
1365675ad1bcSpeter klausler
IONAME(InquireLogical)1366675ad1bcSpeter klausler bool IONAME(InquireLogical)(
1367675ad1bcSpeter klausler Cookie cookie, InquiryKeywordHash inquiry, bool &result) {
1368675ad1bcSpeter klausler IoStatementState &io{*cookie};
1369675ad1bcSpeter klausler return io.Inquire(inquiry, result);
1370675ad1bcSpeter klausler }
1371675ad1bcSpeter klausler
IONAME(InquirePendingId)1372675ad1bcSpeter klausler bool IONAME(InquirePendingId)(Cookie cookie, std::int64_t id, bool &result) {
1373675ad1bcSpeter klausler IoStatementState &io{*cookie};
1374675ad1bcSpeter klausler return io.Inquire(HashInquiryKeyword("PENDING"), id, result);
1375675ad1bcSpeter klausler }
1376675ad1bcSpeter klausler
IONAME(InquireInteger64)1377675ad1bcSpeter klausler bool IONAME(InquireInteger64)(
1378675ad1bcSpeter klausler Cookie cookie, InquiryKeywordHash inquiry, std::int64_t &result, int kind) {
1379675ad1bcSpeter klausler IoStatementState &io{*cookie};
1380675ad1bcSpeter klausler std::int64_t n;
1381675ad1bcSpeter klausler if (io.Inquire(inquiry, n)) {
138273b193aeSPeter Klausler if (SetInteger(result, kind, n)) {
1383675ad1bcSpeter klausler return true;
1384675ad1bcSpeter klausler }
138573b193aeSPeter Klausler io.GetIoErrorHandler().SignalError(
1386e3550f19SPeter Steinfeld "InquireInteger64(): bad INTEGER kind(%d) or out-of-range "
1387e3550f19SPeter Steinfeld "value(%jd) "
138873b193aeSPeter Klausler "for result",
138973b193aeSPeter Klausler kind, static_cast<std::intmax_t>(n));
139073b193aeSPeter Klausler }
1391675ad1bcSpeter klausler return false;
1392675ad1bcSpeter klausler }
1393675ad1bcSpeter klausler
IONAME(EndIoStatement)1394f7be2518Speter klausler enum Iostat IONAME(EndIoStatement)(Cookie cookie) {
1395f7be2518Speter klausler IoStatementState &io{*cookie};
1396f7be2518Speter klausler return static_cast<enum Iostat>(io.EndIoStatement());
1397352d347aSAlexis Perry }
1398c58c64d0SJean Perier
1399c58c64d0SJean Perier template <typename INT>
CheckUnitNumberInRangeImpl(INT unit,bool handleError,char * ioMsg,std::size_t ioMsgLength,const char * sourceFile,int sourceLine)1400c58c64d0SJean Perier static enum Iostat CheckUnitNumberInRangeImpl(INT unit, bool handleError,
1401c58c64d0SJean Perier char *ioMsg, std::size_t ioMsgLength, const char *sourceFile,
1402c58c64d0SJean Perier int sourceLine) {
14039cfa899bSJean Perier static_assert(sizeof(INT) >= sizeof(ExternalUnit),
14049cfa899bSJean Perier "only intended to be used when the INT to ExternalUnit conversion is "
14059cfa899bSJean Perier "narrowing");
1406c58c64d0SJean Perier if (unit != static_cast<ExternalUnit>(unit)) {
1407c58c64d0SJean Perier Terminator oom{sourceFile, sourceLine};
1408c58c64d0SJean Perier IoErrorHandler errorHandler{oom};
1409c58c64d0SJean Perier if (handleError) {
1410c58c64d0SJean Perier errorHandler.HasIoStat();
1411c58c64d0SJean Perier if (ioMsg) {
1412c58c64d0SJean Perier errorHandler.HasIoMsg();
1413c58c64d0SJean Perier }
1414c58c64d0SJean Perier }
1415c58c64d0SJean Perier // Only provide the bad unit number in the message if SignalError can print
1416c58c64d0SJean Perier // it accurately. Otherwise, the generic IostatUnitOverflow message will be
1417c58c64d0SJean Perier // used.
1418c58c64d0SJean Perier if (static_cast<std::intmax_t>(unit) == unit) {
1419c58c64d0SJean Perier errorHandler.SignalError(IostatUnitOverflow,
1420c58c64d0SJean Perier "UNIT number %jd is out of range", static_cast<std::intmax_t>(unit));
1421c58c64d0SJean Perier } else {
1422c58c64d0SJean Perier errorHandler.SignalError(IostatUnitOverflow);
1423c58c64d0SJean Perier }
1424c58c64d0SJean Perier if (ioMsg) {
1425c58c64d0SJean Perier errorHandler.GetIoMsg(ioMsg, ioMsgLength);
1426c58c64d0SJean Perier }
1427c58c64d0SJean Perier return static_cast<enum Iostat>(errorHandler.GetIoStat());
1428c58c64d0SJean Perier }
1429c58c64d0SJean Perier return IostatOk;
1430c58c64d0SJean Perier }
1431c58c64d0SJean Perier
IONAME(CheckUnitNumberInRange64)1432c58c64d0SJean Perier enum Iostat IONAME(CheckUnitNumberInRange64)(std::int64_t unit,
1433c58c64d0SJean Perier bool handleError, char *ioMsg, std::size_t ioMsgLength,
1434c58c64d0SJean Perier const char *sourceFile, int sourceLine) {
1435c58c64d0SJean Perier return CheckUnitNumberInRangeImpl(
1436c58c64d0SJean Perier unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine);
1437c58c64d0SJean Perier }
1438c58c64d0SJean Perier
1439c58c64d0SJean Perier #ifdef __SIZEOF_INT128__
IONAME(CheckUnitNumberInRange128)1440c58c64d0SJean Perier enum Iostat IONAME(CheckUnitNumberInRange128)(common::int128_t unit,
1441c58c64d0SJean Perier bool handleError, char *ioMsg, std::size_t ioMsgLength,
1442c58c64d0SJean Perier const char *sourceFile, int sourceLine) {
1443c58c64d0SJean Perier return CheckUnitNumberInRangeImpl(
1444c58c64d0SJean Perier unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine);
1445c58c64d0SJean Perier }
1446c58c64d0SJean Perier #endif
1447c58c64d0SJean Perier
14481f879005STim Keith } // namespace Fortran::runtime::io
1449