re PR fortran/60956 (error reading (and writing) large text files in gfortran)
[gcc.git] / libgfortran / io / fbuf.c
1 /* Copyright (C) 2008-2015 Free Software Foundation, Inc.
2 Contributed by Janne Blomqvist
3
4 This file is part of the GNU Fortran runtime library (libgfortran).
5
6 Libgfortran is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
24
25
26 #include "io.h"
27 #include "fbuf.h"
28 #include "unix.h"
29 #include <string.h>
30 #include <stdlib.h>
31
32
33 //#define FBUF_DEBUG
34
35
36 void
37 fbuf_init (gfc_unit * u, int len)
38 {
39 if (len == 0)
40 len = 512; /* Default size. */
41
42 u->fbuf = xmalloc (sizeof (struct fbuf));
43 u->fbuf->buf = xmalloc (len);
44 u->fbuf->len = len;
45 u->fbuf->act = u->fbuf->pos = 0;
46 }
47
48
49 void
50 fbuf_destroy (gfc_unit * u)
51 {
52 if (u->fbuf == NULL)
53 return;
54 free (u->fbuf->buf);
55 free (u->fbuf);
56 u->fbuf = NULL;
57 }
58
59
60 static void
61 #ifdef FBUF_DEBUG
62 fbuf_debug (gfc_unit * u, const char * format, ...)
63 {
64 va_list args;
65 va_start(args, format);
66 vfprintf(stderr, format, args);
67 va_end(args);
68 fprintf (stderr, "fbuf_debug pos: %d, act: %d, buf: ''",
69 u->fbuf->pos, u->fbuf->act);
70 for (int ii = 0; ii < u->fbuf->act; ii++)
71 {
72 putc (u->fbuf->buf[ii], stderr);
73 }
74 fprintf (stderr, "''\n");
75 }
76 #else
77 fbuf_debug (gfc_unit * u __attribute__ ((unused)),
78 const char * format __attribute__ ((unused)),
79 ...) {}
80 #endif
81
82
83
84 /* You should probably call this before doing a physical seek on the
85 underlying device. Returns how much the physical position was
86 modified. */
87
88 int
89 fbuf_reset (gfc_unit * u)
90 {
91 int seekval = 0;
92
93 if (!u->fbuf)
94 return 0;
95
96 fbuf_debug (u, "fbuf_reset: ");
97 fbuf_flush (u, u->mode);
98 /* If we read past the current position, seek the underlying device
99 back. */
100 if (u->mode == READING && u->fbuf->act > u->fbuf->pos)
101 {
102 seekval = - (u->fbuf->act - u->fbuf->pos);
103 fbuf_debug (u, "fbuf_reset seekval %d, ", seekval);
104 }
105 u->fbuf->act = u->fbuf->pos = 0;
106 return seekval;
107 }
108
109
110 /* Return a pointer to the current position in the buffer, and increase
111 the pointer by len. Makes sure that the buffer is big enough,
112 reallocating if necessary. */
113
114 char *
115 fbuf_alloc (gfc_unit * u, int len)
116 {
117 int newlen;
118 char *dest;
119 fbuf_debug (u, "fbuf_alloc len %d, ", len);
120 if (u->fbuf->pos + len > u->fbuf->len)
121 {
122 /* Round up to nearest multiple of the current buffer length. */
123 newlen = ((u->fbuf->pos + len) / u->fbuf->len + 1) * u->fbuf->len;
124 u->fbuf->buf = xrealloc (u->fbuf->buf, newlen);
125 u->fbuf->len = newlen;
126 }
127
128 dest = u->fbuf->buf + u->fbuf->pos;
129 u->fbuf->pos += len;
130 if (u->fbuf->pos > u->fbuf->act)
131 u->fbuf->act = u->fbuf->pos;
132 return dest;
133 }
134
135
136 /* mode argument is WRITING for write mode and READING for read
137 mode. Return value is 0 for success, -1 on failure. */
138
139 int
140 fbuf_flush (gfc_unit * u, unit_mode mode)
141 {
142 int nwritten;
143
144 if (!u->fbuf)
145 return 0;
146
147 fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
148
149 if (mode == WRITING)
150 {
151 if (u->fbuf->pos > 0)
152 {
153 nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
154 if (nwritten < 0)
155 return -1;
156 }
157 }
158 /* Salvage remaining bytes for both reading and writing. This
159 happens with the combination of advance='no' and T edit
160 descriptors leaving the final position somewhere not at the end
161 of the record. For reading, this also happens if we sread() past
162 the record boundary. */
163 if (u->fbuf->act > u->fbuf->pos && u->fbuf->pos > 0)
164 memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
165 u->fbuf->act - u->fbuf->pos);
166
167 u->fbuf->act -= u->fbuf->pos;
168 u->fbuf->pos = 0;
169
170 return 0;
171 }
172
173
174 /* The mode argument is LIST_WRITING for write mode and LIST_READING for
175 read. This should only be used for list directed I/O.
176 Return value is 0 for success, -1 on failure. */
177
178 int
179 fbuf_flush_list (gfc_unit * u, unit_mode mode)
180 {
181 int nwritten;
182
183 if (!u->fbuf)
184 return 0;
185
186 if (u->fbuf->pos < 524288) /* Upper limit for list writing. */
187 return 0;
188
189 fbuf_debug (u, "fbuf_flush_list with mode %d: ", mode);
190
191 if (mode == LIST_WRITING)
192 {
193 nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
194 if (nwritten < 0)
195 return -1;
196 }
197
198 /* Salvage remaining bytes for both reading and writing. */
199 if (u->fbuf->act > u->fbuf->pos)
200 memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
201 u->fbuf->act - u->fbuf->pos);
202
203 u->fbuf->act -= u->fbuf->pos;
204 u->fbuf->pos = 0;
205
206 return 0;
207 }
208
209
210 int
211 fbuf_seek (gfc_unit * u, int off, int whence)
212 {
213 if (!u->fbuf)
214 return -1;
215
216 switch (whence)
217 {
218 case SEEK_SET:
219 break;
220 case SEEK_CUR:
221 off += u->fbuf->pos;
222 break;
223 case SEEK_END:
224 off += u->fbuf->act;
225 break;
226 default:
227 return -1;
228 }
229
230 fbuf_debug (u, "fbuf_seek, off %d ", off);
231 /* The start of the buffer is always equal to the left tab
232 limit. Moving to the left past the buffer is illegal in C and
233 would also imply moving past the left tab limit, which is never
234 allowed in Fortran. Similarly, seeking past the end of the buffer
235 is not possible, in that case the user must make sure to allocate
236 space with fbuf_alloc(). So return error if that is
237 attempted. */
238 if (off < 0 || off > u->fbuf->act)
239 return -1;
240 u->fbuf->pos = off;
241 return off;
242 }
243
244
245 /* Fill the buffer with bytes for reading. Returns a pointer to start
246 reading from. If we hit EOF, returns a short read count. If any
247 other error occurs, return NULL. After reading, the caller is
248 expected to call fbuf_seek to update the position with the number
249 of bytes actually processed. */
250
251 char *
252 fbuf_read (gfc_unit * u, int * len)
253 {
254 char *ptr;
255 int oldact, oldpos;
256 int readlen = 0;
257
258 fbuf_debug (u, "fbuf_read, len %d: ", *len);
259 oldact = u->fbuf->act;
260 oldpos = u->fbuf->pos;
261 ptr = fbuf_alloc (u, *len);
262 u->fbuf->pos = oldpos;
263 if (oldpos + *len > oldact)
264 {
265 fbuf_debug (u, "reading %d bytes starting at %d ",
266 oldpos + *len - oldact, oldact);
267 readlen = sread (u->s, u->fbuf->buf + oldact, oldpos + *len - oldact);
268 if (readlen < 0)
269 return NULL;
270 *len = oldact - oldpos + readlen;
271 }
272 u->fbuf->act = oldact + readlen;
273 fbuf_debug (u, "fbuf_read done: ");
274 return ptr;
275 }
276
277
278 /* When the fbuf_getc() inline function runs out of buffer space, it
279 calls this function to fill the buffer with bytes for
280 reading. Never call this function directly. */
281
282 int
283 fbuf_getc_refill (gfc_unit * u)
284 {
285 int nread;
286 char *p;
287
288 fbuf_debug (u, "fbuf_getc_refill ");
289
290 /* Read 80 bytes (average line length?). This is a compromise
291 between not needing to call the read() syscall all the time and
292 not having to memmove unnecessary stuff when switching to the
293 next record. */
294 nread = 80;
295
296 p = fbuf_read (u, &nread);
297
298 if (p && nread > 0)
299 return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
300 else
301 return EOF;
302 }