blob: f9d60fecb149a52af7d61839aeef1a00c9f771b4 [file] [log] [blame]
Diana Picus651f58b2021-09-02 08:14:011//===-- runtime/io-api.cpp ------------------------------------------------===//
peter klausler491122d2020-01-16 21:51:252//
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
peter klauslerf7be2512020-01-24 00:59:279// Implements the I/O statement API
10
Peter Klausler830c0b92021-09-01 23:00:5311#include "flang/Runtime/io-api.h"
peter klauslercc011942020-08-07 00:30:0112#include "descriptor-io.h"
peter klausler3b635712020-02-13 22:41:5613#include "edit-input.h"
14#include "edit-output.h"
peter klausler95696d52020-02-05 00:55:4515#include "environment.h"
peter klausler491122d2020-01-16 21:51:2516#include "format.h"
17#include "io-stmt.h"
peter klausler491122d2020-01-16 21:51:2518#include "terminator.h"
peter klausler95696d52020-02-05 00:55:4519#include "tools.h"
peter klauslerf7be2512020-01-24 00:59:2720#include "unit.h"
Peter Klausler830c0b92021-09-01 23:00:5321#include "flang/Runtime/descriptor.h"
22#include "flang/Runtime/memory.h"
peter klausler491122d2020-01-16 21:51:2523#include <cstdlib>
24#include <memory>
25
26namespace Fortran::runtime::io {
27
peter klausler675ad1b2020-08-03 18:35:2928const char *InquiryKeywordHashDecode(
29 char *buffer, std::size_t n, InquiryKeywordHash hash) {
30 if (n < 1) {
31 return nullptr;
32 }
33 char *p{buffer + n};
34 *--p = '\0';
35 while (hash > 1) {
36 if (p < buffer) {
37 return nullptr;
38 }
39 *--p = 'A' + (hash % 26);
40 hash /= 26;
41 }
42 return hash == 1 ? p : nullptr;
43}
44
Tim Keith1f879002020-03-29 04:00:1645template <Direction DIR>
peter klausler3b635712020-02-13 22:41:5646Cookie BeginInternalArrayListIO(const Descriptor &descriptor,
peter klausler95696d52020-02-05 00:55:4547 void ** /*scratchArea*/, std::size_t /*scratchBytes*/,
48 const char *sourceFile, int sourceLine) {
49 Terminator oom{sourceFile, sourceLine};
peter klausler98d576c2020-07-03 01:35:2050 return &New<InternalListIoStatementState<DIR>>{oom}(
51 descriptor, sourceFile, sourceLine)
52 .release()
53 ->ioStatementState();
peter klausler95696d52020-02-05 00:55:4554}
55
peter klausler3b635712020-02-13 22:41:5656Cookie IONAME(BeginInternalArrayListOutput)(const Descriptor &descriptor,
57 void **scratchArea, std::size_t scratchBytes, const char *sourceFile,
58 int sourceLine) {
59 return BeginInternalArrayListIO<Direction::Output>(
60 descriptor, scratchArea, scratchBytes, sourceFile, sourceLine);
61}
62
63Cookie IONAME(BeginInternalArrayListInput)(const Descriptor &descriptor,
64 void **scratchArea, std::size_t scratchBytes, const char *sourceFile,
65 int sourceLine) {
66 return BeginInternalArrayListIO<Direction::Input>(
67 descriptor, scratchArea, scratchBytes, sourceFile, sourceLine);
68}
69
Tim Keith1f879002020-03-29 04:00:1670template <Direction DIR>
peter klausler3b635712020-02-13 22:41:5671Cookie BeginInternalArrayFormattedIO(const Descriptor &descriptor,
V Donaldson27d666b2022-08-24 17:22:4272 const char *format, std::size_t formatLength,
73 const Descriptor *formatDescriptor, void ** /*scratchArea*/,
74 std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {
peter klausler95696d52020-02-05 00:55:4575 Terminator oom{sourceFile, sourceLine};
Peter Klauslercc180f42022-08-18 17:52:5976 return &New<InternalFormattedIoStatementState<DIR>>{oom}(descriptor, format,
V Donaldson27d666b2022-08-24 17:22:4277 formatLength, formatDescriptor, sourceFile, sourceLine)
peter klausler98d576c2020-07-03 01:35:2078 .release()
79 ->ioStatementState();
peter klausler95696d52020-02-05 00:55:4580}
81
peter klausler3b635712020-02-13 22:41:5682Cookie IONAME(BeginInternalArrayFormattedOutput)(const Descriptor &descriptor,
V Donaldson27d666b2022-08-24 17:22:4283 const char *format, std::size_t formatLength,
84 const Descriptor *formatDescriptor, void **scratchArea,
85 std::size_t scratchBytes, const char *sourceFile, int sourceLine) {
peter klausler3b635712020-02-13 22:41:5686 return BeginInternalArrayFormattedIO<Direction::Output>(descriptor, format,
V Donaldson27d666b2022-08-24 17:22:4287 formatLength, formatDescriptor, scratchArea, scratchBytes, sourceFile,
88 sourceLine);
peter klausler3b635712020-02-13 22:41:5689}
90
91Cookie IONAME(BeginInternalArrayFormattedInput)(const Descriptor &descriptor,
V Donaldson27d666b2022-08-24 17:22:4292 const char *format, std::size_t formatLength,
93 const Descriptor *formatDescriptor, void **scratchArea,
94 std::size_t scratchBytes, const char *sourceFile, int sourceLine) {
peter klausler3b635712020-02-13 22:41:5695 return BeginInternalArrayFormattedIO<Direction::Input>(descriptor, format,
V Donaldson27d666b2022-08-24 17:22:4296 formatLength, formatDescriptor, scratchArea, scratchBytes, sourceFile,
97 sourceLine);
peter klausler3b635712020-02-13 22:41:5698}
99
Tim Keith1f879002020-03-29 04:00:16100template <Direction DIR>
peter klauslerb30fa1c2020-07-17 18:27:40101Cookie BeginInternalListIO(
102 std::conditional_t<DIR == Direction::Input, const char, char> *internal,
103 std::size_t internalLength, void ** /*scratchArea*/,
104 std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {
105 Terminator oom{sourceFile, sourceLine};
106 return &New<InternalListIoStatementState<DIR>>{oom}(
107 internal, internalLength, sourceFile, sourceLine)
108 .release()
109 ->ioStatementState();
110}
111
112Cookie IONAME(BeginInternalListOutput)(char *internal,
113 std::size_t internalLength, void **scratchArea, std::size_t scratchBytes,
114 const char *sourceFile, int sourceLine) {
115 return BeginInternalListIO<Direction::Output>(internal, internalLength,
116 scratchArea, scratchBytes, sourceFile, sourceLine);
117}
118
119Cookie IONAME(BeginInternalListInput)(const char *internal,
120 std::size_t internalLength, void **scratchArea, std::size_t scratchBytes,
121 const char *sourceFile, int sourceLine) {
122 return BeginInternalListIO<Direction::Input>(internal, internalLength,
123 scratchArea, scratchBytes, sourceFile, sourceLine);
124}
125
126template <Direction DIR>
peter klausler3b635712020-02-13 22:41:56127Cookie BeginInternalFormattedIO(
128 std::conditional_t<DIR == Direction::Input, const char, char> *internal,
129 std::size_t internalLength, const char *format, std::size_t formatLength,
V Donaldson27d666b2022-08-24 17:22:42130 const Descriptor *formatDescriptor, void ** /*scratchArea*/,
131 std::size_t /*scratchBytes*/, const char *sourceFile, int sourceLine) {
peter klausler95696d52020-02-05 00:55:45132 Terminator oom{sourceFile, sourceLine};
Peter Klauslercc180f42022-08-18 17:52:59133 return &New<InternalFormattedIoStatementState<DIR>>{oom}(internal,
V Donaldson27d666b2022-08-24 17:22:42134 internalLength, format, formatLength, formatDescriptor, sourceFile,
135 sourceLine)
peter klausler98d576c2020-07-03 01:35:20136 .release()
137 ->ioStatementState();
peter klausler95696d52020-02-05 00:55:45138}
139
peter klausler491122d2020-01-16 21:51:25140Cookie IONAME(BeginInternalFormattedOutput)(char *internal,
141 std::size_t internalLength, const char *format, std::size_t formatLength,
V Donaldson27d666b2022-08-24 17:22:42142 const Descriptor *formatDescriptor, void **scratchArea,
143 std::size_t scratchBytes, const char *sourceFile, int sourceLine) {
peter klausler3b635712020-02-13 22:41:56144 return BeginInternalFormattedIO<Direction::Output>(internal, internalLength,
V Donaldson27d666b2022-08-24 17:22:42145 format, formatLength, formatDescriptor, scratchArea, scratchBytes,
146 sourceFile, sourceLine);
peter klausler95696d52020-02-05 00:55:45147}
148
peter klausler3b635712020-02-13 22:41:56149Cookie IONAME(BeginInternalFormattedInput)(const char *internal,
peter klausler95696d52020-02-05 00:55:45150 std::size_t internalLength, const char *format, std::size_t formatLength,
V Donaldson27d666b2022-08-24 17:22:42151 const Descriptor *formatDescriptor, void **scratchArea,
152 std::size_t scratchBytes, const char *sourceFile, int sourceLine) {
peter klausler3b635712020-02-13 22:41:56153 return BeginInternalFormattedIO<Direction::Input>(internal, internalLength,
V Donaldson27d666b2022-08-24 17:22:42154 format, formatLength, formatDescriptor, scratchArea, scratchBytes,
155 sourceFile, sourceLine);
peter klausler3b635712020-02-13 22:41:56156}
157
Peter Klauslerc078e462022-06-22 20:24:51158static Cookie NoopUnit(const Terminator &terminator, int unitNumber,
159 enum Iostat iostat = IostatOk) {
160 Cookie cookie{&New<NoopStatementState>{terminator}(
161 terminator.sourceFileName(), terminator.sourceLine(), unitNumber)
162 .release()
163 ->ioStatementState()};
164 if (iostat != IostatOk) {
165 cookie->GetIoErrorHandler().SetPendingError(iostat);
166 }
167 return cookie;
168}
169
Peter Klauslercfbde712022-06-11 01:08:14170static ExternalFileUnit *GetOrCreateUnit(int unitNumber, Direction direction,
171 std::optional<bool> isUnformatted, const Terminator &terminator,
172 Cookie &errorCookie) {
173 if (ExternalFileUnit *
174 unit{ExternalFileUnit::LookUpOrCreateAnonymous(
175 unitNumber, direction, isUnformatted, terminator)}) {
176 errorCookie = nullptr;
177 return unit;
178 } else {
Peter Klauslerc078e462022-06-22 20:24:51179 errorCookie = NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
Peter Klauslercfbde712022-06-11 01:08:14180 return nullptr;
181 }
182}
183
peter klausler6a1c3ef2021-05-05 18:37:49184template <Direction DIR, template <Direction> class STATE, typename... A>
Peter Klauslerdf38f352022-02-16 22:55:19185Cookie BeginExternalListIO(
186 int unitNumber, const char *sourceFile, int sourceLine, A &&...xs) {
peter klausler3b635712020-02-13 22:41:56187 Terminator terminator{sourceFile, sourceLine};
188 if (unitNumber == DefaultUnit) {
189 unitNumber = DIR == Direction::Input ? 5 : 6;
190 }
Peter Klauslercfbde712022-06-11 01:08:14191 Cookie errorCookie{nullptr};
192 ExternalFileUnit *unit{GetOrCreateUnit(
193 unitNumber, DIR, false /*!unformatted*/, terminator, errorCookie)};
194 if (!unit) {
195 return errorCookie;
196 }
197 if (!unit->isUnformatted.has_value()) {
198 unit->isUnformatted = false;
Peter Klauslerb1856002022-01-18 18:40:10199 }
Peter Klauslerdf38f352022-02-16 22:55:19200 Iostat iostat{IostatOk};
Peter Klauslercfbde712022-06-11 01:08:14201 if (*unit->isUnformatted) {
Peter Klauslerdf38f352022-02-16 22:55:19202 iostat = IostatFormattedIoOnUnformattedUnit;
Peter Klauslerb1856002022-01-18 18:40:10203 }
Peter Klauslercfbde712022-06-11 01:08:14204 if (ChildIo * child{unit->GetChildIo()}) {
Peter Klauslerdf38f352022-02-16 22:55:19205 if (iostat == IostatOk) {
206 iostat = child->CheckFormattingAndDirection(false, DIR);
peter klausler43fadef2021-06-25 17:40:08207 }
Peter Klauslerdf38f352022-02-16 22:55:19208 if (iostat == IostatOk) {
209 return &child->BeginIoStatement<ChildListIoStatementState<DIR>>(
210 *child, sourceFile, sourceLine);
211 } else {
212 return &child->BeginIoStatement<ErroneousIoStatementState>(
Peter Klausler11f928a2022-06-02 20:33:10213 iostat, nullptr /* no unit */, sourceFile, sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19214 }
215 } else {
Peter Klauslercfbde712022-06-11 01:08:14216 if (iostat == IostatOk && unit->access == Access::Direct) {
Peter Klauslerdf38f352022-02-16 22:55:19217 iostat = IostatListIoOnDirectAccessUnit;
218 }
219 if (iostat == IostatOk) {
Peter Klauslercfbde712022-06-11 01:08:14220 iostat = unit->SetDirection(DIR);
Peter Klauslerdf38f352022-02-16 22:55:19221 }
222 if (iostat == IostatOk) {
Peter Klauslercfbde712022-06-11 01:08:14223 return &unit->BeginIoStatement<STATE<DIR>>(
Peter Klausler921316a2022-07-26 00:27:15224 terminator, std::forward<A>(xs)..., *unit, sourceFile, sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19225 } else {
Peter Klauslercfbde712022-06-11 01:08:14226 return &unit->BeginIoStatement<ErroneousIoStatementState>(
Peter Klausler921316a2022-07-26 00:27:15227 terminator, iostat, unit, sourceFile, sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19228 }
peter klausler3b635712020-02-13 22:41:56229 }
peter klausler95696d52020-02-05 00:55:45230}
231
232Cookie IONAME(BeginExternalListOutput)(
233 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
peter klausler6a1c3ef2021-05-05 18:37:49234 return BeginExternalListIO<Direction::Output, ExternalListIoStatementState>(
Peter Klauslerdf38f352022-02-16 22:55:19235 unitNumber, sourceFile, sourceLine);
peter klausler3b635712020-02-13 22:41:56236}
237
238Cookie IONAME(BeginExternalListInput)(
239 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
peter klausler6a1c3ef2021-05-05 18:37:49240 return BeginExternalListIO<Direction::Input, ExternalListIoStatementState>(
Peter Klauslerdf38f352022-02-16 22:55:19241 unitNumber, sourceFile, sourceLine);
peter klausler3b635712020-02-13 22:41:56242}
243
Tim Keith1f879002020-03-29 04:00:16244template <Direction DIR>
peter klausler3b635712020-02-13 22:41:56245Cookie BeginExternalFormattedIO(const char *format, std::size_t formatLength,
V Donaldson27d666b2022-08-24 17:22:42246 const Descriptor *formatDescriptor, ExternalUnit unitNumber,
247 const char *sourceFile, int sourceLine) {
peter klausler95696d52020-02-05 00:55:45248 Terminator terminator{sourceFile, sourceLine};
peter klausler3b635712020-02-13 22:41:56249 if (unitNumber == DefaultUnit) {
250 unitNumber = DIR == Direction::Input ? 5 : 6;
peter klausler95696d52020-02-05 00:55:45251 }
Peter Klauslercfbde712022-06-11 01:08:14252 Cookie errorCookie{nullptr};
253 ExternalFileUnit *unit{GetOrCreateUnit(
254 unitNumber, DIR, false /*!unformatted*/, terminator, errorCookie)};
255 if (!unit) {
256 return errorCookie;
Peter Klauslerb1856002022-01-18 18:40:10257 }
Peter Klauslercfbde712022-06-11 01:08:14258 Iostat iostat{IostatOk};
259 if (!unit->isUnformatted.has_value()) {
260 unit->isUnformatted = false;
261 }
262 if (*unit->isUnformatted) {
Peter Klauslerdf38f352022-02-16 22:55:19263 iostat = IostatFormattedIoOnUnformattedUnit;
Peter Klauslerb1856002022-01-18 18:40:10264 }
Peter Klauslercfbde712022-06-11 01:08:14265 if (ChildIo * child{unit->GetChildIo()}) {
Peter Klauslerdf38f352022-02-16 22:55:19266 if (iostat == IostatOk) {
267 iostat = child->CheckFormattingAndDirection(false, DIR);
268 }
269 if (iostat == IostatOk) {
270 return &child->BeginIoStatement<ChildFormattedIoStatementState<DIR>>(
V Donaldson27d666b2022-08-24 17:22:42271 *child, format, formatLength, formatDescriptor, sourceFile,
272 sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19273 } else {
274 return &child->BeginIoStatement<ErroneousIoStatementState>(
Peter Klausler11f928a2022-06-02 20:33:10275 iostat, nullptr /* no unit */, sourceFile, sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19276 }
peter klausler43fadef2021-06-25 17:40:08277 } else {
Peter Klauslerdf38f352022-02-16 22:55:19278 if (iostat == IostatOk) {
Peter Klauslercfbde712022-06-11 01:08:14279 iostat = unit->SetDirection(DIR);
Peter Klauslerdf38f352022-02-16 22:55:19280 }
281 if (iostat == IostatOk) {
Peter Klauslercfbde712022-06-11 01:08:14282 return &unit->BeginIoStatement<ExternalFormattedIoStatementState<DIR>>(
V Donaldson27d666b2022-08-24 17:22:42283 terminator, *unit, format, formatLength, formatDescriptor, sourceFile,
284 sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19285 } else {
Peter Klauslercfbde712022-06-11 01:08:14286 return &unit->BeginIoStatement<ErroneousIoStatementState>(
Peter Klausler921316a2022-07-26 00:27:15287 terminator, iostat, unit, sourceFile, sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19288 }
peter klausler199a6232021-05-05 18:33:00289 }
peter klausler491122d2020-01-16 21:51:25290}
291
peter klauslerf7be2512020-01-24 00:59:27292Cookie IONAME(BeginExternalFormattedOutput)(const char *format,
V Donaldson27d666b2022-08-24 17:22:42293 std::size_t formatLength, const Descriptor *formatDescriptor,
294 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Peter Klauslercc180f42022-08-18 17:52:59295 return BeginExternalFormattedIO<Direction::Output>(format, formatLength,
V Donaldson27d666b2022-08-24 17:22:42296 formatDescriptor, unitNumber, sourceFile, sourceLine);
peter klausler95696d52020-02-05 00:55:45297}
298
peter klausler3b635712020-02-13 22:41:56299Cookie IONAME(BeginExternalFormattedInput)(const char *format,
V Donaldson27d666b2022-08-24 17:22:42300 std::size_t formatLength, const Descriptor *formatDescriptor,
301 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Peter Klauslercc180f42022-08-18 17:52:59302 return BeginExternalFormattedIO<Direction::Input>(format, formatLength,
V Donaldson27d666b2022-08-24 17:22:42303 formatDescriptor, unitNumber, sourceFile, sourceLine);
peter klausler3b635712020-02-13 22:41:56304}
305
Tim Keith1f879002020-03-29 04:00:16306template <Direction DIR>
peter klausler3b635712020-02-13 22:41:56307Cookie BeginUnformattedIO(
peter klausler95696d52020-02-05 00:55:45308 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
309 Terminator terminator{sourceFile, sourceLine};
Peter Klauslercfbde712022-06-11 01:08:14310 Cookie errorCookie{nullptr};
311 ExternalFileUnit *unit{GetOrCreateUnit(
312 unitNumber, DIR, true /*unformatted*/, terminator, errorCookie)};
313 if (!unit) {
314 return errorCookie;
Peter Klauslerb1856002022-01-18 18:40:10315 }
Peter Klauslercfbde712022-06-11 01:08:14316 Iostat iostat{IostatOk};
317 if (!unit->isUnformatted.has_value()) {
318 unit->isUnformatted = true;
319 }
320 if (!*unit->isUnformatted) {
Peter Klauslerdf38f352022-02-16 22:55:19321 iostat = IostatUnformattedIoOnFormattedUnit;
Peter Klauslerb1856002022-01-18 18:40:10322 }
Peter Klauslercfbde712022-06-11 01:08:14323 if (ChildIo * child{unit->GetChildIo()}) {
Peter Klauslerdf38f352022-02-16 22:55:19324 if (iostat == IostatOk) {
325 iostat = child->CheckFormattingAndDirection(true, DIR);
peter klausler43fadef2021-06-25 17:40:08326 }
Peter Klauslerdf38f352022-02-16 22:55:19327 if (iostat == IostatOk) {
328 return &child->BeginIoStatement<ChildUnformattedIoStatementState<DIR>>(
329 *child, sourceFile, sourceLine);
330 } else {
331 return &child->BeginIoStatement<ErroneousIoStatementState>(
Peter Klausler11f928a2022-06-02 20:33:10332 iostat, nullptr /* no unit */, sourceFile, sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19333 }
334 } else {
335 if (iostat == IostatOk) {
Peter Klauslercfbde712022-06-11 01:08:14336 iostat = unit->SetDirection(DIR);
Peter Klauslerdf38f352022-02-16 22:55:19337 }
338 if (iostat == IostatOk) {
339 IoStatementState &io{
Peter Klauslercfbde712022-06-11 01:08:14340 unit->BeginIoStatement<ExternalUnformattedIoStatementState<DIR>>(
Peter Klausler921316a2022-07-26 00:27:15341 terminator, *unit, sourceFile, sourceLine)};
Peter Klauslerdf38f352022-02-16 22:55:19342 if constexpr (DIR == Direction::Output) {
Peter Klauslercfbde712022-06-11 01:08:14343 if (unit->access == Access::Sequential) {
Peter Klauslerdf38f352022-02-16 22:55:19344 // Create space for (sub)record header to be completed by
345 // ExternalFileUnit::AdvanceRecord()
Peter Klauslercfbde712022-06-11 01:08:14346 unit->recordLength.reset(); // in case of prior BACKSPACE
Peter Klauslerdf38f352022-02-16 22:55:19347 io.Emit("\0\0\0\0", 4); // placeholder for record length header
348 }
349 }
350 return &io;
351 } else {
Peter Klauslercfbde712022-06-11 01:08:14352 return &unit->BeginIoStatement<ErroneousIoStatementState>(
Peter Klausler921316a2022-07-26 00:27:15353 terminator, iostat, unit, sourceFile, sourceLine);
Peter Klauslerdf38f352022-02-16 22:55:19354 }
peter klausler95696d52020-02-05 00:55:45355 }
peter klausler95696d52020-02-05 00:55:45356}
357
peter klausler3b635712020-02-13 22:41:56358Cookie IONAME(BeginUnformattedOutput)(
359 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
360 return BeginUnformattedIO<Direction::Output>(
361 unitNumber, sourceFile, sourceLine);
362}
363
364Cookie IONAME(BeginUnformattedInput)(
365 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
366 return BeginUnformattedIO<Direction::Input>(
367 unitNumber, sourceFile, sourceLine);
368}
369
Tim Keith1f879002020-03-29 04:00:16370Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=)
peter klausler95696d52020-02-05 00:55:45371 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
peter klausler3b635712020-02-13 22:41:56372 Terminator terminator{sourceFile, sourceLine};
Peter Klauslercfbde712022-06-11 01:08:14373 bool wasExtant{false};
374 if (ExternalFileUnit *
375 unit{ExternalFileUnit::LookUpOrCreate(
376 unitNumber, terminator, wasExtant)}) {
Peter Klausler79f6b812023-03-08 19:07:39377 if (ChildIo * child{unit->GetChildIo()}) {
378 return &child->BeginIoStatement<ErroneousIoStatementState>(
379 IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,
380 sourceLine);
381 } else {
Peter Klauslerafdbf1b2023-07-19 00:05:47382 return &unit->BeginIoStatement<OpenStatementState>(terminator, *unit,
383 wasExtant, false /*not NEWUNIT=*/, sourceFile, sourceLine);
Peter Klausler79f6b812023-03-08 19:07:39384 }
Peter Klauslercfbde712022-06-11 01:08:14385 } else {
Peter Klauslerc078e462022-06-22 20:24:51386 return NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
Peter Klauslercfbde712022-06-11 01:08:14387 }
peter klausler95696d52020-02-05 00:55:45388}
389
Tim Keith1f879002020-03-29 04:00:16390Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j)
peter klausler95696d52020-02-05 00:55:45391 const char *sourceFile, int sourceLine) {
peter klausler3b635712020-02-13 22:41:56392 Terminator terminator{sourceFile, sourceLine};
Peter Klauslerc7f4c332022-01-26 17:53:12393 ExternalFileUnit &unit{
394 ExternalFileUnit::NewUnit(terminator, false /*not child I/O*/)};
Peter Klauslerafdbf1b2023-07-19 00:05:47395 return &unit.BeginIoStatement<OpenStatementState>(terminator, unit,
396 false /*was an existing file*/, true /*NEWUNIT=*/, sourceFile,
397 sourceLine);
peter klausler95696d52020-02-05 00:55:45398}
399
Peter Klausler166d6ed2022-06-06 18:44:19400Cookie IONAME(BeginWait)(ExternalUnit unitNumber, AsynchronousId id,
401 const char *sourceFile, int sourceLine) {
Peter Klausler921316a2022-07-26 00:27:15402 Terminator terminator{sourceFile, sourceLine};
Peter Klausler166d6ed2022-06-06 18:44:19403 if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
404 if (unit->Wait(id)) {
Peter Klausler921316a2022-07-26 00:27:15405 return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,
Peter Klausler166d6ed2022-06-06 18:44:19406 *unit, ExternalMiscIoStatementState::Wait, sourceFile, sourceLine);
407 } else {
408 return &unit->BeginIoStatement<ErroneousIoStatementState>(
Peter Klausler921316a2022-07-26 00:27:15409 terminator, IostatBadWaitId, unit, sourceFile, sourceLine);
Peter Klausler166d6ed2022-06-06 18:44:19410 }
411 } else {
Peter Klauslerc078e462022-06-22 20:24:51412 return NoopUnit(
413 terminator, unitNumber, id == 0 ? IostatOk : IostatBadWaitUnit);
Peter Klauslerdeb62f52022-05-12 00:08:21414 }
Peter Klauslerdeb62f52022-05-12 00:08:21415}
Peter Klausler166d6ed2022-06-06 18:44:19416Cookie IONAME(BeginWaitAll)(
417 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Peter Klausler17853922022-06-15 23:53:56418 return IONAME(BeginWait)(unitNumber, 0 /*no ID=*/, sourceFile, sourceLine);
Peter Klauslerdeb62f52022-05-12 00:08:21419}
420
peter klausler95696d52020-02-05 00:55:45421Cookie IONAME(BeginClose)(
422 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Peter Klausler921316a2022-07-26 00:27:15423 Terminator terminator{sourceFile, sourceLine};
Peter Klausler79f6b812023-03-08 19:07:39424 if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
425 if (ChildIo * child{unit->GetChildIo()}) {
426 return &child->BeginIoStatement<ErroneousIoStatementState>(
427 IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,
428 sourceLine);
429 }
430 }
peter klausler3b635712020-02-13 22:41:56431 if (ExternalFileUnit * unit{ExternalFileUnit::LookUpForClose(unitNumber)}) {
peter klausler95696d52020-02-05 00:55:45432 return &unit->BeginIoStatement<CloseStatementState>(
Peter Klausler921316a2022-07-26 00:27:15433 terminator, *unit, sourceFile, sourceLine);
peter klausler95696d52020-02-05 00:55:45434 } else {
435 // CLOSE(UNIT=bad unit) is just a no-op
Peter Klauslerc078e462022-06-22 20:24:51436 return NoopUnit(terminator, unitNumber);
peter klausler95696d52020-02-05 00:55:45437 }
438}
439
peter klausler5d5b9682020-07-04 18:06:28440Cookie IONAME(BeginFlush)(
441 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Peter Klausler921316a2022-07-26 00:27:15442 Terminator terminator{sourceFile, sourceLine};
Peter Klausler9ddd0792022-01-12 23:48:06443 if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
Peter Klausler79f6b812023-03-08 19:07:39444 if (ChildIo * child{unit->GetChildIo()}) {
445 return &child->BeginIoStatement<ExternalMiscIoStatementState>(
446 *unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine);
447 } else {
448 return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,
449 *unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine);
450 }
Peter Klausler9ddd0792022-01-12 23:48:06451 } else {
Peter Klauslerc078e462022-06-22 20:24:51452 // FLUSH(UNIT=bad unit) is an error; an unconnected unit is a no-op
Peter Klauslerc078e462022-06-22 20:24:51453 return NoopUnit(terminator, unitNumber,
454 unitNumber >= 0 ? IostatOk : IostatBadFlushUnit);
Peter Klausler9ddd0792022-01-12 23:48:06455 }
peter klausler5d5b9682020-07-04 18:06:28456}
457
458Cookie IONAME(BeginBackspace)(
459 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
460 Terminator terminator{sourceFile, sourceLine};
Peter Klausler142db432022-06-09 21:31:03461 if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
Peter Klausler79f6b812023-03-08 19:07:39462 if (ChildIo * child{unit->GetChildIo()}) {
463 return &child->BeginIoStatement<ErroneousIoStatementState>(
464 IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,
465 sourceLine);
466 } else {
467 return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,
468 *unit, ExternalMiscIoStatementState::Backspace, sourceFile,
469 sourceLine);
470 }
Peter Klausler142db432022-06-09 21:31:03471 } else {
Peter Klauslerc078e462022-06-22 20:24:51472 return NoopUnit(terminator, unitNumber, IostatBadBackspaceUnit);
Peter Klausler142db432022-06-09 21:31:03473 }
peter klausler5d5b9682020-07-04 18:06:28474}
475
476Cookie IONAME(BeginEndfile)(
477 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
478 Terminator terminator{sourceFile, sourceLine};
Peter Klauslercfbde712022-06-11 01:08:14479 Cookie errorCookie{nullptr};
480 if (ExternalFileUnit *
481 unit{GetOrCreateUnit(unitNumber, Direction::Output, std::nullopt,
482 terminator, errorCookie)}) {
Peter Klausler79f6b812023-03-08 19:07:39483 if (ChildIo * child{unit->GetChildIo()}) {
484 return &child->BeginIoStatement<ErroneousIoStatementState>(
485 IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,
486 sourceLine);
487 } else {
488 return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,
489 *unit, ExternalMiscIoStatementState::Endfile, sourceFile, sourceLine);
490 }
Peter Klauslercfbde712022-06-11 01:08:14491 } else {
492 return errorCookie;
493 }
peter klausler5d5b9682020-07-04 18:06:28494}
495
496Cookie IONAME(BeginRewind)(
497 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
498 Terminator terminator{sourceFile, sourceLine};
Peter Klauslercfbde712022-06-11 01:08:14499 Cookie errorCookie{nullptr};
500 if (ExternalFileUnit *
501 unit{GetOrCreateUnit(unitNumber, Direction::Input, std::nullopt,
502 terminator, errorCookie)}) {
Peter Klausler79f6b812023-03-08 19:07:39503 if (ChildIo * child{unit->GetChildIo()}) {
504 return &child->BeginIoStatement<ErroneousIoStatementState>(
505 IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,
506 sourceLine);
507 } else {
508 return &unit->BeginIoStatement<ExternalMiscIoStatementState>(terminator,
509 *unit, ExternalMiscIoStatementState::Rewind, sourceFile, sourceLine);
510 }
Peter Klauslercfbde712022-06-11 01:08:14511 } else {
512 return errorCookie;
513 }
peter klausler5d5b9682020-07-04 18:06:28514}
515
peter klausler675ad1b2020-08-03 18:35:29516Cookie IONAME(BeginInquireUnit)(
517 ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Peter Klausler921316a2022-07-26 00:27:15518 Terminator terminator{sourceFile, sourceLine};
peter klausler675ad1b2020-08-03 18:35:29519 if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
Peter Klauslerb1856002022-01-18 18:40:10520 if (ChildIo * child{unit->GetChildIo()}) {
521 return &child->BeginIoStatement<InquireUnitState>(
522 *unit, sourceFile, sourceLine);
523 } else {
524 return &unit->BeginIoStatement<InquireUnitState>(
Peter Klausler921316a2022-07-26 00:27:15525 terminator, *unit, sourceFile, sourceLine);
Peter Klauslerb1856002022-01-18 18:40:10526 }
peter klausler675ad1b2020-08-03 18:35:29527 } else {
528 // INQUIRE(UNIT=unrecognized unit)
Peter Klausler921316a2022-07-26 00:27:15529 return &New<InquireNoUnitState>{terminator}(
530 sourceFile, sourceLine, unitNumber)
peter klausler675ad1b2020-08-03 18:35:29531 .release()
532 ->ioStatementState();
533 }
534}
535
536Cookie IONAME(BeginInquireFile)(const char *path, std::size_t pathLength,
537 const char *sourceFile, int sourceLine) {
Peter Klausler921316a2022-07-26 00:27:15538 Terminator terminator{sourceFile, sourceLine};
539 auto trimmed{SaveDefaultCharacter(
540 path, TrimTrailingSpaces(path, pathLength), terminator)};
Peter Klausler03c066a2022-06-03 20:44:13541 if (ExternalFileUnit *
542 unit{ExternalFileUnit::LookUp(
543 trimmed.get(), std::strlen(trimmed.get()))}) {
peter klausler675ad1b2020-08-03 18:35:29544 // INQUIRE(FILE=) to a connected unit
Peter Klausler79f6b812023-03-08 19:07:39545 if (ChildIo * child{unit->GetChildIo()}) {
546 return &child->BeginIoStatement<InquireUnitState>(
547 *unit, sourceFile, sourceLine);
548 } else {
549 return &unit->BeginIoStatement<InquireUnitState>(
550 terminator, *unit, sourceFile, sourceLine);
551 }
peter klausler675ad1b2020-08-03 18:35:29552 } else {
Peter Klausler921316a2022-07-26 00:27:15553 return &New<InquireUnconnectedFileState>{terminator}(
peter klausler675ad1b2020-08-03 18:35:29554 std::move(trimmed), sourceFile, sourceLine)
555 .release()
556 ->ioStatementState();
557 }
558}
559
560Cookie IONAME(BeginInquireIoLength)(const char *sourceFile, int sourceLine) {
561 Terminator oom{sourceFile, sourceLine};
562 return &New<InquireIOLengthState>{oom}(sourceFile, sourceLine)
563 .release()
564 ->ioStatementState();
565}
566
peter klausler95696d52020-02-05 00:55:45567// Control list items
568
peter klausler3b635712020-02-13 22:41:56569void IONAME(EnableHandlers)(Cookie cookie, bool hasIoStat, bool hasErr,
570 bool hasEnd, bool hasEor, bool hasIoMsg) {
peter klausler95696d52020-02-05 00:55:45571 IoErrorHandler &handler{cookie->GetIoErrorHandler()};
572 if (hasIoStat) {
573 handler.HasIoStat();
574 }
575 if (hasErr) {
576 handler.HasErrLabel();
577 }
578 if (hasEnd) {
579 handler.HasEndLabel();
580 }
581 if (hasEor) {
582 handler.HasEorLabel();
583 }
peter klausler3b635712020-02-13 22:41:56584 if (hasIoMsg) {
585 handler.HasIoMsg();
586 }
peter klausler95696d52020-02-05 00:55:45587}
588
589static bool YesOrNo(const char *keyword, std::size_t length, const char *what,
peter klausler3b635712020-02-13 22:41:56590 IoErrorHandler &handler) {
peter klausler95696d52020-02-05 00:55:45591 static const char *keywords[]{"YES", "NO", nullptr};
592 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16593 case 0:
594 return true;
595 case 1:
596 return false;
peter klausler95696d52020-02-05 00:55:45597 default:
peter klausler3b635712020-02-13 22:41:56598 handler.SignalError(IostatErrorInKeyword, "Invalid %s='%.*s'", what,
599 static_cast<int>(length), keyword);
peter klausler95696d52020-02-05 00:55:45600 return false;
601 }
602}
603
604bool IONAME(SetAdvance)(
605 Cookie cookie, const char *keyword, std::size_t length) {
606 IoStatementState &io{*cookie};
Peter Klauslerdeb62f52022-05-12 00:08:21607 IoErrorHandler &handler{io.GetIoErrorHandler()};
608 bool nonAdvancing{!YesOrNo(keyword, length, "ADVANCE", handler)};
peter klauslercd0a1222021-06-28 18:41:04609 if (nonAdvancing && io.GetConnectionState().access == Access::Direct) {
Peter Klauslerdeb62f52022-05-12 00:08:21610 handler.SignalError("Non-advancing I/O attempted on direct access file");
peter klauslercd0a1222021-06-28 18:41:04611 } else {
Peter Klausler79f6b812023-03-08 19:07:39612 auto *unit{io.GetExternalFileUnit()};
613 if (unit && unit->GetChildIo()) {
614 // ADVANCE= is ignored for child I/O (12.6.4.8.3 p3)
615 } else {
616 io.mutableModes().nonAdvancing = nonAdvancing;
617 }
peter klausler3b635712020-02-13 22:41:56618 }
Peter Klauslerdeb62f52022-05-12 00:08:21619 return !handler.InError();
peter klausler95696d52020-02-05 00:55:45620}
621
622bool IONAME(SetBlank)(Cookie cookie, const char *keyword, std::size_t length) {
623 IoStatementState &io{*cookie};
peter klausler95696d52020-02-05 00:55:45624 static const char *keywords[]{"NULL", "ZERO", nullptr};
625 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16626 case 0:
Peter Klausler2b0b9b22022-01-31 18:06:40627 io.mutableModes().editingFlags &= ~blankZero;
Tim Keith1f879002020-03-29 04:00:16628 return true;
629 case 1:
Peter Klausler2b0b9b22022-01-31 18:06:40630 io.mutableModes().editingFlags |= blankZero;
Tim Keith1f879002020-03-29 04:00:16631 return true;
peter klausler95696d52020-02-05 00:55:45632 default:
peter klausler3b635712020-02-13 22:41:56633 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:45634 "Invalid BLANK='%.*s'", static_cast<int>(length), keyword);
635 return false;
636 }
637}
638
639bool IONAME(SetDecimal)(
640 Cookie cookie, const char *keyword, std::size_t length) {
641 IoStatementState &io{*cookie};
peter klausler95696d52020-02-05 00:55:45642 static const char *keywords[]{"COMMA", "POINT", nullptr};
643 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16644 case 0:
Peter Klausler2b0b9b22022-01-31 18:06:40645 io.mutableModes().editingFlags |= decimalComma;
Tim Keith1f879002020-03-29 04:00:16646 return true;
647 case 1:
Peter Klausler2b0b9b22022-01-31 18:06:40648 io.mutableModes().editingFlags &= ~decimalComma;
Tim Keith1f879002020-03-29 04:00:16649 return true;
peter klausler95696d52020-02-05 00:55:45650 default:
peter klausler3b635712020-02-13 22:41:56651 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:45652 "Invalid DECIMAL='%.*s'", static_cast<int>(length), keyword);
653 return false;
654 }
655}
656
657bool IONAME(SetDelim)(Cookie cookie, const char *keyword, std::size_t length) {
658 IoStatementState &io{*cookie};
peter klausler95696d52020-02-05 00:55:45659 static const char *keywords[]{"APOSTROPHE", "QUOTE", "NONE", nullptr};
660 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16661 case 0:
Peter Klausler2b0b9b22022-01-31 18:06:40662 io.mutableModes().delim = '\'';
Tim Keith1f879002020-03-29 04:00:16663 return true;
664 case 1:
Peter Klausler2b0b9b22022-01-31 18:06:40665 io.mutableModes().delim = '"';
Tim Keith1f879002020-03-29 04:00:16666 return true;
667 case 2:
Peter Klausler2b0b9b22022-01-31 18:06:40668 io.mutableModes().delim = '\0';
Tim Keith1f879002020-03-29 04:00:16669 return true;
peter klausler95696d52020-02-05 00:55:45670 default:
peter klausler3b635712020-02-13 22:41:56671 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:45672 "Invalid DELIM='%.*s'", static_cast<int>(length), keyword);
673 return false;
674 }
675}
676
677bool IONAME(SetPad)(Cookie cookie, const char *keyword, std::size_t length) {
678 IoStatementState &io{*cookie};
Peter Klauslerdeb62f52022-05-12 00:08:21679 IoErrorHandler &handler{io.GetIoErrorHandler()};
680 io.mutableModes().pad = YesOrNo(keyword, length, "PAD", handler);
681 return !handler.InError();
peter klausler95696d52020-02-05 00:55:45682}
683
peter klausler3b635712020-02-13 22:41:56684bool IONAME(SetPos)(Cookie cookie, std::int64_t pos) {
685 IoStatementState &io{*cookie};
Peter Klausler991696c2022-01-28 23:34:28686 IoErrorHandler &handler{io.GetIoErrorHandler()};
peter klausler3b635712020-02-13 22:41:56687 if (auto *unit{io.GetExternalFileUnit()}) {
Peter Klauslerd7712452022-06-17 18:20:29688 return unit->SetStreamPos(pos, handler);
Peter Klausler2a07db42022-06-06 22:59:01689 } else if (!io.get_if<ErroneousIoStatementState>()) {
Peter Klauslerd7712452022-06-17 18:20:29690 handler.Crash("SetPos() called on internal unit");
peter klausler3b635712020-02-13 22:41:56691 }
peter klausler3b635712020-02-13 22:41:56692 return false;
693}
694
695bool IONAME(SetRec)(Cookie cookie, std::int64_t rec) {
696 IoStatementState &io{*cookie};
Peter Klausler991696c2022-01-28 23:34:28697 IoErrorHandler &handler{io.GetIoErrorHandler()};
peter klausler3b635712020-02-13 22:41:56698 if (auto *unit{io.GetExternalFileUnit()}) {
Peter Klausler79f6b812023-03-08 19:07:39699 if (unit->GetChildIo()) {
700 handler.SignalError(
701 IostatBadOpOnChildUnit, "REC= specifier on child I/O");
702 } else {
703 unit->SetDirectRec(rec, handler);
704 }
Peter Klauslerd7712452022-06-17 18:20:29705 } else if (!io.get_if<ErroneousIoStatementState>()) {
706 handler.Crash("SetRec() called on internal unit");
peter klausler3b635712020-02-13 22:41:56707 }
708 return true;
709}
peter klausler95696d52020-02-05 00:55:45710
711bool IONAME(SetRound)(Cookie cookie, const char *keyword, std::size_t length) {
712 IoStatementState &io{*cookie};
peter klausler95696d52020-02-05 00:55:45713 static const char *keywords[]{"UP", "DOWN", "ZERO", "NEAREST", "COMPATIBLE",
714 "PROCESSOR_DEFINED", nullptr};
715 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16716 case 0:
Peter Klausler2b0b9b22022-01-31 18:06:40717 io.mutableModes().round = decimal::RoundUp;
Tim Keith1f879002020-03-29 04:00:16718 return true;
719 case 1:
Peter Klausler2b0b9b22022-01-31 18:06:40720 io.mutableModes().round = decimal::RoundDown;
Tim Keith1f879002020-03-29 04:00:16721 return true;
722 case 2:
Peter Klausler2b0b9b22022-01-31 18:06:40723 io.mutableModes().round = decimal::RoundToZero;
Tim Keith1f879002020-03-29 04:00:16724 return true;
725 case 3:
Peter Klausler2b0b9b22022-01-31 18:06:40726 io.mutableModes().round = decimal::RoundNearest;
Tim Keith1f879002020-03-29 04:00:16727 return true;
728 case 4:
Peter Klausler2b0b9b22022-01-31 18:06:40729 io.mutableModes().round = decimal::RoundCompatible;
Tim Keith1f879002020-03-29 04:00:16730 return true;
peter klausler95696d52020-02-05 00:55:45731 case 5:
Peter Klausler2b0b9b22022-01-31 18:06:40732 io.mutableModes().round = executionEnvironment.defaultOutputRoundingMode;
peter klausler95696d52020-02-05 00:55:45733 return true;
734 default:
peter klausler3b635712020-02-13 22:41:56735 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:45736 "Invalid ROUND='%.*s'", static_cast<int>(length), keyword);
737 return false;
738 }
739}
740
741bool IONAME(SetSign)(Cookie cookie, const char *keyword, std::size_t length) {
742 IoStatementState &io{*cookie};
Peter Klausler5501c162022-01-11 22:54:31743 static const char *keywords[]{
744 "PLUS", "SUPPRESS", "PROCESSOR_DEFINED", nullptr};
peter klausler95696d52020-02-05 00:55:45745 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16746 case 0:
Peter Klausler2b0b9b22022-01-31 18:06:40747 io.mutableModes().editingFlags |= signPlus;
Tim Keith1f879002020-03-29 04:00:16748 return true;
peter klausler95696d52020-02-05 00:55:45749 case 1:
Tim Keith1f879002020-03-29 04:00:16750 case 2: // processor default is SS
Peter Klausler2b0b9b22022-01-31 18:06:40751 io.mutableModes().editingFlags &= ~signPlus;
peter klausler95696d52020-02-05 00:55:45752 return true;
753 default:
peter klausler3b635712020-02-13 22:41:56754 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:45755 "Invalid SIGN='%.*s'", static_cast<int>(length), keyword);
756 return false;
757 }
758}
759
760bool IONAME(SetAccess)(Cookie cookie, const char *keyword, std::size_t length) {
761 IoStatementState &io{*cookie};
762 auto *open{io.get_if<OpenStatementState>()};
763 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:01764 if (!io.get_if<ErroneousIoStatementState>()) {
765 io.GetIoErrorHandler().Crash(
766 "SetAccess() called when not in an OPEN statement");
767 }
768 return false;
Peter Klausler8db4dc82022-03-14 20:39:50769 } else if (open->completedOperation()) {
770 io.GetIoErrorHandler().Crash(
771 "SetAccess() called after GetNewUnit() for an OPEN statement");
peter klausler95696d52020-02-05 00:55:45772 }
peter klausler72abc192021-05-12 19:03:21773 static const char *keywords[]{
774 "SEQUENTIAL", "DIRECT", "STREAM", "APPEND", nullptr};
peter klausler95696d52020-02-05 00:55:45775 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16776 case 0:
peter klausler675ad1b2020-08-03 18:35:29777 open->set_access(Access::Sequential);
Tim Keith1f879002020-03-29 04:00:16778 break;
779 case 1:
peter klausler675ad1b2020-08-03 18:35:29780 open->set_access(Access::Direct);
Tim Keith1f879002020-03-29 04:00:16781 break;
782 case 2:
peter klausler675ad1b2020-08-03 18:35:29783 open->set_access(Access::Stream);
Tim Keith1f879002020-03-29 04:00:16784 break;
peter klausler72abc192021-05-12 19:03:21785 case 3: // Sun Fortran extension ACCESS=APPEND: treat as if POSITION=APPEND
786 open->set_position(Position::Append);
787 break;
peter klausler95696d52020-02-05 00:55:45788 default:
peter klausler3b635712020-02-13 22:41:56789 open->SignalError(IostatErrorInKeyword, "Invalid ACCESS='%.*s'",
790 static_cast<int>(length), keyword);
peter klausler95696d52020-02-05 00:55:45791 }
peter klausler95696d52020-02-05 00:55:45792 return true;
793}
794
795bool IONAME(SetAction)(Cookie cookie, const char *keyword, std::size_t length) {
796 IoStatementState &io{*cookie};
797 auto *open{io.get_if<OpenStatementState>()};
798 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:01799 if (!io.get_if<ErroneousIoStatementState>()) {
800 io.GetIoErrorHandler().Crash(
801 "SetAction() called when not in an OPEN statement");
802 }
803 return false;
Peter Klausler8db4dc82022-03-14 20:39:50804 } else if (open->completedOperation()) {
805 io.GetIoErrorHandler().Crash(
806 "SetAction() called after GetNewUnit() for an OPEN statement");
peter klausler95696d52020-02-05 00:55:45807 }
peter klauslerea4758a2020-07-17 18:24:29808 std::optional<Action> action;
peter klausler95696d52020-02-05 00:55:45809 static const char *keywords[]{"READ", "WRITE", "READWRITE", nullptr};
810 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16811 case 0:
peter klauslerea4758a2020-07-17 18:24:29812 action = Action::Read;
Tim Keith1f879002020-03-29 04:00:16813 break;
814 case 1:
peter klauslerea4758a2020-07-17 18:24:29815 action = Action::Write;
Tim Keith1f879002020-03-29 04:00:16816 break;
817 case 2:
peter klauslerea4758a2020-07-17 18:24:29818 action = Action::ReadWrite;
Tim Keith1f879002020-03-29 04:00:16819 break;
peter klausler95696d52020-02-05 00:55:45820 default:
peter klausler3b635712020-02-13 22:41:56821 open->SignalError(IostatErrorInKeyword, "Invalid ACTION='%.*s'",
822 static_cast<int>(length), keyword);
peter klausler95696d52020-02-05 00:55:45823 return false;
824 }
peter klauslerea4758a2020-07-17 18:24:29825 RUNTIME_CHECK(io.GetIoErrorHandler(), action.has_value());
826 if (open->wasExtant()) {
827 if ((*action != Action::Write) != open->unit().mayRead() ||
828 (*action != Action::Read) != open->unit().mayWrite()) {
peter klausler3b635712020-02-13 22:41:56829 open->SignalError("ACTION= may not be changed on an open unit");
peter klausler95696d52020-02-05 00:55:45830 }
peter klausler95696d52020-02-05 00:55:45831 }
peter klauslerea4758a2020-07-17 18:24:29832 open->set_action(*action);
peter klausler95696d52020-02-05 00:55:45833 return true;
834}
835
836bool IONAME(SetAsynchronous)(
837 Cookie cookie, const char *keyword, std::size_t length) {
838 IoStatementState &io{*cookie};
Peter Klauslerdeb62f52022-05-12 00:08:21839 IoErrorHandler &handler{io.GetIoErrorHandler()};
840 bool isYes{YesOrNo(keyword, length, "ASYNCHRONOUS", handler)};
841 if (auto *open{io.get_if<OpenStatementState>()}) {
842 if (open->completedOperation()) {
843 handler.Crash(
844 "SetAsynchronous() called after GetNewUnit() for an OPEN statement");
845 }
846 open->unit().set_mayAsynchronous(isYes);
Peter Klausler166d6ed2022-06-06 18:44:19847 } else if (auto *ext{io.get_if<ExternalIoStatementBase>()}) {
848 if (isYes) {
849 if (ext->unit().mayAsynchronous()) {
850 ext->SetAsynchronous();
851 } else {
852 handler.SignalError(IostatBadAsynchronous);
853 }
Peter Klauslerdeb62f52022-05-12 00:08:21854 }
Peter Klausler2a07db42022-06-06 22:59:01855 } else if (!io.get_if<ErroneousIoStatementState>()) {
Peter Klauslerdeb62f52022-05-12 00:08:21856 handler.Crash("SetAsynchronous() called when not in an OPEN or external "
857 "I/O statement");
peter klausler95696d52020-02-05 00:55:45858 }
Peter Klauslerdeb62f52022-05-12 00:08:21859 return !handler.InError();
peter klausler95696d52020-02-05 00:55:45860}
861
peter klauslerc9637572020-09-02 17:37:48862bool IONAME(SetCarriagecontrol)(
863 Cookie cookie, const char *keyword, std::size_t length) {
864 IoStatementState &io{*cookie};
865 auto *open{io.get_if<OpenStatementState>()};
866 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:01867 if (!io.get_if<ErroneousIoStatementState>()) {
868 io.GetIoErrorHandler().Crash(
869 "SetCarriageControl() called when not in an OPEN statement");
870 }
871 return false;
Peter Klausler8db4dc82022-03-14 20:39:50872 } else if (open->completedOperation()) {
873 io.GetIoErrorHandler().Crash(
874 "SetCarriageControl() called after GetNewUnit() for an OPEN statement");
peter klauslerc9637572020-09-02 17:37:48875 }
876 static const char *keywords[]{"LIST", "FORTRAN", "NONE", nullptr};
877 switch (IdentifyValue(keyword, length, keywords)) {
878 case 0:
879 return true;
880 case 1:
881 case 2:
882 open->SignalError(IostatErrorInKeyword,
883 "Unimplemented CARRIAGECONTROL='%.*s'", static_cast<int>(length),
884 keyword);
885 return false;
886 default:
887 open->SignalError(IostatErrorInKeyword, "Invalid CARRIAGECONTROL='%.*s'",
888 static_cast<int>(length), keyword);
889 return false;
890 }
891}
892
peter klausler8f2c5c42020-07-22 00:37:35893bool IONAME(SetConvert)(
894 Cookie cookie, const char *keyword, std::size_t length) {
895 IoStatementState &io{*cookie};
896 auto *open{io.get_if<OpenStatementState>()};
897 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:01898 if (!io.get_if<ErroneousIoStatementState>()) {
899 io.GetIoErrorHandler().Crash(
900 "SetConvert() called when not in an OPEN statement");
901 }
902 return false;
Peter Klausler8db4dc82022-03-14 20:39:50903 } else if (open->completedOperation()) {
904 io.GetIoErrorHandler().Crash(
905 "SetConvert() called after GetNewUnit() for an OPEN statement");
peter klausler8f2c5c42020-07-22 00:37:35906 }
907 if (auto convert{GetConvertFromString(keyword, length)}) {
908 open->set_convert(*convert);
909 return true;
910 } else {
911 open->SignalError(IostatErrorInKeyword, "Invalid CONVERT='%.*s'",
912 static_cast<int>(length), keyword);
913 return false;
914 }
915}
916
peter klausler95696d52020-02-05 00:55:45917bool IONAME(SetEncoding)(
918 Cookie cookie, const char *keyword, std::size_t length) {
919 IoStatementState &io{*cookie};
920 auto *open{io.get_if<OpenStatementState>()};
921 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:01922 if (!io.get_if<ErroneousIoStatementState>()) {
923 io.GetIoErrorHandler().Crash(
924 "SetEncoding() called when not in an OPEN statement");
925 }
926 return false;
Peter Klausler8db4dc82022-03-14 20:39:50927 } else if (open->completedOperation()) {
928 io.GetIoErrorHandler().Crash(
929 "SetEncoding() called after GetNewUnit() for an OPEN statement");
peter klausler95696d52020-02-05 00:55:45930 }
Peter Klauslerc9b31da2023-06-29 22:19:23931 // Allow the encoding to be changed on an open unit -- it's
932 // useful and safe.
peter klausler95696d52020-02-05 00:55:45933 static const char *keywords[]{"UTF-8", "DEFAULT", nullptr};
934 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16935 case 0:
Peter Klauslerc9b31da2023-06-29 22:19:23936 open->unit().isUTF8 = true;
Tim Keith1f879002020-03-29 04:00:16937 break;
938 case 1:
Peter Klauslerc9b31da2023-06-29 22:19:23939 open->unit().isUTF8 = false;
Tim Keith1f879002020-03-29 04:00:16940 break;
peter klausler95696d52020-02-05 00:55:45941 default:
peter klausler3b635712020-02-13 22:41:56942 open->SignalError(IostatErrorInKeyword, "Invalid ENCODING='%.*s'",
943 static_cast<int>(length), keyword);
peter klausler95696d52020-02-05 00:55:45944 }
peter klausler95696d52020-02-05 00:55:45945 return true;
946}
947
948bool IONAME(SetForm)(Cookie cookie, const char *keyword, std::size_t length) {
949 IoStatementState &io{*cookie};
950 auto *open{io.get_if<OpenStatementState>()};
951 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:01952 if (!io.get_if<ErroneousIoStatementState>()) {
953 io.GetIoErrorHandler().Crash(
954 "SetForm() called when not in an OPEN statement");
955 }
Peter Klausler8db4dc82022-03-14 20:39:50956 } else if (open->completedOperation()) {
957 io.GetIoErrorHandler().Crash(
958 "SetForm() called after GetNewUnit() for an OPEN statement");
peter klausler95696d52020-02-05 00:55:45959 }
peter klausler95696d52020-02-05 00:55:45960 static const char *keywords[]{"FORMATTED", "UNFORMATTED", nullptr};
961 switch (IdentifyValue(keyword, length, keywords)) {
Tim Keith1f879002020-03-29 04:00:16962 case 0:
peter klausler675ad1b2020-08-03 18:35:29963 open->set_isUnformatted(false);
Tim Keith1f879002020-03-29 04:00:16964 break;
965 case 1:
peter klausler675ad1b2020-08-03 18:35:29966 open->set_isUnformatted(true);
Tim Keith1f879002020-03-29 04:00:16967 break;
peter klausler95696d52020-02-05 00:55:45968 default:
peter klausler3b635712020-02-13 22:41:56969 open->SignalError(IostatErrorInKeyword, "Invalid FORM='%.*s'",
970 static_cast<int>(length), keyword);
peter klausler95696d52020-02-05 00:55:45971 }
peter klausler95696d52020-02-05 00:55:45972 return true;
973}
974
975bool IONAME(SetPosition)(
976 Cookie cookie, const char *keyword, std::size_t length) {
977 IoStatementState &io{*cookie};
978 auto *open{io.get_if<OpenStatementState>()};
979 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:01980 if (!io.get_if<ErroneousIoStatementState>()) {
981 io.GetIoErrorHandler().Crash(
982 "SetPosition() called when not in an OPEN statement");
983 }
984 return false;
Peter Klausler8db4dc82022-03-14 20:39:50985 } else if (open->completedOperation()) {
986 io.GetIoErrorHandler().Crash(
987 "SetPosition() called after GetNewUnit() for an OPEN statement");
peter klausler95696d52020-02-05 00:55:45988 }
989 static const char *positions[]{"ASIS", "REWIND", "APPEND", nullptr};
990 switch (IdentifyValue(keyword, length, positions)) {
Tim Keith1f879002020-03-29 04:00:16991 case 0:
992 open->set_position(Position::AsIs);
993 return true;
994 case 1:
995 open->set_position(Position::Rewind);
996 return true;
997 case 2:
998 open->set_position(Position::Append);
999 return true;
peter klausler95696d52020-02-05 00:55:451000 default:
peter klausler3b635712020-02-13 22:41:561001 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:451002 "Invalid POSITION='%.*s'", static_cast<int>(length), keyword);
1003 }
1004 return true;
1005}
1006
1007bool IONAME(SetRecl)(Cookie cookie, std::size_t n) {
1008 IoStatementState &io{*cookie};
1009 auto *open{io.get_if<OpenStatementState>()};
1010 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:011011 if (!io.get_if<ErroneousIoStatementState>()) {
1012 io.GetIoErrorHandler().Crash(
1013 "SetRecl() called when not in an OPEN statement");
1014 }
1015 return false;
Peter Klausler8db4dc82022-03-14 20:39:501016 } else if (open->completedOperation()) {
1017 io.GetIoErrorHandler().Crash(
1018 "SetRecl() called after GetNewUnit() for an OPEN statement");
peter klausler95696d52020-02-05 00:55:451019 }
peter klausler3b635712020-02-13 22:41:561020 if (n <= 0) {
1021 io.GetIoErrorHandler().SignalError("RECL= must be greater than zero");
Peter Klauslere847b302022-01-10 20:04:301022 return false;
1023 } else if (open->wasExtant() &&
1024 open->unit().openRecl.value_or(0) != static_cast<std::int64_t>(n)) {
peter klausler3b635712020-02-13 22:41:561025 open->SignalError("RECL= may not be changed for an open unit");
Peter Klauslere847b302022-01-10 20:04:301026 return false;
1027 } else {
1028 open->unit().openRecl = n;
1029 return true;
peter klausler95696d52020-02-05 00:55:451030 }
peter klausler95696d52020-02-05 00:55:451031}
1032
1033bool IONAME(SetStatus)(Cookie cookie, const char *keyword, std::size_t length) {
1034 IoStatementState &io{*cookie};
1035 if (auto *open{io.get_if<OpenStatementState>()}) {
Peter Klausler8db4dc82022-03-14 20:39:501036 if (open->completedOperation()) {
1037 io.GetIoErrorHandler().Crash(
1038 "SetStatus() called after GetNewUnit() for an OPEN statement");
1039 }
peter klausler95696d52020-02-05 00:55:451040 static const char *statuses[]{
1041 "OLD", "NEW", "SCRATCH", "REPLACE", "UNKNOWN", nullptr};
1042 switch (IdentifyValue(keyword, length, statuses)) {
Tim Keith1f879002020-03-29 04:00:161043 case 0:
1044 open->set_status(OpenStatus::Old);
1045 return true;
1046 case 1:
1047 open->set_status(OpenStatus::New);
1048 return true;
1049 case 2:
1050 open->set_status(OpenStatus::Scratch);
1051 return true;
1052 case 3:
1053 open->set_status(OpenStatus::Replace);
1054 return true;
1055 case 4:
1056 open->set_status(OpenStatus::Unknown);
1057 return true;
peter klausler95696d52020-02-05 00:55:451058 default:
peter klausler3b635712020-02-13 22:41:561059 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:451060 "Invalid STATUS='%.*s'", static_cast<int>(length), keyword);
1061 }
1062 return false;
1063 }
1064 if (auto *close{io.get_if<CloseStatementState>()}) {
1065 static const char *statuses[]{"KEEP", "DELETE", nullptr};
1066 switch (IdentifyValue(keyword, length, statuses)) {
Tim Keith1f879002020-03-29 04:00:161067 case 0:
1068 close->set_status(CloseStatus::Keep);
1069 return true;
1070 case 1:
1071 close->set_status(CloseStatus::Delete);
1072 return true;
peter klausler95696d52020-02-05 00:55:451073 default:
peter klausler3b635712020-02-13 22:41:561074 io.GetIoErrorHandler().SignalError(IostatErrorInKeyword,
peter klausler95696d52020-02-05 00:55:451075 "Invalid STATUS='%.*s'", static_cast<int>(length), keyword);
1076 }
1077 return false;
1078 }
Peter Klausler2a07db42022-06-06 22:59:011079 if (io.get_if<NoopStatementState>() ||
1080 io.get_if<ErroneousIoStatementState>()) {
Tim Keith1f879002020-03-29 04:00:161081 return true; // don't bother validating STATUS= in a no-op CLOSE
peter klausler95696d52020-02-05 00:55:451082 }
1083 io.GetIoErrorHandler().Crash(
1084 "SetStatus() called when not in an OPEN or CLOSE statement");
1085}
1086
peter klausler675ad1b2020-08-03 18:35:291087bool IONAME(SetFile)(Cookie cookie, const char *path, std::size_t chars) {
peter klausler95696d52020-02-05 00:55:451088 IoStatementState &io{*cookie};
1089 if (auto *open{io.get_if<OpenStatementState>()}) {
Peter Klausler8db4dc82022-03-14 20:39:501090 if (open->completedOperation()) {
1091 io.GetIoErrorHandler().Crash(
1092 "SetFile() called after GetNewUnit() for an OPEN statement");
1093 }
peter klausler675ad1b2020-08-03 18:35:291094 open->set_path(path, chars);
peter klausler95696d52020-02-05 00:55:451095 return true;
Peter Klausler2a07db42022-06-06 22:59:011096 } else if (!io.get_if<ErroneousIoStatementState>()) {
1097 io.GetIoErrorHandler().Crash(
1098 "SetFile() called when not in an OPEN statement");
peter klausler95696d52020-02-05 00:55:451099 }
peter klausler95696d52020-02-05 00:55:451100 return false;
1101}
1102
peter klausler95696d52020-02-05 00:55:451103bool IONAME(GetNewUnit)(Cookie cookie, int &unit, int kind) {
1104 IoStatementState &io{*cookie};
1105 auto *open{io.get_if<OpenStatementState>()};
1106 if (!open) {
Peter Klausler2a07db42022-06-06 22:59:011107 if (!io.get_if<ErroneousIoStatementState>()) {
1108 io.GetIoErrorHandler().Crash(
1109 "GetNewUnit() called when not in an OPEN statement");
1110 }
1111 return false;
Peter Klausler8db4dc82022-03-14 20:39:501112 } else if (!open->InError()) {
1113 open->CompleteOperation();
1114 }
1115 if (open->InError()) {
1116 // A failed OPEN(NEWUNIT=n) does not modify 'n'
1117 return false;
peter klausler95696d52020-02-05 00:55:451118 }
Peter Klausler73b193a2022-02-16 21:26:441119 std::int64_t result{open->unit().unitNumber()};
1120 if (!SetInteger(unit, kind, result)) {
Peter Steinfelde3550f12022-03-11 22:01:071121 open->SignalError("GetNewUnit(): bad INTEGER kind(%d) or out-of-range "
Peter Klausler73b193a2022-02-16 21:26:441122 "value(%jd) for result",
1123 kind, static_cast<std::intmax_t>(result));
peter klausler95696d52020-02-05 00:55:451124 }
1125 return true;
1126}
1127
1128// Data transfers
peter klausler95696d52020-02-05 00:55:451129
peter klauslercc011942020-08-07 00:30:011130bool IONAME(OutputDescriptor)(Cookie cookie, const Descriptor &descriptor) {
1131 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
peter klausler95696d52020-02-05 00:55:451132}
1133
peter klauslercc011942020-08-07 00:30:011134bool IONAME(InputDescriptor)(Cookie cookie, const Descriptor &descriptor) {
1135 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klausler8f2c5c42020-07-22 00:37:351136}
1137
1138bool IONAME(OutputUnformattedBlock)(Cookie cookie, const char *x,
1139 std::size_t length, std::size_t elementBytes) {
peter klausler95696d52020-02-05 00:55:451140 IoStatementState &io{*cookie};
peter klausler43fadef2021-06-25 17:40:081141 if (auto *unf{io.get_if<
1142 ExternalUnformattedIoStatementState<Direction::Output>>()}) {
peter klausler8f2c5c42020-07-22 00:37:351143 return unf->Emit(x, length, elementBytes);
peter klausler4393e372021-09-20 17:52:391144 } else if (auto *inq{io.get_if<InquireIOLengthState>()}) {
1145 return inq->Emit(x, length, elementBytes);
Peter Klausler2a07db42022-06-06 22:59:011146 } else if (!io.get_if<ErroneousIoStatementState>()) {
1147 io.GetIoErrorHandler().Crash("OutputUnformattedBlock() called for an I/O "
1148 "statement that is not unformatted output");
peter klausler95696d52020-02-05 00:55:451149 }
peter klausler5d5b9682020-07-04 18:06:281150 return false;
1151}
1152
peter klausler8f2c5c42020-07-22 00:37:351153bool IONAME(InputUnformattedBlock)(
1154 Cookie cookie, char *x, std::size_t length, std::size_t elementBytes) {
peter klausler5d5b9682020-07-04 18:06:281155 IoStatementState &io{*cookie};
Peter Klausler8db4dc82022-03-14 20:39:501156 IoErrorHandler &handler{io.GetIoErrorHandler()};
peter klauslerd879ac82020-08-03 18:31:131157 io.BeginReadingRecord();
Peter Klausler8db4dc82022-03-14 20:39:501158 if (handler.InError()) {
peter klauslere81c96d2021-04-13 23:07:581159 return false;
1160 }
peter klausler43fadef2021-06-25 17:40:081161 if (auto *unf{
1162 io.get_if<ExternalUnformattedIoStatementState<Direction::Input>>()}) {
peter klausler8f2c5c42020-07-22 00:37:351163 return unf->Receive(x, length, elementBytes);
Peter Klausler2a07db42022-06-06 22:59:011164 } else if (!io.get_if<ErroneousIoStatementState>()) {
1165 handler.Crash("InputUnformattedBlock() called for an I/O statement that is "
1166 "not unformatted input");
peter klausler5d5b9682020-07-04 18:06:281167 }
peter klausler95696d52020-02-05 00:55:451168 return false;
peter klauslerf7be2512020-01-24 00:59:271169}
1170
peter klauslerf65f8302021-10-11 22:41:141171bool IONAME(OutputInteger8)(Cookie cookie, std::int8_t n) {
Peter Klausler2a07db42022-06-06 22:59:011172 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger8")) {
1173 return false;
1174 }
peter klauslerf65f8302021-10-11 22:41:141175 StaticDescriptor staticDescriptor;
1176 Descriptor &descriptor{staticDescriptor.descriptor()};
1177 descriptor.Establish(
1178 TypeCategory::Integer, 1, reinterpret_cast<void *>(&n), 0);
1179 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1180}
1181
1182bool IONAME(OutputInteger16)(Cookie cookie, std::int16_t n) {
Peter Klausler2a07db42022-06-06 22:59:011183 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger16")) {
1184 return false;
1185 }
peter klauslerf65f8302021-10-11 22:41:141186 StaticDescriptor staticDescriptor;
1187 Descriptor &descriptor{staticDescriptor.descriptor()};
1188 descriptor.Establish(
1189 TypeCategory::Integer, 2, reinterpret_cast<void *>(&n), 0);
1190 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1191}
1192
1193bool IONAME(OutputInteger32)(Cookie cookie, std::int32_t n) {
Peter Klausler2a07db42022-06-06 22:59:011194 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger32")) {
1195 return false;
1196 }
peter klauslerf65f8302021-10-11 22:41:141197 StaticDescriptor staticDescriptor;
1198 Descriptor &descriptor{staticDescriptor.descriptor()};
1199 descriptor.Establish(
1200 TypeCategory::Integer, 4, reinterpret_cast<void *>(&n), 0);
1201 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1202}
1203
peter klauslerf7be2512020-01-24 00:59:271204bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) {
Peter Klausler2a07db42022-06-06 22:59:011205 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger64")) {
1206 return false;
1207 }
peter klauslercc011942020-08-07 00:30:011208 StaticDescriptor staticDescriptor;
1209 Descriptor &descriptor{staticDescriptor.descriptor()};
1210 descriptor.Establish(
peter klauslerf65f8302021-10-11 22:41:141211 TypeCategory::Integer, 8, reinterpret_cast<void *>(&n), 0);
peter klauslercc011942020-08-07 00:30:011212 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
peter klausler3b635712020-02-13 22:41:561213}
1214
peter klauslerf65f8302021-10-11 22:41:141215#ifdef __SIZEOF_INT128__
1216bool IONAME(OutputInteger128)(Cookie cookie, common::int128_t n) {
Peter Klausler2a07db42022-06-06 22:59:011217 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger128")) {
1218 return false;
1219 }
peter klauslerf65f8302021-10-11 22:41:141220 StaticDescriptor staticDescriptor;
1221 Descriptor &descriptor{staticDescriptor.descriptor()};
1222 descriptor.Establish(
1223 TypeCategory::Integer, 16, reinterpret_cast<void *>(&n), 0);
1224 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
1225}
1226#endif
1227
peter klausler3b635712020-02-13 22:41:561228bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
Peter Klausler2a07db42022-06-06 22:59:011229 if (!cookie->CheckFormattedStmtType<Direction::Input>("InputInteger")) {
1230 return false;
1231 }
peter klauslercc011942020-08-07 00:30:011232 StaticDescriptor staticDescriptor;
1233 Descriptor &descriptor{staticDescriptor.descriptor()};
1234 descriptor.Establish(
1235 TypeCategory::Integer, kind, reinterpret_cast<void *>(&n), 0);
1236 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klausler3bc2ae92020-07-23 00:01:221237}
1238
1239bool IONAME(OutputReal32)(Cookie cookie, float x) {
Peter Klausler2a07db42022-06-06 22:59:011240 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputReal32")) {
1241 return false;
1242 }
peter klauslercc011942020-08-07 00:30:011243 StaticDescriptor staticDescriptor;
1244 Descriptor &descriptor{staticDescriptor.descriptor()};
1245 descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
1246 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
peter klausler3bc2ae92020-07-23 00:01:221247}
1248
1249bool IONAME(OutputReal64)(Cookie cookie, double x) {
Peter Klausler2a07db42022-06-06 22:59:011250 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputReal64")) {
1251 return false;
1252 }
peter klauslercc011942020-08-07 00:30:011253 StaticDescriptor staticDescriptor;
1254 Descriptor &descriptor{staticDescriptor.descriptor()};
1255 descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
1256 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
Zachary Selk4b9b64d2020-07-07 19:33:311257}
1258
1259bool IONAME(InputReal32)(Cookie cookie, float &x) {
Peter Klausler2a07db42022-06-06 22:59:011260 if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal32")) {
1261 return false;
1262 }
peter klauslercc011942020-08-07 00:30:011263 StaticDescriptor staticDescriptor;
1264 Descriptor &descriptor{staticDescriptor.descriptor()};
1265 descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
1266 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klausler3b635712020-02-13 22:41:561267}
1268
1269bool IONAME(InputReal64)(Cookie cookie, double &x) {
Peter Klausler2a07db42022-06-06 22:59:011270 if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal64")) {
1271 return false;
1272 }
peter klauslercc011942020-08-07 00:30:011273 StaticDescriptor staticDescriptor;
1274 Descriptor &descriptor{staticDescriptor.descriptor()};
1275 descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
1276 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klausler3bc2ae92020-07-23 00:01:221277}
1278
peter klauslercc011942020-08-07 00:30:011279bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) {
Peter Klausler2a07db42022-06-06 22:59:011280 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex32")) {
1281 return false;
1282 }
peter klauslercc011942020-08-07 00:30:011283 float z[2]{r, i};
1284 StaticDescriptor staticDescriptor;
1285 Descriptor &descriptor{staticDescriptor.descriptor()};
1286 descriptor.Establish(
1287 TypeCategory::Complex, 4, reinterpret_cast<void *>(&z), 0);
1288 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
peter klausler95696d52020-02-05 00:55:451289}
1290
peter klauslercc011942020-08-07 00:30:011291bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) {
Peter Klausler2a07db42022-06-06 22:59:011292 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex64")) {
1293 return false;
1294 }
peter klauslercc011942020-08-07 00:30:011295 double z[2]{r, i};
1296 StaticDescriptor staticDescriptor;
1297 Descriptor &descriptor{staticDescriptor.descriptor()};
1298 descriptor.Establish(
1299 TypeCategory::Complex, 8, reinterpret_cast<void *>(&z), 0);
1300 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
Zachary Selk4b9b64d2020-07-07 19:33:311301}
1302
peter klauslercc011942020-08-07 00:30:011303bool IONAME(InputComplex32)(Cookie cookie, float z[2]) {
Peter Klausler2a07db42022-06-06 22:59:011304 if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex32")) {
1305 return false;
1306 }
peter klauslercc011942020-08-07 00:30:011307 StaticDescriptor staticDescriptor;
1308 Descriptor &descriptor{staticDescriptor.descriptor()};
1309 descriptor.Establish(
1310 TypeCategory::Complex, 4, reinterpret_cast<void *>(z), 0);
1311 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klausler3bc2ae92020-07-23 00:01:221312}
1313
peter klauslercc011942020-08-07 00:30:011314bool IONAME(InputComplex64)(Cookie cookie, double z[2]) {
Peter Klausler2a07db42022-06-06 22:59:011315 if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex64")) {
1316 return false;
1317 }
peter klauslercc011942020-08-07 00:30:011318 StaticDescriptor staticDescriptor;
1319 Descriptor &descriptor{staticDescriptor.descriptor()};
1320 descriptor.Establish(
1321 TypeCategory::Complex, 8, reinterpret_cast<void *>(z), 0);
1322 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klauslerf7be2512020-01-24 00:59:271323}
1324
peter klauslercdfb95a2020-10-01 16:32:481325bool IONAME(OutputCharacter)(
1326 Cookie cookie, const char *x, std::size_t length, int kind) {
Peter Klausler2a07db42022-06-06 22:59:011327 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputCharacter")) {
1328 return false;
1329 }
peter klauslercc011942020-08-07 00:30:011330 StaticDescriptor staticDescriptor;
1331 Descriptor &descriptor{staticDescriptor.descriptor()};
1332 descriptor.Establish(
peter klauslercdfb95a2020-10-01 16:32:481333 kind, length, reinterpret_cast<void *>(const_cast<char *>(x)), 0);
peter klauslercc011942020-08-07 00:30:011334 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
peter klausler3b635712020-02-13 22:41:561335}
1336
peter klauslercdfb95a2020-10-01 16:32:481337bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
1338 return IONAME(OutputCharacter(cookie, x, length, 1));
1339}
1340
1341bool IONAME(InputCharacter)(
1342 Cookie cookie, char *x, std::size_t length, int kind) {
Peter Klausler2a07db42022-06-06 22:59:011343 if (!cookie->CheckFormattedStmtType<Direction::Input>("InputCharacter")) {
1344 return false;
1345 }
peter klauslercc011942020-08-07 00:30:011346 StaticDescriptor staticDescriptor;
1347 Descriptor &descriptor{staticDescriptor.descriptor()};
peter klauslercdfb95a2020-10-01 16:32:481348 descriptor.Establish(kind, length, reinterpret_cast<void *>(x), 0);
peter klauslercc011942020-08-07 00:30:011349 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klauslerf7be2512020-01-24 00:59:271350}
1351
peter klauslercdfb95a2020-10-01 16:32:481352bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) {
Peter Klauslercea8b8a2022-04-27 20:28:591353 return IONAME(InputCharacter)(cookie, x, length, 1);
peter klauslercdfb95a2020-10-01 16:32:481354}
1355
peter klauslerf7be2512020-01-24 00:59:271356bool IONAME(OutputLogical)(Cookie cookie, bool truth) {
Peter Klausler2a07db42022-06-06 22:59:011357 if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputLogical")) {
1358 return false;
1359 }
peter klauslercc011942020-08-07 00:30:011360 StaticDescriptor staticDescriptor;
1361 Descriptor &descriptor{staticDescriptor.descriptor()};
1362 descriptor.Establish(
peter klauslercdfb95a2020-10-01 16:32:481363 TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0);
peter klauslercc011942020-08-07 00:30:011364 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
peter klausler3b635712020-02-13 22:41:561365}
1366
1367bool IONAME(InputLogical)(Cookie cookie, bool &truth) {
Peter Klausler2a07db42022-06-06 22:59:011368 if (!cookie->CheckFormattedStmtType<Direction::Input>("InputLogical")) {
1369 return false;
1370 }
peter klauslercc011942020-08-07 00:30:011371 StaticDescriptor staticDescriptor;
1372 Descriptor &descriptor{staticDescriptor.descriptor()};
1373 descriptor.Establish(
peter klauslercdfb95a2020-10-01 16:32:481374 TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0);
peter klauslercc011942020-08-07 00:30:011375 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
peter klausler3b635712020-02-13 22:41:561376}
1377
Peter Klausler09b00ab2023-03-10 23:06:011378bool IONAME(OutputDerivedType)(Cookie cookie, const Descriptor &descriptor,
Peter Klausler7cf16082023-04-13 17:28:191379 const NonTbpDefinedIoTable *table) {
1380 return descr::DescriptorIO<Direction::Output>(*cookie, descriptor, table);
Peter Klausler09b00ab2023-03-10 23:06:011381}
1382
1383bool IONAME(InputDerivedType)(Cookie cookie, const Descriptor &descriptor,
Peter Klausler7cf16082023-04-13 17:28:191384 const NonTbpDefinedIoTable *table) {
1385 return descr::DescriptorIO<Direction::Input>(*cookie, descriptor, table);
Peter Klausler09b00ab2023-03-10 23:06:011386}
1387
peter klausler4393e372021-09-20 17:52:391388std::size_t IONAME(GetSize)(Cookie cookie) {
1389 IoStatementState &io{*cookie};
Peter Klausler8db4dc82022-03-14 20:39:501390 IoErrorHandler &handler{io.GetIoErrorHandler()};
1391 if (!handler.InError()) {
1392 io.CompleteOperation();
1393 }
peter klausler4393e372021-09-20 17:52:391394 if (const auto *formatted{
1395 io.get_if<FormattedIoStatementState<Direction::Input>>()}) {
1396 return formatted->GetEditDescriptorChars();
Peter Klausler2a07db42022-06-06 22:59:011397 } else if (!io.get_if<ErroneousIoStatementState>()) {
1398 handler.Crash("GetIoSize() called for an I/O statement that is not a "
1399 "formatted READ()");
peter klausler4393e372021-09-20 17:52:391400 }
peter klausler4393e372021-09-20 17:52:391401 return 0;
1402}
1403
1404std::size_t IONAME(GetIoLength)(Cookie cookie) {
1405 IoStatementState &io{*cookie};
Peter Klausler8db4dc82022-03-14 20:39:501406 IoErrorHandler &handler{io.GetIoErrorHandler()};
1407 if (!handler.InError()) {
1408 io.CompleteOperation();
1409 }
peter klausler4393e372021-09-20 17:52:391410 if (const auto *inq{io.get_if<InquireIOLengthState>()}) {
1411 return inq->bytes();
Peter Klausler2a07db42022-06-06 22:59:011412 } else if (!io.get_if<ErroneousIoStatementState>()) {
1413 handler.Crash("GetIoLength() called for an I/O statement that is not "
1414 "INQUIRE(IOLENGTH=)");
peter klausler4393e372021-09-20 17:52:391415 }
peter klausler4393e372021-09-20 17:52:391416 return 0;
1417}
1418
peter klausler3b635712020-02-13 22:41:561419void IONAME(GetIoMsg)(Cookie cookie, char *msg, std::size_t length) {
Peter Klausler8db4dc82022-03-14 20:39:501420 IoStatementState &io{*cookie};
1421 IoErrorHandler &handler{io.GetIoErrorHandler()};
1422 if (!handler.InError()) {
1423 io.CompleteOperation();
1424 }
peter klauslere81c96d2021-04-13 23:07:581425 if (handler.InError()) { // leave "msg" alone when no error
peter klausler3b635712020-02-13 22:41:561426 handler.GetIoMsg(msg, length);
1427 }
peter klauslerf7be2512020-01-24 00:59:271428}
1429
peter klausler675ad1b2020-08-03 18:35:291430bool IONAME(InquireCharacter)(Cookie cookie, InquiryKeywordHash inquiry,
1431 char *result, std::size_t length) {
1432 IoStatementState &io{*cookie};
1433 return io.Inquire(inquiry, result, length);
1434}
1435
1436bool IONAME(InquireLogical)(
1437 Cookie cookie, InquiryKeywordHash inquiry, bool &result) {
1438 IoStatementState &io{*cookie};
1439 return io.Inquire(inquiry, result);
1440}
1441
1442bool IONAME(InquirePendingId)(Cookie cookie, std::int64_t id, bool &result) {
1443 IoStatementState &io{*cookie};
1444 return io.Inquire(HashInquiryKeyword("PENDING"), id, result);
1445}
1446
1447bool IONAME(InquireInteger64)(
1448 Cookie cookie, InquiryKeywordHash inquiry, std::int64_t &result, int kind) {
1449 IoStatementState &io{*cookie};
Peter Klauslere468f072023-06-06 18:37:521450 std::int64_t n{0}; // safe "undefined" value
peter klausler675ad1b2020-08-03 18:35:291451 if (io.Inquire(inquiry, n)) {
Peter Klausler73b193a2022-02-16 21:26:441452 if (SetInteger(result, kind, n)) {
1453 return true;
1454 }
1455 io.GetIoErrorHandler().SignalError(
Peter Steinfelde3550f12022-03-11 22:01:071456 "InquireInteger64(): bad INTEGER kind(%d) or out-of-range "
Peter Klauslere468f072023-06-06 18:37:521457 "value(%jd) for result",
Peter Klausler73b193a2022-02-16 21:26:441458 kind, static_cast<std::intmax_t>(n));
peter klausler675ad1b2020-08-03 18:35:291459 }
1460 return false;
1461}
1462
peter klauslerf7be2512020-01-24 00:59:271463enum Iostat IONAME(EndIoStatement)(Cookie cookie) {
1464 IoStatementState &io{*cookie};
1465 return static_cast<enum Iostat>(io.EndIoStatement());
peter klausler491122d2020-01-16 21:51:251466}
Jean Perierc58c64d2022-04-06 13:37:481467
1468template <typename INT>
1469static enum Iostat CheckUnitNumberInRangeImpl(INT unit, bool handleError,
1470 char *ioMsg, std::size_t ioMsgLength, const char *sourceFile,
1471 int sourceLine) {
Jean Perier9cfa8992022-04-11 07:32:031472 static_assert(sizeof(INT) >= sizeof(ExternalUnit),
1473 "only intended to be used when the INT to ExternalUnit conversion is "
1474 "narrowing");
Jean Perierc58c64d2022-04-06 13:37:481475 if (unit != static_cast<ExternalUnit>(unit)) {
1476 Terminator oom{sourceFile, sourceLine};
1477 IoErrorHandler errorHandler{oom};
1478 if (handleError) {
1479 errorHandler.HasIoStat();
1480 if (ioMsg) {
1481 errorHandler.HasIoMsg();
1482 }
1483 }
1484 // Only provide the bad unit number in the message if SignalError can print
1485 // it accurately. Otherwise, the generic IostatUnitOverflow message will be
1486 // used.
Peter Klausler1c35c1a2023-07-06 22:03:051487 if constexpr (sizeof(INT) > sizeof(std::intmax_t)) {
1488 errorHandler.SignalError(IostatUnitOverflow);
1489 } else if (static_cast<std::intmax_t>(unit) == unit) {
Jean Perierc58c64d2022-04-06 13:37:481490 errorHandler.SignalError(IostatUnitOverflow,
1491 "UNIT number %jd is out of range", static_cast<std::intmax_t>(unit));
1492 } else {
1493 errorHandler.SignalError(IostatUnitOverflow);
1494 }
1495 if (ioMsg) {
1496 errorHandler.GetIoMsg(ioMsg, ioMsgLength);
1497 }
1498 return static_cast<enum Iostat>(errorHandler.GetIoStat());
1499 }
1500 return IostatOk;
1501}
1502
1503enum Iostat IONAME(CheckUnitNumberInRange64)(std::int64_t unit,
1504 bool handleError, char *ioMsg, std::size_t ioMsgLength,
1505 const char *sourceFile, int sourceLine) {
1506 return CheckUnitNumberInRangeImpl(
1507 unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine);
1508}
1509
1510#ifdef __SIZEOF_INT128__
1511enum Iostat IONAME(CheckUnitNumberInRange128)(common::int128_t unit,
1512 bool handleError, char *ioMsg, std::size_t ioMsgLength,
1513 const char *sourceFile, int sourceLine) {
1514 return CheckUnitNumberInRangeImpl(
1515 unit, handleError, ioMsg, ioMsgLength, sourceFile, sourceLine);
1516}
1517#endif
1518
Tim Keith1f879002020-03-29 04:00:161519} // namespace Fortran::runtime::io