Peter Nilsson wrote:
.... snip ...
You've hit what is a surprisingly non trivial thing to do in C. A
truly robust bullet proof program will allow the user to do some
things like entering 000000000000000 000000000000000 00000000012,
potentially exhausting any fixed with input buffer. The fgets/sscanf
combination can fail because of that and sscanf's %d invokes
undefined behaviour if it receives an integer which is outside
the range of int.
One way is to write a routine that excepts an arbitrary large
input line by dynamically allocating space for it (samples have
been posted to clc on numerous occasions), and then parse that
input using strtol (making use of the 'end' pointer).
If you're willing to flag multiple leading zeros as an error, then
you can fix your buffer to a compile time fixed limit.
.... snip ...
Try these, after suitable #includes. No buffers needed. Build int
input routines around them. The only nuisance for that is a
guaranteed method of negating values without creating an integer
overflow.
/* --------------------------------------------------------------
* Skip to non-blank on f, and return that char. or EOF. The next
* char that getc(f) will return is unknown. Local use only,
* because it violates the principle of leaving the terminating
* char in the input stream.
*/
static int ignoreblks(FILE *f)
{
int ch;
do {
ch = getc(f);
} while ((' ' == ch) || ('\t' == ch));
/* while (isblank(ch)); */ /* for C99 */
return ch;
} /* ignoreblks */
/*--------------------------------------------------------------
* Read an unsigned value. Signal error for overflow or no
* valid number found. Returns 1 for error, 0 for noerror, EOF
* for EOF encountered before parsing a value.
*
* Skip all leading blanks on f. At completion getc(f) will
* return the character terminating the number, which may be \n
* or EOF among others. Barring EOF it will NOT be a digit. The
* combination of error, 0 result, and the next getc returning
* \n indicates that no numerical value was found on the line.
*
* If the user wants to skip all leading white space including
* \n, \f, \v, \r, he should first call "skipwhite( f);"
*
* Peculiarity: This specifically forbids a leading '+' or '-'.
*/
int readxwd(unsigne d int *wd, FILE *f)
{
unsigned int value, digit;
int status;
int ch;
#define UWARNLVL (UINT_MAX / 10U)
#define UWARNDIG (UINT_MAX - UWARNLVL * 10U)
value = 0; /* default */
status = 1; /* default error */
ch = ignoreblks(f);
if (EOF == ch) status = EOF;
else if (isdigit(ch)) status = 0; /* digit, no error */
while (isdigit(ch)) {
digit = ch - '0';
if ((value > UWARNLVL) ||
((UWARNLVL == value) && (digit > UWARNDIG))) {
status = 1; /* overflow */
value -= UWARNLVL;
}
value = 10 * value + digit;
ch = getc(f);
} /* while (ch is a digit) */
*wd = value;
ungetc(ch, f);
return status;
} /* readxwd */
--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943