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