Coverage Report

Created: 2022-04-16 11:23

/src/ghostpdl/psi/zstack.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Operand stack operators */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "ialloc.h"
21
#include "istack.h"
22
#include "oper.h"
23
#include "store.h"
24
25
/* <obj> pop - */
26
int
27
zpop(i_ctx_t *i_ctx_p)
28
683
{
29
683
    os_ptr op = osp;
30
31
683
    check_op(1);
32
683
    pop(1);
33
683
    return 0;
34
683
}
35
36
/* <obj1> <obj2> exch <obj2> <obj1> */
37
int
38
zexch(i_ctx_t *i_ctx_p)
39
0
{
40
0
    os_ptr op = osp;
41
0
    ref next;
42
43
0
    check_op(2);
44
0
    ref_assign_inline(&next, op - 1);
45
0
    ref_assign_inline(op - 1, op);
46
0
    ref_assign_inline(op, &next);
47
0
    return 0;
48
0
}
49
50
/* <obj> dup <obj> <obj> */
51
int
52
zdup(i_ctx_t *i_ctx_p)
53
0
{
54
0
    os_ptr op = osp;
55
56
0
    check_op(1);
57
0
    push(1);
58
0
    ref_assign_inline(op, op - 1);
59
0
    return 0;
60
0
}
61
62
/* <obj_n> ... <obj_0> <n> index <obj_n> ... <obj_0> <obj_n> */
63
int
64
zindex(i_ctx_t *i_ctx_p)
65
12.0M
{
66
12.0M
    os_ptr op = osp;
67
12.0M
    register os_ptr opn;
68
69
12.0M
    check_type(*op, t_integer);
70
12.0M
    if ((ulong)op->value.intval >= (ulong)(op - osbot)) {
71
        /* Might be in an older stack block. */
72
0
        ref *elt;
73
74
0
        if (op->value.intval < 0)
75
0
            return_error(gs_error_rangecheck);
76
0
        elt = ref_stack_index(&o_stack, op->value.intval + 1);
77
0
        if (elt == 0)
78
0
            return_error(gs_error_stackunderflow);
79
0
        ref_assign(op, elt);
80
0
        return 0;
81
0
    }
82
12.0M
    opn = op + ~(int)op->value.intval;
83
12.0M
    ref_assign_inline(op, opn);
84
12.0M
    return 0;
85
12.0M
}
86
87
/* <obj_n> ... <obj_0> <n> .argindex <obj_n> ... <obj_0> <obj_n> */
88
static int
89
zargindex(i_ctx_t *i_ctx_p)
90
1.13M
{
91
1.13M
    int code = zindex(i_ctx_p);
92
93
    /*
94
     * Pseudo-operators should use .argindex rather than index to access
95
     * their arguments on the stack, so that if there aren't enough, the
96
     * result will be a stackunderflow rather than a rangecheck.  (This is,
97
     * in fact, the only reason this operator exists.)
98
     */
99
1.13M
    if (code == gs_error_rangecheck && osp->value.intval >= 0)
100
0
        code = gs_note_error(gs_error_stackunderflow);
101
1.13M
    return code;
102
1.13M
}
103
104
/* <obj_n-1> ... <obj_0> <n> <i> roll */
105
/*      <obj_(i-1)_mod_ n> ... <obj_0> <obj_n-1> ... <obj_i_mod_n> */
106
int
107
zroll(i_ctx_t *i_ctx_p)
108
8.52M
{
109
8.52M
    os_ptr op = osp;
110
8.52M
    os_ptr op1 = op - 1;
111
8.52M
    int count, mod;
112
8.52M
    register os_ptr from, to;
113
8.52M
    register int n;
114
115
8.52M
    check_type(*op1, t_integer);
116
8.52M
    check_type(*op, t_integer);
117
8.52M
    if ((uint) op1->value.intval > (uint)(op1 - osbot)) {
118
        /*
119
         * The data might span multiple stack blocks.
120
         * There are efficient ways to handle this situation,
121
         * but they're more complicated than seems worth implementing;
122
         * for now, do something very simple and inefficient.
123
         */
124
0
        int left, i;
125
126
0
        if (op1->value.intval < 0)
127
0
            return_error(gs_error_rangecheck);
128
0
        if (op1->value.intval + 2 > (int)ref_stack_count(&o_stack))
129
0
            return_error(gs_error_stackunderflow);
130
0
        count = op1->value.intval;
131
0
        if (count <= 1) {
132
0
            pop(2);
133
0
            return 0;
134
0
        }
135
0
        mod = op->value.intval;
136
0
        if (mod >= count)
137
0
            mod %= count;
138
0
        else if (mod < 0) {
139
0
            mod %= count;
140
0
            if (mod < 0)
141
0
                mod += count; /* can't assume % means mod! */
142
0
        }
143
        /* Use the chain rotation algorithm mentioned below. */
144
0
        for (i = 0, left = count; left; i++) {
145
0
            ref *elt = ref_stack_index(&o_stack, i + 2);
146
0
            ref save;
147
0
            int j, k;
148
0
            ref *next;
149
150
0
            save = *elt;
151
0
            for (j = i, left--;; j = k, elt = next, left--) {
152
0
                k = (j + mod) % count;
153
0
                if (k == i)
154
0
                    break;
155
0
                next = ref_stack_index(&o_stack, k + 2);
156
0
                ref_assign(elt, next);
157
0
            }
158
0
            *elt = save;
159
0
        }
160
0
        pop(2);
161
0
        return 0;
162
0
    }
163
8.52M
    count = op1->value.intval;
164
8.52M
    if (count <= 1) {
165
0
        pop(2);
166
0
        return 0;
167
0
    }
168
8.52M
    mod = op->value.intval;
169
    /*
170
     * The elegant approach, requiring no extra space, would be to
171
     * rotate the elements in chains separated by mod elements.
172
     * Instead, we simply check to make sure there is enough space
173
     * above op to do the roll in two block moves.
174
     * Unfortunately, we can't count on memcpy doing the right thing
175
     * in *either* direction.
176
     */
177
8.52M
    switch (mod) {
178
4.29M
        case 1:   /* common special case */
179
4.29M
            pop(2);
180
4.29M
            op -= 2;
181
4.29M
            {
182
4.29M
                ref top;
183
184
4.29M
                ref_assign_inline(&top, op);
185
13.5M
                for (from = op, n = count; --n; from--)
186
9.23M
                    ref_assign_inline(from, from - 1);
187
4.29M
                ref_assign_inline(from, &top);
188
4.29M
            }
189
4.29M
            return 0;
190
3.89M
        case -1:    /* common special case */
191
3.89M
            pop(2);
192
3.89M
            op -= 2;
193
3.89M
            {
194
3.89M
                ref bot;
195
196
3.89M
                to = op - count + 1;
197
3.89M
                ref_assign_inline(&bot, to);
198
14.6M
                for (n = count; --n; to++)
199
10.7M
                    ref_assign(to, to + 1);
200
3.89M
                ref_assign_inline(to, &bot);
201
3.89M
            }
202
3.89M
            return 0;
203
8.52M
    }
204
339k
    if (mod < 0) {
205
70.7k
        mod += count;
206
70.7k
        if (mod < 0) {
207
0
            mod %= count;
208
0
            if (mod < 0)
209
0
                mod += count; /* can't assume % means mod! */
210
0
        }
211
269k
    } else if (mod >= count)
212
0
        mod %= count;
213
339k
    if (mod <= count >> 1) {
214
        /* Move everything up, then top elements down. */
215
300k
        if (mod >= ostop - op) {
216
0
            o_stack.requested = mod;
217
0
            return_error(gs_error_stackoverflow);
218
0
        }
219
300k
        pop(2);
220
300k
        op -= 2;
221
2.38M
        for (to = op + mod, from = op, n = count; n--; to--, from--)
222
2.08M
            ref_assign(to, from);
223
300k
        memcpy((char *)(from + 1), (char *)(op + 1), mod * sizeof(ref));
224
300k
    } else {
225
        /* Move bottom elements up, then everything down. */
226
39.0k
        mod = count - mod;
227
39.0k
        if (mod >= ostop - op) {
228
0
            o_stack.requested = mod;
229
0
            return_error(gs_error_stackoverflow);
230
0
        }
231
39.0k
        pop(2);
232
39.0k
        op -= 2;
233
39.0k
        to = op - count + 1;
234
39.0k
        memcpy((char *)(op + 1), (char *)to, mod * sizeof(ref));
235
169k
        for (from = to + mod, n = count; n--; to++, from++)
236
130k
            ref_assign(to, from);
237
39.0k
    }
238
339k
    return 0;
239
339k
}
240
241
/* |- ... clear |- */
242
/* The function name is changed, because the IRIS library has */
243
/* a function called zclear. */
244
static int
245
zclear_stack(i_ctx_t *i_ctx_p)
246
1
{
247
1
    ref_stack_clear(&o_stack);
248
1
    return 0;
249
1
}
250
251
/* |- <obj_n-1> ... <obj_0> count <obj_n-1> ... <obj_0> <n> */
252
static int
253
zcount(i_ctx_t *i_ctx_p)
254
24.4k
{
255
24.4k
    os_ptr op = osp;
256
257
24.4k
    push(1);
258
24.4k
    make_int(op, ref_stack_count(&o_stack) - 1);
259
24.4k
    return 0;
260
24.4k
}
261
262
/* - mark <mark> */
263
static int
264
zmark(i_ctx_t *i_ctx_p)
265
4.53M
{
266
4.53M
    os_ptr op = osp;
267
268
4.53M
    push(1);
269
4.53M
    make_mark(op);
270
4.53M
    return 0;
271
4.53M
}
272
273
/* <mark> ... cleartomark */
274
int
275
zcleartomark(i_ctx_t *i_ctx_p)
276
820k
{
277
820k
    uint count = ref_stack_counttomark(&o_stack);
278
279
820k
    if (count == 0)
280
0
        return_error(gs_error_unmatchedmark);
281
820k
    ref_stack_pop(&o_stack, count);
282
820k
    return 0;
283
820k
}
284
285
/* <mark> <obj_n-1> ... <obj_0> counttomark */
286
/*      <mark> <obj_n-1> ... <obj_0> <n> */
287
static int
288
zcounttomark(i_ctx_t *i_ctx_p)
289
3.85M
{
290
3.85M
    os_ptr op = osp;
291
3.85M
    uint count = ref_stack_counttomark(&o_stack);
292
293
3.85M
    if (count == 0)
294
0
        return_error(gs_error_unmatchedmark);
295
3.85M
    push(1);
296
3.85M
    make_int(op, count - 1);
297
3.85M
    return 0;
298
3.85M
}
299
300
/* ------ Initialization procedure ------ */
301
302
const op_def zstack_op_defs[] =
303
{
304
    {"2.argindex", zargindex},
305
    {"0clear", zclear_stack},
306
    {"0cleartomark", zcleartomark},
307
    {"0count", zcount},
308
    {"0counttomark", zcounttomark},
309
    {"1dup", zdup},
310
    {"2exch", zexch},
311
    {"2index", zindex},
312
    {"0mark", zmark},
313
    {"1pop", zpop},
314
    {"2roll", zroll},
315
    op_def_end(0)
316
};