1 //===-- runtime/io-api.h ----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // Defines API between compiled code and I/O runtime library.
10
11 #ifndef FORTRAN_RUNTIME_IO_API_H_
12 #define FORTRAN_RUNTIME_IO_API_H_
13
14 #include "entry-names.h"
15 #include "iostat.h"
16 #include <cinttypes>
17 #include <cstddef>
18
19 namespace Fortran::runtime {
20 class Descriptor;
21 class NamelistGroup;
22 } // namespace Fortran::runtime
23
24 namespace Fortran::runtime::io {
25
26 class IoStatementState;
27 using Cookie = IoStatementState *;
28 using ExternalUnit = int;
29 using AsynchronousId = int;
30 static constexpr ExternalUnit DefaultUnit{-1}; // READ(*), WRITE(*), PRINT
31
32 // INQUIRE specifiers are encoded as simple base-26 packings of
33 // the spellings of their keywords.
34 using InquiryKeywordHash = std::uint64_t;
HashInquiryKeyword(const char * p)35 constexpr InquiryKeywordHash HashInquiryKeyword(const char *p) {
36 InquiryKeywordHash hash{1};
37 while (char ch{*p++}) {
38 std::uint64_t letter{0};
39 if (ch >= 'a' && ch <= 'z') {
40 letter = ch - 'a';
41 } else {
42 letter = ch - 'A';
43 }
44 hash = 26 * hash + letter;
45 }
46 return hash;
47 }
48
49 const char *InquiryKeywordHashDecode(
50 char *buffer, std::size_t, InquiryKeywordHash);
51
52 extern "C" {
53
54 #define IONAME(name) RTNAME(io##name)
55
56 // These functions initiate data transfer statements (READ, WRITE, PRINT).
57 // Example: PRINT *, 666 is implemented as the series of calls:
58 // Cookie cookie{BeginExternalListOutput(DefaultUnit,__FILE__,__LINE__)};
59 // OutputInteger64(cookie, 666);
60 // EndIoStatement(cookie);
61
62 // Internal I/O initiation
63 // Internal I/O can loan the runtime library an optional block of memory
64 // in which the library can maintain state across the calls that implement
65 // the internal transfer; use of these blocks can reduce the need for dynamic
66 // memory allocation &/or thread-local storage. The block must be sufficiently
67 // aligned to hold a pointer.
RecommendedInternalIoScratchAreaBytes(int maxFormatParenthesesNestingDepth)68 constexpr std::size_t RecommendedInternalIoScratchAreaBytes(
69 int maxFormatParenthesesNestingDepth) {
70 return 32 + 8 * maxFormatParenthesesNestingDepth;
71 }
72
73 // Internal I/O to/from character arrays &/or non-default-kind character
74 // requires a descriptor, which is copied.
75 Cookie IONAME(BeginInternalArrayListOutput)(const Descriptor &,
76 void **scratchArea = nullptr, std::size_t scratchBytes = 0,
77 const char *sourceFile = nullptr, int sourceLine = 0);
78 Cookie IONAME(BeginInternalArrayListInput)(const Descriptor &,
79 void **scratchArea = nullptr, std::size_t scratchBytes = 0,
80 const char *sourceFile = nullptr, int sourceLine = 0);
81 Cookie IONAME(BeginInternalArrayFormattedOutput)(const Descriptor &,
82 const char *format, std::size_t formatLength, void **scratchArea = nullptr,
83 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
84 int sourceLine = 0);
85 Cookie IONAME(BeginInternalArrayFormattedInput)(const Descriptor &,
86 const char *format, std::size_t formatLength, void **scratchArea = nullptr,
87 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
88 int sourceLine = 0);
89
90 // Internal I/O to/from a default-kind character scalar can avoid a
91 // descriptor.
92 Cookie IONAME(BeginInternalListOutput)(char *internal,
93 std::size_t internalLength, void **scratchArea = nullptr,
94 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
95 int sourceLine = 0);
96 Cookie IONAME(BeginInternalListInput)(const char *internal,
97 std::size_t internalLength, void **scratchArea = nullptr,
98 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
99 int sourceLine = 0);
100 Cookie IONAME(BeginInternalFormattedOutput)(char *internal,
101 std::size_t internalLength, const char *format, std::size_t formatLength,
102 void **scratchArea = nullptr, std::size_t scratchBytes = 0,
103 const char *sourceFile = nullptr, int sourceLine = 0);
104 Cookie IONAME(BeginInternalFormattedInput)(const char *internal,
105 std::size_t internalLength, const char *format, std::size_t formatLength,
106 void **scratchArea = nullptr, std::size_t scratchBytes = 0,
107 const char *sourceFile = nullptr, int sourceLine = 0);
108
109 // Internal namelist I/O
110 Cookie IONAME(BeginInternalNamelistOutput)(const Descriptor &,
111 const NamelistGroup &, void **scratchArea = nullptr,
112 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
113 int sourceLine = 0);
114 Cookie IONAME(BeginInternalNamelistInput)(const Descriptor &,
115 const NamelistGroup &, void **scratchArea = nullptr,
116 std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
117 int sourceLine = 0);
118
119 // External synchronous I/O initiation
120 Cookie IONAME(BeginExternalListOutput)(ExternalUnit = DefaultUnit,
121 const char *sourceFile = nullptr, int sourceLine = 0);
122 Cookie IONAME(BeginExternalListInput)(ExternalUnit = DefaultUnit,
123 const char *sourceFile = nullptr, int sourceLine = 0);
124 Cookie IONAME(BeginExternalFormattedOutput)(const char *format, std::size_t,
125 ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
126 int sourceLine = 0);
127 Cookie IONAME(BeginExternalFormattedInput)(const char *format, std::size_t,
128 ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
129 int sourceLine = 0);
130 Cookie IONAME(BeginUnformattedOutput)(ExternalUnit = DefaultUnit,
131 const char *sourceFile = nullptr, int sourceLine = 0);
132 Cookie IONAME(BeginUnformattedInput)(ExternalUnit = DefaultUnit,
133 const char *sourceFile = nullptr, int sourceLine = 0);
134 Cookie IONAME(BeginExternalNamelistOutput)(const NamelistGroup &,
135 ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
136 int sourceLine = 0);
137 Cookie IONAME(BeginExternalNamelistInput)(const NamelistGroup &,
138 ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
139 int sourceLine = 0);
140
141 // Asynchronous I/O is supported (at most) for unformatted direct access
142 // block transfers.
143 AsynchronousId IONAME(BeginAsynchronousOutput)(ExternalUnit, std::int64_t REC,
144 const char *, std::size_t, const char *sourceFile = nullptr,
145 int sourceLine = 0);
146 AsynchronousId IONAME(BeginAsynchronousInput)(ExternalUnit, std::int64_t REC,
147 char *, std::size_t, const char *sourceFile = nullptr, int sourceLine = 0);
148 Cookie IONAME(BeginWait)(ExternalUnit, AsynchronousId);
149 Cookie IONAME(BeginWaitAll)(ExternalUnit);
150
151 // Other I/O statements
152 Cookie IONAME(BeginClose)(
153 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
154 Cookie IONAME(BeginFlush)(
155 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
156 Cookie IONAME(BeginBackspace)(
157 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
158 Cookie IONAME(BeginEndfile)(
159 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
160 Cookie IONAME(BeginRewind)(
161 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
162
163 // OPEN(UNIT=) and OPEN(NEWUNIT=) have distinct interfaces.
164 Cookie IONAME(BeginOpenUnit)(
165 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
166 Cookie IONAME(BeginOpenNewUnit)(
167 const char *sourceFile = nullptr, int sourceLine = 0);
168
169 // The variant forms of INQUIRE() statements have distinct interfaces.
170 // BeginInquireIoLength() is basically a no-op output statement.
171 Cookie IONAME(BeginInquireUnit)(
172 ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
173 Cookie IONAME(BeginInquireFile)(const char *, std::size_t,
174 const char *sourceFile = nullptr, int sourceLine = 0);
175 Cookie IONAME(BeginInquireIoLength)(
176 const char *sourceFile = nullptr, int sourceLine = 0);
177
178 // If an I/O statement has any IOSTAT=, ERR=, END=, or EOR= specifiers,
179 // call EnableHandlers() immediately after the Begin...() call.
180 // An output or OPEN statement may not enable HasEnd or HasEor.
181 // This call makes the runtime library defer those particular error/end
182 // conditions to the EndIoStatement() call rather than terminating
183 // the image. E.g., for READ(*,*,END=666) A, B, (C(J),J=1,N)
184 // Cookie cookie{BeginExternalListInput(DefaultUnit,__FILE__,__LINE__)};
185 // EnableHandlers(cookie, false, false, true /*END=*/, false);
186 // if (InputReal64(cookie, &A)) {
187 // if (InputReal64(cookie, &B)) {
188 // for (int J{1}; J<=N; ++J) {
189 // if (!InputReal64(cookie, &C[J])) break;
190 // }
191 // }
192 // }
193 // if (EndIoStatement(cookie) == FORTRAN_RUTIME_IOSTAT_END) goto label666;
194 void IONAME(EnableHandlers)(Cookie, bool hasIoStat = false, bool hasErr = false,
195 bool hasEnd = false, bool hasEor = false, bool hasIoMsg = false);
196
197 // Control list options. These return false on a error that the
198 // Begin...() call has specified will be handled by the caller.
199 // The interfaces that pass a default-kind CHARACTER argument
200 // are limited to passing specific case-insensitive keyword values.
201 // ADVANCE=YES, NO
202 bool IONAME(SetAdvance)(Cookie, const char *, std::size_t);
203 // BLANK=NULL, ZERO
204 bool IONAME(SetBlank)(Cookie, const char *, std::size_t);
205 // DECIMAL=COMMA, POINT
206 bool IONAME(SetDecimal)(Cookie, const char *, std::size_t);
207 // DELIM=APOSTROPHE, QUOTE, NONE
208 bool IONAME(SetDelim)(Cookie, const char *, std::size_t);
209 // PAD=YES, NO
210 bool IONAME(SetPad)(Cookie, const char *, std::size_t);
211 bool IONAME(SetPos)(Cookie, std::int64_t);
212 bool IONAME(SetRec)(Cookie, std::int64_t);
213 // ROUND=UP, DOWN, ZERO, NEAREST, COMPATIBLE, PROCESSOR_DEFINED
214 bool IONAME(SetRound)(Cookie, const char *, std::size_t);
215 // SIGN=PLUS, SUPPRESS, PROCESSOR_DEFINED
216 bool IONAME(SetSign)(Cookie, const char *, std::size_t);
217
218 // Data item transfer for modes other than namelist.
219 // Any data object that can be passed as an actual argument without the
220 // use of a temporary can be transferred by means of a descriptor;
221 // vector-valued subscripts and coindexing will require elementwise
222 // transfers &/or data copies. Unformatted transfers to/from contiguous
223 // blocks of local image memory can avoid the descriptor, and there
224 // are specializations for the most common scalar types.
225 //
226 // These functions return false when the I/O statement has encountered an
227 // error or end-of-file/record condition that the caller has indicated
228 // should not cause termination of the image by the runtime library.
229 // Once the statement has encountered an error, all following items will be
230 // ignored and also return false; but compiled code should check for errors
231 // and avoid the following items when they might crash.
232 bool IONAME(OutputDescriptor)(Cookie, const Descriptor &);
233 bool IONAME(InputDescriptor)(Cookie, const Descriptor &);
234 // Contiguous transfers for unformatted I/O
235 bool IONAME(OutputUnformattedBlock)(
236 Cookie, const char *, std::size_t, std::size_t elementBytes);
237 bool IONAME(InputUnformattedBlock)(
238 Cookie, char *, std::size_t, std::size_t elementBytes);
239 // Formatted (including list directed) I/O data items
240 bool IONAME(OutputInteger64)(Cookie, std::int64_t);
241 bool IONAME(InputInteger)(Cookie, std::int64_t &, int kind = 8);
242 bool IONAME(OutputReal32)(Cookie, float);
243 bool IONAME(InputReal32)(Cookie, float &);
244 bool IONAME(OutputReal64)(Cookie, double);
245 bool IONAME(InputReal64)(Cookie, double &);
246 bool IONAME(OutputComplex32)(Cookie, float, float);
247 bool IONAME(InputComplex32)(Cookie, float[2]);
248 bool IONAME(OutputComplex64)(Cookie, double, double);
249 bool IONAME(InputComplex64)(Cookie, double[2]);
250 bool IONAME(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1);
251 bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
252 bool IONAME(InputCharacter)(Cookie, char *, std::size_t, int kind = 1);
253 bool IONAME(InputAscii)(Cookie, char *, std::size_t);
254 bool IONAME(OutputLogical)(Cookie, bool);
255 bool IONAME(InputLogical)(Cookie, bool &);
256
257 // Additional specifier interfaces for the connection-list of
258 // on OPEN statement (only). SetBlank(), SetDecimal(),
259 // SetDelim(), GetIoMsg(), SetPad(), SetRound(), & SetSign()
260 // are also acceptable for OPEN.
261 // ACCESS=SEQUENTIAL, DIRECT, STREAM
262 bool IONAME(SetAccess)(Cookie, const char *, std::size_t);
263 // ACTION=READ, WRITE, or READWRITE
264 bool IONAME(SetAction)(Cookie, const char *, std::size_t);
265 // ASYNCHRONOUS=YES, NO
266 bool IONAME(SetAsynchronous)(Cookie, const char *, std::size_t);
267 // CARRIAGECONTROL=LIST, FORTRAN, NONE
268 bool IONAME(SetCarriagecontrol)(Cookie, const char *, std::size_t);
269 // CONVERT=NATIVE, LITTLE_ENDIAN, BIG_ENDIAN, or SWAP
270 bool IONAME(SetConvert)(Cookie, const char *, std::size_t);
271 // ENCODING=UTF-8, DEFAULT
272 bool IONAME(SetEncoding)(Cookie, const char *, std::size_t);
273 // FORM=FORMATTED, UNFORMATTED
274 bool IONAME(SetForm)(Cookie, const char *, std::size_t);
275 // POSITION=ASIS, REWIND, APPEND
276 bool IONAME(SetPosition)(Cookie, const char *, std::size_t);
277 bool IONAME(SetRecl)(Cookie, std::size_t); // RECL=
278
279 // STATUS can be set during an OPEN or CLOSE statement.
280 // For OPEN: STATUS=OLD, NEW, SCRATCH, REPLACE, UNKNOWN
281 // For CLOSE: STATUS=KEEP, DELETE
282 bool IONAME(SetStatus)(Cookie, const char *, std::size_t);
283
284 bool IONAME(SetFile)(Cookie, const char *, std::size_t chars);
285
286 // Acquires the runtime-created unit number for OPEN(NEWUNIT=)
287 bool IONAME(GetNewUnit)(Cookie, int &, int kind = 4);
288
289 // READ(SIZE=), after all input items
290 bool IONAME(GetSize)(Cookie, std::int64_t, int kind = 8);
291
292 // INQUIRE(IOLENGTH=), after all output items
293 bool IONAME(GetIoLength)(Cookie, std::int64_t, int kind = 8);
294
295 // GetIoMsg() does not modify its argument unless an error or
296 // end-of-record/file condition is present.
297 void IONAME(GetIoMsg)(Cookie, char *, std::size_t); // IOMSG=
298
299 // INQUIRE() specifiers are mostly identified by their NUL-terminated
300 // case-insensitive names.
301 // ACCESS, ACTION, ASYNCHRONOUS, BLANK, CONVERT, DECIMAL, DELIM, DIRECT,
302 // ENCODING, FORM, FORMATTED, NAME, PAD, POSITION, READ, READWRITE, ROUND,
303 // SEQUENTIAL, SIGN, STREAM, UNFORMATTED, WRITE:
304 bool IONAME(InquireCharacter)(Cookie, InquiryKeywordHash, char *, std::size_t);
305 // EXIST, NAMED, OPENED, and PENDING (without ID):
306 bool IONAME(InquireLogical)(Cookie, InquiryKeywordHash, bool &);
307 // PENDING with ID
308 bool IONAME(InquirePendingId)(Cookie, std::int64_t, bool &);
309 // NEXTREC, NUMBER, POS, RECL, SIZE
310 bool IONAME(InquireInteger64)(
311 Cookie, InquiryKeywordHash, std::int64_t &, int kind = 8);
312
313 // This function must be called to end an I/O statement, and its
314 // cookie value may not be used afterwards unless it is recycled
315 // by the runtime library to serve a later I/O statement.
316 // The return value can be used to implement IOSTAT=, ERR=, END=, & EOR=;
317 // store it into the IOSTAT= variable if there is one, and test
318 // it to implement the various branches. The error condition
319 // returned is guaranteed to only be one of the problems that the
320 // EnableHandlers() call has indicated should be handled in compiled code
321 // rather than by terminating the image.
322 enum Iostat IONAME(EndIoStatement)(Cookie);
323
324 } // extern "C"
325 } // namespace Fortran::runtime::io
326 #endif
327