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