Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/iinit.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Initialize internally known objects for Ghostscript interpreter */
18
#include "string_.h"
19
#include "ghost.h"
20
#include "gscdefs.h"
21
#include "gsexit.h"
22
#include "gsstruct.h"
23
#include "ierrors.h"
24
#include "ialloc.h"
25
#include "iddict.h"
26
#include "dstack.h"
27
#include "ilevel.h"
28
#include "iinit.h"
29
#include "iname.h"
30
#include "interp.h"
31
#include "ipacked.h"
32
#include "iparray.h"
33
#include "iutil.h"
34
#include "ivmspace.h"
35
#include "opdef.h"
36
#include "store.h"
37
#include "iconf.h"
38
#include "gxiodev.h"
39
40
/* Implementation parameters. */
41
/*
42
 * Define the (initial) sizes of the various system dictionaries.  We want
43
 * the sizes to be prime numbers large enough to cover all the operators,
44
 * plus everything in the init files, even if all the optional features are
45
 * selected.  Note that these sizes must be large enough to get us through
46
 * initialization, since we start up in Level 1 mode where dictionaries
47
 * don't expand automatically.
48
 */
49
/* The size of systemdict can be set in the makefile. */
50
#ifndef SYSTEMDICT_SIZE
51
0
#  define SYSTEMDICT_SIZE 631
52
#endif
53
#ifndef SYSTEMDICT_LEVEL2_SIZE
54
0
#  define SYSTEMDICT_LEVEL2_SIZE 983
55
#endif
56
#ifndef SYSTEMDICT_LL3_SIZE
57
162k
#  define SYSTEMDICT_LL3_SIZE 1123
58
#endif
59
/* The size of level2dict, if applicable, can be set in the makefile. */
60
#ifndef LEVEL2DICT_SIZE
61
#  define LEVEL2DICT_SIZE 251
62
#endif
63
/* Ditto the size of ll3dict. */
64
#ifndef LL3DICT_SIZE
65
#  define LL3DICT_SIZE 43
66
#endif
67
/* Ditto the size of userdict. */
68
#ifndef USERDICT_SIZE
69
#  define USERDICT_SIZE 211
70
#endif
71
/* Ditto the size of $error. */
72
#ifndef DOLLARERROR_SIZE
73
#  define DOLLARERROR_SIZE 43
74
#endif
75
/* Ditto the size of errordict. */
76
#ifndef ERRORDICT_SIZE
77
#  define ERRORDICT_SIZE 43
78
#endif
79
#ifndef STATUSDICT_SIZE
80
#  define STATUSDICT_SIZE 91
81
#endif
82
#ifndef SERVERDICT_SIZE
83
#  define SERVERDICT_SIZE 11
84
#endif
85
/* Ditto the size of FontDirectory. */
86
#ifndef FONTDIRECTORY_SIZE
87
#  define FONTDIRECTORY_SIZE 101
88
#endif
89
/* Ditto the size of filterdict. */
90
#ifndef FILTERDICT_SIZE
91
#  define FILTERDICT_SIZE 43
92
#endif
93
/* Ditto the size of filterdict. */
94
#ifndef LOCALINSTANCEDICT_SIZE
95
#  define LOCALINSTANCEDICT_SIZE 5
96
#endif
97
/* Define an arbitrary size for the operator procedure tables. */
98
#ifndef OP_ARRAY_TABLE_SIZE
99
324k
#  define OP_ARRAY_TABLE_SIZE 300
100
#endif
101
#ifndef OP_ARRAY_TABLE_GLOBAL_SIZE
102
162k
#  define OP_ARRAY_TABLE_GLOBAL_SIZE OP_ARRAY_TABLE_SIZE
103
#endif
104
#ifndef OP_ARRAY_TABLE_LOCAL_SIZE
105
162k
#  define OP_ARRAY_TABLE_LOCAL_SIZE (OP_ARRAY_TABLE_SIZE / 2)
106
#endif
107
#define OP_ARRAY_TABLE_TOTAL_SIZE\
108
  (OP_ARRAY_TABLE_GLOBAL_SIZE + OP_ARRAY_TABLE_LOCAL_SIZE)
109
110
/* Define the list of error names. */
111
const char *const gs_error_names[] =
112
{
113
    ERROR_NAMES
114
};
115
116
/* Enter a name and value into a dictionary. */
117
static int
118
i_initial_enter_name_in(i_ctx_t *i_ctx_p, ref *pdict, const char *nstr,
119
                        const ref * pref)
120
98.9M
{
121
98.9M
    int code = idict_put_string(pdict, nstr, pref);
122
123
98.9M
    if (code < 0)
124
0
        lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
125
98.9M
                 code, nstr, dict_length(pdict), dict_maxlength(pdict));
126
98.9M
    return code;
127
98.9M
}
128
int
129
i_initial_enter_name(i_ctx_t *i_ctx_p, const char *nstr, const ref * pref)
130
4.54M
{
131
4.54M
    return i_initial_enter_name_in(i_ctx_p, systemdict, nstr, pref);
132
4.54M
}
133
134
/* Enter a name and value into a dictionary. */
135
static int
136
i_initial_enter_name_copy_in(i_ctx_t *i_ctx_p, ref *pdict, const char *nstr,
137
                             const ref * pref)
138
2.36M
{
139
2.36M
    int code = idict_put_string_copy(pdict, nstr, pref);
140
141
2.36M
    if (code < 0)
142
0
        lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
143
2.36M
                 code, nstr, dict_length(pdict), dict_maxlength(pdict));
144
2.36M
    return code;
145
2.36M
}
146
int
147
i_initial_enter_name_copy(i_ctx_t *i_ctx_p, const char *nstr, const ref * pref)
148
2.36M
{
149
2.36M
    return i_initial_enter_name_copy_in(i_ctx_p, systemdict, nstr, pref);
150
2.36M
}
151
152
/* Remove a name from systemdict. */
153
void
154
i_initial_remove_name(i_ctx_t *i_ctx_p, const char *nstr)
155
0
{
156
0
    ref nref;
157
158
0
    if (name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1) >= 0)
159
0
        idict_undef(systemdict, &nref);
160
0
}
161
162
/* Define the names and sizes of the initial dictionaries. */
163
/* The names are used to create references in systemdict. */
164
const struct {
165
    const char *name;
166
    uint size;
167
    bool local;
168
} initial_dictionaries[] = {
169
#ifdef INITIAL_DICTIONARIES
170
    INITIAL_DICTIONARIES
171
#else
172
    /* systemdict is created and named automagically */
173
    {
174
        "level2dict", LEVEL2DICT_SIZE, false
175
    },
176
    {
177
        "ll3dict", LL3DICT_SIZE, false
178
    },
179
    {
180
        "globaldict", 0, false
181
    },
182
    {
183
        "userdict", USERDICT_SIZE, true
184
    },
185
    {
186
        "$error", DOLLARERROR_SIZE, true
187
    },
188
    {
189
        "errordict", ERRORDICT_SIZE, true
190
    },
191
    {
192
        "LocalFontDirectory", FONTDIRECTORY_SIZE, true
193
    },
194
    {
195
        "GlobalFontDirectory", FONTDIRECTORY_SIZE, false
196
    },
197
    {
198
        "statusdict", STATUSDICT_SIZE, true
199
    },
200
    {
201
        "serverdict", SERVERDICT_SIZE, true
202
    },
203
    {
204
        "filterdict", FILTERDICT_SIZE, false
205
    },
206
    {
207
        "localinstancedict", LOCALINSTANCEDICT_SIZE, true
208
    },
209
#endif
210
};
211
const char *const initial_referred[] =
212
{
213
#ifdef INITIAL_REFERRED
214
    INITIAL_REFERRED
215
#else
216
    "$error",
217
    "errordict",
218
    "LocalFontDirectory",
219
    "GlobalFontDirectory",
220
    "statusdict",
221
    "serverdict",
222
    "localinstancedict",
223
#endif
224
};
225
/* systemdict and globaldict are magically inserted at the bottom */
226
const char *const initial_dstack[] =
227
{
228
#ifdef INITIAL_DSTACK
229
    INITIAL_DSTACK
230
#else
231
    "userdict"
232
#endif
233
};
234
235
162k
#define MIN_DSTACK_SIZE (countof(initial_dstack) + 1)   /* +1 for systemdict */
236
237
/*
238
 * Detect whether we have any Level 2 or LanguageLevel 3 operators.
239
 * We export this for gs_init1 in imain.c.
240
 * This is slow, but we only call it a couple of times.
241
 */
242
static int
243
gs_op_language_level(void)
244
324k
{
245
324k
    const op_def *const *tptr;
246
324k
    int level = 1;
247
248
33.4M
    for (tptr = op_defs_all; *tptr != 0; ++tptr) {
249
33.0M
        const op_def *def;
250
251
257M
        for (def = *tptr; def->oname != 0; ++def)
252
224M
            if (op_def_is_begin_dict(def)) {
253
9.08M
                if (!strcmp(def->oname, "level2dict"))
254
4.86M
                    level = max(level, 2);
255
4.21M
                else if (!strcmp(def->oname, "ll3dict"))
256
1.29M
                    level = max(level, 3);
257
9.08M
            }
258
33.0M
    }
259
324k
    return level;
260
324k
}
261
bool
262
gs_have_level2(void)
263
162k
{
264
162k
    return (gs_op_language_level() >= 2);
265
162k
}
266
267
/* Create an initial dictionary if necessary. */
268
static ref *
269
make_initial_dict(i_ctx_t *i_ctx_p, const char *iname, ref idicts[])
270
5.83M
{
271
5.83M
    int i;
272
273
    /* systemdict was created specially. */
274
5.83M
    if (!strcmp(iname, "systemdict"))
275
162k
        return systemdict;
276
27.9M
    for (i = 0; i < countof(initial_dictionaries); i++) {
277
27.9M
        const char *dname = initial_dictionaries[i].name;
278
27.9M
        const int dsize = initial_dictionaries[i].size;
279
280
27.9M
        if (!strcmp(iname, dname)) {
281
5.67M
            ref *dref = &idicts[i];
282
283
5.67M
            if (r_has_type(dref, t_null)) {
284
1.78M
                gs_ref_memory_t *mem =
285
1.78M
                    (initial_dictionaries[i].local ?
286
1.13M
                     iimemory_local : iimemory_global);
287
1.78M
                int code = dict_alloc(mem, dsize, dref);
288
289
1.78M
                if (code < 0)
290
0
                    return 0;   /* disaster */
291
1.78M
            }
292
5.67M
            return dref;
293
5.67M
        }
294
27.9M
    }
295
296
    /*
297
     * Name mentioned in some op_def, but not in initial_dictionaries.
298
     * Punt.
299
     */
300
0
    return 0;
301
5.67M
}
302
303
/* Initialize objects other than operators.  In particular, */
304
/* initialize the dictionaries that hold operator definitions. */
305
int
306
obj_init(i_ctx_t **pi_ctx_p, gs_dual_memory_t *idmem)
307
162k
{
308
162k
    int level = gs_op_language_level();
309
162k
    ref system_dict;
310
162k
    i_ctx_t *i_ctx_p;
311
162k
    int code;
312
313
    /*
314
     * Create systemdict.  The context machinery requires that
315
     * we do this before initializing the interpreter.
316
     */
317
162k
    code = dict_alloc(idmem->space_global,
318
162k
                      (level >= 3 ? SYSTEMDICT_LL3_SIZE :
319
162k
                       level >= 2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE),
320
162k
                      &system_dict);
321
162k
    if (code < 0)
322
0
        return code;
323
324
    /* Initialize the interpreter. */
325
162k
    code = gs_interp_init(pi_ctx_p, &system_dict, idmem);
326
162k
    if (code < 0)
327
0
        return code;
328
162k
    i_ctx_p = *pi_ctx_p;
329
330
162k
    {
331
2.10M
#define icount countof(initial_dictionaries)
332
162k
        ref idicts[icount];
333
162k
        int i;
334
162k
        const op_def *const *tptr;
335
336
162k
        min_dstack_size = MIN_DSTACK_SIZE;
337
338
162k
        refset_null(idicts, icount);
339
340
        /* Put systemdict on the dictionary stack. */
341
162k
        if (level >= 2) {
342
162k
            dsp += 2;
343
            /*
344
             * For the moment, let globaldict be an alias for systemdict.
345
             */
346
162k
            dsp[-1] = system_dict;
347
162k
            min_dstack_size++;
348
162k
        } else {
349
0
            ++dsp;
350
0
        }
351
162k
        *dsp = system_dict;
352
353
        /* Create dictionaries which are to be homes for operators. */
354
16.7M
        for (tptr = op_defs_all; *tptr != 0; tptr++) {
355
16.5M
            const op_def *def;
356
357
128M
            for (def = *tptr; def->oname != 0; def++)
358
112M
                if (op_def_is_begin_dict(def)) {
359
4.54M
                    if (make_initial_dict(i_ctx_p, def->oname, idicts) == 0)
360
0
                        return_error(gs_error_VMerror);
361
4.54M
                }
362
16.5M
        }
363
364
        /* Create dictionaries which are stored inside systemdict, but in local VM
365
         * (apart from userdict, which additionally needs to be on the initial
366
         * dictionary stack). This used to be done in PostScript in gs_init.ps, but
367
         * that required the use of .forceput.
368
         * This is all complicated by the intention to potentially build the interpreter
369
         * supporting only lower versions of PostScript. This could all be simplified
370
         * now, since we don't really support that any more.
371
         */
372
1.29M
        for (i = 0; i < countof(initial_referred); i++) {
373
1.13M
            const char *dname = initial_referred[i];
374
1.13M
            ref *r;
375
376
1.13M
            r = make_initial_dict(i_ctx_p, dname, idicts);
377
1.13M
            if (r == NULL)
378
0
                return_error(gs_error_VMerror);
379
1.13M
        }
380
381
        /* Set up the initial dstack. */
382
324k
        for (i = 0; i < countof(initial_dstack); i++) {
383
162k
            const char *dname = initial_dstack[i];
384
162k
            ref *r;
385
386
162k
            ++dsp;
387
162k
            if (!strcmp(dname, "userdict"))
388
162k
                dstack_userdict_index = dsp - dsbot;
389
162k
            r = make_initial_dict(i_ctx_p, dname, idicts);
390
162k
            if (r == NULL)
391
0
                return_error(gs_error_VMerror);
392
162k
            ref_assign(dsp, r);
393
162k
        }
394
395
        /* Enter names of referenced initial dictionaries into systemdict. */
396
162k
        i_initial_enter_name(i_ctx_p, "systemdict", systemdict);
397
2.10M
        for (i = 0; i < icount; i++) {
398
1.94M
            ref *idict = &idicts[i];
399
400
1.94M
            if (!r_has_type(idict, t_null)) {
401
                /*
402
                 * Note that we enter the dictionary in systemdict
403
                 * even if it is in local VM.  There is a special
404
                 * provision in the garbage collector for this:
405
                 * see ivmspace.h for more information.
406
                 * In order to do this, we must temporarily
407
                 * identify systemdict as local, so that the
408
                 * store check in dict_put won't fail.
409
                 */
410
1.78M
                uint save_space = r_space(systemdict);
411
412
1.78M
                r_set_space(systemdict, avm_local);
413
1.78M
                code = i_initial_enter_name(i_ctx_p, initial_dictionaries[i].name,
414
1.78M
                                            idict);
415
1.78M
                r_set_space(systemdict, save_space);
416
1.78M
                if (code < 0)
417
0
                    return code;
418
1.78M
            }
419
1.94M
        }
420
162k
#undef icount
421
162k
    }
422
423
162k
    gs_interp_reset(i_ctx_p);
424
425
162k
    {
426
162k
#ifdef PACIFY_VALGRIND
427
162k
        ref vnull = { 0 }, vtrue = { 0 }, vfalse = { 0 };
428
#else
429
        ref vnull, vtrue, vfalse;
430
#endif
431
432
162k
        make_null(&vnull);
433
162k
        make_true(&vtrue);
434
162k
        make_false(&vfalse);
435
162k
        if ((code = i_initial_enter_name(i_ctx_p, "null", &vnull)) < 0 ||
436
162k
            (code = i_initial_enter_name(i_ctx_p, "true", &vtrue)) < 0 ||
437
162k
            (code = i_initial_enter_name(i_ctx_p, "false", &vfalse)) < 0
438
162k
            )
439
0
            return code;
440
162k
    }
441
442
    /* Create the error name table */
443
162k
    {
444
162k
        int n = countof(gs_error_names);
445
162k
        int i;
446
162k
        ref era;
447
448
162k
        code = ialloc_ref_array(&era, a_readonly, n, "ErrorNames");
449
162k
        if (code < 0)
450
0
            return code;
451
5.35M
        for (i = 0; i < n; i++)
452
5.19M
          if ((code = name_enter_string(imemory, (const char *)gs_error_names[i],
453
5.19M
                                          era.value.refs + i)) < 0)
454
0
                return code;
455
162k
        if ((code = i_initial_enter_name(i_ctx_p, "ErrorNames", &era)) < 0)
456
0
            return code;
457
162k
    }
458
459
162k
    {
460
162k
        ref *r;
461
162k
        if ((code = dict_find_string(systemdict, "LocalFontDirectory", &r)) < 0)
462
0
            return code;
463
162k
        ref_assign(&i_ctx_p->LocalFontDirectory, r);
464
162k
        if ((code = dict_find_string(systemdict, "GlobalFontDirectory", &r)) < 0)
465
0
            return code;
466
162k
        ref_assign(&i_ctx_p->GlobalFontDirectory, r);
467
162k
    }
468
0
    return 0;
469
162k
}
470
471
/* Run the initialization procedures of the individual operator files. */
472
int
473
zop_init(i_ctx_t *i_ctx_p)
474
162k
{
475
162k
    const op_def *const *tptr;
476
162k
    int code;
477
478
    /* Because of a bug in Sun's SC1.0 compiler, */
479
    /* we have to spell out the typedef for op_def_ptr here: */
480
162k
    const op_def *def;
481
482
16.7M
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
483
128M
        for (def = *tptr; def->oname != 0; def++)
484
112M
            DO_NOTHING;
485
16.5M
        if (def->proc != 0) {
486
648k
            code = def->proc(i_ctx_p);
487
648k
            if (code < 0) {
488
#ifdef DEBUG
489
                lprintf2("op_init proc "PRI_INTPTR" returned error %d!\n",
490
                         (intptr_t)def->proc, code);
491
#else
492
0
                lprintf("op_init proc returned error !\n");
493
0
#endif
494
0
                return code;
495
0
            }
496
648k
        }
497
16.5M
    }
498
499
    /* Initialize the predefined names other than operators. */
500
    /* Do this here in case op_init changed any of them. */
501
162k
    {
502
162k
        ref vcr, vpr, vpf, vre, vrd, vres;
503
504
162k
        make_const_string(&vcr, a_readonly | avm_foreign,
505
162k
                          strlen(gs_copyright), (const byte *)gs_copyright);
506
162k
        make_const_string(&vpr, a_readonly | avm_foreign,
507
162k
                          strlen(gs_product), (const byte *)gs_product);
508
162k
        make_const_string(&vpf, a_readonly | avm_foreign,
509
162k
                          strlen(gs_productfamily),
510
162k
                          (const byte *)gs_productfamily);
511
162k
        make_const_string(&vres, a_readonly | avm_foreign,
512
162k
                          strlen(GS_STRINGIZE(GS_DOT_VERSION)),
513
162k
                          (const byte *)GS_STRINGIZE(GS_DOT_VERSION));
514
162k
        make_int(&vre, gs_revision);
515
162k
        make_int(&vrd, gs_revisiondate);
516
162k
        if ((code = i_initial_enter_name(i_ctx_p, "copyright", &vcr)) < 0 ||
517
162k
            (code = i_initial_enter_name(i_ctx_p, "product", &vpr)) < 0 ||
518
162k
            (code = i_initial_enter_name(i_ctx_p, "productfamily", &vpf)) < 0 ||
519
162k
            (code = i_initial_enter_name(i_ctx_p, "revision", &vre)) < 0 ||
520
162k
            (code = i_initial_enter_name(i_ctx_p, "revisiondate", &vrd)) < 0 ||
521
162k
            (code = i_initial_enter_name(i_ctx_p, ".revisionstring", &vres)) < 0)
522
0
            return code;
523
162k
    }
524
525
162k
    return 0;
526
162k
}
527
528
/* Create an op_array table. */
529
static int
530
alloc_op_array_table(i_ctx_t *i_ctx_p, uint size, uint space,
531
                     op_array_table *opt)
532
324k
{
533
324k
    uint save_space = ialloc_space(idmemory);
534
324k
    int code;
535
536
324k
    ialloc_set_space(idmemory, space);
537
324k
    code = ialloc_ref_array(&opt->table, a_readonly, size,
538
324k
                            "op_array table");
539
324k
    ialloc_set_space(idmemory, save_space);
540
324k
    if (code < 0)
541
0
        return code;
542
324k
    refset_null(opt->table.value.refs, size);
543
324k
    opt->nx_table =
544
324k
        (ushort *) ialloc_byte_array(size, sizeof(ushort),
545
324k
                                     "op_array nx_table");
546
324k
    if (opt->nx_table == 0)
547
0
        return_error(gs_error_VMerror);
548
324k
    opt->count = 0;
549
324k
    opt->attrs = space | a_executable;
550
324k
    return 0;
551
324k
}
552
553
/* Initialize the operator table. */
554
int
555
op_init(i_ctx_t *i_ctx_p)
556
162k
{
557
162k
    const op_def *const *tptr;
558
162k
    int code;
559
560
    /* Enter each operator into the appropriate dictionary. */
561
562
16.7M
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
563
16.5M
        ref *pdict = systemdict;
564
16.5M
        const op_def *def;
565
16.5M
        const char *nstr;
566
567
128M
        for (def = *tptr; (nstr = def->oname) != 0; def++)
568
112M
            if (op_def_is_begin_dict(def)) {
569
4.54M
                ref nref;
570
571
4.54M
                code = name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1);
572
4.54M
                if (code < 0)
573
0
                    return code;
574
4.54M
                if (!dict_find(systemdict, &nref, &pdict))
575
0
                    return_error(gs_error_Fatal);
576
4.54M
                if (!r_has_type(pdict, t_dictionary))
577
0
                    return_error(gs_error_Fatal);
578
107M
            } else {
579
107M
                ref oper;
580
107M
                uint index_in_table = def - *tptr;
581
107M
                uint opidx = (tptr - op_defs_all) * OP_DEFS_MAX_SIZE +
582
107M
                    index_in_table;
583
584
107M
                if (index_in_table >= OP_DEFS_MAX_SIZE) {
585
0
                    lprintf1("opdef overrun! %s\n", def->oname);
586
0
                    return_error(gs_error_Fatal);
587
0
                }
588
107M
                gs_interp_make_oper(&oper, def->proc, opidx);
589
                /* The first character of the name is a digit */
590
                /* giving the minimum acceptable number of operands. */
591
                /* Check to make sure it's within bounds. */
592
107M
                if (*nstr - '0' > gs_interp_max_op_num_args)
593
0
                    return_error(gs_error_Fatal);
594
107M
                nstr++;
595
                /*
596
                 * Skip internal operators, and the second occurrence of
597
                 * operators with special indices.
598
                 */
599
107M
                if (*nstr != '%' && r_size(&oper) == opidx) {
600
94.4M
                    code =
601
94.4M
                        i_initial_enter_name_in(i_ctx_p, pdict, nstr, &oper);
602
94.4M
                    if (code < 0)
603
0
                        return code;
604
94.4M
                }
605
107M
            }
606
16.5M
    }
607
    /* Allocate the tables for `operator' procedures. */
608
    /* Make one of them local so we can have local operators. */
609
162k
    if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_GLOBAL_SIZE,
610
162k
                                     avm_global,
611
162k
                                     &i_ctx_p->op_array_table_global) < 0))
612
0
        return code;
613
162k
    i_ctx_p->op_array_table_global.base_index = op_def_count;
614
162k
    if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_LOCAL_SIZE,
615
162k
                                     avm_local,
616
162k
                                     &i_ctx_p->op_array_table_local) < 0))
617
0
        return code;
618
162k
    i_ctx_p->op_array_table_local.base_index =
619
162k
        i_ctx_p->op_array_table_global.base_index +
620
162k
        r_size(&i_ctx_p->op_array_table_global.table);
621
622
162k
    return 0;
623
162k
}
624
625
#if defined(DEBUG_TRACE_PS_OPERATORS) || defined(DEBUG)
626
static const char *unknown_op_name = "unknown_op";
627
628
const char *
629
op_get_name_string(op_proc_t opproc)
630
{
631
    const op_def *const *tptr;
632
633
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
634
        const op_def *def;
635
636
        for (def = *tptr; def->oname != 0; def++)
637
            if (!op_def_is_begin_dict(def)) {
638
                if (def->proc == opproc)
639
                    return def->oname;
640
            }
641
    }
642
    return unknown_op_name;
643
}
644
#endif
645
646
int
647
i_iodev_init(gs_dual_memory_t *dmem)
648
162k
{
649
162k
    int i;
650
162k
    int code;
651
162k
    gs_memory_t *mem = (gs_memory_t *)dmem->current;
652
653
162k
    code = gs_iodev_init(mem);
654
655
1.29M
    for (i = 0; i < i_io_device_table_count && code >= 0; i++) {
656
1.13M
        code = gs_iodev_register_dev(mem, i_io_device_table[i]);
657
1.13M
    }
658
659
162k
    return code;
660
162k
}
661
662
void
663
i_iodev_finit(gs_dual_memory_t *dmem)
664
162k
{
665
162k
    gs_iodev_finit((gs_memory_t *)dmem->current);
666
162k
}