1190214Srpaulo/*- 2190214Srpaulo * Copyright (c) 2009 David Schultz <das@FreeBSD.org> 3190214Srpaulo * All rights reserved. 4190214Srpaulo * 5190214Srpaulo * Redistribution and use in source and binary forms, with or without 6190214Srpaulo * modification, are permitted provided that the following conditions 7190214Srpaulo * are met: 8190214Srpaulo * 1. Redistributions of source code must retain the above copyright 9190214Srpaulo * notice, this list of conditions and the following disclaimer. 10190214Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11190214Srpaulo * notice, this list of conditions and the following disclaimer in the 12190214Srpaulo * documentation and/or other materials provided with the distribution. 13190214Srpaulo * 14190214Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15190214Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16190214Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17190214Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18190214Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19190214Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20190214Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21190214Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22190214Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23190214Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24190214Srpaulo * SUCH DAMAGE. 25190214Srpaulo */ 26190214Srpaulo 27190214Srpaulo#include <sys/cdefs.h> 28190214Srpaulo__FBSDID("$FreeBSD: stable/10/lib/libc/stdio/getdelim.c 321074 2017-07-17 14:09:34Z kib $"); 29214518Srpaulo 30190214Srpaulo#include "namespace.h" 31190214Srpaulo#include <sys/param.h> 32190214Srpaulo#include <errno.h> 33190214Srpaulo#include <limits.h> 34190214Srpaulo#include <stdio.h> 35190214Srpaulo#include <stdlib.h> 36190214Srpaulo#include <string.h> 37190214Srpaulo#include "un-namespace.h" 38190214Srpaulo 39190214Srpaulo#include "libc_private.h" 40190214Srpaulo#include "local.h" 41190214Srpaulo 42190214Srpaulostatic inline size_t 43190214Srpaulop2roundup(size_t n) 44190214Srpaulo{ 45190214Srpaulo 46190214Srpaulo if (!powerof2(n)) { 47190214Srpaulo n--; 48190214Srpaulo n |= n >> 1; 49190214Srpaulo n |= n >> 2; 50190214Srpaulo n |= n >> 4; 51190214Srpaulo n |= n >> 8; 52235426Sdelphij n |= n >> 16; 53190214Srpaulo#if SIZE_T_MAX > 0xffffffffU 54190214Srpaulo n |= n >> 32; 55190214Srpaulo#endif 56190214Srpaulo n++; 57214518Srpaulo } 58190214Srpaulo return (n); 59190214Srpaulo} 60190214Srpaulo 61190214Srpaulo/* 62190214Srpaulo * Expand *linep to hold len bytes (up to SSIZE_MAX + 1). 63190214Srpaulo */ 64190214Srpaulostatic inline int 65190214Srpauloexpandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp) 66190214Srpaulo{ 67190214Srpaulo char *newline; 68190214Srpaulo size_t newcap; 69190214Srpaulo 70190214Srpaulo if (len > (size_t)SSIZE_MAX + 1) { 71190214Srpaulo errno = EOVERFLOW; 72190214Srpaulo return (-1); 73190214Srpaulo } 74190214Srpaulo if (len > *capp) { 75190214Srpaulo if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */ 76190214Srpaulo newcap = (size_t)SSIZE_MAX + 1; 77190214Srpaulo else 78190214Srpaulo newcap = p2roundup(len); 79190214Srpaulo newline = realloc(*linep, newcap); 80190214Srpaulo if (newline == NULL) 81190214Srpaulo return (-1); 82190214Srpaulo *capp = newcap; 83190214Srpaulo *linep = newline; 84190214Srpaulo } 85190214Srpaulo return (0); 86190214Srpaulo} 87190214Srpaulo 88190214Srpaulo/* 89190214Srpaulo * Append the src buffer to the *dstp buffer. The buffers are of 90190214Srpaulo * length srclen and *dstlenp, respectively, and dst has space for 91190214Srpaulo * *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated 92190214Srpaulo * appropriately, and *dstp is reallocated if needed. Returns 0 on 93190214Srpaulo * success, -1 on allocation failure. 94190214Srpaulo */ 95190214Srpaulostatic int 96190214Srpaulosappend(char ** __restrict dstp, size_t * __restrict dstlenp, 97190214Srpaulo size_t * __restrict dstcapp, char * __restrict src, size_t srclen) 98190214Srpaulo{ 99190214Srpaulo 100190214Srpaulo /* ensure room for srclen + dstlen + terminating NUL */ 101190214Srpaulo if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp)) 102190214Srpaulo return (-1); 103190214Srpaulo memcpy(*dstp + *dstlenp, src, srclen); 104190214Srpaulo *dstlenp += srclen; 105190214Srpaulo return (0); 106190214Srpaulo} 107190214Srpaulo 108190214Srpaulossize_t 109190214Srpaulogetdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, 110190214Srpaulo FILE * __restrict fp) 111190214Srpaulo{ 112190214Srpaulo u_char *endp; 113190214Srpaulo size_t linelen; 114190214Srpaulo 115190214Srpaulo FLOCKFILE_CANCELSAFE(fp); 116190214Srpaulo ORIENT(fp, -1); 117190214Srpaulo 118235426Sdelphij if (linep == NULL || linecapp == NULL) { 119235426Sdelphij errno = EINVAL; 120190214Srpaulo goto error; 121190214Srpaulo } 122190214Srpaulo 123190214Srpaulo if (*linep == NULL) 124190214Srpaulo *linecapp = 0; 125190214Srpaulo 126190214Srpaulo if (fp->_r <= 0 && __srefill(fp)) { 127190214Srpaulo /* If fp is at EOF already, we just need space for the NUL. */ 128190214Srpaulo if (!__sfeof(fp) || expandtofit(linep, 1, linecapp)) 129190214Srpaulo goto error; 130190214Srpaulo (*linep)[0] = '\0'; 131190214Srpaulo linelen = -1; 132190214Srpaulo goto end; 133190214Srpaulo } 134190214Srpaulo 135190214Srpaulo linelen = 0; 136190214Srpaulo while ((endp = memchr(fp->_p, delim, fp->_r)) == NULL) { 137190214Srpaulo if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r)) 138190214Srpaulo goto error; 139190214Srpaulo if (__srefill(fp)) { 140190214Srpaulo if (!__sfeof(fp)) 141190214Srpaulo goto error; 142190214Srpaulo goto done; /* hit EOF */ 143190214Srpaulo } 144235426Sdelphij } 145235426Sdelphij endp++; /* snarf the delimiter, too */ 146235426Sdelphij if (sappend(linep, &linelen, linecapp, fp->_p, endp - fp->_p)) 147235426Sdelphij goto error; 148235426Sdelphij fp->_r -= endp - fp->_p; 149235426Sdelphij fp->_p = endp; 150235426Sdelphijdone: 151235426Sdelphij /* Invariant: *linep has space for at least linelen+1 bytes. */ 152235426Sdelphij (*linep)[linelen] = '\0'; 153235426Sdelphijend: 154235426Sdelphij FUNLOCKFILE_CANCELSAFE(); 155235426Sdelphij return (linelen); 156235426Sdelphij 157235426Sdelphijerror: 158235426Sdelphij fp->_flags |= __SERR; 159235426Sdelphij linelen = -1; 160235426Sdelphij goto end; 161190214Srpaulo} 162190214Srpaulo