getdelim.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /* getdelim.c --- Implementation of replacement getdelim function.
  2. Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2013 Free Software
  3. Foundation, Inc.
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License as
  6. published by the Free Software Foundation; either version 3, or (at
  7. your option) any later version.
  8. This program is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, see <http://www.gnu.org/licenses/>. */
  14. /* Ported from glibc by Simon Josefsson. */
  15. /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
  16. optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below. */
  17. #define _GL_ARG_NONNULL(params)
  18. #include <config.h>
  19. #include <stdio.h>
  20. #include <limits.h>
  21. #include <stdint.h>
  22. #include <stdlib.h>
  23. #include <errno.h>
  24. #ifndef SSIZE_MAX
  25. # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
  26. #endif
  27. #if USE_UNLOCKED_IO
  28. # include "unlocked-io.h"
  29. # define getc_maybe_unlocked(fp) getc(fp)
  30. #elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED
  31. # undef flockfile
  32. # undef funlockfile
  33. # define flockfile(x) ((void) 0)
  34. # define funlockfile(x) ((void) 0)
  35. # define getc_maybe_unlocked(fp) getc(fp)
  36. #else
  37. # define getc_maybe_unlocked(fp) getc_unlocked(fp)
  38. #endif
  39. /* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
  40. NUL-terminate it). *LINEPTR is a pointer returned from malloc (or
  41. NULL), pointing to *N characters of space. It is realloc'ed as
  42. necessary. Returns the number of characters read (not including
  43. the null terminator), or -1 on error or EOF. */
  44. ssize_t
  45. getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
  46. {
  47. ssize_t result;
  48. size_t cur_len = 0;
  49. if (lineptr == NULL || n == NULL || fp == NULL)
  50. {
  51. errno = EINVAL;
  52. return -1;
  53. }
  54. flockfile (fp);
  55. if (*lineptr == NULL || *n == 0)
  56. {
  57. char *new_lineptr;
  58. *n = 120;
  59. new_lineptr = (char *) realloc (*lineptr, *n);
  60. if (new_lineptr == NULL)
  61. {
  62. result = -1;
  63. goto unlock_return;
  64. }
  65. *lineptr = new_lineptr;
  66. }
  67. for (;;)
  68. {
  69. int i;
  70. i = getc_maybe_unlocked (fp);
  71. if (i == EOF)
  72. {
  73. result = -1;
  74. break;
  75. }
  76. /* Make enough space for len+1 (for final NUL) bytes. */
  77. if (cur_len + 1 >= *n)
  78. {
  79. size_t needed_max =
  80. SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
  81. size_t needed = 2 * *n + 1; /* Be generous. */
  82. char *new_lineptr;
  83. if (needed_max < needed)
  84. needed = needed_max;
  85. if (cur_len + 1 >= needed)
  86. {
  87. result = -1;
  88. errno = EOVERFLOW;
  89. goto unlock_return;
  90. }
  91. new_lineptr = (char *) realloc (*lineptr, needed);
  92. if (new_lineptr == NULL)
  93. {
  94. result = -1;
  95. goto unlock_return;
  96. }
  97. *lineptr = new_lineptr;
  98. *n = needed;
  99. }
  100. (*lineptr)[cur_len] = i;
  101. cur_len++;
  102. if (i == delimiter)
  103. break;
  104. }
  105. (*lineptr)[cur_len] = '\0';
  106. result = cur_len ? cur_len : result;
  107. unlock_return:
  108. funlockfile (fp); /* doesn't set errno */
  109. return result;
  110. }