Reputation: 7610
I want the same functionality of readline but for a file. I don't want to pass a buffer and size. I'd like a method to malloc the right amount of space
Upvotes: 1
Views: 314
Reputation: 36071
With fgetc
, you can read a character at a time from a file.
Thus, you can create a function that reads a file line by line by calling fgetc
several times. If a line is over, fgetc
reads a \n
. If the file is over, it reads EOF
.
Now, you do the following: You create a char line[1024]
(resp. a char*
that is created via malloc
) (or any other size) at the beginning, and fill it either one of the following is the case:
fgetc
gets \n
: This means, that the current line is over, and you are done with this line.fgetc
gets EOF
: This means, that the whole file is over and you are completely done.fgetc
gets anything else and there is still space available in line
: Then you simply copy the char read into the appropriate position in line
.fgetc
gets anything else and line
is already completely filled: Then, you realloc
new memory for line
and grow the current line
(to be more specific, it is practical to double the size of line
in this step).So basically you need to inform yourself about fgetc
and realloc
and combine these two functions (and some auxiliary functions) to get what you want.
Upvotes: 2
Reputation: 123578
Here's a solution I've used before. It will read a line from a text file up to and including the newline. It reads into a local, fixed-sized buffer first, and then appends that buffer to the result.
Reading ends when we see a newline or EOF or hit an error on input.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define PAGE_SIZE ... // some size large enough to handle most cases
char *getLine(FILE *stream)
{
char *res = NULL;
char inbuf[PAGE_SIZE];
size_t len = 0;
/**
* We want to use strcpy the first time through the loop,
* then strcat afterward. Using a function pointer means
* we don't have to execute a test each time through the
* loop. For a sane text file where individual lines aren't
* more than a few dozen characters long, this really doesn't
* buy us anything over an if-else statement; I just think it's a cool trick.
*
* For C99, the prototype should be
*
* char *(*f)(char * restrict, const char * restrict)
*/
char *(*f)(char *, const char *) = strcpy;
while (fgets(inbuf, sizeof inbuf, stream))
{
char *tmp = realloc(res, len + strlen(inbuf) + 1);
if (tmp)
{
res = tmp;
f(res, inbuf);
f = strcat;
len += strlen(inbuf) + 1;
}
if (strchr(inbuf, '\n'))
break;
}
if (feof(stream))
// hit EOF
else
// error on read; how you deal with it is up to you.
return res;
}
Note that if we hit EOF or error on the initial read, the function will return NULL
.
You will need to free
each line when you're done with it.
Upvotes: 1