OSDN Git Service

2011-09-01 Thomas Koenig <tkoenig@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / libgfortran / io / fbuf.c
1 /* Copyright (C) 2008, 2009, 2010 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 = 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;
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       dest = realloc (u->fbuf->buf, newlen);
125       if (dest == NULL)
126         return NULL;
127       u->fbuf->buf = dest;
128       u->fbuf->len = newlen;
129     }
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;
135   return dest;
136 }
137
138
139 /* mode argument is WRITING for write mode and READING for read
140    mode. Return value is 0 for success, -1 on failure.  */
141
142 int
143 fbuf_flush (gfc_unit * u, unit_mode mode)
144 {
145   int nwritten;
146
147   if (!u->fbuf)
148     return 0;
149
150   fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
151
152   if (mode == WRITING)
153     {
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         }
160     }
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;
174 }
175
176
177 int
178 fbuf_seek (gfc_unit * u, int off, int whence)
179 {
180   if (!u->fbuf)
181     return -1;
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
218 char *
219 fbuf_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
249 int
250 fbuf_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;
269 }