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" 123b337242SSlava Zakharin #include "flang/Runtime/freestanding-tools.h" 1395696d56Speter klausler #include <algorithm> 1495696d56Speter klausler #include <type_traits> 1595696d56Speter klausler 1695696d56Speter klausler namespace Fortran::runtime::io { 178ebf7411SSlava Zakharin RT_OFFLOAD_API_GROUP_BEGIN 1895696d56Speter klausler 193b635714Speter klausler template <Direction DIR> 208ebf7411SSlava Zakharin RT_API_ATTRS InternalDescriptorUnit<DIR>::InternalDescriptorUnit( 21bad52055SPeter Klausler Scalar scalar, std::size_t length, int kind) { 22bad52055SPeter Klausler internalIoCharKind = kind; 2395696d56Speter klausler recordLength = length; 2495696d56Speter klausler endfileRecordNumber = 2; 2595696d56Speter klausler void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))}; 26bad52055SPeter Klausler descriptor().Establish(TypeCode{TypeCategory::Character, kind}, length * kind, 27bad52055SPeter Klausler pointer, 0, nullptr, CFI_attribute_pointer); 2895696d56Speter klausler } 2995696d56Speter klausler 303b635714Speter klausler template <Direction DIR> 318ebf7411SSlava Zakharin RT_API_ATTRS InternalDescriptorUnit<DIR>::InternalDescriptorUnit( 3295696d56Speter klausler const Descriptor &that, const Terminator &terminator) { 33bad52055SPeter Klausler auto thatType{that.type().GetCategoryAndKind()}; 34bad52055SPeter Klausler RUNTIME_CHECK(terminator, thatType.has_value()); 35bad52055SPeter Klausler RUNTIME_CHECK(terminator, thatType->first == TypeCategory::Character); 3695696d56Speter klausler Descriptor &d{descriptor()}; 3795696d56Speter klausler RUNTIME_CHECK( 3895696d56Speter klausler terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0)); 39*c91ba043SMichael Kruse RUNTIME_CHECK(terminator, 40*c91ba043SMichael Kruse that.SizeInBytes() <= MaxDescriptorSizeInBytes(maxRank, true, 0)); 4195696d56Speter klausler new (&d) Descriptor{that}; 4295696d56Speter klausler d.Check(); 43bad52055SPeter Klausler internalIoCharKind = thatType->second; 4495696d56Speter klausler recordLength = d.ElementBytes(); 4595696d56Speter klausler endfileRecordNumber = d.Elements() + 1; 4695696d56Speter klausler } 4795696d56Speter klausler 483b635714Speter klausler template <Direction DIR> 498ebf7411SSlava Zakharin RT_API_ATTRS bool InternalDescriptorUnit<DIR>::Emit( 5095696d56Speter klausler const char *data, std::size_t bytes, IoErrorHandler &handler) { 513b635714Speter klausler if constexpr (DIR == Direction::Input) { 523b635714Speter klausler handler.Crash("InternalDescriptorUnit<Direction::Input>::Emit() called"); 533b635714Speter klausler return false && data[bytes] != 0; // bogus compare silences GCC warning 543b635714Speter klausler } else { 553b635714Speter klausler if (bytes <= 0) { 563b635714Speter klausler return true; 573b635714Speter klausler } 583b635714Speter klausler char *record{CurrentRecord()}; 593b635714Speter klausler if (!record) { 603b635714Speter klausler handler.SignalError(IostatInternalWriteOverrun); 6195696d56Speter klausler return false; 6295696d56Speter klausler } 6395696d56Speter klausler auto furthestAfter{std::max(furthestPositionInRecord, 6495696d56Speter klausler positionInRecord + static_cast<std::int64_t>(bytes))}; 6595696d56Speter klausler bool ok{true}; 6695696d56Speter klausler if (furthestAfter > static_cast<std::int64_t>(recordLength.value_or(0))) { 673b635714Speter klausler handler.SignalError(IostatRecordWriteOverrun); 6895696d56Speter klausler furthestAfter = recordLength.value_or(0); 6995696d56Speter klausler bytes = std::max(std::int64_t{0}, furthestAfter - positionInRecord); 7095696d56Speter klausler ok = false; 713b635714Speter klausler } else if (positionInRecord > furthestPositionInRecord) { 72bad52055SPeter Klausler BlankFill(record + furthestPositionInRecord, 73bad52055SPeter Klausler positionInRecord - furthestPositionInRecord); 7495696d56Speter klausler } 7595696d56Speter klausler std::memcpy(record + positionInRecord, data, bytes); 7695696d56Speter klausler positionInRecord += bytes; 7795696d56Speter klausler furthestPositionInRecord = furthestAfter; 7895696d56Speter klausler return ok; 7995696d56Speter klausler } 803b635714Speter klausler } 8195696d56Speter klausler 823b635714Speter klausler template <Direction DIR> 838ebf7411SSlava Zakharin RT_API_ATTRS std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes( 84da25f968SPeter Klausler const char *&p, IoErrorHandler &handler) { 85c2a95ad2SPeter Klausler p = nullptr; 863b635714Speter klausler if constexpr (DIR == Direction::Output) { 87da25f968SPeter Klausler handler.Crash("InternalDescriptorUnit<Direction::Output>::" 88da25f968SPeter Klausler "GetNextInputBytes() called"); 89da25f968SPeter Klausler return 0; 90da25f968SPeter Klausler } else { 913b635714Speter klausler const char *record{CurrentRecord()}; 923b635714Speter klausler if (!record) { 933b635714Speter klausler handler.SignalEnd(); 94da25f968SPeter Klausler return 0; 95da25f968SPeter Klausler } else if (positionInRecord >= recordLength.value_or(positionInRecord)) { 96da25f968SPeter Klausler return 0; 97da25f968SPeter Klausler } else { 98da25f968SPeter Klausler p = &record[positionInRecord]; 99da25f968SPeter Klausler return *recordLength - positionInRecord; 1003b635714Speter klausler } 1013b635714Speter klausler } 102da25f968SPeter Klausler } 103da25f968SPeter Klausler 104da25f968SPeter Klausler template <Direction DIR> 105c2a95ad2SPeter Klausler RT_API_ATTRS std::size_t InternalDescriptorUnit<DIR>::ViewBytesInRecord( 106c2a95ad2SPeter Klausler const char *&p, bool forward) const { 107c2a95ad2SPeter Klausler p = nullptr; 108c2a95ad2SPeter Klausler auto recl{recordLength.value_or(positionInRecord)}; 109c2a95ad2SPeter Klausler const char *record{CurrentRecord()}; 110c2a95ad2SPeter Klausler if (forward) { 111c2a95ad2SPeter Klausler if (positionInRecord < recl) { 112c2a95ad2SPeter Klausler if (record) { 113c2a95ad2SPeter Klausler p = &record[positionInRecord]; 114c2a95ad2SPeter Klausler } 115c2a95ad2SPeter Klausler return recl - positionInRecord; 116c2a95ad2SPeter Klausler } 117c2a95ad2SPeter Klausler } else { 118c2a95ad2SPeter Klausler if (record && positionInRecord <= recl) { 119c2a95ad2SPeter Klausler p = &record[positionInRecord]; 120c2a95ad2SPeter Klausler } 121c2a95ad2SPeter Klausler return positionInRecord - leftTabLimit.value_or(0); 122c2a95ad2SPeter Klausler } 123c2a95ad2SPeter Klausler return 0; 124c2a95ad2SPeter Klausler } 125c2a95ad2SPeter Klausler 126c2a95ad2SPeter Klausler template <Direction DIR> 1278ebf7411SSlava Zakharin RT_API_ATTRS bool InternalDescriptorUnit<DIR>::AdvanceRecord( 1288ebf7411SSlava Zakharin IoErrorHandler &handler) { 12995696d56Speter klausler if (currentRecordNumber >= endfileRecordNumber.value_or(0)) { 130fc71a49eSPeter Klausler if constexpr (DIR == Direction::Input) { 13195696d56Speter klausler handler.SignalEnd(); 132fc71a49eSPeter Klausler } else { 133fc71a49eSPeter Klausler handler.SignalError(IostatInternalWriteOverrun); 134fc71a49eSPeter Klausler } 13595696d56Speter klausler return false; 13695696d56Speter klausler } 137b77fd01aSPeter Klausler if constexpr (DIR == Direction::Output) { 138b77fd01aSPeter Klausler BlankFillOutputRecord(); 13995696d56Speter klausler } 14095696d56Speter klausler ++currentRecordNumber; 14137f98f6fSpeter klausler BeginRecord(); 14295696d56Speter klausler return true; 14395696d56Speter klausler } 14495696d56Speter klausler 1453b635714Speter klausler template <Direction DIR> 1468ebf7411SSlava Zakharin RT_API_ATTRS void InternalDescriptorUnit<DIR>::BlankFill( 1478ebf7411SSlava Zakharin char *at, std::size_t bytes) { 148bad52055SPeter Klausler switch (internalIoCharKind) { 149bad52055SPeter Klausler case 2: 1508ebf7411SSlava Zakharin Fortran::runtime::fill_n(reinterpret_cast<char16_t *>(at), bytes / 2, 151bad52055SPeter Klausler static_cast<char16_t>(' ')); 152bad52055SPeter Klausler break; 153bad52055SPeter Klausler case 4: 1548ebf7411SSlava Zakharin Fortran::runtime::fill_n(reinterpret_cast<char32_t *>(at), bytes / 4, 155bad52055SPeter Klausler static_cast<char32_t>(' ')); 156bad52055SPeter Klausler break; 157bad52055SPeter Klausler default: 1588ebf7411SSlava Zakharin Fortran::runtime::fill_n(at, bytes, ' '); 159bad52055SPeter Klausler break; 160bad52055SPeter Klausler } 161bad52055SPeter Klausler } 162bad52055SPeter Klausler 163bad52055SPeter Klausler template <Direction DIR> 1648ebf7411SSlava Zakharin RT_API_ATTRS void InternalDescriptorUnit<DIR>::BlankFillOutputRecord() { 165b77fd01aSPeter Klausler if constexpr (DIR == Direction::Output) { 166b77fd01aSPeter Klausler if (furthestPositionInRecord < 167b77fd01aSPeter Klausler recordLength.value_or(furthestPositionInRecord)) { 168bad52055SPeter Klausler BlankFill(CurrentRecord() + furthestPositionInRecord, 169bad52055SPeter Klausler *recordLength - furthestPositionInRecord); 170b77fd01aSPeter Klausler } 171b77fd01aSPeter Klausler } 172b77fd01aSPeter Klausler } 173b77fd01aSPeter Klausler 174b77fd01aSPeter Klausler template <Direction DIR> 1758ebf7411SSlava Zakharin RT_API_ATTRS void InternalDescriptorUnit<DIR>::BackspaceRecord( 1768ebf7411SSlava Zakharin IoErrorHandler &handler) { 1773b635714Speter klausler RUNTIME_CHECK(handler, currentRecordNumber > 1); 1783b635714Speter klausler --currentRecordNumber; 17937f98f6fSpeter klausler BeginRecord(); 18095696d56Speter klausler } 18195696d56Speter klausler 1824180b29dSPeter Klausler template <Direction DIR> 1838ebf7411SSlava Zakharin RT_API_ATTRS std::int64_t InternalDescriptorUnit<DIR>::InquirePos() { 1844180b29dSPeter Klausler return (currentRecordNumber - 1) * recordLength.value_or(0) + 1854180b29dSPeter Klausler positionInRecord + 1; 1864180b29dSPeter Klausler } 1874180b29dSPeter Klausler 1883b635714Speter klausler template class InternalDescriptorUnit<Direction::Output>; 1893b635714Speter klausler template class InternalDescriptorUnit<Direction::Input>; 1908ebf7411SSlava Zakharin 1918ebf7411SSlava Zakharin RT_OFFLOAD_API_GROUP_END 1921f879005STim Keith } // namespace Fortran::runtime::io 193