#include "getln.h" #include #include #include #include static char *getln_held = NULL; char *getln(FILE *stream) { size_t size; char *buf; /* Recover held input from previous run. */ if (getln_held == NULL) { size = 1024; buf = malloc(1024); } else { size = 1024 + strlen(getln_held); buf = realloc(getln_held, size); } if (buf == NULL) { perror("getln"); return NULL; } memset(buf + size - 1024, 0, 1024); getln_held = NULL; /* Read until either end of file or end of line. */ for (;;) { if (fgets(buf + size - 1024, 1023, stream) == NULL) break; if (strchr(buf, '\n') != NULL) break; /* Line is longer than 1024 bytes, realloc to make space. */ size += 1024; char *new_buf = realloc(buf, size); if (new_buf == NULL) { perror("getln"); free(buf); return NULL; } buf = new_buf; memset(buf + size - 1024, 0, 1024); } char *endl = strchr(buf, '\n'); if (endl == NULL || endl == buf) { if (buf[0] == '\0') { free(buf); return NULL; } return buf; } size_t endl_size = strlen(endl + 1); if (endl_size > 0) { getln_held = malloc(endl_size + 1); if (getln_held == NULL) { perror("getln"); free(buf); return NULL; } strcpy(getln_held, endl); endl[1] = '\0'; } return buf; } void getln_cleanup(void) { if (getln_held != NULL) { free(getln_held); getln_held = NULL; } }