On 2/7/2013 07:42, Noob wrote:
>
> Here's my attempt at writing a "get_line" implementation, which
> reads an entire line from a file stream, dynamically allocating
> the space needed to store said line.
>
Based on your other posts in this thread, I gather your next version
won't skip lines, or it'll be documented and the name adjusted.
> Since this is for my own personal use, I didn't bother handling
> out-of-memory conditions elegantly. I just kick the bucket.
> ("We all kick the bucket in the end, in the end.")
>
> EOF is signaled by returning NULL.
>
An alternative is to return an 'enum' value which a caller can 'switch'
with, or opaque values which a header can define macros for.
> I'd like to hear suggestions/criticism.
>
> #include <stdio.h>
> #include <stdlib.h>
> #define BUFLEN 4000
As Ben mentioned, it might be better called 'BUFINC', or some such. Or
you could use 'BUFSIZ' from stdio.h. Or you could allow the caller to
make the choice either through a parameter, encapsulating the choice in
some kind of state, or even with a callback function that allows the
caller to specify the method of growth. (You could have a default
choice or callback, in case the caller isn't interested.)
> char *get_line(FILE *stream)
> {
> char *s = NULL; size_t len = 0; int c;
>
> do c = fgetc(stream); while (c == '\n'); /* ignore leading empty lines */
> if (c == EOF) return NULL;
> ungetc(c, stream);
>
> while ( 1 )
> {
> size_t max = len + BUFLEN;
> s = realloc(s, max);
> if (s == NULL) exit(EXIT_FAILURE);
Although you said above that error-handling wasn't particularly
graceful, this call to 'exit' seems a bit harsh.
> while (len < max)
> {
> c = fgetc(stream);
> if (c == EOF || c == '\n')
> {
> s[len] = '\0';
> return realloc(s, len+1);
> }
> s[len++] = c;
> }
> }
> }
>
Since a stream might be "line buffered", I wonder if you could gain any
sort of advantage by using 'fscanf'... The following quick C89 code
(could have bugs!) doesn't try to grow any buffer, but uses 'fscanf':
#include <stdio.h>
int fetch_a_line(char * buf, unsigned int bufsz, FILE * stream) {
char format_buf[
/* '%' */
1 +
/* 32 decimal digits */
32 +
/* "[^\n]%n" */
6 +
/* null terminator */
1
];
int matched;
int bytes;
int c;
sprintf(format_buf, "%%%u[^\n]%%n", bufsz);
matched = fscanf(stream, format_buf, buf, &bytes);
c = getc(stream);
if (c != '\n')
ungetc(c, stream);
if (matched > 0)
return bytes;
return matched;
}
int main(void) {
char test[512];
int bytes;
while (1) {
bytes = fetch_a_line(test, sizeof test - 1, stdin);
if (bytes == EOF)
break;
printf("Read line of %d characters: %s\n", bytes, test);
}
printf("Done.\n");
return 0;
}
--
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.
Cheerily," -- Richard Harter