Doc fix.
[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_getc (port);
121 for (k = 0; k < num_delims; k++)
122 {
123 if (cdelims[k] == c)
124 {
125 if (SCM_FALSEP (gobble))
126 scm_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 /*
142 * %read-line uses a port's fgets method for fast line i/o. It
143 * truncates any terminating newline from its input, and returns
144 * a cons of the string read and its terminating character. Doing
145 * so makes it easy to implement the hairy `read-line' options
146 * efficiently in Scheme.
147 */
148
149 SCM_PROC (s_read_line, "%read-line", 0, 1, 0, scm_read_line);
150
151 SCM
152 scm_read_line (port)
153 SCM port;
154 {
155 char *s;
156 int slen;
157 SCM line, term;
158
159 if (SCM_UNBNDP (port))
160 port = scm_cur_inp;
161 else
162 {
163 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port),
164 port, SCM_ARG1, s_read_line);
165 }
166
167 s = scm_do_read_line (port, &slen);
168
169 if (s == NULL)
170 term = line = SCM_EOF_VAL;
171 else
172 {
173 if (s[slen-1] == '\n')
174 {
175 term = SCM_MAKICHR ('\n');
176 line = scm_makfromstr (s, slen-1, 0);
177 }
178 else
179 {
180 /* Fix: we should check for eof on the port before assuming this. */
181 term = SCM_EOF_VAL;
182 line = scm_makfromstr (s, slen, 0);
183 }
184 free (s);
185 }
186
187 return scm_cons (line, term);
188 }
189
190 SCM_PROC (s_write_line, "write-line", 1, 1, 0, scm_write_line);
191
192 SCM
193 scm_write_line (obj, port)
194 SCM obj;
195 SCM port;
196 {
197 scm_display (obj, port);
198 return scm_newline (port);
199 }
200
201 SCM_PROC (s_ftell, "ftell", 1, 0, 0, scm_ftell);
202
203 SCM
204 scm_ftell (object)
205 SCM object;
206 {
207 long pos;
208
209 object = SCM_COERCE_OUTPORT (object);
210
211 SCM_DEFER_INTS;
212 if (SCM_NIMP (object) && SCM_OPFPORTP (object))
213 {
214 SCM_SYSCALL (pos = ftell ((FILE *)SCM_STREAM (object)));
215 if (pos > 0 && SCM_CRDYP (object))
216 pos--;
217 }
218 else
219 {
220 SCM_ASSERT (SCM_INUMP (object), object, SCM_ARG1, s_ftell);
221 SCM_SYSCALL (pos = lseek (SCM_INUM (object), 0, SEEK_CUR));
222 }
223 if (pos < 0)
224 scm_syserror (s_ftell);
225 SCM_ALLOW_INTS;
226 return scm_long2num (pos);
227 }
228
229
230
231 SCM_PROC (s_fseek, "fseek", 3, 0, 0, scm_fseek);
232
233 SCM
234 scm_fseek (object, offset, whence)
235 SCM object;
236 SCM offset;
237 SCM whence;
238 {
239 int rv;
240 long loff;
241
242 object = SCM_COERCE_OUTPORT (object);
243
244 loff = scm_num2long (offset, (char *)SCM_ARG2, s_fseek);
245 SCM_ASSERT (SCM_INUMP (whence), whence, SCM_ARG3, s_fseek);
246 SCM_DEFER_INTS;
247 if (SCM_NIMP (object) && SCM_OPFPORTP (object))
248 {
249 SCM_CLRDY (object); /* Clear ungetted char */
250 rv = fseek ((FILE *)SCM_STREAM (object), loff, SCM_INUM (whence));
251 }
252 else
253 {
254 SCM_ASSERT (SCM_INUMP (object), object, SCM_ARG1, s_fseek);
255 rv = lseek (SCM_INUM (object), loff, SCM_INUM (whence));
256 }
257 if (rv < 0)
258 scm_syserror (s_fseek);
259 SCM_ALLOW_INTS;
260 return SCM_UNSPECIFIED;
261 }
262
263 SCM_PROC (s_freopen, "freopen", 3, 0, 0, scm_freopen);
264
265 SCM
266 scm_freopen (filename, modes, port)
267 SCM filename;
268 SCM modes;
269 SCM port;
270 {
271 FILE *f;
272 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename,
273 SCM_ARG1, s_freopen);
274 SCM_ASSERT (SCM_NIMP (modes) && SCM_ROSTRINGP (modes), modes, SCM_ARG2,
275 s_freopen);
276
277 SCM_COERCE_SUBSTR (filename);
278 SCM_COERCE_SUBSTR (modes);
279 port = SCM_COERCE_OUTPORT (port);
280 SCM_DEFER_INTS;
281 SCM_ASSERT (SCM_NIMP (port) && SCM_FPORTP (port), port, SCM_ARG3, s_freopen);
282 SCM_SYSCALL (f = freopen (SCM_ROCHARS (filename), SCM_ROCHARS (modes),
283 (FILE *)SCM_STREAM (port)));
284 if (!f)
285 {
286 SCM p;
287 p = port;
288 port = SCM_MAKINUM (errno);
289 SCM_SETAND_CAR (p, ~SCM_OPN);
290 scm_remove_from_port_table (p);
291 }
292 else
293 {
294 SCM_SETCAR (port, scm_tc16_fport | scm_mode_bits (SCM_ROCHARS (modes)));
295 SCM_SETSTREAM (port, (SCM)f);
296 SCM_SETCAR (port, scm_tc16_fport | scm_mode_bits (SCM_ROCHARS (modes)));
297 if (SCM_BUF0 & SCM_CAR (port))
298 scm_setbuf0 (port);
299 }
300 SCM_ALLOW_INTS;
301 return port;
302 }
303
304 SCM_PROC (s_redirect_port, "redirect-port", 2, 0, 0, scm_redirect_port);
305
306 SCM
307 scm_redirect_port (old, new)
308 SCM old;
309 SCM new;
310 {
311 int ans, oldfd, newfd;
312
313 old = SCM_COERCE_OUTPORT (old);
314 new = SCM_COERCE_OUTPORT (new);
315
316 SCM_DEFER_INTS;
317 SCM_ASSERT (SCM_NIMP (old) && SCM_OPPORTP (old), old, SCM_ARG1, s_redirect_port);
318 SCM_ASSERT (SCM_NIMP (new) && SCM_OPPORTP (new), new, SCM_ARG2, s_redirect_port);
319 oldfd = fileno ((FILE *)SCM_STREAM (old));
320 if (oldfd == -1)
321 scm_syserror (s_redirect_port);
322 newfd = fileno ((FILE *)SCM_STREAM (new));
323 if (newfd == -1)
324 scm_syserror (s_redirect_port);
325 SCM_SYSCALL (ans = dup2 (oldfd, newfd));
326 if (ans == -1)
327 scm_syserror (s_redirect_port);
328 SCM_ALLOW_INTS;
329 return SCM_UNSPECIFIED;
330 }
331
332 SCM_PROC (s_dup_to_fdes, "dup->fdes", 1, 1, 0, scm_dup_to_fdes);
333 SCM
334 scm_dup_to_fdes (SCM fd_or_port, SCM fd)
335 {
336 int oldfd, newfd, rv;
337
338 fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
339
340 SCM_DEFER_INTS;
341 if (SCM_INUMP (fd_or_port))
342 oldfd = SCM_INUM (fd_or_port);
343 else
344 {
345 SCM_ASSERT (SCM_NIMP (fd_or_port) && SCM_OPPORTP (fd_or_port),
346 fd_or_port, SCM_ARG1, s_dup_to_fdes);
347 oldfd = fileno ((FILE *)SCM_STREAM (fd_or_port));
348 if (oldfd == -1)
349 scm_syserror (s_dup_to_fdes);
350 }
351
352 if (SCM_UNBNDP (fd))
353 {
354 SCM_SYSCALL (newfd = dup (oldfd));
355 if (newfd == -1)
356 scm_syserror (s_dup_to_fdes);
357 fd = SCM_MAKINUM (newfd);
358 }
359 else
360 {
361 SCM_ASSERT (SCM_INUMP (fd), fd, SCM_ARG2, s_dup_to_fdes);
362 newfd = SCM_INUM (fd);
363 if (oldfd != newfd)
364 {
365 scm_evict_ports (newfd); /* see scsh manual. */
366 SCM_SYSCALL (rv = dup2 (oldfd, newfd));
367 if (rv == -1)
368 scm_syserror (s_dup_to_fdes);
369 }
370 }
371 SCM_ALLOW_INTS;
372 return fd;
373 }
374
375 SCM_PROC (s_fileno, "fileno", 1, 0, 0, scm_fileno);
376
377 SCM
378 scm_fileno (port)
379 SCM port;
380 {
381 int fd;
382
383 port = SCM_COERCE_OUTPORT (port);
384
385 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_fileno);
386 fd = fileno ((FILE *)SCM_STREAM (port));
387 if (fd == -1)
388 scm_syserror (s_fileno);
389 return SCM_MAKINUM (fd);
390 }
391
392 SCM_PROC (s_isatty, "isatty?", 1, 0, 0, scm_isatty_p);
393
394 SCM
395 scm_isatty_p (port)
396 SCM port;
397 {
398 int rv;
399
400 port = SCM_COERCE_OUTPORT (port);
401
402 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_isatty);
403 rv = fileno ((FILE *)SCM_STREAM (port));
404 if (rv == -1)
405 scm_syserror (s_isatty);
406 rv = isatty (rv);
407 return rv ? SCM_BOOL_T : SCM_BOOL_F;
408 }
409
410
411
412 SCM_PROC (s_fdopen, "fdopen", 2, 0, 0, scm_fdopen);
413
414 SCM
415 scm_fdopen (fdes, modes)
416 SCM fdes;
417 SCM modes;
418 {
419 FILE *f;
420 SCM port;
421 struct scm_port_table * pt;
422
423 SCM_ASSERT (SCM_INUMP (fdes), fdes, SCM_ARG1, s_fdopen);
424 SCM_ASSERT (SCM_NIMP (modes) && SCM_ROSTRINGP (modes), modes, SCM_ARG2,
425 s_fdopen);
426 SCM_COERCE_SUBSTR (modes);
427 SCM_NEWCELL (port);
428 SCM_DEFER_INTS;
429 f = fdopen (SCM_INUM (fdes), SCM_ROCHARS (modes));
430 if (f == NULL)
431 scm_syserror (s_fdopen);
432 pt = scm_add_to_port_table (port);
433 SCM_SETPTAB_ENTRY (port, pt);
434 SCM_SETCAR (port, scm_tc16_fport | scm_mode_bits (SCM_ROCHARS (modes)));
435 SCM_SETSTREAM (port, (SCM)f);
436 if (SCM_BUF0 & SCM_CAR (port))
437 scm_setbuf0 (port);
438 SCM_ALLOW_INTS;
439 return port;
440 }
441
442
443
444 /* Move a port's underlying file descriptor to a given value.
445 * Returns #f if fdes is already the given value.
446 * #t if fdes moved.
447 * MOVE->FDES is implemented in Scheme and calls this primitive.
448 */
449 SCM_PROC (s_primitive_move_to_fdes, "primitive-move->fdes", 2, 0, 0, scm_primitive_move_to_fdes);
450
451 SCM
452 scm_primitive_move_to_fdes (port, fd)
453 SCM port;
454 SCM fd;
455 {
456 FILE *stream;
457 int old_fd;
458 int new_fd;
459 int rv;
460
461 port = SCM_COERCE_OUTPORT (port);
462
463 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1, s_primitive_move_to_fdes);
464 SCM_ASSERT (SCM_INUMP (fd), fd, SCM_ARG2, s_primitive_move_to_fdes);
465 SCM_DEFER_INTS;
466 stream = (FILE *)SCM_STREAM (port);
467 old_fd = fileno (stream);
468 new_fd = SCM_INUM (fd);
469 if (old_fd == new_fd)
470 {
471 SCM_ALLOW_INTS;
472 return SCM_BOOL_F;
473 }
474 scm_evict_ports (new_fd);
475 rv = dup2 (old_fd, new_fd);
476 if (rv == -1)
477 scm_syserror (s_primitive_move_to_fdes);
478 scm_setfileno (stream, new_fd);
479 SCM_SYSCALL (close (old_fd));
480 SCM_ALLOW_INTS;
481 return SCM_BOOL_T;
482 }
483
484 /* Return a list of ports using a given file descriptor. */
485 SCM_PROC(s_fdes_to_ports, "fdes->ports", 1, 0, 0, scm_fdes_to_ports);
486
487 SCM
488 scm_fdes_to_ports (fd)
489 SCM fd;
490 {
491 SCM result = SCM_EOL;
492 int int_fd;
493 int i;
494
495 SCM_ASSERT (SCM_INUMP (fd), fd, SCM_ARG1, s_fdes_to_ports);
496 int_fd = SCM_INUM (fd);
497
498 SCM_DEFER_INTS;
499 for (i = 0; i < scm_port_table_size; i++)
500 {
501 if (SCM_FPORTP (scm_port_table[i]->port)
502 && fileno ((FILE *)SCM_STREAM (scm_port_table[i]->port)) == int_fd)
503 result = scm_cons (scm_port_table[i]->port, result);
504 }
505 SCM_ALLOW_INTS;
506 return result;
507 }
508
509
510 void
511 scm_init_ioext ()
512 {
513 /* fseek() symbols. */
514 scm_sysintern ("SEEK_SET", SCM_MAKINUM (SEEK_SET));
515 scm_sysintern ("SEEK_CUR", SCM_MAKINUM (SEEK_CUR));
516 scm_sysintern ("SEEK_END", SCM_MAKINUM (SEEK_END));
517
518 #include "ioext.x"
519 }
520