1/* getndelim2 - Read a line from a stream, stopping at one of 2 delimiters, 2 with bounded memory allocation. 3 4 Copyright (C) 1993, 1996, 1997, 1998, 2000, 2003 Free Software 5 Foundation, Inc. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software Foundation, 19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 21/* Originally written by Jan Brittenson, bson@gnu.ai.mit.edu. */ 22 23#if HAVE_CONFIG_H 24# include <config.h> 25#endif 26 27/* Specification. */ 28#include "getndelim2.h" 29 30#if STDC_HEADERS 31# include <stdlib.h> 32#else 33char *malloc (), *realloc (); 34#endif 35 36#include "unlocked-io.h" 37 38/* Always add at least this many bytes when extending the buffer. */ 39#define MIN_CHUNK 64 40 41ssize_t 42getndelim2 (char **lineptr, size_t *linesize, size_t nmax, 43 FILE *stream, int delim1, int delim2, size_t offset) 44{ 45 size_t nbytes_avail; /* Allocated but unused chars in *LINEPTR. */ 46 char *read_pos; /* Where we're reading into *LINEPTR. */ 47 48 if (!lineptr || !linesize || !nmax || !stream) 49 return -1; 50 51 if (!*lineptr) 52 { 53 size_t newlinesize = MIN_CHUNK; 54 55 if (newlinesize > nmax) 56 newlinesize = nmax; 57 58 *linesize = newlinesize; 59 *lineptr = malloc (*linesize); 60 if (!*lineptr) 61 return -1; 62 } 63 64 if (*linesize < offset) 65 return -1; 66 67 nbytes_avail = *linesize - offset; 68 read_pos = *lineptr + offset; 69 70 if (nbytes_avail == 0 && *linesize >= nmax) 71 return -1; 72 73 for (;;) 74 { 75 /* Here always *lineptr + *linesize == read_pos + nbytes_avail. */ 76 77 register int c = getc (stream); 78 79 /* We always want at least one char left in the buffer, since we 80 always (unless we get an error while reading the first char) 81 NUL-terminate the line buffer. */ 82 83 if (nbytes_avail < 2 && *linesize < nmax) 84 { 85 size_t newlinesize = 86 (*linesize > MIN_CHUNK ? 2 * *linesize : *linesize + MIN_CHUNK); 87 88 if (newlinesize > nmax) 89 newlinesize = nmax; 90 91 if (newlinesize > *linesize) 92 { 93 *linesize = newlinesize; 94 nbytes_avail = *linesize + *lineptr - read_pos; 95 *lineptr = realloc (*lineptr, *linesize); 96 if (!*lineptr) 97 return -1; 98 read_pos = *linesize - nbytes_avail + *lineptr; 99 } 100 } 101 102 if (c == EOF || ferror (stream)) 103 { 104 /* Return partial line, if any. */ 105 if (read_pos == *lineptr) 106 return -1; 107 else 108 break; 109 } 110 111 if (nbytes_avail >= 2) 112 { 113 *read_pos++ = c; 114 nbytes_avail--; 115 } 116 117 if (c == delim1 || (delim2 && c == delim2)) 118 /* Return the line. */ 119 break; 120 } 121 122 /* Done - NUL terminate and return the number of chars read. 123 At this point we know that nbytes_avail >= 1. */ 124 *read_pos = '\0'; 125 126 return read_pos - (*lineptr + offset); 127} 128