1*555c7784Suwe /* $NetBSD: getdelim.c,v 1.14 2017/06/08 15:59:45 uwe Exp $ */
2d4a3cf6aSroy
3d4a3cf6aSroy /*
4d4a3cf6aSroy * Copyright (c) 2009 The NetBSD Foundation, Inc.
5d4a3cf6aSroy *
6d4a3cf6aSroy * This code is derived from software contributed to The NetBSD Foundation
7d4a3cf6aSroy * by Roy Marples.
8d4a3cf6aSroy *
9d4a3cf6aSroy * Redistribution and use in source and binary forms, with or without
10d4a3cf6aSroy * modification, are permitted provided that the following conditions
11d4a3cf6aSroy * are met:
12d4a3cf6aSroy * 1. Redistributions of source code must retain the above copyright
13d4a3cf6aSroy * notice, this list of conditions and the following disclaimer.
14d4a3cf6aSroy * 2. Redistributions in binary form must reproduce the above copyright
15d4a3cf6aSroy * notice, this list of conditions and the following disclaimer in the
16d4a3cf6aSroy * documentation and/or other materials provided with the distribution.
17d4a3cf6aSroy *
18d4a3cf6aSroy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19d4a3cf6aSroy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20d4a3cf6aSroy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21d4a3cf6aSroy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22d4a3cf6aSroy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23d4a3cf6aSroy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24d4a3cf6aSroy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25d4a3cf6aSroy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26d4a3cf6aSroy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27d4a3cf6aSroy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28d4a3cf6aSroy */
29d4a3cf6aSroy
30d4a3cf6aSroy #include <sys/cdefs.h>
31*555c7784Suwe __RCSID("$NetBSD: getdelim.c,v 1.14 2017/06/08 15:59:45 uwe Exp $");
3286eafd3eSroy
3386eafd3eSroy #include "namespace.h"
34d4a3cf6aSroy
35d4a3cf6aSroy #include <sys/param.h>
36d4a3cf6aSroy
37d4a3cf6aSroy #include <assert.h>
38d4a3cf6aSroy #include <errno.h>
39d4a3cf6aSroy #include <limits.h>
40d4a3cf6aSroy #include <stdio.h>
41d4a3cf6aSroy #include <stdlib.h>
42d4a3cf6aSroy #include <string.h>
43d4a3cf6aSroy
44d4a3cf6aSroy #include "reentrant.h"
45d4a3cf6aSroy #include "local.h"
46d4a3cf6aSroy
473490b83aSroy #ifdef __weak_alias
__weak_alias(getdelim,_getdelim)483490b83aSroy __weak_alias(getdelim, _getdelim)
493490b83aSroy #endif
503490b83aSroy
51d4a3cf6aSroy /* Minimum buffer size we create.
52d4a3cf6aSroy * This should allow config files to fit into our power of 2 buffer growth
53d4a3cf6aSroy * without the need for a realloc. */
54d4a3cf6aSroy #define MINBUF 128
55d4a3cf6aSroy
56d4a3cf6aSroy ssize_t
577cfa0468Sroy __getdelim(char **__restrict buf, size_t *__restrict buflen,
58d4a3cf6aSroy int sep, FILE *__restrict fp)
59d4a3cf6aSroy {
60d4a3cf6aSroy unsigned char *p;
6186eafd3eSroy size_t len, newlen, off;
62d4a3cf6aSroy char *newb;
63d4a3cf6aSroy
64d4a3cf6aSroy _DIAGASSERT(fp != NULL);
65d4a3cf6aSroy
66d4a3cf6aSroy if (buf == NULL || buflen == NULL) {
67d4a3cf6aSroy errno = EINVAL;
689c6b248aSjoerg goto error;
69d4a3cf6aSroy }
70d4a3cf6aSroy
71d4a3cf6aSroy /* If buf is NULL, we have to assume a size of zero */
72d4a3cf6aSroy if (*buf == NULL)
73d4a3cf6aSroy *buflen = 0;
74d4a3cf6aSroy
75d4a3cf6aSroy _SET_ORIENTATION(fp, -1);
76d4a3cf6aSroy off = 0;
77755657beSroy do {
78d4a3cf6aSroy /* If the input buffer is empty, refill it */
79d4a3cf6aSroy if (fp->_r <= 0 && __srefill(fp)) {
8086eafd3eSroy if (__sferror(fp))
81d4a3cf6aSroy goto error;
82755657beSroy /* No error, so EOF. */
83d4a3cf6aSroy break;
84d4a3cf6aSroy }
85d4a3cf6aSroy
86d4a3cf6aSroy /* Scan through looking for the separator */
87cfbb35edSchristos p = memchr(fp->_p, sep, (size_t)fp->_r);
88d4a3cf6aSroy if (p == NULL)
89d4a3cf6aSroy len = fp->_r;
90d4a3cf6aSroy else
91d4a3cf6aSroy len = (p - fp->_p) + 1;
92d4a3cf6aSroy
935eba3548Sroy newlen = off + len;
9486eafd3eSroy /* Ensure we can handle it */
95c9c21f1eSroy if (newlen < off || newlen > SSIZE_MAX) {
96d4a3cf6aSroy errno = EOVERFLOW;
97d4a3cf6aSroy goto error;
98d4a3cf6aSroy }
99*555c7784Suwe newlen++; /* reserve space for the null terminator */
100d4a3cf6aSroy if (newlen > *buflen) {
101d4a3cf6aSroy if (newlen < MINBUF)
102d4a3cf6aSroy newlen = MINBUF;
103d4a3cf6aSroy if (!powerof2(newlen)) {
104d4a3cf6aSroy /* Grow the buffer to the next power of 2 */
105d4a3cf6aSroy newlen--;
106d4a3cf6aSroy newlen |= newlen >> 1;
107d4a3cf6aSroy newlen |= newlen >> 2;
108d4a3cf6aSroy newlen |= newlen >> 4;
109d4a3cf6aSroy newlen |= newlen >> 8;
110d4a3cf6aSroy newlen |= newlen >> 16;
111d4a3cf6aSroy #if SIZE_T_MAX > 0xffffffffU
112d4a3cf6aSroy newlen |= newlen >> 32;
113d4a3cf6aSroy #endif
114d4a3cf6aSroy newlen++;
115d4a3cf6aSroy }
116d4a3cf6aSroy
117d4a3cf6aSroy newb = realloc(*buf, newlen);
118d4a3cf6aSroy if (newb == NULL)
119d4a3cf6aSroy goto error;
120d4a3cf6aSroy *buf = newb;
121d4a3cf6aSroy *buflen = newlen;
122d4a3cf6aSroy }
123d4a3cf6aSroy
124cfbb35edSchristos (void)memcpy((*buf + off), fp->_p, len);
125cfef64a1Schristos /* Safe, len is never greater than what fp->_r can fit. */
126cfef64a1Schristos fp->_r -= (int)len;
127cfef64a1Schristos fp->_p += (int)len;
128d4a3cf6aSroy off += len;
129755657beSroy } while (p == NULL);
130755657beSroy
131755657beSroy /* POSIX demands we return -1 on EOF. */
132755657beSroy if (off == 0)
133755657beSroy return -1;
134755657beSroy
135d4a3cf6aSroy if (*buf != NULL)
136d4a3cf6aSroy *(*buf + off) = '\0';
137d4a3cf6aSroy return off;
138d4a3cf6aSroy
139d4a3cf6aSroy error:
140755657beSroy fp->_flags |= __SERR;
141d4a3cf6aSroy return -1;
142d4a3cf6aSroy }
1437cfa0468Sroy
1447cfa0468Sroy ssize_t
getdelim(char ** __restrict buf,size_t * __restrict buflen,int sep,FILE * __restrict fp)1457cfa0468Sroy getdelim(char **__restrict buf, size_t *__restrict buflen,
1467cfa0468Sroy int sep, FILE *__restrict fp)
1477cfa0468Sroy {
1487cfa0468Sroy ssize_t n;
1497cfa0468Sroy
1507cfa0468Sroy FLOCKFILE(fp);
1517cfa0468Sroy n = __getdelim(buf, buflen, sep, fp);
1527cfa0468Sroy FUNLOCKFILE(fp);
1537cfa0468Sroy return n;
1547cfa0468Sroy }
155