defsubst
[bpt/guile.git] / libguile / ioext.c
CommitLineData
bc8e6d7d 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2006,
475772ea 2 * 2011, 2014 Free Software Foundation, Inc.
0f2d19dd 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd
JB
21\f
22
dbb605f5 23#ifdef HAVE_CONFIG_H
381534b3
RB
24# include <config.h>
25#endif
26
7beabedb 27#include <stdio.h>
e6e2e95a
MD
28#include <errno.h>
29
a0599745 30#include "libguile/_scm.h"
5dbc6c06 31#include "libguile/dynwind.h"
a0599745 32#include "libguile/feature.h"
5dbc6c06
HWN
33#include "libguile/fports.h"
34#include "libguile/hashtab.h"
35#include "libguile/ioext.h"
6d36532c 36#include "libguile/ports.h"
a0599745 37#include "libguile/strings.h"
a0599745 38#include "libguile/validate.h"
0f2d19dd 39
ee149d03
JB
40#include <fcntl.h>
41
ec65f5da
MV
42#ifdef HAVE_IO_H
43#include <io.h>
44#endif
95b88819 45#include <unistd.h>
0f2d19dd
JB
46\f
47
a1ec6916 48SCM_DEFINE (scm_ftell, "ftell", 1, 0, 0,
1e6808ea
MG
49 (SCM fd_port),
50 "Return an integer representing the current position of\n"
b7e64f8b 51 "@var{fd_port}, measured from the beginning. Equivalent to:\n"
1e6808ea
MG
52 "\n"
53 "@lisp\n"
b380b885 54 "(seek port 0 SEEK_CUR)\n"
1e6808ea 55 "@end lisp")
1bbd0b84 56#define FUNC_NAME s_scm_ftell
0f2d19dd 57{
e11e83f3 58 return scm_seek (fd_port, SCM_INUM0, scm_from_int (SEEK_CUR));
ee149d03 59}
1bbd0b84 60#undef FUNC_NAME
0f2d19dd 61
a1ec6916 62SCM_DEFINE (scm_redirect_port, "redirect-port", 2, 0, 0,
1bbd0b84 63 (SCM old, SCM new),
b380b885 64 "This procedure takes two ports and duplicates the underlying file\n"
b7e64f8b
BT
65 "descriptor from @var{old} into @var{new}. The\n"
66 "current file descriptor in @var{new} will be closed.\n"
b380b885
MD
67 "After the redirection the two ports will share a file position\n"
68 "and file status flags.\n\n"
69 "The return value is unspecified.\n\n"
70 "Unexpected behaviour can result if both ports are subsequently used\n"
71 "and the original and/or duplicate ports are buffered.\n\n"
72 "This procedure does not have any side effects on other ports or\n"
73 "revealed counts.")
1bbd0b84 74#define FUNC_NAME s_scm_redirect_port
0f2d19dd
JB
75{
76 int ans, oldfd, newfd;
92c2555f 77 scm_t_fport *fp;
9c29ac66 78
78446828
MV
79 old = SCM_COERCE_OUTPORT (old);
80 new = SCM_COERCE_OUTPORT (new);
1bbd0b84 81
34d19ef6
HWN
82 SCM_VALIDATE_OPFPORT (1, old);
83 SCM_VALIDATE_OPFPORT (2, new);
ee149d03
JB
84 oldfd = SCM_FPORT_FDES (old);
85 fp = SCM_FSTREAM (new);
86 newfd = fp->fdes;
87 if (oldfd != newfd)
88 {
92c2555f
MV
89 scm_t_port *pt = SCM_PTAB_ENTRY (new);
90 scm_t_port *old_pt = SCM_PTAB_ENTRY (old);
62bd5d66 91 scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (new);
afc5764c
JB
92
93 /* must flush to old fdes. */
94 if (pt->rw_active == SCM_PORT_WRITE)
affc96b5 95 ptob->flush (new);
afc5764c 96 else if (pt->rw_active == SCM_PORT_READ)
4251ae2e 97 scm_end_input_unlocked (new);
ee149d03
JB
98 ans = dup2 (oldfd, newfd);
99 if (ans == -1)
1bbd0b84 100 SCM_SYSERROR;
afc5764c 101 pt->rw_random = old_pt->rw_random;
ee149d03 102 /* continue using existing buffers, even if inappropriate. */
ee149d03 103 }
02b754d3 104 return SCM_UNSPECIFIED;
0f2d19dd 105}
1bbd0b84 106#undef FUNC_NAME
0f2d19dd 107
a1ec6916 108SCM_DEFINE (scm_dup_to_fdes, "dup->fdes", 1, 1, 0,
1bbd0b84 109 (SCM fd_or_port, SCM fd),
1e6808ea
MG
110 "Return a new integer file descriptor referring to the open file\n"
111 "designated by @var{fd_or_port}, which must be either an open\n"
112 "file port or a file descriptor.")
1bbd0b84 113#define FUNC_NAME s_scm_dup_to_fdes
a9488d12
GH
114{
115 int oldfd, newfd, rv;
116
78446828
MV
117 fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
118
e11e83f3
MV
119 if (scm_is_integer (fd_or_port))
120 oldfd = scm_to_int (fd_or_port);
a9488d12
GH
121 else
122 {
34d19ef6 123 SCM_VALIDATE_OPFPORT (1, fd_or_port);
ee149d03 124 oldfd = SCM_FPORT_FDES (fd_or_port);
a9488d12 125 }
7a6f1ffa
GH
126
127 if (SCM_UNBNDP (fd))
e38303a2 128 {
ee149d03 129 newfd = dup (oldfd);
7a6f1ffa 130 if (newfd == -1)
1bbd0b84 131 SCM_SYSERROR;
a55c2b68 132 fd = scm_from_int (newfd);
7a6f1ffa
GH
133 }
134 else
135 {
a55c2b68 136 newfd = scm_to_int (fd);
7a6f1ffa
GH
137 if (oldfd != newfd)
138 {
139 scm_evict_ports (newfd); /* see scsh manual. */
ee149d03 140 rv = dup2 (oldfd, newfd);
7a6f1ffa 141 if (rv == -1)
1bbd0b84 142 SCM_SYSERROR;
7a6f1ffa 143 }
e38303a2 144 }
e38303a2 145 return fd;
a9488d12 146}
1bbd0b84 147#undef FUNC_NAME
a9488d12 148
34526073 149
c2ca4493
GH
150SCM_DEFINE (scm_dup2, "dup2", 2, 0, 0,
151 (SCM oldfd, SCM newfd),
152 "A simple wrapper for the @code{dup2} system call.\n"
153 "Copies the file descriptor @var{oldfd} to descriptor\n"
154 "number @var{newfd}, replacing the previous meaning\n"
155 "of @var{newfd}. Both @var{oldfd} and @var{newfd} must\n"
156 "be integers.\n"
157 "Unlike for dup->fdes or primitive-move->fdes, no attempt\n"
34526073 158 "is made to move away ports which are using @var{newfd}.\n"
c2ca4493
GH
159 "The return value is unspecified.")
160#define FUNC_NAME s_scm_dup2
161{
162 int c_oldfd;
163 int c_newfd;
164 int rv;
165
a55c2b68
MV
166 c_oldfd = scm_to_int (oldfd);
167 c_newfd = scm_to_int (newfd);
c2ca4493
GH
168 rv = dup2 (c_oldfd, c_newfd);
169 if (rv == -1)
170 SCM_SYSERROR;
171 return SCM_UNSPECIFIED;
172}
173#undef FUNC_NAME
174
a1ec6916 175SCM_DEFINE (scm_fileno, "fileno", 1, 0, 0,
1bbd0b84 176 (SCM port),
1e6808ea
MG
177 "Return the integer file descriptor underlying @var{port}. Does\n"
178 "not change its revealed count.")
1bbd0b84 179#define FUNC_NAME s_scm_fileno
0f2d19dd 180{
78446828 181 port = SCM_COERCE_OUTPORT (port);
34d19ef6 182 SCM_VALIDATE_OPFPORT (1, port);
e11e83f3 183 return scm_from_int (SCM_FPORT_FDES (port));
0f2d19dd 184}
1bbd0b84
GB
185#undef FUNC_NAME
186
187/* GJB:FIXME:: why does this not throw
188 an error if the arg is not a port?
189 This proc as is would be better names isattyport?
1be6b49c
ML
190 if it is not going to assume that the arg is a port
191
192 [cmm] I don't see any problem with the above. why should a type
193 predicate assume _anything_ about its argument?
194*/
a1ec6916 195SCM_DEFINE (scm_isatty_p, "isatty?", 1, 0, 0,
1bbd0b84 196 (SCM port),
1e6808ea
MG
197 "Return @code{#t} if @var{port} is using a serial non--file\n"
198 "device, otherwise @code{#f}.")
1bbd0b84 199#define FUNC_NAME s_scm_isatty_p
0f2d19dd
JB
200{
201 int rv;
78446828
MV
202
203 port = SCM_COERCE_OUTPORT (port);
204
0c95b57d 205 if (!SCM_OPFPORTP (port))
10ccfad7 206 return SCM_BOOL_F;
ee149d03
JB
207
208 rv = isatty (SCM_FPORT_FDES (port));
7888309b 209 return scm_from_bool(rv);
0f2d19dd 210}
1bbd0b84 211#undef FUNC_NAME
0f2d19dd
JB
212
213
214
a1ec6916 215SCM_DEFINE (scm_fdopen, "fdopen", 2, 0, 0,
1bbd0b84 216 (SCM fdes, SCM modes),
1e6808ea
MG
217 "Return a new port based on the file descriptor @var{fdes}.\n"
218 "Modes are given by the string @var{modes}. The revealed count\n"
219 "of the port is initialized to zero. The modes string is the\n"
220 "same as that accepted by @ref{File Ports, open-file}.")
1bbd0b84 221#define FUNC_NAME s_scm_fdopen
0f2d19dd 222{
86e14f5c
MV
223 return scm_i_fdes_to_port (scm_to_int (fdes),
224 scm_i_mode_bits (modes), SCM_BOOL_F);
0f2d19dd 225}
1bbd0b84 226#undef FUNC_NAME
0f2d19dd
JB
227
228
229
230/* Move a port's underlying file descriptor to a given value.
8b13c6b3
GH
231 * Returns #f if fdes is already the given value.
232 * #t if fdes moved.
0f2d19dd
JB
233 * MOVE->FDES is implemented in Scheme and calls this primitive.
234 */
a1ec6916 235SCM_DEFINE (scm_primitive_move_to_fdes, "primitive-move->fdes", 2, 0, 0,
1bbd0b84 236 (SCM port, SCM fd),
b380b885 237 "Moves the underlying file descriptor for @var{port} to the integer\n"
b7e64f8b 238 "value @var{fd} without changing the revealed count of @var{port}.\n"
b380b885
MD
239 "Any other ports already using this descriptor will be automatically\n"
240 "shifted to new descriptors and their revealed counts reset to zero.\n"
241 "The return value is @code{#f} if the file descriptor already had the\n"
242 "required value or @code{#t} if it was moved.")
1bbd0b84 243#define FUNC_NAME s_scm_primitive_move_to_fdes
0f2d19dd 244{
92c2555f 245 scm_t_fport *stream;
0f2d19dd
JB
246 int old_fd;
247 int new_fd;
248 int rv;
249
78446828
MV
250 port = SCM_COERCE_OUTPORT (port);
251
34d19ef6 252 SCM_VALIDATE_OPFPORT (1, port);
ee149d03
JB
253 stream = SCM_FSTREAM (port);
254 old_fd = stream->fdes;
a55c2b68 255 new_fd = scm_to_int (fd);
0f2d19dd
JB
256 if (old_fd == new_fd)
257 {
8b13c6b3 258 return SCM_BOOL_F;
0f2d19dd
JB
259 }
260 scm_evict_ports (new_fd);
261 rv = dup2 (old_fd, new_fd);
262 if (rv == -1)
1bbd0b84 263 SCM_SYSERROR;
ee149d03 264 stream->fdes = new_fd;
0f2d19dd 265 SCM_SYSCALL (close (old_fd));
8b13c6b3 266 return SCM_BOOL_T;
0f2d19dd 267}
1bbd0b84 268#undef FUNC_NAME
0f2d19dd 269
5dbc6c06 270static SCM
2721f918 271get_matching_port (void *closure, SCM port, SCM result)
5dbc6c06
HWN
272{
273 int fd = * (int *) closure;
274 scm_t_port *entry = SCM_PTAB_ENTRY (port);
275
276 if (SCM_OPFPORTP (port)
277 && ((scm_t_fport *) entry->stream)->fdes == fd)
278 result = scm_cons (port, result);
279
280 return result;
281}
282
0f2d19dd 283/* Return a list of ports using a given file descriptor. */
3b3b36dd 284SCM_DEFINE (scm_fdes_to_ports, "fdes->ports", 1, 0, 0,
1bbd0b84 285 (SCM fd),
b7e64f8b 286 "Return a list of existing ports which have @var{fd} as an\n"
1e6808ea
MG
287 "underlying file descriptor, without changing their revealed\n"
288 "counts.")
1bbd0b84 289#define FUNC_NAME s_scm_fdes_to_ports
0f2d19dd
JB
290{
291 SCM result = SCM_EOL;
5dbc6c06 292 int int_fd = scm_to_int (fd);
0f2d19dd 293
2721f918
AW
294 result = scm_c_weak_set_fold (get_matching_port,
295 (void*) &int_fd, result,
296 scm_i_port_weak_set);
0f2d19dd 297 return result;
1bbd0b84
GB
298}
299#undef FUNC_NAME
0f2d19dd 300
1cc91f1b 301
0f2d19dd
JB
302void
303scm_init_ioext ()
0f2d19dd 304{
52cfc69b
GH
305 scm_add_feature ("i/o-extensions");
306
a0599745 307#include "libguile/ioext.x"
0f2d19dd
JB
308}
309
89e00824
ML
310
311/*
312 Local Variables:
313 c-file-style: "gnu"
314 End:
315*/