xref: /plan9/sys/src/cmd/gs/src/zfproc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1994, 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: zfproc.c,v 1.12 2002/06/16 03:43:51 lpd Exp $ */
187dd7cddfSDavid du Colombier /* Procedure-based filter stream support */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "ghost.h"
217dd7cddfSDavid du Colombier #include "oper.h"		/* for ifilter.h */
227dd7cddfSDavid du Colombier #include "estack.h"
237dd7cddfSDavid du Colombier #include "gsstruct.h"
247dd7cddfSDavid du Colombier #include "ialloc.h"
257dd7cddfSDavid du Colombier #include "istruct.h"		/* for RELOC_REF_VAR */
267dd7cddfSDavid du Colombier #include "stream.h"
277dd7cddfSDavid du Colombier #include "strimpl.h"
287dd7cddfSDavid du Colombier #include "ifilter.h"
297dd7cddfSDavid du Colombier #include "files.h"
307dd7cddfSDavid du Colombier #include "store.h"
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier /* ---------------- Generic ---------------- */
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier /* GC procedures */
357dd7cddfSDavid du Colombier private
CLEAR_MARKS_PROC(sproc_clear_marks)367dd7cddfSDavid du Colombier CLEAR_MARKS_PROC(sproc_clear_marks)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier     stream_proc_state *const pptr = vptr;
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier     r_clear_attrs(&pptr->proc, l_mark);
417dd7cddfSDavid du Colombier     r_clear_attrs(&pptr->data, l_mark);
427dd7cddfSDavid du Colombier }
437dd7cddfSDavid du Colombier private
447dd7cddfSDavid du Colombier ENUM_PTRS_WITH(sproc_enum_ptrs, stream_proc_state *pptr) return 0;
457dd7cddfSDavid du Colombier case 0:
467dd7cddfSDavid du Colombier ENUM_RETURN_REF(&pptr->proc);
477dd7cddfSDavid du Colombier case 1:
487dd7cddfSDavid du Colombier ENUM_RETURN_REF(&pptr->data);
497dd7cddfSDavid du Colombier ENUM_PTRS_END
507dd7cddfSDavid du Colombier private RELOC_PTRS_WITH(sproc_reloc_ptrs, stream_proc_state *pptr);
517dd7cddfSDavid du Colombier RELOC_REF_VAR(pptr->proc);
527dd7cddfSDavid du Colombier r_clear_attrs(&pptr->proc, l_mark);
537dd7cddfSDavid du Colombier RELOC_REF_VAR(pptr->data);
547dd7cddfSDavid du Colombier r_clear_attrs(&pptr->data, l_mark);
557dd7cddfSDavid du Colombier RELOC_PTRS_END
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier /* Structure type for procedure-based streams. */
587dd7cddfSDavid du Colombier private_st_stream_proc_state();
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier /* Allocate and open a procedure-based filter. */
617dd7cddfSDavid du Colombier /* The caller must have checked that *sop is a procedure. */
627dd7cddfSDavid du Colombier private int
s_proc_init(ref * sop,stream ** psstrm,uint mode,const stream_template * temp,const stream_procs * procs,gs_ref_memory_t * imem)637dd7cddfSDavid du Colombier s_proc_init(ref * sop, stream ** psstrm, uint mode,
647dd7cddfSDavid du Colombier 	    const stream_template * temp, const stream_procs * procs,
657dd7cddfSDavid du Colombier 	    gs_ref_memory_t *imem)
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier     gs_memory_t *const mem = (gs_memory_t *)imem;
687dd7cddfSDavid du Colombier     stream *sstrm = file_alloc_stream(mem, "s_proc_init(stream)");
697dd7cddfSDavid du Colombier     stream_proc_state *state = (stream_proc_state *)
707dd7cddfSDavid du Colombier 	s_alloc_state(mem, &st_sproc_state, "s_proc_init(state)");
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier     if (sstrm == 0 || state == 0) {
737dd7cddfSDavid du Colombier 	gs_free_object(mem, state, "s_proc_init(state)");
747dd7cddfSDavid du Colombier 	/*gs_free_object(mem, sstrm, "s_proc_init(stream)"); *//* just leave it on the file list */
757dd7cddfSDavid du Colombier 	return_error(e_VMerror);
767dd7cddfSDavid du Colombier     }
777dd7cddfSDavid du Colombier     s_std_init(sstrm, NULL, 0, procs, mode);
787dd7cddfSDavid du Colombier     sstrm->procs.process = temp->process;
797dd7cddfSDavid du Colombier     state->template = temp;
807dd7cddfSDavid du Colombier     state->memory = mem;
817dd7cddfSDavid du Colombier     state->eof = 0;
827dd7cddfSDavid du Colombier     state->proc = *sop;
837dd7cddfSDavid du Colombier     make_empty_string(&state->data, a_all);
847dd7cddfSDavid du Colombier     state->index = 0;
857dd7cddfSDavid du Colombier     sstrm->state = (stream_state *) state;
867dd7cddfSDavid du Colombier     *psstrm = sstrm;
877dd7cddfSDavid du Colombier     return 0;
887dd7cddfSDavid du Colombier }
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier /* Handle an interrupt during a stream operation. */
917dd7cddfSDavid du Colombier /* This is logically unrelated to procedure streams, */
927dd7cddfSDavid du Colombier /* but it is also associated with the interpreter stream machinery. */
937dd7cddfSDavid du Colombier private int
s_handle_intc(i_ctx_t * i_ctx_p,const ref * pstate,int nstate,op_proc_t cont)947dd7cddfSDavid du Colombier s_handle_intc(i_ctx_t *i_ctx_p, const ref *pstate, int nstate,
957dd7cddfSDavid du Colombier 	      op_proc_t cont)
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier     int npush = nstate + 2;
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier     check_estack(npush);
1007dd7cddfSDavid du Colombier     if (nstate)
1017dd7cddfSDavid du Colombier 	memcpy(esp + 2, pstate, nstate * sizeof(ref));
1027dd7cddfSDavid du Colombier #if 0				/* **************** */
1037dd7cddfSDavid du Colombier     {
1047dd7cddfSDavid du Colombier 	int code = gs_interpret_error(e_interrupt, (ref *) (esp + npush));
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier 	if (code < 0)
1077dd7cddfSDavid du Colombier 	    return code;
1087dd7cddfSDavid du Colombier     }
1097dd7cddfSDavid du Colombier #else /* **************** */
1107dd7cddfSDavid du Colombier     npush--;
1117dd7cddfSDavid du Colombier #endif /* **************** */
1127dd7cddfSDavid du Colombier     make_op_estack(esp + 1, cont);
1137dd7cddfSDavid du Colombier     esp += npush;
1147dd7cddfSDavid du Colombier     return o_push_estack;
1157dd7cddfSDavid du Colombier }
1167dd7cddfSDavid du Colombier 
1177dd7cddfSDavid du Colombier /* Set default parameter values (actually, just clear pointers). */
1187dd7cddfSDavid du Colombier private void
s_proc_set_defaults(stream_state * st)1197dd7cddfSDavid du Colombier s_proc_set_defaults(stream_state * st)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier     stream_proc_state *const ss = (stream_proc_state *) st;
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier     make_null(&ss->proc);
1247dd7cddfSDavid du Colombier     make_null(&ss->data);
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier /* ---------------- Read streams ---------------- */
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier /* Forward references */
1307dd7cddfSDavid du Colombier private stream_proc_process(s_proc_read_process);
131*593dc095SDavid du Colombier private int s_proc_read_continue(i_ctx_t *);
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier /* Stream templates */
1347dd7cddfSDavid du Colombier private const stream_template s_proc_read_template = {
1357dd7cddfSDavid du Colombier     &st_sproc_state, NULL, s_proc_read_process, 1, 1,
1367dd7cddfSDavid du Colombier     NULL, s_proc_set_defaults
1377dd7cddfSDavid du Colombier };
1387dd7cddfSDavid du Colombier private const stream_procs s_proc_read_procs = {
1397dd7cddfSDavid du Colombier     s_std_noavailable, s_std_noseek, s_std_read_reset,
1407dd7cddfSDavid du Colombier     s_std_read_flush, s_std_null, NULL
1417dd7cddfSDavid du Colombier };
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier /* Allocate and open a procedure-based read stream. */
1447dd7cddfSDavid du Colombier /* The caller must have checked that *sop is a procedure. */
1457dd7cddfSDavid du Colombier int
sread_proc(ref * sop,stream ** psstrm,gs_ref_memory_t * imem)1467dd7cddfSDavid du Colombier sread_proc(ref * sop, stream ** psstrm, gs_ref_memory_t *imem)
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier     int code =
1497dd7cddfSDavid du Colombier 	s_proc_init(sop, psstrm, s_mode_read, &s_proc_read_template,
1507dd7cddfSDavid du Colombier 		    &s_proc_read_procs, imem);
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier     if (code < 0)
1537dd7cddfSDavid du Colombier 	return code;
1547dd7cddfSDavid du Colombier     (*psstrm)->end_status = CALLC;
1557dd7cddfSDavid du Colombier     return code;
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier /* Handle an input request. */
1597dd7cddfSDavid du Colombier private int
s_proc_read_process(stream_state * st,stream_cursor_read * ignore_pr,stream_cursor_write * pw,bool last)1607dd7cddfSDavid du Colombier s_proc_read_process(stream_state * st, stream_cursor_read * ignore_pr,
1617dd7cddfSDavid du Colombier 		    stream_cursor_write * pw, bool last)
1627dd7cddfSDavid du Colombier {
1637dd7cddfSDavid du Colombier     /* Move data from the string returned by the procedure */
1647dd7cddfSDavid du Colombier     /* into the stream buffer, or ask for a callback. */
1657dd7cddfSDavid du Colombier     stream_proc_state *const ss = (stream_proc_state *) st;
1667dd7cddfSDavid du Colombier     uint count = r_size(&ss->data) - ss->index;
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier     if (count > 0) {
1697dd7cddfSDavid du Colombier 	uint wcount = pw->limit - pw->ptr;
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	if (wcount < count)
1727dd7cddfSDavid du Colombier 	    count = wcount;
1737dd7cddfSDavid du Colombier 	memcpy(pw->ptr + 1, ss->data.value.bytes + ss->index, count);
1747dd7cddfSDavid du Colombier 	pw->ptr += count;
1757dd7cddfSDavid du Colombier 	ss->index += count;
1767dd7cddfSDavid du Colombier 	return 1;
1777dd7cddfSDavid du Colombier     }
1787dd7cddfSDavid du Colombier     return (ss->eof ? EOFC : CALLC);
1797dd7cddfSDavid du Colombier }
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier /* Handle an exception (INTC or CALLC) from a read stream */
1827dd7cddfSDavid du Colombier /* whose buffer is empty. */
1837dd7cddfSDavid du Colombier int
s_handle_read_exception(i_ctx_t * i_ctx_p,int status,const ref * fop,const ref * pstate,int nstate,op_proc_t cont)1847dd7cddfSDavid du Colombier s_handle_read_exception(i_ctx_t *i_ctx_p, int status, const ref * fop,
1857dd7cddfSDavid du Colombier 			const ref * pstate, int nstate, op_proc_t cont)
1867dd7cddfSDavid du Colombier {
1877dd7cddfSDavid du Colombier     int npush = nstate + 4;
1887dd7cddfSDavid du Colombier     stream *ps;
1893ff48bf5SDavid du Colombier     stream *psstdin;
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier     switch (status) {
1927dd7cddfSDavid du Colombier 	case INTC:
1937dd7cddfSDavid du Colombier 	    return s_handle_intc(i_ctx_p, pstate, nstate, cont);
1947dd7cddfSDavid du Colombier 	case CALLC:
1957dd7cddfSDavid du Colombier 	    break;
1967dd7cddfSDavid du Colombier 	default:
1977dd7cddfSDavid du Colombier 	    return_error(e_ioerror);
1987dd7cddfSDavid du Colombier     }
1997dd7cddfSDavid du Colombier     /* Find the stream whose buffer needs refilling. */
2007dd7cddfSDavid du Colombier     for (ps = fptr(fop); ps->strm != 0;)
2017dd7cddfSDavid du Colombier 	ps = ps->strm;
2027dd7cddfSDavid du Colombier     check_estack(npush);
2037dd7cddfSDavid du Colombier     if (nstate)
2047dd7cddfSDavid du Colombier 	memcpy(esp + 2, pstate, nstate * sizeof(ref));
2057dd7cddfSDavid du Colombier     make_op_estack(esp + 1, cont);
2067dd7cddfSDavid du Colombier     esp += npush;
2077dd7cddfSDavid du Colombier     make_op_estack(esp - 2, s_proc_read_continue);
2087dd7cddfSDavid du Colombier     esp[-1] = *fop;
2097dd7cddfSDavid du Colombier     r_clear_attrs(esp - 1, a_executable);
2107dd7cddfSDavid du Colombier     *esp = ((stream_proc_state *) ps->state)->proc;
2113ff48bf5SDavid du Colombier 
2123ff48bf5SDavid du Colombier     /* If stream is stdin, ask for callout. */
2133ff48bf5SDavid du Colombier     zget_stdin(i_ctx_p, &psstdin);
2143ff48bf5SDavid du Colombier     if (ps == psstdin) {
2153ff48bf5SDavid du Colombier 	check_estack(1);
2163ff48bf5SDavid du Colombier 	esp += 1;
2173ff48bf5SDavid du Colombier 	make_op_estack(esp, zneedstdin);
2183ff48bf5SDavid du Colombier     }
2197dd7cddfSDavid du Colombier     return o_push_estack;
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier /* Continue a read operation after returning from a procedure callout. */
2227dd7cddfSDavid du Colombier /* osp[0] contains the file (pushed on the e-stack by handle_read_status); */
2237dd7cddfSDavid du Colombier /* osp[-1] contains the new data string (pushed by the procedure). */
2247dd7cddfSDavid du Colombier /* The top of the e-stack contains the real continuation. */
2257dd7cddfSDavid du Colombier private int
s_proc_read_continue(i_ctx_t * i_ctx_p)2267dd7cddfSDavid du Colombier s_proc_read_continue(i_ctx_t *i_ctx_p)
2277dd7cddfSDavid du Colombier {
2287dd7cddfSDavid du Colombier     os_ptr op = osp;
2297dd7cddfSDavid du Colombier     os_ptr opbuf = op - 1;
2307dd7cddfSDavid du Colombier     stream *ps;
2317dd7cddfSDavid du Colombier     stream_proc_state *ss;
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier     check_file(ps, op);
2347dd7cddfSDavid du Colombier     check_read_type(*opbuf, t_string);
2357dd7cddfSDavid du Colombier     while ((ps->end_status = 0, ps->strm) != 0)
2367dd7cddfSDavid du Colombier 	ps = ps->strm;
2377dd7cddfSDavid du Colombier     ss = (stream_proc_state *) ps->state;
2387dd7cddfSDavid du Colombier     ss->data = *opbuf;
2397dd7cddfSDavid du Colombier     ss->index = 0;
2407dd7cddfSDavid du Colombier     if (r_size(opbuf) == 0)
2417dd7cddfSDavid du Colombier 	ss->eof = true;
2427dd7cddfSDavid du Colombier     pop(2);
2437dd7cddfSDavid du Colombier     return 0;
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier /* ---------------- Write streams ---------------- */
2477dd7cddfSDavid du Colombier 
2487dd7cddfSDavid du Colombier /* Forward references */
2493ff48bf5SDavid du Colombier private stream_proc_flush(s_proc_write_flush);
2507dd7cddfSDavid du Colombier private stream_proc_process(s_proc_write_process);
251*593dc095SDavid du Colombier private int s_proc_write_continue(i_ctx_t *);
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier /* Stream templates */
2547dd7cddfSDavid du Colombier private const stream_template s_proc_write_template = {
2557dd7cddfSDavid du Colombier     &st_sproc_state, NULL, s_proc_write_process, 1, 1,
2567dd7cddfSDavid du Colombier     NULL, s_proc_set_defaults
2577dd7cddfSDavid du Colombier };
2587dd7cddfSDavid du Colombier private const stream_procs s_proc_write_procs = {
2597dd7cddfSDavid du Colombier     s_std_noavailable, s_std_noseek, s_std_write_reset,
2603ff48bf5SDavid du Colombier     s_proc_write_flush, s_std_null, NULL
2617dd7cddfSDavid du Colombier };
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier /* Allocate and open a procedure-based write stream. */
2647dd7cddfSDavid du Colombier /* The caller must have checked that *sop is a procedure. */
2657dd7cddfSDavid du Colombier int
swrite_proc(ref * sop,stream ** psstrm,gs_ref_memory_t * imem)2667dd7cddfSDavid du Colombier swrite_proc(ref * sop, stream ** psstrm, gs_ref_memory_t *imem)
2677dd7cddfSDavid du Colombier {
2687dd7cddfSDavid du Colombier     return s_proc_init(sop, psstrm, s_mode_write, &s_proc_write_template,
2697dd7cddfSDavid du Colombier 		       &s_proc_write_procs, imem);
2707dd7cddfSDavid du Colombier }
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier /* Handle an output request. */
2737dd7cddfSDavid du Colombier private int
s_proc_write_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * ignore_pw,bool last)2747dd7cddfSDavid du Colombier s_proc_write_process(stream_state * st, stream_cursor_read * pr,
2757dd7cddfSDavid du Colombier 		     stream_cursor_write * ignore_pw, bool last)
2767dd7cddfSDavid du Colombier {
2777dd7cddfSDavid du Colombier     /* Move data from the stream buffer to the string */
2787dd7cddfSDavid du Colombier     /* returned by the procedure, or ask for a callback. */
2797dd7cddfSDavid du Colombier     stream_proc_state *const ss = (stream_proc_state *) st;
2807dd7cddfSDavid du Colombier     uint rcount = pr->limit - pr->ptr;
2817dd7cddfSDavid du Colombier 
2827dd7cddfSDavid du Colombier     if (rcount > 0) {
2837dd7cddfSDavid du Colombier 	uint wcount = r_size(&ss->data) - ss->index;
2847dd7cddfSDavid du Colombier 	uint count = min(rcount, wcount);
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 	memcpy(ss->data.value.bytes + ss->index, pr->ptr + 1, count);
2877dd7cddfSDavid du Colombier 	pr->ptr += count;
2887dd7cddfSDavid du Colombier 	ss->index += count;
2897dd7cddfSDavid du Colombier 	if (rcount > wcount)
2907dd7cddfSDavid du Colombier 	    return CALLC;
2917dd7cddfSDavid du Colombier 	else if (last) {
2927dd7cddfSDavid du Colombier 	    ss->eof = true;
2937dd7cddfSDavid du Colombier 	    return CALLC;
2947dd7cddfSDavid du Colombier 	} else
2957dd7cddfSDavid du Colombier 	    return 0;
2967dd7cddfSDavid du Colombier     }
2977dd7cddfSDavid du Colombier     return ((ss->eof = last) ? EOFC : 0);
2987dd7cddfSDavid du Colombier }
2997dd7cddfSDavid du Colombier 
3003ff48bf5SDavid du Colombier /* Flush the output.  This is non-standard because it must call the */
3013ff48bf5SDavid du Colombier /* procedure. */
3023ff48bf5SDavid du Colombier private int
s_proc_write_flush(stream * s)3033ff48bf5SDavid du Colombier s_proc_write_flush(stream *s)
3043ff48bf5SDavid du Colombier {
3053ff48bf5SDavid du Colombier     int result = s_process_write_buf(s, false);
3063ff48bf5SDavid du Colombier     stream_proc_state *const ss = (stream_proc_state *)s->state;
3073ff48bf5SDavid du Colombier 
3083ff48bf5SDavid du Colombier     return (result < 0 || ss->index == 0 ? result : CALLC);
3093ff48bf5SDavid du Colombier }
3103ff48bf5SDavid du Colombier 
3117dd7cddfSDavid du Colombier /* Handle an exception (INTC or CALLC) from a write stream */
3127dd7cddfSDavid du Colombier /* whose buffer is full. */
3137dd7cddfSDavid du Colombier int
s_handle_write_exception(i_ctx_t * i_ctx_p,int status,const ref * fop,const ref * pstate,int nstate,op_proc_t cont)3147dd7cddfSDavid du Colombier s_handle_write_exception(i_ctx_t *i_ctx_p, int status, const ref * fop,
3157dd7cddfSDavid du Colombier 			 const ref * pstate, int nstate, op_proc_t cont)
3167dd7cddfSDavid du Colombier {
3177dd7cddfSDavid du Colombier     stream *ps;
3183ff48bf5SDavid du Colombier     stream *psstderr;
3193ff48bf5SDavid du Colombier     stream *psstdout;
3207dd7cddfSDavid du Colombier     stream_proc_state *psst;
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier     switch (status) {
3237dd7cddfSDavid du Colombier 	case INTC:
3247dd7cddfSDavid du Colombier 	    return s_handle_intc(i_ctx_p, pstate, nstate, cont);
3257dd7cddfSDavid du Colombier 	case CALLC:
3267dd7cddfSDavid du Colombier 	    break;
3277dd7cddfSDavid du Colombier 	default:
3287dd7cddfSDavid du Colombier 	    return_error(e_ioerror);
3297dd7cddfSDavid du Colombier     }
3307dd7cddfSDavid du Colombier     /* Find the stream whose buffer needs emptying. */
3317dd7cddfSDavid du Colombier     for (ps = fptr(fop); ps->strm != 0;)
3327dd7cddfSDavid du Colombier 	ps = ps->strm;
3337dd7cddfSDavid du Colombier     psst = (stream_proc_state *) ps->state;
3343ff48bf5SDavid du Colombier     {
3357dd7cddfSDavid du Colombier 	int npush = nstate + 6;
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier 	check_estack(npush);
3387dd7cddfSDavid du Colombier 	if (nstate)
3397dd7cddfSDavid du Colombier 	    memcpy(esp + 2, pstate, nstate * sizeof(ref));
3407dd7cddfSDavid du Colombier 	make_op_estack(esp + 1, cont);
3417dd7cddfSDavid du Colombier 	esp += npush;
3427dd7cddfSDavid du Colombier 	make_op_estack(esp - 4, s_proc_write_continue);
3437dd7cddfSDavid du Colombier 	esp[-3] = *fop;
3447dd7cddfSDavid du Colombier 	r_clear_attrs(esp - 3, a_executable);
3453ff48bf5SDavid du Colombier 	make_bool(esp - 1, !psst->eof);
3467dd7cddfSDavid du Colombier     }
3477dd7cddfSDavid du Colombier     esp[-2] = psst->proc;
3487dd7cddfSDavid du Colombier     *esp = psst->data;
3497dd7cddfSDavid du Colombier     r_set_size(esp, psst->index);
3503ff48bf5SDavid du Colombier 
3513ff48bf5SDavid du Colombier     /* If stream is stdout/err, ask for callout. */
3523ff48bf5SDavid du Colombier     zget_stdout(i_ctx_p, &psstdout);
3533ff48bf5SDavid du Colombier     zget_stderr(i_ctx_p, &psstderr);
3543ff48bf5SDavid du Colombier     if ((ps == psstderr) || (ps == psstdout)) {
3553ff48bf5SDavid du Colombier 	check_estack(1);
3563ff48bf5SDavid du Colombier 	esp += 1;
3573ff48bf5SDavid du Colombier 	make_op_estack(esp, (ps == psstderr) ? zneedstderr : zneedstdout);
3583ff48bf5SDavid du Colombier     }
3597dd7cddfSDavid du Colombier     return o_push_estack;
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier /* Continue a write operation after returning from a procedure callout. */
3627dd7cddfSDavid du Colombier /* osp[0] contains the file (pushed on the e-stack by handle_write_status); */
3637dd7cddfSDavid du Colombier /* osp[-1] contains the new buffer string (pushed by the procedure). */
3647dd7cddfSDavid du Colombier /* The top of the e-stack contains the real continuation. */
3657dd7cddfSDavid du Colombier private int
s_proc_write_continue(i_ctx_t * i_ctx_p)3667dd7cddfSDavid du Colombier s_proc_write_continue(i_ctx_t *i_ctx_p)
3677dd7cddfSDavid du Colombier {
3687dd7cddfSDavid du Colombier     os_ptr op = osp;
3697dd7cddfSDavid du Colombier     os_ptr opbuf = op - 1;
3707dd7cddfSDavid du Colombier     stream *ps;
3717dd7cddfSDavid du Colombier     stream_proc_state *ss;
3727dd7cddfSDavid du Colombier 
3737dd7cddfSDavid du Colombier     check_file(ps, op);
3747dd7cddfSDavid du Colombier     check_write_type(*opbuf, t_string);
3753ff48bf5SDavid du Colombier     while (ps->strm != 0) {
3763ff48bf5SDavid du Colombier 	if (ps->end_status == CALLC)
3773ff48bf5SDavid du Colombier 	    ps->end_status = 0;
3787dd7cddfSDavid du Colombier 	ps = ps->strm;
3793ff48bf5SDavid du Colombier     }
3803ff48bf5SDavid du Colombier     ps->end_status = 0;
3817dd7cddfSDavid du Colombier     ss = (stream_proc_state *) ps->state;
3827dd7cddfSDavid du Colombier     ss->data = *opbuf;
3837dd7cddfSDavid du Colombier     ss->index = 0;
3847dd7cddfSDavid du Colombier     pop(2);
3857dd7cddfSDavid du Colombier     return 0;
3867dd7cddfSDavid du Colombier }
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier /* ------ More generic ------ */
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier /* Test whether a stream is procedure-based. */
3917dd7cddfSDavid du Colombier bool
s_is_proc(const stream * s)3927dd7cddfSDavid du Colombier s_is_proc(const stream *s)
3937dd7cddfSDavid du Colombier {
3947dd7cddfSDavid du Colombier     return (s->procs.process == s_proc_read_process ||
3957dd7cddfSDavid du Colombier 	    s->procs.process == s_proc_write_process);
3967dd7cddfSDavid du Colombier }
3977dd7cddfSDavid du Colombier 
3987dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier const op_def zfproc_op_defs[] =
4017dd7cddfSDavid du Colombier {
4027dd7cddfSDavid du Colombier 		/* Internal operators */
4037dd7cddfSDavid du Colombier     {"2%s_proc_read_continue", s_proc_read_continue},
4047dd7cddfSDavid du Colombier     {"2%s_proc_write_continue", s_proc_write_continue},
4057dd7cddfSDavid du Colombier     op_def_end(0)
4067dd7cddfSDavid du Colombier };
407