Update to 2.1.x development version
[glibc.git] / stdio / getdelim.c
blobcd6f5e5bd4825f773c3f38d05af1b0a9dc369259
1 /* Copyright (C) 1991, 1992, 1995, 1996, 1997 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 not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <limits.h>
24 #include <errno.h>
26 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
27 (and null-terminate it). *LINEPTR is a pointer returned from malloc (or
28 NULL), pointing to *N characters of space. It is realloc'd as
29 necessary. Returns the number of characters read (not including the
30 null terminator), or -1 on error or EOF. */
32 ssize_t
33 __getdelim (lineptr, n, terminator, stream)
34 char **lineptr;
35 size_t *n;
36 int terminator;
37 FILE *stream;
39 char *line, *p;
40 size_t size, copy;
42 if (!__validfp (stream) || lineptr == NULL || n == NULL)
44 __set_errno (EINVAL);
45 return -1;
48 if (ferror (stream))
49 return -1;
51 /* Make sure we have a line buffer to start with. */
52 if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */
54 #ifndef MAX_CANON
55 #define MAX_CANON 256
56 #endif
57 line = realloc (*lineptr, MAX_CANON);
58 if (line == NULL)
59 return -1;
60 *lineptr = line;
61 *n = MAX_CANON;
64 line = *lineptr;
65 size = *n;
67 copy = size;
68 p = line;
70 if (stream->__buffer == NULL && stream->__userbuf)
72 /* Unbuffered stream. Not much optimization to do. */
74 while (1)
76 size_t len;
78 while (--copy > 0)
80 register int c = getc (stream);
81 if (c == EOF)
82 goto lose;
83 else if ((*p++ = c) == terminator)
84 goto win;
87 /* Need to enlarge the line buffer. */
88 len = p - line;
89 size *= 2;
90 line = realloc (line, size);
91 if (line == NULL)
92 goto lose;
93 *lineptr = line;
94 *n = size;
95 p = line + len;
96 copy = size - len;
99 else
101 /* Leave space for the terminating null. */
102 --copy;
104 if (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back)
106 /* Do one with getc to allocate a buffer. */
107 int c = getc (stream);
108 if (c == EOF)
109 goto lose;
110 *p++ = c;
111 if (c == terminator)
112 goto win;
113 --copy;
116 while (1)
118 size_t i;
119 char *found;
121 i = stream->__get_limit - stream->__bufp;
122 if (i == 0)
124 /* Refill the buffer. */
125 int c = __fillbf (stream);
126 if (c == EOF)
127 goto lose;
128 *p++ = c;
129 if (c == terminator)
130 goto win;
131 --copy;
132 i = stream->__get_limit - stream->__bufp;
135 if (i > copy)
136 i = copy;
138 found = (char *) __memccpy ((void *) p, stream->__bufp,
139 terminator, i);
140 if (found != NULL)
142 stream->__bufp += found - p;
143 p = found;
144 goto win;
147 stream->__bufp += i;
148 p += i;
149 copy -= i;
150 if (copy == 0)
152 /* Need to enlarge the line buffer. */
153 size_t len = p - line;
154 size *= 2;
155 line = realloc (line, size);
156 if (line == NULL)
157 goto lose;
158 *lineptr = line;
159 *n = size;
160 p = line + len;
161 copy = size - len;
162 /* Leave space for the terminating null. */
163 --copy;
168 lose:
169 if (p == *lineptr)
170 return -1;
171 /* Return a partial line since we got an error in the middle. */
172 win:
173 *p = '\0';
174 return p - *lineptr;
177 weak_alias (__getdelim, getdelim)