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