(gh_set_substr): Made src const.
[bpt/guile.git] / libguile / fports.c
CommitLineData
fd08c236 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 7 *
73be1d9e
MV
8 * This library 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 GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd 19\f
85286595
RB
20#if HAVE_CONFIG_H
21# include <config.h>
22#endif
0f2d19dd
JB
23
24#include <stdio.h>
cb63cf9e 25#include <fcntl.h>
a0599745
MD
26#include "libguile/_scm.h"
27#include "libguile/strings.h"
a0599745 28#include "libguile/validate.h"
6b72ac1d 29#include "libguile/gc.h"
eb372585 30#include "libguile/posix.h"
7f9994d9 31#include "libguile/dynwind.h"
6b72ac1d 32
a0599745 33#include "libguile/fports.h"
95b88819
GH
34
35#ifdef HAVE_STRING_H
36#include <string.h>
37#endif
0f2d19dd
JB
38#ifdef HAVE_UNISTD_H
39#include <unistd.h>
40#else
1be6b49c 41size_t fwrite ();
0f2d19dd 42#endif
b8b17bfd
MV
43#ifdef HAVE_IO_H
44#include <io.h>
45#endif
f47a5239 46#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e
JB
47#include <sys/stat.h>
48#endif
0f2d19dd 49
cb63cf9e 50#include <errno.h>
e145dd02 51
a0599745 52#include "libguile/iselect.h"
edb810bb
SJ
53
54/* Some defines for Windows (native port, not Cygwin). */
82893676
MG
55#ifdef __MINGW32__
56# include <sys/stat.h>
57# include <winsock2.h>
58# define ftruncate(fd, size) chsize (fd, size)
59#endif /* __MINGW32__ */
cb63cf9e 60
a98bddfd 61
92c2555f 62scm_t_bits scm_tc16_fport;
a98bddfd
DH
63
64
19b27fa2 65/* default buffer size, used if the O/S won't supply a value. */
1be6b49c 66static const size_t default_buffer_size = 1024;
19b27fa2 67
cb63cf9e
JB
68/* create FPORT buffer with specified sizes (or -1 to use default size or
69 0 for no buffer. */
70static void
c014a02e 71scm_fport_buffer_add (SCM port, long read_size, int write_size)
c6c79933 72#define FUNC_NAME "scm_fport_buffer_add"
e145dd02 73{
92c2555f 74 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e145dd02 75
cb63cf9e
JB
76 if (read_size == -1 || write_size == -1)
77 {
1be6b49c 78 size_t default_size;
f47a5239 79#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e 80 struct stat st;
b8b17bfd 81 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 82
19b27fa2
GH
83 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
84 : st.st_blksize;
cb63cf9e 85#else
19b27fa2 86 default_size = default_buffer_size;
cb63cf9e
JB
87#endif
88 if (read_size == -1)
89 read_size = default_size;
90 if (write_size == -1)
91 write_size = default_size;
92 }
0f2d19dd 93
f5f2dcff 94 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 95 {
4c9419ac 96 pt->read_buf = scm_gc_malloc (read_size, "port buffer");
cb63cf9e
JB
97 pt->read_pos = pt->read_end = pt->read_buf;
98 pt->read_buf_size = read_size;
99 }
100 else
101 {
840ae05d 102 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
103 pt->read_buf_size = 1;
104 }
1717856b 105
f5f2dcff 106 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 107 {
4c9419ac 108 pt->write_buf = scm_gc_malloc (write_size, "port buffer");
cb63cf9e
JB
109 pt->write_pos = pt->write_buf;
110 pt->write_buf_size = write_size;
111 }
112 else
113 {
114 pt->write_buf = pt->write_pos = &pt->shortbuf;
115 pt->write_buf_size = 1;
116 }
117
118 pt->write_end = pt->write_buf + pt->write_buf_size;
119 if (read_size > 0 || write_size > 0)
54778cd3 120 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
cb63cf9e 121 else
54778cd3 122 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
7a6f1ffa 123}
c6c79933 124#undef FUNC_NAME
7a6f1ffa 125
a1ec6916 126SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 127 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
128 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
129 "@table @code\n"
130 "@item _IONBF\n"
131 "non-buffered\n"
132 "@item _IOLBF\n"
133 "line buffered\n"
134 "@item _IOFBF\n"
135 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
136 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 137 "@end table")
1bbd0b84 138#define FUNC_NAME s_scm_setvbuf
7a6f1ffa 139{
1be6b49c 140 int cmode;
c014a02e 141 long csize;
92c2555f 142 scm_t_port *pt;
7a6f1ffa 143
78446828
MV
144 port = SCM_COERCE_OUTPORT (port);
145
3b3b36dd 146 SCM_VALIDATE_OPFPORT (1,port);
a55c2b68 147 cmode = scm_to_int (mode);
d3639214 148 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 149 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
150
151 if (cmode == _IOLBF)
152 {
54778cd3 153 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
154 cmode = _IOFBF;
155 }
156 else
157 {
54778cd3 158 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) ^ SCM_BUFLINE);
d3639214
GH
159 }
160
7a6f1ffa 161 if (SCM_UNBNDP (size))
cb63cf9e
JB
162 {
163 if (cmode == _IOFBF)
164 csize = -1;
165 else
166 csize = 0;
167 }
7a6f1ffa
GH
168 else
169 {
a55c2b68 170 csize = scm_to_int (size);
cb63cf9e 171 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 172 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 173 }
d3639214 174
cb63cf9e 175 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 176
4c9419ac
MV
177 /* silently discards buffered and put-back chars. */
178 if (pt->read_buf == pt->putback_buf)
179 {
180 pt->read_buf = pt->saved_read_buf;
181 pt->read_pos = pt->saved_read_pos;
182 pt->read_end = pt->saved_read_end;
183 pt->read_buf_size = pt->saved_read_buf_size;
184 }
cb63cf9e 185 if (pt->read_buf != &pt->shortbuf)
4c9419ac 186 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 187 if (pt->write_buf != &pt->shortbuf)
4c9419ac 188 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
7a6f1ffa 189
cb63cf9e
JB
190 scm_fport_buffer_add (port, csize, csize);
191 return SCM_UNSPECIFIED;
0f2d19dd 192}
1bbd0b84 193#undef FUNC_NAME
0f2d19dd 194
eadd48de 195/* Move ports with the specified file descriptor to new descriptors,
387d418c 196 * resetting the revealed count to 0.
0f2d19dd 197 */
1717856b 198
eadd48de 199void
6e8d25a6 200scm_evict_ports (int fd)
0f2d19dd 201{
c014a02e 202 long i;
0f2d19dd 203
b9ad392e
MD
204 scm_mutex_lock (&scm_i_port_table_mutex);
205
67329a9e 206 for (i = 0; i < scm_i_port_table_size; i++)
eadd48de 207 {
67329a9e 208 SCM port = scm_i_port_table[i]->port;
cb63cf9e
JB
209
210 if (SCM_FPORTP (port))
eadd48de 211 {
92c2555f 212 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e
JB
213
214 if (fp->fdes == fd)
215 {
216 fp->fdes = dup (fd);
217 if (fp->fdes == -1)
218 scm_syserror ("scm_evict_ports");
e11e83f3 219 scm_set_port_revealed_x (port, scm_from_int (0));
cb63cf9e 220 }
eadd48de
GH
221 }
222 }
b9ad392e
MD
223
224 scm_mutex_unlock (&scm_i_port_table_mutex);
eadd48de 225}
0f2d19dd 226
efa40607
DH
227
228SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
229 (SCM obj),
2069af38 230 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
231#define FUNC_NAME s_scm_file_port_p
232{
7888309b 233 return scm_from_bool (SCM_FPORTP (obj));
efa40607
DH
234}
235#undef FUNC_NAME
236
237
0f2d19dd
JB
238/* scm_open_file
239 * Return a new port open on a given file.
240 *
241 * The mode string must match the pattern: [rwa+]** which
242 * is interpreted in the usual unix way.
243 *
244 * Return the new port.
245 */
3b3b36dd 246SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
1e6808ea
MG
247 (SCM filename, SCM mode),
248 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 249 "representing that file. The attributes of the port are\n"
1e6808ea
MG
250 "determined by the @var{mode} string. The way in which this is\n"
251 "interpreted is similar to C stdio. The first character must be\n"
252 "one of the following:\n"
fc0d72d4
MD
253 "@table @samp\n"
254 "@item r\n"
255 "Open an existing file for input.\n"
256 "@item w\n"
257 "Open a file for output, creating it if it doesn't already exist\n"
258 "or removing its contents if it does.\n"
259 "@item a\n"
1e6808ea
MG
260 "Open a file for output, creating it if it doesn't already\n"
261 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
262 "The \"append mode\" can be turned off while the port is in use\n"
263 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
264 "@end table\n"
265 "The following additional characters can be appended:\n"
fc0d72d4
MD
266 "@table @samp\n"
267 "@item +\n"
268 "Open the port for both input and output. E.g., @code{r+}: open\n"
269 "an existing file for both input and output.\n"
270 "@item 0\n"
1e6808ea
MG
271 "Create an \"unbuffered\" port. In this case input and output\n"
272 "operations are passed directly to the underlying port\n"
273 "implementation without additional buffering. This is likely to\n"
274 "slow down I/O operations. The buffering mode can be changed\n"
275 "while a port is in use @pxref{Ports and File Descriptors,\n"
276 "setvbuf}\n"
fc0d72d4
MD
277 "@item l\n"
278 "Add line-buffering to the port. The port output buffer will be\n"
279 "automatically flushed whenever a newline character is written.\n"
1e6808ea
MG
280 "@end table\n"
281 "In theory we could create read/write ports which were buffered\n"
282 "in one direction only. However this isn't included in the\n"
283 "current interfaces. If a file cannot be opened with the access\n"
284 "requested, @code{open-file} throws an exception.")
1bbd0b84 285#define FUNC_NAME s_scm_open_file
0f2d19dd 286{
19639113 287 SCM port;
cb63cf9e
JB
288 int fdes;
289 int flags = 0;
19639113 290 char *file;
1e6808ea 291 char *md;
cb63cf9e 292 char *ptr;
19639113 293
7f9994d9 294 scm_frame_begin (0);
19639113 295
7f9994d9
MV
296 file = scm_to_locale_string (filename);
297 scm_frame_free (file);
298
299 md = scm_to_locale_string (mode);
300 scm_frame_free (md);
19639113 301
1e6808ea 302 switch (*md)
0f2d19dd 303 {
cb63cf9e
JB
304 case 'r':
305 flags |= O_RDONLY;
306 break;
307 case 'w':
308 flags |= O_WRONLY | O_CREAT | O_TRUNC;
309 break;
310 case 'a':
311 flags |= O_WRONLY | O_CREAT | O_APPEND;
312 break;
313 default:
1e6808ea 314 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 315 }
1e6808ea 316 ptr = md + 1;
cb63cf9e 317 while (*ptr != '\0')
e145dd02 318 {
cb63cf9e
JB
319 switch (*ptr)
320 {
321 case '+':
322 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
323 break;
9f561420
GH
324 case 'b':
325#if defined (O_BINARY)
326 flags |= O_BINARY;
327#endif
328 break;
cb63cf9e 329 case '0': /* unbuffered: handled later. */
d3639214 330 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
331 break;
332 default:
1e6808ea 333 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
334 }
335 ptr++;
e145dd02 336 }
cb63cf9e
JB
337 SCM_SYSCALL (fdes = open (file, flags, 0666));
338 if (fdes == -1)
e145dd02 339 {
cb63cf9e
JB
340 int en = errno;
341
5d2d2ffc 342 SCM_SYSERROR_MSG ("~A: ~S",
fd08c236 343 scm_cons (scm_strerror (scm_from_int (en)),
5d2d2ffc 344 scm_cons (filename, SCM_EOL)), en);
0f2d19dd 345 }
d617ee18 346 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode), filename);
7f9994d9
MV
347
348 scm_frame_end ();
349
0f2d19dd
JB
350 return port;
351}
1bbd0b84 352#undef FUNC_NAME
0f2d19dd 353
e145dd02 354\f
82893676
MG
355#ifdef __MINGW32__
356/*
357 * Try getting the appropiate file flags for a given file descriptor
358 * under Windows. This incorporates some fancy operations because Windows
359 * differentiates between file, pipe and socket descriptors.
360 */
361#ifndef O_ACCMODE
362# define O_ACCMODE 0x0003
363#endif
364
365static int getflags (int fdes)
366{
367 int flags = 0;
368 struct stat buf;
369 int error, optlen = sizeof (int);
370
371 /* Is this a socket ? */
372 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
373 flags = O_RDWR;
374 /* Maybe a regular file ? */
375 else if (fstat (fdes, &buf) < 0)
376 flags = -1;
377 else
378 {
379 /* Or an anonymous pipe handle ? */
b8b17bfd 380 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
381 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
382 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 383 /* stdin ? */
b8b17bfd 384 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
385 flags = O_RDONLY;
386 /* stdout / stderr ? */
b8b17bfd
MV
387 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
388 isatty (fdes))
82893676
MG
389 flags = O_WRONLY;
390 else
391 flags = buf.st_mode;
392 }
393 return flags;
394}
395#endif /* __MINGW32__ */
396
cb63cf9e 397/* Building Guile ports from a file descriptor. */
e145dd02 398
cb63cf9e 399/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
400 MODE indicates whether FILE is open for reading or writing; it uses
401 the same notation as open-file's second argument.
19b27fa2
GH
402 NAME is a string to be used as the port's filename.
403*/
a089567e 404SCM
d617ee18 405scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 406#define FUNC_NAME "scm_fdes_to_port"
a089567e 407{
a089567e 408 SCM port;
92c2555f 409 scm_t_port *pt;
19b27fa2
GH
410 int flags;
411
412 /* test that fdes is valid. */
82893676
MG
413#ifdef __MINGW32__
414 flags = getflags (fdes);
415#else
19b27fa2 416 flags = fcntl (fdes, F_GETFL, 0);
82893676 417#endif
19b27fa2
GH
418 if (flags == -1)
419 SCM_SYSERROR;
420 flags &= O_ACCMODE;
421 if (flags != O_RDWR
422 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
423 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
424 {
425 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
426 }
a089567e 427
b9ad392e 428 scm_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
429
430 port = scm_new_port_table_entry (scm_tc16_fport);
431 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
432 pt = SCM_PTAB_ENTRY(port);
a089567e 433 {
92c2555f 434 scm_t_fport *fp
4c9419ac 435 = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), "file port");
c6c79933 436
cb63cf9e 437 fp->fdes = fdes;
0de97b83 438 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
439 SCM_SETSTREAM (port, fp);
440 if (mode_bits & SCM_BUF0)
441 scm_fport_buffer_add (port, 0, 0);
442 else
443 scm_fport_buffer_add (port, -1, -1);
a089567e 444 }
b24b5e13 445 SCM_SET_FILENAME (port, name);
b9ad392e 446 scm_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
447 return port;
448}
19b27fa2 449#undef FUNC_NAME
e145dd02 450
d617ee18
MV
451SCM
452scm_fdes_to_port (int fdes, char *mode, SCM name)
453{
454 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
455}
456
affc96b5 457/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 458static int
affc96b5 459fport_input_waiting (SCM port)
e145dd02 460{
cb63cf9e
JB
461 int fdes = SCM_FSTREAM (port)->fdes;
462
463#ifdef HAVE_SELECT
464 struct timeval timeout;
465 SELECT_TYPE read_set;
466 SELECT_TYPE write_set;
467 SELECT_TYPE except_set;
468
469 FD_ZERO (&read_set);
470 FD_ZERO (&write_set);
471 FD_ZERO (&except_set);
472
473 FD_SET (fdes, &read_set);
474
475 timeout.tv_sec = 0;
476 timeout.tv_usec = 0;
477
478 if (select (SELECT_SET_SIZE,
479 &read_set, &write_set, &except_set, &timeout)
480 < 0)
affc96b5
GH
481 scm_syserror ("fport_input_waiting");
482 return FD_ISSET (fdes, &read_set) ? 1 : 0;
cb63cf9e
JB
483#elif defined (FIONREAD)
484 int remir;
485 ioctl(fdes, FIONREAD, &remir);
486 return remir;
487#else
affc96b5 488 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
489 "Not fully implemented on this platform",
490 SCM_EOL);
491#endif
a089567e
JB
492}
493
cb63cf9e 494\f
0f2d19dd 495static int
e81d98ec 496fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 497{
b3ec3c64
MD
498 scm_puts ("#<", port);
499 scm_print_port_mode (exp, port);
500 if (SCM_OPFPORTP (exp))
0f2d19dd 501 {
b3ec3c64 502 int fdes;
b24b5e13 503 SCM name = SCM_FILENAME (exp);
7f9994d9 504 if (scm_is_string (name) || SCM_SYMBOLP (name))
b24b5e13
DH
505 scm_display (name, port);
506 else
507 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
508 scm_putc (' ', port);
509 fdes = (SCM_FSTREAM (exp))->fdes;
510
82893676 511#ifdef HAVE_TTYNAME
b3ec3c64 512 if (isatty (fdes))
eb372585 513 scm_display (scm_ttyname (exp), port);
b3ec3c64 514 else
82893676 515#endif /* HAVE_TTYNAME */
b3ec3c64 516 scm_intprint (fdes, 10, port);
0f2d19dd
JB
517 }
518 else
519 {
b3ec3c64
MD
520 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
521 scm_putc (' ', port);
63bcad19 522 scm_intprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 523 }
b3ec3c64
MD
524 scm_putc ('>', port);
525 return 1;
0f2d19dd
JB
526}
527
2e945bcc 528#ifndef __MINGW32__
cb63cf9e
JB
529/* thread-local block for input on fport's fdes. */
530static void
531fport_wait_for_input (SCM port)
3cb988bd 532{
cb63cf9e 533 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 534
affc96b5 535 if (!fport_input_waiting (port))
8122b543 536 {
cb63cf9e
JB
537 int n;
538 SELECT_TYPE readfds;
539 int flags = fcntl (fdes, F_GETFL);
540
541 if (flags == -1)
542 scm_syserror ("scm_fdes_wait_for_input");
543 if (!(flags & O_NONBLOCK))
544 do
545 {
546 FD_ZERO (&readfds);
547 FD_SET (fdes, &readfds);
548 n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
549 }
550 while (n == -1 && errno == EINTR);
8122b543 551 }
3cb988bd 552}
2e945bcc 553#endif /* !__MINGW32__ */
0f2d19dd 554
affc96b5 555static void fport_flush (SCM port);
0f2d19dd 556
c2da2648
GH
557/* fill a port's read-buffer with a single read. returns the first
558 char or EOF if end of file. */
0f2d19dd 559static int
affc96b5 560fport_fill_input (SCM port)
0f2d19dd 561{
c014a02e 562 long count;
92c2555f
MV
563 scm_t_port *pt = SCM_PTAB_ENTRY (port);
564 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 565
2e945bcc 566#ifndef __MINGW32__
cb63cf9e 567 fport_wait_for_input (port);
2e945bcc 568#endif /* !__MINGW32__ */
cb63cf9e
JB
569 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
570 if (count == -1)
affc96b5 571 scm_syserror ("fport_fill_input");
cb63cf9e
JB
572 if (count == 0)
573 return EOF;
574 else
575 {
5c070ca7 576 pt->read_pos = pt->read_buf;
cb63cf9e 577 pt->read_end = pt->read_buf + count;
5c070ca7 578 return *pt->read_buf;
cb63cf9e 579 }
0f2d19dd
JB
580}
581
cb63cf9e 582static off_t
affc96b5 583fport_seek (SCM port, off_t offset, int whence)
0f2d19dd 584{
92c2555f
MV
585 scm_t_port *pt = SCM_PTAB_ENTRY (port);
586 scm_t_fport *fp = SCM_FSTREAM (port);
7dcb364d
GH
587 off_t rv;
588 off_t result;
589
590 if (pt->rw_active == SCM_PORT_WRITE)
591 {
592 if (offset != 0 || whence != SEEK_CUR)
593 {
594 fport_flush (port);
595 result = rv = lseek (fp->fdes, offset, whence);
596 }
597 else
598 {
599 /* read current position without disturbing the buffer. */
600 rv = lseek (fp->fdes, offset, whence);
601 result = rv + (pt->write_pos - pt->write_buf);
602 }
603 }
604 else if (pt->rw_active == SCM_PORT_READ)
605 {
606 if (offset != 0 || whence != SEEK_CUR)
607 {
608 /* could expand to avoid a second seek. */
609 scm_end_input (port);
610 result = rv = lseek (fp->fdes, offset, whence);
611 }
612 else
613 {
614 /* read current position without disturbing the buffer
615 (particularly the unread-char buffer). */
616 rv = lseek (fp->fdes, offset, whence);
617 result = rv - (pt->read_end - pt->read_pos);
618
619 if (pt->read_buf == pt->putback_buf)
620 result -= pt->saved_read_end - pt->saved_read_pos;
621 }
622 }
623 else /* SCM_PORT_NEITHER */
624 {
625 result = rv = lseek (fp->fdes, offset, whence);
626 }
cb8dfa3f 627
7dcb364d 628 if (rv == -1)
affc96b5 629 scm_syserror ("fport_seek");
7dcb364d 630
cb8dfa3f 631 return result;
0f2d19dd
JB
632}
633
840ae05d 634static void
affc96b5 635fport_truncate (SCM port, off_t length)
840ae05d 636{
92c2555f 637 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
638
639 if (ftruncate (fp->fdes, length) == -1)
640 scm_syserror ("ftruncate");
641}
642
0c6d2191
GH
643/* helper for fport_write: try to write data, using multiple system
644 calls if required. */
645#define FUNC_NAME "write_all"
646static void write_all (SCM port, const void *data, size_t remaining)
647{
648 int fdes = SCM_FSTREAM (port)->fdes;
649
650 while (remaining > 0)
651 {
82893676 652 size_t done;
0c6d2191
GH
653
654 SCM_SYSCALL (done = write (fdes, data, remaining));
655
656 if (done == -1)
657 SCM_SYSERROR;
658 remaining -= done;
659 data = ((const char *) data) + done;
660 }
661}
662#undef FUNC_NAME
663
31703ab8 664static void
8aa011a1 665fport_write (SCM port, const void *data, size_t size)
31703ab8 666{
0c6d2191 667 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 668 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 669
0c6d2191
GH
670 if (pt->write_buf == &pt->shortbuf
671 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 672 {
0c6d2191
GH
673 /* "unbuffered" port, or
674 port with empty buffer and data won't fit in buffer. */
675 write_all (port, data, size);
676 return;
31703ab8 677 }
d3639214 678
0c6d2191
GH
679 {
680 off_t space = pt->write_end - pt->write_pos;
681
682 if (size <= space)
683 {
684 /* data fits in buffer. */
685 memcpy (pt->write_pos, data, size);
686 pt->write_pos += size;
687 if (pt->write_pos == pt->write_end)
688 {
affc96b5 689 fport_flush (port);
0c6d2191
GH
690 /* we can skip the line-buffering check if nothing's buffered. */
691 return;
692 }
693 }
694 else
695 {
696 memcpy (pt->write_pos, data, space);
697 pt->write_pos = pt->write_end;
698 fport_flush (port);
699 {
700 const void *ptr = ((const char *) data) + space;
701 size_t remaining = size - space;
702
703 if (size >= pt->write_buf_size)
704 {
705 write_all (port, ptr, remaining);
706 return;
707 }
708 else
709 {
710 memcpy (pt->write_pos, ptr, remaining);
711 pt->write_pos += remaining;
712 }
31703ab8 713 }
0c6d2191 714 }
31703ab8 715
0c6d2191
GH
716 /* handle line buffering. */
717 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
718 fport_flush (port);
719 }
31703ab8
GH
720}
721
722/* becomes 1 when process is exiting: normal exception handling won't
723 work by this time. */
04a98cff 724extern int scm_i_terminating;
0f2d19dd 725
cb63cf9e 726static void
affc96b5 727fport_flush (SCM port)
0f2d19dd 728{
92c2555f
MV
729 scm_t_port *pt = SCM_PTAB_ENTRY (port);
730 scm_t_fport *fp = SCM_FSTREAM (port);
6f760c1d 731 unsigned char *ptr = pt->write_buf;
c014a02e
ML
732 long init_size = pt->write_pos - pt->write_buf;
733 long remaining = init_size;
0f2d19dd 734
cb63cf9e
JB
735 while (remaining > 0)
736 {
c014a02e 737 long count;
cb63cf9e
JB
738
739 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
740 if (count < 0)
741 {
742 /* error. assume nothing was written this call, but
743 fix up the buffer for any previous successful writes. */
c014a02e 744 long done = init_size - remaining;
cb63cf9e
JB
745
746 if (done > 0)
747 {
748 int i;
749
750 for (i = 0; i < remaining; i++)
751 {
752 *(pt->write_buf + i) = *(pt->write_buf + done + i);
753 }
754 pt->write_pos = pt->write_buf + remaining;
755 }
04a98cff 756 if (scm_i_terminating)
cb63cf9e
JB
757 {
758 const char *msg = "Error: could not flush file-descriptor ";
759 char buf[11];
760
761 write (2, msg, strlen (msg));
762 sprintf (buf, "%d\n", fp->fdes);
763 write (2, buf, strlen (buf));
764
765 count = remaining;
766 }
6b72ac1d
GH
767 else if (scm_gc_running_p)
768 {
769 /* silently ignore the error. scm_error would abort if we
770 called it now. */
771 count = remaining;
772 }
773 else
774 scm_syserror ("fport_flush");
cb63cf9e
JB
775 }
776 ptr += count;
777 remaining -= count;
778 }
779 pt->write_pos = pt->write_buf;
61e452ba 780 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
781}
782
283a1a0e 783/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 784static void
affc96b5 785fport_end_input (SCM port, int offset)
840ae05d 786{
92c2555f
MV
787 scm_t_fport *fp = SCM_FSTREAM (port);
788 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
789
790 offset += pt->read_end - pt->read_pos;
840ae05d 791
840ae05d
JB
792 if (offset > 0)
793 {
794 pt->read_pos = pt->read_end;
795 /* will throw error if unread-char used at beginning of file
796 then attempting to write. seems correct. */
797 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 798 scm_syserror ("fport_end_input");
840ae05d 799 }
61e452ba 800 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
801}
802
6a2c4c81 803static int
affc96b5 804fport_close (SCM port)
6a2c4c81 805{
92c2555f
MV
806 scm_t_fport *fp = SCM_FSTREAM (port);
807 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 808 int rv;
840ae05d 809
affc96b5 810 fport_flush (port);
cb63cf9e
JB
811 SCM_SYSCALL (rv = close (fp->fdes));
812 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
813 {
814 if (scm_gc_running_p)
815 /* silently ignore the error. scm_error would abort if we
816 called it now. */
817 ;
818 else
819 scm_syserror ("fport_close");
820 }
6c951427
GH
821 if (pt->read_buf == pt->putback_buf)
822 pt->read_buf = pt->saved_read_buf;
cb63cf9e 823 if (pt->read_buf != &pt->shortbuf)
4c9419ac 824 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 825 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
826 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
827 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 828 return rv;
6a2c4c81
JB
829}
830
1be6b49c 831static size_t
affc96b5 832fport_free (SCM port)
b3ec3c64 833{
affc96b5 834 fport_close (port);
b3ec3c64
MD
835 return 0;
836}
837
92c2555f 838static scm_t_bits
b3ec3c64
MD
839scm_make_fptob ()
840{
92c2555f 841 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 842
affc96b5 843 scm_set_port_free (tc, fport_free);
e841c3e0 844 scm_set_port_print (tc, fport_print);
affc96b5
GH
845 scm_set_port_flush (tc, fport_flush);
846 scm_set_port_end_input (tc, fport_end_input);
847 scm_set_port_close (tc, fport_close);
848 scm_set_port_seek (tc, fport_seek);
849 scm_set_port_truncate (tc, fport_truncate);
850 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
851
852 return tc;
b3ec3c64 853}
0f2d19dd 854
0f2d19dd
JB
855void
856scm_init_fports ()
0f2d19dd 857{
a98bddfd
DH
858 scm_tc16_fport = scm_make_fptob ();
859
e11e83f3
MV
860 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
861 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
862 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 863
a98bddfd 864#include "libguile/fports.x"
0f2d19dd 865}
89e00824
ML
866
867/*
868 Local Variables:
869 c-file-style: "gnu"
870 End:
871*/