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 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 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