forked from OSchip/llvm-project
327 lines
15 KiB
C++
327 lines
15 KiB
C++
//===-- runtime/io-api.h ----------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Defines API between compiled code and I/O runtime library.
|
|
|
|
#ifndef FORTRAN_RUNTIME_IO_API_H_
|
|
#define FORTRAN_RUNTIME_IO_API_H_
|
|
|
|
#include "entry-names.h"
|
|
#include "iostat.h"
|
|
#include <cinttypes>
|
|
#include <cstddef>
|
|
|
|
namespace Fortran::runtime {
|
|
class Descriptor;
|
|
class NamelistGroup;
|
|
} // namespace Fortran::runtime
|
|
|
|
namespace Fortran::runtime::io {
|
|
|
|
class IoStatementState;
|
|
using Cookie = IoStatementState *;
|
|
using ExternalUnit = int;
|
|
using AsynchronousId = int;
|
|
static constexpr ExternalUnit DefaultUnit{-1}; // READ(*), WRITE(*), PRINT
|
|
|
|
// INQUIRE specifiers are encoded as simple base-26 packings of
|
|
// the spellings of their keywords.
|
|
using InquiryKeywordHash = std::uint64_t;
|
|
constexpr InquiryKeywordHash HashInquiryKeyword(const char *p) {
|
|
InquiryKeywordHash hash{1};
|
|
while (char ch{*p++}) {
|
|
std::uint64_t letter{0};
|
|
if (ch >= 'a' && ch <= 'z') {
|
|
letter = ch - 'a';
|
|
} else {
|
|
letter = ch - 'A';
|
|
}
|
|
hash = 26 * hash + letter;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
const char *InquiryKeywordHashDecode(
|
|
char *buffer, std::size_t, InquiryKeywordHash);
|
|
|
|
extern "C" {
|
|
|
|
#define IONAME(name) RTNAME(io##name)
|
|
|
|
// These functions initiate data transfer statements (READ, WRITE, PRINT).
|
|
// Example: PRINT *, 666 is implemented as the series of calls:
|
|
// Cookie cookie{BeginExternalListOutput(DefaultUnit,__FILE__,__LINE__)};
|
|
// OutputInteger64(cookie, 666);
|
|
// EndIoStatement(cookie);
|
|
|
|
// Internal I/O initiation
|
|
// Internal I/O can loan the runtime library an optional block of memory
|
|
// in which the library can maintain state across the calls that implement
|
|
// the internal transfer; use of these blocks can reduce the need for dynamic
|
|
// memory allocation &/or thread-local storage. The block must be sufficiently
|
|
// aligned to hold a pointer.
|
|
constexpr std::size_t RecommendedInternalIoScratchAreaBytes(
|
|
int maxFormatParenthesesNestingDepth) {
|
|
return 32 + 8 * maxFormatParenthesesNestingDepth;
|
|
}
|
|
|
|
// Internal I/O to/from character arrays &/or non-default-kind character
|
|
// requires a descriptor, which is copied.
|
|
Cookie IONAME(BeginInternalArrayListOutput)(const Descriptor &,
|
|
void **scratchArea = nullptr, std::size_t scratchBytes = 0,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginInternalArrayListInput)(const Descriptor &,
|
|
void **scratchArea = nullptr, std::size_t scratchBytes = 0,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginInternalArrayFormattedOutput)(const Descriptor &,
|
|
const char *format, std::size_t formatLength, void **scratchArea = nullptr,
|
|
std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
Cookie IONAME(BeginInternalArrayFormattedInput)(const Descriptor &,
|
|
const char *format, std::size_t formatLength, void **scratchArea = nullptr,
|
|
std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
|
|
// Internal I/O to/from a default-kind character scalar can avoid a
|
|
// descriptor.
|
|
Cookie IONAME(BeginInternalListOutput)(char *internal,
|
|
std::size_t internalLength, void **scratchArea = nullptr,
|
|
std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
Cookie IONAME(BeginInternalListInput)(const char *internal,
|
|
std::size_t internalLength, void **scratchArea = nullptr,
|
|
std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
Cookie IONAME(BeginInternalFormattedOutput)(char *internal,
|
|
std::size_t internalLength, const char *format, std::size_t formatLength,
|
|
void **scratchArea = nullptr, std::size_t scratchBytes = 0,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginInternalFormattedInput)(const char *internal,
|
|
std::size_t internalLength, const char *format, std::size_t formatLength,
|
|
void **scratchArea = nullptr, std::size_t scratchBytes = 0,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
|
|
// Internal namelist I/O
|
|
Cookie IONAME(BeginInternalNamelistOutput)(const Descriptor &,
|
|
const NamelistGroup &, void **scratchArea = nullptr,
|
|
std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
Cookie IONAME(BeginInternalNamelistInput)(const Descriptor &,
|
|
const NamelistGroup &, void **scratchArea = nullptr,
|
|
std::size_t scratchBytes = 0, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
|
|
// External synchronous I/O initiation
|
|
Cookie IONAME(BeginExternalListOutput)(ExternalUnit = DefaultUnit,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginExternalListInput)(ExternalUnit = DefaultUnit,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginExternalFormattedOutput)(const char *format, std::size_t,
|
|
ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
Cookie IONAME(BeginExternalFormattedInput)(const char *format, std::size_t,
|
|
ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
Cookie IONAME(BeginUnformattedOutput)(ExternalUnit = DefaultUnit,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginUnformattedInput)(ExternalUnit = DefaultUnit,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginExternalNamelistOutput)(const NamelistGroup &,
|
|
ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
Cookie IONAME(BeginExternalNamelistInput)(const NamelistGroup &,
|
|
ExternalUnit = DefaultUnit, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
|
|
// Asynchronous I/O is supported (at most) for unformatted direct access
|
|
// block transfers.
|
|
AsynchronousId IONAME(BeginAsynchronousOutput)(ExternalUnit, std::int64_t REC,
|
|
const char *, std::size_t, const char *sourceFile = nullptr,
|
|
int sourceLine = 0);
|
|
AsynchronousId IONAME(BeginAsynchronousInput)(ExternalUnit, std::int64_t REC,
|
|
char *, std::size_t, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginWait)(ExternalUnit, AsynchronousId);
|
|
Cookie IONAME(BeginWaitAll)(ExternalUnit);
|
|
|
|
// Other I/O statements
|
|
Cookie IONAME(BeginClose)(
|
|
ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginFlush)(
|
|
ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginBackspace)(
|
|
ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginEndfile)(
|
|
ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginRewind)(
|
|
ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
|
|
// OPEN(UNIT=) and OPEN(NEWUNIT=) have distinct interfaces.
|
|
Cookie IONAME(BeginOpenUnit)(
|
|
ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginOpenNewUnit)(
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
|
|
// The variant forms of INQUIRE() statements have distinct interfaces.
|
|
// BeginInquireIoLength() is basically a no-op output statement.
|
|
Cookie IONAME(BeginInquireUnit)(
|
|
ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginInquireFile)(const char *, std::size_t,
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
Cookie IONAME(BeginInquireIoLength)(
|
|
const char *sourceFile = nullptr, int sourceLine = 0);
|
|
|
|
// If an I/O statement has any IOSTAT=, ERR=, END=, or EOR= specifiers,
|
|
// call EnableHandlers() immediately after the Begin...() call.
|
|
// An output or OPEN statement may not enable HasEnd or HasEor.
|
|
// This call makes the runtime library defer those particular error/end
|
|
// conditions to the EndIoStatement() call rather than terminating
|
|
// the image. E.g., for READ(*,*,END=666) A, B, (C(J),J=1,N)
|
|
// Cookie cookie{BeginExternalListInput(DefaultUnit,__FILE__,__LINE__)};
|
|
// EnableHandlers(cookie, false, false, true /*END=*/, false);
|
|
// if (InputReal64(cookie, &A)) {
|
|
// if (InputReal64(cookie, &B)) {
|
|
// for (int J{1}; J<=N; ++J) {
|
|
// if (!InputReal64(cookie, &C[J])) break;
|
|
// }
|
|
// }
|
|
// }
|
|
// if (EndIoStatement(cookie) == FORTRAN_RUTIME_IOSTAT_END) goto label666;
|
|
void IONAME(EnableHandlers)(Cookie, bool hasIoStat = false, bool hasErr = false,
|
|
bool hasEnd = false, bool hasEor = false, bool hasIoMsg = false);
|
|
|
|
// Control list options. These return false on a error that the
|
|
// Begin...() call has specified will be handled by the caller.
|
|
// The interfaces that pass a default-kind CHARACTER argument
|
|
// are limited to passing specific case-insensitive keyword values.
|
|
// ADVANCE=YES, NO
|
|
bool IONAME(SetAdvance)(Cookie, const char *, std::size_t);
|
|
// BLANK=NULL, ZERO
|
|
bool IONAME(SetBlank)(Cookie, const char *, std::size_t);
|
|
// DECIMAL=COMMA, POINT
|
|
bool IONAME(SetDecimal)(Cookie, const char *, std::size_t);
|
|
// DELIM=APOSTROPHE, QUOTE, NONE
|
|
bool IONAME(SetDelim)(Cookie, const char *, std::size_t);
|
|
// PAD=YES, NO
|
|
bool IONAME(SetPad)(Cookie, const char *, std::size_t);
|
|
bool IONAME(SetPos)(Cookie, std::int64_t);
|
|
bool IONAME(SetRec)(Cookie, std::int64_t);
|
|
// ROUND=UP, DOWN, ZERO, NEAREST, COMPATIBLE, PROCESSOR_DEFINED
|
|
bool IONAME(SetRound)(Cookie, const char *, std::size_t);
|
|
// SIGN=PLUS, SUPPRESS, PROCESSOR_DEFINED
|
|
bool IONAME(SetSign)(Cookie, const char *, std::size_t);
|
|
|
|
// Data item transfer for modes other than namelist.
|
|
// Any data object that can be passed as an actual argument without the
|
|
// use of a temporary can be transferred by means of a descriptor;
|
|
// vector-valued subscripts and coindexing will require elementwise
|
|
// transfers &/or data copies. Unformatted transfers to/from contiguous
|
|
// blocks of local image memory can avoid the descriptor, and there
|
|
// are specializations for the most common scalar types.
|
|
//
|
|
// These functions return false when the I/O statement has encountered an
|
|
// error or end-of-file/record condition that the caller has indicated
|
|
// should not cause termination of the image by the runtime library.
|
|
// Once the statement has encountered an error, all following items will be
|
|
// ignored and also return false; but compiled code should check for errors
|
|
// and avoid the following items when they might crash.
|
|
bool IONAME(OutputDescriptor)(Cookie, const Descriptor &);
|
|
bool IONAME(InputDescriptor)(Cookie, const Descriptor &);
|
|
// Contiguous transfers for unformatted I/O
|
|
bool IONAME(OutputUnformattedBlock)(
|
|
Cookie, const char *, std::size_t, std::size_t elementBytes);
|
|
bool IONAME(InputUnformattedBlock)(
|
|
Cookie, char *, std::size_t, std::size_t elementBytes);
|
|
// Formatted (including list directed) I/O data items
|
|
bool IONAME(OutputInteger64)(Cookie, std::int64_t);
|
|
bool IONAME(InputInteger)(Cookie, std::int64_t &, int kind = 8);
|
|
bool IONAME(OutputReal32)(Cookie, float);
|
|
bool IONAME(InputReal32)(Cookie, float &);
|
|
bool IONAME(OutputReal64)(Cookie, double);
|
|
bool IONAME(InputReal64)(Cookie, double &);
|
|
bool IONAME(OutputComplex32)(Cookie, float, float);
|
|
bool IONAME(InputComplex32)(Cookie, float[2]);
|
|
bool IONAME(OutputComplex64)(Cookie, double, double);
|
|
bool IONAME(InputComplex64)(Cookie, double[2]);
|
|
bool IONAME(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1);
|
|
bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
|
|
bool IONAME(InputCharacter)(Cookie, char *, std::size_t, int kind = 1);
|
|
bool IONAME(InputAscii)(Cookie, char *, std::size_t);
|
|
bool IONAME(OutputLogical)(Cookie, bool);
|
|
bool IONAME(InputLogical)(Cookie, bool &);
|
|
|
|
// Additional specifier interfaces for the connection-list of
|
|
// on OPEN statement (only). SetBlank(), SetDecimal(),
|
|
// SetDelim(), GetIoMsg(), SetPad(), SetRound(), & SetSign()
|
|
// are also acceptable for OPEN.
|
|
// ACCESS=SEQUENTIAL, DIRECT, STREAM
|
|
bool IONAME(SetAccess)(Cookie, const char *, std::size_t);
|
|
// ACTION=READ, WRITE, or READWRITE
|
|
bool IONAME(SetAction)(Cookie, const char *, std::size_t);
|
|
// ASYNCHRONOUS=YES, NO
|
|
bool IONAME(SetAsynchronous)(Cookie, const char *, std::size_t);
|
|
// CARRIAGECONTROL=LIST, FORTRAN, NONE
|
|
bool IONAME(SetCarriagecontrol)(Cookie, const char *, std::size_t);
|
|
// CONVERT=NATIVE, LITTLE_ENDIAN, BIG_ENDIAN, or SWAP
|
|
bool IONAME(SetConvert)(Cookie, const char *, std::size_t);
|
|
// ENCODING=UTF-8, DEFAULT
|
|
bool IONAME(SetEncoding)(Cookie, const char *, std::size_t);
|
|
// FORM=FORMATTED, UNFORMATTED
|
|
bool IONAME(SetForm)(Cookie, const char *, std::size_t);
|
|
// POSITION=ASIS, REWIND, APPEND
|
|
bool IONAME(SetPosition)(Cookie, const char *, std::size_t);
|
|
bool IONAME(SetRecl)(Cookie, std::size_t); // RECL=
|
|
|
|
// STATUS can be set during an OPEN or CLOSE statement.
|
|
// For OPEN: STATUS=OLD, NEW, SCRATCH, REPLACE, UNKNOWN
|
|
// For CLOSE: STATUS=KEEP, DELETE
|
|
bool IONAME(SetStatus)(Cookie, const char *, std::size_t);
|
|
|
|
bool IONAME(SetFile)(Cookie, const char *, std::size_t chars);
|
|
|
|
// Acquires the runtime-created unit number for OPEN(NEWUNIT=)
|
|
bool IONAME(GetNewUnit)(Cookie, int &, int kind = 4);
|
|
|
|
// READ(SIZE=), after all input items
|
|
bool IONAME(GetSize)(Cookie, std::int64_t, int kind = 8);
|
|
|
|
// INQUIRE(IOLENGTH=), after all output items
|
|
bool IONAME(GetIoLength)(Cookie, std::int64_t, int kind = 8);
|
|
|
|
// GetIoMsg() does not modify its argument unless an error or
|
|
// end-of-record/file condition is present.
|
|
void IONAME(GetIoMsg)(Cookie, char *, std::size_t); // IOMSG=
|
|
|
|
// INQUIRE() specifiers are mostly identified by their NUL-terminated
|
|
// case-insensitive names.
|
|
// ACCESS, ACTION, ASYNCHRONOUS, BLANK, CONVERT, DECIMAL, DELIM, DIRECT,
|
|
// ENCODING, FORM, FORMATTED, NAME, PAD, POSITION, READ, READWRITE, ROUND,
|
|
// SEQUENTIAL, SIGN, STREAM, UNFORMATTED, WRITE:
|
|
bool IONAME(InquireCharacter)(Cookie, InquiryKeywordHash, char *, std::size_t);
|
|
// EXIST, NAMED, OPENED, and PENDING (without ID):
|
|
bool IONAME(InquireLogical)(Cookie, InquiryKeywordHash, bool &);
|
|
// PENDING with ID
|
|
bool IONAME(InquirePendingId)(Cookie, std::int64_t, bool &);
|
|
// NEXTREC, NUMBER, POS, RECL, SIZE
|
|
bool IONAME(InquireInteger64)(
|
|
Cookie, InquiryKeywordHash, std::int64_t &, int kind = 8);
|
|
|
|
// This function must be called to end an I/O statement, and its
|
|
// cookie value may not be used afterwards unless it is recycled
|
|
// by the runtime library to serve a later I/O statement.
|
|
// The return value can be used to implement IOSTAT=, ERR=, END=, & EOR=;
|
|
// store it into the IOSTAT= variable if there is one, and test
|
|
// it to implement the various branches. The error condition
|
|
// returned is guaranteed to only be one of the problems that the
|
|
// EnableHandlers() call has indicated should be handled in compiled code
|
|
// rather than by terminating the image.
|
|
enum Iostat IONAME(EndIoStatement)(Cookie);
|
|
|
|
} // extern "C"
|
|
} // namespace Fortran::runtime::io
|
|
#endif
|