* ioext.c (scm_duplicate_port): bug fix: don't try to make the
[bpt/guile.git] / libguile / ioext.c
1 /* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
2 *
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)
6 * any later version.
7 *
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.
12 *
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
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
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.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
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.
37 *
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. */
41 \f
42
43
44 #include <stdio.h>
45 #include "_scm.h"
46 #include "genio.h"
47 #include "read.h"
48 #include "fports.h"
49 #include "unif.h"
50 #include "chars.h"
51
52 #include "ioext.h"
53
54 #ifdef HAVE_STRING_H
55 #include <string.h>
56 #endif
57 #ifdef HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
60 \f
61
62 SCM_PROC (s_read_delimited_x, "%read-delimited!", 3, 3, 0, scm_read_delimited_x);
63
64 SCM
65 scm_read_delimited_x (delims, buf, gobble, port, start, end)
66 SCM delims;
67 SCM buf;
68 SCM gobble;
69 SCM port;
70 SCM start;
71 SCM end;
72 {
73 long j;
74 char *cbuf;
75 long cstart;
76 long cend;
77 int c;
78 char *cdelims;
79 int num_delims;
80
81 SCM_ASSERT (SCM_NIMP (delims) && SCM_ROSTRINGP (delims),
82 delims, SCM_ARG1, s_read_delimited_x);
83 cdelims = SCM_ROCHARS (delims);
84 num_delims = SCM_ROLENGTH (delims);
85 SCM_ASSERT (SCM_NIMP (buf) && SCM_STRINGP (buf),
86 buf, SCM_ARG2, s_read_delimited_x);
87 cbuf = SCM_CHARS (buf);
88 cend = SCM_LENGTH (buf);
89 if (SCM_UNBNDP (port))
90 port = scm_cur_inp;
91 else
92 {
93 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port),
94 port, SCM_ARG1, s_read_delimited_x);
95 }
96
97 if (SCM_UNBNDP (start))
98 cstart = 0;
99 else
100 {
101 cstart = scm_num2long (start,
102 (char *) SCM_ARG5, s_read_delimited_x);
103 if (cstart < 0 || cstart >= cend)
104 scm_out_of_range (s_read_delimited_x, start);
105
106 if (!SCM_UNBNDP (end))
107 {
108 long tend = scm_num2long (end, (char *) SCM_ARG6,
109 s_read_delimited_x);
110 if (tend <= cstart || tend > cend)
111 scm_out_of_range (s_read_delimited_x, end);
112 cend = tend;
113 }
114 }
115
116 for (j = cstart; j < cend; j++)
117 {
118 int k;
119
120 c = scm_gen_getc (port);
121 for (k = 0; k < num_delims; k++)
122 {
123 if (cdelims[k] == c)
124 {
125 if (SCM_FALSEP (gobble))
126 scm_gen_ungetc (c, port);
127
128 return scm_cons (SCM_MAKICHR (c),
129 scm_long2num (j - cstart));
130 }
131 }
132 if (c == EOF)
133 return scm_cons (SCM_EOF_VAL,
134 scm_long2num (j - cstart));
135
136 cbuf[j] = c;
137 }
138 return scm_cons (SCM_BOOL_F, scm_long2num (j - cstart));
139 }
140
141 SCM_PROC (s_write_line, "write-line", 1, 1, 0, scm_write_line);
142
143 SCM
144 scm_write_line (obj, port)
145 SCM obj;
146 SCM port;
147 {
148 scm_display (obj, port);
149 return scm_newline (port);
150 }
151
152 SCM_PROC (s_ftell, "ftell", 1, 0, 0, scm_ftell);
153
154 SCM
155 scm_ftell (port)
156 SCM port;
157 {
158 long pos;
159 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_ftell);
160 SCM_SYSCALL (pos = ftell ((FILE *)SCM_STREAM (port)));
161 if (pos < 0)
162 scm_syserror (s_ftell);
163 if (pos > 0 && SCM_CRDYP (port))
164 pos--;
165 return scm_long2num (pos);
166 }
167
168
169
170 SCM_PROC (s_fseek, "fseek", 3, 0, 0, scm_fseek);
171
172 SCM
173 scm_fseek (port, offset, whence)
174 SCM port;
175 SCM offset;
176 SCM whence;
177 {
178 int rv;
179 long loff;
180
181 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_fseek);
182 loff = scm_num2long (offset, (char *)SCM_ARG2, s_fseek);
183 SCM_ASSERT (SCM_INUMP (whence) && (SCM_INUM (whence) < 3) && (SCM_INUM (whence) >= 0),
184 whence, SCM_ARG3, s_fseek);
185
186 SCM_CLRDY (port); /* Clear ungetted char */
187 /* Values of whence are interned in scm_init_ioext. */
188 rv = fseek ((FILE *)SCM_STREAM (port), loff, SCM_INUM (whence));
189 if (rv != 0)
190 scm_syserror (s_fseek);
191 return SCM_UNSPECIFIED;
192 }
193
194
195
196 SCM_PROC (s_freopen, "freopen", 3, 0, 0, scm_freopen);
197
198 SCM
199 scm_freopen (filename, modes, port)
200 SCM filename;
201 SCM modes;
202 SCM port;
203 {
204 FILE *f;
205 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename,
206 SCM_ARG1, s_freopen);
207 SCM_ASSERT (SCM_NIMP (modes) && SCM_ROSTRINGP (modes), modes, SCM_ARG2,
208 s_freopen);
209
210 SCM_COERCE_SUBSTR (filename);
211 SCM_COERCE_SUBSTR (modes);
212 SCM_DEFER_INTS;
213 SCM_ASSERT (SCM_NIMP (port) && SCM_FPORTP (port), port, SCM_ARG3, s_freopen);
214 SCM_SYSCALL (f = freopen (SCM_ROCHARS (filename), SCM_ROCHARS (modes),
215 (FILE *)SCM_STREAM (port)));
216 if (!f)
217 {
218 SCM p;
219 p = port;
220 port = SCM_MAKINUM (errno);
221 SCM_SETAND_CAR (p, ~SCM_OPN);
222 scm_remove_from_port_table (p);
223 }
224 else
225 {
226 SCM_SETCAR (port, scm_tc16_fport | scm_mode_bits (SCM_ROCHARS (modes)));
227 SCM_SETSTREAM (port, (SCM)f);
228 SCM_SETCAR (port, scm_tc16_fport | scm_mode_bits (SCM_ROCHARS (modes)));
229 if (SCM_BUF0 & SCM_CAR (port))
230 scm_setbuf0 (port);
231 }
232 SCM_ALLOW_INTS;
233 return port;
234 }
235
236
237
238 SCM_PROC (s_duplicate_port, "duplicate-port", 2, 0, 0, scm_duplicate_port);
239
240 SCM
241 scm_duplicate_port (oldpt, modes)
242 SCM oldpt;
243 SCM modes;
244 {
245 int oldfd;
246 int newfd;
247 FILE *f;
248 SCM newpt;
249 SCM_ASSERT (SCM_NIMP (oldpt) && SCM_OPPORTP (oldpt), oldpt, SCM_ARG1,
250 s_duplicate_port);
251 SCM_ASSERT (SCM_NIMP (modes) && SCM_ROSTRINGP (modes), modes, SCM_ARG2,
252 s_duplicate_port);
253
254 SCM_COERCE_SUBSTR (modes);
255 SCM_NEWCELL (newpt);
256 SCM_DEFER_INTS;
257 oldfd = fileno ((FILE *)SCM_STREAM (oldpt));
258 if (oldfd == -1)
259 scm_syserror (s_duplicate_port);
260 SCM_SYSCALL (newfd = dup (oldfd));
261 if (newfd == -1)
262 scm_syserror (s_duplicate_port);
263 f = fdopen (newfd, SCM_ROCHARS (modes));
264 if (!f)
265 {
266 SCM_SYSCALL (close (newfd));
267 scm_syserror (s_duplicate_port);
268 }
269 {
270 struct scm_port_table * pt;
271 pt = scm_add_to_port_table (newpt);
272 SCM_SETPTAB_ENTRY (newpt, pt);
273 SCM_SETCAR (newpt, scm_tc16_fport | scm_mode_bits (SCM_ROCHARS (modes)));
274 SCM_SETSTREAM (newpt, (SCM)f);
275 if (SCM_BUF0 & SCM_CAR (newpt))
276 scm_setbuf0 (newpt);
277 SCM_PTAB_ENTRY (newpt)->file_name = SCM_PTAB_ENTRY (oldpt)->file_name;
278 }
279 SCM_ALLOW_INTS;
280 return newpt;
281 }
282
283
284
285 SCM_PROC (s_redirect_port, "redirect-port", 2, 0, 0, scm_redirect_port);
286
287 SCM
288 scm_redirect_port (into_pt, from_pt)
289 SCM into_pt;
290 SCM from_pt;
291 {
292 int ans, oldfd, newfd;
293 SCM_DEFER_INTS;
294 SCM_ASSERT (SCM_NIMP (into_pt) && SCM_OPPORTP (into_pt), into_pt, SCM_ARG1, s_redirect_port);
295 SCM_ASSERT (SCM_NIMP (from_pt) && SCM_OPPORTP (from_pt), from_pt, SCM_ARG2, s_redirect_port);
296 oldfd = fileno ((FILE *)SCM_STREAM (into_pt));
297 if (oldfd == -1)
298 scm_syserror (s_redirect_port);
299 newfd = fileno ((FILE *)SCM_STREAM (from_pt));
300 if (newfd == -1)
301 scm_syserror (s_redirect_port);
302 SCM_SYSCALL (ans = dup2 (oldfd, newfd));
303 if (ans == -1)
304 scm_syserror (s_redirect_port);
305 SCM_ALLOW_INTS;
306 return SCM_UNSPECIFIED;
307 }
308
309 SCM_PROC (s_fileno, "fileno", 1, 0, 0, scm_fileno);
310
311 SCM
312 scm_fileno (port)
313 SCM port;
314 {
315 int fd;
316 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_fileno);
317 fd = fileno ((FILE *)SCM_STREAM (port));
318 if (fd == -1)
319 scm_syserror (s_fileno);
320 return SCM_MAKINUM (fd);
321 }
322
323 SCM_PROC (s_isatty, "isatty?", 1, 0, 0, scm_isatty_p);
324
325 SCM
326 scm_isatty_p (port)
327 SCM port;
328 {
329 int rv;
330 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_isatty);
331 rv = fileno ((FILE *)SCM_STREAM (port));
332 if (rv == -1)
333 scm_syserror (s_isatty);
334 rv = isatty (rv);
335 return rv ? SCM_BOOL_T : SCM_BOOL_F;
336 }
337
338
339
340 SCM_PROC (s_fdopen, "fdopen", 2, 0, 0, scm_fdopen);
341
342 SCM
343 scm_fdopen (fdes, modes)
344 SCM fdes;
345 SCM modes;
346 {
347 FILE *f;
348 SCM port;
349 struct scm_port_table * pt;
350
351 SCM_ASSERT (SCM_INUMP (fdes), fdes, SCM_ARG1, s_fdopen);
352 SCM_ASSERT (SCM_NIMP (modes) && SCM_ROSTRINGP (modes), modes, SCM_ARG2,
353 s_fdopen);
354 SCM_COERCE_SUBSTR (modes);
355 SCM_NEWCELL (port);
356 SCM_DEFER_INTS;
357 f = fdopen (SCM_INUM (fdes), SCM_ROCHARS (modes));
358 if (f == NULL)
359 scm_syserror (s_fdopen);
360 pt = scm_add_to_port_table (port);
361 SCM_SETPTAB_ENTRY (port, pt);
362 SCM_SETCAR (port, scm_tc16_fport | scm_mode_bits (SCM_ROCHARS (modes)));
363 if (SCM_BUF0 & SCM_CAR (port))
364 scm_setbuf0 (port);
365 SCM_SETSTREAM (port, (SCM)f);
366 SCM_ALLOW_INTS;
367 return port;
368 }
369
370
371
372 /* Move a port's underlying file descriptor to a given value.
373 * Returns #f if fdes is already the given value.
374 * #t if fdes moved.
375 * MOVE->FDES is implemented in Scheme and calls this primitive.
376 */
377 SCM_PROC (s_primitive_move_to_fdes, "primitive-move->fdes", 2, 0, 0, scm_primitive_move_to_fdes);
378
379 SCM
380 scm_primitive_move_to_fdes (port, fd)
381 SCM port;
382 SCM fd;
383 {
384 FILE *stream;
385 int old_fd;
386 int new_fd;
387 int rv;
388
389 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_primitive_move_to_fdes);
390 SCM_ASSERT (SCM_INUMP (fd), fd, SCM_ARG2, s_primitive_move_to_fdes);
391 SCM_DEFER_INTS;
392 stream = (FILE *)SCM_STREAM (port);
393 old_fd = fileno (stream);
394 new_fd = SCM_INUM (fd);
395 if (old_fd == new_fd)
396 {
397 SCM_ALLOW_INTS;
398 return SCM_BOOL_F;
399 }
400 scm_evict_ports (new_fd);
401 rv = dup2 (old_fd, new_fd);
402 if (rv == -1)
403 scm_syserror (s_primitive_move_to_fdes);
404 scm_setfileno (stream, new_fd);
405 SCM_SYSCALL (close (old_fd));
406 SCM_ALLOW_INTS;
407 return SCM_BOOL_T;
408 }
409
410 #ifdef FD_SETTER
411 #define SET_FILE_FD_FIELD(F,D) ((F)->FD_SETTER = (D))
412 #endif
413
414 void
415 scm_setfileno (fs, fd)
416 FILE *fs;
417 int fd;
418 {
419 #ifdef SET_FILE_FD_FIELD
420 SET_FILE_FD_FIELD(fs, fd);
421 #else
422 scm_misc_error ("scm_setfileno", "Not fully implemented on this platform",
423 SCM_EOL);
424 #endif
425 }
426
427 /* Move ports with the specified file descriptor to new descriptors,
428 * reseting the revealed count to 0.
429 * Should be called with SCM_DEFER_INTS active.
430 */
431
432 void
433 scm_evict_ports (fd)
434 int fd;
435 {
436 int i;
437
438 for (i = 0; i < scm_port_table_size; i++)
439 {
440 if (SCM_FPORTP (scm_port_table[i]->port)
441 && fileno ((FILE *)SCM_STREAM (scm_port_table[i]->port)) == fd)
442 {
443 scm_setfileno ((FILE *)SCM_STREAM (scm_port_table[i]->port), dup (fd));
444 scm_set_port_revealed_x (scm_port_table[i]->port, SCM_MAKINUM (0));
445 }
446 }
447 }
448
449 /* Return a list of ports using a given file descriptor. */
450 SCM_PROC(s_fdes_to_ports, "fdes->ports", 1, 0, 0, scm_fdes_to_ports);
451
452 SCM
453 scm_fdes_to_ports (fd)
454 SCM fd;
455 {
456 SCM result = SCM_EOL;
457 int int_fd;
458 int i;
459
460 SCM_ASSERT (SCM_INUMP (fd), fd, SCM_ARG1, s_fdes_to_ports);
461 int_fd = SCM_INUM (fd);
462
463 SCM_DEFER_INTS;
464 for (i = 0; i < scm_port_table_size; i++)
465 {
466 if (SCM_FPORTP (scm_port_table[i]->port)
467 && fileno ((FILE *)SCM_STREAM (scm_port_table[i]->port)) == int_fd)
468 result = scm_cons (scm_port_table[i]->port, result);
469 }
470 SCM_ALLOW_INTS;
471 return result;
472 }
473
474
475 void
476 scm_init_ioext ()
477 {
478 /* fseek() symbols. */
479 scm_sysintern ("SEEK_SET", SCM_MAKINUM (SEEK_SET));
480 scm_sysintern ("SEEK_CUR", SCM_MAKINUM (SEEK_CUR));
481 scm_sysintern ("SEEK_END", SCM_MAKINUM (SEEK_END));
482
483 #include "ioext.x"
484 }
485