]>
Commit | Line | Data |
---|---|---|
3185942a JA |
1 | /* zgetline - read a line of input from a specified file descriptor and return |
2 | a pointer to a newly-allocated buffer containing the data. */ | |
3 | ||
8868edaf | 4 | /* Copyright (C) 2008-2020 Free Software Foundation, Inc. |
3185942a JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
8 | Bash is free software: you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation, either version 3 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | Bash is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with Bash. If not, see <http://www.gnu.org/licenses/>. | |
20 | */ | |
21 | ||
22 | #include <config.h> | |
23 | ||
24 | #include <sys/types.h> | |
25 | ||
26 | #if defined (HAVE_UNISTD_H) | |
27 | # include <unistd.h> | |
28 | #endif | |
29 | ||
30 | #include <errno.h> | |
31 | #include "xmalloc.h" | |
32 | ||
33 | #if !defined (errno) | |
34 | extern int errno; | |
35 | #endif | |
36 | ||
8868edaf CR |
37 | extern ssize_t zread PARAMS((int, char *, size_t)); |
38 | extern ssize_t zreadc PARAMS((int, char *)); | |
39 | extern ssize_t zreadintr PARAMS((int, char *, size_t)); | |
40 | extern ssize_t zreadcintr PARAMS((int, char *)); | |
17345e5a | 41 | |
8868edaf CR |
42 | typedef ssize_t breadfunc_t PARAMS((int, char *, size_t)); |
43 | typedef ssize_t creadfunc_t PARAMS((int, char *)); | |
3185942a JA |
44 | |
45 | /* Initial memory allocation for automatic growing buffer in zreadlinec */ | |
46 | #define GET_LINE_INITIAL_ALLOCATION 16 | |
47 | ||
48 | /* Derived from GNU libc's getline. | |
49 | The behavior is almost the same as getline. See man getline. | |
50 | The differences are | |
a0c0a00f CR |
51 | (1) using file descriptor instead of FILE *; |
52 | (2) the order of arguments: the file descriptor comes first; | |
53 | (3) the addition of a fourth argument, DELIM; sets the delimiter to | |
54 | be something other than newline if desired. If setting DELIM, | |
55 | the next argument should be 1; and | |
56 | (4) the addition of a fifth argument, UNBUFFERED_READ; this argument | |
3185942a JA |
57 | controls whether get_line uses buffering or not to get a byte data |
58 | from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and | |
59 | uses zread if UNBUFFERED_READ is non-zero. | |
60 | ||
61 | Returns number of bytes read or -1 on error. */ | |
62 | ||
63 | ssize_t | |
a0c0a00f | 64 | zgetline (fd, lineptr, n, delim, unbuffered_read) |
3185942a JA |
65 | int fd; |
66 | char **lineptr; | |
67 | size_t *n; | |
a0c0a00f | 68 | int delim; |
3185942a JA |
69 | int unbuffered_read; |
70 | { | |
71 | int nr, retval; | |
72 | char *line, c; | |
73 | ||
74 | if (lineptr == 0 || n == 0 || (*lineptr == 0 && *n != 0)) | |
75 | return -1; | |
76 | ||
77 | nr = 0; | |
78 | line = *lineptr; | |
79 | ||
80 | while (1) | |
81 | { | |
82 | retval = unbuffered_read ? zread (fd, &c, 1) : zreadc(fd, &c); | |
83 | ||
84 | if (retval <= 0) | |
85 | { | |
17345e5a JA |
86 | if (line && nr > 0) |
87 | line[nr] = '\0'; | |
3185942a JA |
88 | break; |
89 | } | |
90 | ||
91 | if (nr + 2 >= *n) | |
92 | { | |
17345e5a JA |
93 | size_t new_size; |
94 | ||
95 | new_size = (*n == 0) ? GET_LINE_INITIAL_ALLOCATION : *n * 2; | |
96 | line = (*n >= new_size) ? NULL : xrealloc (*lineptr, new_size); | |
97 | ||
98 | if (line) | |
99 | { | |
100 | *lineptr = line; | |
101 | *n = new_size; | |
102 | } | |
103 | else | |
104 | { | |
105 | if (*n > 0) | |
106 | { | |
107 | (*lineptr)[*n - 1] = '\0'; | |
108 | nr = *n - 2; | |
109 | } | |
110 | break; | |
111 | } | |
3185942a JA |
112 | } |
113 | ||
114 | line[nr] = c; | |
115 | nr++; | |
116 | ||
a0c0a00f | 117 | if (c == delim) |
3185942a JA |
118 | { |
119 | line[nr] = '\0'; | |
120 | break; | |
121 | } | |
122 | } | |
123 | ||
124 | return nr - 1; | |
125 | } |