blob: b9eed2101ecfc94e2cfd0f63226fd1e77e836cd3 [file] [log] [blame]
Diana Picus651f58b2021-09-02 08:14:011//===-- runtime/namelist.cpp ----------------------------------------------===//
peter klausler6a1c3ef2021-05-05 18:37:492//
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 "namelist.h"
10#include "descriptor-io.h"
Peter Klauslerbad52052022-08-03 19:31:0511#include "emit-encoded.h"
peter klausler6a1c3ef2021-05-05 18:37:4912#include "io-stmt.h"
Peter Klausler830c0b92021-09-01 23:00:5313#include "flang/Runtime/io-api.h"
peter klausler89a927c2021-10-21 21:13:2114#include <algorithm>
peter klausler6a1c3ef2021-05-05 18:37:4915#include <cstring>
16#include <limits>
17
18namespace Fortran::runtime::io {
19
Slava Zakharinf3c31d72024-04-05 15:29:2420RT_VAR_GROUP_BEGIN
peter klausler79caf692021-06-17 20:13:1921// Max size of a group, symbol or component identifier that can appear in
22// NAMELIST input, plus a byte for NUL termination.
Slava Zakharinf3c31d72024-04-05 15:29:2423static constexpr RT_CONST_VAR_ATTRS std::size_t nameBufferSize{201};
24RT_VAR_GROUP_END
peter klausler79caf692021-06-17 20:13:1925
Slava Zakharinf3c31d72024-04-05 15:29:2426RT_OFFLOAD_API_GROUP_BEGIN
27
28static inline RT_API_ATTRS char32_t GetComma(IoStatementState &io) {
Peter Klausler896a5432022-01-20 00:25:4129 return io.mutableModes().editingFlags & decimalComma ? char32_t{';'}
30 : char32_t{','};
31}
32
Slava Zakharinf3c31d72024-04-05 15:29:2433bool IODEF(OutputNamelist)(Cookie cookie, const NamelistGroup &group) {
peter klausler6a1c3ef2021-05-05 18:37:4934 IoStatementState &io{*cookie};
35 io.CheckFormattedStmtType<Direction::Output>("OutputNamelist");
Peter Klausler9772dbb2022-01-27 20:09:0736 io.mutableModes().inNamelist = true;
Peter Klausler9772dbb2022-01-27 20:09:0737 ConnectionState &connection{io.GetConnectionState()};
Slava Zakharin8ebf7412024-03-25 23:01:2538 // The following lambda definition violates the conding style,
39 // but cuda-11.8 nvcc hits an internal error with the brace initialization.
40
Peter Klauslerf08b55d2024-01-15 18:02:5241 // Internal function to advance records and convert case
Slava Zakharin8ebf7412024-03-25 23:01:2542 const auto EmitUpperCase = [&](const char *prefix, std::size_t prefixLen,
43 const char *str, char suffix) -> bool {
Peter Klauslerf08b55d2024-01-15 18:02:5244 if ((connection.NeedAdvance(prefixLen) &&
45 !(io.AdvanceRecord() && EmitAscii(io, " ", 1))) ||
46 !EmitAscii(io, prefix, prefixLen) ||
Slava Zakharinf3c31d72024-04-05 15:29:2447 (connection.NeedAdvance(
48 Fortran::runtime::strlen(str) + (suffix != ' ')) &&
Peter Klauslerf08b55d2024-01-15 18:02:5249 !(io.AdvanceRecord() && EmitAscii(io, " ", 1)))) {
peter klausler6a1c3ef2021-05-05 18:37:4950 return false;
51 }
52 for (; *str; ++str) {
53 char up{*str >= 'a' && *str <= 'z' ? static_cast<char>(*str - 'a' + 'A')
54 : *str};
Peter Klauslerbad52052022-08-03 19:31:0555 if (!EmitAscii(io, &up, 1)) {
peter klausler6a1c3ef2021-05-05 18:37:4956 return false;
57 }
58 }
Peter Klauslerf08b55d2024-01-15 18:02:5259 return suffix == ' ' || EmitAscii(io, &suffix, 1);
Slava Zakharin8ebf7412024-03-25 23:01:2560 };
peter klausler6a1c3ef2021-05-05 18:37:4961 // &GROUP
Peter Klauslerf08b55d2024-01-15 18:02:5262 if (!EmitUpperCase(" &", 2, group.groupName, ' ')) {
peter klausler6a1c3ef2021-05-05 18:37:4963 return false;
64 }
Peter Klausler3a96446d2022-02-17 23:32:0665 auto *listOutput{io.get_if<ListDirectedStatementState<Direction::Output>>()};
Peter Klauslerf08b55d2024-01-15 18:02:5266 char comma{static_cast<char>(GetComma(io))};
67 char prefix{' '};
peter klausler6a1c3ef2021-05-05 18:37:4968 for (std::size_t j{0}; j < group.items; ++j) {
69 // [,]ITEM=...
70 const NamelistGroup::Item &item{group.item[j]};
Peter Klausler3a96446d2022-02-17 23:32:0671 if (listOutput) {
72 listOutput->set_lastWasUndelimitedCharacter(false);
73 }
Peter Klauslerf08b55d2024-01-15 18:02:5274 if (!EmitUpperCase(&prefix, 1, item.name, '=')) {
Peter Klausler7cf16082023-04-13 17:28:1975 return false;
76 }
Peter Klauslerf08b55d2024-01-15 18:02:5277 prefix = comma;
Peter Klausler7cf16082023-04-13 17:28:1978 if (const auto *addendum{item.descriptor.Addendum()};
79 addendum && addendum->derivedType()) {
V Donaldson6f7a3b02023-05-16 20:34:5780 const NonTbpDefinedIoTable *table{group.nonTbpDefinedIo};
Peter Klausler7cf16082023-04-13 17:28:1981 if (!IONAME(OutputDerivedType)(cookie, item.descriptor, table)) {
82 return false;
83 }
84 } else if (!descr::DescriptorIO<Direction::Output>(io, item.descriptor)) {
peter klausler6a1c3ef2021-05-05 18:37:4985 return false;
86 }
87 }
88 // terminal /
Peter Klauslerf08b55d2024-01-15 18:02:5289 return EmitUpperCase("/", 1, "", ' ');
peter klausler6a1c3ef2021-05-05 18:37:4990}
91
Slava Zakharinf3c31d72024-04-05 15:29:2492static constexpr RT_API_ATTRS bool IsLegalIdStart(char32_t ch) {
peter klausler79caf692021-06-17 20:13:1993 return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_' ||
Peter Klausler120ad252024-01-02 16:42:1094 ch == '@';
peter klausler79caf692021-06-17 20:13:1995}
96
Slava Zakharinf3c31d72024-04-05 15:29:2497static constexpr RT_API_ATTRS bool IsLegalIdChar(char32_t ch) {
peter klausler79caf692021-06-17 20:13:1998 return IsLegalIdStart(ch) || (ch >= '0' && ch <= '9');
99}
100
Slava Zakharinf3c31d72024-04-05 15:29:24101static constexpr RT_API_ATTRS char NormalizeIdChar(char32_t ch) {
peter klausler79caf692021-06-17 20:13:19102 return static_cast<char>(ch >= 'A' && ch <= 'Z' ? ch - 'A' + 'a' : ch);
103}
104
Slava Zakharinf3c31d72024-04-05 15:29:24105static RT_API_ATTRS bool GetLowerCaseName(
peter klausler6a1c3ef2021-05-05 18:37:49106 IoStatementState &io, char buffer[], std::size_t maxLength) {
Peter Klauslerbafbae22022-03-16 19:32:03107 std::size_t byteLength{0};
108 if (auto ch{io.GetNextNonBlank(byteLength)}) {
peter klausler6a1c3ef2021-05-05 18:37:49109 if (IsLegalIdStart(*ch)) {
110 std::size_t j{0};
111 do {
peter klausler79caf692021-06-17 20:13:19112 buffer[j] = NormalizeIdChar(*ch);
Peter Klauslerbafbae22022-03-16 19:32:03113 io.HandleRelativePosition(byteLength);
114 ch = io.GetCurrentChar(byteLength);
peter klausler79caf692021-06-17 20:13:19115 } while (++j < maxLength && ch && IsLegalIdChar(*ch));
peter klausler6a1c3ef2021-05-05 18:37:49116 buffer[j++] = '\0';
117 if (j <= maxLength) {
118 return true;
119 }
120 io.GetIoErrorHandler().SignalError(
121 "Identifier '%s...' in NAMELIST input group is too long", buffer);
122 }
123 }
124 return false;
125}
126
Slava Zakharinf3c31d72024-04-05 15:29:24127static RT_API_ATTRS Fortran::common::optional<SubscriptValue> GetSubscriptValue(
Slava Zakharin71e02612024-03-15 21:25:47128 IoStatementState &io) {
129 Fortran::common::optional<SubscriptValue> value;
Peter Klauslerbafbae22022-03-16 19:32:03130 std::size_t byteCount{0};
Slava Zakharin71e02612024-03-15 21:25:47131 Fortran::common::optional<char32_t> ch{io.GetCurrentChar(byteCount)};
peter klausler6a1c3ef2021-05-05 18:37:49132 bool negate{ch && *ch == '-'};
Peter Klausler922c29c2022-01-12 23:10:20133 if ((ch && *ch == '+') || negate) {
Peter Klauslerbafbae22022-03-16 19:32:03134 io.HandleRelativePosition(byteCount);
135 ch = io.GetCurrentChar(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49136 }
137 bool overflow{false};
138 while (ch && *ch >= '0' && *ch <= '9') {
139 SubscriptValue was{value.value_or(0)};
140 overflow |= was >= std::numeric_limits<SubscriptValue>::max() / 10;
141 value = 10 * was + *ch - '0';
Peter Klauslerbafbae22022-03-16 19:32:03142 io.HandleRelativePosition(byteCount);
143 ch = io.GetCurrentChar(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49144 }
145 if (overflow) {
146 io.GetIoErrorHandler().SignalError(
147 "NAMELIST input subscript value overflow");
Slava Zakharin71e02612024-03-15 21:25:47148 return Fortran::common::nullopt;
peter klausler6a1c3ef2021-05-05 18:37:49149 }
150 if (negate) {
151 if (value) {
152 return -*value;
153 } else {
Peter Klauslerbafbae22022-03-16 19:32:03154 io.HandleRelativePosition(-byteCount); // give back '-' with no digits
peter klausler6a1c3ef2021-05-05 18:37:49155 }
156 }
157 return value;
158}
159
Slava Zakharinf3c31d72024-04-05 15:29:24160static RT_API_ATTRS bool HandleSubscripts(IoStatementState &io,
161 Descriptor &desc, const Descriptor &source, const char *name) {
peter klausler6a1c3ef2021-05-05 18:37:49162 IoErrorHandler &handler{io.GetIoErrorHandler()};
peter klausler79caf692021-06-17 20:13:19163 // Allow for blanks in subscripts; they're nonstandard, but not
164 // ambiguous within the parentheses.
peter klausler6a1c3ef2021-05-05 18:37:49165 SubscriptValue lower[maxRank], upper[maxRank], stride[maxRank];
166 int j{0};
peter klausler89a927c2021-10-21 21:13:21167 std::size_t contiguousStride{source.ElementBytes()};
peter klausler6a1c3ef2021-05-05 18:37:49168 bool ok{true};
Peter Klauslerbafbae22022-03-16 19:32:03169 std::size_t byteCount{0};
Slava Zakharin71e02612024-03-15 21:25:47170 Fortran::common::optional<char32_t> ch{io.GetNextNonBlank(byteCount)};
Peter Klausler896a5432022-01-20 00:25:41171 char32_t comma{GetComma(io)};
peter klausler6a1c3ef2021-05-05 18:37:49172 for (; ch && *ch != ')'; ++j) {
173 SubscriptValue dimLower{0}, dimUpper{0}, dimStride{0};
174 if (j < maxRank && j < source.rank()) {
175 const Dimension &dim{source.GetDimension(j)};
176 dimLower = dim.LowerBound();
177 dimUpper = dim.UpperBound();
peter klausler89a927c2021-10-21 21:13:21178 dimStride =
179 dim.ByteStride() / std::max<SubscriptValue>(contiguousStride, 1);
180 contiguousStride *= dim.Extent();
peter klausler6a1c3ef2021-05-05 18:37:49181 } else if (ok) {
182 handler.SignalError(
183 "Too many subscripts for rank-%d NAMELIST group item '%s'",
184 source.rank(), name);
185 ok = false;
186 }
187 if (auto low{GetSubscriptValue(io)}) {
188 if (*low < dimLower || (dimUpper >= dimLower && *low > dimUpper)) {
189 if (ok) {
190 handler.SignalError("Subscript %jd out of range %jd..%jd in NAMELIST "
191 "group item '%s' dimension %d",
192 static_cast<std::intmax_t>(*low),
193 static_cast<std::intmax_t>(dimLower),
194 static_cast<std::intmax_t>(dimUpper), name, j + 1);
195 ok = false;
196 }
197 } else {
198 dimLower = *low;
199 }
Peter Klauslerbafbae22022-03-16 19:32:03200 ch = io.GetNextNonBlank(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49201 }
202 if (ch && *ch == ':') {
Peter Klauslerbafbae22022-03-16 19:32:03203 io.HandleRelativePosition(byteCount);
204 ch = io.GetNextNonBlank(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49205 if (auto high{GetSubscriptValue(io)}) {
206 if (*high > dimUpper) {
207 if (ok) {
208 handler.SignalError(
209 "Subscript triplet upper bound %jd out of range (>%jd) in "
210 "NAMELIST group item '%s' dimension %d",
211 static_cast<std::intmax_t>(*high),
212 static_cast<std::intmax_t>(dimUpper), name, j + 1);
213 ok = false;
214 }
215 } else {
216 dimUpper = *high;
217 }
Peter Klauslerbafbae22022-03-16 19:32:03218 ch = io.GetNextNonBlank(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49219 }
220 if (ch && *ch == ':') {
Peter Klauslerbafbae22022-03-16 19:32:03221 io.HandleRelativePosition(byteCount);
222 ch = io.GetNextNonBlank(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49223 if (auto str{GetSubscriptValue(io)}) {
224 dimStride = *str;
Peter Klauslerbafbae22022-03-16 19:32:03225 ch = io.GetNextNonBlank(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49226 }
227 }
228 } else { // scalar
229 dimUpper = dimLower;
230 dimStride = 0;
231 }
Peter Klausler896a5432022-01-20 00:25:41232 if (ch && *ch == comma) {
Peter Klauslerbafbae22022-03-16 19:32:03233 io.HandleRelativePosition(byteCount);
234 ch = io.GetNextNonBlank(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49235 }
236 if (ok) {
237 lower[j] = dimLower;
238 upper[j] = dimUpper;
239 stride[j] = dimStride;
240 }
241 }
242 if (ok) {
243 if (ch && *ch == ')') {
Peter Klauslerbafbae22022-03-16 19:32:03244 io.HandleRelativePosition(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49245 if (desc.EstablishPointerSection(source, lower, upper, stride)) {
246 return true;
247 } else {
248 handler.SignalError(
249 "Bad subscripts for NAMELIST input group item '%s'", name);
250 }
251 } else {
252 handler.SignalError(
253 "Bad subscripts (missing ')') for NAMELIST input group item '%s'",
254 name);
255 }
256 }
257 return false;
258}
259
Slava Zakharinf3c31d72024-04-05 15:29:24260static RT_API_ATTRS void StorageSequenceExtension(
Peter Klauslerdea30ac2024-01-02 17:25:49261 Descriptor &desc, const Descriptor &source) {
262 // Support the near-universal extension of NAMELIST input into a
263 // designatable storage sequence identified by its initial scalar array
264 // element. For example, treat "A(1) = 1. 2. 3." as if it had been
265 // "A(1:) = 1. 2. 3.".
266 if (desc.rank() == 0 && (source.rank() == 1 || source.IsContiguous())) {
267 if (auto stride{source.rank() == 1
268 ? source.GetDimension(0).ByteStride()
269 : static_cast<SubscriptValue>(source.ElementBytes())};
270 stride != 0) {
271 desc.raw().attribute = CFI_attribute_pointer;
272 desc.raw().rank = 1;
273 desc.GetDimension(0)
274 .SetBounds(1,
275 source.Elements() -
276 ((source.OffsetElement() - desc.OffsetElement()) / stride))
277 .SetByteStride(stride);
278 }
279 }
280}
281
Slava Zakharinf3c31d72024-04-05 15:29:24282static RT_API_ATTRS bool HandleSubstring(
Peter Klausler0ab17082022-01-07 21:39:28283 IoStatementState &io, Descriptor &desc, const char *name) {
284 IoErrorHandler &handler{io.GetIoErrorHandler()};
285 auto pair{desc.type().GetCategoryAndKind()};
286 if (!pair || pair->first != TypeCategory::Character) {
287 handler.SignalError("Substring reference to non-character item '%s'", name);
288 return false;
289 }
290 int kind{pair->second};
291 SubscriptValue chars{static_cast<SubscriptValue>(desc.ElementBytes()) / kind};
292 // Allow for blanks in substring bounds; they're nonstandard, but not
293 // ambiguous within the parentheses.
Slava Zakharin71e02612024-03-15 21:25:47294 Fortran::common::optional<SubscriptValue> lower, upper;
Peter Klauslerbafbae22022-03-16 19:32:03295 std::size_t byteCount{0};
Slava Zakharin71e02612024-03-15 21:25:47296 Fortran::common::optional<char32_t> ch{io.GetNextNonBlank(byteCount)};
Peter Klausler0ab17082022-01-07 21:39:28297 if (ch) {
298 if (*ch == ':') {
299 lower = 1;
300 } else {
301 lower = GetSubscriptValue(io);
Peter Klauslerbafbae22022-03-16 19:32:03302 ch = io.GetNextNonBlank(byteCount);
Peter Klausler0ab17082022-01-07 21:39:28303 }
304 }
Slava Zakharin8ebf7412024-03-25 23:01:25305 if (ch && *ch == ':') {
Peter Klauslerbafbae22022-03-16 19:32:03306 io.HandleRelativePosition(byteCount);
307 ch = io.GetNextNonBlank(byteCount);
Peter Klausler0ab17082022-01-07 21:39:28308 if (ch) {
309 if (*ch == ')') {
310 upper = chars;
311 } else {
312 upper = GetSubscriptValue(io);
Peter Klauslerbafbae22022-03-16 19:32:03313 ch = io.GetNextNonBlank(byteCount);
Peter Klausler0ab17082022-01-07 21:39:28314 }
315 }
316 }
317 if (ch && *ch == ')') {
Peter Klauslerbafbae22022-03-16 19:32:03318 io.HandleRelativePosition(byteCount);
Peter Klausler0ab17082022-01-07 21:39:28319 if (lower && upper) {
320 if (*lower > *upper) {
321 // An empty substring, whatever the values are
322 desc.raw().elem_len = 0;
323 return true;
324 }
Peter Klausler15e4a3c2024-01-25 23:15:20325 if (*lower >= 1 && *upper <= chars) {
Peter Klausler0ab17082022-01-07 21:39:28326 // Offset the base address & adjust the element byte length
327 desc.raw().elem_len = (*upper - *lower + 1) * kind;
328 desc.set_base_addr(reinterpret_cast<void *>(
329 reinterpret_cast<char *>(desc.raw().base_addr) +
330 kind * (*lower - 1)));
331 return true;
332 }
333 }
334 handler.SignalError(
335 "Bad substring bounds for NAMELIST input group item '%s'", name);
336 } else {
337 handler.SignalError(
338 "Bad substring (missing ')') for NAMELIST input group item '%s'", name);
339 }
340 return false;
341}
342
Slava Zakharinf3c31d72024-04-05 15:29:24343static RT_API_ATTRS bool HandleComponent(IoStatementState &io, Descriptor &desc,
peter klausler79caf692021-06-17 20:13:19344 const Descriptor &source, const char *name) {
345 IoErrorHandler &handler{io.GetIoErrorHandler()};
peter klausler79caf692021-06-17 20:13:19346 char compName[nameBufferSize];
347 if (GetLowerCaseName(io, compName, sizeof compName)) {
348 const DescriptorAddendum *addendum{source.Addendum()};
349 if (const typeInfo::DerivedType *
350 type{addendum ? addendum->derivedType() : nullptr}) {
351 if (const typeInfo::Component *
Slava Zakharinf3c31d72024-04-05 15:29:24352 comp{type->FindDataComponent(
353 compName, Fortran::runtime::strlen(compName))}) {
Peter Klausler6e7df702022-10-04 21:14:05354 bool createdDesc{false};
355 if (comp->rank() > 0 && source.rank() > 0) {
356 // If base and component are both arrays, the component name
357 // must be followed by subscripts; process them now.
358 std::size_t byteCount{0};
Slava Zakharin71e02612024-03-15 21:25:47359 if (Fortran::common::optional<char32_t> next{
360 io.GetNextNonBlank(byteCount)};
Peter Klausler6e7df702022-10-04 21:14:05361 next && *next == '(') {
362 io.HandleRelativePosition(byteCount); // skip over '('
363 StaticDescriptor<maxRank, true, 16> staticDesc;
364 Descriptor &tmpDesc{staticDesc.descriptor()};
365 comp->CreatePointerDescriptor(tmpDesc, source, handler);
366 if (!HandleSubscripts(io, desc, tmpDesc, compName)) {
367 return false;
368 }
369 createdDesc = true;
370 }
371 }
372 if (!createdDesc) {
373 comp->CreatePointerDescriptor(desc, source, handler);
374 }
375 if (source.rank() > 0) {
376 if (desc.rank() > 0) {
377 handler.SignalError(
378 "NAMELIST component reference '%%%s' of input group "
379 "item %s cannot be an array when its base is not scalar",
380 compName, name);
381 return false;
382 }
383 desc.raw().rank = source.rank();
384 for (int j{0}; j < source.rank(); ++j) {
385 const auto &srcDim{source.GetDimension(j)};
386 desc.GetDimension(j)
387 .SetBounds(1, srcDim.UpperBound())
388 .SetByteStride(srcDim.ByteStride());
389 }
390 }
peter klausler79caf692021-06-17 20:13:19391 return true;
392 } else {
393 handler.SignalError(
394 "NAMELIST component reference '%%%s' of input group item %s is not "
395 "a component of its derived type",
396 compName, name);
397 }
peter klausler6d443872021-10-20 23:01:52398 } else if (source.type().IsDerived()) {
399 handler.Crash("Derived type object '%s' in NAMELIST is missing its "
400 "derived type information!",
401 name);
peter klausler79caf692021-06-17 20:13:19402 } else {
403 handler.SignalError("NAMELIST component reference '%%%s' of input group "
404 "item %s for non-derived type",
405 compName, name);
406 }
407 } else {
408 handler.SignalError("NAMELIST component reference of input group item %s "
Peter Klausler38382452022-08-14 17:02:30409 "has no name after '%%'",
peter klausler79caf692021-06-17 20:13:19410 name);
411 }
412 return false;
413}
414
Peter Klausler120ad252024-01-02 16:42:10415// Advance to the terminal '/' of a namelist group or leading '&'/'$'
416// of the next.
Slava Zakharinf3c31d72024-04-05 15:29:24417static RT_API_ATTRS void SkipNamelistGroup(IoStatementState &io) {
Peter Klauslerbafbae22022-03-16 19:32:03418 std::size_t byteCount{0};
419 while (auto ch{io.GetNextNonBlank(byteCount)}) {
420 io.HandleRelativePosition(byteCount);
Peter Klausler120ad252024-01-02 16:42:10421 if (*ch == '/' || *ch == '&' || *ch == '$') {
Peter Klauslerd1123e32022-01-13 01:34:52422 break;
423 } else if (*ch == '\'' || *ch == '"') {
424 // Skip quoted character literal
425 char32_t quote{*ch};
426 while (true) {
Peter Klauslerbafbae22022-03-16 19:32:03427 if ((ch = io.GetCurrentChar(byteCount))) {
428 io.HandleRelativePosition(byteCount);
Peter Klauslerd1123e32022-01-13 01:34:52429 if (*ch == quote) {
430 break;
431 }
432 } else if (!io.AdvanceRecord()) {
433 return;
434 }
435 }
436 }
437 }
438}
439
Slava Zakharinf3c31d72024-04-05 15:29:24440bool IODEF(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
peter klausler6a1c3ef2021-05-05 18:37:49441 IoStatementState &io{*cookie};
442 io.CheckFormattedStmtType<Direction::Input>("InputNamelist");
Peter Klausler9772dbb2022-01-27 20:09:07443 io.mutableModes().inNamelist = true;
peter klausler6a1c3ef2021-05-05 18:37:49444 IoErrorHandler &handler{io.GetIoErrorHandler()};
peter klauslere093cbb2021-07-21 20:07:04445 auto *listInput{io.get_if<ListDirectedStatementState<Direction::Input>>()};
446 RUNTIME_CHECK(handler, listInput != nullptr);
Peter Klauslerd1123e32022-01-13 01:34:52447 // Find this namelist group's header in the input
peter klausler4c15a972021-08-13 18:57:58448 io.BeginReadingRecord();
Slava Zakharin71e02612024-03-15 21:25:47449 Fortran::common::optional<char32_t> next;
peter klausler79caf692021-06-17 20:13:19450 char name[nameBufferSize];
peter klausler6a1c3ef2021-05-05 18:37:49451 RUNTIME_CHECK(handler, group.groupName != nullptr);
Peter Klausler896a5432022-01-20 00:25:41452 char32_t comma{GetComma(io)};
Peter Klauslerbafbae22022-03-16 19:32:03453 std::size_t byteCount{0};
Peter Klauslerd1123e32022-01-13 01:34:52454 while (true) {
Peter Klauslerbafbae22022-03-16 19:32:03455 next = io.GetNextNonBlank(byteCount);
Peter Klausler120ad252024-01-02 16:42:10456 while (next && *next != '&' && *next != '$') {
Peter Klauslerd1123e32022-01-13 01:34:52457 // Extension: comment lines without ! before namelist groups
458 if (!io.AdvanceRecord()) {
459 next.reset();
460 } else {
Peter Klauslerbafbae22022-03-16 19:32:03461 next = io.GetNextNonBlank(byteCount);
Peter Klauslerd1123e32022-01-13 01:34:52462 }
463 }
Peter Klauslera5f5d722022-10-04 18:40:38464 if (!next) {
465 handler.SignalEnd();
466 return false;
467 }
Peter Klausler120ad252024-01-02 16:42:10468 if (*next != '&' && *next != '$') {
Peter Klauslerd1123e32022-01-13 01:34:52469 handler.SignalError(
Peter Klausler120ad252024-01-02 16:42:10470 "NAMELIST input group does not begin with '&' or '$' (at '%lc')",
471 *next);
Peter Klauslerd1123e32022-01-13 01:34:52472 return false;
473 }
Peter Klauslerbafbae22022-03-16 19:32:03474 io.HandleRelativePosition(byteCount);
Peter Klauslerd1123e32022-01-13 01:34:52475 if (!GetLowerCaseName(io, name, sizeof name)) {
476 handler.SignalError("NAMELIST input group has no name");
477 return false;
478 }
Slava Zakharinf3c31d72024-04-05 15:29:24479 if (Fortran::runtime::strcmp(group.groupName, name) == 0) {
Peter Klauslerd1123e32022-01-13 01:34:52480 break; // found it
481 }
482 SkipNamelistGroup(io);
peter klausler6a1c3ef2021-05-05 18:37:49483 }
484 // Read the group's items
485 while (true) {
Peter Klauslerbafbae22022-03-16 19:32:03486 next = io.GetNextNonBlank(byteCount);
Peter Klausler120ad252024-01-02 16:42:10487 if (!next || *next == '/' || *next == '&' || *next == '$') {
peter klausler6a1c3ef2021-05-05 18:37:49488 break;
489 }
490 if (!GetLowerCaseName(io, name, sizeof name)) {
491 handler.SignalError(
Peter Klausler896a5432022-01-20 00:25:41492 "NAMELIST input group '%s' was not terminated at '%c'",
493 group.groupName, static_cast<char>(*next));
peter klausler6a1c3ef2021-05-05 18:37:49494 return false;
495 }
496 std::size_t itemIndex{0};
497 for (; itemIndex < group.items; ++itemIndex) {
Slava Zakharinf3c31d72024-04-05 15:29:24498 if (Fortran::runtime::strcmp(name, group.item[itemIndex].name) == 0) {
peter klausler6a1c3ef2021-05-05 18:37:49499 break;
500 }
501 }
502 if (itemIndex >= group.items) {
503 handler.SignalError(
504 "'%s' is not an item in NAMELIST group '%s'", name, group.groupName);
505 return false;
506 }
507 // Handle indexing and components, if any. No spaces are allowed.
508 // A copy of the descriptor is made if necessary.
509 const Descriptor &itemDescriptor{group.item[itemIndex].descriptor};
510 const Descriptor *useDescriptor{&itemDescriptor};
511 StaticDescriptor<maxRank, true, 16> staticDesc[2];
512 int whichStaticDesc{0};
Peter Klauslerbafbae22022-03-16 19:32:03513 next = io.GetCurrentChar(byteCount);
Peter Klausler0ab17082022-01-07 21:39:28514 bool hadSubscripts{false};
515 bool hadSubstring{false};
peter klausler6a1c3ef2021-05-05 18:37:49516 if (next && (*next == '(' || *next == '%')) {
Peter Klauslerdea30ac2024-01-02 17:25:49517 const Descriptor *lastSubscriptBase{nullptr};
518 Descriptor *lastSubscriptDescriptor{nullptr};
peter klausler6a1c3ef2021-05-05 18:37:49519 do {
peter klausler79caf692021-06-17 20:13:19520 Descriptor &mutableDescriptor{staticDesc[whichStaticDesc].descriptor()};
521 whichStaticDesc ^= 1;
Peter Klauslerbad52052022-08-03 19:31:05522 io.HandleRelativePosition(byteCount); // skip over '(' or '%'
Peter Klauslerdea30ac2024-01-02 17:25:49523 lastSubscriptDescriptor = nullptr;
524 lastSubscriptBase = nullptr;
peter klausler6a1c3ef2021-05-05 18:37:49525 if (*next == '(') {
Peter Klausler0ab17082022-01-07 21:39:28526 if (!hadSubstring && (hadSubscripts || useDescriptor->rank() == 0)) {
527 mutableDescriptor = *useDescriptor;
528 mutableDescriptor.raw().attribute = CFI_attribute_pointer;
529 if (!HandleSubstring(io, mutableDescriptor, name)) {
530 return false;
531 }
532 hadSubstring = true;
533 } else if (hadSubscripts) {
534 handler.SignalError("Multiple sets of subscripts for item '%s' in "
535 "NAMELIST group '%s'",
536 name, group.groupName);
537 return false;
Peter Klauslerdea30ac2024-01-02 17:25:49538 } else if (HandleSubscripts(
539 io, mutableDescriptor, *useDescriptor, name)) {
540 lastSubscriptBase = useDescriptor;
541 lastSubscriptDescriptor = &mutableDescriptor;
Peter Klauslerbad52052022-08-03 19:31:05542 } else {
Peter Klauslerdea30ac2024-01-02 17:25:49543 return false;
peter klausler6d443872021-10-20 23:01:52544 }
Peter Klausler0ab17082022-01-07 21:39:28545 hadSubscripts = true;
peter klausler6a1c3ef2021-05-05 18:37:49546 } else {
peter klausler6d443872021-10-20 23:01:52547 if (!HandleComponent(io, mutableDescriptor, *useDescriptor, name)) {
548 return false;
549 }
Peter Klausler0ab17082022-01-07 21:39:28550 hadSubscripts = false;
551 hadSubstring = false;
peter klausler6a1c3ef2021-05-05 18:37:49552 }
peter klausler79caf692021-06-17 20:13:19553 useDescriptor = &mutableDescriptor;
Peter Klauslerbafbae22022-03-16 19:32:03554 next = io.GetCurrentChar(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49555 } while (next && (*next == '(' || *next == '%'));
Peter Klauslerdea30ac2024-01-02 17:25:49556 if (lastSubscriptDescriptor) {
557 StorageSequenceExtension(*lastSubscriptDescriptor, *lastSubscriptBase);
558 }
peter klausler6a1c3ef2021-05-05 18:37:49559 }
560 // Skip the '='
Peter Klauslerbafbae22022-03-16 19:32:03561 next = io.GetNextNonBlank(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49562 if (!next || *next != '=') {
563 handler.SignalError("No '=' found after item '%s' in NAMELIST group '%s'",
564 name, group.groupName);
565 return false;
566 }
Peter Klauslerbafbae22022-03-16 19:32:03567 io.HandleRelativePosition(byteCount);
peter klauslerb8452db2021-10-20 20:56:47568 // Read the values into the descriptor. An array can be short.
Peter Klausler7cf16082023-04-13 17:28:19569 if (const auto *addendum{useDescriptor->Addendum()};
570 addendum && addendum->derivedType()) {
V Donaldson6f7a3b02023-05-16 20:34:57571 const NonTbpDefinedIoTable *table{group.nonTbpDefinedIo};
Peter Klausler750c8e32023-10-16 20:23:31572 listInput->ResetForNextNamelistItem(/*inNamelistSequence=*/true);
Peter Klausler7cf16082023-04-13 17:28:19573 if (!IONAME(InputDerivedType)(cookie, *useDescriptor, table)) {
574 return false;
575 }
Peter Klausler750c8e32023-10-16 20:23:31576 } else {
577 listInput->ResetForNextNamelistItem(useDescriptor->rank() > 0);
578 if (!descr::DescriptorIO<Direction::Input>(io, *useDescriptor)) {
579 return false;
580 }
peter klausler6a1c3ef2021-05-05 18:37:49581 }
Peter Klauslerbafbae22022-03-16 19:32:03582 next = io.GetNextNonBlank(byteCount);
Peter Klausler896a5432022-01-20 00:25:41583 if (next && *next == comma) {
Peter Klauslerbafbae22022-03-16 19:32:03584 io.HandleRelativePosition(byteCount);
peter klausler6a1c3ef2021-05-05 18:37:49585 }
586 }
Peter Klausler120ad252024-01-02 16:42:10587 if (next && *next == '/') {
588 io.HandleRelativePosition(byteCount);
589 } else if (*next && (*next == '&' || *next == '$')) {
590 // stop at beginning of next group
591 } else {
peter klausler6a1c3ef2021-05-05 18:37:49592 handler.SignalError(
593 "No '/' found after NAMELIST group '%s'", group.groupName);
594 return false;
595 }
peter klausler6a1c3ef2021-05-05 18:37:49596 return true;
597}
598
Peter Klausler514b7592022-08-14 17:29:21599bool IsNamelistNameOrSlash(IoStatementState &io) {
Peter Klausler2c399752022-08-14 16:56:31600 if (auto *listInput{
601 io.get_if<ListDirectedStatementState<Direction::Input>>()}) {
Peter Klausler750c8e32023-10-16 20:23:31602 if (listInput->inNamelistSequence()) {
Peter Klauslere7823602021-11-03 22:33:29603 SavedPosition savedPosition{io};
Peter Klauslerbafbae22022-03-16 19:32:03604 std::size_t byteCount{0};
605 if (auto ch{io.GetNextNonBlank(byteCount)}) {
peter klauslerb8452db2021-10-20 20:56:47606 if (IsLegalIdStart(*ch)) {
607 do {
Peter Klauslerbafbae22022-03-16 19:32:03608 io.HandleRelativePosition(byteCount);
609 ch = io.GetCurrentChar(byteCount);
peter klauslerb8452db2021-10-20 20:56:47610 } while (ch && IsLegalIdChar(*ch));
Peter Klauslerbafbae22022-03-16 19:32:03611 ch = io.GetNextNonBlank(byteCount);
peter klauslerb8452db2021-10-20 20:56:47612 // TODO: how to deal with NaN(...) ambiguity?
Peter Klauslere7823602021-11-03 22:33:29613 return ch && (*ch == '=' || *ch == '(' || *ch == '%');
Peter Klausler514b7592022-08-14 17:29:21614 } else {
Peter Klausler120ad252024-01-02 16:42:10615 return *ch == '/' || *ch == '&' || *ch == '$';
peter klauslerb8452db2021-10-20 20:56:47616 }
617 }
618 }
619 }
620 return false;
621}
622
Slava Zakharin8ebf7412024-03-25 23:01:25623RT_OFFLOAD_API_GROUP_END
624
peter klausler6a1c3ef2021-05-05 18:37:49625} // namespace Fortran::runtime::io