Sun Jun 16 00:40:20 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[glibc.git] / stdio / getdelim.c
blob2cdb95c2a63536b18b1a9bc1acb44b55c01380f7
1 /* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #include <ansidecl.h>
20 #include <stddef.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <errno.h>
27 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
28 (and null-terminate it). *LINEPTR is a pointer returned from malloc (or
29 NULL), pointing to *N characters of space. It is realloc'd as
30 necessary. Returns the number of characters read (not including the
31 null terminator), or -1 on error or EOF. */
33 ssize_t
34 DEFUN(__getdelim, (lineptr, n, terminator, stream),
35 char **lineptr AND size_t *n AND int terminator AND FILE *stream)
37 char *line, *p;
38 size_t size, copy;
40 if (!__validfp (stream) || lineptr == NULL || n == NULL)
42 errno = EINVAL;
43 return -1;
46 if (ferror (stream))
47 return -1;
49 /* Make sure we have a line buffer to start with. */
50 if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */
52 #ifndef MAX_CANON
53 #define MAX_CANON 256
54 #endif
55 line = realloc (*lineptr, MAX_CANON);
56 if (line == NULL)
57 return -1;
58 *lineptr = line;
59 *n = MAX_CANON;
62 line = *lineptr;
63 size = *n;
65 copy = size;
66 p = line;
68 if (stream->__buffer == NULL && stream->__userbuf)
70 /* Unbuffered stream. Not much optimization to do. */
72 while (1)
74 size_t len;
76 while (--copy > 0)
78 register int c = getc (stream);
79 if (c == EOF)
80 goto lose;
81 else if ((*p++ = c) == terminator)
82 goto win;
85 /* Need to enlarge the line buffer. */
86 len = p - line;
87 size *= 2;
88 line = realloc (line, size);
89 if (line == NULL)
90 goto lose;
91 *lineptr = line;
92 *n = size;
93 p = line + len;
94 copy = size - len;
97 else
99 /* Leave space for the terminating null. */
100 --copy;
102 if (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back)
104 /* Do one with getc to allocate a buffer. */
105 int c = getc (stream);
106 if (c == EOF)
107 goto lose;
108 *p++ = c;
109 if (c == terminator)
110 goto win;
111 --copy;
114 while (1)
116 size_t i;
117 char *found;
119 i = stream->__get_limit - stream->__bufp;
120 if (i == 0)
122 /* Refill the buffer. */
123 int c = __fillbf (stream);
124 if (c == EOF)
125 goto lose;
126 *p++ = c;
127 if (c == terminator)
128 goto win;
129 --copy;
130 i = stream->__get_limit - stream->__bufp;
133 if (i > copy)
134 i = copy;
136 found = (char *) __memccpy ((PTR) p, stream->__bufp, terminator, i);
137 if (found != NULL)
139 stream->__bufp += found - p;
140 p = found;
141 goto win;
144 stream->__bufp += i;
145 p += i;
146 copy -= i;
147 if (copy == 0)
149 /* Need to enlarge the line buffer. */
150 size_t len = p - line;
151 size *= 2;
152 line = realloc (line, size);
153 if (line == NULL)
154 goto lose;
155 *lineptr = line;
156 *n = size;
157 p = line + len;
158 copy = size - len;
159 /* Leave space for the terminating null. */
160 --copy;
165 lose:
166 if (p == *lineptr)
167 return -1;
168 /* Return a partial line since we got an error in the middle. */
169 win:
170 *p = '\0';
171 return p - *lineptr;
174 weak_alias (__getdelim, getdelim)