]> diplodocus.org Git - nmh/blob - sbr/getline.c
Replace getcpy() with mh_xstrdup() where the string isn't NULL.
[nmh] / sbr / getline.c
1 /*
2 * getline.c -- replacement getline() implementation
3 *
4 * This code is Copyright (c) 2016, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <limits.h>
12 #include <errno.h>
13 #ifdef HAVE_STDBOOL_H
14 # include <stdbool.h>
15 #else /* ! HAVE_STDBOOL_H */
16 # define bool int
17 # define true 1
18 # define false 0
19 #endif /* ! HAVE_STDBOOL_H */
20
21 /* Largest possible size of buffer that allows SSIZE_MAX to be returned
22 * to indicate SSIZE_MAX - 1 characters read before the '\n'. The
23 * additional 1 is for the terminating NUL. */
24 #define MAX_AVAIL ((size_t)SSIZE_MAX + 1)
25
26 /* Ideal increase in size of line buffer. */
27 #define GROWTH 128
28
29 ssize_t getline(char **lineptr, size_t *n, FILE *stream)
30 {
31 char *l;
32 size_t avail;
33 size_t used;
34 int c;
35 bool last;
36
37 if (!lineptr || !n) {
38 errno = EINVAL;
39 return -1;
40 }
41
42 l = *lineptr;
43 if (l)
44 avail = *n <= MAX_AVAIL ? *n : MAX_AVAIL;
45 else
46 avail = *n = 0; /* POSIX allows *lineptr = NULL, *n = 42. */
47 used = 0;
48 last = false;
49 for (;;) {
50 c = getc(stream);
51 if (c == EOF) {
52 if (ferror(stream) || /* errno set by stdlib. */
53 !used) /* EOF with nothing read. */
54 return -1;
55 /* Line will be returned without a \n terminator. */
56 append_nul:
57 c = '\0';
58 last = true;
59 }
60
61 if (used == avail) {
62 size_t want;
63 char *new;
64
65 if (avail == MAX_AVAIL) {
66 errno = EOVERFLOW;
67 return -1;
68 }
69 want = avail + GROWTH;
70 if (want > MAX_AVAIL)
71 want = MAX_AVAIL;
72 new = realloc(l, want);
73 if (!new)
74 return -1; /* errno set by stdlib. */
75 l = *lineptr = new;
76 avail = *n = want;
77 }
78 l[used++] = c;
79
80 if (last)
81 return used - 1; /* Don't include NUL. */
82
83 if (c == '\n')
84 goto append_nul; /* Final half loop. */
85 }
86 }