Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
};