Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 1991, 1992, 1994, 1999 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: zstack.c,v 1.4 2002/02/21 22:24:54 giles Exp $ */
18
/* Operand stack operators */
19
#include "memory_.h"
20
#include "ghost.h"
21
#include "ialloc.h"
22
#include "istack.h"
23
#include "oper.h"
24
#include "store.h"
25
 
26
/* <obj> pop - */
27
int
28
zpop(i_ctx_t *i_ctx_p)
29
{
30
    os_ptr op = osp;
31
 
32
    check_op(1);
33
    pop(1);
34
    return 0;
35
}
36
 
37
/* <obj1> <obj2> exch <obj2> <obj1> */
38
int
39
zexch(i_ctx_t *i_ctx_p)
40
{
41
    os_ptr op = osp;
42
    ref next;
43
 
44
    check_op(2);
45
    ref_assign_inline(&next, op - 1);
46
    ref_assign_inline(op - 1, op);
47
    ref_assign_inline(op, &next);
48
    return 0;
49
}
50
 
51
/* <obj> dup <obj> <obj> */
52
int
53
zdup(i_ctx_t *i_ctx_p)
54
{
55
    os_ptr op = osp;
56
 
57
    check_op(1);
58
    push(1);
59
    ref_assign_inline(op, op - 1);
60
    return 0;
61
}
62
 
63
/* <obj_n> ... <obj_0> <n> index <obj_n> ... <obj_0> <obj_n> */
64
int
65
zindex(i_ctx_t *i_ctx_p)
66
{
67
    os_ptr op = osp;
68
    register os_ptr opn;
69
 
70
    check_type(*op, t_integer);
71
    if ((ulong)op->value.intval >= op - osbot) {
72
	/* Might be in an older stack block. */
73
	ref *elt;
74
 
75
	if (op->value.intval < 0)
76
	    return_error(e_rangecheck);
77
	elt = ref_stack_index(&o_stack, op->value.intval + 1);
78
	if (elt == 0)
79
	    return_error(e_rangecheck);
80
	ref_assign(op, elt);
81
	return 0;
82
    }
83
    opn = op + ~(int)op->value.intval;
84
    ref_assign_inline(op, opn);
85
    return 0;
86
}
87
 
88
/* <obj_n-1> ... <obj_0> <n> <i> roll */
89
/*      <obj_(i-1)_mod_ n> ... <obj_0> <obj_n-1> ... <obj_i_mod_n> */
90
int
91
zroll(i_ctx_t *i_ctx_p)
92
{
93
    os_ptr op = osp;
94
    os_ptr op1 = op - 1;
95
    int count, mod;
96
    register os_ptr from, to;
97
    register int n;
98
 
99
    check_type(*op1, t_integer);
100
    check_type(*op, t_integer);
101
    if ((ulong) op1->value.intval > op1 - osbot) {
102
	/*
103
	 * The data might span multiple stack blocks.
104
	 * There are efficient ways to handle this situation,
105
	 * but they're more complicated than seems worth implementing;
106
	 * for now, do something very simple and inefficient.
107
	 */
108
	int left, i;
109
 
110
	if (op1->value.intval < 0 ||
111
	    op1->value.intval + 2 > ref_stack_count(&o_stack)
112
	    )
113
	    return_error(e_rangecheck);
114
	count = op1->value.intval;
115
	if (count <= 1) {
116
	    pop(2);
117
	    return 0;
118
	}
119
	mod = op->value.intval;
120
	if (mod >= count)
121
	    mod %= count;
122
	else if (mod < 0) {
123
	    mod %= count;
124
	    if (mod < 0)
125
		mod += count;	/* can't assume % means mod! */
126
	}
127
	/* Use the chain rotation algorithm mentioned below. */
128
	for (i = 0, left = count; left; i++) {
129
	    ref *elt = ref_stack_index(&o_stack, i + 2);
130
	    ref save;
131
	    int j, k;
132
	    ref *next;
133
 
134
	    save = *elt;
135
	    for (j = i, left--;; j = k, elt = next, left--) {
136
		k = (j + mod) % count;
137
		if (k == i)
138
		    break;
139
		next = ref_stack_index(&o_stack, k + 2);
140
		ref_assign(elt, next);
141
	    }
142
	    *elt = save;
143
	}
144
	pop(2);
145
	return 0;
146
    }
147
    count = op1->value.intval;
148
    if (count <= 1) {
149
	pop(2);
150
	return 0;
151
    }
152
    mod = op->value.intval;
153
    /*
154
     * The elegant approach, requiring no extra space, would be to
155
     * rotate the elements in chains separated by mod elements.
156
     * Instead, we simply check to make sure there is enough space
157
     * above op to do the roll in two block moves.
158
     * Unfortunately, we can't count on memcpy doing the right thing
159
     * in *either* direction.
160
     */
161
    switch (mod) {
162
	case 1:		/* common special case */
163
	    pop(2);
164
	    op -= 2;
165
	    {
166
		ref top;
167
 
168
		ref_assign_inline(&top, op);
169
		for (from = op, n = count; --n; from--)
170
		    ref_assign_inline(from, from - 1);
171
		ref_assign_inline(from, &top);
172
	    }
173
	    return 0;
174
	case -1:		/* common special case */
175
	    pop(2);
176
	    op -= 2;
177
	    {
178
		ref bot;
179
 
180
		to = op - count + 1;
181
		ref_assign_inline(&bot, to);
182
		for (n = count; --n; to++)
183
		    ref_assign(to, to + 1);
184
		ref_assign_inline(to, &bot);
185
	    }
186
	    return 0;
187
    }
188
    if (mod < 0) {
189
	mod += count;
190
	if (mod < 0) {
191
	    mod %= count;
192
	    if (mod < 0)
193
		mod += count;	/* can't assume % means mod! */
194
	}
195
    } else if (mod >= count)
196
	mod %= count;
197
    if (mod <= count >> 1) {
198
	/* Move everything up, then top elements down. */
199
	if (mod >= ostop - op) {
200
	    o_stack.requested = mod;
201
	    return_error(e_stackoverflow);
202
	}
203
	pop(2);
204
	op -= 2;
205
	for (to = op + mod, from = op, n = count; n--; to--, from--)
206
	    ref_assign(to, from);
207
	memcpy((char *)(from + 1), (char *)(op + 1), mod * sizeof(ref));
208
    } else {
209
	/* Move bottom elements up, then everything down. */
210
	mod = count - mod;
211
	if (mod >= ostop - op) {
212
	    o_stack.requested = mod;
213
	    return_error(e_stackoverflow);
214
	}
215
	pop(2);
216
	op -= 2;
217
	to = op - count + 1;
218
	memcpy((char *)(op + 1), (char *)to, mod * sizeof(ref));
219
	for (from = to + mod, n = count; n--; to++, from++)
220
	    ref_assign(to, from);
221
    }
222
    return 0;
223
}
224
 
225
/* |- ... clear |- */
226
/* The function name is changed, because the IRIS library has */
227
/* a function called zclear. */
228
private int
229
zclear_stack(i_ctx_t *i_ctx_p)
230
{
231
    ref_stack_clear(&o_stack);
232
    return 0;
233
}
234
 
235
/* |- <obj_n-1> ... <obj_0> count <obj_n-1> ... <obj_0> <n> */
236
private int
237
zcount(i_ctx_t *i_ctx_p)
238
{
239
    os_ptr op = osp;
240
 
241
    push(1);
242
    make_int(op, ref_stack_count(&o_stack) - 1);
243
    return 0;
244
}
245
 
246
/* - mark <mark> */
247
private int
248
zmark(i_ctx_t *i_ctx_p)
249
{
250
    os_ptr op = osp;
251
 
252
    push(1);
253
    make_mark(op);
254
    return 0;
255
}
256
 
257
/* <mark> ... cleartomark */
258
int
259
zcleartomark(i_ctx_t *i_ctx_p)
260
{
261
    uint count = ref_stack_counttomark(&o_stack);
262
 
263
    if (count == 0)
264
	return_error(e_unmatchedmark);
265
    ref_stack_pop(&o_stack, count);
266
    return 0;
267
}
268
 
269
/* <mark> <obj_n-1> ... <obj_0> counttomark */
270
/*      <mark> <obj_n-1> ... <obj_0> <n> */
271
private int
272
zcounttomark(i_ctx_t *i_ctx_p)
273
{
274
    os_ptr op = osp;
275
    uint count = ref_stack_counttomark(&o_stack);
276
 
277
    if (count == 0)
278
	return_error(e_unmatchedmark);
279
    push(1);
280
    make_int(op, count - 1);
281
    return 0;
282
}
283
 
284
/* ------ Initialization procedure ------ */
285
 
286
const op_def zstack_op_defs[] =
287
{
288
    {"0clear", zclear_stack},
289
    {"0cleartomark", zcleartomark},
290
    {"0count", zcount},
291
    {"0counttomark", zcounttomark},
292
    {"1dup", zdup},
293
    {"2exch", zexch},
294
    {"2index", zindex},
295
    {"0mark", zmark},
296
    {"1pop", zpop},
297
    {"2roll", zroll},
298
    op_def_end(0)
299
};