1 | /* getline.c -- Replacement for GNU C library function getline |
---|
2 | |
---|
3 | Copyright (C) 1993, 1996 Free Software Foundation, Inc. |
---|
4 | |
---|
5 | This program is free software; you can redistribute it and/or |
---|
6 | modify it under the terms of the GNU General Public License as |
---|
7 | published by the Free Software Foundation; either version 2 of the |
---|
8 | License, or (at your option) any later version. |
---|
9 | |
---|
10 | This program is distributed in the hope that it will be useful, but |
---|
11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
13 | 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, write to the Free Software |
---|
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
---|
18 | |
---|
19 | /* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ |
---|
20 | |
---|
21 | #if HAVE_CONFIG_H |
---|
22 | # include <config.h> |
---|
23 | #endif |
---|
24 | |
---|
25 | /* The `getdelim' function is only declared if the following symbol |
---|
26 | is defined. */ |
---|
27 | #ifndef _GNU_SOURCE |
---|
28 | # define _GNU_SOURCE 1 |
---|
29 | #endif |
---|
30 | #include <stdio.h> |
---|
31 | #include <sys/types.h> |
---|
32 | |
---|
33 | #if defined __GNU_LIBRARY__ && HAVE_GETDELIM |
---|
34 | |
---|
35 | int |
---|
36 | getline (lineptr, n, stream) |
---|
37 | char **lineptr; |
---|
38 | size_t *n; |
---|
39 | FILE *stream; |
---|
40 | { |
---|
41 | return getdelim (lineptr, n, '\n', stream); |
---|
42 | } |
---|
43 | |
---|
44 | #else /* ! have getdelim */ |
---|
45 | |
---|
46 | # define NDEBUG |
---|
47 | # include <assert.h> |
---|
48 | |
---|
49 | # if HAVE_STDLIB_H |
---|
50 | # include <stdlib.h> |
---|
51 | # else |
---|
52 | extern char *malloc (); |
---|
53 | extern char *realloc (); |
---|
54 | # endif |
---|
55 | |
---|
56 | /* Always add at least this many bytes when extending the buffer. */ |
---|
57 | # define MIN_CHUNK 64 |
---|
58 | |
---|
59 | /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR |
---|
60 | + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from |
---|
61 | malloc (or NULL), pointing to *N characters of space. It is realloc'd |
---|
62 | as necessary. Return the number of characters read (not including the |
---|
63 | null terminator), or -1 on error or EOF. |
---|
64 | NOTE: There is another getstr() function declared in <curses.h>. */ |
---|
65 | |
---|
66 | static int |
---|
67 | getstr (lineptr, n, stream, terminator, offset) |
---|
68 | char **lineptr; |
---|
69 | size_t *n; |
---|
70 | FILE *stream; |
---|
71 | char terminator; |
---|
72 | size_t offset; |
---|
73 | { |
---|
74 | int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ |
---|
75 | char *read_pos; /* Where we're reading into *LINEPTR. */ |
---|
76 | int ret; |
---|
77 | |
---|
78 | if (!lineptr || !n || !stream) |
---|
79 | return -1; |
---|
80 | |
---|
81 | if (!*lineptr) |
---|
82 | { |
---|
83 | *n = MIN_CHUNK; |
---|
84 | *lineptr = malloc (*n); |
---|
85 | if (!*lineptr) |
---|
86 | return -1; |
---|
87 | } |
---|
88 | |
---|
89 | nchars_avail = *n - offset; |
---|
90 | read_pos = *lineptr + offset; |
---|
91 | |
---|
92 | for (;;) |
---|
93 | { |
---|
94 | register int c = getc (stream); |
---|
95 | |
---|
96 | /* We always want at least one char left in the buffer, since we |
---|
97 | always (unless we get an error while reading the first char) |
---|
98 | NUL-terminate the line buffer. */ |
---|
99 | |
---|
100 | assert(*n - nchars_avail == read_pos - *lineptr); |
---|
101 | if (nchars_avail < 2) |
---|
102 | { |
---|
103 | if (*n > MIN_CHUNK) |
---|
104 | *n *= 2; |
---|
105 | else |
---|
106 | *n += MIN_CHUNK; |
---|
107 | |
---|
108 | nchars_avail = *n + *lineptr - read_pos; |
---|
109 | *lineptr = realloc (*lineptr, *n); |
---|
110 | if (!*lineptr) |
---|
111 | return -1; |
---|
112 | read_pos = *n - nchars_avail + *lineptr; |
---|
113 | assert(*n - nchars_avail == read_pos - *lineptr); |
---|
114 | } |
---|
115 | |
---|
116 | if (c == EOF || ferror (stream)) |
---|
117 | { |
---|
118 | /* Return partial line, if any. */ |
---|
119 | if (read_pos == *lineptr) |
---|
120 | return -1; |
---|
121 | else |
---|
122 | break; |
---|
123 | } |
---|
124 | |
---|
125 | *read_pos++ = c; |
---|
126 | nchars_avail--; |
---|
127 | |
---|
128 | if (c == terminator) |
---|
129 | /* Return the line. */ |
---|
130 | break; |
---|
131 | } |
---|
132 | |
---|
133 | /* Done - NUL terminate and return the number of chars read. */ |
---|
134 | *read_pos = '\0'; |
---|
135 | |
---|
136 | ret = read_pos - (*lineptr + offset); |
---|
137 | return ret; |
---|
138 | } |
---|
139 | |
---|
140 | int |
---|
141 | getline (lineptr, n, stream) |
---|
142 | char **lineptr; |
---|
143 | size_t *n; |
---|
144 | FILE *stream; |
---|
145 | { |
---|
146 | return getstr (lineptr, n, stream, '\n', 0); |
---|
147 | } |
---|
148 | |
---|
149 | int |
---|
150 | getdelim (lineptr, n, delimiter, stream) |
---|
151 | char **lineptr; |
---|
152 | size_t *n; |
---|
153 | int delimiter; |
---|
154 | FILE *stream; |
---|
155 | { |
---|
156 | return getstr (lineptr, n, stream, delimiter, 0); |
---|
157 | } |
---|
158 | #endif |
---|