13
13
14
14
namespace Fortran ::runtime::io {
15
15
16
+ // For fixed-width fields, initialize the number of remaining characters.
17
+ // Skip over leading blanks, then return the first non-blank character (if any).
16
18
static std::optional<char32_t > PrepareInput (
17
19
IoStatementState &io, const DataEdit &edit, std::optional<int > &remaining) {
18
20
remaining.reset ();
@@ -61,14 +63,16 @@ static bool EditBOZInput(IoStatementState &io, const DataEdit &edit, void *n,
61
63
return true ;
62
64
}
63
65
64
- // Returns false if there's a '-' sign
66
+ // Prepares input from a field, and consumes the sign, if any.
67
+ // Returns true if there's a '-' sign.
65
68
static bool ScanNumericPrefix (IoStatementState &io, const DataEdit &edit,
66
69
std::optional<char32_t > &next, std::optional<int > &remaining) {
67
70
next = PrepareInput (io, edit, remaining);
68
71
bool negative{false };
69
72
if (next) {
70
73
negative = *next == ' -' ;
71
74
if (negative || *next == ' +' ) {
75
+ io.SkipSpaces (remaining);
72
76
next = io.NextInField (remaining);
73
77
}
74
78
}
@@ -126,39 +130,44 @@ bool EditIntegerInput(
126
130
return true ;
127
131
}
128
132
133
+ // Parses a REAL input number from the input source as a normalized
134
+ // fraction into a supplied buffer -- there's an optional '-', a
135
+ // decimal point, and at least one digit. The adjusted exponent value
136
+ // is returned in a reference argument. The returned value is the number
137
+ // of characters that (should) have been written to the buffer -- this can
138
+ // be larger than the buffer size and can indicate overflow. Replaces
139
+ // blanks with zeroes if appropriate.
129
140
static int ScanRealInput (char *buffer, int bufferSize, IoStatementState &io,
130
141
const DataEdit &edit, int &exponent) {
131
142
std::optional<int > remaining;
132
143
std::optional<char32_t > next;
133
144
int got{0 };
134
145
std::optional<int > decimalPoint;
135
- if ( ScanNumericPrefix (io, edit, next, remaining) && next) {
146
+ auto Put{[&]( char ch) -> void {
136
147
if (got < bufferSize) {
137
- buffer[got++ ] = ' - ' ;
148
+ buffer[got] = ch ;
138
149
}
150
+ ++got;
151
+ }};
152
+ if (ScanNumericPrefix (io, edit, next, remaining)) {
153
+ Put (' -' );
139
154
}
140
155
if (!next) { // empty field means zero
141
- if (got < bufferSize) {
142
- buffer[got++] = ' 0' ;
143
- }
156
+ Put (' 0' );
144
157
return got;
145
158
}
146
- if (got < bufferSize) {
147
- buffer[got++] = ' .' ; // input field is normalized to a fraction
148
- }
149
159
char32_t decimal = edit.modes .editingFlags & decimalComma ? ' ,' : ' .' ;
150
- auto start{got };
151
- if ((*next >= ' a ' && *next < = ' z ' ) || (*next >= ' A ' && *next < = ' Z ' ) ) {
160
+ char32_t first{*next >= ' a ' && *next <= ' z ' ? *next + ' A ' - ' a ' : *next };
161
+ if (first = = ' N ' || first = = ' I ' ) {
152
162
// NaN or infinity - convert to upper case
163
+ // Subtle: a blank field of digits could be followed by 'E' or 'D',
153
164
for (; next &&
154
165
((*next >= ' a' && *next <= ' z' ) || (*next >= ' A' && *next <= ' Z' ));
155
166
next = io.NextInField (remaining)) {
156
- if (got < bufferSize) {
157
- if (*next >= ' a' && *next <= ' z' ) {
158
- buffer[got++] = *next - ' a' + ' A' ;
159
- } else {
160
- buffer[got++] = *next;
161
- }
167
+ if (*next >= ' a' && *next <= ' z' ) {
168
+ Put (*next - ' a' + ' A' );
169
+ } else {
170
+ Put (*next);
162
171
}
163
172
}
164
173
if (next && *next == ' (' ) { // NaN(...)
@@ -167,7 +176,10 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
167
176
}
168
177
}
169
178
exponent = 0 ;
170
- } else if (*next == decimal || (*next >= ' 0' && *next <= ' 9' )) {
179
+ } else if (first == decimal || (first >= ' 0' && first <= ' 9' ) ||
180
+ first == ' E' || first == ' D' || first == ' Q' ) {
181
+ Put (' .' ); // input field is normalized to a fraction
182
+ auto start{got};
171
183
for (; next; next = io.NextInField (remaining)) {
172
184
char32_t ch{*next};
173
185
if (ch == ' ' || ch == ' \t ' ) {
@@ -180,18 +192,16 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
180
192
if (ch == ' 0' && got == start && !decimalPoint) {
181
193
// omit leading zeroes before the decimal
182
194
} else if (ch >= ' 0' && ch <= ' 9' ) {
183
- if (got < bufferSize) {
184
- buffer[got++] = ch;
185
- }
195
+ Put (ch);
186
196
} else if (ch == decimal && !decimalPoint) {
187
197
// the decimal point is *not* copied to the buffer
188
198
decimalPoint = got - start; // # of digits before the decimal point
189
199
} else {
190
200
break ;
191
201
}
192
202
}
193
- if (got == start && got < bufferSize ) {
194
- buffer[got++] = ' 0' ; // all digits were zeroes
203
+ if (got == start) {
204
+ Put ( ' 0' ) ; // emit at least one digit
195
205
}
196
206
if (next &&
197
207
(*next == ' e' || *next == ' E' || *next == ' d' || *next == ' D' ||
0 commit comments