xref: /plan9/sys/src/cmd/gs/src/ztoken.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1994, 2000 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: ztoken.c,v 1.14 2004/08/04 19:36:13 stefan Exp $ */
18 /* Token reading operators */
19 #include "string_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "dstack.h"		/* for dict_find_name */
23 #include "estack.h"
24 #include "gsstruct.h"		/* for iscan.h */
25 #include "stream.h"
26 #include "files.h"
27 #include "store.h"
28 #include "strimpl.h"		/* for sfilter.h */
29 #include "sfilter.h"		/* for iscan.h */
30 #include "idict.h"
31 #include "iname.h"
32 #include "iscan.h"
33 #include "itoken.h"		/* for prototypes */
34 
35 /* <file> token <obj> -true- */
36 /* <string> token <post> <obj> -true- */
37 /* <string|file> token -false- */
38 private int ztoken_continue(i_ctx_t *);
39 private int token_continue(i_ctx_t *, stream *, scanner_state *, bool);
40 int
ztoken(i_ctx_t * i_ctx_p)41 ztoken(i_ctx_t *i_ctx_p)
42 {
43     os_ptr op = osp;
44 
45     switch (r_type(op)) {
46 	default:
47 	    return_op_typecheck(op);
48 	case t_file: {
49 	    stream *s;
50 	    scanner_state state;
51 
52 	    check_read_file(s, op);
53 	    check_ostack(1);
54 	    scanner_state_init(&state, false);
55 	    return token_continue(i_ctx_p, s, &state, true);
56 	}
57 	case t_string: {
58 	    ref token;
59 	    int orig_ostack_depth = ref_stack_count(&o_stack);
60 	    int code = scan_string_token(i_ctx_p, op, &token);
61 
62 	    switch (code) {
63 	    case scan_EOF:	/* no tokens */
64 		make_false(op);
65 		return 0;
66 	    default:
67 		if (code < 0) {
68 		    /* Clear anything that may have been left on the ostack */
69 	    	    if (orig_ostack_depth < ref_stack_count(&o_stack))
70 	    		pop(ref_stack_count(&o_stack)- orig_ostack_depth);
71 		    return code;
72 		}
73 	    }
74 	    push(2);
75 	    op[-1] = token;
76 	    make_true(op);
77 	    return 0;
78 	}
79     }
80 }
81 /* Continue reading a token after an interrupt or callout. */
82 /* *op is the scanner state; op[-1] is the file. */
83 private int
ztoken_continue(i_ctx_t * i_ctx_p)84 ztoken_continue(i_ctx_t *i_ctx_p)
85 {
86     os_ptr op = osp;
87     stream *s;
88     scanner_state *pstate;
89 
90     check_read_file(s, op - 1);
91     check_stype(*op, st_scanner_state);
92     pstate = r_ptr(op, scanner_state);
93     pop(1);
94     return token_continue(i_ctx_p, s, pstate, false);
95 }
96 /* Common code for token reading. */
97 private int
token_continue(i_ctx_t * i_ctx_p,stream * s,scanner_state * pstate,bool save)98 token_continue(i_ctx_t *i_ctx_p, stream * s, scanner_state * pstate,
99 	       bool save)
100 {
101     os_ptr op = osp;
102     int code;
103     ref token;
104 
105     /* Note that scan_token may change osp! */
106     /* Also, we must temporarily remove the file from the o-stack */
107     /* when calling scan_token, in case we are scanning a procedure. */
108     ref fref;
109 
110     ref_assign(&fref, op);
111 again:
112     pop(1);
113     code = scan_token(i_ctx_p, s, &token, pstate);
114     op = osp;
115     switch (code) {
116 	default:		/* error */
117 	    if (code > 0)	/* comment, not possible */
118 		code = gs_note_error(e_syntaxerror);
119 	    push(1);
120 	    ref_assign(op, &fref);
121 	    break;
122 	case scan_BOS:
123 	    code = 0;
124 	case 0:		/* read a token */
125 	    push(2);
126 	    ref_assign(op - 1, &token);
127 	    make_true(op);
128 	    break;
129 	case scan_EOF:		/* no tokens */
130 	    push(1);
131 	    make_false(op);
132 	    code = 0;
133 	    break;
134 	case scan_Refill:	/* need more data */
135 	    push(1);
136 	    ref_assign(op, &fref);
137 	    code = scan_handle_refill(i_ctx_p, op, pstate, save, false,
138 				      ztoken_continue);
139 	    switch (code) {
140 		case 0:	/* state is not copied to the heap */
141 		    goto again;
142 		case o_push_estack:
143 		    return code;
144 	    }
145 	    break;		/* error */
146     }
147     if (code <= 0 && !save) {	/* Deallocate the scanner state record. */
148 	ifree_object(pstate, "token_continue");
149     }
150     return code;
151 }
152 
153 /* <file> .tokenexec - */
154 /* Read a token and do what the interpreter would do with it. */
155 /* This is different from token + exec because literal procedures */
156 /* are not executed (although binary object sequences ARE executed). */
157 int ztokenexec_continue(i_ctx_t *);	/* export for interpreter */
158 private int tokenexec_continue(i_ctx_t *, stream *, scanner_state *, bool);
159 int
ztokenexec(i_ctx_t * i_ctx_p)160 ztokenexec(i_ctx_t *i_ctx_p)
161 {
162     os_ptr op = osp;
163     stream *s;
164     scanner_state state;
165 
166     check_read_file(s, op);
167     check_estack(1);
168     scanner_state_init(&state, false);
169     return tokenexec_continue(i_ctx_p, s, &state, true);
170 }
171 /* Continue reading a token for execution after an interrupt or callout. */
172 /* *op is the scanner state; op[-1] is the file. */
173 /* We export this because this is how the interpreter handles a */
174 /* scan_Refill for an executable file. */
175 int
ztokenexec_continue(i_ctx_t * i_ctx_p)176 ztokenexec_continue(i_ctx_t *i_ctx_p)
177 {
178     os_ptr op = osp;
179     stream *s;
180     scanner_state *pstate;
181 
182     check_read_file(s, op - 1);
183     check_stype(*op, st_scanner_state);
184     pstate = r_ptr(op, scanner_state);
185     pop(1);
186     return tokenexec_continue(i_ctx_p, s, pstate, false);
187 }
188 /* Common code for token reading + execution. */
189 private int
tokenexec_continue(i_ctx_t * i_ctx_p,stream * s,scanner_state * pstate,bool save)190 tokenexec_continue(i_ctx_t *i_ctx_p, stream * s, scanner_state * pstate,
191 		   bool save)
192 {
193     os_ptr op = osp;
194     int code;
195     /* Note that scan_token may change osp! */
196     /* Also, we must temporarily remove the file from the o-stack */
197     /* when calling scan_token, in case we are scanning a procedure. */
198     ref fref;
199 
200     ref_assign(&fref, op);
201     pop(1);
202 again:
203     check_estack(1);
204     code = scan_token(i_ctx_p, s, (ref *) (esp + 1), pstate);
205     op = osp;
206     switch (code) {
207 	case 0:
208 	    if (r_is_proc(esp + 1)) {	/* Treat procedure as a literal. */
209 		push(1);
210 		ref_assign(op, esp + 1);
211 		code = 0;
212 		break;
213 	    }
214 	    /* falls through */
215 	case scan_BOS:
216 	    ++esp;
217 	    code = o_push_estack;
218 	    break;
219 	case scan_EOF:		/* no tokens */
220 	    code = 0;
221 	    break;
222 	case scan_Refill:	/* need more data */
223 	    code = scan_handle_refill(i_ctx_p, &fref, pstate, save, true,
224 				      ztokenexec_continue);
225 	    switch (code) {
226 		case 0:	/* state is not copied to the heap */
227 		    goto again;
228 		case o_push_estack:
229 		    return code;
230 	    }
231 	    break;		/* error */
232 	case scan_Comment:
233 	case scan_DSC_Comment:
234 	    return ztoken_handle_comment(i_ctx_p, &fref, pstate, esp + 1, code,
235 					 save, true, ztokenexec_continue);
236 	default:		/* error */
237 	    break;
238     }
239     if (code < 0) {		/* Push the operand back on the stack. */
240 	push(1);
241 	ref_assign(op, &fref);
242     }
243     if (!save) {		/* Deallocate the scanner state record. */
244 	ifree_object(pstate, "token_continue");
245     }
246     return code;
247 }
248 
249 /*
250  * Handle a scan_Comment or scan_DSC_Comment return from scan_token
251  * (scan_code) by calling out to %Process[DSC]Comment.  The continuation
252  * procedure expects the file and scanner state on the o-stack.
253  */
254 int
ztoken_handle_comment(i_ctx_t * i_ctx_p,const ref * fop,scanner_state * sstate,const ref * ptoken,int scan_code,bool save,bool push_file,op_proc_t cont)255 ztoken_handle_comment(i_ctx_t *i_ctx_p, const ref *fop, scanner_state *sstate,
256 		      const ref *ptoken, int scan_code,
257 		      bool save, bool push_file, op_proc_t cont)
258 {
259     const char *proc_name;
260     scanner_state *pstate;
261     os_ptr op;
262     ref *ppcproc;
263     int code;
264 
265     switch (scan_code) {
266     case scan_Comment:
267 	proc_name = "%ProcessComment";
268 	break;
269     case scan_DSC_Comment:
270 	proc_name = "%ProcessDSCComment";
271 	break;
272     default:
273 	return_error(e_Fatal);	/* can't happen */
274     }
275     /*
276      * We can't use check_ostack here, because it returns on overflow.
277      */
278     /*check_ostack(2);*/
279     if (ostop - osp < 2) {
280 	code = ref_stack_extend(&o_stack, 2);
281 	if (code < 0)
282 	    return code;
283     }
284     check_estack(4);
285     code = name_enter_string(imemory, proc_name, esp + 4);
286     if (code < 0)
287 	return code;
288     if (save) {
289 	pstate = ialloc_struct(scanner_state, &st_scanner_state,
290 			       "ztoken_handle_comment");
291 	if (pstate == 0)
292 	    return_error(e_VMerror);
293 	*pstate = *sstate;
294     } else
295 	pstate = sstate;
296     /* Save the token now -- it might be on the e-stack. */
297     if (!pstate->s_pstack)
298 	osp[2] = *ptoken;
299     /*
300      * Push the continuation, scanner state, file, and callout procedure
301      * on the e-stack.
302      */
303     make_op_estack(esp + 1, cont);
304     make_istruct(esp + 2, 0, pstate);
305     esp[3] = *fop;
306     r_clear_attrs(esp + 3, a_executable);
307     ppcproc = dict_find_name(esp + 4);
308     if (ppcproc == 0) {
309 	/*
310 	 * This can only happen during initialization.
311 	 * Pop the comment string from the o-stack if needed (see below).
312 	 */
313 	if (pstate->s_pstack)
314 	    --osp;
315 	esp += 3;		/* do run the continuation */
316     } else {
317 	/*
318 	 * Push the file and comment string on the o-stack.
319 	 * If we were inside { }, the comment string is already on the stack.
320 	 */
321 	if (pstate->s_pstack) {
322 	    op = ++osp;
323 	    *op = op[-1];
324 	} else {
325 	    op = osp += 2;
326 	    /* *op = *ptoken; */	/* saved above */
327 	}
328 	op[-1] = *fop;
329 	esp[4] = *ppcproc;
330 	esp += 4;
331     }
332     return o_push_estack;
333 }
334 
335 /*
336  * Update the cached scanner_options in the context state after doing a
337  * setuserparams.  (We might move this procedure somewhere else eventually.)
338  */
339 int
ztoken_scanner_options(const ref * upref,int old_options)340 ztoken_scanner_options(const ref *upref, int old_options)
341 {
342     typedef struct named_scanner_option_s {
343 	const char *pname;
344 	int option;
345     } named_scanner_option_t;
346     static const named_scanner_option_t named_options[4] = {
347 	{"ProcessComment", SCAN_PROCESS_COMMENTS},
348 	{"ProcessDSCComment", SCAN_PROCESS_DSC_COMMENTS},
349 	{"PDFScanRules", SCAN_PDF_RULES},
350 	{"PDFScanInvNum", SCAN_PDF_INV_NUM}
351     };
352     int options = old_options;
353     int i;
354 
355     for (i = 0; i < countof(named_options); ++i) {
356 	const named_scanner_option_t *pnso = &named_options[i];
357 	ref *ppcproc;
358 	int code = dict_find_string(upref, pnso->pname, &ppcproc);
359 
360 	/* Update the options only if the parameter has changed. */
361 	if (code >= 0) {
362 	    if (r_has_type(ppcproc, t_null))
363 		options &= ~pnso->option;
364 	    else
365 		options |= pnso->option;
366 	}
367     }
368     return options;
369 }
370 
371 /* ------ Initialization procedure ------ */
372 
373 const op_def ztoken_op_defs[] =
374 {
375     {"1token", ztoken},
376     {"1.tokenexec", ztokenexec},
377 		/* Internal operators */
378     {"2%ztokenexec_continue", ztokenexec_continue},
379     op_def_end(0)
380 };
381