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