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