1 /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
8 * This program 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
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
42 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
49 #include "libguile/_scm.h"
50 #include "libguile/ioext.h"
51 #include "libguile/fports.h"
52 #include "libguile/feature.h"
53 #include "libguile/ports.h"
54 #include "libguile/root.h"
55 #include "libguile/strings.h"
56 #include "libguile/validate.h"
69 #define SCM_MAYBE_EAGAIN || errno == EAGAIN
71 #define SCM_MAYBE_EAGAIN
74 #if defined (EWOULDBLOCK)
75 #define SCM_MAYBE_EWOULDBLOCK || errno == EWOULDBLOCK
77 #define SCM_MAYBE_EWOULDBLOCK
80 /* MAYBE there is EAGAIN way of defining this macro but now I EWOULDBLOCK. */
81 #define SCM_EBLOCK(errno) \
82 (0 SCM_MAYBE_EAGAIN SCM_MAYBE_EWOULDBLOCK)
84 SCM_DEFINE (scm_read_string_x_partial
, "read-string!/partial", 1, 3, 0,
85 (SCM str
, SCM port_or_fdes
, SCM start
, SCM end
),
86 "Read characters from an fport or file descriptor into a\n"
87 "string @var{str}. This procedure is scsh-compatible\n"
88 "and can efficiently read large strings. It will:\n\n"
91 "attempt to fill the entire string, unless the @var{start}\n"
92 "and/or @var{end} arguments are supplied. i.e., @var{start}\n"
93 "defaults to 0 and @var{end} defaults to\n"
94 "@code{(string-length str)}\n"
96 "use the current input port if @var{port_or_fdes} is not\n"
99 "read any characters that are currently available,\n"
100 "without waiting for the rest (short reads are possible).\n\n"
102 "wait for as long as it needs to for the first character to\n"
103 "become available, unless the port is in non-blocking mode\n"
105 "return @code{#f} if end-of-file is encountered before reading\n"
106 "any characters, otherwise return the number of characters\n"
109 "return 0 if the port is in non-blocking mode and no characters\n"
110 "are immediately available.\n"
112 "return 0 if the request is for 0 bytes, with no\n"
113 "end-of-file check\n"
115 #define FUNC_NAME s_scm_read_string_x_partial
126 SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, str
, dest
, 3, start
, offset
,
129 read_len
= last
- offset
;
132 if (SCM_INUMP (port_or_fdes
))
133 fdes
= SCM_INUM (port_or_fdes
);
136 SCM port
= SCM_UNBNDP (port_or_fdes
) ? scm_cur_inp
: port_or_fdes
;
138 SCM_VALIDATE_OPFPORT (2, port
);
139 SCM_VALIDATE_INPUT_PORT (2, port
);
141 /* if there's anything in the port buffers, use it, but then
142 don't touch the file descriptor. otherwise the
143 "return immediately if something is available" rule may
145 chars_read
= scm_take_from_input_buffers (port
, dest
, read_len
);
146 fdes
= SCM_FPORT_FDES (port
);
149 if (chars_read
== 0 && read_len
> 0) /* don't confuse read_len == 0 with
152 SCM_SYSCALL (chars_read
= read (fdes
, dest
, read_len
));
153 if (chars_read
== -1)
155 if (SCM_EBLOCK (errno
))
160 else if (chars_read
== 0)
163 return scm_long2num (chars_read
);
167 SCM_DEFINE (scm_ftell
, "ftell", 1, 0, 0,
169 "Return an integer representing the current position of\n"
170 "@var{fd/port}, measured from the beginning. Equivalent to:\n"
173 "(seek port 0 SEEK_CUR)\n"
175 #define FUNC_NAME s_scm_ftell
177 return scm_seek (fd_port
, SCM_INUM0
, SCM_MAKINUM (SEEK_CUR
));
181 SCM_DEFINE (scm_redirect_port
, "redirect-port", 2, 0, 0,
183 "This procedure takes two ports and duplicates the underlying file\n"
184 "descriptor from @var{old-port} into @var{new-port}. The\n"
185 "current file descriptor in @var{new-port} will be closed.\n"
186 "After the redirection the two ports will share a file position\n"
187 "and file status flags.\n\n"
188 "The return value is unspecified.\n\n"
189 "Unexpected behaviour can result if both ports are subsequently used\n"
190 "and the original and/or duplicate ports are buffered.\n\n"
191 "This procedure does not have any side effects on other ports or\n"
193 #define FUNC_NAME s_scm_redirect_port
195 int ans
, oldfd
, newfd
;
196 struct scm_fport
*fp
;
198 old
= SCM_COERCE_OUTPORT (old
);
199 new = SCM_COERCE_OUTPORT (new);
201 SCM_VALIDATE_OPFPORT (1,old
);
202 SCM_VALIDATE_OPFPORT (2,new);
203 oldfd
= SCM_FPORT_FDES (old
);
204 fp
= SCM_FSTREAM (new);
208 scm_port
*pt
= SCM_PTAB_ENTRY (new);
209 scm_port
*old_pt
= SCM_PTAB_ENTRY (old
);
210 scm_ptob_descriptor
*ptob
= &scm_ptobs
[SCM_PTOBNUM (new)];
212 /* must flush to old fdes. */
213 if (pt
->rw_active
== SCM_PORT_WRITE
)
215 else if (pt
->rw_active
== SCM_PORT_READ
)
217 ans
= dup2 (oldfd
, newfd
);
220 pt
->rw_random
= old_pt
->rw_random
;
221 /* continue using existing buffers, even if inappropriate. */
223 return SCM_UNSPECIFIED
;
227 SCM_DEFINE (scm_dup_to_fdes
, "dup->fdes", 1, 1, 0,
228 (SCM fd_or_port
, SCM fd
),
229 "Return a new integer file descriptor referring to the open file\n"
230 "designated by @var{fd_or_port}, which must be either an open\n"
231 "file port or a file descriptor.")
232 #define FUNC_NAME s_scm_dup_to_fdes
234 int oldfd
, newfd
, rv
;
236 fd_or_port
= SCM_COERCE_OUTPORT (fd_or_port
);
238 if (SCM_INUMP (fd_or_port
))
239 oldfd
= SCM_INUM (fd_or_port
);
242 SCM_VALIDATE_OPFPORT (1,fd_or_port
);
243 oldfd
= SCM_FPORT_FDES (fd_or_port
);
251 fd
= SCM_MAKINUM (newfd
);
255 SCM_VALIDATE_INUM_COPY (2, fd
, newfd
);
258 scm_evict_ports (newfd
); /* see scsh manual. */
259 rv
= dup2 (oldfd
, newfd
);
269 SCM_DEFINE (scm_dup2
, "dup2", 2, 0, 0,
270 (SCM oldfd
, SCM newfd
),
271 "A simple wrapper for the @code{dup2} system call.\n"
272 "Copies the file descriptor @var{oldfd} to descriptor\n"
273 "number @var{newfd}, replacing the previous meaning\n"
274 "of @var{newfd}. Both @var{oldfd} and @var{newfd} must\n"
276 "Unlike for dup->fdes or primitive-move->fdes, no attempt\n"
277 "is made to move away ports which are using @var{newfd}.\n"
278 "The return value is unspecified.")
279 #define FUNC_NAME s_scm_dup2
285 SCM_VALIDATE_INUM_COPY (1, oldfd
, c_oldfd
);
286 SCM_VALIDATE_INUM_COPY (2, newfd
, c_newfd
);
287 rv
= dup2 (c_oldfd
, c_newfd
);
290 return SCM_UNSPECIFIED
;
294 SCM_DEFINE (scm_fileno
, "fileno", 1, 0, 0,
296 "Return the integer file descriptor underlying @var{port}. Does\n"
297 "not change its revealed count.")
298 #define FUNC_NAME s_scm_fileno
300 port
= SCM_COERCE_OUTPORT (port
);
301 SCM_VALIDATE_OPFPORT (1,port
);
302 return SCM_MAKINUM (SCM_FPORT_FDES (port
));
306 /* GJB:FIXME:: why does this not throw
307 an error if the arg is not a port?
308 This proc as is would be better names isattyport?
309 if it is not going to assume that the arg is a port */
310 SCM_DEFINE (scm_isatty_p
, "isatty?", 1, 0, 0,
312 "Return @code{#t} if @var{port} is using a serial non--file\n"
313 "device, otherwise @code{#f}.")
314 #define FUNC_NAME s_scm_isatty_p
318 port
= SCM_COERCE_OUTPORT (port
);
320 if (!SCM_OPFPORTP (port
))
323 rv
= isatty (SCM_FPORT_FDES (port
));
330 SCM_DEFINE (scm_fdopen
, "fdopen", 2, 0, 0,
331 (SCM fdes
, SCM modes
),
332 "Return a new port based on the file descriptor @var{fdes}.\n"
333 "Modes are given by the string @var{modes}. The revealed count\n"
334 "of the port is initialized to zero. The modes string is the\n"
335 "same as that accepted by @ref{File Ports, open-file}.")
336 #define FUNC_NAME s_scm_fdopen
338 SCM_VALIDATE_INUM (1,fdes
);
339 SCM_VALIDATE_STRING (2, modes
);
340 SCM_STRING_COERCE_0TERMINATION_X (modes
);
342 return scm_fdes_to_port (SCM_INUM (fdes
), SCM_STRING_CHARS (modes
), SCM_BOOL_F
);
348 /* Move a port's underlying file descriptor to a given value.
349 * Returns #f if fdes is already the given value.
351 * MOVE->FDES is implemented in Scheme and calls this primitive.
353 SCM_DEFINE (scm_primitive_move_to_fdes
, "primitive-move->fdes", 2, 0, 0,
355 "Moves the underlying file descriptor for @var{port} to the integer\n"
356 "value @var{fdes} without changing the revealed count of @var{port}.\n"
357 "Any other ports already using this descriptor will be automatically\n"
358 "shifted to new descriptors and their revealed counts reset to zero.\n"
359 "The return value is @code{#f} if the file descriptor already had the\n"
360 "required value or @code{#t} if it was moved.")
361 #define FUNC_NAME s_scm_primitive_move_to_fdes
363 struct scm_fport
*stream
;
368 port
= SCM_COERCE_OUTPORT (port
);
370 SCM_VALIDATE_OPFPORT (1,port
);
371 SCM_VALIDATE_INUM (2,fd
);
372 stream
= SCM_FSTREAM (port
);
373 old_fd
= stream
->fdes
;
374 new_fd
= SCM_INUM (fd
);
375 if (old_fd
== new_fd
)
379 scm_evict_ports (new_fd
);
380 rv
= dup2 (old_fd
, new_fd
);
383 stream
->fdes
= new_fd
;
384 SCM_SYSCALL (close (old_fd
));
389 /* Return a list of ports using a given file descriptor. */
390 SCM_DEFINE (scm_fdes_to_ports
, "fdes->ports", 1, 0, 0,
392 "Return a list of existing ports which have @var{fdes} as an\n"
393 "underlying file descriptor, without changing their revealed\n"
395 #define FUNC_NAME s_scm_fdes_to_ports
397 SCM result
= SCM_EOL
;
401 SCM_VALIDATE_INUM_COPY (1,fd
,int_fd
);
403 for (i
= 0; i
< scm_port_table_size
; i
++)
405 if (SCM_OPFPORTP (scm_port_table
[i
]->port
)
406 && ((struct scm_fport
*) scm_port_table
[i
]->stream
)->fdes
== int_fd
)
407 result
= scm_cons (scm_port_table
[i
]->port
, result
);
417 scm_add_feature ("i/o-extensions");
419 #ifndef SCM_MAGIC_SNARFER
420 #include "libguile/ioext.x"