initial import
[glibc.git] / stdio / getdelim.c
blob8047c1fe0c66edceb607d6d77c9977d92a8c2acb
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>
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 DEFUN(__getdelim, (lineptr, n, terminator, stream),
34 char **lineptr AND size_t *n AND int terminator AND FILE *stream)
36 char *line, *p;
37 size_t size, copy;
39 if (!__validfp (stream) || lineptr == NULL || n == NULL)
41 errno = EINVAL;
42 return -1;
45 if (ferror (stream))
46 return -1;
48 /* Make sure we have a line buffer to start with. */
49 if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */
51 #ifndef MAX_CANON
52 #define MAX_CANON 256
53 #endif
54 line = realloc (*lineptr, MAX_CANON);
55 if (line == NULL)
56 return -1;
57 *lineptr = line;
58 *n = MAX_CANON;
61 line = *lineptr;
62 size = *n;
64 copy = size;
65 p = line;
67 if (stream->__buffer == NULL && stream->__userbuf)
69 /* Unbuffered stream. Not much optimization to do. */
71 while (1)
73 size_t len;
75 while (--copy > 0)
77 register int c = getc (stream);
78 if (c == EOF)
79 goto lose;
80 else if ((*p++ = c) == terminator)
81 goto win;
84 /* Need to enlarge the line buffer. */
85 len = p - line;
86 size *= 2;
87 line = realloc (line, size);
88 if (line == NULL)
89 goto lose;
90 *lineptr = line;
91 *n = size;
92 p = line + len;
93 copy = size - len;
96 else
98 /* Leave space for the terminating null. */
99 --copy;
101 if (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back)
103 /* Do one with getc to allocate a buffer. */
104 int c = getc (stream);
105 if (c == EOF)
106 goto lose;
107 *p++ = c;
108 if (c == terminator)
109 goto win;
110 --copy;
113 while (1)
115 size_t i;
116 char *found;
118 i = stream->__get_limit - stream->__bufp;
119 if (i == 0)
121 /* Refill the buffer. */
122 int c = __fillbf (stream);
123 if (c == EOF)
124 goto lose;
125 *p++ = c;
126 if (c == terminator)
127 goto win;
128 --copy;
129 i = stream->__get_limit - stream->__bufp;
132 if (i > copy)
133 i = copy;
135 found = (char *) __memccpy ((PTR) p, stream->__bufp, terminator, i);
136 if (found != NULL)
138 stream->__bufp += found - p;
139 p = found;
140 goto win;
143 stream->__bufp += i;
144 p += i;
145 copy -= i;
146 if (copy == 0)
148 /* Need to enlarge the line buffer. */
149 size_t len = p - line;
150 size *= 2;
151 line = realloc (line, size);
152 if (line == NULL)
153 goto lose;
154 *lineptr = line;
155 *n = size;
156 p = line + len;
157 copy = size - len;
158 /* Leave space for the terminating null. */
159 --copy;
164 lose:
165 if (p == *lineptr)
166 return -1;
167 /* Return a partial line since we got an error in the middle. */
168 win:
169 *p = '\0';
170 return p - *lineptr;
173 weak_alias (__getdelim, getdelim)