Simplify smob and port marking; set the mark bit in the generic
[bpt/guile.git] / libguile / fports.c
CommitLineData
3d8d56df 1/* Copyright (C) 1995,1996,1997 Free Software Foundation, Inc.
0f2d19dd
JB
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
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
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.
82892bed 40 * If you do not wish that, delete this exception notice. */
0f2d19dd
JB
41\f
42
43#include <stdio.h>
44#include "_scm.h"
20e6290e
JB
45#include "markers.h"
46
47#include "fports.h"
95b88819
GH
48
49#ifdef HAVE_STRING_H
50#include <string.h>
51#endif
0f2d19dd
JB
52#ifdef HAVE_UNISTD_H
53#include <unistd.h>
54#else
0f2d19dd
JB
55scm_sizet fwrite ();
56#endif
0f2d19dd 57
0f2d19dd
JB
58/* {Ports - file ports}
59 *
60 */
61
62/* should be called with SCM_DEFER_INTS active */
1717856b 63
0f2d19dd
JB
64SCM
65scm_setbuf0 (port)
66 SCM port;
0f2d19dd 67{
7a6f1ffa
GH
68 /* NOSETBUF was provided by scm to allow unbuffered ports to be
69 avoided on systems where ungetc didn't work correctly. See
70 comment in unif.c, which seems to be the only place where it
71 could still be a problem. */
0f2d19dd 72#ifndef NOSETBUF
7a6f1ffa
GH
73 /* SCM_SYSCALL (setbuf ((FILE *)SCM_STREAM (port), 0);); */
74 SCM_SYSCALL (setvbuf ((FILE *)SCM_STREAM (port), 0, _IONBF, 0););
0f2d19dd 75#endif
7a6f1ffa
GH
76 return SCM_UNSPECIFIED;
77}
78
79SCM_PROC (s_setvbuf, "setvbuf", 2, 1, 0, scm_setvbuf);
80SCM
81scm_setvbuf (SCM port, SCM mode, SCM size)
82{
83 int rv;
84 int cmode, csize;
85
78446828
MV
86 port = SCM_COERCE_OUTPORT (port);
87
7a6f1ffa
GH
88 SCM_ASSERT (SCM_NIMP (port) && SCM_FPORTP (port), port, SCM_ARG1, s_setvbuf);
89 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG2, s_setvbuf);
90 if (SCM_UNBNDP (size))
91 csize = 0;
92 else
93 {
94 SCM_ASSERT (SCM_INUMP (size), size, SCM_ARG3, s_setvbuf);
95 csize = SCM_INUM (size);
96 }
97 cmode = SCM_INUM (mode);
98 if (csize == 0 && cmode == _IOFBF)
99 cmode = _IONBF;
100 SCM_DEFER_INTS;
101 SCM_SYSCALL (rv = setvbuf ((FILE *)SCM_STREAM (port), 0, cmode, csize));
102 if (rv < 0)
103 scm_syserror (s_setvbuf);
104 if (cmode == _IONBF)
105 SCM_SETCAR (port, SCM_CAR (port) | SCM_BUF0);
106 else
107 SCM_SETCAR (port, (SCM_CAR (port) & ~SCM_BUF0));
108 SCM_ALLOW_INTS;
109 return SCM_UNSPECIFIED;
110}
111
112#ifdef FD_SETTER
113#define SET_FILE_FD_FIELD(F,D) ((F)->FD_SETTER = (D))
0f2d19dd 114#endif
7a6f1ffa
GH
115
116void
117scm_setfileno (fs, fd)
118 FILE *fs;
119 int fd;
120{
121#ifdef SET_FILE_FD_FIELD
122 SET_FILE_FD_FIELD(fs, fd);
123#else
124 scm_misc_error ("scm_setfileno", "Not fully implemented on this platform",
125 SCM_EOL);
0f2d19dd 126#endif
0f2d19dd
JB
127}
128
eadd48de
GH
129/* Move ports with the specified file descriptor to new descriptors,
130 * reseting the revealed count to 0.
131 * Should be called with SCM_DEFER_INTS active.
0f2d19dd 132 */
1717856b 133
eadd48de
GH
134void
135scm_evict_ports (fd)
136 int fd;
0f2d19dd 137{
eadd48de 138 int i;
0f2d19dd 139
eadd48de
GH
140 for (i = 0; i < scm_port_table_size; i++)
141 {
142 if (SCM_FPORTP (scm_port_table[i]->port)
143 && fileno ((FILE *)SCM_STREAM (scm_port_table[i]->port)) == fd)
144 {
145 scm_setfileno ((FILE *)SCM_STREAM (scm_port_table[i]->port), dup (fd));
146 scm_set_port_revealed_x (scm_port_table[i]->port, SCM_MAKINUM (0));
147 }
148 }
149}
0f2d19dd
JB
150
151/* scm_open_file
152 * Return a new port open on a given file.
153 *
154 * The mode string must match the pattern: [rwa+]** which
155 * is interpreted in the usual unix way.
156 *
157 * Return the new port.
158 */
19639113 159SCM_PROC(s_open_file, "open-file", 2, 0, 0, scm_open_file);
1717856b 160
0f2d19dd 161SCM
19639113
GH
162scm_open_file (filename, modes)
163 SCM filename;
164 SCM modes;
0f2d19dd 165{
19639113 166 SCM port;
0f2d19dd 167 FILE *f;
19639113
GH
168 char *file;
169 char *mode;
170
171 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename, SCM_ARG1, s_open_file);
172 SCM_ASSERT (SCM_NIMP (modes) && SCM_ROSTRINGP (modes), modes, SCM_ARG2, s_open_file);
173 if (SCM_SUBSTRP (filename))
174 filename = scm_makfromstr (SCM_ROCHARS (filename), SCM_ROLENGTH (filename), 0);
175 if (SCM_SUBSTRP (modes))
176 modes = scm_makfromstr (SCM_ROCHARS (modes), SCM_ROLENGTH (modes), 0);
177
178 file = SCM_ROCHARS (filename);
179 mode = SCM_ROCHARS (modes);
180
0f2d19dd
JB
181 SCM_NEWCELL (port);
182 SCM_DEFER_INTS;
19639113 183 SCM_SYSCALL (f = fopen (file, mode));
0f2d19dd
JB
184 if (!f)
185 {
3d8d56df
GH
186 int en = errno;
187
f5bf2977 188 scm_syserror_msg (s_open_file, "%s: %S",
19639113
GH
189 scm_listify (scm_makfrom0str (strerror (errno)),
190 filename,
3d8d56df
GH
191 SCM_UNDEFINED),
192 en);
0f2d19dd
JB
193 }
194 else
195 {
196 struct scm_port_table * pt;
19639113 197
0f2d19dd
JB
198 pt = scm_add_to_port_table (port);
199 SCM_SETPTAB_ENTRY (port, pt);
a6c64c3c 200 SCM_SETCAR (port, scm_tc16_fport | scm_mode_bits (mode));
7471fb03 201 SCM_SETSTREAM (port, (SCM) f);
a6c64c3c 202 if (SCM_BUF0 & SCM_CAR (port))
0f2d19dd 203 scm_setbuf0 (port);
96937708 204 SCM_PTAB_ENTRY (port)->file_name = filename;
0f2d19dd 205 }
19639113 206 SCM_ALLOW_INTS;
0f2d19dd
JB
207 return port;
208}
209
a089567e
JB
210
211/* Build a Scheme port from an open stdio port, FILE.
212 MODE indicates whether FILE is open for reading or writing; it uses
213 the same notation as open-file's second argument.
214 If NAME is non-zero, use it as the port's filename.
215
216 scm_stdio_to_port sets the revealed count for FILE's file
217 descriptor to 1, so that FILE won't be closed when the port object
218 is GC'd. */
219SCM
220scm_stdio_to_port (file, mode, name)
221 FILE *file;
222 char *mode;
223 char *name;
224{
225 long mode_bits = scm_mode_bits (mode);
226 SCM port;
227 struct scm_port_table * pt;
228
229 SCM_NEWCELL (port);
230 SCM_DEFER_INTS;
231 {
232 pt = scm_add_to_port_table (port);
233 SCM_SETPTAB_ENTRY (port, pt);
234 SCM_SETCAR (port, (scm_tc16_fport | mode_bits));
7471fb03 235 SCM_SETSTREAM (port, (SCM) file);
a089567e
JB
236 if (SCM_BUF0 & SCM_CAR (port))
237 scm_setbuf0 (port);
a089567e
JB
238 SCM_PTAB_ENTRY (port)->file_name = scm_makfrom0str (name);
239 }
240 SCM_ALLOW_INTS;
241 scm_set_port_revealed_x (port, SCM_MAKINUM (1));
242 return port;
243}
244
245
1717856b
JB
246
247static int prinfport SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
248
0f2d19dd 249static int
1717856b 250prinfport (exp, port, pstate)
0f2d19dd
JB
251 SCM exp;
252 SCM port;
1717856b 253 scm_print_state *pstate;
0f2d19dd
JB
254{
255 SCM name;
256 char * c;
257 if (SCM_CLOSEDP (exp))
258 {
259 c = "file";
260 }
261 else
262 {
263 name = SCM_PTAB_ENTRY (exp)->file_name;
264 if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
265 c = SCM_ROCHARS (name);
266 else
267 c = "file";
268 }
19639113 269
0f2d19dd
JB
270 scm_prinport (exp, port, c);
271 return !0;
272}
273
274
1717856b
JB
275
276static int scm_fgetc SCM_P ((FILE * s));
277
0f2d19dd
JB
278static int
279scm_fgetc (s)
280 FILE * s;
0f2d19dd
JB
281{
282 if (feof (s))
283 return EOF;
284 else
285 return fgetc (s);
286}
287
3cb988bd
TP
288/*
289 * The fgets method must take a port as its argument, rather than
290 * the underlying file handle. The reason is that we also provide
291 * a generic fgets method for ports which can't use fgets(3) (e.g.
292 * string ports). This generic method calls the port's own
293 * fgetc method. In order for it to know how to get that method,
294 * we must pass the original Scheme port object.
295 */
296
848f2a01 297static char * scm_fgets SCM_P ((SCM port, int *len));
3cb988bd
TP
298
299static char *
848f2a01 300scm_fgets (port, len)
3cb988bd 301 SCM port;
848f2a01 302 int *len;
3cb988bd
TP
303{
304 FILE *f;
305
306 char *buf = NULL;
307 char *p; /* pointer to current buffer position */
3cb988bd 308 int limit = 80; /* current size of buffer */
3cb988bd 309
7a6f1ffa 310 f = (FILE *) SCM_STREAM (port);
3cb988bd
TP
311 if (feof (f))
312 return NULL;
313
3e2043c4 314 buf = (char *) malloc (limit * sizeof(char));
848f2a01 315 *len = 0;
3e2043c4
TP
316
317 /* If a char has been pushed onto the port with scm_ungetc,
318 read that first. */
319 if (SCM_CRDYP (port))
320 {
848f2a01 321 buf[*len] = SCM_CGETUN (port);
3e2043c4 322 SCM_CLRDY (port);
848f2a01 323 if (buf[(*len)++] == '\n')
3e2043c4 324 {
848f2a01 325 buf[*len] = '\0';
3e2043c4
TP
326 return buf;
327 }
328 }
3cb988bd 329
8122b543
TP
330 while (1)
331 {
848f2a01
TP
332 int chunk_size = limit - *len;
333 long int numread, pos;
8122b543 334
848f2a01
TP
335 p = buf + *len;
336
337 /* We must use ftell to figure out how many characters were read.
338 If there are null characters near the end of file, and no
339 terminating newline, there is no other way to tell the difference
340 between an embedded null and the string-terminating null. */
341
342 pos = ftell (f);
8122b543 343 if (fgets (p, chunk_size, f) == NULL) {
848f2a01 344 if (*len)
8122b543
TP
345 return buf;
346 free (buf);
347 return NULL;
348 }
848f2a01
TP
349 numread = ftell (f) - pos;
350 *len += numread;
3cb988bd 351
848f2a01 352 if (numread < chunk_size - 1 || buf[limit-2] == '\n')
8122b543 353 return buf;
3cb988bd 354
8122b543 355 buf = (char *) realloc (buf, sizeof(char) * limit * 2);
8122b543
TP
356 limit *= 2;
357 }
3cb988bd
TP
358}
359
0f2d19dd 360#ifdef vms
1717856b
JB
361
362static scm_sizet pwrite SCM_P ((char *ptr, scm_sizet size, nitems, FILE *port));
363
0f2d19dd
JB
364static scm_sizet
365pwrite (ptr, size, nitems, port)
366 char *ptr;
367 scm_sizet size, nitems;
368 FILE *port;
0f2d19dd
JB
369{
370 scm_sizet len = size * nitems;
371 scm_sizet i = 0;
372 for (; i < len; i++)
373 putc (ptr[i], port);
374 return len;
375}
376
377#define ffwrite pwrite
378#else
379#define ffwrite fwrite
380#endif
381
382\f
383/* This otherwise pointless code helps some poor
384 * crippled C compilers cope with life.
385 */
1717856b
JB
386
387static int local_fclose SCM_P ((FILE *fp));
388
0f2d19dd
JB
389static int
390local_fclose (fp)
391 FILE * fp;
392{
393 return fclose (fp);
394}
395
1717856b
JB
396static int local_fflush SCM_P ((FILE *fp));
397
0f2d19dd
JB
398static int
399local_fflush (fp)
400 FILE * fp;
401{
402 return fflush (fp);
403}
404
1717856b
JB
405static int local_fputc SCM_P ((int c, FILE *fp));
406
0f2d19dd
JB
407static int
408local_fputc (c, fp)
409 int c;
410 FILE * fp;
411{
412 return fputc (c, fp);
413}
414
1717856b
JB
415static int local_fputs SCM_P ((char *s, FILE *fp));
416
0f2d19dd
JB
417static int
418local_fputs (s, fp)
419 char * s;
420 FILE * fp;
421{
422 return fputs (s, fp);
423}
424
1717856b
JB
425static scm_sizet local_ffwrite SCM_P ((void *ptr, int size, int nitems, FILE *fp));
426
0f2d19dd
JB
427static scm_sizet
428local_ffwrite (ptr, size, nitems, fp)
429 void * ptr;
430 int size;
431 int nitems;
432 FILE * fp;
433{
434 return ffwrite (ptr, size, nitems, fp);
435}
436
8f29fbd0
JB
437static int
438print_pipe_port (SCM exp, SCM port, scm_print_state *pstate)
439{
440 scm_prinport (exp, port, "pipe");
441 return 1;
442}
443
444
445
6a2c4c81
JB
446/* On SunOS, there's no declaration for pclose in the headers, so
447 putting it directly in the initializer for scm_pipob doesn't really
448 fly. We could add an extern declaration for it, but then it'll
449 mismatch on some systems that do have a declaration. So we just
450 wrap it up this way. */
451static int
452local_pclose (fp)
453 FILE * fp;
454{
455 return pclose (fp);
456}
457
0f2d19dd
JB
458\f
459scm_ptobfuns scm_fptob =
460{
dc53f026 461 0,
1717856b 462 (int (*) SCM_P ((SCM))) local_fclose,
0f2d19dd
JB
463 prinfport,
464 0,
1717856b
JB
465 (int (*) SCM_P ((int, SCM))) local_fputc,
466 (int (*) SCM_P ((char *, SCM))) local_fputs,
467 (scm_sizet (*) SCM_P ((char *, scm_sizet, scm_sizet, SCM))) local_ffwrite,
468 (int (*) SCM_P ((SCM))) local_fflush,
469 (int (*) SCM_P ((SCM))) scm_fgetc,
848f2a01 470 (char * (*) SCM_P ((SCM, int *))) scm_fgets,
1717856b 471 (int (*) SCM_P ((SCM))) local_fclose
0f2d19dd
JB
472};
473
6a2c4c81 474/* {Pipe ports} */
0f2d19dd
JB
475scm_ptobfuns scm_pipob =
476{
dc53f026 477 0,
6a2c4c81 478 (int (*) SCM_P ((SCM))) local_pclose,
8f29fbd0 479 print_pipe_port,
0f2d19dd 480 0,
1717856b
JB
481 (int (*) SCM_P ((int, SCM))) local_fputc,
482 (int (*) SCM_P ((char *, SCM))) local_fputs,
483 (scm_sizet (*) SCM_P ((char *, scm_sizet, scm_sizet, SCM))) local_ffwrite,
484 (int (*) SCM_P ((SCM))) local_fflush,
485 (int (*) SCM_P ((SCM))) scm_fgetc,
37747447 486 (char * (*) SCM_P ((SCM, int *))) scm_generic_fgets,
6a2c4c81 487 (int (*) SCM_P ((SCM))) local_pclose
19468eff 488};
0f2d19dd 489
0f2d19dd
JB
490void
491scm_init_fports ()
0f2d19dd
JB
492{
493#include "fports.x"
7a6f1ffa
GH
494 scm_sysintern ("_IOFBF", SCM_MAKINUM (_IOFBF));
495 scm_sysintern ("_IOLBF", SCM_MAKINUM (_IOLBF));
496 scm_sysintern ("_IONBF", SCM_MAKINUM (_IONBF));
0f2d19dd 497}