xref: /plan9/sys/src/cmd/gs/src/ziodevs.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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