about summary refs log tree commit diff
path: root/lib/util/io.c
blob: 54ecb6a885de55f65ebbce32c7a839bff714571f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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;
        }
    }
}