Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 10 additions & 31 deletions flang-rt/lib/runtime/edit-input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@
namespace Fortran::runtime::io {
RT_OFFLOAD_API_GROUP_BEGIN

// Checks that a list-directed input value has been entirely consumed and
// doesn't contain unparsed characters before the next value separator.
// Handle DC or DECIMAL='COMMA' and determine the active separator character
static inline RT_API_ATTRS char32_t GetSeparatorChar(const DataEdit &edit) {
return edit.modes.editingFlags & decimalComma ? char32_t{';'} : char32_t{','};
}

static inline RT_API_ATTRS bool IsCharValueSeparator(
const DataEdit &edit, char32_t ch) {
char32_t comma{
edit.modes.editingFlags & decimalComma ? char32_t{';'} : char32_t{','}};
return ch == ' ' || ch == '\t' || ch == comma || ch == '/' ||
return ch == ' ' || ch == '\t' || ch == '/' || ch == GetSeparatorChar(edit) ||
(edit.IsNamelist() && (ch == '&' || ch == '$'));
}

// Checks that a list-directed input value has been entirely consumed and
// doesn't contain unparsed characters before the next value separator.
static RT_API_ATTRS bool CheckCompleteListDirectedField(
IoStatementState &io, const DataEdit &edit) {
if (edit.IsListDirected()) {
Expand All @@ -54,10 +57,6 @@ static RT_API_ATTRS bool CheckCompleteListDirectedField(
}
}

static inline RT_API_ATTRS char32_t GetSeparatorChar(const DataEdit &edit) {
return edit.modes.editingFlags & decimalComma ? char32_t{';'} : char32_t{','};
}

template <int LOG2_BASE>
static RT_API_ATTRS bool EditBOZInput(
IoStatementState &io, const DataEdit &edit, void *n, std::size_t bytes) {
Expand Down Expand Up @@ -518,7 +517,7 @@ static RT_API_ATTRS ScannedRealInput ScanRealInput(
// Consume the trailing ')' of a list-directed or NAMELIST complex
// input value.
if (edit.descriptor == DataEdit::ListDirectedImaginaryPart) {
if (next && (*next == ' ' || *next == '\t')) {
if (!next || *next == ' ' || *next == '\t') {
io.SkipSpaces(remaining);
next = io.NextInField(remaining, edit);
}
Expand Down Expand Up @@ -1006,27 +1005,7 @@ static RT_API_ATTRS bool EditListDirectedCharacterInput(
// Undelimited list-directed character input: stop at a value separator
// or the end of the current record.
while (auto ch{io.GetCurrentChar(byteCount)}) {
bool isSep{false};
switch (*ch) {
case ' ':
case '\t':
case '/':
isSep = true;
break;
case '&':
case '$':
isSep = edit.IsNamelist();
break;
case ',':
isSep = !(edit.modes.editingFlags & decimalComma);
break;
case ';':
isSep = !!(edit.modes.editingFlags & decimalComma);
break;
default:
break;
}
if (isSep) {
if (IsCharValueSeparator(edit, *ch)) {
break;
}
if (length > 0) {
Expand Down
31 changes: 31 additions & 0 deletions flang-rt/unittests/Runtime/NumericalFormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,37 @@ TEST(IOApiTests, ListInputTest) {
<< "', but got '" << output << "'";
}

TEST(IOApiTests, ListInputComplexRegressionTest) {
static const char input[]{"(1,;2, );(3,;4,)"};
auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)};
static constexpr int numRealValues{4};
float z[numRealValues];
ASSERT_TRUE(IONAME(SetDecimal)(cookie, "COMMA", 5));
for (int j{0}; j < numRealValues; j += 2) {
ASSERT_TRUE(IONAME(InputComplex32)(cookie, &z[j]))
<< "InputComplex32 failed with value " << z[j];
}
auto status{IONAME(EndIoStatement)(cookie)};
ASSERT_EQ(status, 0) << "Failed complex list-directed input, status "
<< static_cast<int>(status);
static constexpr int bufferSize{18};
char output[bufferSize];
output[bufferSize - 1] = '\0';
cookie = IONAME(BeginInternalListOutput)(output, bufferSize - 1);
for (int j{0}; j < numRealValues; j += 2) {
ASSERT_TRUE(IONAME(OutputComplex32)(cookie, z[j], z[j + 1]))
<< "OutputComplex32 failed when outputting value " << z[j] << ", "
<< z[j + 1];
}
status = IONAME(EndIoStatement)(cookie);
ASSERT_EQ(status, 0) << "Failed complex list-directed output, status "
<< static_cast<int>(status);
static const char expect[bufferSize]{" (1.,2.) (3.,4.) "};
ASSERT_EQ(std::strncmp(output, expect, bufferSize), 0)
<< "Failed complex list-directed output, expected '" << expect
<< "', but got '" << output << "'";
}

TEST(IOApiTests, DescriptorOutputTest) {
static constexpr int bufferSize{10};
char buffer[bufferSize];
Expand Down
Loading