1 /* Copyright (C) 1992, 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: zmisc2.c,v 1.7 2004/08/04 19:36:13 stefan Exp $ */
18 /* Miscellaneous Level 2 operators */
19 #include "memory_.h"
20 #include "string_.h"
21 #include "ghost.h"
22 #include "oper.h"
23 #include "estack.h"
24 #include "iddict.h"
25 #include "idparam.h"
26 #include "iparam.h"
27 #include "dstack.h"
28 #include "ilevel.h"
29 #include "iname.h"
30 #include "iutil2.h"
31 #include "ivmspace.h"
32 #include "store.h"
33
34 /* Forward references */
35 private int set_language_level(i_ctx_t *, int);
36
37 /* ------ Language level operators ------ */
38
39 /* - .languagelevel <int> */
40 private int
zlanguagelevel(i_ctx_t * i_ctx_p)41 zlanguagelevel(i_ctx_t *i_ctx_p)
42 {
43 os_ptr op = osp;
44
45 push(1);
46 make_int(op, LANGUAGE_LEVEL);
47 return 0;
48 }
49
50 /* <int> .setlanguagelevel - */
51 private int
zsetlanguagelevel(i_ctx_t * i_ctx_p)52 zsetlanguagelevel(i_ctx_t *i_ctx_p)
53 {
54 os_ptr op = osp;
55 int code = 0;
56
57 check_type(*op, t_integer);
58 if (op->value.intval != LANGUAGE_LEVEL) {
59 code = set_language_level(i_ctx_p, (int)op->value.intval);
60 if (code < 0)
61 return code;
62 }
63 LANGUAGE_LEVEL = op->value.intval;
64 pop(1);
65 return code;
66 }
67
68 /* ------ Initialization procedure ------ */
69
70 /* The level setting ops are recognized even in Level 1 mode. */
71 const op_def zmisc2_op_defs[] =
72 {
73 {"0.languagelevel", zlanguagelevel},
74 {"1.setlanguagelevel", zsetlanguagelevel},
75 op_def_end(0)
76 };
77
78 /* ------ Internal procedures ------ */
79
80 /*
81 * Adjust the interpreter for a change in language level.
82 * This is used for the .setlanguagelevel operator,
83 * and (perhaps someday) after a restore.
84 */
85 private int swap_level_dict(i_ctx_t *i_ctx_p, const char *dict_name);
86 private int swap_entry(i_ctx_t *i_ctx_p, ref elt[2], ref * pdict,
87 ref * pdict2);
88 private int
set_language_level(i_ctx_t * i_ctx_p,int new_level)89 set_language_level(i_ctx_t *i_ctx_p, int new_level)
90 {
91 int old_level = LANGUAGE_LEVEL;
92 ref *pgdict = /* globaldict, if present */
93 ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 2);
94 ref *level2dict;
95 int code = 0;
96
97 if (new_level < 1 ||
98 new_level >
99 (dict_find_string(systemdict, "ll3dict", &level2dict) > 0 ? 3 : 2)
100 )
101 return_error(e_rangecheck);
102 if (dict_find_string(systemdict, "level2dict", &level2dict) <= 0)
103 return_error(e_undefined);
104 /*
105 * As noted in dstack.h, we allocate the extra d-stack entry for
106 * globaldict even in Level 1 mode; in Level 1 mode, this entry
107 * holds an extra copy of systemdict, and [count]dictstack omit the
108 * very bottommost entry.
109 */
110 while (new_level != old_level) {
111 switch (old_level) {
112 case 1: { /* 1 => 2 or 3 */
113 /* Put globaldict in the dictionary stack. */
114 ref *pdict;
115
116 /*
117 * This might be called so early in initialization that
118 * globaldict hasn't been defined yet. If so, just skip
119 * this step.
120 */
121 code = dict_find_string(level2dict, "globaldict", &pdict);
122 if (code > 0) {
123 if (!r_has_type(pdict, t_dictionary))
124 return_error(e_typecheck);
125 *pgdict = *pdict;
126 }
127 /* Set other flags for Level 2 operation. */
128 imemory->gs_lib_ctx->dict_auto_expand = true;
129 }
130 code = swap_level_dict(i_ctx_p, "level2dict");
131 if (code < 0)
132 return code;
133 ++old_level;
134 continue;
135 case 3: /* 3 => 1 or 2 */
136 code = swap_level_dict(i_ctx_p, "ll3dict");
137 if (code < 0)
138 return code;
139 --old_level;
140 continue;
141 default: /* 2 => 1 or 3 */
142 break;
143 }
144 switch (new_level) {
145 case 1: { /* 2 => 1 */
146 /*
147 * Clear the cached definition pointers of all names defined
148 * in globaldict. This will slow down future lookups, but
149 * we don't care.
150 */
151 int index = dict_first(pgdict);
152 ref elt[2];
153
154 while ((index = dict_next(pgdict, index, &elt[0])) >= 0)
155 if (r_has_type(&elt[0], t_name))
156 name_invalidate_value_cache(imemory, &elt[0]);
157 /* Overwrite globaldict in the dictionary stack. */
158 *pgdict = *systemdict;
159 /* Set other flags for Level 1 operation. */
160 imemory->gs_lib_ctx->dict_auto_expand = false;
161 }
162 code = swap_level_dict(i_ctx_p, "level2dict");
163 break;
164 case 3: /* 2 => 3 */
165 code = swap_level_dict(i_ctx_p, "ll3dict");
166 break;
167 default: /* not possible */
168 return_error(e_Fatal);
169 }
170 break;
171 }
172 dict_set_top(); /* reload dict stack cache */
173 return code;
174 }
175
176 /*
177 * Swap the contents of a level dictionary (level2dict or ll3dict) and
178 * systemdict. If a value in the level dictionary is itself a dictionary,
179 * and it contains a key/value pair referring to itself, swap its contents
180 * with the contents of the same dictionary in systemdict. (This is a hack
181 * to swap the contents of statusdict.)
182 */
183 private int
swap_level_dict(i_ctx_t * i_ctx_p,const char * dict_name)184 swap_level_dict(i_ctx_t *i_ctx_p, const char *dict_name)
185 {
186 ref *pleveldict;
187 ref rleveldict;
188 int index;
189 ref elt[2]; /* key, value */
190 ref *psubdict;
191
192 /*
193 * We have to copy the refs for leveldict and subdict, since they may
194 * move if their containing dictionary is resized.
195 */
196 if (dict_find_string(systemdict, dict_name, &pleveldict) <= 0)
197 return_error(e_undefined);
198 rleveldict = *pleveldict;
199 index = dict_first(&rleveldict);
200 while ((index = dict_next(&rleveldict, index, &elt[0])) >= 0)
201 if (r_has_type(&elt[1], t_dictionary) &&
202 dict_find(&elt[1], &elt[0], &psubdict) > 0 &&
203 obj_eq(imemory, &elt[1], psubdict)
204 ) {
205 /* elt[1] is the 2nd-level sub-dictionary */
206 int isub = dict_first(&elt[1]);
207 ref subelt[2];
208 int found = dict_find(systemdict, &elt[0], &psubdict);
209 ref rsubdict;
210
211 if (found <= 0)
212 continue;
213 rsubdict = *psubdict;
214 while ((isub = dict_next(&elt[1], isub, &subelt[0])) >= 0)
215 if (!obj_eq(imemory, &subelt[0], &elt[0])) {
216 /* don't swap dict itself */
217 int code = swap_entry(i_ctx_p, subelt, &rsubdict, &elt[1]);
218
219 if (code < 0)
220 return code;
221 }
222 } else {
223 int code = swap_entry(i_ctx_p, elt, systemdict, &rleveldict);
224
225 if (code < 0)
226 return code;
227 }
228 return 0;
229 }
230
231 /*
232 * Swap an entry from a higher level dictionary into a base dictionary.
233 * elt[0] is the key, elt[1] is the current value in the Level 2 dictionary
234 * (*pdict2).
235 */
236 private int
swap_entry(i_ctx_t * i_ctx_p,ref elt[2],ref * pdict,ref * pdict2)237 swap_entry(i_ctx_t *i_ctx_p, ref elt[2], ref * pdict, ref * pdict2)
238 {
239 ref *pvalue;
240 ref old_value; /* current value in *pdict */
241 int found = dict_find(pdict, &elt[0], &pvalue);
242
243 switch (found) {
244 default: /* <0, error */
245 /*
246 * The only possible error here is a dictfull error, which is
247 * harmless.
248 */
249 /* fall through */
250 case 0: /* missing */
251 make_null(&old_value);
252 break;
253 case 1: /* present */
254 old_value = *pvalue;
255 }
256 /*
257 * Temporarily flag the dictionaries as local, so that we don't
258 * get invalidaccess errors. (We know that they are both
259 * referenced from systemdict, so they are allowed to reference
260 * local objects even if they are global.)
261 */
262 {
263 uint space2 = r_space(pdict2);
264 int code;
265
266 r_set_space(pdict2, avm_local);
267 idict_put(pdict2, &elt[0], &old_value);
268 if (r_has_type(&elt[1], t_null)) {
269 code = idict_undef(pdict, &elt[0]);
270 if (code == e_undefined &&
271 r_has_type(&old_value, t_null)
272 )
273 code = 0;
274 } else {
275 uint space = r_space(pdict);
276
277 r_set_space(pdict, avm_local);
278 code = idict_put(pdict, &elt[0], &elt[1]);
279 r_set_space(pdict, space);
280 }
281 r_set_space(pdict2, space2);
282 return code;
283 }
284 }
285