/* vi: set tabstop=4 shiftwidth=4: */ /* * $Id: fgetline.c,v 1.2 1996/12/28 22:11:10 schweikh Exp $ */ /*@ignore@ */ #ifndef _POSIX_SOURCE #define _POSIX_SOURCE 1 #endif /*@end@ */ /*@+charintliteral@ */ #include /* malloc */ #include "shutup.h" #include "fgetline.h" /* * fgetline: reads a stream up to the next \n and * returns the pointer to that line. The \n is replaced * by a \0. Returns NULL on EOF or error. To distinguish * between EOF and error use feof(fp) which is nonzero * on EOF. Memory is allocated using malloc(). The caller * is responsible for freeing. */ /* * M_START is the initial size of the allocated memory. It must be * even and is doubled every time the line fills up the memory. */ #define M_START 16 #if M_START % 2 == 1 #error M_START must be even #endif char * fgetline (FILE * fp) { char *mem, *new_mem, *write_to; /* mem is const, write_to changes */ int input; size_t mem_size = M_START; input = fgetc (fp); if (input == EOF) { return NULL; /* feof(fp) now is nonzero */ } Ungetc (input, fp); /* okay, there is at least one character to read */ mem = malloc (mem_size); if (mem == NULL) { return NULL; } while ((new_mem = realloc (mem, mem_size)) != NULL) { mem = new_mem; /* On the first iteration, make write_to = mem, otherwise let * write_to point to the newly allocated memory. */ write_to = (mem_size == M_START ? mem : mem + mem_size / 2); /*@i@ */ while (write_to != mem + mem_size) { /* while we have space * to write */ input = fgetc (fp); if (input == '\n' || input == EOF) { *write_to = '\0'; return mem; } *write_to++ = (char) input; } /* We have written mem+mem_size-write_to chars into mem[], it's full. * But there might be more to read or an EOF coming. Even if EOF is * next, we have to realloc to have space for the terminating \0. */ mem_size *= 2; } /* while realloc != NULL */ /* Out of memory. Free what we allocated so far to avoid memory leak. */ /*@i1@ */ free (mem); return NULL; }