Coverage Report

Created: 2026-08-08 08:00

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