]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/io/fbuf.c
gfortran.texi (Project Status): Fix broken link.
[thirdparty/gcc.git] / libgfortran / io / fbuf.c
CommitLineData
f0bcf628 1/* Copyright (C) 2008-2014 Free Software Foundation, Inc.
7c1b4aba
JB
2 Contributed by Janne Blomqvist
3
4This file is part of the GNU Fortran runtime library (libgfortran).
5
6Libgfortran is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
748086b7 8the Free Software Foundation; either version 3, or (at your option)
7c1b4aba
JB
9any later version.
10
7c1b4aba
JB
11Libgfortran is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
748086b7
JJ
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23<http://www.gnu.org/licenses/>. */
7c1b4aba
JB
24
25
26#include "io.h"
92cbdb68
JB
27#include "fbuf.h"
28#include "unix.h"
7c1b4aba
JB
29#include <string.h>
30#include <stdlib.h>
31
32
7812c78c
JD
33//#define FBUF_DEBUG
34
35
7c1b4aba 36void
7812c78c 37fbuf_init (gfc_unit * u, int len)
7c1b4aba
JB
38{
39 if (len == 0)
8947fd62 40 len = 512; /* Default size. */
7c1b4aba 41
1a0fd3d3
JB
42 u->fbuf = xmalloc (sizeof (struct fbuf));
43 u->fbuf->buf = xmalloc (len);
7c1b4aba 44 u->fbuf->len = len;
7812c78c 45 u->fbuf->act = u->fbuf->pos = 0;
7c1b4aba
JB
46}
47
48
49void
50fbuf_destroy (gfc_unit * u)
51{
52 if (u->fbuf == NULL)
53 return;
04695783 54 free (u->fbuf->buf);
bb408e87 55 free (u->fbuf);
7812c78c
JD
56 u->fbuf = NULL;
57}
58
59
60static void
61#ifdef FBUF_DEBUG
62fbuf_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
77fbuf_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
88int
89fbuf_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;
7c1b4aba
JB
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,
7812c78c 112 reallocating if necessary. */
7c1b4aba
JB
113
114char *
7812c78c 115fbuf_alloc (gfc_unit * u, int len)
7c1b4aba 116{
7812c78c 117 int newlen;
7c1b4aba 118 char *dest;
7812c78c 119 fbuf_debug (u, "fbuf_alloc len %d, ", len);
8947fd62 120 if (u->fbuf->pos + len > u->fbuf->len)
7c1b4aba 121 {
7812c78c
JD
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 dest = realloc (u->fbuf->buf, newlen);
125 if (dest == NULL)
126 return NULL;
127 u->fbuf->buf = dest;
128 u->fbuf->len = newlen;
7c1b4aba 129 }
8947fd62
JB
130
131 dest = u->fbuf->buf + u->fbuf->pos;
132 u->fbuf->pos += len;
133 if (u->fbuf->pos > u->fbuf->act)
134 u->fbuf->act = u->fbuf->pos;
7c1b4aba
JB
135 return dest;
136}
137
138
7812c78c
JD
139/* mode argument is WRITING for write mode and READING for read
140 mode. Return value is 0 for success, -1 on failure. */
8947fd62 141
7c1b4aba 142int
7812c78c 143fbuf_flush (gfc_unit * u, unit_mode mode)
7c1b4aba 144{
7812c78c 145 int nwritten;
7c1b4aba
JB
146
147 if (!u->fbuf)
148 return 0;
7812c78c
JD
149
150 fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
151
152 if (mode == WRITING)
7c1b4aba 153 {
7812c78c
JD
154 if (u->fbuf->pos > 0)
155 {
156 nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
157 if (nwritten < 0)
158 return -1;
159 }
7c1b4aba 160 }
7812c78c
JD
161 /* Salvage remaining bytes for both reading and writing. This
162 happens with the combination of advance='no' and T edit
163 descriptors leaving the final position somewhere not at the end
164 of the record. For reading, this also happens if we sread() past
165 the record boundary. */
166 if (u->fbuf->act > u->fbuf->pos && u->fbuf->pos > 0)
167 memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
168 u->fbuf->act - u->fbuf->pos);
169
170 u->fbuf->act -= u->fbuf->pos;
171 u->fbuf->pos = 0;
172
173 return 0;
7c1b4aba
JB
174}
175
176
177int
7812c78c 178fbuf_seek (gfc_unit * u, int off, int whence)
7c1b4aba 179{
7812c78c 180 if (!u->fbuf)
7c1b4aba 181 return -1;
7812c78c
JD
182
183 switch (whence)
184 {
185 case SEEK_SET:
186 break;
187 case SEEK_CUR:
188 off += u->fbuf->pos;
189 break;
190 case SEEK_END:
191 off += u->fbuf->act;
192 break;
193 default:
194 return -1;
195 }
196
197 fbuf_debug (u, "fbuf_seek, off %d ", off);
198 /* The start of the buffer is always equal to the left tab
199 limit. Moving to the left past the buffer is illegal in C and
200 would also imply moving past the left tab limit, which is never
201 allowed in Fortran. Similarly, seeking past the end of the buffer
202 is not possible, in that case the user must make sure to allocate
203 space with fbuf_alloc(). So return error if that is
204 attempted. */
205 if (off < 0 || off > u->fbuf->act)
206 return -1;
207 u->fbuf->pos = off;
208 return off;
209}
210
211
212/* Fill the buffer with bytes for reading. Returns a pointer to start
213 reading from. If we hit EOF, returns a short read count. If any
214 other error occurs, return NULL. After reading, the caller is
215 expected to call fbuf_seek to update the position with the number
216 of bytes actually processed. */
217
218char *
219fbuf_read (gfc_unit * u, int * len)
220{
221 char *ptr;
222 int oldact, oldpos;
223 int readlen = 0;
224
225 fbuf_debug (u, "fbuf_read, len %d: ", *len);
226 oldact = u->fbuf->act;
227 oldpos = u->fbuf->pos;
228 ptr = fbuf_alloc (u, *len);
229 u->fbuf->pos = oldpos;
230 if (oldpos + *len > oldact)
231 {
232 fbuf_debug (u, "reading %d bytes starting at %d ",
233 oldpos + *len - oldact, oldact);
234 readlen = sread (u->s, u->fbuf->buf + oldact, oldpos + *len - oldact);
235 if (readlen < 0)
236 return NULL;
237 *len = oldact - oldpos + readlen;
238 }
239 u->fbuf->act = oldact + readlen;
240 fbuf_debug (u, "fbuf_read done: ");
241 return ptr;
242}
243
244
245/* When the fbuf_getc() inline function runs out of buffer space, it
246 calls this function to fill the buffer with bytes for
247 reading. Never call this function directly. */
248
249int
250fbuf_getc_refill (gfc_unit * u)
251{
252 int nread;
253 char *p;
254
255 fbuf_debug (u, "fbuf_getc_refill ");
256
257 /* Read 80 bytes (average line length?). This is a compromise
258 between not needing to call the read() syscall all the time and
259 not having to memmove unnecessary stuff when switching to the
260 next record. */
261 nread = 80;
262
263 p = fbuf_read (u, &nread);
264
265 if (p && nread > 0)
266 return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
267 else
268 return EOF;
7c1b4aba 269}