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