1651f58bfSDiana Picus //===-- runtime/internal-unit.cpp -----------------------------------------===//
295696d56Speter klausler //
395696d56Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
495696d56Speter klausler // See https://llvm.org/LICENSE.txt for license information.
595696d56Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
695696d56Speter klausler //
795696d56Speter klausler //===----------------------------------------------------------------------===//
895696d56Speter klausler
995696d56Speter klausler #include "internal-unit.h"
1095696d56Speter klausler #include "io-error.h"
11830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
1295696d56Speter klausler #include <algorithm>
1395696d56Speter klausler #include <type_traits>
1495696d56Speter klausler
1595696d56Speter klausler namespace Fortran::runtime::io {
1695696d56Speter klausler
173b635714Speter klausler template <Direction DIR>
InternalDescriptorUnit(Scalar scalar,std::size_t length)183b635714Speter klausler InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
1995696d56Speter klausler Scalar scalar, std::size_t length) {
2095696d56Speter klausler recordLength = length;
2195696d56Speter klausler endfileRecordNumber = 2;
2295696d56Speter klausler void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))};
2395696d56Speter klausler descriptor().Establish(TypeCode{CFI_type_char}, length, pointer, 0, nullptr,
2495696d56Speter klausler CFI_attribute_pointer);
2595696d56Speter klausler }
2695696d56Speter klausler
273b635714Speter klausler template <Direction DIR>
InternalDescriptorUnit(const Descriptor & that,const Terminator & terminator)283b635714Speter klausler InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
2995696d56Speter klausler const Descriptor &that, const Terminator &terminator) {
3095696d56Speter klausler RUNTIME_CHECK(terminator, that.type().IsCharacter());
3195696d56Speter klausler Descriptor &d{descriptor()};
3295696d56Speter klausler RUNTIME_CHECK(
3395696d56Speter klausler terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0));
3495696d56Speter klausler new (&d) Descriptor{that};
3595696d56Speter klausler d.Check();
3695696d56Speter klausler recordLength = d.ElementBytes();
3795696d56Speter klausler endfileRecordNumber = d.Elements() + 1;
3895696d56Speter klausler }
3995696d56Speter klausler
EndIoStatement()403b635714Speter klausler template <Direction DIR> void InternalDescriptorUnit<DIR>::EndIoStatement() {
41b77fd01aSPeter Klausler if constexpr (DIR == Direction::Output) {
420f5c60f1SPeter Klausler // Clear the remainder of the current record if anything was written
430f5c60f1SPeter Klausler // to it, or if it is the only record.
44*ea5b205bSPeter Klausler auto end{endfileRecordNumber.value_or(0)};
45*ea5b205bSPeter Klausler if (currentRecordNumber < end &&
46*ea5b205bSPeter Klausler (end == 2 || furthestPositionInRecord > 0)) {
47b77fd01aSPeter Klausler BlankFillOutputRecord();
4895696d56Speter klausler }
4995696d56Speter klausler }
5095696d56Speter klausler }
5195696d56Speter klausler
523b635714Speter klausler template <Direction DIR>
Emit(const char * data,std::size_t bytes,IoErrorHandler & handler)533b635714Speter klausler bool InternalDescriptorUnit<DIR>::Emit(
5495696d56Speter klausler const char *data, std::size_t bytes, IoErrorHandler &handler) {
553b635714Speter klausler if constexpr (DIR == Direction::Input) {
563b635714Speter klausler handler.Crash("InternalDescriptorUnit<Direction::Input>::Emit() called");
573b635714Speter klausler return false && data[bytes] != 0; // bogus compare silences GCC warning
583b635714Speter klausler } else {
593b635714Speter klausler if (bytes <= 0) {
603b635714Speter klausler return true;
613b635714Speter klausler }
623b635714Speter klausler char *record{CurrentRecord()};
633b635714Speter klausler if (!record) {
643b635714Speter klausler handler.SignalError(IostatInternalWriteOverrun);
6595696d56Speter klausler return false;
6695696d56Speter klausler }
6795696d56Speter klausler auto furthestAfter{std::max(furthestPositionInRecord,
6895696d56Speter klausler positionInRecord + static_cast<std::int64_t>(bytes))};
6995696d56Speter klausler bool ok{true};
7095696d56Speter klausler if (furthestAfter > static_cast<std::int64_t>(recordLength.value_or(0))) {
713b635714Speter klausler handler.SignalError(IostatRecordWriteOverrun);
7295696d56Speter klausler furthestAfter = recordLength.value_or(0);
7395696d56Speter klausler bytes = std::max(std::int64_t{0}, furthestAfter - positionInRecord);
7495696d56Speter klausler ok = false;
753b635714Speter klausler } else if (positionInRecord > furthestPositionInRecord) {
763b635714Speter klausler std::fill_n(record + furthestPositionInRecord,
773b635714Speter klausler positionInRecord - furthestPositionInRecord, ' ');
7895696d56Speter klausler }
7995696d56Speter klausler std::memcpy(record + positionInRecord, data, bytes);
8095696d56Speter klausler positionInRecord += bytes;
8195696d56Speter klausler furthestPositionInRecord = furthestAfter;
8295696d56Speter klausler return ok;
8395696d56Speter klausler }
843b635714Speter klausler }
8595696d56Speter klausler
863b635714Speter klausler template <Direction DIR>
GetNextInputBytes(const char * & p,IoErrorHandler & handler)87da25f968SPeter Klausler std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
88da25f968SPeter Klausler const char *&p, IoErrorHandler &handler) {
893b635714Speter klausler if constexpr (DIR == Direction::Output) {
90da25f968SPeter Klausler handler.Crash("InternalDescriptorUnit<Direction::Output>::"
91da25f968SPeter Klausler "GetNextInputBytes() called");
92da25f968SPeter Klausler return 0;
93da25f968SPeter Klausler } else {
943b635714Speter klausler const char *record{CurrentRecord()};
953b635714Speter klausler if (!record) {
963b635714Speter klausler handler.SignalEnd();
97da25f968SPeter Klausler return 0;
98da25f968SPeter Klausler } else if (positionInRecord >= recordLength.value_or(positionInRecord)) {
99da25f968SPeter Klausler return 0;
100da25f968SPeter Klausler } else {
101da25f968SPeter Klausler p = &record[positionInRecord];
102da25f968SPeter Klausler return *recordLength - positionInRecord;
1033b635714Speter klausler }
1043b635714Speter klausler }
105da25f968SPeter Klausler }
106da25f968SPeter Klausler
107da25f968SPeter Klausler template <Direction DIR>
AdvanceRecord(IoErrorHandler & handler)1083b635714Speter klausler bool InternalDescriptorUnit<DIR>::AdvanceRecord(IoErrorHandler &handler) {
10995696d56Speter klausler if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
11095696d56Speter klausler handler.SignalEnd();
11195696d56Speter klausler return false;
11295696d56Speter klausler }
113b77fd01aSPeter Klausler if constexpr (DIR == Direction::Output) {
114b77fd01aSPeter Klausler BlankFillOutputRecord();
11595696d56Speter klausler }
11695696d56Speter klausler ++currentRecordNumber;
11737f98f6fSpeter klausler BeginRecord();
11895696d56Speter klausler return true;
11995696d56Speter klausler }
12095696d56Speter klausler
1213b635714Speter klausler template <Direction DIR>
BlankFillOutputRecord()122b77fd01aSPeter Klausler void InternalDescriptorUnit<DIR>::BlankFillOutputRecord() {
123b77fd01aSPeter Klausler if constexpr (DIR == Direction::Output) {
124b77fd01aSPeter Klausler if (furthestPositionInRecord <
125b77fd01aSPeter Klausler recordLength.value_or(furthestPositionInRecord)) {
126b77fd01aSPeter Klausler char *record{CurrentRecord()};
127b77fd01aSPeter Klausler std::fill_n(record + furthestPositionInRecord,
128b77fd01aSPeter Klausler *recordLength - furthestPositionInRecord, ' ');
129b77fd01aSPeter Klausler }
130b77fd01aSPeter Klausler }
131b77fd01aSPeter Klausler }
132b77fd01aSPeter Klausler
133b77fd01aSPeter Klausler template <Direction DIR>
BackspaceRecord(IoErrorHandler & handler)1343b635714Speter klausler void InternalDescriptorUnit<DIR>::BackspaceRecord(IoErrorHandler &handler) {
1353b635714Speter klausler RUNTIME_CHECK(handler, currentRecordNumber > 1);
1363b635714Speter klausler --currentRecordNumber;
13737f98f6fSpeter klausler BeginRecord();
13895696d56Speter klausler }
13995696d56Speter klausler
1403b635714Speter klausler template class InternalDescriptorUnit<Direction::Output>;
1413b635714Speter klausler template class InternalDescriptorUnit<Direction::Input>;
1421f879005STim Keith } // namespace Fortran::runtime::io
143