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