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