gen-strtab.awk: Work around ULTRIX 4.5 nawk bug.
[dxcommon.git] / src / getline.h
blobe82fffba1958134dd729f4527e870d8a9afe17e1
1 /*
2 * Copyright © 2024 Nick Bowler
4 * getline-like function which removes trailing newline (if any).
6 * If HAVE_GETLINE is not defined (or defined to 0) then a standard C
7 * implementation is used. Othewrise, the POSIX getline function
8 * is called.
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 #ifndef DX_GETLINE_H_
24 #define DX_GETLINE_H_
27 * On some very old preprocessors (e.g., VAX C) -Dinline= defines inline to 1,
28 * so when not using a config header detect and work around the problem here.
30 #if !HAVE_CONFIG_H && (inline - 1 == 0)
31 # undef inline
32 # define inline
33 #endif
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <limits.h>
41 * Size of the initial buffer allocated internally by the fallback
42 * implementation when *linebuf is NULL.
44 #ifndef DX_GETLINE_INITIAL_ALLOC
45 # define DX_GETLINE_INITIAL_ALLOC 75
46 #endif
48 enum {
49 DX_GETLINE_OK = 1,
50 DX_GETLINE_EOF = 0,
51 DX_GETLINE_ERROR = -1,
52 DX_GETLINE_ENOMEM = -2
56 * Wrapper around getline with standard C fallback.
58 * Note that for portability to some getline implementations (e.g., FreeBSD)
59 * both *linebuf and *n should be set to zero on the initial call.
61 * If pre-allocating a buffer, ensure that its size is more than 1 byte,
62 * otherwise AIX 7.2 getline fails to work correctly.
64 * Returns 1 (DX_GETLINE_OK) if a line was read or 0 (DX_GETLINE_EOF) if
65 * no line could be read because the end of file was reached.
67 * On failure, returns a negative value. If the C library input call failed
68 * then the return value is DX_GETLINE_ERROR and the reason for the failure
69 * should be available in errno.
71 * For the standard C fallback only, a return value of DX_GETLINE_ENOMEM
72 * indicates that the buffer allocation could not be expanded to fit the
73 * input line.
75 static inline int dx_getline(char **linebuf, size_t *n, FILE *f)
77 #if HAVE_GETLINE
78 ssize_t rc;
80 if ((rc = getline(linebuf, n, f)) < 0) {
81 if (ferror(f))
82 return DX_GETLINE_ERROR;
83 return DX_GETLINE_EOF;
86 if (rc-- && (*linebuf)[rc] == '\n')
87 (*linebuf)[rc] = '\0';
89 return DX_GETLINE_OK;
90 #else
91 char *work = *linebuf;
92 size_t pos = 0;
93 size_t sz;
95 if (!work) {
96 sz = DX_GETLINE_INITIAL_ALLOC;
97 goto initial_alloc;
100 for (sz = *n;;) {
101 if (!fgets(&work[pos], sz - pos, f)) {
102 if (ferror(f))
103 return DX_GETLINE_ERROR;
105 return pos ? DX_GETLINE_OK : DX_GETLINE_EOF;
108 pos += strlen(&work[pos]);
109 if (work[pos-1] == '\n') {
110 work[pos-1] = '\0';
111 return DX_GETLINE_OK;
114 if (sz > INT_MAX/2 || sz > ((size_t)-1)/4)
115 break;
117 sz = ((sz*4) + 2) / 3;
118 initial_alloc:
119 work = realloc(work, sz);
120 if (!work)
121 break;
122 *linebuf = work;
123 *n = sz;
126 return DX_GETLINE_ENOMEM;
127 #endif
130 #endif