1 /* getline.c -- Replacement for GNU C library function getline 2 * 3 * Copyright (C) 1993, 1996, 2001, 2002 Free Software Foundation, Inc. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 /* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ 9 10 #include <assert.h> 11 #include <stdio.h> 12 13 /* Always add at least this many bytes when extending the buffer. */ 14 #define MIN_CHUNK 64 15 16 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR 17 + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from 18 malloc (or NULL), pointing to *N characters of space. It is realloc'd 19 as necessary. Return the number of characters read (not including the 20 null terminator), or -1 on error or EOF. 21 NOTE: There is another getstr() function declared in <curses.h>. */ 22 static int getstr(char **lineptr, size_t *n, FILE *stream, 23 char terminator, size_t offset) 24 { 25 int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ 26 char *read_pos; /* Where we're reading into *LINEPTR. */ 27 int ret; 28 29 if (!lineptr || !n || !stream) 30 return -1; 31 32 if (!*lineptr) { 33 *n = MIN_CHUNK; 34 *lineptr = malloc(*n); 35 if (!*lineptr) 36 return -1; 37 } 38 39 nchars_avail = *n - offset; 40 read_pos = *lineptr + offset; 41 42 for (;;) { 43 register int c = getc(stream); 44 45 /* We always want at least one char left in the buffer, since we 46 always (unless we get an error while reading the first char) 47 NUL-terminate the line buffer. */ 48 49 assert(*n - nchars_avail == read_pos - *lineptr); 50 if (nchars_avail < 2) { 51 if (*n > MIN_CHUNK) 52 *n *= 2; 53 else 54 *n += MIN_CHUNK; 55 56 nchars_avail = *n + *lineptr - read_pos; 57 *lineptr = realloc(*lineptr, *n); 58 if (!*lineptr) 59 return -1; 60 read_pos = *n - nchars_avail + *lineptr; 61 assert(*n - nchars_avail == read_pos - *lineptr); 62 } 63 64 if (c == EOF || ferror (stream)) { 65 /* Return partial line, if any. */ 66 if (read_pos == *lineptr) 67 return -1; 68 else 69 break; 70 } 71 72 *read_pos++ = c; 73 nchars_avail--; 74 75 if (c == terminator) 76 /* Return the line. */ 77 break; 78 } 79 80 /* Done - NUL terminate and return the number of chars read. */ 81 *read_pos = '\0'; 82 83 ret = read_pos - (*lineptr + offset); 84 return ret; 85 } 86 87 int getline (char **lineptr, size_t *n, FILE *stream) 88 { 89 return getstr(lineptr, n, stream, '\n', 0); 90 } 91