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