merge from 1.8 branch
[bpt/guile.git] / libguile / fports.c
CommitLineData
2b829bbb 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2006 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
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 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 {
2b829bbb 158 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~(scm_t_bits)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
9de87eea 204 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
b9ad392e 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 223
9de87eea 224 scm_i_pthread_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 266 "@table @samp\n"
fc9c5d06
HWN
267 "@item b\n"
268 "Open the underlying file in binary mode, if supported by the operating system. "
fc0d72d4
MD
269 "@item +\n"
270 "Open the port for both input and output. E.g., @code{r+}: open\n"
271 "an existing file for both input and output.\n"
272 "@item 0\n"
1e6808ea
MG
273 "Create an \"unbuffered\" port. In this case input and output\n"
274 "operations are passed directly to the underlying port\n"
275 "implementation without additional buffering. This is likely to\n"
276 "slow down I/O operations. The buffering mode can be changed\n"
277 "while a port is in use @pxref{Ports and File Descriptors,\n"
278 "setvbuf}\n"
fc0d72d4
MD
279 "@item l\n"
280 "Add line-buffering to the port. The port output buffer will be\n"
281 "automatically flushed whenever a newline character is written.\n"
1e6808ea
MG
282 "@end table\n"
283 "In theory we could create read/write ports which were buffered\n"
284 "in one direction only. However this isn't included in the\n"
285 "current interfaces. If a file cannot be opened with the access\n"
286 "requested, @code{open-file} throws an exception.")
1bbd0b84 287#define FUNC_NAME s_scm_open_file
0f2d19dd 288{
19639113 289 SCM port;
cb63cf9e
JB
290 int fdes;
291 int flags = 0;
19639113 292 char *file;
1e6808ea 293 char *md;
cb63cf9e 294 char *ptr;
19639113 295
661ae7ab 296 scm_dynwind_begin (0);
19639113 297
7f9994d9 298 file = scm_to_locale_string (filename);
661ae7ab 299 scm_dynwind_free (file);
7f9994d9
MV
300
301 md = scm_to_locale_string (mode);
661ae7ab 302 scm_dynwind_free (md);
19639113 303
1e6808ea 304 switch (*md)
0f2d19dd 305 {
cb63cf9e
JB
306 case 'r':
307 flags |= O_RDONLY;
308 break;
309 case 'w':
310 flags |= O_WRONLY | O_CREAT | O_TRUNC;
311 break;
312 case 'a':
313 flags |= O_WRONLY | O_CREAT | O_APPEND;
314 break;
315 default:
1e6808ea 316 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 317 }
1e6808ea 318 ptr = md + 1;
cb63cf9e 319 while (*ptr != '\0')
e145dd02 320 {
cb63cf9e
JB
321 switch (*ptr)
322 {
323 case '+':
324 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
325 break;
9f561420
GH
326 case 'b':
327#if defined (O_BINARY)
328 flags |= O_BINARY;
329#endif
330 break;
cb63cf9e 331 case '0': /* unbuffered: handled later. */
d3639214 332 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
333 break;
334 default:
1e6808ea 335 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
336 }
337 ptr++;
e145dd02 338 }
cb63cf9e
JB
339 SCM_SYSCALL (fdes = open (file, flags, 0666));
340 if (fdes == -1)
e145dd02 341 {
cb63cf9e
JB
342 int en = errno;
343
5d2d2ffc 344 SCM_SYSERROR_MSG ("~A: ~S",
fd08c236 345 scm_cons (scm_strerror (scm_from_int (en)),
5d2d2ffc 346 scm_cons (filename, SCM_EOL)), en);
0f2d19dd 347 }
d617ee18 348 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode), filename);
7f9994d9 349
661ae7ab 350 scm_dynwind_end ();
7f9994d9 351
0f2d19dd
JB
352 return port;
353}
1bbd0b84 354#undef FUNC_NAME
0f2d19dd 355
e145dd02 356\f
82893676
MG
357#ifdef __MINGW32__
358/*
359 * Try getting the appropiate file flags for a given file descriptor
360 * under Windows. This incorporates some fancy operations because Windows
361 * differentiates between file, pipe and socket descriptors.
362 */
363#ifndef O_ACCMODE
364# define O_ACCMODE 0x0003
365#endif
366
367static int getflags (int fdes)
368{
369 int flags = 0;
370 struct stat buf;
371 int error, optlen = sizeof (int);
372
373 /* Is this a socket ? */
374 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
375 flags = O_RDWR;
376 /* Maybe a regular file ? */
377 else if (fstat (fdes, &buf) < 0)
378 flags = -1;
379 else
380 {
381 /* Or an anonymous pipe handle ? */
b8b17bfd 382 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
383 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
384 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 385 /* stdin ? */
b8b17bfd 386 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
387 flags = O_RDONLY;
388 /* stdout / stderr ? */
b8b17bfd
MV
389 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
390 isatty (fdes))
82893676
MG
391 flags = O_WRONLY;
392 else
393 flags = buf.st_mode;
394 }
395 return flags;
396}
397#endif /* __MINGW32__ */
398
cb63cf9e 399/* Building Guile ports from a file descriptor. */
e145dd02 400
cb63cf9e 401/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
402 MODE indicates whether FILE is open for reading or writing; it uses
403 the same notation as open-file's second argument.
19b27fa2
GH
404 NAME is a string to be used as the port's filename.
405*/
a089567e 406SCM
d617ee18 407scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 408#define FUNC_NAME "scm_fdes_to_port"
a089567e 409{
a089567e 410 SCM port;
92c2555f 411 scm_t_port *pt;
19b27fa2
GH
412 int flags;
413
414 /* test that fdes is valid. */
82893676
MG
415#ifdef __MINGW32__
416 flags = getflags (fdes);
417#else
19b27fa2 418 flags = fcntl (fdes, F_GETFL, 0);
82893676 419#endif
19b27fa2
GH
420 if (flags == -1)
421 SCM_SYSERROR;
422 flags &= O_ACCMODE;
423 if (flags != O_RDWR
424 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
425 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
426 {
427 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
428 }
a089567e 429
9de87eea 430 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
431
432 port = scm_new_port_table_entry (scm_tc16_fport);
433 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
434 pt = SCM_PTAB_ENTRY(port);
a089567e 435 {
92c2555f 436 scm_t_fport *fp
4c9419ac 437 = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), "file port");
c6c79933 438
cb63cf9e 439 fp->fdes = fdes;
0de97b83 440 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
441 SCM_SETSTREAM (port, fp);
442 if (mode_bits & SCM_BUF0)
443 scm_fport_buffer_add (port, 0, 0);
444 else
445 scm_fport_buffer_add (port, -1, -1);
a089567e 446 }
b24b5e13 447 SCM_SET_FILENAME (port, name);
9de87eea 448 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
449 return port;
450}
19b27fa2 451#undef FUNC_NAME
e145dd02 452
d617ee18
MV
453SCM
454scm_fdes_to_port (int fdes, char *mode, SCM name)
455{
456 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
457}
458
affc96b5 459/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 460static int
affc96b5 461fport_input_waiting (SCM port)
e145dd02 462{
cb63cf9e
JB
463 int fdes = SCM_FSTREAM (port)->fdes;
464
465#ifdef HAVE_SELECT
466 struct timeval timeout;
467 SELECT_TYPE read_set;
468 SELECT_TYPE write_set;
469 SELECT_TYPE except_set;
470
471 FD_ZERO (&read_set);
472 FD_ZERO (&write_set);
473 FD_ZERO (&except_set);
474
475 FD_SET (fdes, &read_set);
476
477 timeout.tv_sec = 0;
478 timeout.tv_usec = 0;
479
480 if (select (SELECT_SET_SIZE,
481 &read_set, &write_set, &except_set, &timeout)
482 < 0)
affc96b5
GH
483 scm_syserror ("fport_input_waiting");
484 return FD_ISSET (fdes, &read_set) ? 1 : 0;
cb63cf9e
JB
485#elif defined (FIONREAD)
486 int remir;
487 ioctl(fdes, FIONREAD, &remir);
488 return remir;
489#else
affc96b5 490 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
491 "Not fully implemented on this platform",
492 SCM_EOL);
493#endif
a089567e
JB
494}
495
cb63cf9e 496\f
0f2d19dd 497static int
e81d98ec 498fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 499{
b3ec3c64
MD
500 scm_puts ("#<", port);
501 scm_print_port_mode (exp, port);
502 if (SCM_OPFPORTP (exp))
0f2d19dd 503 {
b3ec3c64 504 int fdes;
b24b5e13 505 SCM name = SCM_FILENAME (exp);
cc95e00a 506 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
507 scm_display (name, port);
508 else
509 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
510 scm_putc (' ', port);
511 fdes = (SCM_FSTREAM (exp))->fdes;
512
82893676 513#ifdef HAVE_TTYNAME
b3ec3c64 514 if (isatty (fdes))
eb372585 515 scm_display (scm_ttyname (exp), port);
b3ec3c64 516 else
82893676 517#endif /* HAVE_TTYNAME */
b3ec3c64 518 scm_intprint (fdes, 10, port);
0f2d19dd
JB
519 }
520 else
521 {
b3ec3c64
MD
522 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
523 scm_putc (' ', port);
0345e278 524 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 525 }
b3ec3c64
MD
526 scm_putc ('>', port);
527 return 1;
0f2d19dd
JB
528}
529
2e945bcc 530#ifndef __MINGW32__
cb63cf9e
JB
531/* thread-local block for input on fport's fdes. */
532static void
533fport_wait_for_input (SCM port)
3cb988bd 534{
cb63cf9e 535 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 536
affc96b5 537 if (!fport_input_waiting (port))
8122b543 538 {
cb63cf9e
JB
539 int n;
540 SELECT_TYPE readfds;
541 int flags = fcntl (fdes, F_GETFL);
542
543 if (flags == -1)
544 scm_syserror ("scm_fdes_wait_for_input");
545 if (!(flags & O_NONBLOCK))
546 do
547 {
548 FD_ZERO (&readfds);
549 FD_SET (fdes, &readfds);
9de87eea 550 n = scm_std_select (fdes + 1, &readfds, NULL, NULL, NULL);
cb63cf9e
JB
551 }
552 while (n == -1 && errno == EINTR);
8122b543 553 }
3cb988bd 554}
2e945bcc 555#endif /* !__MINGW32__ */
0f2d19dd 556
affc96b5 557static void fport_flush (SCM port);
0f2d19dd 558
c2da2648
GH
559/* fill a port's read-buffer with a single read. returns the first
560 char or EOF if end of file. */
0f2d19dd 561static int
affc96b5 562fport_fill_input (SCM port)
0f2d19dd 563{
c014a02e 564 long count;
92c2555f
MV
565 scm_t_port *pt = SCM_PTAB_ENTRY (port);
566 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 567
2e945bcc 568#ifndef __MINGW32__
cb63cf9e 569 fport_wait_for_input (port);
2e945bcc 570#endif /* !__MINGW32__ */
cb63cf9e
JB
571 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
572 if (count == -1)
affc96b5 573 scm_syserror ("fport_fill_input");
cb63cf9e
JB
574 if (count == 0)
575 return EOF;
576 else
577 {
5c070ca7 578 pt->read_pos = pt->read_buf;
cb63cf9e 579 pt->read_end = pt->read_buf + count;
5c070ca7 580 return *pt->read_buf;
cb63cf9e 581 }
0f2d19dd
JB
582}
583
cb63cf9e 584static off_t
affc96b5 585fport_seek (SCM port, off_t offset, int whence)
0f2d19dd 586{
92c2555f
MV
587 scm_t_port *pt = SCM_PTAB_ENTRY (port);
588 scm_t_fport *fp = SCM_FSTREAM (port);
7dcb364d
GH
589 off_t rv;
590 off_t result;
591
592 if (pt->rw_active == SCM_PORT_WRITE)
593 {
594 if (offset != 0 || whence != SEEK_CUR)
595 {
596 fport_flush (port);
597 result = rv = lseek (fp->fdes, offset, whence);
598 }
599 else
600 {
601 /* read current position without disturbing the buffer. */
602 rv = lseek (fp->fdes, offset, whence);
603 result = rv + (pt->write_pos - pt->write_buf);
604 }
605 }
606 else if (pt->rw_active == SCM_PORT_READ)
607 {
608 if (offset != 0 || whence != SEEK_CUR)
609 {
610 /* could expand to avoid a second seek. */
611 scm_end_input (port);
612 result = rv = lseek (fp->fdes, offset, whence);
613 }
614 else
615 {
616 /* read current position without disturbing the buffer
617 (particularly the unread-char buffer). */
618 rv = lseek (fp->fdes, offset, whence);
619 result = rv - (pt->read_end - pt->read_pos);
620
621 if (pt->read_buf == pt->putback_buf)
622 result -= pt->saved_read_end - pt->saved_read_pos;
623 }
624 }
625 else /* SCM_PORT_NEITHER */
626 {
627 result = rv = lseek (fp->fdes, offset, whence);
628 }
cb8dfa3f 629
7dcb364d 630 if (rv == -1)
affc96b5 631 scm_syserror ("fport_seek");
7dcb364d 632
cb8dfa3f 633 return result;
0f2d19dd
JB
634}
635
840ae05d 636static void
affc96b5 637fport_truncate (SCM port, off_t length)
840ae05d 638{
92c2555f 639 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
640
641 if (ftruncate (fp->fdes, length) == -1)
642 scm_syserror ("ftruncate");
643}
644
0c6d2191
GH
645/* helper for fport_write: try to write data, using multiple system
646 calls if required. */
647#define FUNC_NAME "write_all"
648static void write_all (SCM port, const void *data, size_t remaining)
649{
650 int fdes = SCM_FSTREAM (port)->fdes;
651
652 while (remaining > 0)
653 {
82893676 654 size_t done;
0c6d2191
GH
655
656 SCM_SYSCALL (done = write (fdes, data, remaining));
657
658 if (done == -1)
659 SCM_SYSERROR;
660 remaining -= done;
661 data = ((const char *) data) + done;
662 }
663}
664#undef FUNC_NAME
665
31703ab8 666static void
8aa011a1 667fport_write (SCM port, const void *data, size_t size)
31703ab8 668{
0c6d2191 669 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 670 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 671
0c6d2191
GH
672 if (pt->write_buf == &pt->shortbuf
673 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 674 {
0c6d2191
GH
675 /* "unbuffered" port, or
676 port with empty buffer and data won't fit in buffer. */
677 write_all (port, data, size);
678 return;
31703ab8 679 }
d3639214 680
0c6d2191
GH
681 {
682 off_t space = pt->write_end - pt->write_pos;
683
684 if (size <= space)
685 {
686 /* data fits in buffer. */
687 memcpy (pt->write_pos, data, size);
688 pt->write_pos += size;
689 if (pt->write_pos == pt->write_end)
690 {
affc96b5 691 fport_flush (port);
0c6d2191
GH
692 /* we can skip the line-buffering check if nothing's buffered. */
693 return;
694 }
695 }
696 else
697 {
698 memcpy (pt->write_pos, data, space);
699 pt->write_pos = pt->write_end;
700 fport_flush (port);
701 {
702 const void *ptr = ((const char *) data) + space;
703 size_t remaining = size - space;
704
705 if (size >= pt->write_buf_size)
706 {
707 write_all (port, ptr, remaining);
708 return;
709 }
710 else
711 {
712 memcpy (pt->write_pos, ptr, remaining);
713 pt->write_pos += remaining;
714 }
31703ab8 715 }
0c6d2191 716 }
31703ab8 717
0c6d2191
GH
718 /* handle line buffering. */
719 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
720 fport_flush (port);
721 }
31703ab8
GH
722}
723
724/* becomes 1 when process is exiting: normal exception handling won't
725 work by this time. */
04a98cff 726extern int scm_i_terminating;
0f2d19dd 727
cb63cf9e 728static void
affc96b5 729fport_flush (SCM port)
0f2d19dd 730{
92c2555f
MV
731 scm_t_port *pt = SCM_PTAB_ENTRY (port);
732 scm_t_fport *fp = SCM_FSTREAM (port);
6f760c1d 733 unsigned char *ptr = pt->write_buf;
c014a02e
ML
734 long init_size = pt->write_pos - pt->write_buf;
735 long remaining = init_size;
0f2d19dd 736
cb63cf9e
JB
737 while (remaining > 0)
738 {
c014a02e 739 long count;
cb63cf9e
JB
740
741 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
742 if (count < 0)
743 {
744 /* error. assume nothing was written this call, but
745 fix up the buffer for any previous successful writes. */
c014a02e 746 long done = init_size - remaining;
cb63cf9e
JB
747
748 if (done > 0)
749 {
750 int i;
751
752 for (i = 0; i < remaining; i++)
753 {
754 *(pt->write_buf + i) = *(pt->write_buf + done + i);
755 }
756 pt->write_pos = pt->write_buf + remaining;
757 }
04a98cff 758 if (scm_i_terminating)
cb63cf9e
JB
759 {
760 const char *msg = "Error: could not flush file-descriptor ";
761 char buf[11];
762
763 write (2, msg, strlen (msg));
764 sprintf (buf, "%d\n", fp->fdes);
765 write (2, buf, strlen (buf));
766
767 count = remaining;
768 }
6b72ac1d
GH
769 else if (scm_gc_running_p)
770 {
771 /* silently ignore the error. scm_error would abort if we
772 called it now. */
773 count = remaining;
774 }
775 else
776 scm_syserror ("fport_flush");
cb63cf9e
JB
777 }
778 ptr += count;
779 remaining -= count;
780 }
781 pt->write_pos = pt->write_buf;
61e452ba 782 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
783}
784
283a1a0e 785/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 786static void
affc96b5 787fport_end_input (SCM port, int offset)
840ae05d 788{
92c2555f
MV
789 scm_t_fport *fp = SCM_FSTREAM (port);
790 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
791
792 offset += pt->read_end - pt->read_pos;
840ae05d 793
840ae05d
JB
794 if (offset > 0)
795 {
796 pt->read_pos = pt->read_end;
797 /* will throw error if unread-char used at beginning of file
798 then attempting to write. seems correct. */
799 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 800 scm_syserror ("fport_end_input");
840ae05d 801 }
61e452ba 802 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
803}
804
6a2c4c81 805static int
affc96b5 806fport_close (SCM port)
6a2c4c81 807{
92c2555f
MV
808 scm_t_fport *fp = SCM_FSTREAM (port);
809 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 810 int rv;
840ae05d 811
affc96b5 812 fport_flush (port);
cb63cf9e
JB
813 SCM_SYSCALL (rv = close (fp->fdes));
814 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
815 {
816 if (scm_gc_running_p)
817 /* silently ignore the error. scm_error would abort if we
818 called it now. */
819 ;
820 else
821 scm_syserror ("fport_close");
822 }
6c951427
GH
823 if (pt->read_buf == pt->putback_buf)
824 pt->read_buf = pt->saved_read_buf;
cb63cf9e 825 if (pt->read_buf != &pt->shortbuf)
4c9419ac 826 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 827 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
828 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
829 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 830 return rv;
6a2c4c81
JB
831}
832
1be6b49c 833static size_t
affc96b5 834fport_free (SCM port)
b3ec3c64 835{
affc96b5 836 fport_close (port);
b3ec3c64
MD
837 return 0;
838}
839
92c2555f 840static scm_t_bits
b3ec3c64
MD
841scm_make_fptob ()
842{
92c2555f 843 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 844
affc96b5 845 scm_set_port_free (tc, fport_free);
e841c3e0 846 scm_set_port_print (tc, fport_print);
affc96b5
GH
847 scm_set_port_flush (tc, fport_flush);
848 scm_set_port_end_input (tc, fport_end_input);
849 scm_set_port_close (tc, fport_close);
850 scm_set_port_seek (tc, fport_seek);
851 scm_set_port_truncate (tc, fport_truncate);
852 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
853
854 return tc;
b3ec3c64 855}
0f2d19dd 856
0f2d19dd
JB
857void
858scm_init_fports ()
0f2d19dd 859{
a98bddfd
DH
860 scm_tc16_fport = scm_make_fptob ();
861
e11e83f3
MV
862 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
863 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
864 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 865
a98bddfd 866#include "libguile/fports.x"
0f2d19dd 867}
89e00824
ML
868
869/*
870 Local Variables:
871 c-file-style: "gnu"
872 End:
873*/