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: ziodevs.c 9043 2008-08-28 22:48:19Z giles $ */
15 /* %stdxxx IODevice implementation for PostScript interpreter */
16 #include "stdio_.h"
17 #include "ghost.h"
18 #include "gp.h"
19 #include "gpcheck.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 "files.h"
25 #include "store.h"
26
27 /* Define the special devices. */
28 const char iodev_dtype_stdio[] = "Special";
29 #define iodev_special(dname, init, open) {\
30 dname, iodev_dtype_stdio,\
31 { init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,\
32 iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,\
33 iodev_no_enumerate_files, NULL, NULL,\
34 iodev_no_get_params, iodev_no_put_params\
35 }\
36 }
37
38 /*
39 * We need the current context pointer for accessing / opening the %std
40 * IODevices. However, this is not available to the open routine.
41 * Therefore, we use the hack of storing this pointer in the IODevice state
42 * pointer just before calling the open routines. We clear the pointer
43 * immediately afterwards so as not to wind up with dangling references.
44 */
45
46 #define STDIN_BUF_SIZE 1024
47
48 static iodev_proc_init(stdin_init);
49 static iodev_proc_open_device(stdin_open);
50 const gx_io_device gs_iodev_stdin =
51 iodev_special("%stdin%", stdin_init, stdin_open);
52
53 #define STDOUT_BUF_SIZE 128
54 static iodev_proc_open_device(stdout_open);
55 const gx_io_device gs_iodev_stdout =
56 iodev_special("%stdout%", iodev_no_init, stdout_open);
57
58 #define STDERR_BUF_SIZE 128
59 static iodev_proc_open_device(stderr_open);
60 const gx_io_device gs_iodev_stderr =
61 iodev_special("%stderr%", iodev_no_init, stderr_open);
62
63 /* ------- %stdin, %stdout, and %stderr ------ */
64
65 /*
66 * According to Adobe, it is legal to close the %std... files and then
67 * re-open them later. However, the re-opened file object is not 'eq' to
68 * the original file object (in our implementation, it has a different
69 * read_id or write_id).
70 */
71
72 static int
73 s_stdin_read_process(stream_state *, stream_cursor_read *,
74 stream_cursor_write *, bool);
75
76 static int
stdin_init(gx_io_device * iodev,gs_memory_t * mem)77 stdin_init(gx_io_device * iodev, gs_memory_t * mem)
78 {
79 mem->gs_lib_ctx->stdin_is_interactive = true;
80 return 0;
81 }
82
83 /* Read from stdin into the buffer. */
84 /* If interactive, only read one character. */
85 static int
s_stdin_read_process(stream_state * st,stream_cursor_read * ignore_pr,stream_cursor_write * pw,bool last)86 s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
87 stream_cursor_write * pw, bool last)
88 {
89 FILE *file = ((stream *) st)->file; /* hack for file streams */
90 int wcount = (int)(pw->limit - pw->ptr);
91 int count;
92
93 if (wcount <= 0)
94 return 0;
95 count = gp_stdin_read( (char*) pw->ptr + 1, wcount,
96 st->memory->gs_lib_ctx->stdin_is_interactive, file);
97 pw->ptr += (count < 0) ? 0 : count;
98 return ((count < 0) ? ERRC : (count == 0) ? EOFC : count);
99 }
100
101 static int
stdin_open(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)102 stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
103 gs_memory_t * mem)
104 {
105 i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state; /* see above */
106 stream *s;
107
108 if (!streq1(access, 'r'))
109 return_error(e_invalidfileaccess);
110 if (file_is_invalid(s, &ref_stdin)) {
111 /****** stdin SHOULD NOT LINE-BUFFER ******/
112 gs_memory_t *mem = imemory_system;
113 byte *buf;
114
115 s = file_alloc_stream(mem, "stdin_open(stream)");
116 /* We want stdin to read only one character at a time, */
117 /* but it must have a substantial buffer, in case it is used */
118 /* by a stream that requires more than one input byte */
119 /* to make progress. */
120 buf = gs_alloc_bytes(mem, STDIN_BUF_SIZE, "stdin_open(buffer)");
121 if (s == 0 || buf == 0)
122 return_error(e_VMerror);
123 sread_file(s, gs_stdin, buf, STDIN_BUF_SIZE);
124 s->procs.process = s_stdin_read_process;
125 s->save_close = s_std_null;
126 s->procs.close = file_close_file;
127 make_file(&ref_stdin, a_readonly | avm_system, s->read_id, s);
128 *ps = s;
129 return 1;
130 }
131 *ps = s;
132 return 0;
133 }
134 /* This is the public routine for getting the stdin stream. */
135 int
zget_stdin(i_ctx_t * i_ctx_p,stream ** ps)136 zget_stdin(i_ctx_t *i_ctx_p, stream ** ps)
137 {
138 stream *s;
139 gx_io_device *iodev;
140 int code;
141
142 if (file_is_valid(s, &ref_stdin)) {
143 *ps = s;
144 return 0;
145 }
146 iodev = gs_findiodevice((const byte *)"%stdin", 6);
147 iodev->state = i_ctx_p;
148 code = (*iodev->procs.open_device)(iodev, "r", ps, imemory_system);
149 iodev->state = NULL;
150 return min(code, 0);
151 }
152 /* Test whether a stream is stdin. */
153 bool
zis_stdin(const stream * s)154 zis_stdin(const stream *s)
155 {
156 return (s_is_valid(s) && s->procs.process == s_stdin_read_process);
157 }
158
159 static int
160 s_stdout_swrite_process(stream_state *, stream_cursor_read *,
161 stream_cursor_write *, bool);
162
163 /* Write a buffer to stdout, potentially writing to callback */
164 static int
s_stdout_write_process(stream_state * st,stream_cursor_read * ignore_pr,stream_cursor_write * pw,bool last)165 s_stdout_write_process(stream_state * st, stream_cursor_read * ignore_pr,
166 stream_cursor_write * pw, bool last)
167 {
168 uint count = pr->limit - pr->ptr;
169 int written;
170
171 if (count == 0)
172 return 0;
173 written = outwrite(st->memory, pr->ptr + 1, count);
174 if (written < count) {
175 return ERRC;
176 pr->ptr += written;
177 return 0;
178 }
179
180 static int
181 stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
182 gs_memory_t * mem)
183 {
184 i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state; /* see above */
185 stream *s;
186
187 if (!streq1(access, 'w'))
188 return_error(e_invalidfileaccess);
189 if (file_is_invalid(s, &ref_stdout)) {
190 gs_memory_t *mem = imemory_system;
191 byte *buf;
192
193 s = file_alloc_stream(mem, "stdout_open(stream)");
194 buf = gs_alloc_bytes(mem, STDOUT_BUF_SIZE, "stdout_open(buffer)");
195 if (s == 0 || buf == 0)
196 return_error(e_VMerror);
197 swrite_file(s, gs_stdout, buf, STDOUT_BUF_SIZE);
198 s->save_close = s->procs.flush;
199 s->procs.close = file_close_file;
200 s->procs.process = s_stdout_write_process;
201 make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
202 *ps = s;
203 return 1;
204 }
205 *ps = s;
206 return 0;
207 }
208 /* This is the public routine for getting the stdout stream. */
209 int
210 zget_stdout(i_ctx_t *i_ctx_p, stream ** ps)
211 {
212 stream *s;
213 gx_io_device *iodev;
214 int code;
215
216 if (file_is_valid(s, &ref_stdout)) {
217 *ps = s;
218 return 0;
219 }
220 iodev = gs_findiodevice((const byte *)"%stdout", 7);
221 iodev->state = i_ctx_p;
222 code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
223 iodev->state = NULL;
224 return min(code, 0);
225 }
226
227 static int
228 stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
229 gs_memory_t * mem)
230 {
231 i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state; /* see above */
232 stream *s;
233
234 if (!streq1(access, 'w'))
235 return_error(e_invalidfileaccess);
236 if (file_is_invalid(s, &ref_stderr)) {
237 gs_memory_t *mem = imemory_system;
238 byte *buf;
239
240 s = file_alloc_stream(mem, "stderr_open(stream)");
241 buf = gs_alloc_bytes(mem, STDERR_BUF_SIZE, "stderr_open(buffer)");
242 if (s == 0 || buf == 0)
243 return_error(e_VMerror);
244 swrite_file(s, gs_stderr, buf, STDERR_BUF_SIZE);
245 s->save_close = s->procs.flush;
246 s->procs.close = file_close_file;
247 make_file(&ref_stderr, a_write | avm_system, s->write_id, s);
248 *ps = s;
249 return 1;
250 }
251 *ps = s;
252 return 0;
253 }
254 /* This is the public routine for getting the stderr stream. */
255 int
256 zget_stderr(i_ctx_t *i_ctx_p, stream ** ps)
257 {
258 stream *s;
259 gx_io_device *iodev;
260 int code;
261
262 if (file_is_valid(s, &ref_stderr)) {
263 *ps = s;
264 return 0;
265 }
266 iodev = gs_findiodevice((const byte *)"%stderr", 7);
267 iodev->state = i_ctx_p;
268 code = (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
269 iodev->state = NULL;
270 return min(code, 0);
271 }
272