1 /* $OpenBSD: getdelim.c,v 1.6 2017/04/13 18:36:51 brynet Exp $ */ 2 /* $NetBSD: getdelim.c,v 1.13 2011/07/22 23:12:30 joerg Exp $ */ 3 4 /* 5 * Copyright (c) 2009 The NetBSD Foundation, Inc. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Roy Marples. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <errno.h> 32 #include <limits.h> 33 #include <stdint.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #include "local.h" 39 40 /* Minimum buffer size we create. 41 * This should allow config files to fit into our power of 2 buffer growth 42 * without the need for a realloc. */ 43 #define MINBUF 128 44 45 ssize_t 46 getdelim(char **__restrict buf, size_t *__restrict buflen, 47 int sep, FILE *__restrict fp) 48 { 49 unsigned char *p; 50 size_t len, newlen, off; 51 char *newb; 52 53 FLOCKFILE(fp); 54 55 if (buf == NULL || buflen == NULL) { 56 errno = EINVAL; 57 goto error; 58 } 59 60 /* If buf is NULL, we have to assume a size of zero */ 61 if (*buf == NULL) 62 *buflen = 0; 63 64 _SET_ORIENTATION(fp, -1); 65 off = 0; 66 do { 67 /* If the input buffer is empty, refill it */ 68 if (fp->_r <= 0 && __srefill(fp)) { 69 if (__sferror(fp)) 70 goto error; 71 /* No error, so EOF. */ 72 break; 73 } 74 75 /* Scan through looking for the separator */ 76 p = memchr(fp->_p, sep, fp->_r); 77 if (p == NULL) 78 len = fp->_r; 79 else 80 len = (p - fp->_p) + 1; 81 82 /* Ensure we can handle it */ 83 if (off > SSIZE_MAX || len + 1 > SSIZE_MAX - off) { 84 errno = EOVERFLOW; 85 goto error; 86 } 87 newlen = off + len + 1; /* reserve space for NUL terminator */ 88 if (newlen > *buflen) { 89 if (newlen < MINBUF) 90 newlen = MINBUF; 91 #define powerof2(x) ((((x)-1)&(x))==0) 92 if (!powerof2(newlen)) { 93 /* Grow the buffer to the next power of 2 */ 94 newlen--; 95 newlen |= newlen >> 1; 96 newlen |= newlen >> 2; 97 newlen |= newlen >> 4; 98 newlen |= newlen >> 8; 99 newlen |= newlen >> 16; 100 #if SIZE_MAX > 0xffffffffU 101 newlen |= newlen >> 32; 102 #endif 103 newlen++; 104 } 105 106 newb = recallocarray(*buf, *buflen, newlen, 1); 107 if (newb == NULL) 108 goto error; 109 *buf = newb; 110 *buflen = newlen; 111 } 112 113 (void)memcpy((*buf + off), fp->_p, len); 114 /* Safe, len is never greater than what fp->_r can fit. */ 115 fp->_r -= (int)len; 116 fp->_p += (int)len; 117 off += len; 118 } while (p == NULL); 119 120 FUNLOCKFILE(fp); 121 122 /* POSIX demands we return -1 on EOF. */ 123 if (off == 0) 124 return -1; 125 126 if (*buf != NULL) 127 *(*buf + off) = '\0'; 128 return off; 129 130 error: 131 fp->_flags |= __SERR; 132 FUNLOCKFILE(fp); 133 return -1; 134 } 135 DEF_WEAK(getdelim); 136