popen.test: Don't auto-compile `popen-child.scm'.
[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
69cac238 269static SCM sys_file_port_name_canonicalization;
0157a341
AW
270SCM_SYMBOL (sym_relative, "relative");
271SCM_SYMBOL (sym_absolute, "absolute");
272
273static SCM
274fport_canonicalize_filename (SCM filename)
275{
69cac238
AW
276 SCM mode = scm_fluid_ref (sys_file_port_name_canonicalization);
277
0157a341
AW
278 if (!scm_is_string (filename))
279 {
280 return filename;
281 }
69cac238 282 else if (scm_is_eq (mode, sym_relative))
0157a341 283 {
22457d57
AW
284 SCM path, rel;
285
286 path = scm_variable_ref (scm_c_module_lookup (scm_the_root_module (),
287 "%load-path"));
288 rel = scm_i_relativize_path (filename, path);
289
290 return scm_is_true (rel) ? rel : filename;
0157a341 291 }
69cac238 292 else if (scm_is_eq (mode, sym_absolute))
0157a341
AW
293 {
294 char *str, *canon;
295
296 str = scm_to_locale_string (filename);
297 canon = canonicalize_file_name (str);
298 free (str);
299
300 return canon ? scm_take_locale_string (canon) : filename;
301 }
302 else
303 {
304 return filename;
305 }
306}
307
308
0f2d19dd
JB
309/* scm_open_file
310 * Return a new port open on a given file.
311 *
312 * The mode string must match the pattern: [rwa+]** which
313 * is interpreted in the usual unix way.
314 *
315 * Return the new port.
316 */
3b3b36dd 317SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
211683cc 318 (SCM filename, SCM mode),
1e6808ea 319 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 320 "representing that file. The attributes of the port are\n"
1e6808ea
MG
321 "determined by the @var{mode} string. The way in which this is\n"
322 "interpreted is similar to C stdio. The first character must be\n"
323 "one of the following:\n"
fc0d72d4
MD
324 "@table @samp\n"
325 "@item r\n"
326 "Open an existing file for input.\n"
327 "@item w\n"
328 "Open a file for output, creating it if it doesn't already exist\n"
329 "or removing its contents if it does.\n"
330 "@item a\n"
1e6808ea
MG
331 "Open a file for output, creating it if it doesn't already\n"
332 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
333 "The \"append mode\" can be turned off while the port is in use\n"
334 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
335 "@end table\n"
336 "The following additional characters can be appended:\n"
fc0d72d4 337 "@table @samp\n"
fc9c5d06 338 "@item b\n"
211683cc
MG
339 "Open the underlying file in binary mode, if supported by the system.\n"
340 "Also, open the file using the binary-compatible character encoding\n"
341 "\"ISO-8859-1\", ignoring the port's encoding and the coding declaration\n"
342 "at the top of the input file, if any.\n"
fc0d72d4
MD
343 "@item +\n"
344 "Open the port for both input and output. E.g., @code{r+}: open\n"
345 "an existing file for both input and output.\n"
346 "@item 0\n"
1e6808ea
MG
347 "Create an \"unbuffered\" port. In this case input and output\n"
348 "operations are passed directly to the underlying port\n"
349 "implementation without additional buffering. This is likely to\n"
350 "slow down I/O operations. The buffering mode can be changed\n"
351 "while a port is in use @pxref{Ports and File Descriptors,\n"
352 "setvbuf}\n"
fc0d72d4
MD
353 "@item l\n"
354 "Add line-buffering to the port. The port output buffer will be\n"
355 "automatically flushed whenever a newline character is written.\n"
1e6808ea 356 "@end table\n"
211683cc
MG
357 "When the file is opened, this procedure will scan for a coding\n"
358 "declaration@pxref{Character Encoding of Source Files}. If present\n"
359 "will use that encoding for interpreting the file. Otherwise, the\n"
360 "port's encoding will be used.\n"
361 "\n"
1e6808ea
MG
362 "In theory we could create read/write ports which were buffered\n"
363 "in one direction only. However this isn't included in the\n"
364 "current interfaces. If a file cannot be opened with the access\n"
365 "requested, @code{open-file} throws an exception.")
1bbd0b84 366#define FUNC_NAME s_scm_open_file
0f2d19dd 367{
19639113 368 SCM port;
211683cc 369 int fdes, flags = 0, use_encoding = 1;
64e3a89c
LC
370 unsigned int retries;
371 char *file, *md, *ptr;
19639113 372
661ae7ab 373 scm_dynwind_begin (0);
19639113 374
7f9994d9 375 file = scm_to_locale_string (filename);
661ae7ab 376 scm_dynwind_free (file);
7f9994d9
MV
377
378 md = scm_to_locale_string (mode);
661ae7ab 379 scm_dynwind_free (md);
19639113 380
1e6808ea 381 switch (*md)
0f2d19dd 382 {
cb63cf9e
JB
383 case 'r':
384 flags |= O_RDONLY;
385 break;
386 case 'w':
387 flags |= O_WRONLY | O_CREAT | O_TRUNC;
388 break;
389 case 'a':
390 flags |= O_WRONLY | O_CREAT | O_APPEND;
391 break;
392 default:
1e6808ea 393 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 394 }
1e6808ea 395 ptr = md + 1;
cb63cf9e 396 while (*ptr != '\0')
e145dd02 397 {
cb63cf9e
JB
398 switch (*ptr)
399 {
400 case '+':
401 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
402 break;
9f561420 403 case 'b':
211683cc 404 use_encoding = 0;
9f561420
GH
405#if defined (O_BINARY)
406 flags |= O_BINARY;
407#endif
408 break;
cb63cf9e 409 case '0': /* unbuffered: handled later. */
d3639214 410 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
411 break;
412 default:
1e6808ea 413 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
414 }
415 ptr++;
e145dd02 416 }
cb63cf9e 417
64e3a89c
LC
418 for (retries = 0, fdes = -1;
419 fdes < 0 && retries < 2;
420 retries++)
421 {
422 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
423 if (fdes == -1)
424 {
425 int en = errno;
426
427 if (en == EMFILE && retries == 0)
428 /* Run the GC in case it collects open file ports that are no
429 longer referenced. */
430 scm_i_gc (FUNC_NAME);
431 else
432 SCM_SYSERROR_MSG ("~A: ~S",
433 scm_cons (scm_strerror (scm_from_int (en)),
434 scm_cons (filename, SCM_EOL)), en);
435 }
0f2d19dd 436 }
64e3a89c 437
211683cc
MG
438 /* Create a port from this file descriptor. The port's encoding is initially
439 %default-port-encoding. */
0157a341
AW
440 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
441 fport_canonicalize_filename (filename));
7f9994d9 442
211683cc
MG
443 if (use_encoding)
444 {
445 /* If this file has a coding declaration, use that as the port
446 encoding. */
447 if (SCM_INPUT_PORT_P (port))
448 {
449 char *enc = scm_i_scan_for_encoding (port);
450 if (enc != NULL)
451 scm_i_set_port_encoding_x (port, enc);
452 }
453 }
454 else
455 /* If this is a binary file, use the binary-friendly ISO-8859-1
456 encoding. */
457 scm_i_set_port_encoding_x (port, NULL);
458
661ae7ab 459 scm_dynwind_end ();
7f9994d9 460
0f2d19dd
JB
461 return port;
462}
1bbd0b84 463#undef FUNC_NAME
0f2d19dd 464
e145dd02 465\f
82893676
MG
466#ifdef __MINGW32__
467/*
468 * Try getting the appropiate file flags for a given file descriptor
469 * under Windows. This incorporates some fancy operations because Windows
470 * differentiates between file, pipe and socket descriptors.
471 */
472#ifndef O_ACCMODE
473# define O_ACCMODE 0x0003
474#endif
475
476static int getflags (int fdes)
477{
478 int flags = 0;
479 struct stat buf;
480 int error, optlen = sizeof (int);
481
482 /* Is this a socket ? */
483 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
484 flags = O_RDWR;
485 /* Maybe a regular file ? */
486 else if (fstat (fdes, &buf) < 0)
487 flags = -1;
488 else
489 {
490 /* Or an anonymous pipe handle ? */
b8b17bfd 491 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
492 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
493 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 494 /* stdin ? */
b8b17bfd 495 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
496 flags = O_RDONLY;
497 /* stdout / stderr ? */
b8b17bfd
MV
498 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
499 isatty (fdes))
82893676
MG
500 flags = O_WRONLY;
501 else
502 flags = buf.st_mode;
503 }
504 return flags;
505}
506#endif /* __MINGW32__ */
507
cb63cf9e 508/* Building Guile ports from a file descriptor. */
e145dd02 509
cb63cf9e 510/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
511 MODE indicates whether FILE is open for reading or writing; it uses
512 the same notation as open-file's second argument.
19b27fa2
GH
513 NAME is a string to be used as the port's filename.
514*/
a089567e 515SCM
d617ee18 516scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 517#define FUNC_NAME "scm_fdes_to_port"
a089567e 518{
a089567e 519 SCM port;
92c2555f 520 scm_t_port *pt;
19b27fa2
GH
521 int flags;
522
523 /* test that fdes is valid. */
82893676
MG
524#ifdef __MINGW32__
525 flags = getflags (fdes);
526#else
19b27fa2 527 flags = fcntl (fdes, F_GETFL, 0);
82893676 528#endif
19b27fa2
GH
529 if (flags == -1)
530 SCM_SYSERROR;
531 flags &= O_ACCMODE;
532 if (flags != O_RDWR
533 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
534 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
535 {
536 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
537 }
a089567e 538
9de87eea 539 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
540
541 port = scm_new_port_table_entry (scm_tc16_fport);
542 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
543 pt = SCM_PTAB_ENTRY(port);
a089567e 544 {
92c2555f 545 scm_t_fport *fp
92d8fd32
LC
546 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
547 "file port");
c6c79933 548
cb63cf9e 549 fp->fdes = fdes;
0de97b83 550 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
551 SCM_SETSTREAM (port, fp);
552 if (mode_bits & SCM_BUF0)
553 scm_fport_buffer_add (port, 0, 0);
554 else
555 scm_fport_buffer_add (port, -1, -1);
a089567e 556 }
b24b5e13 557 SCM_SET_FILENAME (port, name);
9de87eea 558 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
559 return port;
560}
19b27fa2 561#undef FUNC_NAME
e145dd02 562
d617ee18
MV
563SCM
564scm_fdes_to_port (int fdes, char *mode, SCM name)
565{
566 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
567}
568
affc96b5 569/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 570static int
affc96b5 571fport_input_waiting (SCM port)
e145dd02 572{
cb63cf9e 573#ifdef HAVE_SELECT
23f2b9a3 574 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
575 struct timeval timeout;
576 SELECT_TYPE read_set;
577 SELECT_TYPE write_set;
578 SELECT_TYPE except_set;
579
580 FD_ZERO (&read_set);
581 FD_ZERO (&write_set);
582 FD_ZERO (&except_set);
583
584 FD_SET (fdes, &read_set);
585
586 timeout.tv_sec = 0;
587 timeout.tv_usec = 0;
588
589 if (select (SELECT_SET_SIZE,
590 &read_set, &write_set, &except_set, &timeout)
591 < 0)
affc96b5
GH
592 scm_syserror ("fport_input_waiting");
593 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
594
595#elif HAVE_IOCTL && defined (FIONREAD)
596 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
597 (for use with winsock ioctlsocket()) but not ioctl(). */
598 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
599 int remir;
600 ioctl(fdes, FIONREAD, &remir);
601 return remir;
23f2b9a3 602
cb63cf9e 603#else
affc96b5 604 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
605 "Not fully implemented on this platform",
606 SCM_EOL);
607#endif
a089567e
JB
608}
609
cb63cf9e 610\f
0f2d19dd 611static int
e81d98ec 612fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 613{
b3ec3c64
MD
614 scm_puts ("#<", port);
615 scm_print_port_mode (exp, port);
616 if (SCM_OPFPORTP (exp))
0f2d19dd 617 {
b3ec3c64 618 int fdes;
b24b5e13 619 SCM name = SCM_FILENAME (exp);
cc95e00a 620 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
621 scm_display (name, port);
622 else
623 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
624 scm_putc (' ', port);
625 fdes = (SCM_FSTREAM (exp))->fdes;
626
82893676 627#ifdef HAVE_TTYNAME
b3ec3c64 628 if (isatty (fdes))
eb372585 629 scm_display (scm_ttyname (exp), port);
b3ec3c64 630 else
82893676 631#endif /* HAVE_TTYNAME */
b3ec3c64 632 scm_intprint (fdes, 10, port);
0f2d19dd
JB
633 }
634 else
635 {
b3ec3c64
MD
636 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
637 scm_putc (' ', port);
0345e278 638 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 639 }
b3ec3c64
MD
640 scm_putc ('>', port);
641 return 1;
0f2d19dd
JB
642}
643
2e945bcc 644#ifndef __MINGW32__
cb63cf9e
JB
645/* thread-local block for input on fport's fdes. */
646static void
647fport_wait_for_input (SCM port)
3cb988bd 648{
cb63cf9e 649 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 650
affc96b5 651 if (!fport_input_waiting (port))
8122b543 652 {
cb63cf9e
JB
653 int n;
654 SELECT_TYPE readfds;
655 int flags = fcntl (fdes, F_GETFL);
656
657 if (flags == -1)
658 scm_syserror ("scm_fdes_wait_for_input");
659 if (!(flags & O_NONBLOCK))
660 do
661 {
662 FD_ZERO (&readfds);
663 FD_SET (fdes, &readfds);
9de87eea 664 n = scm_std_select (fdes + 1, &readfds, NULL, NULL, NULL);
cb63cf9e
JB
665 }
666 while (n == -1 && errno == EINTR);
8122b543 667 }
3cb988bd 668}
2e945bcc 669#endif /* !__MINGW32__ */
0f2d19dd 670
affc96b5 671static void fport_flush (SCM port);
0f2d19dd 672
c2da2648
GH
673/* fill a port's read-buffer with a single read. returns the first
674 char or EOF if end of file. */
889975e5 675static scm_t_wchar
affc96b5 676fport_fill_input (SCM port)
0f2d19dd 677{
c014a02e 678 long count;
92c2555f
MV
679 scm_t_port *pt = SCM_PTAB_ENTRY (port);
680 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 681
2e945bcc 682#ifndef __MINGW32__
cb63cf9e 683 fport_wait_for_input (port);
2e945bcc 684#endif /* !__MINGW32__ */
cb63cf9e
JB
685 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
686 if (count == -1)
affc96b5 687 scm_syserror ("fport_fill_input");
cb63cf9e 688 if (count == 0)
889975e5 689 return (scm_t_wchar) EOF;
cb63cf9e
JB
690 else
691 {
5c070ca7 692 pt->read_pos = pt->read_buf;
cb63cf9e 693 pt->read_end = pt->read_buf + count;
5c070ca7 694 return *pt->read_buf;
cb63cf9e 695 }
0f2d19dd
JB
696}
697
0a94eb00
LC
698static scm_t_off
699fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 700{
92c2555f
MV
701 scm_t_port *pt = SCM_PTAB_ENTRY (port);
702 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
703 off_t_or_off64_t rv;
704 off_t_or_off64_t result;
7dcb364d
GH
705
706 if (pt->rw_active == SCM_PORT_WRITE)
707 {
708 if (offset != 0 || whence != SEEK_CUR)
709 {
710 fport_flush (port);
8ab3d8a0 711 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
712 }
713 else
714 {
715 /* read current position without disturbing the buffer. */
8ab3d8a0 716 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
717 result = rv + (pt->write_pos - pt->write_buf);
718 }
719 }
720 else if (pt->rw_active == SCM_PORT_READ)
721 {
722 if (offset != 0 || whence != SEEK_CUR)
723 {
724 /* could expand to avoid a second seek. */
725 scm_end_input (port);
8ab3d8a0 726 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
727 }
728 else
729 {
730 /* read current position without disturbing the buffer
731 (particularly the unread-char buffer). */
8ab3d8a0 732 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
733 result = rv - (pt->read_end - pt->read_pos);
734
735 if (pt->read_buf == pt->putback_buf)
736 result -= pt->saved_read_end - pt->saved_read_pos;
737 }
738 }
739 else /* SCM_PORT_NEITHER */
740 {
8ab3d8a0 741 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 742 }
cb8dfa3f 743
7dcb364d 744 if (rv == -1)
affc96b5 745 scm_syserror ("fport_seek");
7dcb364d 746
cb8dfa3f 747 return result;
0f2d19dd
JB
748}
749
840ae05d 750static void
f1ce9199 751fport_truncate (SCM port, scm_t_off length)
840ae05d 752{
92c2555f 753 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
754
755 if (ftruncate (fp->fdes, length) == -1)
756 scm_syserror ("ftruncate");
757}
758
31703ab8 759static void
8aa011a1 760fport_write (SCM port, const void *data, size_t size)
daa4a3f1 761#define FUNC_NAME "fport_write"
31703ab8 762{
0c6d2191 763 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 764 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 765
0c6d2191
GH
766 if (pt->write_buf == &pt->shortbuf
767 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 768 {
daa4a3f1
LC
769 /* Unbuffered port, or port with empty buffer and data won't fit in
770 buffer. */
771 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
772 SCM_SYSERROR;
773
0c6d2191 774 return;
31703ab8 775 }
d3639214 776
0c6d2191 777 {
f1ce9199 778 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
779
780 if (size <= space)
781 {
782 /* data fits in buffer. */
783 memcpy (pt->write_pos, data, size);
784 pt->write_pos += size;
785 if (pt->write_pos == pt->write_end)
786 {
affc96b5 787 fport_flush (port);
0c6d2191
GH
788 /* we can skip the line-buffering check if nothing's buffered. */
789 return;
790 }
791 }
792 else
793 {
794 memcpy (pt->write_pos, data, space);
795 pt->write_pos = pt->write_end;
796 fport_flush (port);
797 {
798 const void *ptr = ((const char *) data) + space;
799 size_t remaining = size - space;
800
801 if (size >= pt->write_buf_size)
802 {
daa4a3f1
LC
803 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
804 < remaining)
805 SCM_SYSERROR;
0c6d2191
GH
806 return;
807 }
808 else
809 {
810 memcpy (pt->write_pos, ptr, remaining);
811 pt->write_pos += remaining;
812 }
31703ab8 813 }
0c6d2191 814 }
31703ab8 815
0c6d2191
GH
816 /* handle line buffering. */
817 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
818 fport_flush (port);
819 }
31703ab8 820}
daa4a3f1 821#undef FUNC_NAME
31703ab8 822
cb63cf9e 823static void
affc96b5 824fport_flush (SCM port)
0f2d19dd 825{
92c2555f
MV
826 scm_t_port *pt = SCM_PTAB_ENTRY (port);
827 scm_t_fport *fp = SCM_FSTREAM (port);
6f760c1d 828 unsigned char *ptr = pt->write_buf;
c014a02e
ML
829 long init_size = pt->write_pos - pt->write_buf;
830 long remaining = init_size;
0f2d19dd 831
cb63cf9e
JB
832 while (remaining > 0)
833 {
c014a02e 834 long count;
cb63cf9e
JB
835
836 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
837 if (count < 0)
838 {
839 /* error. assume nothing was written this call, but
840 fix up the buffer for any previous successful writes. */
c014a02e 841 long done = init_size - remaining;
cb63cf9e
JB
842
843 if (done > 0)
844 {
845 int i;
846
847 for (i = 0; i < remaining; i++)
848 {
849 *(pt->write_buf + i) = *(pt->write_buf + done + i);
850 }
851 pt->write_pos = pt->write_buf + remaining;
852 }
65c7a8bd 853 if (scm_gc_running_p)
6b72ac1d
GH
854 {
855 /* silently ignore the error. scm_error would abort if we
856 called it now. */
857 count = remaining;
858 }
859 else
860 scm_syserror ("fport_flush");
cb63cf9e
JB
861 }
862 ptr += count;
863 remaining -= count;
864 }
865 pt->write_pos = pt->write_buf;
61e452ba 866 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
867}
868
283a1a0e 869/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 870static void
affc96b5 871fport_end_input (SCM port, int offset)
840ae05d 872{
92c2555f
MV
873 scm_t_fport *fp = SCM_FSTREAM (port);
874 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
875
876 offset += pt->read_end - pt->read_pos;
840ae05d 877
840ae05d
JB
878 if (offset > 0)
879 {
880 pt->read_pos = pt->read_end;
881 /* will throw error if unread-char used at beginning of file
882 then attempting to write. seems correct. */
883 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 884 scm_syserror ("fport_end_input");
840ae05d 885 }
61e452ba 886 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
887}
888
6a2c4c81 889static int
affc96b5 890fport_close (SCM port)
6a2c4c81 891{
92c2555f
MV
892 scm_t_fport *fp = SCM_FSTREAM (port);
893 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 894 int rv;
840ae05d 895
affc96b5 896 fport_flush (port);
cb63cf9e
JB
897 SCM_SYSCALL (rv = close (fp->fdes));
898 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
899 {
900 if (scm_gc_running_p)
901 /* silently ignore the error. scm_error would abort if we
902 called it now. */
903 ;
904 else
905 scm_syserror ("fport_close");
906 }
6c951427
GH
907 if (pt->read_buf == pt->putback_buf)
908 pt->read_buf = pt->saved_read_buf;
cb63cf9e 909 if (pt->read_buf != &pt->shortbuf)
4c9419ac 910 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 911 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
912 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
913 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 914 return rv;
6a2c4c81
JB
915}
916
1be6b49c 917static size_t
affc96b5 918fport_free (SCM port)
b3ec3c64 919{
affc96b5 920 fport_close (port);
b3ec3c64
MD
921 return 0;
922}
923
92c2555f 924static scm_t_bits
b3ec3c64
MD
925scm_make_fptob ()
926{
92c2555f 927 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 928
affc96b5 929 scm_set_port_free (tc, fport_free);
e841c3e0 930 scm_set_port_print (tc, fport_print);
affc96b5
GH
931 scm_set_port_flush (tc, fport_flush);
932 scm_set_port_end_input (tc, fport_end_input);
933 scm_set_port_close (tc, fport_close);
934 scm_set_port_seek (tc, fport_seek);
935 scm_set_port_truncate (tc, fport_truncate);
936 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
937
938 return tc;
b3ec3c64 939}
0f2d19dd 940
0f2d19dd
JB
941void
942scm_init_fports ()
0f2d19dd 943{
a98bddfd
DH
944 scm_tc16_fport = scm_make_fptob ();
945
e11e83f3
MV
946 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
947 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
948 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 949
69cac238
AW
950 sys_file_port_name_canonicalization = scm_make_fluid ();
951 scm_c_define ("%file-port-name-canonicalization",
952 sys_file_port_name_canonicalization);
953
a98bddfd 954#include "libguile/fports.x"
0f2d19dd 955}
89e00824
ML
956
957/*
958 Local Variables:
959 c-file-style: "gnu"
960 End:
961*/