]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/sh/zgetline.c
bash-5.1 distribution sources and documentation
[thirdparty/bash.git] / lib / sh / zgetline.c
CommitLineData
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)
34extern int errno;
35#endif
36
8868edaf
CR
37extern ssize_t zread PARAMS((int, char *, size_t));
38extern ssize_t zreadc PARAMS((int, char *));
39extern ssize_t zreadintr PARAMS((int, char *, size_t));
40extern ssize_t zreadcintr PARAMS((int, char *));
17345e5a 41
8868edaf
CR
42typedef ssize_t breadfunc_t PARAMS((int, char *, size_t));
43typedef 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
63ssize_t
a0c0a00f 64zgetline (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}