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