76 lines
2.4 KiB
C
76 lines
2.4 KiB
C
/* File ggets.c - goodgets is a safe alternative to gets */
|
|
/* By C.B. Falconer. Public domain 2002-06-22 */
|
|
/* attribution appreciated. */
|
|
|
|
/* Revised 2002-06-26 New prototype.
|
|
2002-06-27 Incomplete final lines
|
|
2006-06-14 Simplified, using getc, not fgets
|
|
2006-06-15 Fixed memory leak at EOF
|
|
*/
|
|
|
|
/* fggets and ggets [which is fggets(ln, stdin)] set *ln to
|
|
a buffer filled with the next complete line from the text
|
|
stream f. The storage has been allocated within fggets,
|
|
and is normally reduced to be an exact fit. The trailing
|
|
\n has been removed, so the resultant line is ready for
|
|
dumping with puts. The buffer will be as large as is
|
|
required to hold the complete line.
|
|
|
|
Note: this means a final file line without a \n terminator
|
|
has an effective \n appended, as EOF occurs within the read.
|
|
|
|
If no error occurs fggets returns 0. If an EOF occurs on
|
|
the input file, EOF is returned. For memory allocation
|
|
errors some positive value is returned. In this case *ln
|
|
may point to a partial line. For other errors memory is
|
|
freed and *ln is set to NULL.
|
|
|
|
Freeing of assigned storage is the callers responsibility
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "ggets.h"
|
|
|
|
#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
|
|
#define DELTASIZE (INITSIZE + 16)
|
|
|
|
enum {OK = 0, NOMEM};
|
|
|
|
int fggets(char* *ln, FILE *f)
|
|
{
|
|
int cursize, ch, ix;
|
|
char *buffer, *temp;
|
|
|
|
*ln = NULL; /* default */
|
|
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
|
|
cursize = INITSIZE;
|
|
|
|
ix = 0;
|
|
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
|
|
if (ix >= (cursize - 1)) { /* extend buffer */
|
|
cursize += DELTASIZE;
|
|
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
|
|
/* ran out of memory, return partial line */
|
|
buffer[ix] = '\0';
|
|
*ln = buffer;
|
|
return NOMEM;
|
|
}
|
|
buffer = temp;
|
|
}
|
|
buffer[ix++] = ch;
|
|
}
|
|
if ((EOF == ch) && (0 == ix)) {
|
|
free(buffer);
|
|
return EOF;
|
|
}
|
|
|
|
buffer[ix] = '\0';
|
|
if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
|
|
*ln = buffer; /* without reducing it */
|
|
}
|
|
else *ln = temp;
|
|
return OK;
|
|
} /* fggets */
|
|
/* End of ggets.c */
|