1 /* getdelim.c --- Implementation of replacement getdelim function. 2 Copyright (C) 1994, 1996, 1997, 1998, 2001, 2003, 2005 Free 3 Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 2, or (at 8 your option) any later version. 9 10 This program is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 02110-1301, USA. */ 19 20 /* Ported from glibc by Simon Josefsson. */ 21 22 #ifdef HAVE_CONFIG_H 23 # include <config.h> 24 #endif 25 26 #include "getdelim.h" 27 28 #include <limits.h> 29 #include <stdlib.h> 30 #include <errno.h> 31 32 #ifndef SIZE_MAX 33 # define SIZE_MAX ((size_t) -1) 34 #endif 35 #ifndef SSIZE_MAX 36 # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) 37 #endif 38 #if !HAVE_FLOCKFILE 39 # undef flockfile 40 # define flockfile(x) ((void) 0) 41 #endif 42 #if !HAVE_FUNLOCKFILE 43 # undef funlockfile 44 # define funlockfile(x) ((void) 0) 45 #endif 46 47 /* Read up to (and including) a DELIMITER from FP into *LINEPTR (and 48 NUL-terminate it). *LINEPTR is a pointer returned from malloc (or 49 NULL), pointing to *N characters of space. It is realloc'ed as 50 necessary. Returns the number of characters read (not including 51 the null terminator), or -1 on error or EOF. */ 52 53 ssize_t 54 getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp) 55 { 56 ssize_t result; 57 size_t cur_len = 0; 58 59 if (lineptr == NULL || n == NULL || fp == NULL) 60 { 61 errno = EINVAL; 62 return -1; 63 } 64 65 flockfile (fp); 66 67 if (*lineptr == NULL || *n == 0) 68 { 69 *n = 120; 70 *lineptr = (char *) malloc (*n); 71 if (*lineptr == NULL) 72 { 73 result = -1; 74 goto unlock_return; 75 } 76 } 77 78 for (;;) 79 { 80 int i; 81 82 i = getc (fp); 83 if (i == EOF) 84 { 85 result = -1; 86 break; 87 } 88 89 /* Make enough space for len+1 (for final NUL) bytes. */ 90 if (cur_len + 1 >= *n) 91 { 92 size_t needed_max = 93 SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX; 94 size_t needed = 2 * *n + 1; /* Be generous. */ 95 char *new_lineptr; 96 97 if (needed_max < needed) 98 needed = needed_max; 99 if (cur_len + 1 >= needed) 100 { 101 result = -1; 102 goto unlock_return; 103 } 104 105 new_lineptr = (char *) realloc (*lineptr, needed); 106 if (new_lineptr == NULL) 107 { 108 result = -1; 109 goto unlock_return; 110 } 111 112 *lineptr = new_lineptr; 113 *n = needed; 114 } 115 116 (*lineptr)[cur_len] = i; 117 cur_len++; 118 119 if (i == delimiter) 120 break; 121 } 122 (*lineptr)[cur_len] = '\0'; 123 result = cur_len ? cur_len : result; 124 125 unlock_return: 126 funlockfile (fp); 127 return result; 128 } 129