OSDN Git Service

Split up io/io.h
[pf3gnuchains/gcc-fork.git] / libgfortran / io / fbuf.c
1 /* Copyright (C) 2008, 2009 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   if (u->fbuf->buf)
55     free_mem (u->fbuf->buf);
56   free_mem (u->fbuf);
57   u->fbuf = NULL;
58 }
59
60
61 static void
62 #ifdef FBUF_DEBUG
63 fbuf_debug (gfc_unit * u, const char * format, ...)
64 {
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++)
72     {
73       putc (u->fbuf->buf[ii], stderr);
74     }
75   fprintf (stderr, "''\n");
76 }
77 #else
78 fbuf_debug (gfc_unit * u __attribute__ ((unused)),
79             const char * format __attribute__ ((unused)),
80             ...) {}
81 #endif
82
83   
84
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.  */
88
89 int
90 fbuf_reset (gfc_unit * u)
91 {
92   int seekval = 0;
93
94   if (!u->fbuf)
95     return 0;
96
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)
102     {
103       seekval = - (u->fbuf->act - u->fbuf->pos);
104       fbuf_debug (u, "fbuf_reset seekval %d, ", seekval);
105     }
106   u->fbuf->act = u->fbuf->pos = 0;
107   return seekval;
108 }
109
110
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.  */
114
115 char *
116 fbuf_alloc (gfc_unit * u, int len)
117 {
118   int newlen;
119   char *dest;
120   fbuf_debug (u, "fbuf_alloc len %d, ", len);
121   if (u->fbuf->pos + len > u->fbuf->len)
122     {
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;
130     }
131
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;
137 }
138
139
140 /* mode argument is WRITING for write mode and READING for read
141    mode. Return value is 0 for success, -1 on failure.  */
142
143 int
144 fbuf_flush (gfc_unit * u, unit_mode mode)
145 {
146   int nwritten;
147
148   if (!u->fbuf)
149     return 0;
150
151   fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
152
153   if (mode == WRITING)
154     {
155       if (u->fbuf->pos > 0)
156         {
157           nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
158           if (nwritten < 0)
159             return -1;
160         }
161     }
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);
170
171   u->fbuf->act -= u->fbuf->pos;
172   u->fbuf->pos = 0;
173
174   return 0;
175 }
176
177
178 int
179 fbuf_seek (gfc_unit * u, int off, int whence)
180 {
181   if (!u->fbuf)
182     return -1;
183
184   switch (whence)
185     {
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;
196     }
197
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;
210 }
211
212
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. */
218
219 char *
220 fbuf_read (gfc_unit * u, int * len)
221 {
222   char *ptr;
223   int oldact, oldpos;
224   int readlen = 0;
225
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)
232     {
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;
239     }
240   u->fbuf->act = oldact + readlen;
241   fbuf_debug (u, "fbuf_read done: ");
242   return ptr;
243 }
244
245
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.  */
249
250 int
251 fbuf_getc_refill (gfc_unit * u)
252 {
253   int nread;
254   char *p;
255
256   fbuf_debug (u, "fbuf_getc_refill ");
257
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;
263
264   p = fbuf_read (u, &nread);
265
266   if (p && nread > 0)
267     return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
268   else
269     return EOF;
270 }