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 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 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 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 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 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