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