getline.c 2.2 KB

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