xref: /plan9/sys/src/cmd/gs/src/ziodevsc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2001 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: ziodevsc.c,v 1.7 2004/08/04 19:36:13 stefan Exp $ */
18 /* %stdxxx IODevice implementation using callouts for PostScript interpreter */
19 #include "stdio_.h"
20 #include "ghost.h"
21 #include "gpcheck.h"
22 #include "oper.h"
23 #include "stream.h"
24 #include "gxiodev.h"		/* must come after stream.h */
25 				/* and before files.h */
26 #include "istream.h"
27 #include "files.h"
28 #include "ifilter.h"
29 #include "store.h"
30 
31 /* Define the special devices. */
32 const char iodev_dtype_stdio[] = "Special";
33 #define iodev_special(dname, init, open) {\
34     dname, iodev_dtype_stdio,\
35 	{ init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,\
36 	  iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,\
37 	  iodev_no_enumerate_files, NULL, NULL,\
38 	  iodev_no_get_params, iodev_no_put_params\
39 	}\
40 }
41 
42 /*
43  * We need the current context pointer for accessing / opening the %std
44  * IODevices.  However, this is not available to the open routine.
45  * Therefore, we use the hack of storing this pointer in the IODevice state
46  * pointer just before calling the open routines.  We clear the pointer
47  * immediately afterwards so as not to wind up with dangling references.
48  */
49 
50 #define STDIN_BUF_SIZE 128
51 private iodev_proc_init(stdin_init);
52 private iodev_proc_open_device(stdin_open);
53 const gx_io_device gs_iodev_stdin =
54     iodev_special("%stdin%", stdin_init, stdin_open);
55 
56 #define STDOUT_BUF_SIZE 128
57 private iodev_proc_open_device(stdout_open);
58 const gx_io_device gs_iodev_stdout =
59     iodev_special("%stdout%", iodev_no_init, stdout_open);
60 
61 #define STDERR_BUF_SIZE 128
62 private iodev_proc_open_device(stderr_open);
63 const gx_io_device gs_iodev_stderr =
64     iodev_special("%stderr%", iodev_no_init, stderr_open);
65 
66 /* ------- %stdin, %stdout, and %stderr ------ */
67 
68 /*
69  * According to Adobe, it is legal to close the %std... files and then
70  * re-open them later.  However, the re-opened file object is not 'eq' to
71  * the original file object (in our implementation, it has a different
72  * read_id or write_id).
73  */
74 
75 private int
stdio_close(stream * s)76 stdio_close(stream *s)
77 {
78     int code = (*s->save_close)(s);
79     if (code)
80 	return code;
81     /* Increment the IDs to prevent further access. */
82     s->read_id = s->write_id = (s->read_id | s->write_id) + 1;
83     return 0;
84 }
85 
86 private int
stdin_init(gx_io_device * iodev,gs_memory_t * mem)87 stdin_init(gx_io_device * iodev, gs_memory_t * mem)
88 {
89     mem->gs_lib_ctx->stdin_is_interactive = true;
90     return 0;
91 }
92 
93 /* stdin stream implemented as procedure */
94 private int
stdin_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)95 stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
96 	    gs_memory_t * mem)
97 {
98     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
99     stream *s;
100     int code;
101 
102     if (!streq1(access, 'r'))
103 	return_error(e_invalidfileaccess);
104     if (file_is_invalid(s, &ref_stdin)) {
105 	/* procedure source */
106 	gs_ref_memory_t *imem = (gs_ref_memory_t *)imemory_system;
107 	ref rint;
108 
109 	/* The procedure isn't used. */
110 	/* Set it to literal 0 to recognised stdin. */
111 	make_int(&rint, 0);
112 
113 	/* implement stdin as a procedure */
114 	code = sread_proc(&rint, &s, imem);
115 	if (code < 0)
116 	    return code;
117 	s->save_close = s_std_null;
118 	s->procs.close = stdio_close;
119 	/* allocate buffer */
120 	if (s->cbuf == 0) {
121 	    int len = STDIN_BUF_SIZE;
122 	    byte *buf = gs_alloc_bytes((gs_memory_t *)imemory_system,
123 	    		len, "stdin_open");
124 	    if (buf == 0)
125 		return_error(e_VMerror);
126 	    s->cbuf = buf;
127 	    s->srptr = s->srlimit = s->swptr = buf - 1;
128 	    s->swlimit = buf - 1 + len;
129 	    s->bsize = s->cbsize = len;
130 	}
131 	s->state->min_left = 0;
132 	make_file(&ref_stdin, a_read | avm_system, s->read_id, s);
133 	*ps = s;
134 	return 1;
135     }
136     *ps = s;
137     return 0;
138 }
139 /* This is the public routine for getting the stdin stream. */
140 int
zget_stdin(i_ctx_t * i_ctx_p,stream ** ps)141 zget_stdin(i_ctx_t *i_ctx_p, stream ** ps)
142 {
143     stream *s;
144     gx_io_device *iodev;
145     int code;
146 
147     if (file_is_valid(s, &ref_stdin)) {
148 	*ps = s;
149 	return 0;
150     }
151     iodev = gs_findiodevice((const byte *)"%stdin", 6);
152     iodev->state = i_ctx_p;
153     code = (*iodev->procs.open_device)(iodev, "r", ps, imemory_system);
154     iodev->state = NULL;
155     return min(code, 0);
156 }
157 /* Test whether a stream is stdin. */
158 bool
zis_stdin(const stream * s)159 zis_stdin(const stream *s)
160 {
161     /* Only stdin should be a procedure based stream, opened for
162      * reading and with a literal 0 as the procedure.
163      */
164     if (s_is_valid(s) && s_is_reading(s) && s_is_proc(s)) {
165         stream_proc_state *state = (stream_proc_state *)s->state;
166 	if ((r_type(&(state->proc)) == t_integer) &&
167 		(state->proc.value.intval == 0))
168 	    return true;
169     }
170     return false;
171 }
172 
173 /* stdout stream implemented as procedure */
174 private int
stdout_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)175 stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
176 	    gs_memory_t * mem)
177 {
178     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
179     stream *s;
180     int code;
181 
182     if (!streq1(access, 'w'))
183 	return_error(e_invalidfileaccess);
184     if (file_is_invalid(s, &ref_stdout)) {
185 	/* procedure source */
186 	gs_ref_memory_t *imem = (gs_ref_memory_t *)imemory_system;
187 	ref rint;
188 
189 	/* The procedure isn't used. */
190 	/* Set it to literal 1 to recognised stdout. */
191 	make_int(&rint, 1);
192 
193 	/* implement stdout as a procedure */
194 	code = swrite_proc(&rint, &s, imem);
195 	if (code < 0)
196 	    return code;
197 	s->save_close = s->procs.flush;
198 	s->procs.close = stdio_close;
199 	/* allocate buffer */
200 	if (s->cbuf == 0) {
201 	    int len = STDOUT_BUF_SIZE;
202 	    byte *buf = gs_alloc_bytes((gs_memory_t *)imemory_system,
203 	    		len, "stdout_open");
204 	    if (buf == 0)
205 		return_error(e_VMerror);
206 	    s->cbuf = buf;
207 	    s->srptr = s->srlimit = s->swptr = buf - 1;
208 	    s->swlimit = buf - 1 + len;
209 	    s->bsize = s->cbsize = len;
210 	}
211 	make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
212 	*ps = s;
213 	return 1;
214     }
215     *ps = s;
216     return 0;
217 }
218 /* This is the public routine for getting the stdout stream. */
219 int
zget_stdout(i_ctx_t * i_ctx_p,stream ** ps)220 zget_stdout(i_ctx_t *i_ctx_p, stream ** ps)
221 {
222     stream *s;
223     gx_io_device *iodev;
224     int code;
225 
226     if (file_is_valid(s, &ref_stdout)) {
227 	*ps = s;
228 	return 0;
229     }
230     iodev = gs_findiodevice((const byte *)"%stdout", 7);
231     iodev->state = i_ctx_p;
232     code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
233     iodev->state = NULL;
234     return min(code, 0);
235 }
236 
237 /* stderr stream implemented as procedure */
238 private int
stderr_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)239 stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
240 	    gs_memory_t * mem)
241 {
242     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
243     stream *s;
244     int code;
245 
246     if (!streq1(access, 'w'))
247 	return_error(e_invalidfileaccess);
248     if (file_is_invalid(s, &ref_stderr)) {
249 	/* procedure source */
250 	gs_ref_memory_t *imem = (gs_ref_memory_t *)imemory_system;
251 	ref rint;
252 
253 	/* The procedure isn't used. */
254 	/* Set it to literal 2 to recognised stderr. */
255 	make_int(&rint, 2);
256 
257 	/* implement stderr as a procedure */
258 	code = swrite_proc(&rint, &s, imem);
259 	if (code < 0)
260 	    return code;
261 	s->save_close = s->procs.flush;
262 	s->procs.close = stdio_close;
263 	/* allocate buffer */
264 	if (s->cbuf == 0) {
265 	    int len = STDERR_BUF_SIZE;
266 	    byte *buf = gs_alloc_bytes((gs_memory_t *)imemory_system,
267 	    		len, "stderr_open");
268 	    if (buf == 0)
269 		return_error(e_VMerror);
270 	    s->cbuf = buf;
271 	    s->srptr = s->srlimit = s->swptr = buf - 1;
272 	    s->swlimit = buf - 1 + len;
273 	    s->bsize = s->cbsize = len;
274 	}
275 	make_file(&ref_stderr, a_write | avm_system, s->write_id, s);
276 	*ps = s;
277 	return 1;
278     }
279     *ps = s;
280     return 0;
281 }
282 /* This is the public routine for getting the stderr stream. */
283 int
zget_stderr(i_ctx_t * i_ctx_p,stream ** ps)284 zget_stderr(i_ctx_t *i_ctx_p, stream ** ps)
285 {
286     stream *s;
287     gx_io_device *iodev;
288     int code;
289 
290     if (file_is_valid(s, &ref_stderr)) {
291 	*ps = s;
292 	return 0;
293     }
294     iodev = gs_findiodevice((const byte *)"%stderr", 7);
295     iodev->state = i_ctx_p;
296     code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
297     iodev->state = NULL;
298     return min(code, 0);
299 }
300