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