fbuf.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /* Copyright (C) 2008-2015 Free Software Foundation, Inc.
  2. Contributed by Janne Blomqvist
  3. This file is part of the GNU Fortran runtime library (libgfortran).
  4. Libgfortran is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3, or (at your option)
  7. any later version.
  8. Libgfortran is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. Under Section 7 of GPL version 3, you are granted additional
  13. permissions described in the GCC Runtime Library Exception, version
  14. 3.1, as published by the Free Software Foundation.
  15. You should have received a copy of the GNU General Public License and
  16. a copy of the GCC Runtime Library Exception along with this program;
  17. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  18. <http://www.gnu.org/licenses/>. */
  19. #include "io.h"
  20. #include "fbuf.h"
  21. #include "unix.h"
  22. #include <string.h>
  23. #include <stdlib.h>
  24. //#define FBUF_DEBUG
  25. void
  26. fbuf_init (gfc_unit * u, int len)
  27. {
  28. if (len == 0)
  29. len = 512; /* Default size. */
  30. u->fbuf = xmalloc (sizeof (struct fbuf));
  31. u->fbuf->buf = xmalloc (len);
  32. u->fbuf->len = len;
  33. u->fbuf->act = u->fbuf->pos = 0;
  34. }
  35. void
  36. fbuf_destroy (gfc_unit * u)
  37. {
  38. if (u->fbuf == NULL)
  39. return;
  40. free (u->fbuf->buf);
  41. free (u->fbuf);
  42. u->fbuf = NULL;
  43. }
  44. static void
  45. #ifdef FBUF_DEBUG
  46. fbuf_debug (gfc_unit * u, const char * format, ...)
  47. {
  48. va_list args;
  49. va_start(args, format);
  50. vfprintf(stderr, format, args);
  51. va_end(args);
  52. fprintf (stderr, "fbuf_debug pos: %d, act: %d, buf: ''",
  53. u->fbuf->pos, u->fbuf->act);
  54. for (int ii = 0; ii < u->fbuf->act; ii++)
  55. {
  56. putc (u->fbuf->buf[ii], stderr);
  57. }
  58. fprintf (stderr, "''\n");
  59. }
  60. #else
  61. fbuf_debug (gfc_unit * u __attribute__ ((unused)),
  62. const char * format __attribute__ ((unused)),
  63. ...) {}
  64. #endif
  65. /* You should probably call this before doing a physical seek on the
  66. underlying device. Returns how much the physical position was
  67. modified. */
  68. int
  69. fbuf_reset (gfc_unit * u)
  70. {
  71. int seekval = 0;
  72. if (!u->fbuf)
  73. return 0;
  74. fbuf_debug (u, "fbuf_reset: ");
  75. fbuf_flush (u, u->mode);
  76. /* If we read past the current position, seek the underlying device
  77. back. */
  78. if (u->mode == READING && u->fbuf->act > u->fbuf->pos)
  79. {
  80. seekval = - (u->fbuf->act - u->fbuf->pos);
  81. fbuf_debug (u, "fbuf_reset seekval %d, ", seekval);
  82. }
  83. u->fbuf->act = u->fbuf->pos = 0;
  84. return seekval;
  85. }
  86. /* Return a pointer to the current position in the buffer, and increase
  87. the pointer by len. Makes sure that the buffer is big enough,
  88. reallocating if necessary. */
  89. char *
  90. fbuf_alloc (gfc_unit * u, int len)
  91. {
  92. int newlen;
  93. char *dest;
  94. fbuf_debug (u, "fbuf_alloc len %d, ", len);
  95. if (u->fbuf->pos + len > u->fbuf->len)
  96. {
  97. /* Round up to nearest multiple of the current buffer length. */
  98. newlen = ((u->fbuf->pos + len) / u->fbuf->len + 1) * u->fbuf->len;
  99. u->fbuf->buf = xrealloc (u->fbuf->buf, newlen);
  100. u->fbuf->len = newlen;
  101. }
  102. dest = u->fbuf->buf + u->fbuf->pos;
  103. u->fbuf->pos += len;
  104. if (u->fbuf->pos > u->fbuf->act)
  105. u->fbuf->act = u->fbuf->pos;
  106. return dest;
  107. }
  108. /* mode argument is WRITING for write mode and READING for read
  109. mode. Return value is 0 for success, -1 on failure. */
  110. int
  111. fbuf_flush (gfc_unit * u, unit_mode mode)
  112. {
  113. int nwritten;
  114. if (!u->fbuf)
  115. return 0;
  116. fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
  117. if (mode == WRITING)
  118. {
  119. if (u->fbuf->pos > 0)
  120. {
  121. nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
  122. if (nwritten < 0)
  123. return -1;
  124. }
  125. }
  126. /* Salvage remaining bytes for both reading and writing. This
  127. happens with the combination of advance='no' and T edit
  128. descriptors leaving the final position somewhere not at the end
  129. of the record. For reading, this also happens if we sread() past
  130. the record boundary. */
  131. if (u->fbuf->act > u->fbuf->pos && u->fbuf->pos > 0)
  132. memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
  133. u->fbuf->act - u->fbuf->pos);
  134. u->fbuf->act -= u->fbuf->pos;
  135. u->fbuf->pos = 0;
  136. return 0;
  137. }
  138. /* The mode argument is LIST_WRITING for write mode and LIST_READING for
  139. read. This should only be used for list directed I/O.
  140. Return value is 0 for success, -1 on failure. */
  141. int
  142. fbuf_flush_list (gfc_unit * u, unit_mode mode)
  143. {
  144. int nwritten;
  145. if (!u->fbuf)
  146. return 0;
  147. if (u->fbuf->pos < 524288) /* Upper limit for list writing. */
  148. return 0;
  149. fbuf_debug (u, "fbuf_flush_list with mode %d: ", mode);
  150. if (mode == LIST_WRITING)
  151. {
  152. nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
  153. if (nwritten < 0)
  154. return -1;
  155. }
  156. /* Salvage remaining bytes for both reading and writing. */
  157. if (u->fbuf->act > u->fbuf->pos)
  158. memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
  159. u->fbuf->act - u->fbuf->pos);
  160. u->fbuf->act -= u->fbuf->pos;
  161. u->fbuf->pos = 0;
  162. return 0;
  163. }
  164. int
  165. fbuf_seek (gfc_unit * u, int off, int whence)
  166. {
  167. if (!u->fbuf)
  168. return -1;
  169. switch (whence)
  170. {
  171. case SEEK_SET:
  172. break;
  173. case SEEK_CUR:
  174. off += u->fbuf->pos;
  175. break;
  176. case SEEK_END:
  177. off += u->fbuf->act;
  178. break;
  179. default:
  180. return -1;
  181. }
  182. fbuf_debug (u, "fbuf_seek, off %d ", off);
  183. /* The start of the buffer is always equal to the left tab
  184. limit. Moving to the left past the buffer is illegal in C and
  185. would also imply moving past the left tab limit, which is never
  186. allowed in Fortran. Similarly, seeking past the end of the buffer
  187. is not possible, in that case the user must make sure to allocate
  188. space with fbuf_alloc(). So return error if that is
  189. attempted. */
  190. if (off < 0 || off > u->fbuf->act)
  191. return -1;
  192. u->fbuf->pos = off;
  193. return off;
  194. }
  195. /* Fill the buffer with bytes for reading. Returns a pointer to start
  196. reading from. If we hit EOF, returns a short read count. If any
  197. other error occurs, return NULL. After reading, the caller is
  198. expected to call fbuf_seek to update the position with the number
  199. of bytes actually processed. */
  200. char *
  201. fbuf_read (gfc_unit * u, int * len)
  202. {
  203. char *ptr;
  204. int oldact, oldpos;
  205. int readlen = 0;
  206. fbuf_debug (u, "fbuf_read, len %d: ", *len);
  207. oldact = u->fbuf->act;
  208. oldpos = u->fbuf->pos;
  209. ptr = fbuf_alloc (u, *len);
  210. u->fbuf->pos = oldpos;
  211. if (oldpos + *len > oldact)
  212. {
  213. fbuf_debug (u, "reading %d bytes starting at %d ",
  214. oldpos + *len - oldact, oldact);
  215. readlen = sread (u->s, u->fbuf->buf + oldact, oldpos + *len - oldact);
  216. if (readlen < 0)
  217. return NULL;
  218. *len = oldact - oldpos + readlen;
  219. }
  220. u->fbuf->act = oldact + readlen;
  221. fbuf_debug (u, "fbuf_read done: ");
  222. return ptr;
  223. }
  224. /* When the fbuf_getc() inline function runs out of buffer space, it
  225. calls this function to fill the buffer with bytes for
  226. reading. Never call this function directly. */
  227. int
  228. fbuf_getc_refill (gfc_unit * u)
  229. {
  230. int nread;
  231. char *p;
  232. fbuf_debug (u, "fbuf_getc_refill ");
  233. /* Read 80 bytes (average line length?). This is a compromise
  234. between not needing to call the read() syscall all the time and
  235. not having to memmove unnecessary stuff when switching to the
  236. next record. */
  237. nread = 80;
  238. p = fbuf_read (u, &nread);
  239. if (p && nread > 0)
  240. return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
  241. else
  242. return EOF;
  243. }