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