xref: /plan9/sys/src/cmd/gs/src/zdict.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 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: zdict.c,v 1.6 2004/08/04 19:36:13 stefan Exp $ */
18 /* Dictionary operators */
19 #include "ghost.h"
20 #include "oper.h"
21 #include "iddict.h"
22 #include "dstack.h"
23 #include "ilevel.h"		/* for [count]dictstack */
24 #include "iname.h"		/* for dict_find_name */
25 #include "ipacked.h"		/* for inline dict lookup */
26 #include "ivmspace.h"
27 #include "store.h"
28 
29 /* <int> dict <dict> */
30 int
zdict(i_ctx_t * i_ctx_p)31 zdict(i_ctx_t *i_ctx_p)
32 {
33     os_ptr op = osp;
34 
35     check_type(*op, t_integer);
36 #if arch_sizeof_int < arch_sizeof_long
37     check_int_leu(*op, max_uint);
38 #else
39     if (op->value.intval < 0)
40 	return_error(e_rangecheck);
41 #endif
42     return dict_create((uint) op->value.intval, op);
43 }
44 
45 /* <dict> maxlength <int> */
46 private int
zmaxlength(i_ctx_t * i_ctx_p)47 zmaxlength(i_ctx_t *i_ctx_p)
48 {
49     os_ptr op = osp;
50 
51     check_type(*op, t_dictionary);
52     check_dict_read(*op);
53     make_int(op, dict_maxlength(op));
54     return 0;
55 }
56 
57 /* <dict> begin - */
58 int
zbegin(i_ctx_t * i_ctx_p)59 zbegin(i_ctx_t *i_ctx_p)
60 {
61     os_ptr op = osp;
62 
63     check_type(*op, t_dictionary);
64     check_dict_read(*op);
65     if (dsp == dstop)
66 	return_error(e_dictstackoverflow);
67     ++dsp;
68     ref_assign(dsp, op);
69     dict_set_top();
70     pop(1);
71     return 0;
72 }
73 
74 /* - end - */
75 int
zend(i_ctx_t * i_ctx_p)76 zend(i_ctx_t *i_ctx_p)
77 {
78     if (ref_stack_count_inline(&d_stack) == min_dstack_size) {
79 	/* We would underflow the d-stack. */
80 	return_error(e_dictstackunderflow);
81     }
82     while (dsp == dsbot) {
83 	/* We would underflow the current block. */
84 	ref_stack_pop_block(&d_stack);
85     }
86     dsp--;
87     dict_set_top();
88     return 0;
89 }
90 
91 /* <key> <value> def - */
92 /*
93  * We make this into a separate procedure because
94  * the interpreter will almost always call it directly.
95  */
96 int
zop_def(i_ctx_t * i_ctx_p)97 zop_def(i_ctx_t *i_ctx_p)
98 {
99     os_ptr op = osp;
100     os_ptr op1 = op - 1;
101     ref *pvslot;
102 
103     /* The following combines a check_op(2) with a type check. */
104     switch (r_type(op1)) {
105 	case t_name: {
106 	    /* We can use the fast single-probe lookup here. */
107 	    uint nidx = name_index(imemory, op1);
108 	    uint htemp;
109 
110 	    if_dict_find_name_by_index_top(nidx, htemp, pvslot) {
111 		if (dtop_can_store(op))
112 		    goto ra;
113 	    }
114 	    break;		/* handle all slower cases */
115 	    }
116 	case t_null:
117 	    return_error(e_typecheck);
118 	case t__invalid:
119 	    return_error(e_stackunderflow);
120     }
121     /*
122      * Combine the check for a writable top dictionary with
123      * the global/local store check.  See dstack.h for details.
124      */
125     if (!dtop_can_store(op)) {
126 	check_dict_write(*dsp);
127 	/*
128 	 * If the dictionary is writable, the problem must be
129 	 * an invalid store.
130 	 */
131 	return_error(e_invalidaccess);
132     }
133     /*
134      * Save a level of procedure call in the common (redefinition)
135      * case.  With the current interfaces, we pay a double lookup
136      * in the uncommon case.
137      */
138     if (dict_find(dsp, op1, &pvslot) <= 0)
139 	return idict_put(dsp, op1, op);
140 ra:
141     ref_assign_old_inline(&dsp->value.pdict->values, pvslot, op,
142 			  "dict_put(value)");
143     return 0;
144 }
145 int
zdef(i_ctx_t * i_ctx_p)146 zdef(i_ctx_t *i_ctx_p)
147 {
148     int code = zop_def(i_ctx_p);
149 
150     if (code >= 0) {
151 	pop(2);
152     }
153     return code;
154 }
155 
156 /* <key> load <value> */
157 private int
zload(i_ctx_t * i_ctx_p)158 zload(i_ctx_t *i_ctx_p)
159 {
160     os_ptr op = osp;
161     ref *pvalue;
162 
163     switch (r_type(op)) {
164 	case t_name:
165 	    /* Use the fast lookup. */
166 	    if ((pvalue = dict_find_name(op)) == 0)
167 		return_error(e_undefined);
168 	    ref_assign(op, pvalue);
169 	    return 0;
170 	case t_null:
171 	    return_error(e_typecheck);
172 	case t__invalid:
173 	    return_error(e_stackunderflow);
174 	default: {
175 		/* Use an explicit loop. */
176 		uint size = ref_stack_count(&d_stack);
177 		uint i;
178 
179 		for (i = 0; i < size; i++) {
180 		    ref *dp = ref_stack_index(&d_stack, i);
181 
182 		    check_dict_read(*dp);
183 		    if (dict_find(dp, op, &pvalue) > 0) {
184 			ref_assign(op, pvalue);
185 			return 0;
186 		    }
187 		}
188 		return_error(e_undefined);
189 	    }
190     }
191 }
192 
193 /* get - implemented in zgeneric.c */
194 
195 /* put - implemented in zgeneric.c */
196 
197 /* <dict> <key> .undef - */
198 /* <dict> <key> undef - */
199 private int
zundef(i_ctx_t * i_ctx_p)200 zundef(i_ctx_t *i_ctx_p)
201 {
202     os_ptr op = osp;
203 
204     check_type(op[-1], t_dictionary);
205     check_dict_write(op[-1]);
206     idict_undef(op - 1, op);	/* ignore undefined error */
207     pop(2);
208     return 0;
209 }
210 
211 /* <dict> <key> known <bool> */
212 private int
zknown(i_ctx_t * i_ctx_p)213 zknown(i_ctx_t *i_ctx_p)
214 {
215     os_ptr op = osp;
216     register os_ptr op1 = op - 1;
217     ref *pvalue;
218 
219     check_type(*op1, t_dictionary);
220     check_dict_read(*op1);
221     make_bool(op1, (dict_find(op1, op, &pvalue) > 0 ? 1 : 0));
222     pop(1);
223     return 0;
224 }
225 
226 /* <key> where <dict> true */
227 /* <key> where false */
228 int
zwhere(i_ctx_t * i_ctx_p)229 zwhere(i_ctx_t *i_ctx_p)
230 {
231     os_ptr op = osp;
232     ref_stack_enum_t rsenum;
233 
234     check_op(1);
235     ref_stack_enum_begin(&rsenum, &d_stack);
236     do {
237 	const ref *const bot = rsenum.ptr;
238 	const ref *pdref = bot + rsenum.size;
239 	ref *pvalue;
240 
241 	while (pdref-- > bot) {
242 	    check_dict_read(*pdref);
243 	    if (dict_find(pdref, op, &pvalue) > 0) {
244 		push(1);
245 		ref_assign(op - 1, pdref);
246 		make_true(op);
247 		return 0;
248 	    }
249 	}
250     } while (ref_stack_enum_next(&rsenum));
251     make_false(op);
252     return 0;
253 }
254 
255 /* copy for dictionaries -- called from zcopy in zgeneric.c. */
256 /* Only the type of *op has been checked. */
257 int
zcopy_dict(i_ctx_t * i_ctx_p)258 zcopy_dict(i_ctx_t *i_ctx_p)
259 {
260     os_ptr op = osp;
261     os_ptr op1 = op - 1;
262     int code;
263 
264     check_type(*op1, t_dictionary);
265     check_dict_read(*op1);
266     check_dict_write(*op);
267     if (!imemory->gs_lib_ctx->dict_auto_expand &&
268 	(dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1))
269 	)
270 	return_error(e_rangecheck);
271     code = idict_copy(op1, op);
272     if (code < 0)
273 	return code;
274     /*
275      * In Level 1 systems, we must copy the access attributes too.
276      * The only possible effect this can have is to make the
277      * copy read-only if the original dictionary is read-only.
278      */
279     if (!level2_enabled)
280 	r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1));
281     ref_assign(op1, op);
282     pop(1);
283     return 0;
284 }
285 
286 /* - currentdict <dict> */
287 private int
zcurrentdict(i_ctx_t * i_ctx_p)288 zcurrentdict(i_ctx_t *i_ctx_p)
289 {
290     os_ptr op = osp;
291 
292     push(1);
293     ref_assign(op, dsp);
294     return 0;
295 }
296 
297 /* - countdictstack <int> */
298 private int
zcountdictstack(i_ctx_t * i_ctx_p)299 zcountdictstack(i_ctx_t *i_ctx_p)
300 {
301     os_ptr op = osp;
302     uint count = ref_stack_count(&d_stack);
303 
304     push(1);
305     if (!level2_enabled)
306 	count--;		/* see dstack.h */
307     make_int(op, count);
308     return 0;
309 }
310 
311 /* <array> dictstack <subarray> */
312 private int
zdictstack(i_ctx_t * i_ctx_p)313 zdictstack(i_ctx_t *i_ctx_p)
314 {
315     os_ptr op = osp;
316     uint count = ref_stack_count(&d_stack);
317 
318     check_write_type(*op, t_array);
319     if (!level2_enabled)
320 	count--;		/* see dstack.h */
321     return ref_stack_store(&d_stack, op, count, 0, 0, true, idmemory,
322 			   "dictstack");
323 }
324 
325 /* - cleardictstack - */
326 private int
zcleardictstack(i_ctx_t * i_ctx_p)327 zcleardictstack(i_ctx_t *i_ctx_p)
328 {
329     while (zend(i_ctx_p) >= 0)
330 	DO_NOTHING;
331     return 0;
332 }
333 
334 /* ------ Extensions ------ */
335 
336 /* <dict1> <dict2> .dictcopynew <dict2> */
337 private int
zdictcopynew(i_ctx_t * i_ctx_p)338 zdictcopynew(i_ctx_t *i_ctx_p)
339 {
340     os_ptr op = osp;
341     os_ptr op1 = op - 1;
342     int code;
343 
344     check_type(*op1, t_dictionary);
345     check_dict_read(*op1);
346     check_type(*op, t_dictionary);
347     check_dict_write(*op);
348     /* This is only recognized in Level 2 mode. */
349     if (!imemory->gs_lib_ctx->dict_auto_expand)
350 	return_error(e_undefined);
351     code = idict_copy_new(op1, op);
352     if (code < 0)
353 	return code;
354     ref_assign(op1, op);
355     pop(1);
356     return 0;
357 }
358 
359 /* -mark- <key0> <value0> <key1> <value1> ... .dicttomark <dict> */
360 /* This is the Level 2 >> operator. */
361 private int
zdicttomark(i_ctx_t * i_ctx_p)362 zdicttomark(i_ctx_t *i_ctx_p)
363 {
364     uint count2 = ref_stack_counttomark(&o_stack);
365     ref rdict;
366     int code;
367     uint idx;
368 
369     if (count2 == 0)
370 	return_error(e_unmatchedmark);
371     count2--;
372     if ((count2 & 1) != 0)
373 	return_error(e_rangecheck);
374     code = dict_create(count2 >> 1, &rdict);
375     if (code < 0)
376 	return code;
377     /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */
378     /* we must enter the keys in top-to-bottom order. */
379     for (idx = 0; idx < count2; idx += 2) {
380 	code = idict_put(&rdict,
381 			 ref_stack_index(&o_stack, idx + 1),
382 			 ref_stack_index(&o_stack, idx));
383 	if (code < 0) {		/* There's no way to free the dictionary -- too bad. */
384 	    return code;
385 	}
386     }
387     ref_stack_pop(&o_stack, count2);
388     ref_assign(osp, &rdict);
389     return code;
390 }
391 
392 /* <dict> <key> .forceundef - */
393 /*
394  * This forces an "undef" even if the dictionary is not writable.
395  * Like .forceput, it is meant to be used only in a few special situations,
396  * and should not be accessible by name after initialization.
397  */
398 private int
zforceundef(i_ctx_t * i_ctx_p)399 zforceundef(i_ctx_t *i_ctx_p)
400 {
401     os_ptr op = osp;
402 
403     check_type(op[-1], t_dictionary);
404     /* Don't check_dict_write */
405     idict_undef(op - 1, op);	/* ignore undefined error */
406     pop(2);
407     return 0;
408 }
409 
410 /* <dict> <key> .knownget <value> true */
411 /* <dict> <key> .knownget false */
412 private int
zknownget(i_ctx_t * i_ctx_p)413 zknownget(i_ctx_t *i_ctx_p)
414 {
415     os_ptr op = osp;
416     register os_ptr op1 = op - 1;
417     ref *pvalue;
418 
419     check_type(*op1, t_dictionary);
420     check_dict_read(*op1);
421     if (dict_find(op1, op, &pvalue) <= 0) {
422 	make_false(op1);
423 	pop(1);
424     } else {
425 	ref_assign(op1, pvalue);
426 	make_true(op);
427     }
428     return 0;
429 }
430 
431 /* <dict> <key> .knownundef <bool> */
432 private int
zknownundef(i_ctx_t * i_ctx_p)433 zknownundef(i_ctx_t *i_ctx_p)
434 {
435     os_ptr op = osp;
436     os_ptr op1 = op - 1;
437     int code;
438 
439     check_type(*op1, t_dictionary);
440     check_dict_write(*op1);
441     code = idict_undef(op1, op);
442     make_bool(op1, code == 0);
443     pop(1);
444     return 0;
445 }
446 
447 /* <dict> <int> .setmaxlength - */
448 private int
zsetmaxlength(i_ctx_t * i_ctx_p)449 zsetmaxlength(i_ctx_t *i_ctx_p)
450 {
451     os_ptr op = osp;
452     os_ptr op1 = op - 1;
453     uint new_size;
454     int code;
455 
456     check_type(*op1, t_dictionary);
457     check_dict_write(*op1);
458     check_type(*op, t_integer);
459 #if arch_sizeof_int < arch_sizeof_long
460     check_int_leu(*op, max_uint);
461 #else
462     if (op->value.intval < 0)
463 	return_error(e_rangecheck);
464 #endif
465     new_size = (uint) op->value.intval;
466     if (dict_length(op - 1) > new_size)
467 	return_error(e_dictfull);
468     code = idict_resize(op - 1, new_size);
469     if (code >= 0)
470 	pop(2);
471     return code;
472 }
473 
474 /* ------ Initialization procedure ------ */
475 
476 /* We need to split the table because of the 16-element limit. */
477 const op_def zdict1_op_defs[] = {
478     {"0cleardictstack", zcleardictstack},
479     {"1begin", zbegin},
480     {"0countdictstack", zcountdictstack},
481     {"0currentdict", zcurrentdict},
482     {"2def", zdef},
483     {"1dict", zdict},
484     {"0dictstack", zdictstack},
485     {"0end", zend},
486     {"2known", zknown},
487     {"1load", zload},
488     {"1maxlength", zmaxlength},
489     {"2.undef", zundef},	/* we need this even in Level 1 */
490     {"1where", zwhere},
491     op_def_end(0)
492 };
493 const op_def zdict2_op_defs[] = {
494 		/* Extensions */
495     {"2.dictcopynew", zdictcopynew},
496     {"1.dicttomark", zdicttomark},
497     {"2.forceundef", zforceundef},
498     {"2.knownget", zknownget},
499     {"1.knownundef", zknownundef},
500     {"2.setmaxlength", zsetmaxlength},
501     op_def_end(0)
502 };
503