getline - sort of

B

Bill Waddington

This must be a FAQ - or several FAQs - but I can't quite seem
to pin it down.

I need to read a string from stdin which I will then process as digits
with sscanf. I need to limit the # of chars read, and discard the
rest of the line. I also need to detect when more or fewer chars
are input. Something like GNU getline I guess.

Is there a standard portable way to do this w/a library function,
or do I just write it myself and process input a single char at
a time?

This must come up all the time. Sorry to be such a pinhead. Drivers
I can handle. User input, that another thing entirely...

Thanks,
Bill
 
M

Malcolm McLean

Bill Waddington said:
This must be a FAQ - or several FAQs - but I can't quite seem
to pin it down.

I need to read a string from stdin which I will then process as digits
with sscanf. I need to limit the # of chars read, and discard the
rest of the line. I also need to detect when more or fewer chars
are input. Something like GNU getline I guess.

Is there a standard portable way to do this w/a library function,
or do I just write it myself and process input a single char at
a time?

This must come up all the time. Sorry to be such a pinhead. Drivers
I can handle. User input, that another thing entirely...
There's no really good way of getting an unbounded input line.

Probably if the input is line-delimited numbers, your best bet is to call
fgets() with a suitably over-lrage buffer.
Reject any input for which there is no trailing newline.
Then call strtod() to convert the .line to a number.

char buff[256];
double x;
char *end;

fgets(buff, 256, stdin);
if(!strchr(buff, "\n'))
{
evil person is passing you a bad line that is over long
}
x = strtod(buff, &end);
if(end == buff)
{
evil person passed a line that was not a number
}

at this point x holds the number, end the addfress of the last character
after it. You might discard, or process further.
 
F

Flash Gordon

Malcolm McLean wrote, On 16/01/08 17:39:
There's no really good way of getting an unbounded input line.

Probably if the input is line-delimited numbers, your best bet is to
call fgets() with a suitably over-lrage buffer.

Since the OP has a requirement for an upper limit an overly large buffer
is *not* required. The OP needs a buffer of the correct size allowing
for the newline and /0 termination.
Reject any input for which there is no trailing newline.

Where did the OP say reject? The OP should use lack of a newline to
indicate too long a line and loop to discard the rest, and an early
newline to indicate too short a line.
Then call strtod() to convert the .line to a number.

Where did the OP specify a floating point number? I agree that the strto
functions are generally easier to use than sscanf but as the OP does not
mention decimal points or signs strtoul is more likely to be of use.
char buff[256];

Manifest constants are bad.
double x;
char *end;

fgets(buff, 256, stdin);

Here you repeat your manifest constant leading to a higher chance of
introducing bugs.

Either #define (or enum) the buffer size of use sizeof on the buffer (it
it will be the buffer not a pointer passed in, which seems likely.

Also fgets returns a value. Failure to check it means you will not know
if an end-of-file or error occurs, both of which *can* occur on stdin.
if(!strchr(buff, "\n'))

strchr takes the character as an int value, NOT a (pointer to) string.
Also the OP probably wants to use the value returned to find out how
long the line was. So that should be more like:
eolptr = strchr(buff,'\n');
if (!eolptr)
{
evil person is passing you a bad line that is over long

Do a loop reading until you get either EOF or /n. I would use getc
rather than fgetc for this since it is intended to be a macro and
therefore makes the optimisers job easier.

else
linelen = eolptr-buf;
x = strtod(buff, &end);
if(end == buff)
{
evil person passed a line that was not a number

Or something that started with something other than white space or a
number. We do not know that this is invalid and it might be why the OP
wants to use sscanf.
}

at this point x holds the number, end the addfress of the last character
after it. You might discard, or process further.

Or it could contain an INF or NAN. Also errno should be checked (having
been zeroed prior to the call) so that overflow can easily be detected.
 
M

Malcolm McLean

Flash Gordon said:
Or it could contain an INF or NAN. Also errno should be checked (having
been zeroed prior to the call) so that overflow can easily be detected.
That's why strtod is the better choice, unless you really need massive and
accurate integers.
 
F

Flash Gordon

Malcolm McLean wrote, On 16/01/08 18:42:
That's why strtod is the better choice, unless you really need massive
and accurate integers.

You not using strtod properly is a reason why it should be used? Strange
argument. Anyway...

With strtod you need to check the end pointer, errno and *also* check
for INF and NAN (they can be explicitly supplied by the user and that
might not be flagged). If you only expect integers you *also* have to
check that the user entered an integer (entering 0.5 should in my
opinion not be considered correct). You also have to be concerned about
whether the range of exactly represented integers is large enough.

With strtoul you have to check the end pointer and errno. If the valid
range is smaller than unsigned long you also have to check the range.

Hmm, a description under half the length suggests to me that it is a LOT
simpler to use strtoul, strtoull, strtol or strtoll depending on valid
range.

Also you should note that strtoul etc are actually *designed* for
integers unlike strtod. It is generally best to use a tool designed for
the job when one is available rather than some other tool.
 
R

Randy Howard

This must be a FAQ - or several FAQs - but I can't quite seem
to pin it down.

I need to read a string from stdin which I will then process as digits
with sscanf. I need to limit the # of chars read, and discard the
rest of the line. I also need to detect when more or fewer chars
are input. Something like GNU getline I guess.

Richard has this on his website, which seems to cover the general idea
pretty well, I suspect it might be helpful to you.

http://www.cpax.org.uk/prg/writings/fgetdata.php
 
M

Malcolm McLean

Flash Gordon said:
Malcolm McLean wrote, On 16/01/08 18:42:

You not using strtod properly is a reason why it should be used? Strange
argument. Anyway...

With strtoul you have to check the end pointer and errno. If the valid
range is smaller than unsigned long you also have to check the range.

Hmm, a description under half the length suggests to me that it is a LOT
simpler to use strtoul, strtoull, strtol or strtoll depending on valid
range.
If the user passes NAN or INF, it is an open question what the correct
behaviour should be. Having the double set to that value is a good start.
If he passes something non-numeric, endptr will pick it up.
Also you should note that strtoul etc are actually *designed* for integers
unlike strtod. It is generally best to use a tool designed for the job
when one is available rather than some other tool.
Generally, yes, you shoyuld, use functions as designed.

In fact strtol and related functions are driven more by the idea that data
is integers, becasue that's what the machine can crunch efficiently.
Generally data is numerical when it is not strings. It is easier to let
corrupt data be represented as massive flaoting point numbers which can then
be filtered out during sanity checks further down the line, rather than try
to build a parser for integers.

The exception might be super-safe applications where you don't want even the
remote chance that something like 10.000000000000001 would be changed into
an integral 10 and accepted, when in fact you want to reject such input.
However needing that level of safety is rare.
 
E

Eric Sosman

Bill said:
This must be a FAQ - or several FAQs - but I can't quite seem
to pin it down.

I need to read a string from stdin which I will then process as digits
with sscanf. I need to limit the # of chars read, and discard the
rest of the line. I also need to detect when more or fewer chars
are input. Something like GNU getline I guess.

Is there a standard portable way to do this w/a library function,
or do I just write it myself and process input a single char at
a time?

This must come up all the time. Sorry to be such a pinhead. Drivers
I can handle. User input, that another thing entirely...


Other responders seem to be pointing to solutions of a
related but different problem: Reading an entire line without
knowing how long it might be. Your task seems simpler, and
there's no need to commit canaricide with cannons.

Since you know an upper limit on the line length, you can
use a char array of the appropriate size (including room for
the '\n' and the '\0'), and read a line into it with fgets().
Then use strchr() to find the '\n' at the end of the line. If
a newline is found, fgets() got an entire line and the position
of the newline gives you its length. If not, the line was too
long and part of it remains unread, or else you've reached end-
of-input in a malformed file that lacks a '\n' at the end of its
final line. Either way, you can skip the rest of the line (or
detect the newline-less final line), by calling getc() or getchar()
in a loop until it returns '\n' or EOF.
 
B

Bill Waddington

Other responders seem to be pointing to solutions of a
related but different problem: Reading an entire line without
knowing how long it might be.

True. I know how long the useful input might be, but need to
allow for less or more and discard any extra input safely.
Your task seems simpler, and there's no need to commit
canaricide with cannons.
Since you know an upper limit on the line length, you can
use a char array of the appropriate size (including room for
the '\n' and the '\0'), and read a line into it with fgets().
Then use strchr() to find the '\n' at the end of the line. If
a newline is found, fgets() got an entire line and the position
of the newline gives you its length. If not, the line was too
long and part of it remains unread, or else you've reached end-
of-input in a malformed file that lacks a '\n' at the end of its
final line. Either way, you can skip the rest of the line (or
detect the newline-less final line), by calling getc() or getchar()
in a loop until it returns '\n' or EOF.

That, or just grind along w/getc() or getchar() from the start.

If I read all the suggestions correctly, the bottom line is code
it up or borrow it somewhere, but there isn't a single standard
lib way to do it.

Thanks to all,
Bill
 
F

Flash Gordon

Malcolm McLean wrote, On 16/01/08 19:16:
If the user passes NAN or INF, it is an open question what the correct
behaviour should be. Having the double set to that value is a good start.
If he passes something non-numeric, endptr will pick it up.
Generally, yes, you shoyuld, use functions as designed.

In fact strtol and related functions are driven more by the idea that
data is integers, becasue that's what the machine can crunch efficiently.

No, they are driven by the idea the there are a lot of situations where
you are dealing with integers.
Generally data is numerical when it is not strings.

I do a lot of interfacing with other systems. A lot of the time the
numbers are provided as integers (numbers of pennies etc.)
It is easier to let
corrupt data be represented as massive flaoting point numbers which can
then be filtered out during sanity checks further down the line, rather
than try to build a parser for integers.

You do not have to build a parser for integers, those nice library
writers have done the job for you.
The exception might be super-safe applications where you don't want even
the remote chance that something like 10.000000000000001 would be
changed into an integral 10 and accepted, when in fact you want to
reject such input. However needing that level of safety is rare.

No, the exception is where the requirement is to accept an integer, and
this is a very common situation.
 
B

Bart C

Bill Waddington said:
This must be a FAQ - or several FAQs - but I can't quite seem
to pin it down.

I need to read a string from stdin which I will then process as digits
with sscanf. I need to limit the # of chars read, and discard the
rest of the line. I also need to detect when more or fewer chars
are input. Something like GNU getline I guess.

Is there a standard portable way to do this w/a library function,
or do I just write it myself and process input a single char at
a time?

This must come up all the time. Sorry to be such a pinhead. Drivers
I can handle. User input, that another thing entirely...

As I understand this you have input like:

10
20 30
40 50 60
70 80 90 100
110 120 130 140 150

And if you read this using this pseudocode:

while !eof /* note this is not how C uses eof! */
{ readln /* read as much of the next input line as needed, discard rest
*/
read A,B,C /* read your data from the buffer, as integers */
}

Then A,B,C will successively be (10,0,0), (20,30,0), (40,50,60), (70,80,90),
(110,120,130). And with unused input on each line of "", "", "", "100","140
150".

Then you will have an input system like I use, where Newline gives a 'hard'
end to the input (so read attempts give 0 or 0.0 or "") instead of being
ignored as white space and continuing to the next line.

However imposing this behaviour on the C library routines was a quite a bit
of work
(I call them from another language).

The 'readln' can be done according to Eric Sosman's message, that's quite
well-defined. Whatever else you need is just a bunch of routines; sorry
can't point to existing code. But once you know the next input line is in a
memory string and zero-terminated, then this makes life easier.

Bart
 
C

CBFalconer

Bill said:
This must be a FAQ - or several FAQs - but I can't quite seem
to pin it down.

I need to read a string from stdin which I will then process as
digits with sscanf. I need to limit the # of chars read, and
discard the rest of the line. I also need to detect when more
or fewer chars are input. Something like GNU getline I guess.

Is there a standard portable way to do this w/a library function,
or do I just write it myself and process input a single char at
a time?

This must come up all the time. Sorry to be such a pinhead.
Drivers I can handle. User input, that another thing entirely.

Dead simple. Use the standard functions described in ctype.h to
isolate the chars. Count chars any way you wish. Use getc() (or
getchar()) to input chars. Don't use sscanf, it is not suitable
for interactive work. Do use ungetc() to put back the terminating
(unused) char.
 
P

pete

Bill Waddington wrote:
If I read all the suggestions correctly, the bottom line is code
it up or borrow it somewhere, but there isn't a single standard
lib way to do it.

That's it.

I have a way to read lines from stdin and discard input
beyond the buffer length, using fscanf:

http://www.mindspring.com/~pfilandr/C/fscanf_input/fscanf_input.c
http://www.mindspring.com/~pfilandr/C/fscanf_input/grade.c

but that way doesn't tell you
whether or not any bytes were discarded.

I have a get_line function, but it always gets complete lines,
to the extent that the getc and realloc calls that it uses,
succede.

http://www.mindspring.com/~pfilandr/C/get_line/get_line.c

It does however, have a some diagnostic capability built in.
Now With New And Improved Bigger Comment!

/*
** int get_line(char **lineptr, size_t *n, FILE *stream);
**
** Requirements for initial parameter values:
** (*lineptr) is either
** the address of the start of a block of allocated memory,
** or a null pointer;
** (*n) is the number of bytes that (*lineptr) points to;
** (*stream) is associated with a text stream
** that is open for reading.
**
** The definition of get_line uses the following headers:
** <stdio.h> <stdlib.h> <limits.h>
**
** Side effects:
** get_line reads a line from a text stream using getc
** and writes the values of the characters in order,
** as an array of char,
** replacing the newline character with a null character.
** get_line uses realloc to allocate enough memory
** so that if a subsequent call to realloc were to fail,
** then *lineptr would still point to enough memory
** to hold a null terminated array of all of the characters
** which were read during the get_line function call.
** get_line returns if there is an end-of-file condition
** or a read error.
** get_line returns if realloc returns a null pointer.
** get_line returns if getc returns '\n'.
** get_line returns if ((size_t)-2) characters
** of text line have been read.
** get_line updates *lineptr and *n, so that *n
** is always the number of bytes that *lineptr points to.
** If *n is greater than one when get_line returns,
** then get_line will make a null terminated array
** out of the sequence of values read from the text stream.
** If *n equals one, and realloc returns NULL,
** then a null character will be written to **lineptr.
** If *n equals either zero or one, and realloc returns NULL,
** then the character which was read,
** will be pushed back by a call to ungetc.
**
** Return values:
** get_line returns EOF,
** if there is an end-of-file condition or a read error;
** get_line returns zero,
** if realloc returns NULL;
** otherwise,
** get_line returns the number of bytes read,
** if the number of bytes read, including the newline,
** is less than INT_MAX;
** get_line returns INT_MAX,
** if the number of bytes read, including the newline,
** is greater than or equal to INT_MAX.
**
**
** For this expression:
** (buff = NULL, size = 0, rc = get_line(&buff, &size, fp))
** most of what there is to know
** about the status of the function call, can be determined
** from the values of some or all of the following expressions:
** (rc), (feof(fp)), (buff), (*buff), (size)
** If the text file is known to not contain null bytes,
** then the value of (strlen(buff)) can also be used
** to determine the rest of what there is to know
** about the status of the function call.
** Two items of primary interest are:
** 1 Was the return normal? (rc != 0 && !ferror(fp))
** 2 How much of a text line was read? (none, partial, complete)
**
** If rc equals EOF, then:
** if and only if no bytes were read because of
** Normal Return At End Of Text File, then:
** ((buff == NULL || *buff == '\0') && feof(fp));
** if and only if no bytes were read because of a
** Read Error, then:
** ((buff == NULL || *buff == '\0') && !feof(fp));
** if and only if a partial line was read because of a
** Read Error, then:
** (buff != NULL && *buff != '\0' && !feof(fp));
** if and only if a whole line was read because of
** Text File Not Newline Terminated, then:
** (buff != NULL && *buff != '\0' && feof(fp)).
**
** If rc equals zero, then:
** if and only if no bytes were read, then:
** (2 > size);
** if and only if a partial line was read, then:
** (size > 1 && size == strlen(buff) + 1);
** if and only if a whole line was read:
** (size > 1 && size > strlen(buff) + 1).
**
** If rc is positive, then:
** if and only if a partial line was read, then:
** ((size_t)-1 == size && (size_t)-2 == strlen(buff));
** if and only if a whole line was read, then:
** ((size_t)-1 != size || (size_t)-2 > strlen(buff)).
**
** How much of all of that information needs to be checked,
** depends on circumstances:
** The function can be used to read a whole file
** even though realloc keeps returning NULL,
** by keeping track of partial lines;
** or
** Reading the text file can be abandoned
** at the first sign of trouble, such as when (1 > rc),
** with little or no further investigation.
*/
 
C

CBFalconer

Bill said:
This must be a FAQ - or several FAQs - but I can't quite seem
to pin it down.

I need to read a string from stdin which I will then process as
digits with sscanf. I need to limit the # of chars read, and
discard the rest of the line. I also need to detect when more
or fewer chars are input. Something like GNU getline I guess.

Is there a standard portable way to do this w/a library function,
or do I just write it myself and process input a single char at
a time?

This must come up all the time. Sorry to be such a pinhead.
Drivers I can handle. User input, that another thing entirely.

Try this out. It would be handier if changed to input longs. I
have relaxed the GPL licensing.

/* ------------------------------------------------- *
* File txtinput.c *
* ------------------------------------------------- */

#include <limits.h> /* xxxx_MAX, xxxx_MIN */
#include <ctype.h> /* isdigit, isblank, isspace */
#include <stdio.h> /* FILE, getc, ungetc */
#include "txtinput.h"

/* For licensing restrictions (GPL) see readme.txt in:
* <http://cbfalconer.home.att.net/download/txtio.zip>
*
* These stream input routines are written so that simple
* conditionals can be used:
*
* if (readxint(&myint, stdin)) {
* do_error_recovery; normally_abort_to_somewhere;
* }
* else {
* do_normal_things; usually_much_longer_than_bad_case;
* }
*
* They allow overflow detection, and permit other routines to
* detect the character that terminated a numerical field. No
* string storage is required, thus there is no limitation on
* the length of input fields. For example, a number entered
* with a string of 1000 leading zeroes will not annoy these.
*
* The numerical input routines *NEVER* absorb a terminating
* char (including '\n'). Thus a sequence such as:
*
* err = readxint(&myint, stdin);
* flushln(stdin);
*
* will always consume complete lines, and after execution of
* readxint a further getc (or fgetc) will return the character
* that terminated the numeric field.
*
* They are also re-entrant, subject to the limitations of file
* systems. e.g interrupting readxint(v, stdin) operation with
* a call to readxwd(wd, stdin) would not be well defined, if
* the same stdin is being used for both calls. If ungetc is
* interruptible the run-time system is broken.
*
* Originally issued 2002-10-07
*
* Revised 2006-01-15 so that unsigned entry overflow (readxwd)
uses the normal C modulo (UINT_MAX + 1) operation. readxwd
still rejects an initial sign as an error.
*
* Modified to allow free use - C.B. Falconer 2008-01-16
*/

/* -------------------------------------------------------------
* 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.
*/
static int ignoreblks(FILE *f)
{
int ch;

do {
ch = getc(f);
} while ((' ' == ch) || ('\t' == ch));
/* while (isblank(ch)); */ /* for C99 */
return ch;
} /* ignoreblks */

/*--------------------------------------------------------------
* Skip all blanks on f. At completion getc(f) will return
* a non-blank character, which may be \n or EOF
*
* Skipblks returns the char that getc will next return, or EOF.
*/
int skipblks(FILE *f)
{
return ungetc(ignoreblks(f), f);
} /* skipblks */

/*--------------------------------------------------------------
* Skip all whitespace on f, including \n, \f, \v, \r. At
* completion getc(f) will return a non-blank character, which
* may be EOF
*
* Skipwhite returns the char that getc will next return, or EOF.
*/
int skipwhite(FILE *f)
{
int ch;

do {
ch = getc(f);
} while (isspace(ch));
return ungetc(ch, f);
} /* skipwhite */

/*--------------------------------------------------------------
* 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(unsigned 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 */

/*--------------------------------------------------------------
* Read a signed value. Signal error for overflow or no valid
* number found. Returns true for error, false for noerror. On
* overflow either INT_MAX or INT_MIN is returned in *val.
*
* 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: an isolated leading '+' or '-' NOT immediately
* followed by a digit will return error and a value of 0, when
* the next getc will return that following non-digit. This is
* caused by the single level ungetc available.
*
* This module needs further work. CBF 2008-01-16
*/
int readxint(int *val, FILE *f)
{
unsigned int value;
int status, negative;
int ch;

*val = value = 0; /* default */
status = 1; /* default error */
negative = 0;

ch = ignoreblks(f);

if (EOF != ch) {
if (('+' == ch) || ('-' == ch)) {
negative = ('-' == ch);
ch = ignoreblks(f); /* absorb any sign */
}

if (isdigit(ch)) { /* digit, no error */
ungetc(ch, f);
status = readxwd(&value, f);
ch = getc(f); /* This terminated readxwd */
}

if (0 == status) {
/* got initial digit and no readxwd overflow */
if (!negative && (value <= INT_MAX))
*val = value;
else if (negative && (value < UINT_MAX) &&
((value - 1) <= -(1 + INT_MIN)))
*val = -value;
else { /* overflow */
status = 1; /* do whatever the native system does */
if (negative) *val = -value;
else *val = value;
}
}
else if (negative) *val = -value;
else *val = value;
}
ungetc(ch, f);
return status;
} /* readxint */

/*-----------------------------------------------------
* Flush input through an end-of-line marker inclusive.
*/
void flushln(FILE *f)
{
int ch;

do {
ch = getc(f);
} while (('\n' != ch) && (EOF != ch));
} /* flushln */

/* End of txtinput.c */


/* file txtinput.h */
#ifndef H_txtinput_h
#define H_txtinput_h
# ifdef __cplusplus
extern "C" {
# endif

#include <stdio.h>

/* For licensing restrictions (GPL) see readme.txt in:
* <http://cbfalconer.home.att.net/download/txtio.zip>
*
* These stream input routines are written so that simple
* conditionals can be used:
*
* if (readxint(&myint, stdin)) {
* do_error_recovery; normally_abort_to_somewhere;
* }
* else {
* do_normal_things; usually_much_longer_than_bad_case;
* }
*
* They allow overflow detection, and permit other routines to
* detect the character that terminated a numerical field. No
* string storage is required, thus there is no limitation on
* the length of input fields. For example, a number entered
* with a string of 1000 leading zeroes will not annoy these.
*
* The numerical input routines *NEVER* absorb a terminating
* char (including '\n'). Thus a sequence such as:
*
* err = readxint(&myint, stdin);
* flushln(stdin);
*
* will always consume complete lines, and after execution of
* readxint a further getc (or fgetc) will return the character
* that terminated the numeric field.
*
* They are also re-entrant, subject to the limitations of file
* systems. e.g interrupting readxint(v, stdin) operation with
* a call to readxwd(wd, stdin) would not be well defined, if
* the same stdin is being used for both calls. If ungetc is
* interruptible the run-time system is broken.

* Revised 2006-01-15 so that unsigned entry overflow (readxwd)
uses the normal C modulo (UINT_MAX + 1) operation. readxwd
still rejects an initial sign as an error.
*
* Modified to allow free use - C.B. Falconer 2008-01-16
*/

/*--------------------------------------------------------------
* Skip all blanks on f. At completion getc(f) will return
* a non-blank character, which may be \n or EOF
*
* Skipblks returns the char that getc will next return, or EOF.
*/
int skipblks(FILE *f);

/*--------------------------------------------------------------
* Skip all whitespace on f, including \n, \f, \v, \r. At
* completion getc(f) will return a non-blank character, which
* may be EOF
*
* Skipblks returns the char that getc will next return, or EOF.
*/
int skipwhite(FILE *f);

/*--------------------------------------------------------------
* 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(unsigned int *wd, FILE *f);

/*--------------------------------------------------------------
* Read a signed value. Signal error for overflow or no valid
* number found. Returns true for error, false for noerror. On
* overflow either INT_MAX or INT_MIN is returned in *val.
*
* 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: an isolated leading '+' or '-' NOT immediately
* followed by a digit will return error and a value of 0, when
* the next getc will return that following non-digit. This is
* caused by the single level ungetc available.
*/
int readxint(int *val, FILE *f);

/*--------------------------------------------------------------
* Flush input through an end-of-line marker inclusive.
*/
void flushln(FILE *f);

# ifdef __cplusplus
}
# endif
#endif
/* End of txtinput.h */
 
B

Bill Waddington

That's it.

I have a way to read lines from stdin and discard input
beyond the buffer length, using fscanf:

http://www.mindspring.com/~pfilandr/C/fscanf_input/fscanf_input.c
http://www.mindspring.com/~pfilandr/C/fscanf_input/grade.c

but that way doesn't tell you
whether or not any bytes were discarded.

I have a get_line function, but it always gets complete lines,
to the extent that the getc and realloc calls that it uses,
succede.

http://www.mindspring.com/~pfilandr/C/get_line/get_line.c

It does however, have a some diagnostic capability built in.
Now With New And Improved Bigger Comment!

[some snippage - see upthread]

Hi Pete,

Thanks for that. I appreciate all the suggestions. What
I'm doing now is as below. It isn't really worth posting here
but since my C skills are nill, I wouldn't mind general
comments and error messages. It seems to be doing what I
need for now.


int get_line(char *buff, int maxbuff)
{
int good_chars = 0, all_chars = 0, inchar;

while(1) {
inchar = getchar();
if((inchar == EOF) || (inchar == '\n'))
break;
if(good_chars < (maxbuff - 1)) {
*(buff + good_chars) = (char)inchar;
good_chars++;
}
all_chars++;
}
*(buff + good_chars) = '\0';
return all_chars;
}


Thanks, and sorry for the noise,
Bill
 
P

pete

Bill Waddington wrote:
Thanks for that. I appreciate all the suggestions. What
I'm doing now is as below. It isn't really worth posting here
but since my C skills are nill, I wouldn't mind general
comments and error messages. It seems to be doing what I
need for now.

int get_line(char *buff, int maxbuff)
{
int good_chars = 0, all_chars = 0, inchar;

while(1) {
inchar = getchar();
if((inchar == EOF) || (inchar == '\n'))
break;
if(good_chars < (maxbuff - 1)) {
*(buff + good_chars) = (char)inchar;
good_chars++;
}
all_chars++;
}
*(buff + good_chars) = '\0';
return all_chars;
}

I think it looks like it will do what you want.
 
R

Richard Heathfield

Keith Thompson said:
For one thing, its behavior on numeric input overflow is undefined.

But you can use field width specifiers to prevent this. See, for instance,
the C89 example of fscanf (which is obviously analogous to sscanf):

++++++++++++++++++++++
fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name);

with input:

56789 0123 56a72

will assign to i the value 56
++++++++++++++++++++++

Not that I'm rootin' for *scanf or anything. But of the *scanf family,
sscanf is certainly the least useless, and it seems to me that it makes no
odds whether the string on which it works comes from an "interactive"
source or not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,188
Latest member
Crypto TaxSoftware

Latest Threads

Top