xref: /plan9/sys/src/cmd/gs/src/zmisc2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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