1 /* getline.c -- Replacement for GNU C library function getline 2 3 Copyright (C) 1993 Free 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 of the 8 License, or (at 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 /* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ 16 17 #ifdef HAVE_CONFIG_H 18 #include <config.h> 19 #endif 20 21 #include <sys/types.h> 22 #include <stdio.h> 23 #include <assert.h> 24 #include <errno.h> 25 26 #if STDC_HEADERS 27 #include <stdlib.h> 28 #else 29 char *malloc (), *realloc (); 30 #endif 31 32 /* Always add at least this many bytes when extending the buffer. */ 33 #define MIN_CHUNK 64 34 35 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR 36 + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from 37 malloc (or NULL), pointing to *N characters of space. It is realloc'd 38 as necessary. Return the number of characters read (not including the 39 null terminator), or -1 on error or EOF. On a -1 return, the caller 40 should check feof(), if not then errno has been set to indicate 41 the error. */ 42 43 int 44 getstr (lineptr, n, stream, terminator, offset) 45 char **lineptr; 46 size_t *n; 47 FILE *stream; 48 char terminator; 49 int offset; 50 { 51 int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ 52 char *read_pos; /* Where we're reading into *LINEPTR. */ 53 int ret; 54 55 if (!lineptr || !n || !stream) 56 { 57 errno = EINVAL; 58 return -1; 59 } 60 61 if (!*lineptr) 62 { 63 *n = MIN_CHUNK; 64 *lineptr = malloc (*n); 65 if (!*lineptr) 66 { 67 errno = ENOMEM; 68 return -1; 69 } 70 } 71 72 nchars_avail = *n - offset; 73 read_pos = *lineptr + offset; 74 75 for (;;) 76 { 77 int save_errno; 78 register int c = getc (stream); 79 80 save_errno = errno; 81 82 /* We always want at least one char left in the buffer, since we 83 always (unless we get an error while reading the first char) 84 NUL-terminate the line buffer. */ 85 86 assert((*lineptr + *n) == (read_pos + nchars_avail)); 87 if (nchars_avail < 2) 88 { 89 if (*n > MIN_CHUNK) 90 *n *= 2; 91 else 92 *n += MIN_CHUNK; 93 94 nchars_avail = *n + *lineptr - read_pos; 95 *lineptr = realloc (*lineptr, *n); 96 if (!*lineptr) 97 { 98 errno = ENOMEM; 99 return -1; 100 } 101 read_pos = *n - nchars_avail + *lineptr; 102 assert((*lineptr + *n) == (read_pos + nchars_avail)); 103 } 104 105 if (ferror (stream)) 106 { 107 /* Might like to return partial line, but there is no 108 place for us to store errno. And we don't want to just 109 lose errno. */ 110 errno = save_errno; 111 return -1; 112 } 113 114 if (c == EOF) 115 { 116 /* Return partial line, if any. */ 117 if (read_pos == *lineptr) 118 return -1; 119 else 120 break; 121 } 122 123 *read_pos++ = c; 124 nchars_avail--; 125 126 if (c == terminator) 127 /* Return the line. */ 128 break; 129 } 130 131 /* Done - NUL terminate and return the number of chars read. */ 132 *read_pos = '\0'; 133 134 ret = read_pos - (*lineptr + offset); 135 return ret; 136 } 137 138 int 139 getline (lineptr, n, stream) 140 char **lineptr; 141 size_t *n; 142 FILE *stream; 143 { 144 return getstr (lineptr, n, stream, '\n', 0); 145 } 146