236
|
1 //===-- runtime/internal-unit.cpp -----------------------------------------===//
|
173
|
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 #include "internal-unit.h"
|
|
10 #include "io-error.h"
|
236
|
11 #include "flang/Runtime/descriptor.h"
|
173
|
12 #include <algorithm>
|
|
13 #include <type_traits>
|
|
14
|
|
15 namespace Fortran::runtime::io {
|
|
16
|
|
17 template <Direction DIR>
|
|
18 InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
|
236
|
19 Scalar scalar, std::size_t length, int kind) {
|
|
20 internalIoCharKind = kind;
|
173
|
21 recordLength = length;
|
|
22 endfileRecordNumber = 2;
|
|
23 void *pointer{reinterpret_cast<void *>(const_cast<char *>(scalar))};
|
236
|
24 descriptor().Establish(TypeCode{TypeCategory::Character, kind}, length * kind,
|
|
25 pointer, 0, nullptr, CFI_attribute_pointer);
|
173
|
26 }
|
|
27
|
|
28 template <Direction DIR>
|
|
29 InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
|
|
30 const Descriptor &that, const Terminator &terminator) {
|
236
|
31 auto thatType{that.type().GetCategoryAndKind()};
|
|
32 RUNTIME_CHECK(terminator, thatType.has_value());
|
|
33 RUNTIME_CHECK(terminator, thatType->first == TypeCategory::Character);
|
173
|
34 Descriptor &d{descriptor()};
|
|
35 RUNTIME_CHECK(
|
|
36 terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0));
|
|
37 new (&d) Descriptor{that};
|
|
38 d.Check();
|
236
|
39 internalIoCharKind = thatType->second;
|
173
|
40 recordLength = d.ElementBytes();
|
|
41 endfileRecordNumber = d.Elements() + 1;
|
|
42 }
|
|
43
|
|
44 template <Direction DIR> void InternalDescriptorUnit<DIR>::EndIoStatement() {
|
236
|
45 if constexpr (DIR == Direction::Output) {
|
|
46 // Clear the remainder of the current record if anything was written
|
|
47 // to it, or if it is the only record.
|
|
48 auto end{endfileRecordNumber.value_or(0)};
|
|
49 if (currentRecordNumber < end &&
|
|
50 (end == 2 || furthestPositionInRecord > 0)) {
|
|
51 BlankFillOutputRecord();
|
173
|
52 }
|
|
53 }
|
|
54 }
|
|
55
|
|
56 template <Direction DIR>
|
|
57 bool InternalDescriptorUnit<DIR>::Emit(
|
|
58 const char *data, std::size_t bytes, IoErrorHandler &handler) {
|
|
59 if constexpr (DIR == Direction::Input) {
|
|
60 handler.Crash("InternalDescriptorUnit<Direction::Input>::Emit() called");
|
|
61 return false && data[bytes] != 0; // bogus compare silences GCC warning
|
|
62 } else {
|
|
63 if (bytes <= 0) {
|
|
64 return true;
|
|
65 }
|
|
66 char *record{CurrentRecord()};
|
|
67 if (!record) {
|
|
68 handler.SignalError(IostatInternalWriteOverrun);
|
|
69 return false;
|
|
70 }
|
|
71 auto furthestAfter{std::max(furthestPositionInRecord,
|
|
72 positionInRecord + static_cast<std::int64_t>(bytes))};
|
|
73 bool ok{true};
|
|
74 if (furthestAfter > static_cast<std::int64_t>(recordLength.value_or(0))) {
|
|
75 handler.SignalError(IostatRecordWriteOverrun);
|
|
76 furthestAfter = recordLength.value_or(0);
|
|
77 bytes = std::max(std::int64_t{0}, furthestAfter - positionInRecord);
|
|
78 ok = false;
|
|
79 } else if (positionInRecord > furthestPositionInRecord) {
|
236
|
80 BlankFill(record + furthestPositionInRecord,
|
|
81 positionInRecord - furthestPositionInRecord);
|
173
|
82 }
|
|
83 std::memcpy(record + positionInRecord, data, bytes);
|
|
84 positionInRecord += bytes;
|
|
85 furthestPositionInRecord = furthestAfter;
|
|
86 return ok;
|
|
87 }
|
|
88 }
|
|
89
|
|
90 template <Direction DIR>
|
236
|
91 std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
|
|
92 const char *&p, IoErrorHandler &handler) {
|
173
|
93 if constexpr (DIR == Direction::Output) {
|
236
|
94 handler.Crash("InternalDescriptorUnit<Direction::Output>::"
|
|
95 "GetNextInputBytes() called");
|
|
96 return 0;
|
|
97 } else {
|
|
98 const char *record{CurrentRecord()};
|
|
99 if (!record) {
|
|
100 handler.SignalEnd();
|
|
101 return 0;
|
|
102 } else if (positionInRecord >= recordLength.value_or(positionInRecord)) {
|
|
103 return 0;
|
|
104 } else {
|
|
105 p = &record[positionInRecord];
|
|
106 return *recordLength - positionInRecord;
|
|
107 }
|
173
|
108 }
|
|
109 }
|
|
110
|
|
111 template <Direction DIR>
|
|
112 bool InternalDescriptorUnit<DIR>::AdvanceRecord(IoErrorHandler &handler) {
|
|
113 if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
|
|
114 handler.SignalEnd();
|
|
115 return false;
|
|
116 }
|
236
|
117 if constexpr (DIR == Direction::Output) {
|
|
118 BlankFillOutputRecord();
|
173
|
119 }
|
|
120 ++currentRecordNumber;
|
221
|
121 BeginRecord();
|
173
|
122 return true;
|
|
123 }
|
|
124
|
|
125 template <Direction DIR>
|
236
|
126 void InternalDescriptorUnit<DIR>::BlankFill(char *at, std::size_t bytes) {
|
|
127 switch (internalIoCharKind) {
|
|
128 case 2:
|
|
129 std::fill_n(reinterpret_cast<char16_t *>(at), bytes / 2,
|
|
130 static_cast<char16_t>(' '));
|
|
131 break;
|
|
132 case 4:
|
|
133 std::fill_n(reinterpret_cast<char32_t *>(at), bytes / 4,
|
|
134 static_cast<char32_t>(' '));
|
|
135 break;
|
|
136 default:
|
|
137 std::fill_n(at, bytes, ' ');
|
|
138 break;
|
|
139 }
|
|
140 }
|
|
141
|
|
142 template <Direction DIR>
|
|
143 void InternalDescriptorUnit<DIR>::BlankFillOutputRecord() {
|
|
144 if constexpr (DIR == Direction::Output) {
|
|
145 if (furthestPositionInRecord <
|
|
146 recordLength.value_or(furthestPositionInRecord)) {
|
|
147 BlankFill(CurrentRecord() + furthestPositionInRecord,
|
|
148 *recordLength - furthestPositionInRecord);
|
|
149 }
|
|
150 }
|
|
151 }
|
|
152
|
|
153 template <Direction DIR>
|
173
|
154 void InternalDescriptorUnit<DIR>::BackspaceRecord(IoErrorHandler &handler) {
|
|
155 RUNTIME_CHECK(handler, currentRecordNumber > 1);
|
|
156 --currentRecordNumber;
|
221
|
157 BeginRecord();
|
173
|
158 }
|
|
159
|
|
160 template class InternalDescriptorUnit<Direction::Output>;
|
|
161 template class InternalDescriptorUnit<Direction::Input>;
|
|
162 } // namespace Fortran::runtime::io
|