Split up io/io.h
[official-gcc.git] / libgfortran / io / fbuf.c
blobd79cf15c473cd15d69bd61200c23bb98bd1e1c0e
1 /* Copyright (C) 2008, 2009 Free Software Foundation, Inc.
2 Contributed by Janne Blomqvist
4 This file is part of the GNU Fortran runtime library (libgfortran).
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.
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.
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.
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/>. */
26 #include "io.h"
27 #include "fbuf.h"
28 #include "unix.h"
29 #include <string.h>
30 #include <stdlib.h>
33 //#define FBUF_DEBUG
36 void
37 fbuf_init (gfc_unit * u, int len)
39 if (len == 0)
40 len = 512; /* Default size. */
42 u->fbuf = get_mem (sizeof (struct fbuf));
43 u->fbuf->buf = get_mem (len);
44 u->fbuf->len = len;
45 u->fbuf->act = u->fbuf->pos = 0;
49 void
50 fbuf_destroy (gfc_unit * u)
52 if (u->fbuf == NULL)
53 return;
54 if (u->fbuf->buf)
55 free_mem (u->fbuf->buf);
56 free_mem (u->fbuf);
57 u->fbuf = NULL;
61 static void
62 #ifdef FBUF_DEBUG
63 fbuf_debug (gfc_unit * u, const char * format, ...)
65 va_list args;
66 va_start(args, format);
67 vfprintf(stderr, format, args);
68 va_end(args);
69 fprintf (stderr, "fbuf_debug pos: %d, act: %d, buf: ''",
70 u->fbuf->pos, u->fbuf->act);
71 for (int ii = 0; ii < u->fbuf->act; ii++)
73 putc (u->fbuf->buf[ii], stderr);
75 fprintf (stderr, "''\n");
77 #else
78 fbuf_debug (gfc_unit * u __attribute__ ((unused)),
79 const char * format __attribute__ ((unused)),
80 ...) {}
81 #endif
85 /* You should probably call this before doing a physical seek on the
86 underlying device. Returns how much the physical position was
87 modified. */
89 int
90 fbuf_reset (gfc_unit * u)
92 int seekval = 0;
94 if (!u->fbuf)
95 return 0;
97 fbuf_debug (u, "fbuf_reset: ");
98 fbuf_flush (u, u->mode);
99 /* If we read past the current position, seek the underlying device
100 back. */
101 if (u->mode == READING && u->fbuf->act > u->fbuf->pos)
103 seekval = - (u->fbuf->act - u->fbuf->pos);
104 fbuf_debug (u, "fbuf_reset seekval %d, ", seekval);
106 u->fbuf->act = u->fbuf->pos = 0;
107 return seekval;
111 /* Return a pointer to the current position in the buffer, and increase
112 the pointer by len. Makes sure that the buffer is big enough,
113 reallocating if necessary. */
115 char *
116 fbuf_alloc (gfc_unit * u, int len)
118 int newlen;
119 char *dest;
120 fbuf_debug (u, "fbuf_alloc len %d, ", len);
121 if (u->fbuf->pos + len > u->fbuf->len)
123 /* Round up to nearest multiple of the current buffer length. */
124 newlen = ((u->fbuf->pos + len) / u->fbuf->len + 1) * u->fbuf->len;
125 dest = realloc (u->fbuf->buf, newlen);
126 if (dest == NULL)
127 return NULL;
128 u->fbuf->buf = dest;
129 u->fbuf->len = newlen;
132 dest = u->fbuf->buf + u->fbuf->pos;
133 u->fbuf->pos += len;
134 if (u->fbuf->pos > u->fbuf->act)
135 u->fbuf->act = u->fbuf->pos;
136 return dest;
140 /* mode argument is WRITING for write mode and READING for read
141 mode. Return value is 0 for success, -1 on failure. */
144 fbuf_flush (gfc_unit * u, unit_mode mode)
146 int nwritten;
148 if (!u->fbuf)
149 return 0;
151 fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
153 if (mode == WRITING)
155 if (u->fbuf->pos > 0)
157 nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
158 if (nwritten < 0)
159 return -1;
162 /* Salvage remaining bytes for both reading and writing. This
163 happens with the combination of advance='no' and T edit
164 descriptors leaving the final position somewhere not at the end
165 of the record. For reading, this also happens if we sread() past
166 the record boundary. */
167 if (u->fbuf->act > u->fbuf->pos && u->fbuf->pos > 0)
168 memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
169 u->fbuf->act - u->fbuf->pos);
171 u->fbuf->act -= u->fbuf->pos;
172 u->fbuf->pos = 0;
174 return 0;
179 fbuf_seek (gfc_unit * u, int off, int whence)
181 if (!u->fbuf)
182 return -1;
184 switch (whence)
186 case SEEK_SET:
187 break;
188 case SEEK_CUR:
189 off += u->fbuf->pos;
190 break;
191 case SEEK_END:
192 off += u->fbuf->act;
193 break;
194 default:
195 return -1;
198 fbuf_debug (u, "fbuf_seek, off %d ", off);
199 /* The start of the buffer is always equal to the left tab
200 limit. Moving to the left past the buffer is illegal in C and
201 would also imply moving past the left tab limit, which is never
202 allowed in Fortran. Similarly, seeking past the end of the buffer
203 is not possible, in that case the user must make sure to allocate
204 space with fbuf_alloc(). So return error if that is
205 attempted. */
206 if (off < 0 || off > u->fbuf->act)
207 return -1;
208 u->fbuf->pos = off;
209 return off;
213 /* Fill the buffer with bytes for reading. Returns a pointer to start
214 reading from. If we hit EOF, returns a short read count. If any
215 other error occurs, return NULL. After reading, the caller is
216 expected to call fbuf_seek to update the position with the number
217 of bytes actually processed. */
219 char *
220 fbuf_read (gfc_unit * u, int * len)
222 char *ptr;
223 int oldact, oldpos;
224 int readlen = 0;
226 fbuf_debug (u, "fbuf_read, len %d: ", *len);
227 oldact = u->fbuf->act;
228 oldpos = u->fbuf->pos;
229 ptr = fbuf_alloc (u, *len);
230 u->fbuf->pos = oldpos;
231 if (oldpos + *len > oldact)
233 fbuf_debug (u, "reading %d bytes starting at %d ",
234 oldpos + *len - oldact, oldact);
235 readlen = sread (u->s, u->fbuf->buf + oldact, oldpos + *len - oldact);
236 if (readlen < 0)
237 return NULL;
238 *len = oldact - oldpos + readlen;
240 u->fbuf->act = oldact + readlen;
241 fbuf_debug (u, "fbuf_read done: ");
242 return ptr;
246 /* When the fbuf_getc() inline function runs out of buffer space, it
247 calls this function to fill the buffer with bytes for
248 reading. Never call this function directly. */
251 fbuf_getc_refill (gfc_unit * u)
253 int nread;
254 char *p;
256 fbuf_debug (u, "fbuf_getc_refill ");
258 /* Read 80 bytes (average line length?). This is a compromise
259 between not needing to call the read() syscall all the time and
260 not having to memmove unnecessary stuff when switching to the
261 next record. */
262 nread = 80;
264 p = fbuf_read (u, &nread);
266 if (p && nread > 0)
267 return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
268 else
269 return EOF;