Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/cmd/gs/src/zcontrol.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
}