1 /* Copyright (C) 1993, 1995, 1997, 1998, 1999, 2001 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: ziodev.c,v 1.13 2003/09/03 03:22:59 giles Exp $ */
18 /* Standard IODevice implementation */
19 #include "memory_.h"
20 #include "stdio_.h"
21 #include "string_.h"
22 #include "ghost.h"
23 #include "gp.h"
24 #include "gpcheck.h"
25 #include "oper.h"
26 #include "stream.h"
27 #include "istream.h"
28 #include "ialloc.h"
29 #include "iscan.h"
30 #include "ivmspace.h"
31 #include "gxiodev.h" /* must come after stream.h */
32 /* and before files.h */
33 #include "files.h"
34 #include "scanchar.h" /* for char_EOL */
35 #include "store.h"
36 #include "ierrors.h"
37
38 /* Import the dtype of the stdio IODevices. */
39 extern const char iodev_dtype_stdio[];
40
41 /* Define the special devices. */
42 #define iodev_special(dname, init, open) {\
43 dname, iodev_dtype_stdio,\
44 { init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,\
45 iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,\
46 iodev_no_enumerate_files, NULL, NULL,\
47 iodev_no_get_params, iodev_no_put_params\
48 }\
49 }
50
51 /*
52 * We need the current context pointer for accessing / opening the %std
53 * IODevices. However, this is not available to the open routine.
54 * Therefore, we use the hack of storing this pointer in the IODevice state
55 * pointer just before calling the open routines. We clear the pointer
56 * immediately afterwards so as not to wind up with dangling references.
57 */
58
59 #define LINEEDIT_BUF_SIZE 20 /* initial size, not fixed size */
60 /*private iodev_proc_open_device(lineedit_open);*/ /* no longer used */
61 const gx_io_device gs_iodev_lineedit =
62 iodev_special("%lineedit%", iodev_no_init, iodev_no_open_device);
63
64 #define STATEMENTEDIT_BUF_SIZE 50 /* initial size, not fixed size */
65 /*private iodev_proc_open_device(statementedit_open);*/ /* no longer used */
66 const gx_io_device gs_iodev_statementedit =
67 iodev_special("%statementedit%", iodev_no_init, iodev_no_open_device);
68
69 /* ------ Operators ------ */
70
71 /* <int> .getiodevice <string|null> */
72 private int
zgetiodevice(i_ctx_t * i_ctx_p)73 zgetiodevice(i_ctx_t *i_ctx_p)
74 {
75 os_ptr op = osp;
76 gx_io_device *iodev;
77 const byte *dname;
78
79 check_type(*op, t_integer);
80 if (op->value.intval != (int)op->value.intval)
81 return_error(e_rangecheck);
82 iodev = gs_getiodevice((int)(op->value.intval));
83 if (iodev == 0) /* index out of range */
84 return_error(e_rangecheck);
85 dname = (const byte *)iodev->dname;
86 if (dname == 0)
87 make_null(op);
88 else
89 make_const_string(op, a_readonly | avm_foreign,
90 strlen((const char *)dname), dname);
91 return 0;
92 }
93
94 /* ------ %lineedit and %statementedit ------ */
95
96 /* <file> <bool> <int> <string> .filelineedit <file> */
97 /* This opens %statementedit% or %lineedit% and is also the
98 * continuation proc for callouts.
99 * Input:
100 * string is the statement/line buffer,
101 * int is the write index into string
102 * bool is true if %statementedit%
103 * file is stdin
104 * Output:
105 * file is a string based stream
106 * We store the line being read in a PostScript string.
107 * This limits the size to max_string_size (64k).
108 * This could be increased by storing the input line in something
109 * other than a PostScript string.
110 */
111 int
zfilelineedit(i_ctx_t * i_ctx_p)112 zfilelineedit(i_ctx_t *i_ctx_p)
113 {
114 uint count = 0;
115 bool in_eol = false;
116 int code;
117 os_ptr op = osp;
118 bool statement;
119 stream *s;
120 stream *ins;
121 gs_string str;
122 uint initial_buf_size;
123 const char *filename;
124 /*
125 * buf exists only for stylistic parallelism: all occurrences of
126 * buf-> could just as well be str. .
127 */
128 gs_string *const buf = &str;
129
130 check_type(*op, t_string); /* line assembled so far */
131 buf->data = op->value.bytes;
132 buf->size = op->tas.rsize;
133 check_type(*(op-1), t_integer); /* index */
134 count = (op-1)->value.intval;
135 check_type(*(op-2), t_boolean); /* statementedit/lineedit */
136 statement = (op-2)->value.boolval;
137 check_read_file(ins, op - 3); /* %stdin */
138
139 /* extend string */
140 initial_buf_size = statement ? STATEMENTEDIT_BUF_SIZE : LINEEDIT_BUF_SIZE;
141 if (initial_buf_size > max_string_size)
142 return_error(e_limitcheck);
143 if (!buf->data || (buf->size < initial_buf_size)) {
144 count = 0;
145 buf->data = gs_alloc_string(imemory, initial_buf_size,
146 "zfilelineedit(buffer)");
147 if (buf->data == 0)
148 return_error(e_VMerror);
149 op->value.bytes = buf->data;
150 op->tas.rsize = buf->size = initial_buf_size;
151 }
152
153 rd:
154 code = zreadline_from(ins, buf, imemory, &count, &in_eol);
155 if (buf->size > max_string_size) {
156 /* zreadline_from reallocated the buffer larger than
157 * is valid for a PostScript string.
158 * Return an error, but first realloc the buffer
159 * back to a legal size.
160 */
161 byte *nbuf = gs_resize_string(imemory, buf->data, buf->size,
162 max_string_size, "zfilelineedit(shrink buffer)");
163 if (nbuf == 0)
164 return_error(e_VMerror);
165 op->value.bytes = buf->data = nbuf;
166 op->tas.rsize = buf->size = max_string_size;
167 return_error(e_limitcheck);
168 }
169
170 op->value.bytes = buf->data; /* zreadline_from sometimes resizes the buffer. */
171 op->tas.rsize = buf->size;
172
173 switch (code) {
174 case EOFC:
175 code = gs_note_error(e_undefinedfilename);
176 /* falls through */
177 case 0:
178 break;
179 default:
180 code = gs_note_error(e_ioerror);
181 break;
182 case CALLC:
183 {
184 ref rfile;
185 (op-1)->value.intval = count;
186 /* callout is for stdin */
187 make_file(&rfile, a_readonly | avm_system, ins->read_id, ins);
188 code = s_handle_read_exception(i_ctx_p, code, &rfile,
189 NULL, 0, zfilelineedit);
190 }
191 break;
192 case 1: /* filled buffer */
193 {
194 uint nsize = buf->size;
195 byte *nbuf;
196
197 if (nsize >= max_string_size) {
198 code = gs_note_error(e_limitcheck);
199 break;
200 }
201 else if (nsize >= max_string_size / 2)
202 nsize= max_string_size;
203 else
204 nsize = buf->size * 2;
205 nbuf = gs_resize_string(imemory, buf->data, buf->size, nsize,
206 "zfilelineedit(grow buffer)");
207 if (nbuf == 0) {
208 code = gs_note_error(e_VMerror);
209 break;
210 }
211 op->value.bytes = buf->data = nbuf;
212 op->tas.rsize = buf->size = nsize;
213 goto rd;
214 }
215 }
216 if (code != 0)
217 return code;
218 if (statement) {
219 /* If we don't have a complete token, keep going. */
220 stream st;
221 stream *ts = &st;
222 scanner_state state;
223 ref ignore_value;
224 uint depth = ref_stack_count(&o_stack);
225 int code;
226
227 /* Add a terminating EOL. */
228 if (count + 1 > buf->size) {
229 uint nsize;
230 byte *nbuf;
231
232 nsize = buf->size + 1;
233 if (nsize > max_string_size) {
234 return_error(gs_note_error(e_limitcheck));
235 }
236 else {
237 nbuf = gs_resize_string(imemory, buf->data, buf->size, nsize,
238 "zfilelineedit(grow buffer)");
239 if (nbuf == 0) {
240 code = gs_note_error(e_VMerror);
241 return_error(code);
242 }
243 op->value.bytes = buf->data = nbuf;
244 op->tas.rsize = buf->size = nsize;
245 }
246 }
247 buf->data[count++] = char_EOL;
248 s_init(ts, NULL);
249 sread_string(ts, buf->data, count);
250 sc:
251 scanner_state_init_check(&state, false, true);
252 code = scan_token(i_ctx_p, ts, &ignore_value, &state);
253 ref_stack_pop_to(&o_stack, depth);
254 if (code < 0)
255 code = scan_EOF; /* stop on scanner error */
256 switch (code) {
257 case 0: /* read a token */
258 case scan_BOS:
259 goto sc; /* keep going until we run out of data */
260 case scan_Refill:
261 goto rd;
262 case scan_EOF:
263 break;
264 default: /* error */
265 return code;
266 }
267 }
268 buf->data = gs_resize_string(imemory, buf->data, buf->size, count,
269 "zfilelineedit(resize buffer)");
270 if (buf->data == 0)
271 return_error(e_VMerror);
272 op->value.bytes = buf->data;
273 op->tas.rsize = buf->size;
274
275 s = file_alloc_stream(imemory, "zfilelineedit(stream)");
276 if (s == 0)
277 return_error(e_VMerror);
278
279 sread_string(s, buf->data, count);
280 s->save_close = s->procs.close;
281 s->procs.close = file_close_disable;
282
283 filename = statement ? gs_iodev_statementedit.dname
284 : gs_iodev_lineedit.dname;
285 code = ssetfilename(s, (const byte *)filename, strlen(filename)+1);
286 if (code < 0) {
287 sclose(s);
288 return_error(e_VMerror);
289 }
290
291 pop(3);
292 make_stream_file(osp, s, "r");
293
294 return code;
295 }
296
297 /* ------ Initialization procedure ------ */
298
299 const op_def ziodev_op_defs[] =
300 {
301 {"1.getiodevice", zgetiodevice},
302 op_def_end(0)
303 };
304