Coverage Report

Created: 2025-06-10 06:58

/src/ghostpdl/psi/imain.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* Common support for interpreter front ends */
18
19
20
#include "malloc_.h"
21
#include "memory_.h"
22
#include "string_.h"
23
#include "ghost.h"
24
#include "gp.h"
25
#include "gscdefs.h"            /* for gs_init_file */
26
#include "gslib.h"
27
#include "gsmatrix.h"           /* for gxdevice.h */
28
#include "gsutil.h"             /* for bytes_compare */
29
#include "gspaint.h"    /* for gs_erasepage */
30
#include "gxdevice.h"
31
#include "gxdevsop.h"   /* for gxdso_* enums */
32
#include "gxclpage.h"
33
#include "gdevprn.h"
34
#include "gxalloc.h"
35
#include "gxiodev.h"            /* for iodev struct */
36
#include "gzstate.h"
37
#include "ierrors.h"
38
#include "oper.h"
39
#include "iconf.h"              /* for gs_init_* imports */
40
#include "idebug.h"
41
#include "iddict.h"
42
#include "iname.h"              /* for name_init */
43
#include "dstack.h"
44
#include "estack.h"
45
#include "ostack.h"             /* put here for files.h */
46
#include "stream.h"             /* for files.h */
47
#include "files.h"
48
#include "ialloc.h"
49
#include "iinit.h"
50
#include "strimpl.h"            /* for sfilter.h */
51
#include "sfilter.h"            /* for iscan.h */
52
#include "iscan.h"
53
#include "main.h"
54
#include "store.h"
55
#include "isave.h"              /* for prototypes */
56
#include "interp.h"
57
#include "ivmspace.h"
58
#include "idisp.h"              /* for setting display device callback */
59
#include "iplugin.h"
60
#include "zfile.h"
61
62
#include "valgrind.h"
63
64
/* ------ Exported data ------ */
65
66
/** using backpointers retrieve minst from any memory pointer
67
 *
68
 */
69
gs_main_instance*
70
get_minst_from_memory(const gs_memory_t *mem)
71
81.5M
{
72
81.5M
    return (gs_main_instance*)mem->gs_lib_ctx->top_of_system;
73
81.5M
}
74
75
/** construct main instance caller needs to retain */
76
gs_main_instance *
77
gs_main_alloc_instance(gs_memory_t *mem)
78
10.3k
{
79
10.3k
    gs_main_instance *minst;
80
10.3k
    if (mem == NULL)
81
0
        return NULL;
82
83
10.3k
    minst = (gs_main_instance *)gs_alloc_bytes_immovable(mem,
84
10.3k
                                                         sizeof(gs_main_instance),
85
10.3k
                                                         "init_main_instance");
86
10.3k
    if (minst == NULL)
87
0
        return NULL;
88
10.3k
    memset(minst, 0, sizeof(gs_main_instance));
89
10.3k
    memcpy(minst, &gs_main_instance_init_values, sizeof(gs_main_instance_init_values));
90
10.3k
    minst->heap = mem;
91
10.3k
    mem->gs_lib_ctx->top_of_system = minst;
92
10.3k
    return minst;
93
10.3k
}
94
95
op_array_table *
96
get_op_array(const gs_memory_t *mem, int size)
97
16.1M
{
98
16.1M
    gs_main_instance *minst = get_minst_from_memory(mem);
99
16.1M
    return op_index_op_array_table(minst->i_ctx_p,size);
100
16.1M
}
101
102
op_array_table *
103
get_global_op_array(const gs_memory_t *mem)
104
20.6k
{
105
20.6k
    gs_main_instance *minst = get_minst_from_memory(mem);
106
20.6k
    return &minst->i_ctx_p->op_array_table_global;
107
20.6k
}
108
109
op_array_table *
110
get_local_op_array(const gs_memory_t *mem)
111
20.6k
{
112
20.6k
    gs_main_instance *minst = get_minst_from_memory(mem);
113
20.6k
    return &minst->i_ctx_p->op_array_table_local;
114
20.6k
}
115
116
/* ------ Forward references ------ */
117
118
static int gs_run_init_file(gs_main_instance *, int *, ref *);
119
void print_resource_usage(const gs_main_instance *,
120
                                  gs_dual_memory_t *, const char *);
121
122
/* ------ Initialization ------ */
123
124
/* Initialization to be done before anything else. */
125
int
126
gs_main_init0(gs_main_instance * minst, gp_file * in, gp_file * out, gp_file * err,
127
              int max_lib_paths)
128
10.3k
{
129
10.3k
    ref *array;
130
10.3k
    int code = 0;
131
132
10.3k
    if (gs_debug_c(gs_debug_flag_init_details))
133
10.3k
        dmprintf1(minst->heap, "%% Init phase 0 started, instance "PRI_INTPTR"\n",
134
10.3k
                  (intptr_t)minst);
135
136
    /* Do platform-dependent initialization. */
137
    /* We have to do this as the very first thing, */
138
    /* because it detects attempts to run 80N86 executables (N>0) */
139
    /* on incompatible processors. */
140
10.3k
    gp_init();
141
142
    /* Initialize the imager. */
143
144
    /* Reset debugging flags */
145
10.3k
#ifdef PACIFY_VALGRIND
146
10.3k
    VALGRIND_HG_DISABLE_CHECKING(gs_debug, 128);
147
10.3k
#endif
148
10.3k
    memset(gs_debug, 0, 128);
149
10.3k
    gs_log_errors = 0;  /* gs_debug['#'] = 0 */
150
151
10.3k
    gp_get_realtime(minst->base_time);
152
153
    /* Initialize the file search paths. */
154
10.3k
    array = (ref *) gs_alloc_byte_array(minst->heap, max_lib_paths, sizeof(ref),
155
10.3k
                                        "lib_path array");
156
10.3k
    if (array == 0) {
157
0
        gs_lib_finit(1, gs_error_VMerror, minst->heap);
158
0
        code = gs_note_error(gs_error_VMerror);
159
0
        goto fail;
160
0
    }
161
10.3k
    make_array(&minst->lib_path.container, avm_foreign, max_lib_paths,
162
10.3k
               array);
163
10.3k
    make_array(&minst->lib_path.list, avm_foreign | a_readonly, 0,
164
10.3k
               minst->lib_path.container.value.refs);
165
10.3k
    minst->lib_path.env = NULL;
166
10.3k
    minst->lib_path.final = NULL;
167
10.3k
    minst->lib_path.count = 0;
168
10.3k
    minst->lib_path.first_is_current = 0;
169
10.3k
    minst->user_errors = 1;
170
10.3k
    minst->init_done = 0;
171
172
10.3k
fail:
173
10.3k
    if (gs_debug_c(gs_debug_flag_init_details))
174
10.3k
        dmprintf2(minst->heap, "%% Init phase 0 %s, instance "PRI_INTPTR"\n",
175
10.3k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
176
177
10.3k
    return code;
178
10.3k
}
179
180
/* Initialization to be done before constructing any objects. */
181
int
182
gs_main_init1(gs_main_instance * minst)
183
182k
{
184
182k
    gs_dual_memory_t idmem;
185
182k
    name_table *nt = NULL;
186
182k
    int code;
187
188
182k
    if (minst->init_done >= 1)
189
172k
        return 0;
190
191
10.3k
    if (gs_debug_c(gs_debug_flag_init_details))
192
10.3k
        dmprintf1(minst->heap, "%% Init phase 1 started, instance "PRI_INTPTR"\n",
193
10.3k
                  (intptr_t)minst);
194
195
10.3k
    code = ialloc_init(&idmem, minst->heap,
196
10.3k
                       minst->memory_clump_size, gs_have_level2());
197
198
10.3k
    if (code < 0)
199
0
        goto fail_early;
200
201
10.3k
    code = gs_lib_init1((gs_memory_t *)idmem.space_system);
202
10.3k
    if (code < 0)
203
0
        goto fail;
204
10.3k
    alloc_save_init(&idmem);
205
10.3k
    {
206
10.3k
        gs_memory_t *mem = (gs_memory_t *)idmem.space_system;
207
10.3k
        nt = names_init(minst->name_table_size, idmem.space_system);
208
209
10.3k
        if (nt == 0) {
210
0
            code = gs_note_error(gs_error_VMerror);
211
0
            goto fail;
212
0
        }
213
10.3k
        mem->gs_lib_ctx->gs_name_table = nt;
214
10.3k
        code = gs_register_struct_root(mem, &mem->gs_lib_ctx->name_table_root,
215
10.3k
                                       (void **)&mem->gs_lib_ctx->gs_name_table,
216
10.3k
                                       "the_gs_name_table");
217
10.3k
        if (code < 0)
218
0
            goto fail;
219
10.3k
        mem->gs_lib_ctx->client_check_file_permission = z_check_file_permissions;
220
10.3k
    }
221
0
    code = obj_init(&minst->i_ctx_p, &idmem);  /* requires name_init */
222
10.3k
    if (code < 0)
223
0
        goto fail;
224
10.3k
    minst->init_done = 1;
225
10.3k
    code = i_plugin_init(minst->i_ctx_p);
226
10.3k
    if (code < 0)
227
0
        goto fail;
228
10.3k
    code = i_iodev_init(&idmem);
229
10.3k
    if (code < 0) {
230
0
fail:
231
0
        names_free(nt);
232
0
        if (minst->i_ctx_p == NULL)
233
0
            ialloc_finit(&idmem);
234
0
    }
235
10.3k
fail_early:
236
237
10.3k
    if (gs_debug_c(gs_debug_flag_init_details))
238
10.3k
        dmprintf2(minst->heap, "%% Init phase 1 %s, instance "PRI_INTPTR"\n",
239
10.3k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
240
241
10.3k
    return code;
242
10.3k
}
243
244
/*
245
 * Invoke the interpreter. This layer doesn't do much (previously stdio
246
 * callouts were handled here instead of in the stream processing.
247
 */
248
static int
249
gs_main_interpret(gs_main_instance *minst, ref * pref, int user_errors,
250
                  int *pexit_code, ref * perror_object)
251
185k
{
252
185k
    int code;
253
254
    /* set interpreter pointer to lib_path */
255
185k
    minst->i_ctx_p->lib_path = &minst->lib_path;
256
257
185k
    code = gs_interpret(&minst->i_ctx_p, pref,
258
185k
                        user_errors, pexit_code, perror_object);
259
185k
    return code;
260
185k
}
261
262
/* gcc wants prototypes for all external functions. */
263
int gs_main_init2aux(gs_main_instance * minst);
264
265
static const op_array_table empty_table = { { { 0 } } };
266
267
/* This is an external function to work around      */
268
/* a bug in gcc 4.5.1 optimizer. See bug 692684.    */
269
10.3k
int gs_main_init2aux(gs_main_instance * minst) {
270
10.3k
    i_ctx_t * i_ctx_p = minst->i_ctx_p;
271
272
10.3k
    if (minst->init_done < 2) {
273
10.3k
        int code, exit_code;
274
10.3k
        ref error_object, ifa;
275
276
        /* Set up enough so that we can safely be garbage collected */
277
10.3k
        i_ctx_p->op_array_table_global = empty_table;
278
10.3k
        i_ctx_p->op_array_table_local = empty_table;
279
280
10.3k
        code = zop_init(i_ctx_p);
281
10.3k
        if (code < 0)
282
0
            return code;
283
10.3k
        code = op_init(i_ctx_p);        /* requires obj_init */
284
10.3k
        if (code < 0)
285
0
            return code;
286
287
        /* Set up the array of additional initialization files. */
288
10.3k
        make_const_string(&ifa, a_readonly | avm_foreign, gs_init_files_sizeof - 2, gs_init_files);
289
10.3k
        code = i_initial_enter_name(i_ctx_p, "INITFILES", &ifa);
290
10.3k
        if (code < 0)
291
0
            return code;
292
293
        /* Set up the array of emulator names. */
294
10.3k
        make_const_string(&ifa, a_readonly | avm_foreign, gs_emulators_sizeof - 2, gs_emulators);
295
10.3k
        code = i_initial_enter_name(i_ctx_p, "EMULATORS", &ifa);
296
10.3k
        if (code < 0)
297
0
            return code;
298
299
        /* Pass the search path. */
300
10.3k
        code = i_initial_enter_name(i_ctx_p, "LIBPATH", &minst->lib_path.list);
301
10.3k
        if (code < 0)
302
0
            return code;
303
304
        /* Execute the standard initialization file. */
305
10.3k
        code = gs_run_init_file(minst, &exit_code, &error_object);
306
10.3k
        if (code < 0)
307
0
            return code;
308
10.3k
        minst->init_done = 2;
309
310
        /* NB this is to be done with device parameters
311
         * both minst->display and  display_set_callback() are going away
312
        */
313
10.3k
        if ((code = reopen_device_if_required(minst)) < 0)
314
0
            return code;
315
316
10.3k
        if ((code = gs_main_run_string(minst,
317
10.3k
                "JOBSERVER "
318
10.3k
                " { false 0 .startnewjob } "
319
10.3k
                " { NOOUTERSAVE not { save pop } if } "
320
10.3k
                "ifelse", 0, &exit_code,
321
10.3k
                &error_object)) < 0)
322
0
           return code;
323
10.3k
    }
324
10.3k
    return 0;
325
10.3k
}
326
327
int
328
gs_main_set_language_param(gs_main_instance *minst,
329
                           gs_param_list    *plist)
330
0
{
331
0
    ref value;
332
0
    int code = 0;
333
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
334
0
    uint space = icurrent_space;
335
0
    gs_param_enumerator_t enumerator;
336
0
    gs_param_key_t key;
337
0
    gs_lib_ctx_t *ctx = minst->heap->gs_lib_ctx;
338
0
    ref error_object;
339
340
    /* If we're up and running as a jobserver, exit encapsulation. */
341
0
    if (minst->init_done > 1) {
342
0
        code = gs_main_run_string(minst,
343
0
                                  "JOBSERVER {true 0 startjob pop} if",
344
0
                                  0, &code, &error_object);
345
0
        if (code < 0) return code;
346
0
    }
347
348
0
    ialloc_set_space(idmemory, avm_system);
349
350
0
    param_init_enumerator(&enumerator);
351
0
    while ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
352
0
        char string_key[256]; /* big enough for any reasonable key */
353
0
        gs_param_typed_value pvalue;
354
355
0
        if (key.size > sizeof(string_key) - 1) {
356
0
            code = gs_note_error(gs_error_rangecheck);
357
0
            break;
358
0
        }
359
0
        memcpy(string_key, key.data, key.size);
360
0
        string_key[key.size] = 0;
361
0
        if ((code = param_read_typed(plist, string_key, &pvalue)) != 0) {
362
0
            code = (code > 0 ? gs_note_error(gs_error_unknownerror) : code);
363
0
            break;
364
0
        }
365
0
        switch (pvalue.type) {
366
0
        case gs_param_type_null:
367
0
            make_null(&value);
368
0
            break;
369
0
        case gs_param_type_bool:
370
0
            if (pvalue.value.b)
371
0
                make_true(&value);
372
0
            else
373
0
                make_false(&value);
374
0
            break;
375
0
        case gs_param_type_int:
376
0
            make_int(&value, (ps_int)pvalue.value.i);
377
0
            break;
378
0
        case gs_param_type_i64:
379
0
            make_int(&value, (ps_int)pvalue.value.i64);
380
0
            break;
381
0
        case gs_param_type_long:
382
0
            make_int(&value, (ps_int)pvalue.value.l);
383
0
            break;
384
0
        case gs_param_type_size_t:
385
0
            make_int(&value, (ps_int)pvalue.value.z);
386
0
            break;
387
0
        case gs_param_type_float:
388
0
            make_real(&value, pvalue.value.f);
389
0
            break;
390
0
        case gs_param_type_dict:
391
            /* We don't support dicts for now */
392
0
            continue;
393
0
        case gs_param_type_dict_int_keys:
394
            /* We don't support dicts with int keys for now */
395
0
            continue;
396
0
        case gs_param_type_array:
397
            /* We don't support arrays for now */
398
0
            continue;
399
0
        case gs_param_type_string:
400
0
            if (pvalue.value.s.data == NULL || pvalue.value.s.size == 0)
401
0
                make_empty_string(&value, a_readonly);
402
0
            else {
403
0
                size_t len = pvalue.value.s.size;
404
0
                byte *body = ialloc_string(len, "-s");
405
406
0
                if (body == NULL)
407
0
                    return gs_error_Fatal;
408
0
                memcpy(body, pvalue.value.s.data, len);
409
0
                make_const_string(&value, a_readonly | avm_system, len, body);
410
0
            }
411
0
            break;
412
0
        case gs_param_type_name:
413
0
            code = name_ref(ctx->memory, pvalue.value.n.data, pvalue.value.n.size, &value, 1);
414
0
            break;
415
0
        case gs_param_type_int_array:
416
            /* We don't support arrays for now */
417
0
            continue;
418
0
        case gs_param_type_float_array:
419
            /* We don't support arrays for now */
420
0
            continue;
421
0
        case gs_param_type_string_array:
422
            /* We don't support arrays for now */
423
0
            continue;
424
0
        default:
425
0
            continue;
426
0
        }
427
0
        if (code < 0)
428
0
            break;
429
430
0
        ialloc_set_space(idmemory, space);
431
        /* Enter the name in systemdict. */
432
0
        i_initial_enter_name_copy(minst->i_ctx_p, string_key, &value);
433
0
    }
434
435
0
    if (minst->init_done > 1) {
436
0
        int code2 = 0;
437
0
        code2 = gs_main_run_string(minst,
438
0
                                   "JOBSERVER {false 0 startjob pop} if",
439
0
                                   0, &code2, &error_object);
440
0
        if (code >= 0)
441
0
            code = code2;
442
0
    }
443
444
0
    return code;
445
0
}
446
447
static int
448
gs_main_push_params(gs_main_instance *minst)
449
17.8k
{
450
17.8k
    int code;
451
17.8k
    gs_c_param_list *plist;
452
453
17.8k
    plist = minst->param_list;
454
17.8k
    if (!plist)
455
17.8k
        return 0;
456
457
0
    code = gs_putdeviceparams(minst->i_ctx_p->pgs->device,
458
0
                              (gs_param_list *)plist);
459
0
    if (code < 0)
460
0
        return code;
461
462
0
    code = gs_main_set_language_param(minst, (gs_param_list *)plist);
463
0
    if (code < 0)
464
0
        return code;
465
466
0
    gs_c_param_list_release(plist);
467
468
0
    return code;
469
0
}
470
471
int
472
gs_main_init2(gs_main_instance * minst)
473
17.8k
{
474
17.8k
    i_ctx_t *i_ctx_p;
475
17.8k
    int code = gs_main_init1(minst);
476
477
17.8k
    if (code < 0)
478
0
        return code;
479
480
17.8k
    code = gs_main_push_params(minst);
481
17.8k
    if (code < 0)
482
0
        return code;
483
484
17.8k
    if (minst->init_done >= 2)
485
7.55k
        return 0;
486
487
10.3k
    if (gs_debug_c(gs_debug_flag_init_details))
488
10.3k
        dmprintf1(minst->heap, "%% Init phase 2 started, instance "PRI_INTPTR"\n",
489
10.3k
                  (intptr_t)minst);
490
491
10.3k
    code = gs_main_init2aux(minst);
492
10.3k
    if (code < 0)
493
0
       goto fail;
494
495
10.3k
    i_ctx_p = minst->i_ctx_p; /* reopen_device_if_display or run_string may change it */
496
497
    /* Now process the initial saved-pages=... argument, if any as well as saved-pages-test */
498
10.3k
    {
499
10.3k
       gx_device *pdev = gs_currentdevice(minst->i_ctx_p->pgs); /* get the current device */
500
10.3k
       gx_device_printer *ppdev = (gx_device_printer *)pdev;
501
502
10.3k
        if (minst->saved_pages_test_mode) {
503
0
            if ((dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_saved_pages, NULL, 0) <= 0)) {
504
                /* no warning or error if saved-pages-test mode is used, just disable it */
505
0
                minst->saved_pages_test_mode = false;  /* device doesn't support it */
506
0
            } else {
507
0
                if ((code = gx_saved_pages_param_process(ppdev, (byte *)"begin", 5)) < 0)
508
0
                    goto fail;
509
0
                if (code > 0)
510
0
                    if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
511
0
                        goto fail;
512
0
            }
513
10.3k
        } else if (minst->saved_pages_initial_arg != NULL) {
514
0
            if (dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_saved_pages, NULL, 0) <= 0) {
515
0
                while (pdev->child)
516
0
                    pdev = pdev->child;   /* so we get the real device name */
517
0
                outprintf(minst->heap,
518
0
                          "   --saved-pages not supported by the '%s' device.\n",
519
0
                          pdev->dname);
520
0
                code = gs_error_Fatal;
521
0
                goto fail;
522
0
            }
523
0
            code = gx_saved_pages_param_process(ppdev, (byte *)minst->saved_pages_initial_arg,
524
0
                                                strlen(minst->saved_pages_initial_arg));
525
0
            if (code > 0)
526
0
                if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
527
0
                    goto fail;
528
0
        }
529
10.3k
    }
530
531
10.3k
    if (code >= 0) {
532
10.3k
        if (gs_debug_c(':'))
533
0
            print_resource_usage(minst, i_ctx_p ? &gs_imemory : NULL, "Start");
534
10.3k
        gp_readline_init(&minst->readline_data, minst->heap); /* lgtm [cpp/useless-expression] */
535
10.3k
    }
536
537
10.3k
fail:
538
10.3k
    if (gs_debug_c(gs_debug_flag_init_details))
539
10.3k
        dmprintf2(minst->heap, "%% Init phase 2 %s, instance "PRI_INTPTR"\n",
540
10.3k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
541
542
10.3k
    return code;
543
10.3k
}
544
545
/* ------ Search paths ------ */
546
547
#define LIB_PATH_EXTEND 5
548
549
/* If the existing array is full, extend it */
550
static int
551
extend_path_list_container (gs_main_instance * minst, gs_file_path * pfp)
552
0
{
553
0
    uint len = r_size(&minst->lib_path.container);
554
0
    ref *paths, *opaths = minst->lib_path.container.value.refs;
555
556
    /* Add 5 entries at a time to reduce VM thrashing */
557
0
    paths = (ref *) gs_alloc_byte_array(minst->heap, len + LIB_PATH_EXTEND, sizeof(ref),
558
0
                                        "extend_path_list_container array");
559
560
0
    if (paths == 0) {
561
0
        return_error(gs_error_VMerror);
562
0
    }
563
0
    make_array(&minst->lib_path.container, avm_foreign, len + LIB_PATH_EXTEND, paths);
564
0
    make_array(&minst->lib_path.list, avm_foreign | a_readonly, 0,
565
0
               minst->lib_path.container.value.refs);
566
567
0
    memcpy(paths, opaths, len * sizeof(ref));
568
0
    r_set_size(&minst->lib_path.list, len);
569
570
0
    gs_free_object (minst->heap, opaths, "extend_path_list_container");
571
0
    return(0);
572
0
}
573
574
static int
575
lib_path_insert_copy_of_string(gs_main_instance *minst, int pos, size_t strlen, const char *str)
576
1.20M
{
577
1.20M
    ref *paths;
578
1.20M
    int listlen = r_size(&minst->lib_path.list); /* The real number of entries currently in the list */
579
1.20M
    byte *newstr;
580
1.20M
    int code;
581
582
    /* Extend the container if required */
583
1.20M
    if (listlen == r_size(&minst->lib_path.container)) {
584
0
        code = extend_path_list_container(minst, &minst->lib_path);
585
0
        if (code < 0) {
586
0
            emprintf(minst->heap, "\nAdding path to search paths failed.\n");
587
0
            return(code);
588
0
        }
589
0
    }
590
591
    /* Copy the string */
592
1.20M
    newstr = gs_alloc_string(minst->heap, strlen, "lib_path_add");
593
1.20M
    if (newstr == NULL)
594
0
        return gs_error_VMerror;
595
1.20M
    memcpy(newstr, str, strlen);
596
597
    /* Shuffle up the entries */
598
1.20M
    paths = &minst->lib_path.container.value.refs[pos];
599
1.20M
    if (pos != listlen)
600
0
        memmove(paths + 1, paths, (listlen-pos) * sizeof(*paths));
601
602
    /* And insert the new string, converted to a PS thing */
603
1.20M
    make_const_string(paths, avm_foreign | a_readonly,
604
1.20M
                      strlen,
605
1.20M
                      newstr);
606
607
    /* Update the list length */
608
1.20M
    r_set_size(&minst->lib_path.list, listlen+1);
609
610
1.20M
    return 0;
611
1.20M
}
612
613
/* Internal routine to add a set of directories to a search list. */
614
/* Returns 0 or an error code. */
615
616
static int
617
lib_path_add(gs_main_instance * minst, const char *dirs)
618
278k
{
619
278k
    gs_file_path * pfp = &minst->lib_path;
620
278k
    uint len = r_size(&pfp->list);
621
278k
    const char *dpath = dirs;
622
278k
    int code;
623
624
278k
    if (dirs == 0)
625
0
        return 0;
626
627
1.20M
    for (;;) {                  /* Find the end of the next directory name. */
628
1.20M
        const char *npath = dpath;
629
630
41.3M
        while (*npath != 0 && *npath != gp_file_name_list_separator)
631
40.1M
            npath++;
632
1.20M
        if (npath > dpath) {
633
1.20M
            code = gs_add_control_path_len(minst->heap, gs_permit_file_reading, dpath, npath - dpath);
634
1.20M
            if (code < 0) return code;
635
636
1.20M
            code = lib_path_insert_copy_of_string(minst, len, npath - dpath, dpath);
637
1.20M
            if (code < 0)
638
0
                return code;
639
1.20M
            len++;
640
            /* Update length/count so we don't lose entries if a later
641
             * iteration fails. */
642
1.20M
            r_set_size(&pfp->list, len);
643
1.20M
        }
644
1.20M
        if (!*npath)
645
278k
            break;
646
927k
        dpath = npath + 1;
647
927k
    }
648
278k
    return 0;
649
278k
}
650
651
static void
652
set_lib_path_length(gs_main_instance * minst, int newsize)
653
103k
{
654
103k
    gs_file_path * pfp = &minst->lib_path;
655
103k
    uint len = r_size(&pfp->list); /* Yes, list, not container */
656
103k
    uint i;
657
658
    /* Free any entries that are discarded by us shortening the list */
659
1.30M
    for (i = newsize; i < len; i++)
660
1.20M
        gs_free_object(minst->heap, pfp->container.value.refs[i].value.bytes, "lib_path entry");
661
103k
    r_set_size(&pfp->list, newsize);
662
103k
}
663
664
/* Add a library search path to the list. */
665
int
666
gs_main_add_lib_path(gs_main_instance * minst, const char *lpath)
667
0
{
668
0
    gs_file_path * pfp = &minst->lib_path;
669
0
    int code;
670
671
    /* Throw away all the elements after the user ones. */
672
0
    set_lib_path_length(minst, pfp->count + pfp->first_is_current);
673
674
    /* Now add the new one */
675
0
    code = lib_path_add(minst, lpath);
676
0
    if (code < 0)
677
0
        return code;
678
679
    /* Update the count of user paths */
680
0
    pfp->count = r_size(&pfp->list) - pfp->first_is_current;
681
682
    /* Now add back in the others */
683
0
    return gs_main_set_lib_paths(minst);
684
0
}
685
686
/* ------ Execution ------ */
687
688
extern_gx_io_device_table();
689
690
/* Complete the list of library search paths. */
691
/* This may involve adding the %rom%Resource/Init and %rom%lib/ paths (for COMPILE_INITS) */
692
/* and adding or removing the current directory as the first element (for -P and -P-). */
693
int
694
gs_main_set_lib_paths(gs_main_instance * minst)
695
92.7k
{
696
92.7k
    int code = 0;
697
92.7k
    int i, have_rom_device = 0;
698
699
    /* We are entered with a list potentially full of stuff already.
700
     * In general the list is of the form:
701
     *    <optionally, the current directory>
702
     *    <any -I specified directories, "count" of them>
703
     *    <any directories from the environment variable>
704
     *    <if there is a romfs, the romfs paths>
705
     *    <any directories from the 'final' variable>
706
     *
707
     * Unfortunately, the value read from the environment variable may not
708
     * have actually been read the first time this function is called, so
709
     * we can see the value change over time. Short of a complete rewrite
710
     * this requires us to clear the latter part of the list and repopulate
711
     * it each time we run through.
712
     */
713
714
    /* First step, ensure that we have the current directory as our
715
     * first entry, iff we need it. */
716
92.7k
    if (minst->search_here_first && !minst->lib_path.first_is_current) {
717
        /* We should have a "gp_current_directory" at the start, and we haven't.
718
         * So insert one. */
719
720
0
        code = gs_add_control_path_len(minst->heap, gs_permit_file_reading,
721
0
                gp_current_directory_name, strlen(gp_current_directory_name));
722
0
        if (code < 0) return code;
723
724
0
        code = lib_path_insert_copy_of_string(minst, 0,
725
0
                                              strlen(gp_current_directory_name),
726
0
                                              gp_current_directory_name);
727
0
        if (code < 0)
728
0
            return code;
729
92.7k
    } else if (!minst->search_here_first && minst->lib_path.first_is_current) {
730
        /* We have a "gp_current_directory" at the start, and we shouldn't have.
731
         * Remove it. */
732
0
        int listlen = r_size(&minst->lib_path.list); /* The real number of entries currently in the list */
733
0
        ref *paths = minst->lib_path.container.value.refs;
734
735
0
        gs_free_object(minst->heap, paths->value.bytes, "lib_path entry");
736
0
        --listlen;
737
0
        memmove(paths, paths + 1, listlen * sizeof(*paths));
738
0
        r_set_size(&minst->lib_path.list, listlen);
739
740
0
        code = gs_remove_control_path_len(minst->heap, gs_permit_file_reading,
741
0
                gp_current_directory_name, strlen(gp_current_directory_name));
742
0
        if (code < 0) return code;
743
0
    }
744
92.7k
    minst->lib_path.first_is_current = minst->search_here_first;
745
746
    /* Now, the horrid bit. We throw away all the entries after the user entries */
747
92.7k
    set_lib_path_length(minst, minst->lib_path.count + minst->lib_path.first_is_current);
748
749
    /* Now we (re)populate the end of the list. */
750
92.7k
    if (minst->lib_path.env != 0) {
751
0
        code = lib_path_add(minst, minst->lib_path.env);
752
0
        if (code < 0) return code;
753
754
0
        code = gs_add_control_path(minst->heap, gs_permit_file_reading, minst->lib_path.env);
755
0
        if (code < 0) return code;
756
0
    }
757
    /* now put the %rom%lib/ device path before the gs_lib_default_path on the list */
758
649k
    for (i = 0; i < gx_io_device_table_count; i++) {
759
649k
        const gx_io_device *iodev = gx_io_device_table[i];
760
649k
        const char *dname = iodev->dname;
761
649k
        const char *fcheckname = "Resource/Init/gs_init.ps";
762
763
649k
        if (dname && strlen(dname) == 5 && !memcmp("%rom%", dname, 5)) {
764
92.7k
            struct stat pstat;
765
            /* gs_error_unregistered means no usable romfs is available */
766
            /* gpdl always includes a real romfs, but it may or may have the Postscript
767
               resources in it, so we explicitly check for a fairly vital file
768
             */
769
92.7k
            int code = iodev->procs.file_status((gx_io_device *)iodev, fcheckname, &pstat);
770
92.7k
            if (code != gs_error_unregistered && code != gs_error_undefinedfilename){
771
92.7k
                have_rom_device = 1;
772
92.7k
            }
773
92.7k
            break;
774
92.7k
        }
775
649k
    }
776
92.7k
    if (have_rom_device) {
777
92.7k
        code = lib_path_add(minst, "%rom%Resource/Init/");
778
92.7k
        if (code < 0)
779
0
            return code;
780
92.7k
        code = lib_path_add(minst, "%rom%lib/");
781
92.7k
    }
782
0
    else code = 0;
783
784
92.7k
    if (minst->lib_path.final != NULL && code >= 0)
785
92.7k
        code = lib_path_add(minst, minst->lib_path.final);
786
92.7k
    return code;
787
92.7k
}
788
789
/* Open a file, using the search paths. */
790
int
791
gs_main_lib_open(gs_main_instance * minst, const char *file_name, ref * pfile)
792
10.3k
{
793
    /* This is a separate procedure only to avoid tying up */
794
    /* extra stack space while running the file. */
795
10.3k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
796
10.3k
#define maxfn 2048
797
10.3k
    char fn[maxfn];
798
10.3k
    uint len;
799
800
10.3k
    return lib_file_open(&minst->lib_path, imemory,
801
10.3k
                         NULL, /* Don't check permissions here, because permlist
802
                                  isn't ready running init files. */
803
10.3k
                          file_name, strlen(file_name), fn, maxfn, &len, pfile);
804
10.3k
}
805
806
/* Open and execute a file. */
807
int
808
gs_main_run_file(gs_main_instance * minst, const char *file_name, int user_errors, int *pexit_code, ref * perror_object)
809
0
{
810
0
    ref initial_file;
811
0
    int code = gs_main_run_file_open(minst, file_name, &initial_file);
812
813
0
    if (code < 0)
814
0
        return code;
815
0
    return gs_main_interpret(minst, &initial_file, user_errors,
816
0
                        pexit_code, perror_object);
817
0
}
818
int
819
gs_main_run_file_open(gs_main_instance * minst, const char *file_name, ref * pfref)
820
10.3k
{
821
10.3k
    gs_main_set_lib_paths(minst);
822
10.3k
    if (gs_main_lib_open(minst, file_name, pfref) < 0) {
823
0
        emprintf1(minst->heap,
824
0
                  "Can't find initialization file %s.\n",
825
0
                  file_name);
826
0
        return_error(gs_error_Fatal);
827
0
    }
828
10.3k
    r_set_attrs(pfref, a_execute + a_executable);
829
10.3k
    return 0;
830
10.3k
}
831
832
/* Open and run the very first initialization file. */
833
static int
834
gs_run_init_file(gs_main_instance * minst, int *pexit_code, ref * perror_object)
835
10.3k
{
836
10.3k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
837
10.3k
    ref ifile;
838
10.3k
    ref first_token;
839
10.3k
    int code;
840
10.3k
    scanner_state state;
841
842
10.3k
    gs_main_set_lib_paths(minst);
843
10.3k
    code = gs_main_run_file_open(minst, gs_init_file, &ifile);
844
10.3k
    if (code < 0) {
845
0
        *pexit_code = 255;
846
0
        return code;
847
0
    }
848
    /* Check to make sure the first token is an integer */
849
    /* (for the version number check.) */
850
10.3k
    gs_scanner_init(&state, &ifile);
851
10.3k
    code = gs_scan_token(i_ctx_p, &first_token, &state);
852
10.3k
    if (code != 0 || !r_has_type(&first_token, t_integer)) {
853
0
        emprintf1(minst->heap,
854
0
                  "Initialization file %s does not begin with an integer.\n",
855
0
                  gs_init_file);
856
0
        *pexit_code = 255;
857
0
        return_error(gs_error_Fatal);
858
0
    }
859
10.3k
    *++osp = first_token;
860
10.3k
    r_set_attrs(&ifile, a_executable);
861
10.3k
    return gs_main_interpret(minst, &ifile, minst->user_errors,
862
10.3k
                        pexit_code, perror_object);
863
10.3k
}
864
865
/* Run a string. */
866
int
867
gs_main_run_string(gs_main_instance * minst, const char *str, int user_errors,
868
                   int *pexit_code, ref * perror_object)
869
61.8k
{
870
61.8k
    return gs_main_run_string_with_length(minst, str, (uint) strlen(str),
871
61.8k
                                          user_errors,
872
61.8k
                                          pexit_code, perror_object);
873
61.8k
}
874
int
875
gs_main_run_string_with_length(gs_main_instance * minst, const char *str,
876
         uint length, int user_errors, int *pexit_code, ref * perror_object)
877
61.8k
{
878
61.8k
    int code;
879
880
61.8k
    code = gs_main_run_string_begin(minst, user_errors,
881
61.8k
                                    pexit_code, perror_object);
882
61.8k
    if (code < 0)
883
0
        return code;
884
61.8k
    code = gs_main_run_string_continue(minst, str, length, user_errors,
885
61.8k
                                       pexit_code, perror_object);
886
61.8k
    if (code != gs_error_NeedInput)
887
10.3k
        return code;
888
889
51.5k
    code = gs_main_run_string_end(minst, user_errors,
890
51.5k
                                  pexit_code, perror_object);
891
    /* Not okay for user to use .needinput
892
     * This treats it as a fatal error.
893
     */
894
51.5k
    if (code == gs_error_NeedInput)
895
0
        return_error(gs_error_Fatal);
896
51.5k
    return code;
897
51.5k
}
898
899
/* Set up for a suspendable run_string. */
900
int
901
gs_main_run_string_begin(gs_main_instance * minst, int user_errors,
902
                         int *pexit_code, ref * perror_object)
903
61.8k
{
904
61.8k
    const char *setup = ".runstringbegin";
905
61.8k
    ref rstr;
906
61.8k
    int code;
907
908
61.8k
    gs_main_set_lib_paths(minst);
909
61.8k
    make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
910
61.8k
                      strlen(setup), (const byte *)setup);
911
61.8k
    code = gs_main_interpret(minst, &rstr, user_errors, pexit_code,
912
61.8k
                             perror_object);
913
61.8k
    return (code == gs_error_NeedInput ? 0 : code == 0 ? gs_error_Fatal : code);
914
61.8k
}
915
/* Continue running a string with the option of suspending. */
916
int
917
gs_main_run_string_continue(gs_main_instance * minst, const char *str,
918
         uint length, int user_errors, int *pexit_code, ref * perror_object)
919
61.8k
{
920
61.8k
    ref rstr;
921
922
61.8k
    if (length == 0)
923
0
        return 0;               /* empty string signals EOF */
924
61.8k
    make_const_string(&rstr, avm_foreign | a_readonly, length,
925
61.8k
                      (const byte *)str);
926
61.8k
    return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
927
61.8k
                             perror_object);
928
61.8k
}
929
uint
930
gs_main_get_uel_offset(gs_main_instance * minst)
931
0
{
932
0
    if (minst->i_ctx_p == NULL)
933
0
        return 0;
934
0
    return (uint)minst->i_ctx_p->uel_position;
935
0
}
936
937
/* Signal EOF when suspended. */
938
int
939
gs_main_run_string_end(gs_main_instance * minst, int user_errors,
940
                       int *pexit_code, ref * perror_object)
941
51.5k
{
942
51.5k
    ref rstr;
943
944
51.5k
    make_empty_const_string(&rstr, avm_foreign | a_readonly);
945
51.5k
    return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
946
51.5k
                             perror_object);
947
51.5k
}
948
949
gs_memory_t *
950
gs_main_get_device_memory(gs_main_instance * minst)
951
0
{
952
0
  gs_memory_t *dev_mem = NULL;
953
0
  if (minst && minst->init_done >= 1) {
954
0
      i_ctx_t * i_ctx_p = minst->i_ctx_p;
955
0
      dev_mem = imemory_global->stable_memory;
956
0
  }
957
0
  return dev_mem;
958
0
}
959
960
int
961
gs_main_set_device(gs_main_instance * minst, gx_device *pdev)
962
0
{
963
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
964
0
    ref error_object;
965
0
    int code;
966
967
0
    if (pdev == NULL) {
968
        /* Leave job encapsulation, restore the graphics state gsaved below (so back to the nullpage device)
969
           and re-enter job encapsulation.
970
           We rely on the end of job encapsulation restore to the put the gstate stack back how it was when
971
           we entered job encapsulation below, so the grestore will pickup the correct gstate.
972
         */
973
0
        code = gs_main_run_string(minst,
974
0
                                 "true 0 startjob pop grestore false 0 startjob pop",
975
0
                                 0, &code, &error_object);
976
0
        if (code < 0) goto done;
977
0
    }
978
0
    else {
979
        /* Leave job encapsulation, and save the graphics state (including the device: nullpage)
980
           Store the page size in a dictionary, which we'll use to configure the incoming device */
981
0
        code = gs_main_run_string(minst,
982
0
                                  "true 0 startjob pop gsave "
983
                                  /* /PageSize /GetDeviceParam .special_op will either return:
984
                                   * /PageSize [ <width> <height> ] true   (if it exists) or
985
                                   * false                                 (if it does not) */
986
0
                                  "<< /PageSize /GetDeviceParam .special_op "
987
                                  /* If we wanted to force a default pagesize, we'd do:
988
                                   * "not { /PageSize [595 842] } if "
989
                                   * but for now we'll just leave the default as it is, and do: */
990
0
                                  "pop "
991
0
                                  ">> "
992
0
                                  , 0, &code, &error_object);
993
0
        if (code < 0) goto done;
994
        /* First call goes to the C directly to actually set the device. This
995
         * avoids the SAFER checks. */
996
0
        code = zsetdevice_no_safer(i_ctx_p, pdev);
997
0
        if (code < 0) goto done;
998
0
        code = zcurrentdevice(i_ctx_p);
999
0
        if (code < 0) goto done;
1000
0
        code = gs_main_run_string(minst,
1001
                                  /* Set the device again to the same one. This determines
1002
                                   * whether to erase page or not, but passes the safer
1003
                                   * checks as the device is unchanged. */
1004
0
                                  "setdevice "
1005
0
                                  "setpagedevice "
1006
                                  /* GS specifics: Force the cached copy of the params to be updated. */
1007
0
                                  "currentpagedevice pop "
1008
                                  /* Setup the halftone */
1009
0
                                  ".setdefaultscreen "
1010
                                  /* Re-run the scheduled initialisation procs, in case we've just set pdfwrite */
1011
0
                                  "1183615869 internaldict /.execute_scheduled_inits get exec "
1012
                                  /* Re-enter job encapsulation */
1013
0
                                  "false 0 startjob pop "
1014
0
                                  , 0, &code, &error_object);
1015
0
        if (code < 0) goto done;
1016
0
    }
1017
0
done:
1018
0
    return code;
1019
0
}
1020
1021
/* ------ Operand stack access ------ */
1022
1023
/* These are built for comfort, not for speed. */
1024
1025
static int
1026
push_value(gs_main_instance *minst, ref * pvalue)
1027
0
{
1028
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1029
0
    int code = ref_stack_push(&o_stack, 1);
1030
0
    ref *o = ref_stack_index(&o_stack, 0L);
1031
1032
0
    if (o == NULL)
1033
0
        return_error(gs_error_stackoverflow);
1034
1035
0
    if (code < 0)
1036
0
        return code;
1037
0
    *o = *pvalue;
1038
0
    return 0;
1039
0
}
1040
1041
int
1042
gs_push_boolean(gs_main_instance * minst, bool value)
1043
0
{
1044
0
    ref vref;
1045
1046
0
    make_bool(&vref, value);
1047
0
    return push_value(minst, &vref);
1048
0
}
1049
1050
int
1051
gs_push_integer(gs_main_instance * minst, long value)
1052
0
{
1053
0
    ref vref;
1054
1055
0
    make_int(&vref, value);
1056
0
    return push_value(minst, &vref);
1057
0
}
1058
1059
int
1060
gs_push_real(gs_main_instance * minst, double value)
1061
0
{
1062
0
    ref vref;
1063
1064
0
    make_real(&vref, value);
1065
0
    return push_value(minst, &vref);
1066
0
}
1067
1068
int
1069
gs_push_string(gs_main_instance * minst, byte * chars, uint length,
1070
               bool read_only)
1071
0
{
1072
0
    ref vref;
1073
1074
0
    make_string(&vref, avm_foreign | (read_only ? a_readonly : a_all),
1075
0
                length, (byte *) chars);
1076
0
    return push_value(minst, &vref);
1077
0
}
1078
1079
static int
1080
pop_value(i_ctx_t *i_ctx_p, ref * pvalue)
1081
0
{
1082
0
    if (!ref_stack_count(&o_stack))
1083
0
        return_error(gs_error_stackunderflow);
1084
0
    *pvalue = *ref_stack_index(&o_stack, 0L);
1085
0
    return 0;
1086
0
}
1087
1088
int
1089
gs_pop_boolean(gs_main_instance * minst, bool * result)
1090
0
{
1091
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1092
0
    ref vref;
1093
0
    int code = pop_value(i_ctx_p, &vref);
1094
1095
0
    if (code < 0)
1096
0
        return code;
1097
0
    check_type_only(vref, t_boolean);
1098
0
    *result = vref.value.boolval;
1099
0
    ref_stack_pop(&o_stack, 1);
1100
0
    return 0;
1101
0
}
1102
1103
int
1104
gs_pop_integer(gs_main_instance * minst, long *result)
1105
0
{
1106
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1107
0
    ref vref;
1108
0
    int code = pop_value(i_ctx_p, &vref);
1109
1110
0
    if (code < 0)
1111
0
        return code;
1112
0
    check_type_only(vref, t_integer);
1113
0
    *result = vref.value.intval;
1114
0
    ref_stack_pop(&o_stack, 1);
1115
0
    return 0;
1116
0
}
1117
1118
int
1119
gs_pop_real(gs_main_instance * minst, float *result)
1120
0
{
1121
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1122
0
    ref vref;
1123
0
    int code = pop_value(i_ctx_p, &vref);
1124
1125
0
    if (code < 0)
1126
0
        return code;
1127
0
    switch (r_type(&vref)) {
1128
0
        case t_real:
1129
0
            *result = vref.value.realval;
1130
0
            break;
1131
0
        case t_integer:
1132
0
            *result = (float)(vref.value.intval);
1133
0
            break;
1134
0
        default:
1135
0
            return_error(gs_error_typecheck);
1136
0
    }
1137
0
    ref_stack_pop(&o_stack, 1);
1138
0
    return 0;
1139
0
}
1140
1141
int
1142
gs_pop_string(gs_main_instance * minst, gs_string * result)
1143
0
{
1144
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1145
0
    ref vref;
1146
0
    int code = pop_value(i_ctx_p, &vref);
1147
1148
0
    if (code < 0)
1149
0
        return code;
1150
0
    switch (r_type(&vref)) {
1151
0
        case t_name:
1152
0
            name_string_ref(minst->heap, &vref, &vref);
1153
0
            code = 1;
1154
0
            goto rstr;
1155
0
        case t_string:
1156
0
            code = (r_has_attr(&vref, a_write) ? 0 : 1);
1157
0
          rstr:result->data = vref.value.bytes;
1158
0
            result->size = r_size(&vref);
1159
0
            break;
1160
0
        default:
1161
0
            return_error(gs_error_typecheck);
1162
0
    }
1163
0
    ref_stack_pop(&o_stack, 1);
1164
0
    return code;
1165
0
}
1166
1167
/* ------ Termination ------ */
1168
1169
/* Get the names of temporary files.
1170
 * Each name is null terminated, and the last name is
1171
 * terminated by a double null.
1172
 * We retrieve the names of temporary files just before
1173
 * the interpreter finishes, and then delete the files
1174
 * after the interpreter has closed all files.
1175
 */
1176
static char *gs_main_tempnames(gs_main_instance *minst)
1177
10.3k
{
1178
10.3k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1179
10.3k
    ref *SAFETY;
1180
10.3k
    ref *tempfiles;
1181
10.3k
    ref keyval[2];      /* for key and value */
1182
10.3k
    char *tempnames = NULL;
1183
10.3k
    int i;
1184
10.3k
    int idict;
1185
10.3k
    int len = 0;
1186
10.3k
    const byte *data = NULL;
1187
10.3k
    uint size;
1188
10.3k
    if (minst->init_done >= 2) {
1189
10.3k
        if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
1190
10.3k
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0)
1191
0
            return NULL;
1192
        /* get lengths of temporary filenames */
1193
10.3k
        idict = dict_first(tempfiles);
1194
16.4k
        while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
1195
6.13k
            if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0)
1196
6.13k
                len += size + 1;
1197
6.13k
        }
1198
10.3k
        if (len != 0)
1199
6.13k
            tempnames = (char *)malloc(len+1);
1200
10.3k
        if (tempnames) {
1201
6.13k
            memset(tempnames, 0, len+1);
1202
            /* copy temporary filenames */
1203
6.13k
            idict = dict_first(tempfiles);
1204
6.13k
            i = 0;
1205
12.2k
            while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
1206
6.13k
                if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0) {
1207
6.13k
                    memcpy(tempnames+i, (const char *)data, size);
1208
6.13k
                    i+= size;
1209
6.13k
                    tempnames[i++] = '\0';
1210
6.13k
                }
1211
6.13k
            }
1212
6.13k
        }
1213
10.3k
    }
1214
10.3k
    return tempnames;
1215
10.3k
}
1216
1217
static void
1218
gs_finit_push_systemdict(i_ctx_t *i_ctx_p)
1219
10.3k
{
1220
10.3k
    if (i_ctx_p == NULL)
1221
0
        return;
1222
10.3k
    if (dsp == dstop ) {
1223
0
        if (ref_stack_extend(&d_stack, 1) < 0) {
1224
            /* zend() cannot fail */
1225
0
            (void)zend(i_ctx_p);
1226
0
        }
1227
0
    }
1228
10.3k
    dsp++;
1229
10.3k
    ref_assign(dsp, systemdict);
1230
10.3k
}
1231
1232
/* Free all resources and return. */
1233
int
1234
gs_main_finit(gs_main_instance * minst, int exit_status, int env_code)
1235
10.3k
{
1236
10.3k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1237
10.3k
    gs_dual_memory_t dmem = {0};
1238
10.3k
    int exit_code;
1239
10.3k
    ref error_object;
1240
10.3k
    char *tempnames = NULL;
1241
10.3k
    gs_lib_ctx_core_t *core;
1242
1243
    /* NB: need to free gs_name_table
1244
     */
1245
1246
    /*
1247
     * Previous versions of this code closed the devices in the
1248
     * device list here.  Since these devices are now prototypes,
1249
     * they cannot be opened, so they do not need to be closed;
1250
     * alloc_restore_all will close dynamically allocated devices.
1251
     */
1252
10.3k
    tempnames = gs_main_tempnames(minst);
1253
1254
    /* by the time we get here, we *must* avoid any random redefinitions of
1255
     * operators etc, so we push systemdict onto the top of the dict stack.
1256
     * We do this in C to avoid running into any other re-defininitions in the
1257
     * Postscript world.
1258
     */
1259
10.3k
    gs_finit_push_systemdict(i_ctx_p);
1260
1261
    /* We have to disable BGPrint before we call interp_reclaim() to prevent the
1262
     * parent rendering thread initialising for the next page, whilst we are
1263
     * removing objects it may want to access - for example, the I/O device table.
1264
     * We also have to mess with the BeginPage/EndPage procs so that we don't
1265
     * trigger a spurious extra page to be emitted.
1266
     */
1267
10.3k
    if (minst->init_done >= 2) {
1268
10.3k
        gs_main_run_string(minst,
1269
10.3k
            "/BGPrint /GetDeviceParam .special_op \
1270
10.3k
            {{ <</BeginPage {pop} /EndPage {pop pop //false } \
1271
10.3k
              /BGPrint false /NumRenderingThreads 0>> setpagedevice} if} if \
1272
10.3k
              serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse \
1273
10.3k
              .systemvar exec",
1274
10.3k
            0 , &exit_code, &error_object);
1275
10.3k
    }
1276
1277
    /*
1278
     * Close the "main" device, because it may need to write out
1279
     * data before destruction. pdfwrite needs so.
1280
     */
1281
10.3k
    if (minst->init_done >= 2) {
1282
10.3k
        int code = 0;
1283
1284
10.3k
        if (idmemory->reclaim != 0) {
1285
            /* In extreme error conditions, these references can persist, despite the
1286
             * arrays themselves having been restored away.
1287
             */
1288
10.3k
            gs_main_run_string(minst,
1289
10.3k
                "$error /dstack undef \
1290
10.3k
                 $error /estack undef \
1291
10.3k
                 $error /ostack undef \
1292
10.3k
                 serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse \
1293
10.3k
                 .systemvar exec",
1294
10.3k
                 0 , &exit_code, &error_object);
1295
1296
10.3k
            ref_stack_clear(&o_stack);
1297
10.3k
            code = interp_reclaim(&minst->i_ctx_p, avm_global);
1298
1299
            /* We ignore gs_error_VMerror because it comes from gs_vmreclaim()
1300
            calling context_state_load(), and we don't seem to depend on the
1301
            missing fields. */
1302
10.3k
            if (code == gs_error_VMerror) {
1303
0
                if (exit_status == 0 || exit_status == gs_error_Quit) {
1304
0
                    exit_status = gs_error_VMerror;
1305
0
                }
1306
0
            }
1307
10.3k
            else if (code < 0) {
1308
0
                ref error_name;
1309
0
                if (tempnames)
1310
0
                    free(tempnames);
1311
1312
0
                if (gs_errorname(i_ctx_p, code, &error_name) >= 0) {
1313
0
                    char err_str[32] = {0};
1314
0
                    name_string_ref(imemory, &error_name, &error_name);
1315
0
                    memcpy(err_str, error_name.value.const_bytes, r_size(&error_name));
1316
0
                    emprintf2(imemory, "ERROR: %s (%d) reclaiming the memory while the interpreter finalization.\n", err_str, code);
1317
0
                }
1318
0
                else {
1319
0
                    emprintf1(imemory, "UNKNOWN ERROR %d reclaiming the memory while the interpreter finalization.\n", code);
1320
0
                }
1321
#ifdef MEMENTO
1322
                if (Memento_squeezing() && code != gs_error_VMerror ) return gs_error_Fatal;
1323
#endif
1324
0
                return gs_error_Fatal;
1325
0
            }
1326
10.3k
            i_ctx_p = minst->i_ctx_p; /* interp_reclaim could change it. */
1327
10.3k
        }
1328
1329
10.3k
        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL &&
1330
10.3k
            gx_device_is_null(i_ctx_p->pgs->device)) {
1331
            /* if the job replaced the device with the nulldevice, we we need to grestore
1332
               away that device, so the block below can properly dispense
1333
               with the default device.
1334
             */
1335
9
            int code = gs_grestoreall(i_ctx_p->pgs);
1336
9
            if (code < 0) {
1337
0
                free(tempnames);
1338
0
                return_error(gs_error_Fatal);
1339
0
            }
1340
9
        }
1341
1342
10.3k
        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL) {
1343
10.3k
            gx_device *pdev = i_ctx_p->pgs->device;
1344
10.3k
            const char * dname = pdev->dname;
1345
10.3k
            gs_gc_root_t dev_root;
1346
10.3k
            gs_gc_root_t *dev_root_ptr = &dev_root;
1347
            /* There is a chance that, during the call to gs_main_run_string(), the interpreter may
1348
             * decide to call the garbager - the device is in gc memory, and the only reference to it
1349
             * (in the gstate) has been removed, thus it can be destroyed by the garbager.
1350
             * Counter-intuitively, adjusting the reference count makes not difference to that.
1351
             * Register the device as a gc 'root' so it will be implicitely marked by garbager, and
1352
             * and thus surive until control returns here.
1353
             */
1354
10.3k
            if (gs_register_struct_root(pdev->memory, &dev_root_ptr, (void **)&pdev, "gs_main_finit") < 0) {
1355
0
                free(tempnames);
1356
0
                return_error(gs_error_Fatal);
1357
0
            }
1358
1359
            /* make sure device doesn't isn't freed by .uninstalldevice */
1360
10.3k
            rc_adjust(pdev, 1, "gs_main_finit");
1361
            /* deactivate the device just before we close it for the last time */
1362
10.3k
            gs_main_run_string(minst,
1363
                /* we need to do the 'quit' so we don't loop for input (double quit) */
1364
10.3k
                ".uninstallpagedevice serverdict \
1365
10.3k
                /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemvar exec",
1366
10.3k
                0 , &exit_code, &error_object);
1367
10.3k
            code = gs_closedevice(pdev);
1368
10.3k
            if (code < 0) {
1369
0
                ref error_name;
1370
0
                if (gs_errorname(i_ctx_p, code, &error_name) >= 0) {
1371
0
                    char err_str[32] = {0};
1372
0
                    name_string_ref(imemory, &error_name, &error_name);
1373
0
                    memcpy(err_str, error_name.value.const_bytes, r_size(&error_name));
1374
0
                    emprintf3(imemory, "ERROR: %s (%d) on closing %s device.\n", err_str, code, dname);
1375
0
                }
1376
0
                else {
1377
0
                    emprintf2(imemory, "UNKNOWN ERROR %d closing %s device.\n", code, dname);
1378
0
               }
1379
0
            }
1380
10.3k
            gs_unregister_root(pdev->memory, dev_root_ptr, "gs_main_finit");
1381
10.3k
            rc_decrement(pdev, "gs_main_finit");                /* device might be freed */
1382
10.3k
            if (exit_status == 0 || exit_status == gs_error_Quit)
1383
10.3k
                exit_status = code;
1384
10.3k
        }
1385
1386
      /* Flush stdout and stderr */
1387
10.3k
      gs_main_run_string(minst,
1388
10.3k
        "(%stdout) (w) file closefile (%stderr) (w) file closefile \
1389
10.3k
        serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemexec \
1390
10.3k
          systemdict /savedinitialgstate .forceundef",
1391
10.3k
        0 , &exit_code, &error_object);
1392
10.3k
    }
1393
10.3k
    gp_readline_finit(minst->readline_data);
1394
10.3k
    gs_free_object(minst->heap, minst->saved_pages_initial_arg, "gs_main_finit");
1395
10.3k
    i_ctx_p = minst->i_ctx_p;   /* get current interp context */
1396
10.3k
    if (gs_debug_c(':')) {
1397
0
        print_resource_usage(minst, i_ctx_p ? &gs_imemory : NULL, "Final");
1398
0
        dmprintf1(minst->heap, "%% Exiting instance "PRI_INTPTR"\n", (intptr_t)minst);
1399
0
    }
1400
    /* Do the equivalent of a restore "past the bottom". */
1401
    /* This will release all memory, close all open files, etc. */
1402
10.3k
    if (minst->init_done >= 1) {
1403
10.3k
        gs_memory_t *mem_raw = i_ctx_p->memory.current->non_gc_memory;
1404
10.3k
        i_plugin_holder *h = i_ctx_p->plugin_list;
1405
1406
10.3k
        dmem = *idmemory;
1407
10.3k
        env_code = alloc_restore_all(i_ctx_p);
1408
10.3k
        if (env_code < 0)
1409
0
            emprintf1(mem_raw,
1410
10.3k
                      "ERROR %d while the final restore. See gs/psi/ierrors.h for code explanation.\n",
1411
10.3k
                      env_code);
1412
10.3k
        i_iodev_finit(&dmem);
1413
10.3k
        i_plugin_finit(mem_raw, h);
1414
10.3k
    }
1415
1416
    /* clean up redirected stdout */
1417
10.3k
    core = minst->heap->gs_lib_ctx->core;
1418
10.3k
    if (core->fstdout2
1419
10.3k
        && (gp_get_file(core->fstdout2) != core->fstdout)
1420
10.3k
        && (gp_get_file(core->fstdout2) != core->fstderr)) {
1421
10.3k
        gp_fclose(core->fstdout2);
1422
10.3k
        core->fstdout2 = NULL;
1423
10.3k
    }
1424
1425
10.3k
    minst->heap->gs_lib_ctx->core->stdout_is_redirected = 0;
1426
10.3k
    minst->heap->gs_lib_ctx->core->stdout_to_stderr = 0;
1427
    /* remove any temporary files, after ghostscript has closed files */
1428
10.3k
    if (tempnames) {
1429
6.13k
        char *p = tempnames;
1430
12.2k
        while (*p) {
1431
6.13k
            gp_unlink(minst->heap, p);
1432
6.13k
            p += strlen(p) + 1;
1433
6.13k
        }
1434
6.13k
        free(tempnames);
1435
6.13k
    }
1436
10.3k
    gs_lib_finit(exit_status, env_code, minst->heap);
1437
1438
10.3k
    set_lib_path_length(minst, 0);
1439
10.3k
    gs_free_object(minst->heap, minst->lib_path.container.value.refs, "lib_path array");
1440
10.3k
    if (minst->init_done == 0 && i_ctx_p) {
1441
        /* This fixes leak if memento forces failure in gs_main_init1(). */
1442
0
        dmem = *idmemory;
1443
0
    }
1444
10.3k
    ialloc_finit(&dmem);
1445
10.3k
    return exit_status;
1446
10.3k
}
1447
int
1448
gs_to_exit_with_code(const gs_memory_t *mem, int exit_status, int code)
1449
10.3k
{
1450
10.3k
    return gs_main_finit(get_minst_from_memory(mem), exit_status, code);
1451
10.3k
}
1452
int
1453
gs_to_exit(const gs_memory_t *mem, int exit_status)
1454
10.3k
{
1455
10.3k
    return gs_to_exit_with_code(mem, exit_status, 0);
1456
10.3k
}
1457
void
1458
gs_abort(const gs_memory_t *mem)
1459
0
{
1460
    /* In previous versions, we tried to do a cleanup (using gs_to_exit),
1461
     * but more often than not, that will trip another abort and create
1462
     * an infinite recursion. So just abort without trying to cleanup.
1463
     */
1464
0
    gp_do_exit(1);
1465
0
}
1466
1467
/* ------ Debugging ------ */
1468
1469
/* Print resource usage statistics. */
1470
void
1471
print_resource_usage(const gs_main_instance * minst, gs_dual_memory_t * dmem,
1472
                     const char *msg)
1473
0
{
1474
0
    ulong used = 0;   /* this we accumulate for the PS memories */
1475
0
    long utime[2];
1476
0
    int i;
1477
0
    gs_memory_status_t status = { 0 };
1478
1479
0
    gp_get_realtime(utime);
1480
1481
0
    if (dmem)
1482
0
    {
1483
0
        for (i = 0; i < countof(dmem->spaces_indexed); ++i) {
1484
0
            gs_ref_memory_t *mem = dmem->spaces_indexed[i];
1485
1486
0
            if (mem != 0 && (i == 0 || mem != dmem->spaces_indexed[i - 1])) {
1487
0
                gs_ref_memory_t *mem_stable =
1488
0
                    (gs_ref_memory_t *)gs_memory_stable((gs_memory_t *)mem);
1489
1490
0
                gs_memory_status((gs_memory_t *)mem, &status);
1491
0
                used += status.used;
1492
0
                if (mem_stable != mem) {
1493
0
                    gs_memory_status((gs_memory_t *)mem_stable, &status);
1494
0
                    used += status.used;
1495
0
                }
1496
0
            }
1497
0
        }
1498
0
    }
1499
    /* Now get the overall values from the heap memory */
1500
0
    gs_memory_status(minst->heap, &status);
1501
0
    dmprintf5(minst->heap, "%% %s time = %g, memory allocated = %lu, used = %lu, max_used = %lu\n",
1502
0
              msg, utime[0] - minst->base_time[0] +
1503
0
              (utime[1] - minst->base_time[1]) / 1000000000.0,
1504
0
              status.allocated, used, status.max_used);
1505
0
}
1506
1507
/* Dump the stacks after interpretation */
1508
void
1509
gs_main_dump_stack(gs_main_instance *minst, int code, ref * perror_object)
1510
0
{
1511
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1512
1513
0
    zflush(i_ctx_p);            /* force out buffered output */
1514
0
    dmprintf1(minst->heap, "\nUnexpected interpreter error %d.\n", code);
1515
0
    if (perror_object != 0) {
1516
0
        dmputs(minst->heap, "Error object: ");
1517
0
        debug_print_ref(minst->heap, perror_object);
1518
0
        dmputc(minst->heap, '\n');
1519
0
    }
1520
0
    debug_dump_stack(minst->heap, &o_stack, "Operand stack");
1521
0
    debug_dump_stack(minst->heap, &e_stack, "Execution stack");
1522
0
    debug_dump_stack(minst->heap, &d_stack, "Dictionary stack");
1523
0
}
1524
1525
int
1526
gs_main_force_resolutions(gs_main_instance * minst, const float *resolutions)
1527
10.3k
{
1528
10.3k
    ref value;
1529
10.3k
    int code;
1530
1531
10.3k
    if (resolutions == NULL)
1532
0
        return 0;
1533
1534
10.3k
    if (minst == NULL)
1535
0
        return gs_error_Fatal;
1536
1537
10.3k
    make_true(&value);
1538
10.3k
    code = i_initial_enter_name(minst->i_ctx_p, "FIXEDRESOLUTION", &value);
1539
10.3k
    if (code < 0)
1540
0
        return code;
1541
10.3k
    make_real(&value, resolutions[0]);
1542
10.3k
    code = i_initial_enter_name(minst->i_ctx_p, "DEVICEXRESOLUTION", &value);
1543
10.3k
    if (code < 0)
1544
0
        return code;
1545
10.3k
    make_real(&value, resolutions[1]);
1546
10.3k
    return i_initial_enter_name(minst->i_ctx_p, "DEVICEYRESOLUTION", &value);
1547
10.3k
}
1548
1549
int
1550
gs_main_force_dimensions(gs_main_instance *minst, const long *dimensions)
1551
0
{
1552
0
    ref value;
1553
0
    int code = 0;
1554
1555
0
    if (dimensions == NULL)
1556
0
        return 0;
1557
0
    if (minst == NULL)
1558
0
        return gs_error_Fatal;
1559
1560
0
    make_true(&value);
1561
0
    code = i_initial_enter_name(minst->i_ctx_p, "FIXEDMEDIA", &value);
1562
0
    if (code < 0)
1563
0
        return code;
1564
0
    make_int(&value, dimensions[0]);
1565
0
    code = i_initial_enter_name(minst->i_ctx_p, "DEVICEWIDTH", &value);
1566
0
    if (code < 0)
1567
0
        return code;
1568
0
    make_int(&value, dimensions[1]);
1569
0
    return i_initial_enter_name(minst->i_ctx_p, "DEVICEHEIGHT", &value);
1570
0
}