diff options
Diffstat (limited to 'lib/util/io.c')
-rw-r--r-- | lib/util/io.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/lib/util/io.c b/lib/util/io.c new file mode 100644 index 00000000..54ecb6a8 --- /dev/null +++ b/lib/util/io.c @@ -0,0 +1,92 @@ +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#include "mallocvar.h" +#include "nstring.h" + +#include "io.h" + + +void +pm_freadline(FILE * const fileP, + const char ** const lineP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Read a line (assuming the file is text with lines delimited by newlines) + from file *fileP. Return that line in newly malloced storage as *lineP. + + The newline delimiter is not part of the line. + + As a special case, if the file doesn't end in a newline, the characters + after the last newline are a line. + + If there are no more lines in the file, return *lineP == NULL. +-----------------------------------------------------------------------------*/ + char * buffer; + size_t bufferSize; + size_t cursor; + bool gotLine; + bool eof; + + bufferSize = 1024; /* initial value */ + *errorP = NULL; /* initial value */ + + MALLOCARRAY(buffer, bufferSize); + + for (cursor = 0, gotLine = false, eof = false; + !gotLine && !eof && !*errorP; ) { + if (cursor + 1 >= bufferSize) { + if (bufferSize > INT_MAX/2) { + free(buffer); + buffer = NULL; + } else { + bufferSize *= 2; + REALLOCARRAY(buffer, bufferSize); + } + } + + if (!buffer) + pm_asprintf(errorP, + "Couldn't get memory for a %u-byte file read buffer.", + (unsigned int)bufferSize); + else { + int const rc = getc(fileP); + + if (rc < 0) { + if (feof(fileP)) + eof = true; + else + pm_asprintf(errorP, + "Failed to read a character from file. " + "Errno = %d (%s)", + errno, strerror(errno)); + } else { + char const c = (char)rc; + + if (c == '\n') + gotLine = true; + else { + buffer[cursor++] = c; + } + } + } + } + if (*errorP) { + if (buffer) + free(buffer); + } else { + if (eof && cursor == 0) { + *lineP = NULL; + free(buffer); + } else { + assert(cursor < bufferSize); + buffer[cursor++] = '\0'; + + *lineP = buffer; + } + } +} + + |