13ff48bf5SDavid du Colombier /* Copyright (C) 1992, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: zmisc2.c,v 1.7 2004/08/04 19:36:13 stefan Exp $ */
187dd7cddfSDavid du Colombier /* Miscellaneous Level 2 operators */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "string_.h"
217dd7cddfSDavid du Colombier #include "ghost.h"
227dd7cddfSDavid du Colombier #include "oper.h"
237dd7cddfSDavid du Colombier #include "estack.h"
247dd7cddfSDavid du Colombier #include "iddict.h"
257dd7cddfSDavid du Colombier #include "idparam.h"
267dd7cddfSDavid du Colombier #include "iparam.h"
277dd7cddfSDavid du Colombier #include "dstack.h"
287dd7cddfSDavid du Colombier #include "ilevel.h"
297dd7cddfSDavid du Colombier #include "iname.h"
307dd7cddfSDavid du Colombier #include "iutil2.h"
317dd7cddfSDavid du Colombier #include "ivmspace.h"
327dd7cddfSDavid du Colombier #include "store.h"
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier /* Forward references */
35*593dc095SDavid du Colombier private int set_language_level(i_ctx_t *, int);
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier /* ------ Language level operators ------ */
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier /* - .languagelevel <int> */
407dd7cddfSDavid du Colombier private int
zlanguagelevel(i_ctx_t * i_ctx_p)417dd7cddfSDavid du Colombier zlanguagelevel(i_ctx_t *i_ctx_p)
427dd7cddfSDavid du Colombier {
437dd7cddfSDavid du Colombier os_ptr op = osp;
447dd7cddfSDavid du Colombier
457dd7cddfSDavid du Colombier push(1);
467dd7cddfSDavid du Colombier make_int(op, LANGUAGE_LEVEL);
477dd7cddfSDavid du Colombier return 0;
487dd7cddfSDavid du Colombier }
497dd7cddfSDavid du Colombier
507dd7cddfSDavid du Colombier /* <int> .setlanguagelevel - */
517dd7cddfSDavid du Colombier private int
zsetlanguagelevel(i_ctx_t * i_ctx_p)527dd7cddfSDavid du Colombier zsetlanguagelevel(i_ctx_t *i_ctx_p)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier os_ptr op = osp;
557dd7cddfSDavid du Colombier int code = 0;
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier check_type(*op, t_integer);
587dd7cddfSDavid du Colombier if (op->value.intval != LANGUAGE_LEVEL) {
597dd7cddfSDavid du Colombier code = set_language_level(i_ctx_p, (int)op->value.intval);
607dd7cddfSDavid du Colombier if (code < 0)
617dd7cddfSDavid du Colombier return code;
627dd7cddfSDavid du Colombier }
637dd7cddfSDavid du Colombier LANGUAGE_LEVEL = op->value.intval;
647dd7cddfSDavid du Colombier pop(1);
657dd7cddfSDavid du Colombier return code;
667dd7cddfSDavid du Colombier }
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier /* The level setting ops are recognized even in Level 1 mode. */
717dd7cddfSDavid du Colombier const op_def zmisc2_op_defs[] =
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier {"0.languagelevel", zlanguagelevel},
747dd7cddfSDavid du Colombier {"1.setlanguagelevel", zsetlanguagelevel},
757dd7cddfSDavid du Colombier op_def_end(0)
767dd7cddfSDavid du Colombier };
777dd7cddfSDavid du Colombier
787dd7cddfSDavid du Colombier /* ------ Internal procedures ------ */
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier /*
817dd7cddfSDavid du Colombier * Adjust the interpreter for a change in language level.
827dd7cddfSDavid du Colombier * This is used for the .setlanguagelevel operator,
837dd7cddfSDavid du Colombier * and (perhaps someday) after a restore.
847dd7cddfSDavid du Colombier */
85*593dc095SDavid du Colombier private int swap_level_dict(i_ctx_t *i_ctx_p, const char *dict_name);
86*593dc095SDavid du Colombier private int swap_entry(i_ctx_t *i_ctx_p, ref elt[2], ref * pdict,
87*593dc095SDavid du Colombier ref * pdict2);
887dd7cddfSDavid du Colombier private int
set_language_level(i_ctx_t * i_ctx_p,int new_level)897dd7cddfSDavid du Colombier set_language_level(i_ctx_t *i_ctx_p, int new_level)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier int old_level = LANGUAGE_LEVEL;
927dd7cddfSDavid du Colombier ref *pgdict = /* globaldict, if present */
937dd7cddfSDavid du Colombier ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 2);
947dd7cddfSDavid du Colombier ref *level2dict;
957dd7cddfSDavid du Colombier int code = 0;
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier if (new_level < 1 ||
987dd7cddfSDavid du Colombier new_level >
997dd7cddfSDavid du Colombier (dict_find_string(systemdict, "ll3dict", &level2dict) > 0 ? 3 : 2)
1007dd7cddfSDavid du Colombier )
1017dd7cddfSDavid du Colombier return_error(e_rangecheck);
1027dd7cddfSDavid du Colombier if (dict_find_string(systemdict, "level2dict", &level2dict) <= 0)
1037dd7cddfSDavid du Colombier return_error(e_undefined);
1047dd7cddfSDavid du Colombier /*
1057dd7cddfSDavid du Colombier * As noted in dstack.h, we allocate the extra d-stack entry for
1067dd7cddfSDavid du Colombier * globaldict even in Level 1 mode; in Level 1 mode, this entry
1077dd7cddfSDavid du Colombier * holds an extra copy of systemdict, and [count]dictstack omit the
1087dd7cddfSDavid du Colombier * very bottommost entry.
1097dd7cddfSDavid du Colombier */
1107dd7cddfSDavid du Colombier while (new_level != old_level) {
1117dd7cddfSDavid du Colombier switch (old_level) {
1127dd7cddfSDavid du Colombier case 1: { /* 1 => 2 or 3 */
1137dd7cddfSDavid du Colombier /* Put globaldict in the dictionary stack. */
1147dd7cddfSDavid du Colombier ref *pdict;
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier /*
1177dd7cddfSDavid du Colombier * This might be called so early in initialization that
1187dd7cddfSDavid du Colombier * globaldict hasn't been defined yet. If so, just skip
1197dd7cddfSDavid du Colombier * this step.
1207dd7cddfSDavid du Colombier */
1217dd7cddfSDavid du Colombier code = dict_find_string(level2dict, "globaldict", &pdict);
1227dd7cddfSDavid du Colombier if (code > 0) {
1237dd7cddfSDavid du Colombier if (!r_has_type(pdict, t_dictionary))
1247dd7cddfSDavid du Colombier return_error(e_typecheck);
1257dd7cddfSDavid du Colombier *pgdict = *pdict;
1267dd7cddfSDavid du Colombier }
1277dd7cddfSDavid du Colombier /* Set other flags for Level 2 operation. */
128*593dc095SDavid du Colombier imemory->gs_lib_ctx->dict_auto_expand = true;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier code = swap_level_dict(i_ctx_p, "level2dict");
1317dd7cddfSDavid du Colombier if (code < 0)
1327dd7cddfSDavid du Colombier return code;
1337dd7cddfSDavid du Colombier ++old_level;
1347dd7cddfSDavid du Colombier continue;
1357dd7cddfSDavid du Colombier case 3: /* 3 => 1 or 2 */
1367dd7cddfSDavid du Colombier code = swap_level_dict(i_ctx_p, "ll3dict");
1377dd7cddfSDavid du Colombier if (code < 0)
1387dd7cddfSDavid du Colombier return code;
1397dd7cddfSDavid du Colombier --old_level;
1407dd7cddfSDavid du Colombier continue;
1417dd7cddfSDavid du Colombier default: /* 2 => 1 or 3 */
1427dd7cddfSDavid du Colombier break;
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier switch (new_level) {
1457dd7cddfSDavid du Colombier case 1: { /* 2 => 1 */
1467dd7cddfSDavid du Colombier /*
1477dd7cddfSDavid du Colombier * Clear the cached definition pointers of all names defined
1487dd7cddfSDavid du Colombier * in globaldict. This will slow down future lookups, but
1497dd7cddfSDavid du Colombier * we don't care.
1507dd7cddfSDavid du Colombier */
1517dd7cddfSDavid du Colombier int index = dict_first(pgdict);
1527dd7cddfSDavid du Colombier ref elt[2];
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier while ((index = dict_next(pgdict, index, &elt[0])) >= 0)
1557dd7cddfSDavid du Colombier if (r_has_type(&elt[0], t_name))
156*593dc095SDavid du Colombier name_invalidate_value_cache(imemory, &elt[0]);
1577dd7cddfSDavid du Colombier /* Overwrite globaldict in the dictionary stack. */
1587dd7cddfSDavid du Colombier *pgdict = *systemdict;
1597dd7cddfSDavid du Colombier /* Set other flags for Level 1 operation. */
160*593dc095SDavid du Colombier imemory->gs_lib_ctx->dict_auto_expand = false;
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier code = swap_level_dict(i_ctx_p, "level2dict");
1637dd7cddfSDavid du Colombier break;
1647dd7cddfSDavid du Colombier case 3: /* 2 => 3 */
1657dd7cddfSDavid du Colombier code = swap_level_dict(i_ctx_p, "ll3dict");
1667dd7cddfSDavid du Colombier break;
1677dd7cddfSDavid du Colombier default: /* not possible */
1687dd7cddfSDavid du Colombier return_error(e_Fatal);
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier break;
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier dict_set_top(); /* reload dict stack cache */
1737dd7cddfSDavid du Colombier return code;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier /*
1777dd7cddfSDavid du Colombier * Swap the contents of a level dictionary (level2dict or ll3dict) and
1787dd7cddfSDavid du Colombier * systemdict. If a value in the level dictionary is itself a dictionary,
1797dd7cddfSDavid du Colombier * and it contains a key/value pair referring to itself, swap its contents
1807dd7cddfSDavid du Colombier * with the contents of the same dictionary in systemdict. (This is a hack
1817dd7cddfSDavid du Colombier * to swap the contents of statusdict.)
1827dd7cddfSDavid du Colombier */
1837dd7cddfSDavid du Colombier private int
swap_level_dict(i_ctx_t * i_ctx_p,const char * dict_name)1847dd7cddfSDavid du Colombier swap_level_dict(i_ctx_t *i_ctx_p, const char *dict_name)
1857dd7cddfSDavid du Colombier {
1863ff48bf5SDavid du Colombier ref *pleveldict;
1873ff48bf5SDavid du Colombier ref rleveldict;
1887dd7cddfSDavid du Colombier int index;
1897dd7cddfSDavid du Colombier ref elt[2]; /* key, value */
1903ff48bf5SDavid du Colombier ref *psubdict;
1917dd7cddfSDavid du Colombier
1923ff48bf5SDavid du Colombier /*
1933ff48bf5SDavid du Colombier * We have to copy the refs for leveldict and subdict, since they may
1943ff48bf5SDavid du Colombier * move if their containing dictionary is resized.
1953ff48bf5SDavid du Colombier */
1963ff48bf5SDavid du Colombier if (dict_find_string(systemdict, dict_name, &pleveldict) <= 0)
1977dd7cddfSDavid du Colombier return_error(e_undefined);
1983ff48bf5SDavid du Colombier rleveldict = *pleveldict;
1993ff48bf5SDavid du Colombier index = dict_first(&rleveldict);
2003ff48bf5SDavid du Colombier while ((index = dict_next(&rleveldict, index, &elt[0])) >= 0)
2017dd7cddfSDavid du Colombier if (r_has_type(&elt[1], t_dictionary) &&
2023ff48bf5SDavid du Colombier dict_find(&elt[1], &elt[0], &psubdict) > 0 &&
203*593dc095SDavid du Colombier obj_eq(imemory, &elt[1], psubdict)
2047dd7cddfSDavid du Colombier ) {
2057dd7cddfSDavid du Colombier /* elt[1] is the 2nd-level sub-dictionary */
2067dd7cddfSDavid du Colombier int isub = dict_first(&elt[1]);
2077dd7cddfSDavid du Colombier ref subelt[2];
2083ff48bf5SDavid du Colombier int found = dict_find(systemdict, &elt[0], &psubdict);
2093ff48bf5SDavid du Colombier ref rsubdict;
2107dd7cddfSDavid du Colombier
2117dd7cddfSDavid du Colombier if (found <= 0)
2127dd7cddfSDavid du Colombier continue;
2133ff48bf5SDavid du Colombier rsubdict = *psubdict;
2147dd7cddfSDavid du Colombier while ((isub = dict_next(&elt[1], isub, &subelt[0])) >= 0)
215*593dc095SDavid du Colombier if (!obj_eq(imemory, &subelt[0], &elt[0])) {
2167dd7cddfSDavid du Colombier /* don't swap dict itself */
2173ff48bf5SDavid du Colombier int code = swap_entry(i_ctx_p, subelt, &rsubdict, &elt[1]);
2187dd7cddfSDavid du Colombier
2197dd7cddfSDavid du Colombier if (code < 0)
2207dd7cddfSDavid du Colombier return code;
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier } else {
2233ff48bf5SDavid du Colombier int code = swap_entry(i_ctx_p, elt, systemdict, &rleveldict);
2247dd7cddfSDavid du Colombier
2257dd7cddfSDavid du Colombier if (code < 0)
2267dd7cddfSDavid du Colombier return code;
2277dd7cddfSDavid du Colombier }
2287dd7cddfSDavid du Colombier return 0;
2297dd7cddfSDavid du Colombier }
2307dd7cddfSDavid du Colombier
2317dd7cddfSDavid du Colombier /*
2327dd7cddfSDavid du Colombier * Swap an entry from a higher level dictionary into a base dictionary.
2337dd7cddfSDavid du Colombier * elt[0] is the key, elt[1] is the current value in the Level 2 dictionary
2347dd7cddfSDavid du Colombier * (*pdict2).
2357dd7cddfSDavid du Colombier */
2367dd7cddfSDavid du Colombier private int
swap_entry(i_ctx_t * i_ctx_p,ref elt[2],ref * pdict,ref * pdict2)2377dd7cddfSDavid du Colombier swap_entry(i_ctx_t *i_ctx_p, ref elt[2], ref * pdict, ref * pdict2)
2387dd7cddfSDavid du Colombier {
2397dd7cddfSDavid du Colombier ref *pvalue;
2407dd7cddfSDavid du Colombier ref old_value; /* current value in *pdict */
2417dd7cddfSDavid du Colombier int found = dict_find(pdict, &elt[0], &pvalue);
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier switch (found) {
2447dd7cddfSDavid du Colombier default: /* <0, error */
2457dd7cddfSDavid du Colombier /*
2467dd7cddfSDavid du Colombier * The only possible error here is a dictfull error, which is
2477dd7cddfSDavid du Colombier * harmless.
2487dd7cddfSDavid du Colombier */
2497dd7cddfSDavid du Colombier /* fall through */
2507dd7cddfSDavid du Colombier case 0: /* missing */
2517dd7cddfSDavid du Colombier make_null(&old_value);
2527dd7cddfSDavid du Colombier break;
2537dd7cddfSDavid du Colombier case 1: /* present */
2547dd7cddfSDavid du Colombier old_value = *pvalue;
2557dd7cddfSDavid du Colombier }
2567dd7cddfSDavid du Colombier /*
2577dd7cddfSDavid du Colombier * Temporarily flag the dictionaries as local, so that we don't
2587dd7cddfSDavid du Colombier * get invalidaccess errors. (We know that they are both
2597dd7cddfSDavid du Colombier * referenced from systemdict, so they are allowed to reference
2607dd7cddfSDavid du Colombier * local objects even if they are global.)
2617dd7cddfSDavid du Colombier */
2627dd7cddfSDavid du Colombier {
2637dd7cddfSDavid du Colombier uint space2 = r_space(pdict2);
2647dd7cddfSDavid du Colombier int code;
2657dd7cddfSDavid du Colombier
2667dd7cddfSDavid du Colombier r_set_space(pdict2, avm_local);
2677dd7cddfSDavid du Colombier idict_put(pdict2, &elt[0], &old_value);
2687dd7cddfSDavid du Colombier if (r_has_type(&elt[1], t_null)) {
2697dd7cddfSDavid du Colombier code = idict_undef(pdict, &elt[0]);
2707dd7cddfSDavid du Colombier if (code == e_undefined &&
2717dd7cddfSDavid du Colombier r_has_type(&old_value, t_null)
2727dd7cddfSDavid du Colombier )
2737dd7cddfSDavid du Colombier code = 0;
2747dd7cddfSDavid du Colombier } else {
2757dd7cddfSDavid du Colombier uint space = r_space(pdict);
2767dd7cddfSDavid du Colombier
2777dd7cddfSDavid du Colombier r_set_space(pdict, avm_local);
2787dd7cddfSDavid du Colombier code = idict_put(pdict, &elt[0], &elt[1]);
2797dd7cddfSDavid du Colombier r_set_space(pdict, space);
2807dd7cddfSDavid du Colombier }
2817dd7cddfSDavid du Colombier r_set_space(pdict2, space2);
2827dd7cddfSDavid du Colombier return code;
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier }
285