getdelim.c revision 320942
1189136Sdas/*- 2189136Sdas * Copyright (c) 2009 David Schultz <das@FreeBSD.org> 3189136Sdas * All rights reserved. 4189136Sdas * 5189136Sdas * Redistribution and use in source and binary forms, with or without 6189136Sdas * modification, are permitted provided that the following conditions 7189136Sdas * are met: 8189136Sdas * 1. Redistributions of source code must retain the above copyright 9189136Sdas * notice, this list of conditions and the following disclaimer. 10189136Sdas * 2. Redistributions in binary form must reproduce the above copyright 11189136Sdas * notice, this list of conditions and the following disclaimer in the 12189136Sdas * documentation and/or other materials provided with the distribution. 13189136Sdas * 14189136Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15189136Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16189136Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17189136Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18189136Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19189136Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20189136Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21189136Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22189136Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23189136Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24189136Sdas * SUCH DAMAGE. 25189136Sdas */ 26189136Sdas 27189136Sdas#include <sys/cdefs.h> 28189136Sdas__FBSDID("$FreeBSD: stable/11/lib/libc/stdio/getdelim.c 320942 2017-07-13 09:27:11Z kib $"); 29189136Sdas 30189136Sdas#include "namespace.h" 31189136Sdas#include <sys/param.h> 32189136Sdas#include <errno.h> 33189136Sdas#include <limits.h> 34189136Sdas#include <stdio.h> 35189136Sdas#include <stdlib.h> 36189136Sdas#include <string.h> 37189136Sdas#include "un-namespace.h" 38189136Sdas 39189136Sdas#include "libc_private.h" 40189136Sdas#include "local.h" 41189136Sdas 42189136Sdasstatic inline size_t 43189136Sdasp2roundup(size_t n) 44189136Sdas{ 45189136Sdas 46189136Sdas if (!powerof2(n)) { 47189136Sdas n--; 48189136Sdas n |= n >> 1; 49189136Sdas n |= n >> 2; 50189136Sdas n |= n >> 4; 51189136Sdas n |= n >> 8; 52189136Sdas n |= n >> 16; 53189136Sdas#if SIZE_T_MAX > 0xffffffffU 54189136Sdas n |= n >> 32; 55189136Sdas#endif 56189136Sdas n++; 57189136Sdas } 58189136Sdas return (n); 59189136Sdas} 60189136Sdas 61189136Sdas/* 62189136Sdas * Expand *linep to hold len bytes (up to SSIZE_MAX + 1). 63189136Sdas */ 64189136Sdasstatic inline int 65189136Sdasexpandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp) 66189136Sdas{ 67189136Sdas char *newline; 68189136Sdas size_t newcap; 69189136Sdas 70189136Sdas if (len > (size_t)SSIZE_MAX + 1) { 71189136Sdas errno = EOVERFLOW; 72189136Sdas return (-1); 73189136Sdas } 74189136Sdas if (len > *capp) { 75189136Sdas if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */ 76189136Sdas newcap = (size_t)SSIZE_MAX + 1; 77189136Sdas else 78189136Sdas newcap = p2roundup(len); 79189136Sdas newline = realloc(*linep, newcap); 80189136Sdas if (newline == NULL) 81189136Sdas return (-1); 82189136Sdas *capp = newcap; 83189136Sdas *linep = newline; 84189136Sdas } 85189136Sdas return (0); 86189136Sdas} 87189136Sdas 88189136Sdas/* 89189136Sdas * Append the src buffer to the *dstp buffer. The buffers are of 90189136Sdas * length srclen and *dstlenp, respectively, and dst has space for 91189136Sdas * *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated 92189136Sdas * appropriately, and *dstp is reallocated if needed. Returns 0 on 93189136Sdas * success, -1 on allocation failure. 94189136Sdas */ 95189136Sdasstatic int 96189136Sdassappend(char ** __restrict dstp, size_t * __restrict dstlenp, 97189136Sdas size_t * __restrict dstcapp, char * __restrict src, size_t srclen) 98189136Sdas{ 99189136Sdas 100189136Sdas /* ensure room for srclen + dstlen + terminating NUL */ 101189136Sdas if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp)) 102189136Sdas return (-1); 103189136Sdas memcpy(*dstp + *dstlenp, src, srclen); 104189136Sdas *dstlenp += srclen; 105189136Sdas return (0); 106189136Sdas} 107189136Sdas 108189136Sdasssize_t 109189136Sdasgetdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, 110189136Sdas FILE * __restrict fp) 111189136Sdas{ 112189136Sdas u_char *endp; 113189136Sdas size_t linelen; 114189136Sdas 115320942Skib FLOCKFILE_CANCELSAFE(fp); 116189136Sdas ORIENT(fp, -1); 117189136Sdas 118189136Sdas if (linep == NULL || linecapp == NULL) { 119189136Sdas errno = EINVAL; 120189136Sdas goto error; 121189136Sdas } 122189136Sdas 123197752Sdas if (*linep == NULL) 124197752Sdas *linecapp = 0; 125189136Sdas 126189136Sdas if (fp->_r <= 0 && __srefill(fp)) { 127189136Sdas /* If fp is at EOF already, we just need space for the NUL. */ 128304890Sache if (!__sfeof(fp) || expandtofit(linep, 1, linecapp)) 129189136Sdas goto error; 130190773Sdas (*linep)[0] = '\0'; 131320942Skib linelen = -1; 132320942Skib goto end; 133189136Sdas } 134189136Sdas 135190773Sdas linelen = 0; 136189136Sdas while ((endp = memchr(fp->_p, delim, fp->_r)) == NULL) { 137189136Sdas if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r)) 138189136Sdas goto error; 139189136Sdas if (__srefill(fp)) { 140304890Sache if (!__sfeof(fp)) 141189136Sdas goto error; 142189136Sdas goto done; /* hit EOF */ 143189136Sdas } 144189136Sdas } 145189136Sdas endp++; /* snarf the delimiter, too */ 146189136Sdas if (sappend(linep, &linelen, linecapp, fp->_p, endp - fp->_p)) 147189136Sdas goto error; 148189136Sdas fp->_r -= endp - fp->_p; 149189136Sdas fp->_p = endp; 150189136Sdasdone: 151189136Sdas /* Invariant: *linep has space for at least linelen+1 bytes. */ 152189136Sdas (*linep)[linelen] = '\0'; 153320942Skibend: 154320942Skib FUNLOCKFILE_CANCELSAFE(); 155189136Sdas return (linelen); 156189136Sdas 157189136Sdaserror: 158189136Sdas fp->_flags |= __SERR; 159320942Skib linelen = -1; 160320942Skib goto end; 161189136Sdas} 162