123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- /* Copyright (C) 2008-2015 Free Software Foundation, Inc.
- Contributed by Janne Blomqvist
- This file is part of the GNU Fortran runtime library (libgfortran).
- Libgfortran is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- Libgfortran is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- Under Section 7 of GPL version 3, you are granted additional
- permissions described in the GCC Runtime Library Exception, version
- 3.1, as published by the Free Software Foundation.
- You should have received a copy of the GNU General Public License and
- a copy of the GCC Runtime Library Exception along with this program;
- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- <http://www.gnu.org/licenses/>. */
- #include "io.h"
- #include "fbuf.h"
- #include "unix.h"
- #include <string.h>
- #include <stdlib.h>
- //#define FBUF_DEBUG
- void
- fbuf_init (gfc_unit * u, int len)
- {
- if (len == 0)
- len = 512; /* Default size. */
- u->fbuf = xmalloc (sizeof (struct fbuf));
- u->fbuf->buf = xmalloc (len);
- u->fbuf->len = len;
- u->fbuf->act = u->fbuf->pos = 0;
- }
- void
- fbuf_destroy (gfc_unit * u)
- {
- if (u->fbuf == NULL)
- return;
- free (u->fbuf->buf);
- free (u->fbuf);
- u->fbuf = NULL;
- }
- static void
- #ifdef FBUF_DEBUG
- fbuf_debug (gfc_unit * u, const char * format, ...)
- {
- va_list args;
- va_start(args, format);
- vfprintf(stderr, format, args);
- va_end(args);
- fprintf (stderr, "fbuf_debug pos: %d, act: %d, buf: ''",
- u->fbuf->pos, u->fbuf->act);
- for (int ii = 0; ii < u->fbuf->act; ii++)
- {
- putc (u->fbuf->buf[ii], stderr);
- }
- fprintf (stderr, "''\n");
- }
- #else
- fbuf_debug (gfc_unit * u __attribute__ ((unused)),
- const char * format __attribute__ ((unused)),
- ...) {}
- #endif
-
- /* You should probably call this before doing a physical seek on the
- underlying device. Returns how much the physical position was
- modified. */
- int
- fbuf_reset (gfc_unit * u)
- {
- int seekval = 0;
- if (!u->fbuf)
- return 0;
- fbuf_debug (u, "fbuf_reset: ");
- fbuf_flush (u, u->mode);
- /* If we read past the current position, seek the underlying device
- back. */
- if (u->mode == READING && u->fbuf->act > u->fbuf->pos)
- {
- seekval = - (u->fbuf->act - u->fbuf->pos);
- fbuf_debug (u, "fbuf_reset seekval %d, ", seekval);
- }
- u->fbuf->act = u->fbuf->pos = 0;
- return seekval;
- }
- /* Return a pointer to the current position in the buffer, and increase
- the pointer by len. Makes sure that the buffer is big enough,
- reallocating if necessary. */
- char *
- fbuf_alloc (gfc_unit * u, int len)
- {
- int newlen;
- char *dest;
- fbuf_debug (u, "fbuf_alloc len %d, ", len);
- if (u->fbuf->pos + len > u->fbuf->len)
- {
- /* Round up to nearest multiple of the current buffer length. */
- newlen = ((u->fbuf->pos + len) / u->fbuf->len + 1) * u->fbuf->len;
- u->fbuf->buf = xrealloc (u->fbuf->buf, newlen);
- u->fbuf->len = newlen;
- }
- dest = u->fbuf->buf + u->fbuf->pos;
- u->fbuf->pos += len;
- if (u->fbuf->pos > u->fbuf->act)
- u->fbuf->act = u->fbuf->pos;
- return dest;
- }
- /* mode argument is WRITING for write mode and READING for read
- mode. Return value is 0 for success, -1 on failure. */
- int
- fbuf_flush (gfc_unit * u, unit_mode mode)
- {
- int nwritten;
- if (!u->fbuf)
- return 0;
- fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
- if (mode == WRITING)
- {
- if (u->fbuf->pos > 0)
- {
- nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
- if (nwritten < 0)
- return -1;
- }
- }
- /* Salvage remaining bytes for both reading and writing. This
- happens with the combination of advance='no' and T edit
- descriptors leaving the final position somewhere not at the end
- of the record. For reading, this also happens if we sread() past
- the record boundary. */
- if (u->fbuf->act > u->fbuf->pos && u->fbuf->pos > 0)
- memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
- u->fbuf->act - u->fbuf->pos);
- u->fbuf->act -= u->fbuf->pos;
- u->fbuf->pos = 0;
- return 0;
- }
- /* The mode argument is LIST_WRITING for write mode and LIST_READING for
- read. This should only be used for list directed I/O.
- Return value is 0 for success, -1 on failure. */
- int
- fbuf_flush_list (gfc_unit * u, unit_mode mode)
- {
- int nwritten;
- if (!u->fbuf)
- return 0;
- if (u->fbuf->pos < 524288) /* Upper limit for list writing. */
- return 0;
- fbuf_debug (u, "fbuf_flush_list with mode %d: ", mode);
- if (mode == LIST_WRITING)
- {
- nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
- if (nwritten < 0)
- return -1;
- }
- /* Salvage remaining bytes for both reading and writing. */
- if (u->fbuf->act > u->fbuf->pos)
- memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
- u->fbuf->act - u->fbuf->pos);
- u->fbuf->act -= u->fbuf->pos;
- u->fbuf->pos = 0;
- return 0;
- }
- int
- fbuf_seek (gfc_unit * u, int off, int whence)
- {
- if (!u->fbuf)
- return -1;
- switch (whence)
- {
- case SEEK_SET:
- break;
- case SEEK_CUR:
- off += u->fbuf->pos;
- break;
- case SEEK_END:
- off += u->fbuf->act;
- break;
- default:
- return -1;
- }
- fbuf_debug (u, "fbuf_seek, off %d ", off);
- /* The start of the buffer is always equal to the left tab
- limit. Moving to the left past the buffer is illegal in C and
- would also imply moving past the left tab limit, which is never
- allowed in Fortran. Similarly, seeking past the end of the buffer
- is not possible, in that case the user must make sure to allocate
- space with fbuf_alloc(). So return error if that is
- attempted. */
- if (off < 0 || off > u->fbuf->act)
- return -1;
- u->fbuf->pos = off;
- return off;
- }
- /* Fill the buffer with bytes for reading. Returns a pointer to start
- reading from. If we hit EOF, returns a short read count. If any
- other error occurs, return NULL. After reading, the caller is
- expected to call fbuf_seek to update the position with the number
- of bytes actually processed. */
- char *
- fbuf_read (gfc_unit * u, int * len)
- {
- char *ptr;
- int oldact, oldpos;
- int readlen = 0;
- fbuf_debug (u, "fbuf_read, len %d: ", *len);
- oldact = u->fbuf->act;
- oldpos = u->fbuf->pos;
- ptr = fbuf_alloc (u, *len);
- u->fbuf->pos = oldpos;
- if (oldpos + *len > oldact)
- {
- fbuf_debug (u, "reading %d bytes starting at %d ",
- oldpos + *len - oldact, oldact);
- readlen = sread (u->s, u->fbuf->buf + oldact, oldpos + *len - oldact);
- if (readlen < 0)
- return NULL;
- *len = oldact - oldpos + readlen;
- }
- u->fbuf->act = oldact + readlen;
- fbuf_debug (u, "fbuf_read done: ");
- return ptr;
- }
- /* When the fbuf_getc() inline function runs out of buffer space, it
- calls this function to fill the buffer with bytes for
- reading. Never call this function directly. */
- int
- fbuf_getc_refill (gfc_unit * u)
- {
- int nread;
- char *p;
- fbuf_debug (u, "fbuf_getc_refill ");
- /* Read 80 bytes (average line length?). This is a compromise
- between not needing to call the read() syscall all the time and
- not having to memmove unnecessary stuff when switching to the
- next record. */
- nread = 80;
- p = fbuf_read (u, &nread);
- if (p && nread > 0)
- return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
- else
- return EOF;
- }
|