]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/zgetline.c
commit bash-20080814 snapshot
[thirdparty/bash.git] / lib / sh / zgetline.c
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
4 /* Copyright (C) 2008 Free Software Foundation, Inc.
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
37 /* Initial memory allocation for automatic growing buffer in zreadlinec */
38 #define GET_LINE_INITIAL_ALLOCATION 16
39
40 /* Derived from GNU libc's getline.
41 The behavior is almost the same as getline. See man getline.
42 The differences are
43 (1) using file descriptor instead of FILE *,
44 (2) the order of arguments; the file descriptor comes the first, and
45 (3) the addtion of thired argument, UNBUFFERED_READ; this argument
46 controls whether get_line uses buffering or not to get a byte data
47 from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and
48 uses zread if UNBUFFERED_READ is non-zero.
49
50 Returns number of bytes read or -1 on error. */
51
52 ssize_t
53 zgetline (fd, lineptr, n, unbuffered_read)
54 int fd;
55 char **lineptr;
56 size_t *n;
57 int unbuffered_read;
58 {
59 int nr, retval;
60 char *line, c;
61
62 if (lineptr == 0 || n == 0 || (*lineptr == 0 && *n != 0))
63 return -1;
64
65 nr = 0;
66 line = *lineptr;
67
68 while (1)
69 {
70 retval = unbuffered_read ? zread (fd, &c, 1) : zreadc(fd, &c);
71
72 if (retval <= 0)
73 {
74 line[nr] = '\0';
75 break;
76 }
77
78 if (nr + 2 >= *n)
79 {
80 size_t new_size;
81
82 new_size = (*n == 0) ? GET_LINE_INITIAL_ALLOCATION : *n * 2;
83 line = xrealloc (*lineptr, new_size);
84
85 if (line)
86 {
87 *lineptr = line;
88 *n = new_size;
89 }
90 else
91 {
92 if (*n > 0)
93 {
94 (*lineptr)[*n - 1] = '\0';
95 nr = *n - 2;
96 }
97 break;
98 }
99 }
100
101 line[nr] = c;
102 nr++;
103
104 if (c == '\n')
105 {
106 line[nr] = '\0';
107 break;
108 }
109 }
110
111 return nr - 1;
112 }