1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: ziodevsc.c 10455 2009-12-06 02:21:36Z alexcher $ */
15 /* %stdxxx IODevice implementation using callouts for PostScript interpreter */
16 #include "stdio_.h"
17 #include "ghost.h"
18 #include "gpcheck.h"
19 #include "gp.h"
20 #include "oper.h"
21 #include "stream.h"
22 #include "gxiodev.h"		/* must come after stream.h */
23 				/* and before files.h */
24 #include "istream.h"
25 #include "files.h"
26 #include "ifilter.h"
27 #include "store.h"
28 
29 /* Define the special devices. */
30 const char iodev_dtype_stdio[] = "Special";
31 #define iodev_special(dname, init, open) {\
32     dname, iodev_dtype_stdio,\
33 	{ init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,\
34 	  iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,\
35 	  iodev_no_enumerate_files, NULL, NULL,\
36 	  iodev_no_get_params, iodev_no_put_params\
37 	}\
38 }
39 
40 /*
41  * We need the current context pointer for accessing / opening the %std
42  * IODevices.  However, this is not available to the open routine.
43  * Therefore, we use the hack of storing this pointer in the IODevice state
44  * pointer just before calling the open routines.  We clear the pointer
45  * immediately afterwards so as not to wind up with dangling references.
46  */
47 
48 #define STDIN_BUF_SIZE 1024
49 static iodev_proc_init(stdin_init);
50 static iodev_proc_open_device(stdin_open);
51 const gx_io_device gs_iodev_stdin =
52     iodev_special("%stdin%", stdin_init, stdin_open);
53 
54 #define STDOUT_BUF_SIZE 128
55 static iodev_proc_open_device(stdout_open);
56 const gx_io_device gs_iodev_stdout =
57     iodev_special("%stdout%", iodev_no_init, stdout_open);
58 
59 #define STDERR_BUF_SIZE 128
60 static iodev_proc_open_device(stderr_open);
61 const gx_io_device gs_iodev_stderr =
62     iodev_special("%stderr%", iodev_no_init, stderr_open);
63 
64 /* ------- %stdin, %stdout, and %stderr ------ */
65 
66 /*
67  * According to Adobe, it is legal to close the %std... files and then
68  * re-open them later.  However, the re-opened file object is not 'eq' to
69  * the original file object (in our implementation, it has a different
70  * read_id or write_id). This is performed in 'file_close_file' by the
71  * call to file_close_disable.
72  */
73 
74 static int
75     s_stdin_read_process(stream_state *, stream_cursor_read *,
76 			 stream_cursor_write *, bool);
77 
78 static int
stdin_init(gx_io_device * iodev,gs_memory_t * mem)79 stdin_init(gx_io_device * iodev, gs_memory_t * mem)
80 {
81     mem->gs_lib_ctx->stdin_is_interactive = true;
82     return 0;
83 }
84 
85 /* Read from stdin into the buffer. */
86 /* If interactive, only read one character. */
87 static int
s_stdin_read_process(stream_state * st,stream_cursor_read * ignore_pr,stream_cursor_write * pw,bool last)88 s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
89 		     stream_cursor_write * pw, bool last)
90 {
91     int wcount = (int)(pw->limit - pw->ptr);
92     int count;
93     gs_memory_t *mem = st->memory;
94 
95     if (wcount <= 0)
96 	return 0;
97 
98     /* do the callout */
99     if (mem->gs_lib_ctx->stdin_fn)
100 	count = (*mem->gs_lib_ctx->stdin_fn)
101 	    (mem->gs_lib_ctx->caller_handle, (char *)pw->ptr + 1,
102 	     mem->gs_lib_ctx->stdin_is_interactive ? 1 : wcount);
103     else
104 	count = gp_stdin_read((char *)pw->ptr + 1, wcount,
105 		      mem->gs_lib_ctx->stdin_is_interactive,
106 		      mem->gs_lib_ctx->fstdin);
107 
108     pw->ptr += (count < 0) ? 0 : count;
109     return ((count < 0) ? ERRC : (count == 0) ? EOFC : count);
110 }
111 
112 static int
stdin_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)113 stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
114 	   gs_memory_t * mem)
115 {
116     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
117     stream *s;
118 
119     if (!streq1(access, 'r'))
120 	return_error(e_invalidfileaccess);
121     if (file_is_invalid(s, &ref_stdin)) {
122 	/****** stdin SHOULD NOT LINE-BUFFER ******/
123 	gs_memory_t *sysmem = imemory_system;
124 	byte *buf;
125 	static const stream_procs p = {
126 	    s_std_noavailable, s_std_noseek, s_std_read_reset,
127 	    s_std_read_flush, file_close_file, s_stdin_read_process
128 	};
129 
130 	s = file_alloc_stream(sysmem, "stdin_open(stream)");
131 
132 	/* We want stdin to read only one character at a time, */
133 	/* but it must have a substantial buffer, in case it is used */
134 	/* by a stream that requires more than one input byte */
135 	/* to make progress. */
136 	buf = gs_alloc_bytes(sysmem, STDIN_BUF_SIZE, "stdin_open(buffer)");
137 	if (s == 0 || buf == 0)
138 	    return_error(e_VMerror);
139 
140 	s_std_init(s, buf, STDIN_BUF_SIZE, &p, s_mode_read);
141 	s->file = 0;
142 	s->file_modes = s->modes;
143 	s->file_offset = 0;
144 	s->file_limit = max_long;
145 	s->save_close = s_std_null;
146 	make_file(&ref_stdin, a_readonly | avm_system, s->read_id, s);
147 	*ps = s;
148 	return 1;
149     }
150     *ps = s;
151     return 0;
152 }
153 /* This is the public routine for getting the stdin stream. */
154 int
zget_stdin(i_ctx_t * i_ctx_p,stream ** ps)155 zget_stdin(i_ctx_t *i_ctx_p, stream ** ps)
156 {
157     stream *s;
158     gx_io_device *iodev;
159     int code;
160 
161     if (file_is_valid(s, &ref_stdin)) {
162 	*ps = s;
163 	return 0;
164     }
165     iodev = gs_findiodevice((const byte *)"%stdin", 6);
166     iodev->state = i_ctx_p;
167     code = (*iodev->procs.open_device)(iodev, "r", ps, imemory_system);
168     iodev->state = NULL;
169     return min(code, 0);
170 }
171 
172 /* Test whether a stream is stdin. */
173 bool
zis_stdin(const stream * s)174 zis_stdin(const stream *s)
175 {
176     return (s_is_valid(s) && s->procs.process == s_stdin_read_process);
177 }
178 
179 /* Write a buffer to stdout, potentially writing to callback */
180 static int
s_stdout_write_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * ignore_pw,bool last)181 s_stdout_write_process(stream_state * st, stream_cursor_read *pr,
182 		     stream_cursor_write *ignore_pw, bool last)
183 {
184     uint count = pr->limit - pr->ptr;
185     int written;
186 
187     if (count == 0)
188 	return 0;
189     written = outwrite(st->memory, (const char *)pr->ptr + 1, count);
190     if (written < count)
191 	return ERRC;
192     pr->ptr += written;
193     return 0;
194 }
195 
196 static int
stdout_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)197 stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
198 	    gs_memory_t * mem)
199 {
200     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
201     stream *s;
202 
203     if (!streq1(access, 'w'))
204 	return_error(e_invalidfileaccess);
205     if (file_is_invalid(s, &ref_stdout)) {
206 	gs_memory_t *sysmem = imemory_system;
207 	byte *buf;
208 	static const stream_procs p = {
209 	    s_std_noavailable, s_std_noseek, s_std_write_reset,
210 	    s_std_write_flush, file_close_file, s_stdout_write_process
211 	};
212 
213 	s = file_alloc_stream(sysmem, "stdout_open(stream)");
214 	buf = gs_alloc_bytes(sysmem, STDOUT_BUF_SIZE, "stdout_open(buffer)");
215 	if (s == 0 || buf == 0)
216 	    return_error(e_VMerror);
217 	s_std_init(s, buf, STDOUT_BUF_SIZE, &p, s_mode_write);
218 	s->file = 0;
219 	s->file_modes = s->modes;
220 	s->file_offset = 0;		/* in case we switch to reading later */
221 	s->file_limit = max_long;	/* ibid. */
222 	s->save_close = s->procs.flush;
223 	make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
224 	*ps = s;
225 	return 1;
226     }
227     *ps = s;
228     return 0;
229 }
230 
231 /* This is the public routine for getting the stdout stream. */
232 int
zget_stdout(i_ctx_t * i_ctx_p,stream ** ps)233 zget_stdout(i_ctx_t *i_ctx_p, stream ** ps)
234 {
235     stream *s;
236     gx_io_device *iodev;
237     int code;
238 
239     if (file_is_valid(s, &ref_stdout)) {
240 	*ps = s;
241 	return 0;
242     }
243     iodev = gs_findiodevice((const byte *)"%stdout", 7);
244     iodev->state = i_ctx_p;
245     code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
246     iodev->state = NULL;
247     return min(code, 0);
248 }
249 
250 /* Write a buffer to stderr, potentially writing to callback */
251 static int
s_stderr_write_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * ignore_pw,bool last)252 s_stderr_write_process(stream_state * st, stream_cursor_read *pr,
253 		     stream_cursor_write *ignore_pw, bool last)
254 {
255     uint count = pr->limit - pr->ptr;
256     int written;
257 
258     if (count == 0)
259 	return 0;
260     written = errwrite((const char *)(pr->ptr + 1), count);
261     if (written < count)
262 	return ERRC;
263     pr->ptr += written;
264     return 0;
265 }
266 
267 static int
stderr_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)268 stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
269 	    gs_memory_t * mem)
270 {
271     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
272     stream *s;
273 
274     if (!streq1(access, 'w'))
275 	return_error(e_invalidfileaccess);
276     if (file_is_invalid(s, &ref_stderr)) {
277 	gs_memory_t *sysmem = imemory_system;
278 	byte *buf;
279 	static const stream_procs p = {
280 	    s_std_noavailable, s_std_noseek, s_std_write_reset,
281 	    s_std_write_flush, file_close_file, s_stderr_write_process
282 	};
283 
284 	s = file_alloc_stream(sysmem, "stderr_open(stream)");
285 	buf = gs_alloc_bytes(sysmem, STDERR_BUF_SIZE, "stderr_open(buffer)");
286 	if (s == 0 || buf == 0)
287 	    return_error(e_VMerror);
288 	s_std_init(s, buf, STDERR_BUF_SIZE, &p, s_mode_write);
289 	s->file = 0;
290 	s->file_modes = s->modes;
291 	s->file_offset = 0;		/* in case we switch to reading later */
292 	s->file_limit = max_long;	/* ibid. */
293 	s->save_close = s->procs.flush;
294 	make_file(&ref_stderr, a_write | avm_system, s->write_id, s);
295 	*ps = s;
296 	return 1;
297     }
298     *ps = s;
299     return 0;
300 }
301 
302 /* This is the public routine for getting the stderr stream. */
303 int
zget_stderr(i_ctx_t * i_ctx_p,stream ** ps)304 zget_stderr(i_ctx_t *i_ctx_p, stream ** ps)
305 {
306     stream *s;
307     gx_io_device *iodev;
308     int code;
309 
310     if (file_is_valid(s, &ref_stderr)) {
311 	*ps = s;
312 	return 0;
313     }
314     iodev = gs_findiodevice((const byte *)"%stderr", 7);
315     iodev->state = i_ctx_p;
316     code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
317     iodev->state = NULL;
318     return min(code, 0);
319 }
320