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