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