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