1 | /* getline.c -- Replacement for GNU C library function getline |
2 | |
3 | Copyright (C) 1993, 1996, 2001-2002 Free Software Foundation, Inc. |
4 | |
5 | This program is free software: you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; either version 3 of the License, or |
8 | (at your option) any later version. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
17 | |
18 | /* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ |
19 | |
20 | /* Specification. */ |
21 | #include "getline.h" |
22 | |
23 | #include <stddef.h> |
24 | #include <stdio.h> |
25 | #include <string.h> |
26 | #include <assert.h> |
27 | |
28 | /* Always add at least this many bytes when extending the buffer. */ |
29 | #define MIN_CHUNK 64 |
30 | |
31 | /* Reads up to (and including) a TERMINATOR from STREAM into *LINEPTR + OFFSET |
32 | (and null-terminate it). *LINEPTR is a pointer returned from new [] (or |
33 | NULL), pointing to *N characters of space. It is realloc'd as |
34 | necessary. Returns the number of characters read (not including the |
35 | null terminator), or -1 on error or immediate EOF. |
36 | NOTE: There is another getstr() function declared in <curses.h>. */ |
37 | |
38 | static int |
39 | getstr (char **lineptr, size_t *n, FILE *stream, char terminator, size_t offset) |
40 | { |
41 | size_t nchars_avail; /* Allocated but unused chars in *LINEPTR. */ |
42 | char *read_pos; /* Where we're reading into *LINEPTR. */ |
43 | |
44 | if (!lineptr || !n || !stream) |
45 | return -1; |
46 | |
47 | if (!*lineptr) |
48 | { |
49 | *n = MIN_CHUNK; |
50 | *lineptr = new char[*n]; |
51 | } |
52 | |
53 | nchars_avail = *n - offset; |
54 | read_pos = *lineptr + offset; |
55 | |
56 | for (;;) |
57 | { |
58 | register int c = getc (stream); |
59 | |
60 | /* We always want at least one char left in the buffer, since we |
61 | always (unless we get an error while reading the first char) |
62 | NUL-terminate the line buffer. */ |
63 | |
64 | assert (*n - nchars_avail == (size_t) (read_pos - *lineptr)); |
65 | if (nchars_avail < 2) |
66 | { |
67 | if (*n > MIN_CHUNK) |
68 | *n *= 2; |
69 | else |
70 | *n += MIN_CHUNK; |
71 | |
72 | nchars_avail = *n + *lineptr - read_pos; |
73 | char *new_line = new char[*n]; |
74 | if (*lineptr) |
75 | { |
76 | memcpy (new_line, *lineptr, read_pos - *lineptr); |
77 | delete[] *lineptr; |
78 | } |
79 | *lineptr = new_line; |
80 | read_pos = *n - nchars_avail + *lineptr; |
81 | assert (*n - nchars_avail == (size_t) (read_pos - *lineptr)); |
82 | } |
83 | |
84 | if (c == EOF || ferror (stream)) |
85 | { |
86 | /* Return partial line, if any. */ |
87 | if (read_pos == *lineptr) |
88 | return -1; |
89 | else |
90 | break; |
91 | } |
92 | |
93 | *read_pos++ = c; |
94 | nchars_avail--; |
95 | |
96 | if (c == terminator) |
97 | /* Return the line. */ |
98 | break; |
99 | } |
100 | |
101 | /* Done - NUL terminate and return the number of chars read. */ |
102 | *read_pos = '\0'; |
103 | |
104 | return read_pos - (*lineptr + offset); |
105 | } |
106 | |
107 | int |
108 | get_line (char **lineptr, size_t *n, FILE *stream) |
109 | { |
110 | return getstr (lineptr, n, stream, '\n', 0); |
111 | } |
112 | |
113 | int |
114 | get_delim (char **lineptr, size_t *n, int delimiter, FILE *stream) |
115 | { |
116 | return getstr (lineptr, n, stream, delimiter, 0); |
117 | } |
118 | |