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