]>
Commit | Line | Data |
---|---|---|
2e4498b3 CR |
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 | ||
012bac39 | 4 | /* Copyright (C) 2008,2009 Free Software Foundation, Inc. |
9cbcc93b CR |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
2e4498b3 CR |
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 | */ | |
9cbcc93b CR |
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 | ||
48ff5447 CR |
37 | extern ssize_t zread __P((int, char *, size_t)); |
38 | extern ssize_t zreadc __P((int, char *)); | |
e141c35a CR |
39 | extern ssize_t zreadintr __P((int, char *, size_t)); |
40 | extern ssize_t zreadcintr __P((int, char *)); | |
41 | ||
42 | typedef ssize_t breadfunc_t __P((int, char *, size_t)); | |
43 | typedef ssize_t creadfunc_t __P((int, char *)); | |
48ff5447 | 44 | |
9cbcc93b CR |
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 | |
51 | (1) using file descriptor instead of FILE *, | |
52 | (2) the order of arguments; the file descriptor comes the first, and | |
8581f42d | 53 | (3) the addition of third argument, UNBUFFERED_READ; this argument |
9cbcc93b CR |
54 | controls whether get_line uses buffering or not to get a byte data |
55 | from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and | |
56 | uses zread if UNBUFFERED_READ is non-zero. | |
57 | ||
58 | Returns number of bytes read or -1 on error. */ | |
59 | ||
60 | ssize_t | |
61 | zgetline (fd, lineptr, n, unbuffered_read) | |
62 | int fd; | |
63 | char **lineptr; | |
64 | size_t *n; | |
65 | int unbuffered_read; | |
66 | { | |
67 | int nr, retval; | |
68 | char *line, c; | |
69 | ||
70 | if (lineptr == 0 || n == 0 || (*lineptr == 0 && *n != 0)) | |
71 | return -1; | |
72 | ||
73 | nr = 0; | |
74 | line = *lineptr; | |
75 | ||
76 | while (1) | |
77 | { | |
78 | retval = unbuffered_read ? zread (fd, &c, 1) : zreadc(fd, &c); | |
79 | ||
80 | if (retval <= 0) | |
81 | { | |
e141c35a CR |
82 | if (line && nr > 0) |
83 | line[nr] = '\0'; | |
9cbcc93b CR |
84 | break; |
85 | } | |
86 | ||
87 | if (nr + 2 >= *n) | |
88 | { | |
e141c35a CR |
89 | size_t new_size; |
90 | ||
91 | new_size = (*n == 0) ? GET_LINE_INITIAL_ALLOCATION : *n * 2; | |
92 | line = (*n >= new_size) ? NULL : xrealloc (*lineptr, new_size); | |
93 | ||
94 | if (line) | |
95 | { | |
96 | *lineptr = line; | |
97 | *n = new_size; | |
98 | } | |
99 | else | |
100 | { | |
101 | if (*n > 0) | |
102 | { | |
103 | (*lineptr)[*n - 1] = '\0'; | |
104 | nr = *n - 2; | |
105 | } | |
106 | break; | |
107 | } | |
9cbcc93b CR |
108 | } |
109 | ||
110 | line[nr] = c; | |
111 | nr++; | |
112 | ||
113 | if (c == '\n') | |
114 | { | |
115 | line[nr] = '\0'; | |
116 | break; | |
117 | } | |
118 | } | |
119 | ||
120 | return nr - 1; | |
121 | } |