summaryrefslogtreecommitdiff
path: root/psi/zmisc3.c
blob: 807a96e4012309175a9b048896e3b834a80bcaf6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* Copyright (C) 2001-2023 Artifex Software, Inc.
   All Rights Reserved.

   This software is provided AS-IS with no warranty, either express or
   implied.

   This software is distributed under license and may not be copied,
   modified or distributed except as expressly authorized under the terms
   of the license contained in the file LICENSE in this distribution.

   Refer to licensing information at http://www.artifex.com or contact
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
   CA 94129, USA, for further information.
*/


/* Miscellaneous LanguageLevel 3 operators */
#include "ghost.h"
#include "gscspace.h"		/* for gscolor2.h */
#include "gsmatrix.h"		/* ditto */
#include "gsclipsr.h"
#include "gscolor2.h"
#include "oper.h"
#include "igstate.h"
#include "store.h"

/* - clipsave - */
static int
zclipsave(i_ctx_t *i_ctx_p)
{
    return gs_clipsave(igs);
}

/* - cliprestore - */
static int
zcliprestore(i_ctx_t *i_ctx_p)
{
    return gs_cliprestore(igs);
}

static inline bool
eqproc_check_type(ref *r)
{
    return r_has_type(r, t_array)
           || r_has_type(r, t_mixedarray)
           || r_has_type(r, t_shortarray)
           || r_has_type(r, t_oparray);
}

/* <proc1> <proc2> .eqproc <bool> */
/*
 * Test whether two procedures are equal to depth 10.
 * This is the equality test used by idiom recognition in 'bind'.
 */
/* Adobe specifies maximum depth of 10 but 12 is needed */
/* to reproduce the observed behavior. CET 31-01-05 */
#define MAX_DEPTH 12
typedef struct ref2_s {
    ref proc1, proc2;
} ref2_t;
static int
zeqproc(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    ref2_t stack[MAX_DEPTH + 1];
    ref2_t *top = stack;

    check_op(2);
    if (!eqproc_check_type(op -1) || !eqproc_check_type(op)) {
        make_false(op - 1);
        pop(1);
        return 0;
    }

    make_array(&stack[0].proc1, 0, 1, op - 1);
    make_array(&stack[0].proc2, 0, 1, op);
    for (;;) {
        long i;

        if (r_size(&top->proc1) == 0) {
            /* Finished these arrays, go up to next level. */
            if (top == stack) {
                /* We're done matching: it succeeded. */
                make_true(op - 1);
                pop(1);
                return 0;
            }
            --top;
            continue;
        }
        /* Look at the next elements of the arrays. */
        i = r_size(&top->proc1) - 1;
        array_get(imemory, &top->proc1, i, &top[1].proc1);
        array_get(imemory, &top->proc2, i, &top[1].proc2);
        r_dec_size(&top->proc1, 1);
        ++top;
        /*
         * Amazingly enough, the objects' executable attributes are not
         * required to match.  This means { x load } will match { /x load },
         * even though this is clearly wrong.
         */
#if 0
        if (r_has_attr(&top->proc1, a_executable) !=
            r_has_attr(&top->proc2, a_executable)
            )
            break;
#endif
        if (obj_eq(imemory, &top->proc1, &top->proc2)) {
            /* Names don't match strings. */
            if (r_type(&top->proc1) != r_type(&top->proc2) &&
                (r_type(&top->proc1) == t_name ||
                 r_type(&top->proc2) == t_name)
                )
                break;
            --top;		/* no recursion */
            continue;
        }
        if (r_is_array(&top->proc1) && r_is_array(&top->proc2) &&
            r_size(&top->proc1) == r_size(&top->proc2) &&
            top < stack + (MAX_DEPTH - 1)
            ) {
            /* Descend into the arrays. */
            continue;
        }
        break;
    }
    /* An exit from the loop indicates that matching failed. */
    make_false(op - 1);
    pop(1);
    return 0;
}

/* ------ Initialization procedure ------ */

const op_def zmisc3_op_defs[] =
{
    op_def_begin_ll3(),
    {"0cliprestore", zcliprestore},
    {"0clipsave", zclipsave},
    {"2.eqproc", zeqproc},
    op_def_end(0)
};