1e0f95098SPeter Avalos /*- 2e0f95098SPeter Avalos * Copyright (c) 2009 David Schultz <das@FreeBSD.org> 3e0f95098SPeter Avalos * All rights reserved. 4e0f95098SPeter Avalos * 5e0f95098SPeter Avalos * Redistribution and use in source and binary forms, with or without 6e0f95098SPeter Avalos * modification, are permitted provided that the following conditions 7e0f95098SPeter Avalos * are met: 8e0f95098SPeter Avalos * 1. Redistributions of source code must retain the above copyright 9e0f95098SPeter Avalos * notice, this list of conditions and the following disclaimer. 10e0f95098SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 11e0f95098SPeter Avalos * notice, this list of conditions and the following disclaimer in the 12e0f95098SPeter Avalos * documentation and/or other materials provided with the distribution. 13e0f95098SPeter Avalos * 14e0f95098SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15e0f95098SPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16e0f95098SPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17e0f95098SPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18e0f95098SPeter Avalos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19e0f95098SPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20e0f95098SPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21e0f95098SPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22e0f95098SPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23e0f95098SPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24e0f95098SPeter Avalos * SUCH DAMAGE. 25e0f95098SPeter Avalos * 26e0f95098SPeter Avalos * $FreeBSD: src/lib/libc/stdio/getdelim.c,v 1.2 2009/04/06 13:50:04 das Exp $ 27e0f95098SPeter Avalos */ 28e0f95098SPeter Avalos 29e0f95098SPeter Avalos #include "namespace.h" 30e0f95098SPeter Avalos #include <sys/param.h> 31e0f95098SPeter Avalos #include <errno.h> 32e0f95098SPeter Avalos #include <limits.h> 33e0f95098SPeter Avalos #include <stdio.h> 34e0f95098SPeter Avalos #include <stdlib.h> 35e0f95098SPeter Avalos #include <string.h> 36e0f95098SPeter Avalos #include "un-namespace.h" 37e0f95098SPeter Avalos 38e0f95098SPeter Avalos #include "libc_private.h" 39e0f95098SPeter Avalos #include "local.h" 40e0f95098SPeter Avalos #include "priv_stdio.h" 41e0f95098SPeter Avalos 42e0f95098SPeter Avalos static inline size_t 43e0f95098SPeter Avalos p2roundup(size_t n) 44e0f95098SPeter Avalos { 45e0f95098SPeter Avalos 46e0f95098SPeter Avalos if (!powerof2(n)) { 47e0f95098SPeter Avalos n--; 48e0f95098SPeter Avalos n |= n >> 1; 49e0f95098SPeter Avalos n |= n >> 2; 50e0f95098SPeter Avalos n |= n >> 4; 51e0f95098SPeter Avalos n |= n >> 8; 52e0f95098SPeter Avalos n |= n >> 16; 53e0f95098SPeter Avalos #if SIZE_T_MAX > 0xffffffffU 54e0f95098SPeter Avalos n |= n >> 32; 55e0f95098SPeter Avalos #endif 56e0f95098SPeter Avalos n++; 57e0f95098SPeter Avalos } 58e0f95098SPeter Avalos return (n); 59e0f95098SPeter Avalos } 60e0f95098SPeter Avalos 61e0f95098SPeter Avalos /* 62e0f95098SPeter Avalos * Expand *linep to hold len bytes (up to SSIZE_MAX + 1). 63e0f95098SPeter Avalos */ 64e0f95098SPeter Avalos static inline int 65e0f95098SPeter Avalos expandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp) 66e0f95098SPeter Avalos { 67e0f95098SPeter Avalos char *newline; 68e0f95098SPeter Avalos size_t newcap; 69e0f95098SPeter Avalos 70e0f95098SPeter Avalos if (len > (size_t)SSIZE_MAX + 1) { 71e0f95098SPeter Avalos errno = EOVERFLOW; 72e0f95098SPeter Avalos return (-1); 73e0f95098SPeter Avalos } 74e0f95098SPeter Avalos if (len > *capp) { 75e0f95098SPeter Avalos if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */ 76e0f95098SPeter Avalos newcap = (size_t)SSIZE_MAX + 1; 77e0f95098SPeter Avalos else 78e0f95098SPeter Avalos newcap = p2roundup(len); 79e0f95098SPeter Avalos newline = realloc(*linep, newcap); 80e0f95098SPeter Avalos if (newline == NULL) 81e0f95098SPeter Avalos return (-1); 82e0f95098SPeter Avalos *capp = newcap; 83e0f95098SPeter Avalos *linep = newline; 84e0f95098SPeter Avalos } 85e0f95098SPeter Avalos return (0); 86e0f95098SPeter Avalos } 87e0f95098SPeter Avalos 88e0f95098SPeter Avalos /* 89e0f95098SPeter Avalos * Append the src buffer to the *dstp buffer. The buffers are of 90e0f95098SPeter Avalos * length srclen and *dstlenp, respectively, and dst has space for 91e0f95098SPeter Avalos * *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated 92e0f95098SPeter Avalos * appropriately, and *dstp is reallocated if needed. Returns 0 on 93e0f95098SPeter Avalos * success, -1 on allocation failure. 94e0f95098SPeter Avalos */ 95e0f95098SPeter Avalos static int 96e0f95098SPeter Avalos sappend(char ** __restrict dstp, size_t * __restrict dstlenp, 97e0f95098SPeter Avalos size_t * __restrict dstcapp, char * __restrict src, size_t srclen) 98e0f95098SPeter Avalos { 99e0f95098SPeter Avalos 100e0f95098SPeter Avalos /* ensure room for srclen + dstlen + terminating NUL */ 101e0f95098SPeter Avalos if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp)) 102e0f95098SPeter Avalos return (-1); 103e0f95098SPeter Avalos memcpy(*dstp + *dstlenp, src, srclen); 104e0f95098SPeter Avalos *dstlenp += srclen; 105e0f95098SPeter Avalos return (0); 106e0f95098SPeter Avalos } 107e0f95098SPeter Avalos 108e0f95098SPeter Avalos ssize_t 109e0f95098SPeter Avalos getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, 110e0f95098SPeter Avalos FILE * __restrict fp) 111e0f95098SPeter Avalos { 112e0f95098SPeter Avalos u_char *endp; 113e0f95098SPeter Avalos size_t linelen; 114e0f95098SPeter Avalos 115e0f95098SPeter Avalos FLOCKFILE(fp); 116e0f95098SPeter Avalos ORIENT(fp, -1); 117e0f95098SPeter Avalos 118e0f95098SPeter Avalos if (linep == NULL || linecapp == NULL) { 119e0f95098SPeter Avalos errno = EINVAL; 120e0f95098SPeter Avalos goto error; 121e0f95098SPeter Avalos } 122e0f95098SPeter Avalos 123*50b19aebSJohn Marino if (*linep == NULL) 124*50b19aebSJohn Marino *linecapp = 0; 125e0f95098SPeter Avalos 126e0f95098SPeter Avalos if (fp->pub._r <= 0 && __srefill(fp)) { 127e0f95098SPeter Avalos /* If fp is at EOF already, we just need space for the NUL. */ 128e0f95098SPeter Avalos if (__sferror(fp) || expandtofit(linep, 1, linecapp)) 129e0f95098SPeter Avalos goto error; 130e0f95098SPeter Avalos FUNLOCKFILE(fp); 131e0f95098SPeter Avalos (*linep)[0] = '\0'; 132e0f95098SPeter Avalos return (-1); 133e0f95098SPeter Avalos } 134e0f95098SPeter Avalos 135e0f95098SPeter Avalos linelen = 0; 136e0f95098SPeter Avalos while ((endp = memchr(fp->pub._p, delim, fp->pub._r)) == NULL) { 137e0f95098SPeter Avalos if (sappend(linep, &linelen, linecapp, fp->pub._p, fp->pub._r)) 138e0f95098SPeter Avalos goto error; 139e0f95098SPeter Avalos if (__srefill(fp)) { 140e0f95098SPeter Avalos if (__sferror(fp)) 141e0f95098SPeter Avalos goto error; 142e0f95098SPeter Avalos goto done; /* hit EOF */ 143e0f95098SPeter Avalos } 144e0f95098SPeter Avalos } 145e0f95098SPeter Avalos endp++; /* snarf the delimiter, too */ 146e0f95098SPeter Avalos if (sappend(linep, &linelen, linecapp, fp->pub._p, endp - fp->pub._p)) 147e0f95098SPeter Avalos goto error; 148e0f95098SPeter Avalos fp->pub._r -= endp - fp->pub._p; 149e0f95098SPeter Avalos fp->pub._p = endp; 150e0f95098SPeter Avalos done: 151e0f95098SPeter Avalos /* Invariant: *linep has space for at least linelen+1 bytes. */ 152e0f95098SPeter Avalos (*linep)[linelen] = '\0'; 153e0f95098SPeter Avalos FUNLOCKFILE(fp); 154e0f95098SPeter Avalos return (linelen); 155e0f95098SPeter Avalos 156e0f95098SPeter Avalos error: 157e0f95098SPeter Avalos fp->pub._flags |= __SERR; 158e0f95098SPeter Avalos FUNLOCKFILE(fp); 159e0f95098SPeter Avalos return (-1); 160e0f95098SPeter Avalos } 161