Chris said:
.... snip ...
Practically speaking, I would expect either all the functions
(scanf, fscanf, and sscanf) would have the same limit because they
use the same internal engine; or the engine might "see" that sscanf
is working off a string in memory, hence there is no need to make
a copy of digit-sequences for strto*(), hence sort of "accidentally"
avoid upper limits there. (However, the ruling that conversion
of, e.g., "1.23e-x" must fail, instead of converting "1.23" and
leaving the e-x for the next directive, would make this harder than
one might think at first. If the implementor just used the endptr
parameter from strtod(), sscanf against "1.23e-x" with "%f%s" would
convert two items successfully, instead of failing as required.)
There is no necessity to have ANY string length limit affect these
textstream-to-number conversions. I have written code that avoids
the problem entirely. However the error condition for "1.2e-x"
sequences remains. This can obviously be handled easily when the
input is a string, and is otherwise limited by the guaranteed
lookback (ungetc) level.
I disagree that such an input must fail. The interpretation as a
number, followed by a string, seems perfectly reasonable to me.
The cure here is that the application must check the termination
char for the numeric field.
In addition, there should be no problem at the system level in
providing multi-level ungetc ability, provided that the system
never has to back up across line ends. Since a '\n' will always
terminate any numeric input field, this is no hardship. A short
time ago I wrote a small test program to detect this capability,
and found that DJGPP has it. I published the little test here at
the time. So this reduces to a quality of implementation issue.
In practice this all means that the scanf series of functions
should not be used to input numerics without limiting the call to a
single field.
Here is my test program for ungetc levels (tungetc.c):
#include <stdio.h>
#include <stdlib.h>
#define MAXLN 10
int main(void) {
char line[MAXLN + 1];
int ix, ch;
puts("Test ability to ungetc for multiple chars in one line");
fputs("Enter no more than 10 chars:", stdout); fflush(stdout);
ix = 0;
while ((EOF != (ch = getchar())) && ('\n' != ch)) {
if (MAXLN <= ix) break;
line[ix++] = ch;
}
line[ix] = '\0';
if ('\n' != ungetc('\n', stdin)) {
puts("Can't unget a '\\n'");
return(EXIT_FAILURE);
}
puts(line);
puts("Trying to push back the whole line");
while (ix > 0) {
ch = ungetc(line[--ix], stdin);
if (ch == line[ix]) putchar(ch);
else {
putchar(line[ix]);
puts(" failed to push back");
return(EXIT_FAILURE);
}
}
puts("\nTrying to reread the whole line");
while ((EOF != (ch = getchar())) && ('\n' != ch)) {
if (ix++ == MAXLN) break;
putchar(ch);
}
return 0;
} /* main */