1 /* Copyright (C) 1989, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: zcontrol.c,v 1.3.6.2.2.1 2003/01/17 00:49:05 giles Exp $ */
20 /* Control operators */
21 #include "string_.h"
22 #include "ghost.h"
23 #include "stream.h"
24 #include "oper.h"
25 #include "estack.h"
26 #include "files.h"
27 #include "ipacked.h"
28 #include "iutil.h"
29 #include "store.h"
30 
31 /* Forward references */
32 private int no_cleanup(P1(i_ctx_t *));
33 private uint count_exec_stack(P2(i_ctx_t *, bool));
34 private uint count_to_stopped(P2(i_ctx_t *, long));
35 private int unmatched_exit(P2(os_ptr, op_proc_t));
36 
37 /* See the comment in opdef.h for an invariant which allows */
38 /* more efficient implementation of for, loop, and repeat. */
39 
40 /* <[test0 body0 ...]> .cond - */
41 private int cond_continue(P1(i_ctx_t *));
42 private int
zcond(i_ctx_t * i_ctx_p)43 zcond(i_ctx_t *i_ctx_p)
44 {
45     os_ptr op = osp;
46     es_ptr ep = esp;
47 
48     /* Push the array on the e-stack and call the continuation. */
49     if (!r_is_array(op))
50 	return_op_typecheck(op);
51     check_execute(*op);
52     if ((r_size(op) & 1) != 0)
53 	return_error(e_rangecheck);
54     if (r_size(op) == 0)
55 	return zpop(i_ctx_p);
56     check_estack(3);
57     esp = ep += 3;
58     ref_assign(ep - 2, op);	/* the cond body */
59     make_op_estack(ep - 1, cond_continue);
60     array_get(op, 0L, ep);
61     esfile_check_cache();
62     pop(1);
63     return o_push_estack;
64 }
65 private int
cond_continue(i_ctx_t * i_ctx_p)66 cond_continue(i_ctx_t *i_ctx_p)
67 {
68     os_ptr op = osp;
69     es_ptr ep = esp;
70     int code;
71 
72     /* The top element of the e-stack is the remaining tail of */
73     /* the cond body.  The top element of the o-stack should be */
74     /* the (boolean) result of the test that is the first element */
75     /* of the tail. */
76     check_type(*op, t_boolean);
77     if (op->value.boolval) {	/* true */
78 	array_get(ep, 1L, ep);
79 	esfile_check_cache();
80 	code = o_pop_estack;
81     } else if (r_size(ep) > 2) {	/* false */
82 	const ref_packed *elts = ep->value.packed;
83 
84 	check_estack(2);
85 	r_dec_size(ep, 2);
86 	elts = packed_next(elts);
87 	elts = packed_next(elts);
88 	ep->value.packed = elts;
89 	array_get(ep, 0L, ep + 2);
90 	make_op_estack(ep + 1, cond_continue);
91 	esp = ep + 2;
92 	esfile_check_cache();
93 	code = o_push_estack;
94     } else {			/* fall off end of cond */
95 	esp = ep - 1;
96 	code = o_pop_estack;
97     }
98     pop(1);			/* get rid of the boolean */
99     return code;
100 }
101 
102 /* <obj> exec - */
103 int
zexec(i_ctx_t * i_ctx_p)104 zexec(i_ctx_t *i_ctx_p)
105 {
106     os_ptr op = osp;
107 
108     check_op(1);
109     if (!r_has_attr(op, a_executable))
110 	return 0;		/* literal object just gets pushed back */
111     check_estack(1);
112     ++esp;
113     ref_assign(esp, op);
114     esfile_check_cache();
115     pop(1);
116     return o_push_estack;
117 }
118 
119 /* <obj1> ... <objn> <n> .execn - */
120 private int
zexecn(i_ctx_t * i_ctx_p)121 zexecn(i_ctx_t *i_ctx_p)
122 {
123     os_ptr op = osp;
124     uint n, i;
125     es_ptr esp_orig;
126 
127     check_int_leu(*op, max_uint - 1);
128     n = (uint) op->value.intval;
129     check_op(n + 1);
130     check_estack(n);
131     esp_orig = esp;
132     for (i = 0; i < n; ++i) {
133 	const ref *rp = ref_stack_index(&o_stack, (long)(i + 1));
134 
135 	/* Make sure this object is legal to execute. */
136 	if (ref_type_uses_access(r_type(rp))) {
137 	    if (!r_has_attr(rp, a_execute) &&
138 		r_has_attr(rp, a_executable)
139 		) {
140 		esp = esp_orig;
141 		return_error(e_invalidaccess);
142 	    }
143 	}
144 	/* Executable nulls have a special meaning on the e-stack, */
145 	/* so since they are no-ops, don't push them. */
146 	if (!r_has_type_attrs(rp, t_null, a_executable)) {
147 	    ++esp;
148 	    ref_assign(esp, rp);
149 	}
150     }
151     esfile_check_cache();
152     pop(n + 1);
153     return o_push_estack;
154 }
155 
156 /* <obj> superexec - */
157 private int end_superexec(P1(i_ctx_t *));
158 private int
zsuperexec(i_ctx_t * i_ctx_p)159 zsuperexec(i_ctx_t *i_ctx_p)
160 {
161     os_ptr op = osp;
162     es_ptr ep;
163 
164     check_op(1);
165     if (!r_has_attr(op, a_executable))
166 	return 0;		/* literal object just gets pushed back */
167     check_estack(2);
168     ep = esp += 3;
169     make_mark_estack(ep - 2, es_other, end_superexec); /* error case */
170     make_op_estack(ep - 1,  end_superexec); /* normal case */
171     ref_assign(ep, op);
172     esfile_check_cache();
173     pop(1);
174     i_ctx_p->in_superexec++;
175     return o_push_estack;
176 }
177 private int
end_superexec(i_ctx_t * i_ctx_p)178 end_superexec(i_ctx_t *i_ctx_p)
179 {
180     i_ctx_p->in_superexec--;
181     return 0;
182 }
183 
184 /* <array> <executable> .runandhide <obj>				*/
185 /* 	before executing  <executable>, <array> is been removed from	*/
186 /*	the operand stack and placed on the execstack with attributes	*/
187 /* 	changed to 'noaccess'.						*/
188 /* 	After execution, the array will be placed on  the top of the	*/
189 /*	operand stack (on top of any elemetns pushed by <executable>	*/
190 /*	for both the normal case and for the error case.		*/
191 private int end_runandhide(P1(i_ctx_t *));
192 private int err_end_runandhide(P1(i_ctx_t *));
193 private int
zrunandhide(i_ctx_t * i_ctx_p)194 zrunandhide(i_ctx_t *i_ctx_p)
195 {
196     os_ptr op = osp;
197     es_ptr ep;
198     uint size;
199     int code;
200 
201     check_op(2);
202     if (!r_is_array(op - 1))
203 	return_op_typecheck(op);
204     if (!r_has_attr(op, a_executable))
205 	return 0;		/* literal object just gets pushed back */
206     check_estack(5);
207     ep = esp += 5;
208     make_mark_estack(ep - 4, es_other, err_end_runandhide); /* error case */
209     make_op_estack(ep - 1,  end_runandhide); /* normal case */
210     ref_assign(ep, op);
211     /* Store the object we are hiding  and it's current tas.type_attrs */
212     /* on the exec stack then change to 'noaccess' */
213     make_int(ep - 3, (int)op[-1].tas.type_attrs);
214     ref_assign(ep - 2, op - 1);
215     r_clear_attrs(ep - 2, a_all);
216     /* replace the array with a special kind of mark that has a_read access */
217     esfile_check_cache();
218     pop(2);
219     return o_push_estack;
220 }
221 private int
runandhide_restore_hidden(i_ctx_t * i_ctx_p,ref * obj,ref * attrs)222 runandhide_restore_hidden(i_ctx_t *i_ctx_p, ref *obj, ref *attrs)
223 {
224     os_ptr op = osp;
225 
226     push(1);
227     /* restore the hidden_object and its type_attrs */
228     ref_assign(op, obj);
229     r_clear_attrs(op, a_all);
230     r_set_attrs(op, attrs->value.intval);
231     return 0;
232 }
233 
234 /* - %end_runandhide hiddenobject */
235 private int
end_runandhide(i_ctx_t * i_ctx_p)236 end_runandhide(i_ctx_t *i_ctx_p)
237 {
238     int code;
239 
240     if ((code = runandhide_restore_hidden(i_ctx_p, esp, esp - 1)) < 0)
241         return code;
242     esp -= 2;		/* pop the hidden value and its atributes */
243     return o_pop_estack;
244 }
245 
246 /* restore hidden object for error returns */
247 private int
err_end_runandhide(i_ctx_t * i_ctx_p)248 err_end_runandhide(i_ctx_t *i_ctx_p)
249 {
250     int code;
251 
252     if ((code = runandhide_restore_hidden(i_ctx_p, esp + 3, esp + 2)) < 0)
253         return code;
254     return 0;
255 }
256 
257 /* <bool> <proc> if - */
258 int
zif(i_ctx_t * i_ctx_p)259 zif(i_ctx_t *i_ctx_p)
260 {
261     os_ptr op = osp;
262 
263     check_type(op[-1], t_boolean);
264     check_proc(*op);
265     if (op[-1].value.boolval) {
266 	check_estack(1);
267 	++esp;
268 	ref_assign(esp, op);
269 	esfile_check_cache();
270     }
271     pop(2);
272     return o_push_estack;
273 }
274 
275 /* <bool> <proc_true> <proc_false> ifelse - */
276 int
zifelse(i_ctx_t * i_ctx_p)277 zifelse(i_ctx_t *i_ctx_p)
278 {
279     os_ptr op = osp;
280 
281     check_type(op[-2], t_boolean);
282     check_proc(op[-1]);
283     check_proc(*op);
284     check_estack(1);
285     ++esp;
286     if (op[-2].value.boolval) {
287 	ref_assign(esp, op - 1);
288     } else {
289 	ref_assign(esp, op);
290     }
291     esfile_check_cache();
292     pop(3);
293     return o_push_estack;
294 }
295 
296 /* <init> <step> <limit> <proc> for - */
297 private int
298     for_pos_int_continue(P1(i_ctx_t *)),
299     for_neg_int_continue(P1(i_ctx_t *)),
300     for_real_continue(P1(i_ctx_t *));
301 int
zfor(i_ctx_t * i_ctx_p)302 zfor(i_ctx_t *i_ctx_p)
303 {
304     os_ptr op = osp;
305     register es_ptr ep;
306 
307     check_estack(7);
308     ep = esp + 6;
309     check_proc(*op);
310     /* Push a mark, the control variable, the initial value, */
311     /* the increment, the limit, and the procedure, */
312     /* and invoke the continuation operator. */
313     if (r_has_type(op - 3, t_integer) &&
314 	r_has_type(op - 2, t_integer)
315 	) {
316 	make_int(ep - 4, op[-3].value.intval);
317 	make_int(ep - 3, op[-2].value.intval);
318 	switch (r_type(op - 1)) {
319 	    case t_integer:
320 		make_int(ep - 2, op[-1].value.intval);
321 		break;
322 	    case t_real:
323 		make_int(ep - 2, (long)op[-1].value.realval);
324 		break;
325 	    default:
326 		return_op_typecheck(op - 1);
327 	}
328 	if (ep[-3].value.intval >= 0)
329 	    make_op_estack(ep, for_pos_int_continue);
330 	else
331 	    make_op_estack(ep, for_neg_int_continue);
332     } else {
333 	float params[3];
334 	int code;
335 
336 	if ((code = float_params(op - 1, 3, params)) < 0)
337 	    return code;
338 	make_real(ep - 4, params[0]);
339 	make_real(ep - 3, params[1]);
340 	make_real(ep - 2, params[2]);
341 	make_op_estack(ep, for_real_continue);
342     }
343     make_mark_estack(ep - 5, es_for, no_cleanup);
344     ref_assign(ep - 1, op);
345     esp = ep;
346     pop(4);
347     return o_push_estack;
348 }
349 /* Continuation operators for for, separate for positive integer, */
350 /* negative integer, and real. */
351 /* Execution stack contains mark, control variable, increment, */
352 /* limit, and procedure (procedure is topmost.) */
353 /* Continuation operator for positive integers. */
354 private int
for_pos_int_continue(i_ctx_t * i_ctx_p)355 for_pos_int_continue(i_ctx_t *i_ctx_p)
356 {
357     os_ptr op = osp;
358     register es_ptr ep = esp;
359     int var = ep[-3].value.intval;
360 
361     if (var > ep[-1].value.intval) {
362 	esp -= 5;		/* pop everything */
363 	return o_pop_estack;
364     }
365     push(1);
366     make_int(op, var);
367     ep[-3].value.intval = var + ep[-2].value.intval;
368     ref_assign_inline(ep + 2, ep);	/* saved proc */
369     esp = ep + 2;
370     return o_push_estack;
371 }
372 /* Continuation operator for negative integers. */
373 private int
for_neg_int_continue(i_ctx_t * i_ctx_p)374 for_neg_int_continue(i_ctx_t *i_ctx_p)
375 {
376     os_ptr op = osp;
377     register es_ptr ep = esp;
378     int var = ep[-3].value.intval;
379 
380     if (var < ep[-1].value.intval) {
381 	esp -= 5;		/* pop everything */
382 	return o_pop_estack;
383     }
384     push(1);
385     make_int(op, var);
386     ep[-3].value.intval = var + ep[-2].value.intval;
387     ref_assign(ep + 2, ep);	/* saved proc */
388     esp = ep + 2;
389     return o_push_estack;
390 }
391 /* Continuation operator for reals. */
392 private int
for_real_continue(i_ctx_t * i_ctx_p)393 for_real_continue(i_ctx_t *i_ctx_p)
394 {
395     os_ptr op = osp;
396     es_ptr ep = esp;
397     float var = ep[-3].value.realval;
398     float incr = ep[-2].value.realval;
399 
400     if (incr >= 0 ? (var > ep[-1].value.realval) :
401 	(var < ep[-1].value.realval)
402 	) {
403 	esp -= 5;		/* pop everything */
404 	return o_pop_estack;
405     }
406     push(1);
407     ref_assign(op, ep - 3);
408     ep[-3].value.realval = var + incr;
409     esp = ep + 2;
410     ref_assign(ep + 2, ep);	/* saved proc */
411     return o_push_estack;
412 }
413 
414 /* Here we provide an internal variant of 'for' that enumerates the */
415 /* values 0, 1/N, 2/N, ..., 1 precisely.  The arguments must be */
416 /* the integers 0, 1, and N.  We need this for */
417 /* loading caches such as the transfer function cache. */
418 private int for_fraction_continue(P1(i_ctx_t *));
419 int
zfor_fraction(i_ctx_t * i_ctx_p)420 zfor_fraction(i_ctx_t *i_ctx_p)
421 {
422     int code = zfor(i_ctx_p);
423 
424     if (code < 0)
425 	return code;		/* shouldn't ever happen! */
426     make_op_estack(esp, for_fraction_continue);
427     return code;
428 }
429 /* Continuation procedure */
430 private int
for_fraction_continue(i_ctx_t * i_ctx_p)431 for_fraction_continue(i_ctx_t *i_ctx_p)
432 {
433     register es_ptr ep = esp;
434     int code = for_pos_int_continue(i_ctx_p);
435 
436     if (code != o_push_estack)
437 	return code;
438     /* We must use osp instead of op here, because */
439     /* for_pos_int_continue pushes a value on the o-stack. */
440     make_real(osp, (float)osp->value.intval / ep[-1].value.intval);
441     return code;
442 }
443 
444 /* <int> <proc> repeat - */
445 private int repeat_continue(P1(i_ctx_t *));
446 private int
zrepeat(i_ctx_t * i_ctx_p)447 zrepeat(i_ctx_t *i_ctx_p)
448 {
449     os_ptr op = osp;
450     check_type(op[-1], t_integer);
451     check_proc(*op);
452     if (op[-1].value.intval < 0)
453 	return_error(e_rangecheck);
454     check_estack(5);
455     /* Push a mark, the count, and the procedure, and invoke */
456     /* the continuation operator. */
457     push_mark_estack(es_for, no_cleanup);
458     *++esp = op[-1];
459     *++esp = *op;
460     make_op_estack(esp + 1, repeat_continue);
461     pop(2);
462     return repeat_continue(i_ctx_p);
463 }
464 /* Continuation operator for repeat */
465 private int
repeat_continue(i_ctx_t * i_ctx_p)466 repeat_continue(i_ctx_t *i_ctx_p)
467 {
468     es_ptr ep = esp;		/* saved proc */
469 
470     if (--(ep[-1].value.intval) >= 0) {		/* continue */
471 	esp += 2;
472 	ref_assign(esp, ep);
473 	return o_push_estack;
474     } else {			/* done */
475 	esp -= 3;		/* pop mark, count, proc */
476 	return o_pop_estack;
477     }
478 }
479 
480 /* <proc> loop */
481 private int loop_continue(P1(i_ctx_t *));
482 private int
zloop(i_ctx_t * i_ctx_p)483 zloop(i_ctx_t *i_ctx_p)
484 {
485     os_ptr op = osp;
486 
487     check_proc(*op);
488     check_estack(4);
489     /* Push a mark and the procedure, and invoke */
490     /* the continuation operator. */
491     push_mark_estack(es_for, no_cleanup);
492     *++esp = *op;
493     make_op_estack(esp + 1, loop_continue);
494     pop(1);
495     return loop_continue(i_ctx_p);
496 }
497 /* Continuation operator for loop */
498 private int
loop_continue(i_ctx_t * i_ctx_p)499 loop_continue(i_ctx_t *i_ctx_p)
500 {
501     register es_ptr ep = esp;	/* saved proc */
502 
503     ref_assign(ep + 2, ep);
504     esp = ep + 2;
505     return o_push_estack;
506 }
507 
508 /* - exit - */
509 private int
zexit(i_ctx_t * i_ctx_p)510 zexit(i_ctx_t *i_ctx_p)
511 {
512     os_ptr op = osp;
513     ref_stack_enum_t rsenum;
514     uint scanned = 0;
515 
516     ref_stack_enum_begin(&rsenum, &e_stack);
517     do {
518 	uint used = rsenum.size;
519 	es_ptr ep = rsenum.ptr + used - 1;
520 	uint count = used;
521 
522 	for (; count; count--, ep--)
523 	    if (r_is_estack_mark(ep))
524 		switch (estack_mark_index(ep)) {
525 		    case es_for:
526 			pop_estack(i_ctx_p, scanned + (used - count + 1));
527 			return o_pop_estack;
528 		    case es_stopped:
529 			return_error(e_invalidexit);	/* not a loop */
530 		}
531 	scanned += used;
532     } while (ref_stack_enum_next(&rsenum));
533     /* No mark, quit.  (per Adobe documentation) */
534     push(2);
535     return unmatched_exit(op, zexit);
536 }
537 
538 /*
539  * .stopped pushes the following on the e-stack:
540  *      - A mark with type = es_stopped and procedure = no_cleanup.
541  *      - The result to be pushed on a normal return.
542  *      - The signal mask for .stop.
543  *      - The procedure %stopped_push, to handle the normal return case.
544  */
545 
546 /* In the normal (no-error) case, pop the mask from the e-stack, */
547 /* and move the result to the o-stack. */
548 private int
stopped_push(i_ctx_t * i_ctx_p)549 stopped_push(i_ctx_t *i_ctx_p)
550 {
551     os_ptr op = osp;
552 
553     push(1);
554     *op = esp[-1];
555     esp -= 3;
556     return o_pop_estack;
557 }
558 
559 /* - stop - */
560 /* Equivalent to true 1 .stop. */
561 /* This is implemented in C because if were a pseudo-operator, */
562 /* the stacks would get restored in case of an error. */
563 private int
zstop(i_ctx_t * i_ctx_p)564 zstop(i_ctx_t *i_ctx_p)
565 {
566     os_ptr op = osp;
567     uint count = count_to_stopped(i_ctx_p, 1L);
568 
569     if (count) {
570 	/*
571 	 * If there are any t_oparrays on the e-stack, they will pop
572 	 * any new items from the o-stack.  Wait to push the 'true'
573 	 * until we have run all the unwind procedures.
574 	 */
575 	check_ostack(2);
576 	pop_estack(i_ctx_p, count);
577 	op = osp;
578 	push(1);
579 	make_true(op);
580 	return o_pop_estack;
581     }
582     /* No mark, quit.  (per Adobe documentation) */
583     push(2);
584     return unmatched_exit(op, zstop);
585 }
586 
587 /* <result> <mask> .stop - */
588 private int
zzstop(i_ctx_t * i_ctx_p)589 zzstop(i_ctx_t *i_ctx_p)
590 {
591     os_ptr op = osp;
592     uint count;
593 
594     check_type(*op, t_integer);
595     count = count_to_stopped(i_ctx_p, op->value.intval);
596     if (count) {
597 	/*
598 	 * If there are any t_oparrays on the e-stack, they will pop
599 	 * any new items from the o-stack.  Wait to push the result
600 	 * until we have run all the unwind procedures.
601 	 */
602 	ref save_result;
603 
604 	check_op(2);
605 	save_result = op[-1];
606 	pop(2);
607 	pop_estack(i_ctx_p, count);
608 	op = osp;
609 	push(1);
610 	*op = save_result;
611 	return o_pop_estack;
612     }
613     /* No mark, quit.  (per Adobe documentation) */
614     return unmatched_exit(op, zzstop);
615 }
616 
617 /* <obj> stopped <stopped> */
618 /* Equivalent to false 1 .stopped. */
619 /* This is implemented in C because if were a pseudo-operator, */
620 /* the stacks would get restored in case of an error. */
621 private int
zstopped(i_ctx_t * i_ctx_p)622 zstopped(i_ctx_t *i_ctx_p)
623 {
624     os_ptr op = osp;
625     check_op(1);
626     /* Mark the execution stack, and push the default result */
627     /* in case control returns normally. */
628     check_estack(5);
629     push_mark_estack(es_stopped, no_cleanup);
630     ++esp;
631     make_false(esp);		/* save the result */
632     ++esp;
633     make_int(esp, 1);		/* save the signal mask */
634     push_op_estack(stopped_push);
635     *++esp = *op;		/* execute the operand */
636     esfile_check_cache();
637     pop(1);
638     return o_push_estack;
639 }
640 
641 /* <obj> <result> <mask> .stopped <result> */
642 private int
zzstopped(i_ctx_t * i_ctx_p)643 zzstopped(i_ctx_t *i_ctx_p)
644 {
645     os_ptr op = osp;
646     check_type(*op, t_integer);
647     check_op(3);
648     /* Mark the execution stack, and push the default result */
649     /* in case control returns normally. */
650     check_estack(5);
651     push_mark_estack(es_stopped, no_cleanup);
652     *++esp = op[-1];		/* save the result */
653     *++esp = *op;		/* save the signal mask */
654     push_op_estack(stopped_push);
655     *++esp = op[-2];		/* execute the operand */
656     esfile_check_cache();
657     pop(3);
658     return o_push_estack;
659 }
660 
661 /* <mask> .instopped false */
662 /* <mask> .instopped <result> true */
663 private int
zinstopped(i_ctx_t * i_ctx_p)664 zinstopped(i_ctx_t *i_ctx_p)
665 {
666     os_ptr op = osp;
667     uint count;
668 
669     check_type(*op, t_integer);
670     count = count_to_stopped(i_ctx_p, op->value.intval);
671     if (count) {
672 	push(1);
673 	op[-1] = *ref_stack_index(&e_stack, count - 2);		/* default result */
674 	make_true(op);
675     } else
676 	make_false(op);
677     return 0;
678 }
679 
680 /* <include_marks> .countexecstack <int> */
681 /* - countexecstack <int> */
682 /* countexecstack is an operator solely for the sake of the Genoa tests. */
683 private int
zcountexecstack(i_ctx_t * i_ctx_p)684 zcountexecstack(i_ctx_t *i_ctx_p)
685 {
686     os_ptr op = osp;
687 
688     push(1);
689     make_int(op, count_exec_stack(i_ctx_p, false));
690     return 0;
691 }
692 private int
zcountexecstack1(i_ctx_t * i_ctx_p)693 zcountexecstack1(i_ctx_t *i_ctx_p)
694 {
695     os_ptr op = osp;
696 
697     check_type(*op, t_boolean);
698     make_int(op, count_exec_stack(i_ctx_p, op->value.boolval));
699     return 0;
700 }
701 
702 /* <array> <include_marks> .execstack <subarray> */
703 /* <array> execstack <subarray> */
704 /* execstack is an operator solely for the sake of the Genoa tests. */
705 private int execstack_continue(P1(i_ctx_t *));
706 private int execstack2_continue(P1(i_ctx_t *));
707 private int
push_execstack(i_ctx_t * i_ctx_p,os_ptr op1,bool include_marks,op_proc_t cont)708 push_execstack(i_ctx_t *i_ctx_p, os_ptr op1, bool include_marks,
709 	       op_proc_t cont)
710 {
711     uint size;
712     /*
713      * We can't do this directly, because the interpreter
714      * might have cached some state.  To force the interpreter
715      * to update the stored state, we push a continuation on
716      * the exec stack; the continuation is executed immediately,
717      * and does the actual transfer.
718      */
719     uint depth;
720 
721     check_write_type(*op1, t_array);
722     size = r_size(op1);
723     depth = count_exec_stack(i_ctx_p, include_marks);
724     if (depth > size)
725 	return_error(e_rangecheck);
726     {
727 	int code = ref_stack_store_check(&e_stack, op1, size, 0);
728 
729 	if (code < 0)
730 	    return code;
731     }
732     check_estack(1);
733     r_set_size(op1, depth);
734     push_op_estack(cont);
735     return o_push_estack;
736 }
737 private int
zexecstack(i_ctx_t * i_ctx_p)738 zexecstack(i_ctx_t *i_ctx_p)
739 {
740     os_ptr op = osp;
741 
742     return push_execstack(i_ctx_p, op, false, execstack_continue);
743 }
744 private int
zexecstack2(i_ctx_t * i_ctx_p)745 zexecstack2(i_ctx_t *i_ctx_p)
746 {
747     os_ptr op = osp;
748 
749     check_type(*op, t_boolean);
750     return push_execstack(i_ctx_p, op - 1, op->value.boolval, execstack2_continue);
751 }
752 /* Continuation operator to do the actual transfer. */
753 /* r_size(op1) was set just above. */
754 private int
do_execstack(i_ctx_t * i_ctx_p,bool include_marks,os_ptr op1)755 do_execstack(i_ctx_t *i_ctx_p, bool include_marks, os_ptr op1)
756 {
757     os_ptr op = osp;
758     ref *arefs = op1->value.refs;
759     uint asize = r_size(op1);
760     uint i;
761     ref *rq;
762 
763     /*
764      * Copy elements from the stack to the array,
765      * optionally skipping executable nulls.
766      * Clear the executable bit in any internal operators, and
767      * convert t_structs and t_astructs (which can only appear
768      * in connection with stack marks, which means that they will
769      * probably be freed when unwinding) to something harmless.
770      */
771     for (i = 0, rq = arefs + asize; rq != arefs; ++i) {
772 	const ref *rp = ref_stack_index(&e_stack, (long)i);
773 
774 	if (r_has_type_attrs(rp, t_null, a_executable) && !include_marks)
775 	    continue;
776 	--rq;
777 	ref_assign_old(op1, rq, rp, "execstack");
778 	switch (r_type(rq)) {
779 	    case t_operator: {
780 		uint opidx = op_index(rq);
781 
782 		if (opidx == 0 || op_def_is_internal(op_index_def(opidx)))
783 		    r_clear_attrs(rq, a_executable);
784 		break;
785 	    }
786 	    case t_struct:
787 	    case t_astruct: {
788 		const char *tname =
789 		    gs_struct_type_name_string(
790 				gs_object_type(imemory, rq->value.pstruct));
791 
792 		make_const_string(rq, a_readonly | avm_foreign,
793 				  strlen(tname), (const byte *)tname);
794 		break;
795 	    }
796 	    default:
797 		;
798 	}
799     }
800     pop(op - op1);
801     return 0;
802 }
803 private int
execstack_continue(i_ctx_t * i_ctx_p)804 execstack_continue(i_ctx_t *i_ctx_p)
805 {
806     os_ptr op = osp;
807 
808     return do_execstack(i_ctx_p, false, op);
809 }
810 private int
execstack2_continue(i_ctx_t * i_ctx_p)811 execstack2_continue(i_ctx_t *i_ctx_p)
812 {
813     os_ptr op = osp;
814 
815     return do_execstack(i_ctx_p, op->value.boolval, op - 1);
816 }
817 
818 /* - .needinput - */
819 private int
zneedinput(i_ctx_t * i_ctx_p)820 zneedinput(i_ctx_t *i_ctx_p)
821 {
822     return e_NeedInput;		/* interpreter will exit to caller */
823 }
824 
825 /* <obj> <int> .quit - */
826 private int
zquit(i_ctx_t * i_ctx_p)827 zquit(i_ctx_t *i_ctx_p)
828 {
829     os_ptr op = osp;
830 
831     check_op(2);
832     check_type(*op, t_integer);
833     return_error(e_Quit);	/* Interpreter will do the exit */
834 }
835 
836 /* - currentfile <file> */
837 private ref *zget_current_file(P1(i_ctx_t *));
838 private int
zcurrentfile(i_ctx_t * i_ctx_p)839 zcurrentfile(i_ctx_t *i_ctx_p)
840 {
841     os_ptr op = osp;
842     ref *fp;
843 
844     push(1);
845     /* Check the cache first */
846     if (esfile != 0) {
847 #ifdef DEBUG
848 	/* Check that esfile is valid. */
849 	ref *efp = zget_current_file(i_ctx_p);
850 
851 	if (esfile != efp) {
852 	    lprintf2("currentfile: esfile=0x%lx, efp=0x%lx\n",
853 		     (ulong) esfile, (ulong) efp);
854 	    ref_assign(op, efp);
855 	} else
856 #endif
857 	    ref_assign(op, esfile);
858     } else if ((fp = zget_current_file(i_ctx_p)) == 0) {	/* Return an invalid file object. */
859 	/* This doesn't make a lot of sense to me, */
860 	/* but it's what the PostScript manual specifies. */
861 	make_invalid_file(op);
862     } else {
863 	ref_assign(op, fp);
864 	esfile_set_cache(fp);
865     }
866     /* Make the returned value literal. */
867     r_clear_attrs(op, a_executable);
868     return 0;
869 }
870 /* Get the current file from which the interpreter is reading. */
871 private ref *
zget_current_file(i_ctx_t * i_ctx_p)872 zget_current_file(i_ctx_t *i_ctx_p)
873 {
874     ref_stack_enum_t rsenum;
875 
876     ref_stack_enum_begin(&rsenum, &e_stack);
877     do {
878 	uint count = rsenum.size;
879 	es_ptr ep = rsenum.ptr + count - 1;
880 
881 	for (; count; count--, ep--)
882 	    if (r_has_type_attrs(ep, t_file, a_executable))
883 		return ep;
884     } while (ref_stack_enum_next(&rsenum));
885     return 0;
886 }
887 
888 /* ------ Initialization procedure ------ */
889 
890 /* We need to split the table because of the 16-element limit. */
891 const op_def zcontrol1_op_defs[] = {
892     {"1.cond", zcond},
893     {"0countexecstack", zcountexecstack},
894     {"1.countexecstack", zcountexecstack1},
895     {"0currentfile", zcurrentfile},
896     {"1exec", zexec},
897     {"1.execn", zexecn},
898     {"1execstack", zexecstack},
899     {"2.execstack", zexecstack2},
900     {"0exit", zexit},
901     {"2if", zif},
902     {"3ifelse", zifelse},
903     {"0.instopped", zinstopped},
904     {"0.needinput", zneedinput},
905     op_def_end(0)
906 };
907 const op_def zcontrol2_op_defs[] = {
908     {"4for", zfor},
909     {"1loop", zloop},
910     {"2.quit", zquit},
911     {"2repeat", zrepeat},
912     {"0stop", zstop},
913     {"1.stop", zzstop},
914     {"1stopped", zstopped},
915     {"2.stopped", zzstopped},
916     op_def_end(0)
917 };
918 const op_def zcontrol3_op_defs[] = {
919 		/* Internal operators */
920     {"1%cond_continue", cond_continue},
921     {"1%execstack_continue", execstack_continue},
922     {"2%execstack2_continue", execstack2_continue},
923     {"0%for_pos_int_continue", for_pos_int_continue},
924     {"0%for_neg_int_continue", for_neg_int_continue},
925     {"0%for_real_continue", for_real_continue},
926     {"4%for_fraction", zfor_fraction},
927     {"0%for_fraction_continue", for_fraction_continue},
928     {"0%loop_continue", loop_continue},
929     {"0%repeat_continue", repeat_continue},
930     {"0%stopped_push", stopped_push},
931     {"1superexec", zsuperexec},
932     {"0%end_superexec", end_superexec},
933     {"2.runandhide", zrunandhide},
934     {"0%end_runandhide", end_runandhide},
935     op_def_end(0)
936 };
937 
938 /* ------ Internal routines ------ */
939 
940 /* Vacuous cleanup routine */
941 private int
no_cleanup(i_ctx_t * i_ctx_p)942 no_cleanup(i_ctx_t *i_ctx_p)
943 {
944     return 0;
945 }
946 
947 /*
948  * Count the number of elements on the exec stack, with or without
949  * the normally invisible elements (*op is a Boolean that indicates this).
950  */
951 private uint
count_exec_stack(i_ctx_t * i_ctx_p,bool include_marks)952 count_exec_stack(i_ctx_t *i_ctx_p, bool include_marks)
953 {
954     uint count = ref_stack_count(&e_stack);
955 
956     if (!include_marks) {
957 	uint i;
958 
959 	for (i = count; i--;)
960 	    if (r_has_type_attrs(ref_stack_index(&e_stack, (long)i),
961 				 t_null, a_executable))
962 		--count;
963     }
964     return count;
965 }
966 
967 /*
968  * Count the number of elements down to and including the first 'stopped'
969  * mark on the e-stack with a given mask.  Return 0 if there is no 'stopped'
970  * mark.
971  */
972 private uint
count_to_stopped(i_ctx_t * i_ctx_p,long mask)973 count_to_stopped(i_ctx_t *i_ctx_p, long mask)
974 {
975     ref_stack_enum_t rsenum;
976     uint scanned = 0;
977 
978     ref_stack_enum_begin(&rsenum, &e_stack);
979     do {
980 	uint used = rsenum.size;
981 	es_ptr ep = rsenum.ptr + used - 1;
982 	uint count = used;
983 
984 	for (; count; count--, ep--)
985 	    if (r_is_estack_mark(ep) &&
986 		estack_mark_index(ep) == es_stopped &&
987 		(ep[2].value.intval & mask) != 0
988 		)
989 		return scanned + (used - count + 1);
990 	scanned += used;
991     } while (ref_stack_enum_next(&rsenum));
992     return 0;
993 }
994 
995 /*
996  * Pop the e-stack, executing cleanup procedures as needed.
997  * We could make this more efficient using ref_stack_enum_*,
998  * but it isn't used enough to make this worthwhile.
999  */
1000 void
pop_estack(i_ctx_t * i_ctx_p,uint count)1001 pop_estack(i_ctx_t *i_ctx_p, uint count)
1002 {
1003     uint idx = 0;
1004     uint popped = 0;
1005 
1006     esfile_clear_cache();
1007     for (; idx < count; idx++) {
1008 	ref *ep = ref_stack_index(&e_stack, idx - popped);
1009 
1010 	if (r_is_estack_mark(ep)) {
1011 	    ref_stack_pop(&e_stack, idx + 1 - popped);
1012 	    popped = idx + 1;
1013 	    (*real_opproc(ep)) (i_ctx_p);
1014 	}
1015     }
1016     ref_stack_pop(&e_stack, count - popped);
1017 }
1018 
1019 /*
1020  * Execute a quit in the case of an exit or stop with no appropriate
1021  * enclosing control scope (loop or stopped).  The caller has already
1022  * ensured two free slots on the top of the o-stack.
1023  */
1024 private int
unmatched_exit(os_ptr op,op_proc_t opproc)1025 unmatched_exit(os_ptr op, op_proc_t opproc)
1026 {
1027     make_oper(op - 1, 0, opproc);
1028     make_int(op, e_invalidexit);
1029     return_error(e_Quit);
1030 }
1031