Coverage Report

Created: 2026-09-14 07:34

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
147k
#  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
294k
#  define OP_ARRAY_TABLE_SIZE 300
100
#endif
101
#ifndef OP_ARRAY_TABLE_GLOBAL_SIZE
102
147k
#  define OP_ARRAY_TABLE_GLOBAL_SIZE OP_ARRAY_TABLE_SIZE
103
#endif
104
#ifndef OP_ARRAY_TABLE_LOCAL_SIZE
105
147k
#  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
89.5M
{
121
89.5M
    int code = idict_put_string(pdict, nstr, pref);
122
123
89.5M
    if (code < 0)
124
0
        lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
125
89.5M
                 code, nstr, dict_length(pdict), dict_maxlength(pdict));
126
89.5M
    return code;
127
89.5M
}
128
int
129
i_initial_enter_name(i_ctx_t *i_ctx_p, const char *nstr, const ref * pref)
130
3.97M
{
131
3.97M
    return i_initial_enter_name_in(i_ctx_p, systemdict, nstr, pref);
132
3.97M
}
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.15M
{
139
2.15M
    int code = idict_put_string_copy(pdict, nstr, pref);
140
141
2.15M
    if (code < 0)
142
0
        lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
143
2.15M
                 code, nstr, dict_length(pdict), dict_maxlength(pdict));
144
2.15M
    return code;
145
2.15M
}
146
int
147
i_initial_enter_name_copy(i_ctx_t *i_ctx_p, const char *nstr, const ref * pref)
148
2.15M
{
149
2.15M
    return i_initial_enter_name_copy_in(i_ctx_p, systemdict, nstr, pref);
150
2.15M
}
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
        "FontDirectory", FONTDIRECTORY_SIZE, true
193
    },
194
    {
195
        "statusdict", STATUSDICT_SIZE, true
196
    },
197
    {
198
        "serverdict", SERVERDICT_SIZE, true
199
    },
200
    {
201
        "filterdict", FILTERDICT_SIZE, false
202
    },
203
    {
204
        "localinstancedict", LOCALINSTANCEDICT_SIZE, true
205
    },
206
#endif
207
};
208
const char *const initial_referred[] =
209
{
210
#ifdef INITIAL_REFERRED
211
    INITIAL_REFERRED
212
#else
213
    "$error",
214
    "errordict",
215
    "FontDirectory",
216
    "statusdict",
217
    "serverdict",
218
    "localinstancedict",
219
#endif
220
};
221
/* systemdict and globaldict are magically inserted at the bottom */
222
const char *const initial_dstack[] =
223
{
224
#ifdef INITIAL_DSTACK
225
    INITIAL_DSTACK
226
#else
227
    "userdict"
228
#endif
229
};
230
231
147k
#define MIN_DSTACK_SIZE (countof(initial_dstack) + 1)   /* +1 for systemdict */
232
233
/*
234
 * Detect whether we have any Level 2 or LanguageLevel 3 operators.
235
 * We export this for gs_init1 in imain.c.
236
 * This is slow, but we only call it a couple of times.
237
 */
238
static int
239
gs_op_language_level(void)
240
294k
{
241
294k
    const op_def *const *tptr;
242
294k
    int level = 1;
243
244
30.3M
    for (tptr = op_defs_all; *tptr != 0; ++tptr) {
245
30.0M
        const op_def *def;
246
247
232M
        for (def = *tptr; def->oname != 0; ++def)
248
202M
            if (op_def_is_begin_dict(def)) {
249
8.24M
                if (!strcmp(def->oname, "level2dict"))
250
4.41M
                    level = max(level, 2);
251
3.82M
                else if (!strcmp(def->oname, "ll3dict"))
252
1.17M
                    level = max(level, 3);
253
8.24M
            }
254
30.0M
    }
255
294k
    return level;
256
294k
}
257
bool
258
gs_have_level2(void)
259
147k
{
260
147k
    return (gs_op_language_level() >= 2);
261
147k
}
262
263
/* Create an initial dictionary if necessary. */
264
static ref *
265
make_initial_dict(i_ctx_t *i_ctx_p, const char *iname, ref idicts[])
266
5.15M
{
267
5.15M
    int i;
268
269
    /* systemdict was created specially. */
270
5.15M
    if (!strcmp(iname, "systemdict"))
271
147k
        return systemdict;
272
22.5M
    for (i = 0; i < countof(initial_dictionaries); i++) {
273
22.5M
        const char *dname = initial_dictionaries[i].name;
274
22.5M
        const int dsize = initial_dictionaries[i].size;
275
276
22.5M
        if (!strcmp(iname, dname)) {
277
5.00M
            ref *dref = &idicts[i];
278
279
5.00M
            if (r_has_type(dref, t_null)) {
280
1.47M
                gs_ref_memory_t *mem =
281
1.47M
                    (initial_dictionaries[i].local ?
282
1.03M
                     iimemory_local : iimemory_global);
283
1.47M
                int code = dict_alloc(mem, dsize, dref);
284
285
1.47M
                if (code < 0)
286
0
                    return 0;   /* disaster */
287
1.47M
            }
288
5.00M
            return dref;
289
5.00M
        }
290
22.5M
    }
291
292
    /*
293
     * Name mentioned in some op_def, but not in initial_dictionaries.
294
     * Punt.
295
     */
296
0
    return 0;
297
5.00M
}
298
299
/* Initialize objects other than operators.  In particular, */
300
/* initialize the dictionaries that hold operator definitions. */
301
int
302
obj_init(i_ctx_t **pi_ctx_p, gs_dual_memory_t *idmem)
303
147k
{
304
147k
    int level = gs_op_language_level();
305
147k
    ref system_dict;
306
147k
    i_ctx_t *i_ctx_p;
307
147k
    int code;
308
309
    /*
310
     * Create systemdict.  The context machinery requires that
311
     * we do this before initializing the interpreter.
312
     */
313
147k
    code = dict_alloc(idmem->space_global,
314
147k
                      (level >= 3 ? SYSTEMDICT_LL3_SIZE :
315
147k
                       level >= 2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE),
316
147k
                      &system_dict);
317
147k
    if (code < 0)
318
0
        return code;
319
320
    /* Initialize the interpreter. */
321
147k
    code = gs_interp_init(pi_ctx_p, &system_dict, idmem);
322
147k
    if (code < 0)
323
0
        return code;
324
147k
    i_ctx_p = *pi_ctx_p;
325
326
147k
    {
327
1.76M
#define icount countof(initial_dictionaries)
328
147k
        ref idicts[icount];
329
147k
        int i;
330
147k
        const op_def *const *tptr;
331
332
147k
        min_dstack_size = MIN_DSTACK_SIZE;
333
334
147k
        refset_null(idicts, icount);
335
336
        /* Put systemdict on the dictionary stack. */
337
147k
        if (level >= 2) {
338
147k
            dsp += 2;
339
            /*
340
             * For the moment, let globaldict be an alias for systemdict.
341
             */
342
147k
            dsp[-1] = system_dict;
343
147k
            min_dstack_size++;
344
147k
        } else {
345
0
            ++dsp;
346
0
        }
347
147k
        *dsp = system_dict;
348
349
        /* Create dictionaries which are to be homes for operators. */
350
15.1M
        for (tptr = op_defs_all; *tptr != 0; tptr++) {
351
15.0M
            const op_def *def;
352
353
116M
            for (def = *tptr; def->oname != 0; def++)
354
101M
                if (op_def_is_begin_dict(def)) {
355
4.12M
                    if (make_initial_dict(i_ctx_p, def->oname, idicts) == 0)
356
0
                        return_error(gs_error_VMerror);
357
4.12M
                }
358
15.0M
        }
359
360
        /* Create dictionaries which are stored inside systemdict, but in local VM
361
         * (apart from userdict, which additionally needs to be on the initial
362
         * dictionary stack). This used to be done in PostScript in gs_init.ps, but
363
         * that required the use of .forceput.
364
         * This is all complicated by the intention to potentially build the interpreter
365
         * supporting only lower versions of PostScript. This could all be simplified
366
         * now, since we don't really support that any more.
367
         */
368
1.03M
        for (i = 0; i < countof(initial_referred); i++) {
369
883k
            const char *dname = initial_referred[i];
370
883k
            ref *r;
371
372
883k
            r = make_initial_dict(i_ctx_p, dname, idicts);
373
883k
            if (r == NULL)
374
0
                return_error(gs_error_VMerror);
375
883k
        }
376
377
        /* Set up the initial dstack. */
378
294k
        for (i = 0; i < countof(initial_dstack); i++) {
379
147k
            const char *dname = initial_dstack[i];
380
147k
            ref *r;
381
382
147k
            ++dsp;
383
147k
            if (!strcmp(dname, "userdict"))
384
147k
                dstack_userdict_index = dsp - dsbot;
385
147k
            r = make_initial_dict(i_ctx_p, dname, idicts);
386
147k
            if (r == NULL)
387
0
                return_error(gs_error_VMerror);
388
147k
            ref_assign(dsp, r);
389
147k
        }
390
391
        /* Enter names of referenced initial dictionaries into systemdict. */
392
147k
        i_initial_enter_name(i_ctx_p, "systemdict", systemdict);
393
1.76M
        for (i = 0; i < icount; i++) {
394
1.62M
            ref *idict = &idicts[i];
395
396
1.62M
            if (!r_has_type(idict, t_null)) {
397
                /*
398
                 * Note that we enter the dictionary in systemdict
399
                 * even if it is in local VM.  There is a special
400
                 * provision in the garbage collector for this:
401
                 * see ivmspace.h for more information.
402
                 * In order to do this, we must temporarily
403
                 * identify systemdict as local, so that the
404
                 * store check in dict_put won't fail.
405
                 */
406
1.47M
                uint save_space = r_space(systemdict);
407
408
1.47M
                r_set_space(systemdict, avm_local);
409
1.47M
                code = i_initial_enter_name(i_ctx_p, initial_dictionaries[i].name,
410
1.47M
                                            idict);
411
1.47M
                r_set_space(systemdict, save_space);
412
1.47M
                if (code < 0)
413
0
                    return code;
414
1.47M
            }
415
1.62M
        }
416
147k
#undef icount
417
147k
    }
418
419
147k
    gs_interp_reset(i_ctx_p);
420
421
147k
    {
422
147k
#ifdef PACIFY_VALGRIND
423
147k
        ref vnull = { 0 }, vtrue = { 0 }, vfalse = { 0 };
424
#else
425
        ref vnull, vtrue, vfalse;
426
#endif
427
428
147k
        make_null(&vnull);
429
147k
        make_true(&vtrue);
430
147k
        make_false(&vfalse);
431
147k
        if ((code = i_initial_enter_name(i_ctx_p, "null", &vnull)) < 0 ||
432
147k
            (code = i_initial_enter_name(i_ctx_p, "true", &vtrue)) < 0 ||
433
147k
            (code = i_initial_enter_name(i_ctx_p, "false", &vfalse)) < 0
434
147k
            )
435
0
            return code;
436
147k
    }
437
438
    /* Create the error name table */
439
147k
    {
440
147k
        int n = countof(gs_error_names);
441
147k
        int i;
442
147k
        ref era;
443
444
147k
        code = ialloc_ref_array(&era, a_readonly, n, "ErrorNames");
445
147k
        if (code < 0)
446
0
            return code;
447
4.86M
        for (i = 0; i < n; i++)
448
4.71M
          if ((code = name_enter_string(imemory, (const char *)gs_error_names[i],
449
4.71M
                                          era.value.refs + i)) < 0)
450
0
                return code;
451
147k
        return i_initial_enter_name(i_ctx_p, "ErrorNames", &era);
452
147k
    }
453
147k
}
454
455
/* Run the initialization procedures of the individual operator files. */
456
int
457
zop_init(i_ctx_t *i_ctx_p)
458
147k
{
459
147k
    const op_def *const *tptr;
460
147k
    int code;
461
462
    /* Because of a bug in Sun's SC1.0 compiler, */
463
    /* we have to spell out the typedef for op_def_ptr here: */
464
147k
    const op_def *def;
465
466
15.1M
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
467
116M
        for (def = *tptr; def->oname != 0; def++)
468
101M
            DO_NOTHING;
469
15.0M
        if (def->proc != 0) {
470
589k
            code = def->proc(i_ctx_p);
471
589k
            if (code < 0) {
472
#ifdef DEBUG
473
                lprintf2("op_init proc "PRI_INTPTR" returned error %d!\n",
474
                         (intptr_t)def->proc, code);
475
#else
476
0
                lprintf("op_init proc returned error !\n");
477
0
#endif
478
0
                return code;
479
0
            }
480
589k
        }
481
15.0M
    }
482
483
    /* Initialize the predefined names other than operators. */
484
    /* Do this here in case op_init changed any of them. */
485
147k
    {
486
147k
        ref vcr, vpr, vpf, vre, vrd, vres;
487
488
147k
        make_const_string(&vcr, a_readonly | avm_foreign,
489
147k
                          strlen(gs_copyright), (const byte *)gs_copyright);
490
147k
        make_const_string(&vpr, a_readonly | avm_foreign,
491
147k
                          strlen(gs_product), (const byte *)gs_product);
492
147k
        make_const_string(&vpf, a_readonly | avm_foreign,
493
147k
                          strlen(gs_productfamily),
494
147k
                          (const byte *)gs_productfamily);
495
147k
        make_const_string(&vres, a_readonly | avm_foreign,
496
147k
                          strlen(GS_STRINGIZE(GS_DOT_VERSION)),
497
147k
                          (const byte *)GS_STRINGIZE(GS_DOT_VERSION));
498
147k
        make_int(&vre, gs_revision);
499
147k
        make_int(&vrd, gs_revisiondate);
500
147k
        if ((code = i_initial_enter_name(i_ctx_p, "copyright", &vcr)) < 0 ||
501
147k
            (code = i_initial_enter_name(i_ctx_p, "product", &vpr)) < 0 ||
502
147k
            (code = i_initial_enter_name(i_ctx_p, "productfamily", &vpf)) < 0 ||
503
147k
            (code = i_initial_enter_name(i_ctx_p, "revision", &vre)) < 0 ||
504
147k
            (code = i_initial_enter_name(i_ctx_p, "revisiondate", &vrd)) < 0 ||
505
147k
            (code = i_initial_enter_name(i_ctx_p, ".revisionstring", &vres)) < 0)
506
0
            return code;
507
147k
    }
508
509
147k
    return 0;
510
147k
}
511
512
/* Create an op_array table. */
513
static int
514
alloc_op_array_table(i_ctx_t *i_ctx_p, uint size, uint space,
515
                     op_array_table *opt)
516
294k
{
517
294k
    uint save_space = ialloc_space(idmemory);
518
294k
    int code;
519
520
294k
    ialloc_set_space(idmemory, space);
521
294k
    code = ialloc_ref_array(&opt->table, a_readonly, size,
522
294k
                            "op_array table");
523
294k
    ialloc_set_space(idmemory, save_space);
524
294k
    if (code < 0)
525
0
        return code;
526
294k
    refset_null(opt->table.value.refs, size);
527
294k
    opt->nx_table =
528
294k
        (ushort *) ialloc_byte_array(size, sizeof(ushort),
529
294k
                                     "op_array nx_table");
530
294k
    if (opt->nx_table == 0)
531
0
        return_error(gs_error_VMerror);
532
294k
    opt->count = 0;
533
294k
    opt->attrs = space | a_executable;
534
294k
    return 0;
535
294k
}
536
537
/* Initialize the operator table. */
538
int
539
op_init(i_ctx_t *i_ctx_p)
540
147k
{
541
147k
    const op_def *const *tptr;
542
147k
    int code;
543
544
    /* Enter each operator into the appropriate dictionary. */
545
546
15.1M
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
547
15.0M
        ref *pdict = systemdict;
548
15.0M
        const op_def *def;
549
15.0M
        const char *nstr;
550
551
116M
        for (def = *tptr; (nstr = def->oname) != 0; def++)
552
101M
            if (op_def_is_begin_dict(def)) {
553
4.12M
                ref nref;
554
555
4.12M
                code = name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1);
556
4.12M
                if (code < 0)
557
0
                    return code;
558
4.12M
                if (!dict_find(systemdict, &nref, &pdict))
559
0
                    return_error(gs_error_Fatal);
560
4.12M
                if (!r_has_type(pdict, t_dictionary))
561
0
                    return_error(gs_error_Fatal);
562
97.2M
            } else {
563
97.2M
                ref oper;
564
97.2M
                uint index_in_table = def - *tptr;
565
97.2M
                uint opidx = (tptr - op_defs_all) * OP_DEFS_MAX_SIZE +
566
97.2M
                    index_in_table;
567
568
97.2M
                if (index_in_table >= OP_DEFS_MAX_SIZE) {
569
0
                    lprintf1("opdef overrun! %s\n", def->oname);
570
0
                    return_error(gs_error_Fatal);
571
0
                }
572
97.2M
                gs_interp_make_oper(&oper, def->proc, opidx);
573
                /* The first character of the name is a digit */
574
                /* giving the minimum acceptable number of operands. */
575
                /* Check to make sure it's within bounds. */
576
97.2M
                if (*nstr - '0' > gs_interp_max_op_num_args)
577
0
                    return_error(gs_error_Fatal);
578
97.2M
                nstr++;
579
                /*
580
                 * Skip internal operators, and the second occurrence of
581
                 * operators with special indices.
582
                 */
583
97.2M
                if (*nstr != '%' && r_size(&oper) == opidx) {
584
85.5M
                    code =
585
85.5M
                        i_initial_enter_name_in(i_ctx_p, pdict, nstr, &oper);
586
85.5M
                    if (code < 0)
587
0
                        return code;
588
85.5M
                }
589
97.2M
            }
590
15.0M
    }
591
    /* Allocate the tables for `operator' procedures. */
592
    /* Make one of them local so we can have local operators. */
593
147k
    if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_GLOBAL_SIZE,
594
147k
                                     avm_global,
595
147k
                                     &i_ctx_p->op_array_table_global) < 0))
596
0
        return code;
597
147k
    i_ctx_p->op_array_table_global.base_index = op_def_count;
598
147k
    if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_LOCAL_SIZE,
599
147k
                                     avm_local,
600
147k
                                     &i_ctx_p->op_array_table_local) < 0))
601
0
        return code;
602
147k
    i_ctx_p->op_array_table_local.base_index =
603
147k
        i_ctx_p->op_array_table_global.base_index +
604
147k
        r_size(&i_ctx_p->op_array_table_global.table);
605
606
147k
    return 0;
607
147k
}
608
609
#if defined(DEBUG_TRACE_PS_OPERATORS) || defined(DEBUG)
610
static const char *unknown_op_name = "unknown_op";
611
612
const char *
613
op_get_name_string(op_proc_t opproc)
614
{
615
    const op_def *const *tptr;
616
617
    for (tptr = op_defs_all; *tptr != 0; tptr++) {
618
        const op_def *def;
619
620
        for (def = *tptr; def->oname != 0; def++)
621
            if (!op_def_is_begin_dict(def)) {
622
                if (def->proc == opproc)
623
                    return def->oname;
624
            }
625
    }
626
    return unknown_op_name;
627
}
628
#endif
629
630
int
631
i_iodev_init(gs_dual_memory_t *dmem)
632
147k
{
633
147k
    int i;
634
147k
    int code;
635
147k
    gs_memory_t *mem = (gs_memory_t *)dmem->current;
636
637
147k
    code = gs_iodev_init(mem);
638
639
1.17M
    for (i = 0; i < i_io_device_table_count && code >= 0; i++) {
640
1.03M
        code = gs_iodev_register_dev(mem, i_io_device_table[i]);
641
1.03M
    }
642
643
147k
    return code;
644
147k
}
645
646
void
647
i_iodev_finit(gs_dual_memory_t *dmem)
648
147k
{
649
147k
    gs_iodev_finit((gs_memory_t *)dmem->current);
650
147k
}