Warning: This file is not a C or C++ file. It does not have highlighting.

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

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Runtime/io-api.h