13ff48bf5SDavid du Colombier /* Copyright (C) 1993, 1995, 1997, 1998, 1999, 2001 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: ziodev.c,v 1.13 2003/09/03 03:22:59 giles Exp $ */
187dd7cddfSDavid du Colombier /* Standard IODevice implementation */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "stdio_.h"
217dd7cddfSDavid du Colombier #include "string_.h"
227dd7cddfSDavid du Colombier #include "ghost.h"
237dd7cddfSDavid du Colombier #include "gp.h"
247dd7cddfSDavid du Colombier #include "gpcheck.h"
257dd7cddfSDavid du Colombier #include "oper.h"
267dd7cddfSDavid du Colombier #include "stream.h"
273ff48bf5SDavid du Colombier #include "istream.h"
287dd7cddfSDavid du Colombier #include "ialloc.h"
297dd7cddfSDavid du Colombier #include "iscan.h"
307dd7cddfSDavid du Colombier #include "ivmspace.h"
317dd7cddfSDavid du Colombier #include "gxiodev.h" /* must come after stream.h */
327dd7cddfSDavid du Colombier /* and before files.h */
337dd7cddfSDavid du Colombier #include "files.h"
347dd7cddfSDavid du Colombier #include "scanchar.h" /* for char_EOL */
357dd7cddfSDavid du Colombier #include "store.h"
36*593dc095SDavid du Colombier #include "ierrors.h"
377dd7cddfSDavid du Colombier
383ff48bf5SDavid du Colombier /* Import the dtype of the stdio IODevices. */
393ff48bf5SDavid du Colombier extern const char iodev_dtype_stdio[];
403ff48bf5SDavid du Colombier
417dd7cddfSDavid du Colombier /* Define the special devices. */
427dd7cddfSDavid du Colombier #define iodev_special(dname, init, open) {\
437dd7cddfSDavid du Colombier dname, iodev_dtype_stdio,\
447dd7cddfSDavid du Colombier { init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,\
457dd7cddfSDavid du Colombier iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,\
467dd7cddfSDavid du Colombier iodev_no_enumerate_files, NULL, NULL,\
477dd7cddfSDavid du Colombier iodev_no_get_params, iodev_no_put_params\
487dd7cddfSDavid du Colombier }\
497dd7cddfSDavid du Colombier }
507dd7cddfSDavid du Colombier
517dd7cddfSDavid du Colombier /*
527dd7cddfSDavid du Colombier * We need the current context pointer for accessing / opening the %std
537dd7cddfSDavid du Colombier * IODevices. However, this is not available to the open routine.
547dd7cddfSDavid du Colombier * Therefore, we use the hack of storing this pointer in the IODevice state
557dd7cddfSDavid du Colombier * pointer just before calling the open routines. We clear the pointer
567dd7cddfSDavid du Colombier * immediately afterwards so as not to wind up with dangling references.
577dd7cddfSDavid du Colombier */
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier #define LINEEDIT_BUF_SIZE 20 /* initial size, not fixed size */
60*593dc095SDavid du Colombier /*private iodev_proc_open_device(lineedit_open);*/ /* no longer used */
617dd7cddfSDavid du Colombier const gx_io_device gs_iodev_lineedit =
623ff48bf5SDavid du Colombier iodev_special("%lineedit%", iodev_no_init, iodev_no_open_device);
637dd7cddfSDavid du Colombier
647dd7cddfSDavid du Colombier #define STATEMENTEDIT_BUF_SIZE 50 /* initial size, not fixed size */
65*593dc095SDavid du Colombier /*private iodev_proc_open_device(statementedit_open);*/ /* no longer used */
667dd7cddfSDavid du Colombier const gx_io_device gs_iodev_statementedit =
673ff48bf5SDavid du Colombier iodev_special("%statementedit%", iodev_no_init, iodev_no_open_device);
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier /* ------ Operators ------ */
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier /* <int> .getiodevice <string|null> */
727dd7cddfSDavid du Colombier private int
zgetiodevice(i_ctx_t * i_ctx_p)737dd7cddfSDavid du Colombier zgetiodevice(i_ctx_t *i_ctx_p)
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier os_ptr op = osp;
767dd7cddfSDavid du Colombier gx_io_device *iodev;
777dd7cddfSDavid du Colombier const byte *dname;
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier check_type(*op, t_integer);
807dd7cddfSDavid du Colombier if (op->value.intval != (int)op->value.intval)
817dd7cddfSDavid du Colombier return_error(e_rangecheck);
827dd7cddfSDavid du Colombier iodev = gs_getiodevice((int)(op->value.intval));
837dd7cddfSDavid du Colombier if (iodev == 0) /* index out of range */
847dd7cddfSDavid du Colombier return_error(e_rangecheck);
857dd7cddfSDavid du Colombier dname = (const byte *)iodev->dname;
867dd7cddfSDavid du Colombier if (dname == 0)
877dd7cddfSDavid du Colombier make_null(op);
887dd7cddfSDavid du Colombier else
897dd7cddfSDavid du Colombier make_const_string(op, a_readonly | avm_foreign,
907dd7cddfSDavid du Colombier strlen((const char *)dname), dname);
917dd7cddfSDavid du Colombier return 0;
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier /* ------ %lineedit and %statementedit ------ */
957dd7cddfSDavid du Colombier
963ff48bf5SDavid du Colombier /* <file> <bool> <int> <string> .filelineedit <file> */
973ff48bf5SDavid du Colombier /* This opens %statementedit% or %lineedit% and is also the
983ff48bf5SDavid du Colombier * continuation proc for callouts.
993ff48bf5SDavid du Colombier * Input:
1003ff48bf5SDavid du Colombier * string is the statement/line buffer,
1013ff48bf5SDavid du Colombier * int is the write index into string
1023ff48bf5SDavid du Colombier * bool is true if %statementedit%
1033ff48bf5SDavid du Colombier * file is stdin
1043ff48bf5SDavid du Colombier * Output:
1053ff48bf5SDavid du Colombier * file is a string based stream
1063ff48bf5SDavid du Colombier * We store the line being read in a PostScript string.
1073ff48bf5SDavid du Colombier * This limits the size to max_string_size (64k).
1083ff48bf5SDavid du Colombier * This could be increased by storing the input line in something
1093ff48bf5SDavid du Colombier * other than a PostScript string.
1103ff48bf5SDavid du Colombier */
1113ff48bf5SDavid du Colombier int
zfilelineedit(i_ctx_t * i_ctx_p)1123ff48bf5SDavid du Colombier zfilelineedit(i_ctx_t *i_ctx_p)
1137dd7cddfSDavid du Colombier {
1147dd7cddfSDavid du Colombier uint count = 0;
1157dd7cddfSDavid du Colombier bool in_eol = false;
1167dd7cddfSDavid du Colombier int code;
1173ff48bf5SDavid du Colombier os_ptr op = osp;
1183ff48bf5SDavid du Colombier bool statement;
1197dd7cddfSDavid du Colombier stream *s;
1207dd7cddfSDavid du Colombier stream *ins;
1217dd7cddfSDavid du Colombier gs_string str;
1223ff48bf5SDavid du Colombier uint initial_buf_size;
1233ff48bf5SDavid du Colombier const char *filename;
1247dd7cddfSDavid du Colombier /*
1257dd7cddfSDavid du Colombier * buf exists only for stylistic parallelism: all occurrences of
1267dd7cddfSDavid du Colombier * buf-> could just as well be str. .
1277dd7cddfSDavid du Colombier */
1287dd7cddfSDavid du Colombier gs_string *const buf = &str;
1297dd7cddfSDavid du Colombier
1303ff48bf5SDavid du Colombier check_type(*op, t_string); /* line assembled so far */
1313ff48bf5SDavid du Colombier buf->data = op->value.bytes;
1323ff48bf5SDavid du Colombier buf->size = op->tas.rsize;
1333ff48bf5SDavid du Colombier check_type(*(op-1), t_integer); /* index */
1343ff48bf5SDavid du Colombier count = (op-1)->value.intval;
1353ff48bf5SDavid du Colombier check_type(*(op-2), t_boolean); /* statementedit/lineedit */
1363ff48bf5SDavid du Colombier statement = (op-2)->value.boolval;
1373ff48bf5SDavid du Colombier check_read_file(ins, op - 3); /* %stdin */
1383ff48bf5SDavid du Colombier
1393ff48bf5SDavid du Colombier /* extend string */
1403ff48bf5SDavid du Colombier initial_buf_size = statement ? STATEMENTEDIT_BUF_SIZE : LINEEDIT_BUF_SIZE;
1413ff48bf5SDavid du Colombier if (initial_buf_size > max_string_size)
1423ff48bf5SDavid du Colombier return_error(e_limitcheck);
1433ff48bf5SDavid du Colombier if (!buf->data || (buf->size < initial_buf_size)) {
1443ff48bf5SDavid du Colombier count = 0;
1453ff48bf5SDavid du Colombier buf->data = gs_alloc_string(imemory, initial_buf_size,
1463ff48bf5SDavid du Colombier "zfilelineedit(buffer)");
1477dd7cddfSDavid du Colombier if (buf->data == 0)
1487dd7cddfSDavid du Colombier return_error(e_VMerror);
1493ff48bf5SDavid du Colombier op->value.bytes = buf->data;
1503ff48bf5SDavid du Colombier op->tas.rsize = buf->size = initial_buf_size;
1513ff48bf5SDavid du Colombier }
1523ff48bf5SDavid du Colombier
1537dd7cddfSDavid du Colombier rd:
1543ff48bf5SDavid du Colombier code = zreadline_from(ins, buf, imemory, &count, &in_eol);
1553ff48bf5SDavid du Colombier if (buf->size > max_string_size) {
1563ff48bf5SDavid du Colombier /* zreadline_from reallocated the buffer larger than
1573ff48bf5SDavid du Colombier * is valid for a PostScript string.
1583ff48bf5SDavid du Colombier * Return an error, but first realloc the buffer
1593ff48bf5SDavid du Colombier * back to a legal size.
1607dd7cddfSDavid du Colombier */
1613ff48bf5SDavid du Colombier byte *nbuf = gs_resize_string(imemory, buf->data, buf->size,
1623ff48bf5SDavid du Colombier max_string_size, "zfilelineedit(shrink buffer)");
1633ff48bf5SDavid du Colombier if (nbuf == 0)
1643ff48bf5SDavid du Colombier return_error(e_VMerror);
1653ff48bf5SDavid du Colombier op->value.bytes = buf->data = nbuf;
1663ff48bf5SDavid du Colombier op->tas.rsize = buf->size = max_string_size;
1673ff48bf5SDavid du Colombier return_error(e_limitcheck);
1683ff48bf5SDavid du Colombier }
1693ff48bf5SDavid du Colombier
1703ff48bf5SDavid du Colombier op->value.bytes = buf->data; /* zreadline_from sometimes resizes the buffer. */
1713ff48bf5SDavid du Colombier op->tas.rsize = buf->size;
1723ff48bf5SDavid du Colombier
1737dd7cddfSDavid du Colombier switch (code) {
1747dd7cddfSDavid du Colombier case EOFC:
1757dd7cddfSDavid du Colombier code = gs_note_error(e_undefinedfilename);
1767dd7cddfSDavid du Colombier /* falls through */
1777dd7cddfSDavid du Colombier case 0:
1787dd7cddfSDavid du Colombier break;
1797dd7cddfSDavid du Colombier default:
1807dd7cddfSDavid du Colombier code = gs_note_error(e_ioerror);
1817dd7cddfSDavid du Colombier break;
1823ff48bf5SDavid du Colombier case CALLC:
1833ff48bf5SDavid du Colombier {
1843ff48bf5SDavid du Colombier ref rfile;
1853ff48bf5SDavid du Colombier (op-1)->value.intval = count;
1863ff48bf5SDavid du Colombier /* callout is for stdin */
1873ff48bf5SDavid du Colombier make_file(&rfile, a_readonly | avm_system, ins->read_id, ins);
1883ff48bf5SDavid du Colombier code = s_handle_read_exception(i_ctx_p, code, &rfile,
1893ff48bf5SDavid du Colombier NULL, 0, zfilelineedit);
1903ff48bf5SDavid du Colombier }
1913ff48bf5SDavid du Colombier break;
1927dd7cddfSDavid du Colombier case 1: /* filled buffer */
1937dd7cddfSDavid du Colombier {
1943ff48bf5SDavid du Colombier uint nsize = buf->size;
1957dd7cddfSDavid du Colombier byte *nbuf;
1967dd7cddfSDavid du Colombier
1973ff48bf5SDavid du Colombier if (nsize >= max_string_size) {
1987dd7cddfSDavid du Colombier code = gs_note_error(e_limitcheck);
1997dd7cddfSDavid du Colombier break;
2003ff48bf5SDavid du Colombier }
2013ff48bf5SDavid du Colombier else if (nsize >= max_string_size / 2)
2023ff48bf5SDavid du Colombier nsize= max_string_size;
2037dd7cddfSDavid du Colombier else
2047dd7cddfSDavid du Colombier nsize = buf->size * 2;
2053ff48bf5SDavid du Colombier nbuf = gs_resize_string(imemory, buf->data, buf->size, nsize,
2063ff48bf5SDavid du Colombier "zfilelineedit(grow buffer)");
2077dd7cddfSDavid du Colombier if (nbuf == 0) {
2087dd7cddfSDavid du Colombier code = gs_note_error(e_VMerror);
2097dd7cddfSDavid du Colombier break;
2107dd7cddfSDavid du Colombier }
2113ff48bf5SDavid du Colombier op->value.bytes = buf->data = nbuf;
2123ff48bf5SDavid du Colombier op->tas.rsize = buf->size = nsize;
2137dd7cddfSDavid du Colombier goto rd;
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier }
2163ff48bf5SDavid du Colombier if (code != 0)
2177dd7cddfSDavid du Colombier return code;
2187dd7cddfSDavid du Colombier if (statement) {
2197dd7cddfSDavid du Colombier /* If we don't have a complete token, keep going. */
2207dd7cddfSDavid du Colombier stream st;
2217dd7cddfSDavid du Colombier stream *ts = &st;
2227dd7cddfSDavid du Colombier scanner_state state;
2237dd7cddfSDavid du Colombier ref ignore_value;
2247dd7cddfSDavid du Colombier uint depth = ref_stack_count(&o_stack);
2257dd7cddfSDavid du Colombier int code;
2267dd7cddfSDavid du Colombier
2277dd7cddfSDavid du Colombier /* Add a terminating EOL. */
2283ff48bf5SDavid du Colombier if (count + 1 > buf->size) {
2293ff48bf5SDavid du Colombier uint nsize;
2303ff48bf5SDavid du Colombier byte *nbuf;
2313ff48bf5SDavid du Colombier
2323ff48bf5SDavid du Colombier nsize = buf->size + 1;
2333ff48bf5SDavid du Colombier if (nsize > max_string_size) {
2343ff48bf5SDavid du Colombier return_error(gs_note_error(e_limitcheck));
2353ff48bf5SDavid du Colombier }
2363ff48bf5SDavid du Colombier else {
2373ff48bf5SDavid du Colombier nbuf = gs_resize_string(imemory, buf->data, buf->size, nsize,
2383ff48bf5SDavid du Colombier "zfilelineedit(grow buffer)");
2393ff48bf5SDavid du Colombier if (nbuf == 0) {
2403ff48bf5SDavid du Colombier code = gs_note_error(e_VMerror);
2413ff48bf5SDavid du Colombier return_error(code);
2423ff48bf5SDavid du Colombier }
2433ff48bf5SDavid du Colombier op->value.bytes = buf->data = nbuf;
2443ff48bf5SDavid du Colombier op->tas.rsize = buf->size = nsize;
2453ff48bf5SDavid du Colombier }
2463ff48bf5SDavid du Colombier }
2477dd7cddfSDavid du Colombier buf->data[count++] = char_EOL;
248*593dc095SDavid du Colombier s_init(ts, NULL);
2497dd7cddfSDavid du Colombier sread_string(ts, buf->data, count);
2507dd7cddfSDavid du Colombier sc:
2517dd7cddfSDavid du Colombier scanner_state_init_check(&state, false, true);
2527dd7cddfSDavid du Colombier code = scan_token(i_ctx_p, ts, &ignore_value, &state);
2537dd7cddfSDavid du Colombier ref_stack_pop_to(&o_stack, depth);
254*593dc095SDavid du Colombier if (code < 0)
255*593dc095SDavid du Colombier code = scan_EOF; /* stop on scanner error */
2567dd7cddfSDavid du Colombier switch (code) {
2577dd7cddfSDavid du Colombier case 0: /* read a token */
2587dd7cddfSDavid du Colombier case scan_BOS:
2597dd7cddfSDavid du Colombier goto sc; /* keep going until we run out of data */
2607dd7cddfSDavid du Colombier case scan_Refill:
2617dd7cddfSDavid du Colombier goto rd;
2627dd7cddfSDavid du Colombier case scan_EOF:
2637dd7cddfSDavid du Colombier break;
2647dd7cddfSDavid du Colombier default: /* error */
2657dd7cddfSDavid du Colombier return code;
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier }
2683ff48bf5SDavid du Colombier buf->data = gs_resize_string(imemory, buf->data, buf->size, count,
2693ff48bf5SDavid du Colombier "zfilelineedit(resize buffer)");
2707dd7cddfSDavid du Colombier if (buf->data == 0)
2717dd7cddfSDavid du Colombier return_error(e_VMerror);
2723ff48bf5SDavid du Colombier op->value.bytes = buf->data;
2733ff48bf5SDavid du Colombier op->tas.rsize = buf->size;
2743ff48bf5SDavid du Colombier
2753ff48bf5SDavid du Colombier s = file_alloc_stream(imemory, "zfilelineedit(stream)");
2763ff48bf5SDavid du Colombier if (s == 0)
2773ff48bf5SDavid du Colombier return_error(e_VMerror);
2783ff48bf5SDavid du Colombier
2797dd7cddfSDavid du Colombier sread_string(s, buf->data, count);
2807dd7cddfSDavid du Colombier s->save_close = s->procs.close;
2817dd7cddfSDavid du Colombier s->procs.close = file_close_disable;
2823ff48bf5SDavid du Colombier
2833ff48bf5SDavid du Colombier filename = statement ? gs_iodev_statementedit.dname
2843ff48bf5SDavid du Colombier : gs_iodev_lineedit.dname;
2853ff48bf5SDavid du Colombier code = ssetfilename(s, (const byte *)filename, strlen(filename)+1);
2863ff48bf5SDavid du Colombier if (code < 0) {
2873ff48bf5SDavid du Colombier sclose(s);
2883ff48bf5SDavid du Colombier return_error(e_VMerror);
2897dd7cddfSDavid du Colombier }
2907dd7cddfSDavid du Colombier
2913ff48bf5SDavid du Colombier pop(3);
2923ff48bf5SDavid du Colombier make_stream_file(osp, s, "r");
2937dd7cddfSDavid du Colombier
2943ff48bf5SDavid du Colombier return code;
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier
2977dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier const op_def ziodev_op_defs[] =
3007dd7cddfSDavid du Colombier {
3017dd7cddfSDavid du Colombier {"1.getiodevice", zgetiodevice},
3027dd7cddfSDavid du Colombier op_def_end(0)
3037dd7cddfSDavid du Colombier };
304