/contrib/cvs/lib/getline.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 174 lines · 112 code · 25 blank · 37 comment · 21 complexity · 8cdfb1910fe6f3ab4df66f52d6b7a692 MD5 · raw file

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