1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: iinit.c 9043 2008-08-28 22:48:19Z giles $ */
15 /* Initialize internally known objects for Ghostscript interpreter */
16 #include "string_.h"
17 #include "ghost.h"
18 #include "gscdefs.h"
19 #include "gsexit.h"
20 #include "gsstruct.h"
21 #include "ierrors.h"
22 #include "ialloc.h"
23 #include "iddict.h"
24 #include "dstack.h"
25 #include "ilevel.h"
26 #include "iinit.h"
27 #include "iname.h"
28 #include "interp.h"
29 #include "ipacked.h"
30 #include "iparray.h"
31 #include "iutil.h"
32 #include "ivmspace.h"
33 #include "opdef.h"
34 #include "store.h"
35 
36 /* Implementation parameters. */
37 /*
38  * Define the (initial) sizes of the various system dictionaries.  We want
39  * the sizes to be prime numbers large enough to cover all the operators,
40  * plus everything in the init files, even if all the optional features are
41  * selected.  Note that these sizes must be large enough to get us through
42  * initialization, since we start up in Level 1 mode where dictionaries
43  * don't expand automatically.
44  */
45 /* The size of systemdict can be set in the makefile. */
46 #ifndef SYSTEMDICT_SIZE
47 #  define SYSTEMDICT_SIZE 631
48 #endif
49 #ifndef SYSTEMDICT_LEVEL2_SIZE
50 #  define SYSTEMDICT_LEVEL2_SIZE 983
51 #endif
52 #ifndef SYSTEMDICT_LL3_SIZE
53 #  define SYSTEMDICT_LL3_SIZE 1123
54 #endif
55 /* The size of level2dict, if applicable, can be set in the makefile. */
56 #ifndef LEVEL2DICT_SIZE
57 #  define LEVEL2DICT_SIZE 251
58 #endif
59 /* Ditto the size of ll3dict. */
60 #ifndef LL3DICT_SIZE
61 #  define LL3DICT_SIZE 43
62 #endif
63 /* Ditto the size of filterdict. */
64 #ifndef FILTERDICT_SIZE
65 #  define FILTERDICT_SIZE 43
66 #endif
67 /* Define an arbitrary size for the operator procedure tables. */
68 #ifndef OP_ARRAY_TABLE_SIZE
69 #  define OP_ARRAY_TABLE_SIZE 300
70 #endif
71 #ifndef OP_ARRAY_TABLE_GLOBAL_SIZE
72 #  define OP_ARRAY_TABLE_GLOBAL_SIZE OP_ARRAY_TABLE_SIZE
73 #endif
74 #ifndef OP_ARRAY_TABLE_LOCAL_SIZE
75 #  define OP_ARRAY_TABLE_LOCAL_SIZE (OP_ARRAY_TABLE_SIZE / 2)
76 #endif
77 #define OP_ARRAY_TABLE_TOTAL_SIZE\
78   (OP_ARRAY_TABLE_GLOBAL_SIZE + OP_ARRAY_TABLE_LOCAL_SIZE)
79 
80 /* Define the list of error names. */
81 const char *const gs_error_names[] =
82 {
83     ERROR_NAMES
84 };
85 
86 /* The operator tables */
87 op_array_table op_array_table_global, op_array_table_local;	/* definitions of `operator' procedures */
88 
89 /* Enter a name and value into a dictionary. */
90 static int
i_initial_enter_name_in(i_ctx_t * i_ctx_p,ref * pdict,const char * nstr,const ref * pref)91 i_initial_enter_name_in(i_ctx_t *i_ctx_p, ref *pdict, const char *nstr,
92 			const ref * pref)
93 {
94     int code = idict_put_string(pdict, nstr, pref);
95 
96     if (code < 0)
97 	lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
98 		 code, nstr, dict_length(pdict), dict_maxlength(pdict));
99     return code;
100 }
101 int
i_initial_enter_name(i_ctx_t * i_ctx_p,const char * nstr,const ref * pref)102 i_initial_enter_name(i_ctx_t *i_ctx_p, const char *nstr, const ref * pref)
103 {
104     return i_initial_enter_name_in(i_ctx_p, systemdict, nstr, pref);
105 }
106 
107 /* Remove a name from systemdict. */
108 void
i_initial_remove_name(i_ctx_t * i_ctx_p,const char * nstr)109 i_initial_remove_name(i_ctx_t *i_ctx_p, const char *nstr)
110 {
111     ref nref;
112 
113     if (name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1) >= 0)
114 	idict_undef(systemdict, &nref);
115 }
116 
117 /* Define the names and sizes of the initial dictionaries. */
118 /* The names are used to create references in systemdict. */
119 const struct {
120     const char *name;
121     uint size;
122     bool local;
123 } initial_dictionaries[] = {
124 #ifdef INITIAL_DICTIONARIES
125     INITIAL_DICTIONARIES
126 #else
127     /* systemdict is created and named automagically */
128     {
129 	"level2dict", LEVEL2DICT_SIZE, false
130     },
131     {
132 	"ll3dict", LL3DICT_SIZE, false
133     },
134     {
135 	"globaldict", 0, false
136     },
137     {
138 	"userdict", 0, true
139     },
140     {
141 	"filterdict", FILTERDICT_SIZE, false
142     },
143 #endif
144 };
145 /* systemdict and globaldict are magically inserted at the bottom */
146 const char *const initial_dstack[] =
147 {
148 #ifdef INITIAL_DSTACK
149     INITIAL_DSTACK
150 #else
151     "userdict"
152 #endif
153 };
154 
155 #define MIN_DSTACK_SIZE (countof(initial_dstack) + 1)	/* +1 for systemdict */
156 
157 
158 /*
159  * Detect whether we have any Level 2 or LanguageLevel 3 operators.
160  * We export this for gs_init1 in imain.c.
161  * This is slow, but we only call it a couple of times.
162  */
163 static int
gs_op_language_level(void)164 gs_op_language_level(void)
165 {
166     const op_def *const *tptr;
167     int level = 1;
168 
169     for (tptr = op_defs_all; *tptr != 0; ++tptr) {
170 	const op_def *def;
171 
172 	for (def = *tptr; def->oname != 0; ++def)
173 	    if (op_def_is_begin_dict(def)) {
174 		if (!strcmp(def->oname, "level2dict"))
175 		    level = max(level, 2);
176 		else if (!strcmp(def->oname, "ll3dict"))
177 		    level = max(level, 3);
178 	    }
179     }
180     return level;
181 }
182 bool
gs_have_level2(void)183 gs_have_level2(void)
184 {
185     return (gs_op_language_level() >= 2);
186 }
187 
188 /* Create an initial dictionary if necessary. */
189 static ref *
make_initial_dict(i_ctx_t * i_ctx_p,const char * iname,ref idicts[])190 make_initial_dict(i_ctx_t *i_ctx_p, const char *iname, ref idicts[])
191 {
192     int i;
193 
194     /* systemdict was created specially. */
195     if (!strcmp(iname, "systemdict"))
196 	return systemdict;
197     for (i = 0; i < countof(initial_dictionaries); i++) {
198 	const char *dname = initial_dictionaries[i].name;
199 	const int dsize = initial_dictionaries[i].size;
200 
201 	if (!strcmp(iname, dname)) {
202 	    ref *dref = &idicts[i];
203 
204 	    if (r_has_type(dref, t_null)) {
205 		gs_ref_memory_t *mem =
206 		    (initial_dictionaries[i].local ?
207 		     iimemory_local : iimemory_global);
208 		int code = dict_alloc(mem, dsize, dref);
209 
210 		if (code < 0)
211 		    return 0;	/* disaster */
212 	    }
213 	    return dref;
214 	}
215     }
216 
217     /*
218      * Name mentioned in some op_def, but not in initial_dictionaries.
219      * Punt.
220      */
221     return 0;
222 }
223 
224 /* Initialize objects other than operators.  In particular, */
225 /* initialize the dictionaries that hold operator definitions. */
226 int
obj_init(i_ctx_t ** pi_ctx_p,gs_dual_memory_t * idmem)227 obj_init(i_ctx_t **pi_ctx_p, gs_dual_memory_t *idmem)
228 {
229     int level = gs_op_language_level();
230     ref system_dict;
231     i_ctx_t *i_ctx_p;
232     int code;
233 
234     /*
235      * Create systemdict.  The context machinery requires that
236      * we do this before initializing the interpreter.
237      */
238     code = dict_alloc(idmem->space_global,
239 		      (level >= 3 ? SYSTEMDICT_LL3_SIZE :
240 		       level >= 2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE),
241 		      &system_dict);
242     if (code < 0)
243 	return code;
244 
245     /* Initialize the interpreter. */
246     code = gs_interp_init(pi_ctx_p, &system_dict, idmem);
247     if (code < 0)
248 	return code;
249     i_ctx_p = *pi_ctx_p;
250 
251     {
252 #define icount countof(initial_dictionaries)
253 	ref idicts[icount];
254 	int i;
255 	const op_def *const *tptr;
256 
257 	min_dstack_size = MIN_DSTACK_SIZE;
258 
259 	refset_null(idicts, icount);
260 
261 	/* Put systemdict on the dictionary stack. */
262 	if (level >= 2) {
263 	    dsp += 2;
264 	    /*
265 	     * For the moment, let globaldict be an alias for systemdict.
266 	     */
267 	    dsp[-1] = system_dict;
268 	    min_dstack_size++;
269 	} else {
270 	    ++dsp;
271 	}
272 	*dsp = system_dict;
273 
274 	/* Create dictionaries which are to be homes for operators. */
275 	for (tptr = op_defs_all; *tptr != 0; tptr++) {
276 	    const op_def *def;
277 
278 	    for (def = *tptr; def->oname != 0; def++)
279 		if (op_def_is_begin_dict(def)) {
280 		    if (make_initial_dict(i_ctx_p, def->oname, idicts) == 0)
281 			return_error(e_VMerror);
282 		}
283 	}
284 
285 	/* Set up the initial dstack. */
286 	for (i = 0; i < countof(initial_dstack); i++) {
287 	    const char *dname = initial_dstack[i];
288 
289 	    ++dsp;
290 	    if (!strcmp(dname, "userdict"))
291 		dstack_userdict_index = dsp - dsbot;
292 	    ref_assign(dsp, make_initial_dict(i_ctx_p, dname, idicts));
293 	}
294 
295 	/* Enter names of referenced initial dictionaries into systemdict. */
296 	initial_enter_name("systemdict", systemdict);
297 	for (i = 0; i < icount; i++) {
298 	    ref *idict = &idicts[i];
299 
300 	    if (!r_has_type(idict, t_null)) {
301 		/*
302 		 * Note that we enter the dictionary in systemdict
303 		 * even if it is in local VM.  There is a special
304 		 * provision in the garbage collector for this:
305 		 * see ivmspace.h for more information.
306 		 * In order to do this, we must temporarily
307 		 * identify systemdict as local, so that the
308 		 * store check in dict_put won't fail.
309 		 */
310 		uint save_space = r_space(systemdict);
311 
312 		r_set_space(systemdict, avm_local);
313 		code = initial_enter_name(initial_dictionaries[i].name,
314 					  idict);
315 		r_set_space(systemdict, save_space);
316 		if (code < 0)
317 		    return code;
318 	    }
319 	}
320 #undef icount
321     }
322 
323     gs_interp_reset(i_ctx_p);
324 
325     {
326 	ref vnull, vtrue, vfalse;
327 
328 	make_null(&vnull);
329 	make_true(&vtrue);
330 	make_false(&vfalse);
331 	if ((code = initial_enter_name("null", &vnull)) < 0 ||
332 	    (code = initial_enter_name("true", &vtrue)) < 0 ||
333 	    (code = initial_enter_name("false", &vfalse)) < 0
334 	    )
335 	    return code;
336     }
337 
338     /* Create the error name table */
339     {
340 	int n = countof(gs_error_names) - 1;
341 	int i;
342 	ref era;
343 
344 	code = ialloc_ref_array(&era, a_readonly, n, "ErrorNames");
345 	if (code < 0)
346 	    return code;
347 	for (i = 0; i < n; i++)
348 	  if ((code = name_enter_string(imemory, (const char *)gs_error_names[i],
349 					  era.value.refs + i)) < 0)
350 		return code;
351 	return initial_enter_name("ErrorNames", &era);
352     }
353 }
354 
355 /* Run the initialization procedures of the individual operator files. */
356 int
zop_init(i_ctx_t * i_ctx_p)357 zop_init(i_ctx_t *i_ctx_p)
358 {
359     const op_def *const *tptr;
360     int code;
361 
362     /* Because of a bug in Sun's SC1.0 compiler, */
363     /* we have to spell out the typedef for op_def_ptr here: */
364     const op_def *def;
365 
366     for (tptr = op_defs_all; *tptr != 0; tptr++) {
367 	for (def = *tptr; def->oname != 0; def++)
368 	    DO_NOTHING;
369 	if (def->proc != 0) {
370 	    code = def->proc(i_ctx_p);
371 	    if (code < 0) {
372 		lprintf2("op_init proc 0x%lx returned error %d!\n",
373 			 (ulong)def->proc, code);
374 		return code;
375 	    }
376 	}
377     }
378 
379     /* Initialize the predefined names other than operators. */
380     /* Do this here in case op_init changed any of them. */
381     {
382 	ref vcr, vpr, vpf, vre, vrd;
383 
384 	make_const_string(&vcr, a_readonly | avm_foreign,
385 			  strlen(gs_copyright), (const byte *)gs_copyright);
386 	make_const_string(&vpr, a_readonly | avm_foreign,
387 			  strlen(gs_product), (const byte *)gs_product);
388 	make_const_string(&vpf, a_readonly | avm_foreign,
389 			  strlen(gs_productfamily),
390 			  (const byte *)gs_productfamily);
391 	make_int(&vre, gs_revision);
392 	make_int(&vrd, gs_revisiondate);
393 	if ((code = initial_enter_name("copyright", &vcr)) < 0 ||
394 	    (code = initial_enter_name("product", &vpr)) < 0 ||
395 	    (code = initial_enter_name("productfamily", &vpf)) < 0 ||
396 	    (code = initial_enter_name("revision", &vre)) < 0 ||
397 	    (code = initial_enter_name("revisiondate", &vrd)) < 0)
398 	    return code;
399     }
400 
401     return 0;
402 }
403 
404 /* Create an op_array table. */
405 static int
alloc_op_array_table(i_ctx_t * i_ctx_p,uint size,uint space,op_array_table * opt)406 alloc_op_array_table(i_ctx_t *i_ctx_p, uint size, uint space,
407 		     op_array_table *opt)
408 {
409     uint save_space = ialloc_space(idmemory);
410     int code;
411 
412     ialloc_set_space(idmemory, space);
413     code = ialloc_ref_array(&opt->table, a_readonly, size,
414 			    "op_array table");
415     ialloc_set_space(idmemory, save_space);
416     if (code < 0)
417 	return code;
418     refset_null(opt->table.value.refs, size);
419     opt->nx_table =
420 	(ushort *) ialloc_byte_array(size, sizeof(ushort),
421 				     "op_array nx_table");
422     if (opt->nx_table == 0)
423 	return_error(e_VMerror);
424     opt->count = 0;
425     opt->root_p = &opt->table;
426     opt->attrs = space | a_executable;
427     return 0;
428 }
429 
430 /* Initialize the operator table. */
431 int
op_init(i_ctx_t * i_ctx_p)432 op_init(i_ctx_t *i_ctx_p)
433 {
434     const op_def *const *tptr;
435     int code;
436 
437     /* Enter each operator into the appropriate dictionary. */
438 
439     for (tptr = op_defs_all; *tptr != 0; tptr++) {
440 	ref *pdict = systemdict;
441 	const op_def *def;
442 	const char *nstr;
443 
444 	for (def = *tptr; (nstr = def->oname) != 0; def++)
445 	    if (op_def_is_begin_dict(def)) {
446 		ref nref;
447 
448 		code = name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1);
449 		if (code < 0)
450 		    return code;
451 		if (!dict_find(systemdict, &nref, &pdict))
452 		    return_error(e_Fatal);
453 		if (!r_has_type(pdict, t_dictionary))
454 		    return_error(e_Fatal);
455 	    } else {
456 		ref oper;
457 		uint index_in_table = def - *tptr;
458 		uint opidx = (tptr - op_defs_all) * OP_DEFS_MAX_SIZE +
459 		    index_in_table;
460 
461 		if (index_in_table >= OP_DEFS_MAX_SIZE) {
462 		    lprintf1("opdef overrun! %s\n", def->oname);
463 		    return_error(e_Fatal);
464 		}
465 		gs_interp_make_oper(&oper, def->proc, opidx);
466 		/* The first character of the name is a digit */
467 		/* giving the minimum acceptable number of operands. */
468 		/* Check to make sure it's within bounds. */
469 		if (*nstr - '0' > gs_interp_max_op_num_args)
470 		    return_error(e_Fatal);
471 		nstr++;
472 		/*
473 		 * Skip internal operators, and the second occurrence of
474 		 * operators with special indices.
475 		 */
476 		if (*nstr != '%' && r_size(&oper) == opidx) {
477 		    code =
478 			i_initial_enter_name_in(i_ctx_p, pdict, nstr, &oper);
479 		    if (code < 0)
480 			return code;
481 		}
482 	    }
483     }
484     /* Allocate the tables for `operator' procedures. */
485     /* Make one of them local so we can have local operators. */
486 
487     if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_GLOBAL_SIZE,
488 				     avm_global, &op_array_table_global) < 0))
489 	return code;
490     op_array_table_global.base_index = op_def_count;
491     if ((code = gs_register_ref_root(imemory, NULL,
492 				     (void **)&op_array_table_global.root_p,
493 				     "op_array_table(global)")) < 0 ||
494 	(code = gs_register_struct_root(imemory, NULL,
495 				(void **)&op_array_table_global.nx_table,
496 					"op_array nx_table(global)")) < 0 ||
497 	(code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_LOCAL_SIZE,
498 				     avm_local, &op_array_table_local) < 0)
499 	)
500 	return code;
501     op_array_table_local.base_index =
502 	op_array_table_global.base_index +
503 	r_size(&op_array_table_global.table);
504     if ((code = gs_register_ref_root(imemory, NULL,
505 				     (void **)&op_array_table_local.root_p,
506 				     "op_array_table(local)")) < 0 ||
507 	(code = gs_register_struct_root(imemory, NULL,
508 				(void **)&op_array_table_local.nx_table,
509 					"op_array nx_table(local)")) < 0
510 	)
511 	return code;
512 
513     return 0;
514 }
515 
516 #ifdef DEBUG_TRACE_PS_OPERATORS
517 static const char *unknown_op_name = "unknown_op";
518 
519 const char *
op_get_name_string(op_proc_t opproc)520 op_get_name_string(op_proc_t opproc)
521 {
522     const op_def *const *tptr;
523     int code;
524 
525     for (tptr = op_defs_all; *tptr != 0; tptr++) {
526 	const op_def *def;
527 
528 	for (def = *tptr; def->oname != 0; def++)
529 	    if (!op_def_is_begin_dict(def)) {
530 		if (def->proc == opproc)
531 		    return def->oname;
532 	    }
533     }
534     return unknown_op_name;
535 }
536 #endif
537