As I said in a comment above, this isn't a built-in feature of standard C, although there is a POSIX function that does what you're looking for. If you want to roll your own, the way to do it is to dynamically allocate (and reallocate) memory to store the results you get from fgets()
. You can tell when fgets()
reaches the end of the line because it'll either abruptly reach the end of the file (in which case it will return NULL
) or because the last character it returns will be the newline.
Here's an example function. Note that I use strrchr()
to search backwards from the end of the buffer for a newline character. If we get a hit, we make sure to toss out the newline in our returned string, and make sure to break out of the while()
loop so that we don't call fgets()
again and start getting the next line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// NOTE: dygetline() allocates memory! Do not disregard the return and
// remember to free() it when you're done!
#define BSZ 1024
char *dygetline(FILE * restrict stream) {
char *ret = NULL;
char *temp = NULL;
size_t retalloc = 1;
char buffer[BSZ];
size_t buflen = 0;
char *nlsrch;
while (NULL != fgets(buffer, BSZ, stream)) {
nlsrch = strrchr(buffer, '\n');
if (nlsrch) *nlsrch = '\0'; // Remove newline if exists
// Get the size of our read buffer and grow our return buffer
buflen = strlen(buffer);
temp = realloc(ret, retalloc + buflen);
if (NULL == temp) {
fprintf(stderr, "Memory allocation error in dygetline()!\n");
free(ret);
return NULL;
}
ret = temp; // Update return buffer pointer
strcpy((ret+retalloc-1), buffer); // Add read buffer to return buffer
retalloc = retalloc + buflen; // Housekeeping
if (nlsrch) break; // If we got a newline, stop
}
// If there was a file read error and fgets() never got anything, then
// ret will still be NULL, as it was initialized. If the file ended
// without a trailing newline, then ret will contain all characters it
// was able to get from the last line. Otherwise, it should be well-
// formed.
return ret;
}