Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1994, 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: zfproc.c,v 1.12 2002/06/16 03:43:51 lpd Exp $ */
18
/* Procedure-based filter stream support */
19
#include "memory_.h"
20
#include "ghost.h"
21
#include "oper.h"		/* for ifilter.h */
22
#include "estack.h"
23
#include "gsstruct.h"
24
#include "ialloc.h"
25
#include "istruct.h"		/* for RELOC_REF_VAR */
26
#include "stream.h"
27
#include "strimpl.h"
28
#include "ifilter.h"
29
#include "files.h"
30
#include "store.h"
31
 
32
/* ---------------- Generic ---------------- */
33
 
34
/* GC procedures */
35
private 
36
CLEAR_MARKS_PROC(sproc_clear_marks)
37
{
38
    stream_proc_state *const pptr = vptr;
39
 
40
    r_clear_attrs(&pptr->proc, l_mark);
41
    r_clear_attrs(&pptr->data, l_mark);
42
}
43
private 
44
ENUM_PTRS_WITH(sproc_enum_ptrs, stream_proc_state *pptr) return 0;
45
case 0:
46
ENUM_RETURN_REF(&pptr->proc);
47
case 1:
48
ENUM_RETURN_REF(&pptr->data);
49
ENUM_PTRS_END
50
private RELOC_PTRS_WITH(sproc_reloc_ptrs, stream_proc_state *pptr);
51
RELOC_REF_VAR(pptr->proc);
52
r_clear_attrs(&pptr->proc, l_mark);
53
RELOC_REF_VAR(pptr->data);
54
r_clear_attrs(&pptr->data, l_mark);
55
RELOC_PTRS_END
56
 
57
/* Structure type for procedure-based streams. */
58
private_st_stream_proc_state();
59
 
60
/* Allocate and open a procedure-based filter. */
61
/* The caller must have checked that *sop is a procedure. */
62
private int
63
s_proc_init(ref * sop, stream ** psstrm, uint mode,
64
	    const stream_template * temp, const stream_procs * procs,
65
	    gs_ref_memory_t *imem)
66
{
67
    gs_memory_t *const mem = (gs_memory_t *)imem;
68
    stream *sstrm = file_alloc_stream(mem, "s_proc_init(stream)");
69
    stream_proc_state *state = (stream_proc_state *)
70
	s_alloc_state(mem, &st_sproc_state, "s_proc_init(state)");
71
 
72
    if (sstrm == 0 || state == 0) {
73
	gs_free_object(mem, state, "s_proc_init(state)");
74
	/*gs_free_object(mem, sstrm, "s_proc_init(stream)"); *//* just leave it on the file list */
75
	return_error(e_VMerror);
76
    }
77
    s_std_init(sstrm, NULL, 0, procs, mode);
78
    sstrm->procs.process = temp->process;
79
    state->template = temp;
80
    state->memory = mem;
81
    state->eof = 0;
82
    state->proc = *sop;
83
    make_empty_string(&state->data, a_all);
84
    state->index = 0;
85
    sstrm->state = (stream_state *) state;
86
    *psstrm = sstrm;
87
    return 0;
88
}
89
 
90
/* Handle an interrupt during a stream operation. */
91
/* This is logically unrelated to procedure streams, */
92
/* but it is also associated with the interpreter stream machinery. */
93
private int
94
s_handle_intc(i_ctx_t *i_ctx_p, const ref *pstate, int nstate,
95
	      op_proc_t cont)
96
{
97
    int npush = nstate + 2;
98
 
99
    check_estack(npush);
100
    if (nstate)
101
	memcpy(esp + 2, pstate, nstate * sizeof(ref));
102
#if 0				/* **************** */
103
    {
104
	int code = gs_interpret_error(e_interrupt, (ref *) (esp + npush));
105
 
106
	if (code < 0)
107
	    return code;
108
    }
109
#else /* **************** */
110
    npush--;
111
#endif /* **************** */
112
    make_op_estack(esp + 1, cont);
113
    esp += npush;
114
    return o_push_estack;
115
}
116
 
117
/* Set default parameter values (actually, just clear pointers). */
118
private void
119
s_proc_set_defaults(stream_state * st)
120
{
121
    stream_proc_state *const ss = (stream_proc_state *) st;
122
 
123
    make_null(&ss->proc);
124
    make_null(&ss->data);
125
}
126
 
127
/* ---------------- Read streams ---------------- */
128
 
129
/* Forward references */
130
private stream_proc_process(s_proc_read_process);
131
private int s_proc_read_continue(i_ctx_t *);
132
 
133
/* Stream templates */
134
private const stream_template s_proc_read_template = {
135
    &st_sproc_state, NULL, s_proc_read_process, 1, 1,
136
    NULL, s_proc_set_defaults
137
};
138
private const stream_procs s_proc_read_procs = {
139
    s_std_noavailable, s_std_noseek, s_std_read_reset,
140
    s_std_read_flush, s_std_null, NULL
141
};
142
 
143
/* Allocate and open a procedure-based read stream. */
144
/* The caller must have checked that *sop is a procedure. */
145
int
146
sread_proc(ref * sop, stream ** psstrm, gs_ref_memory_t *imem)
147
{
148
    int code =
149
	s_proc_init(sop, psstrm, s_mode_read, &s_proc_read_template,
150
		    &s_proc_read_procs, imem);
151
 
152
    if (code < 0)
153
	return code;
154
    (*psstrm)->end_status = CALLC;
155
    return code;
156
}
157
 
158
/* Handle an input request. */
159
private int
160
s_proc_read_process(stream_state * st, stream_cursor_read * ignore_pr,
161
		    stream_cursor_write * pw, bool last)
162
{
163
    /* Move data from the string returned by the procedure */
164
    /* into the stream buffer, or ask for a callback. */
165
    stream_proc_state *const ss = (stream_proc_state *) st;
166
    uint count = r_size(&ss->data) - ss->index;
167
 
168
    if (count > 0) {
169
	uint wcount = pw->limit - pw->ptr;
170
 
171
	if (wcount < count)
172
	    count = wcount;
173
	memcpy(pw->ptr + 1, ss->data.value.bytes + ss->index, count);
174
	pw->ptr += count;
175
	ss->index += count;
176
	return 1;
177
    }
178
    return (ss->eof ? EOFC : CALLC);
179
}
180
 
181
/* Handle an exception (INTC or CALLC) from a read stream */
182
/* whose buffer is empty. */
183
int
184
s_handle_read_exception(i_ctx_t *i_ctx_p, int status, const ref * fop,
185
			const ref * pstate, int nstate, op_proc_t cont)
186
{
187
    int npush = nstate + 4;
188
    stream *ps;
189
    stream *psstdin;
190
 
191
    switch (status) {
192
	case INTC:
193
	    return s_handle_intc(i_ctx_p, pstate, nstate, cont);
194
	case CALLC:
195
	    break;
196
	default:
197
	    return_error(e_ioerror);
198
    }
199
    /* Find the stream whose buffer needs refilling. */
200
    for (ps = fptr(fop); ps->strm != 0;)
201
	ps = ps->strm;
202
    check_estack(npush);
203
    if (nstate)
204
	memcpy(esp + 2, pstate, nstate * sizeof(ref));
205
    make_op_estack(esp + 1, cont);
206
    esp += npush;
207
    make_op_estack(esp - 2, s_proc_read_continue);
208
    esp[-1] = *fop;
209
    r_clear_attrs(esp - 1, a_executable);
210
    *esp = ((stream_proc_state *) ps->state)->proc;
211
 
212
    /* If stream is stdin, ask for callout. */
213
    zget_stdin(i_ctx_p, &psstdin);
214
    if (ps == psstdin) {
215
	check_estack(1);
216
	esp += 1;
217
	make_op_estack(esp, zneedstdin);
218
    }
219
    return o_push_estack;
220
}
221
/* Continue a read operation after returning from a procedure callout. */
222
/* osp[0] contains the file (pushed on the e-stack by handle_read_status); */
223
/* osp[-1] contains the new data string (pushed by the procedure). */
224
/* The top of the e-stack contains the real continuation. */
225
private int
226
s_proc_read_continue(i_ctx_t *i_ctx_p)
227
{
228
    os_ptr op = osp;
229
    os_ptr opbuf = op - 1;
230
    stream *ps;
231
    stream_proc_state *ss;
232
 
233
    check_file(ps, op);
234
    check_read_type(*opbuf, t_string);
235
    while ((ps->end_status = 0, ps->strm) != 0)
236
	ps = ps->strm;
237
    ss = (stream_proc_state *) ps->state;
238
    ss->data = *opbuf;
239
    ss->index = 0;
240
    if (r_size(opbuf) == 0)
241
	ss->eof = true;
242
    pop(2);
243
    return 0;
244
}
245
 
246
/* ---------------- Write streams ---------------- */
247
 
248
/* Forward references */
249
private stream_proc_flush(s_proc_write_flush);
250
private stream_proc_process(s_proc_write_process);
251
private int s_proc_write_continue(i_ctx_t *);
252
 
253
/* Stream templates */
254
private const stream_template s_proc_write_template = {
255
    &st_sproc_state, NULL, s_proc_write_process, 1, 1,
256
    NULL, s_proc_set_defaults
257
};
258
private const stream_procs s_proc_write_procs = {
259
    s_std_noavailable, s_std_noseek, s_std_write_reset,
260
    s_proc_write_flush, s_std_null, NULL
261
};
262
 
263
/* Allocate and open a procedure-based write stream. */
264
/* The caller must have checked that *sop is a procedure. */
265
int
266
swrite_proc(ref * sop, stream ** psstrm, gs_ref_memory_t *imem)
267
{
268
    return s_proc_init(sop, psstrm, s_mode_write, &s_proc_write_template,
269
		       &s_proc_write_procs, imem);
270
}
271
 
272
/* Handle an output request. */
273
private int
274
s_proc_write_process(stream_state * st, stream_cursor_read * pr,
275
		     stream_cursor_write * ignore_pw, bool last)
276
{
277
    /* Move data from the stream buffer to the string */
278
    /* returned by the procedure, or ask for a callback. */
279
    stream_proc_state *const ss = (stream_proc_state *) st;
280
    uint rcount = pr->limit - pr->ptr;
281
 
282
    if (rcount > 0) {
283
	uint wcount = r_size(&ss->data) - ss->index;
284
	uint count = min(rcount, wcount);
285
 
286
	memcpy(ss->data.value.bytes + ss->index, pr->ptr + 1, count);
287
	pr->ptr += count;
288
	ss->index += count;
289
	if (rcount > wcount)
290
	    return CALLC;
291
	else if (last) {
292
	    ss->eof = true;
293
	    return CALLC;
294
	} else
295
	    return 0;
296
    }
297
    return ((ss->eof = last) ? EOFC : 0);
298
}
299
 
300
/* Flush the output.  This is non-standard because it must call the */
301
/* procedure. */
302
private int
303
s_proc_write_flush(stream *s)
304
{
305
    int result = s_process_write_buf(s, false);
306
    stream_proc_state *const ss = (stream_proc_state *)s->state;
307
 
308
    return (result < 0 || ss->index == 0 ? result : CALLC);
309
}
310
 
311
/* Handle an exception (INTC or CALLC) from a write stream */
312
/* whose buffer is full. */
313
int
314
s_handle_write_exception(i_ctx_t *i_ctx_p, int status, const ref * fop,
315
			 const ref * pstate, int nstate, op_proc_t cont)
316
{
317
    stream *ps;
318
    stream *psstderr;
319
    stream *psstdout;
320
    stream_proc_state *psst;
321
 
322
    switch (status) {
323
	case INTC:
324
	    return s_handle_intc(i_ctx_p, pstate, nstate, cont);
325
	case CALLC:
326
	    break;
327
	default:
328
	    return_error(e_ioerror);
329
    }
330
    /* Find the stream whose buffer needs emptying. */
331
    for (ps = fptr(fop); ps->strm != 0;)
332
	ps = ps->strm;
333
    psst = (stream_proc_state *) ps->state;
334
    {
335
	int npush = nstate + 6;
336
 
337
	check_estack(npush);
338
	if (nstate)
339
	    memcpy(esp + 2, pstate, nstate * sizeof(ref));
340
	make_op_estack(esp + 1, cont);
341
	esp += npush;
342
	make_op_estack(esp - 4, s_proc_write_continue);
343
	esp[-3] = *fop;
344
	r_clear_attrs(esp - 3, a_executable);
345
	make_bool(esp - 1, !psst->eof);
346
    }
347
    esp[-2] = psst->proc;
348
    *esp = psst->data;
349
    r_set_size(esp, psst->index);
350
 
351
    /* If stream is stdout/err, ask for callout. */
352
    zget_stdout(i_ctx_p, &psstdout);
353
    zget_stderr(i_ctx_p, &psstderr);
354
    if ((ps == psstderr) || (ps == psstdout)) {
355
	check_estack(1);
356
	esp += 1;
357
	make_op_estack(esp, (ps == psstderr) ? zneedstderr : zneedstdout);
358
    }
359
    return o_push_estack;
360
}
361
/* Continue a write operation after returning from a procedure callout. */
362
/* osp[0] contains the file (pushed on the e-stack by handle_write_status); */
363
/* osp[-1] contains the new buffer string (pushed by the procedure). */
364
/* The top of the e-stack contains the real continuation. */
365
private int
366
s_proc_write_continue(i_ctx_t *i_ctx_p)
367
{
368
    os_ptr op = osp;
369
    os_ptr opbuf = op - 1;
370
    stream *ps;
371
    stream_proc_state *ss;
372
 
373
    check_file(ps, op);
374
    check_write_type(*opbuf, t_string);
375
    while (ps->strm != 0) {
376
	if (ps->end_status == CALLC)
377
	    ps->end_status = 0;
378
	ps = ps->strm;
379
    }
380
    ps->end_status = 0;
381
    ss = (stream_proc_state *) ps->state;
382
    ss->data = *opbuf;
383
    ss->index = 0;
384
    pop(2);
385
    return 0;
386
}
387
 
388
/* ------ More generic ------ */
389
 
390
/* Test whether a stream is procedure-based. */
391
bool
392
s_is_proc(const stream *s)
393
{
394
    return (s->procs.process == s_proc_read_process ||
395
	    s->procs.process == s_proc_write_process);
396
}
397
 
398
/* ------ Initialization procedure ------ */
399
 
400
const op_def zfproc_op_defs[] =
401
{
402
		/* Internal operators */
403
    {"2%s_proc_read_continue", s_proc_read_continue},
404
    {"2%s_proc_write_continue", s_proc_write_continue},
405
    op_def_end(0)
406
};