Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/imain.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
/* 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
387M
{
72
387M
    return (gs_main_instance*)mem->gs_lib_ctx->top_of_system;
73
387M
}
74
75
/** construct main instance caller needs to retain */
76
gs_main_instance *
77
gs_main_alloc_instance(gs_memory_t *mem)
78
147k
{
79
147k
    gs_main_instance *minst;
80
147k
    if (mem == NULL)
81
0
        return NULL;
82
83
147k
    minst = (gs_main_instance *)gs_alloc_bytes_immovable(mem,
84
147k
                                                         sizeof(gs_main_instance),
85
147k
                                                         "init_main_instance");
86
147k
    if (minst == NULL)
87
0
        return NULL;
88
147k
    memset(minst, 0, sizeof(gs_main_instance));
89
147k
    memcpy(minst, &gs_main_instance_init_values, sizeof(gs_main_instance_init_values));
90
147k
    minst->heap = mem;
91
147k
    mem->gs_lib_ctx->top_of_system = minst;
92
147k
    return minst;
93
147k
}
94
95
op_array_table *
96
get_op_array(const gs_memory_t *mem, int size)
97
222M
{
98
222M
    gs_main_instance *minst = get_minst_from_memory(mem);
99
222M
    return op_index_op_array_table(minst->i_ctx_p,size);
100
222M
}
101
102
op_array_table *
103
get_global_op_array(const gs_memory_t *mem)
104
293k
{
105
293k
    gs_main_instance *minst = get_minst_from_memory(mem);
106
293k
    return &minst->i_ctx_p->op_array_table_global;
107
293k
}
108
109
op_array_table *
110
get_local_op_array(const gs_memory_t *mem)
111
293k
{
112
293k
    gs_main_instance *minst = get_minst_from_memory(mem);
113
293k
    return &minst->i_ctx_p->op_array_table_local;
114
293k
}
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
147k
{
129
147k
    ref *array;
130
147k
    int code = 0;
131
132
147k
    if (gs_debug_c(gs_debug_flag_init_details))
133
147k
        dmprintf1(minst->heap, "%% Init phase 0 started, instance "PRI_INTPTR"\n",
134
147k
                  (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
147k
    gp_init();
141
142
    /* Initialize the imager. */
143
144
    /* Reset debugging flags */
145
147k
#ifdef PACIFY_VALGRIND
146
147k
    VALGRIND_HG_DISABLE_CHECKING(gs_debug, 128);
147
147k
#endif
148
147k
    memset(gs_debug, 0, 128);
149
147k
    gs_log_errors = 0;  /* gs_debug['#'] = 0 */
150
151
147k
    gp_get_realtime(minst->base_time);
152
153
    /* Initialize the file search paths. */
154
147k
    array = (ref *) gs_alloc_byte_array(minst->heap, max_lib_paths, sizeof(ref),
155
147k
                                        "lib_path array");
156
147k
    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
147k
    make_array(&minst->lib_path.container, avm_foreign, max_lib_paths,
162
147k
               array);
163
147k
    make_array(&minst->lib_path.list, avm_foreign | a_readonly, 0,
164
147k
               minst->lib_path.container.value.refs);
165
147k
    minst->lib_path.env = NULL;
166
147k
    minst->lib_path.final = NULL;
167
147k
    minst->lib_path.count = 0;
168
147k
    minst->lib_path.first_is_current = 0;
169
147k
    minst->user_errors = 1;
170
147k
    minst->init_done = 0;
171
172
147k
fail:
173
147k
    if (gs_debug_c(gs_debug_flag_init_details))
174
147k
        dmprintf2(minst->heap, "%% Init phase 0 %s, instance "PRI_INTPTR"\n",
175
147k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
176
177
147k
    return code;
178
147k
}
179
180
/* Initialization to be done before constructing any objects. */
181
int
182
gs_main_init1(gs_main_instance * minst)
183
2.43M
{
184
2.43M
    gs_dual_memory_t idmem;
185
2.43M
    name_table *nt = NULL;
186
2.43M
    int code;
187
188
2.43M
    if (minst->init_done >= 1)
189
2.28M
        return 0;
190
191
147k
    if (gs_debug_c(gs_debug_flag_init_details))
192
147k
        dmprintf1(minst->heap, "%% Init phase 1 started, instance "PRI_INTPTR"\n",
193
147k
                  (intptr_t)minst);
194
195
147k
    code = ialloc_init(&idmem, minst->heap,
196
147k
                       minst->memory_clump_size, gs_have_level2());
197
198
147k
    if (code < 0)
199
0
        goto fail_early;
200
201
147k
    code = gs_lib_init1((gs_memory_t *)idmem.space_system);
202
147k
    if (code < 0)
203
0
        goto fail;
204
147k
    alloc_save_init(&idmem);
205
147k
    {
206
147k
        gs_memory_t *mem = (gs_memory_t *)idmem.space_system;
207
147k
        nt = names_init(minst->name_table_size, idmem.space_system);
208
209
147k
        if (nt == 0) {
210
0
            code = gs_note_error(gs_error_VMerror);
211
0
            goto fail;
212
0
        }
213
147k
        mem->gs_lib_ctx->gs_name_table = nt;
214
147k
        code = gs_register_struct_root(mem, &mem->gs_lib_ctx->name_table_root,
215
147k
                                       (void **)&mem->gs_lib_ctx->gs_name_table,
216
147k
                                       "the_gs_name_table");
217
147k
        if (code < 0)
218
0
            goto fail;
219
147k
        mem->gs_lib_ctx->client_check_file_permission = z_check_file_permissions;
220
147k
    }
221
0
    code = obj_init(&minst->i_ctx_p, &idmem);  /* requires name_init */
222
147k
    if (code < 0)
223
0
        goto fail;
224
147k
    minst->init_done = 1;
225
147k
    code = i_plugin_init(minst->i_ctx_p);
226
147k
    if (code < 0)
227
0
        goto fail;
228
147k
    code = i_iodev_init(&idmem);
229
147k
    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
147k
fail_early:
236
237
147k
    if (gs_debug_c(gs_debug_flag_init_details))
238
147k
        dmprintf2(minst->heap, "%% Init phase 1 %s, instance "PRI_INTPTR"\n",
239
147k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
240
241
147k
    return code;
242
147k
}
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
2.62M
{
252
2.62M
    int code;
253
254
    /* set interpreter pointer to lib_path */
255
2.62M
    minst->i_ctx_p->lib_path = &minst->lib_path;
256
257
2.62M
    code = gs_interpret(&minst->i_ctx_p, pref,
258
2.62M
                        user_errors, pexit_code, perror_object);
259
2.62M
    return code;
260
2.62M
}
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
147k
int gs_main_init2aux(gs_main_instance * minst) {
270
147k
    i_ctx_t * i_ctx_p = minst->i_ctx_p;
271
272
147k
    if (minst->init_done < 2) {
273
147k
        int code, exit_code;
274
147k
        ref error_object, ifa;
275
276
        /* Set up enough so that we can safely be garbage collected */
277
147k
        i_ctx_p->op_array_table_global = empty_table;
278
147k
        i_ctx_p->op_array_table_local = empty_table;
279
280
147k
        code = zop_init(i_ctx_p);
281
147k
        if (code < 0)
282
0
            return code;
283
147k
        code = op_init(i_ctx_p);        /* requires obj_init */
284
147k
        if (code < 0)
285
0
            return code;
286
287
        /* Set up the array of additional initialization files. */
288
147k
        make_const_string(&ifa, a_readonly | avm_foreign, gs_init_files_sizeof - 2, gs_init_files);
289
147k
        code = i_initial_enter_name(i_ctx_p, "INITFILES", &ifa);
290
147k
        if (code < 0)
291
0
            return code;
292
293
        /* Set up the array of emulator names. */
294
147k
        make_const_string(&ifa, a_readonly | avm_foreign, gs_emulators_sizeof - 2, gs_emulators);
295
147k
        code = i_initial_enter_name(i_ctx_p, "EMULATORS", &ifa);
296
147k
        if (code < 0)
297
0
            return code;
298
299
        /* Pass the search path. */
300
147k
        code = i_initial_enter_name(i_ctx_p, "LIBPATH", &minst->lib_path.list);
301
147k
        if (code < 0)
302
0
            return code;
303
304
        /* Execute the standard initialization file. */
305
147k
        code = gs_run_init_file(minst, &exit_code, &error_object);
306
147k
        if (code < 0)
307
438
            return code;
308
146k
        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
146k
        if ((code = reopen_device_if_required(minst)) < 0)
314
0
            return code;
315
316
146k
        if ((code = gs_main_run_string(minst,
317
146k
                "JOBSERVER "
318
146k
                " { false 0 .startnewjob } "
319
146k
                " { NOOUTERSAVE not { save pop } if } "
320
146k
                "ifelse", 0, &exit_code,
321
146k
                &error_object)) < 0)
322
0
           return code;
323
146k
    }
324
146k
    return 0;
325
147k
}
326
327
int
328
gs_main_set_language_param(gs_main_instance *minst,
329
                           gs_param_list    *plist)
330
44.0k
{
331
44.0k
    ref value;
332
44.0k
    int code = 0;
333
44.0k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
334
44.0k
    uint space = icurrent_space;
335
44.0k
    gs_param_enumerator_t enumerator;
336
44.0k
    gs_param_key_t key;
337
44.0k
    gs_lib_ctx_t *ctx = minst->heap->gs_lib_ctx;
338
44.0k
    ref error_object;
339
340
    /* If we're up and running as a jobserver, exit encapsulation. */
341
44.0k
    if (minst->init_done > 1) {
342
14
        code = gs_main_run_string(minst,
343
14
                                  "JOBSERVER {true 0 startjob pop} if",
344
14
                                  0, &code, &error_object);
345
14
        if (code < 0) return code;
346
14
    }
347
348
44.0k
    ialloc_set_space(idmemory, avm_system);
349
350
44.0k
    param_init_enumerator(&enumerator);
351
154k
    while ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
352
110k
        char string_key[256]; /* big enough for any reasonable key */
353
110k
        gs_param_typed_value pvalue;
354
355
110k
        if (key.size > sizeof(string_key) - 1) {
356
0
            code = gs_note_error(gs_error_rangecheck);
357
0
            break;
358
0
        }
359
110k
        memcpy(string_key, key.data, key.size);
360
110k
        string_key[key.size] = 0;
361
110k
        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
110k
        switch (pvalue.type) {
366
0
        case gs_param_type_null:
367
0
            make_null(&value);
368
0
            break;
369
99.1k
        case gs_param_type_bool:
370
99.1k
            if (pvalue.value.b)
371
99.1k
                make_true(&value);
372
0
            else
373
99.1k
                make_false(&value);
374
99.1k
            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
11.0k
        case gs_param_type_string:
400
11.0k
            if (pvalue.value.s.data == NULL || pvalue.value.s.size == 0)
401
11.0k
                make_empty_string(&value, a_readonly);
402
11.0k
            else {
403
11.0k
                size_t len = pvalue.value.s.size;
404
11.0k
                byte *body = ialloc_string(len, "-s");
405
406
11.0k
                if (body == NULL)
407
0
                    return gs_error_Fatal;
408
11.0k
                memcpy(body, pvalue.value.s.data, len);
409
11.0k
                make_const_string(&value, a_readonly | avm_system, len, body);
410
11.0k
            }
411
11.0k
            break;
412
11.0k
        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
12
        case gs_param_type_float_array:
419
            /* We don't support arrays for now */
420
12
            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
110k
        }
427
110k
        if (code < 0)
428
0
            break;
429
430
110k
        ialloc_set_space(idmemory, space);
431
        /* Enter the name in systemdict. */
432
110k
        i_initial_enter_name_copy(minst->i_ctx_p, string_key, &value);
433
110k
    }
434
435
44.0k
    if (minst->init_done > 1) {
436
14
        int code2 = 0;
437
14
        code2 = gs_main_run_string(minst,
438
14
                                   "JOBSERVER {false 0 startjob pop} if",
439
14
                                   0, &code2, &error_object);
440
14
        if (code >= 0)
441
14
            code = code2;
442
14
    }
443
444
44.0k
    return code;
445
44.0k
}
446
447
static int
448
gs_main_push_params(gs_main_instance *minst)
449
248k
{
450
248k
    int code;
451
248k
    gs_c_param_list *plist;
452
453
248k
    plist = minst->param_list;
454
248k
    if (!plist)
455
248k
        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
248k
{
474
248k
    i_ctx_t *i_ctx_p;
475
248k
    int code = gs_main_init1(minst);
476
477
248k
    if (code < 0)
478
0
        return code;
479
480
248k
    code = gs_main_push_params(minst);
481
248k
    if (code < 0)
482
0
        return code;
483
484
248k
    if (minst->init_done >= 2)
485
100k
        return 0;
486
487
147k
    if (gs_debug_c(gs_debug_flag_init_details))
488
147k
        dmprintf1(minst->heap, "%% Init phase 2 started, instance "PRI_INTPTR"\n",
489
147k
                  (intptr_t)minst);
490
491
147k
    code = gs_main_init2aux(minst);
492
147k
    if (code < 0)
493
438
       goto fail;
494
495
146k
    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
146k
    {
499
146k
       gx_device *pdev = gs_currentdevice(minst->i_ctx_p->pgs); /* get the current device */
500
146k
       gx_device_printer *ppdev = (gx_device_printer *)pdev;
501
502
146k
        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
146k
        } 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
146k
    }
530
531
146k
    if (code >= 0) {
532
146k
        if (gs_debug_c(':'))
533
0
            print_resource_usage(minst, i_ctx_p ? &gs_imemory : NULL, "Start");
534
146k
        gp_readline_init(&minst->readline_data, minst->heap); /* lgtm [cpp/useless-expression] */
535
146k
    }
536
537
147k
fail:
538
147k
    if (gs_debug_c(gs_debug_flag_init_details))
539
147k
        dmprintf2(minst->heap, "%% Init phase 2 %s, instance "PRI_INTPTR"\n",
540
147k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
541
542
147k
    return code;
543
146k
}
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
17.1M
{
577
17.1M
    ref *paths;
578
17.1M
    int listlen = r_size(&minst->lib_path.list); /* The real number of entries currently in the list */
579
17.1M
    byte *newstr;
580
17.1M
    int code;
581
582
    /* Extend the container if required */
583
17.1M
    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
17.1M
    newstr = gs_alloc_string(minst->heap, strlen, "lib_path_add");
593
17.1M
    if (newstr == NULL)
594
0
        return gs_error_VMerror;
595
17.1M
    memcpy(newstr, str, strlen);
596
597
    /* Shuffle up the entries */
598
17.1M
    paths = &minst->lib_path.container.value.refs[pos];
599
17.1M
    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
17.1M
    make_const_string(paths, avm_foreign | a_readonly,
604
17.1M
                      strlen,
605
17.1M
                      newstr);
606
607
    /* Update the list length */
608
17.1M
    r_set_size(&minst->lib_path.list, listlen+1);
609
610
17.1M
    return 0;
611
17.1M
}
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
3.94M
{
619
3.94M
    gs_file_path * pfp = &minst->lib_path;
620
3.94M
    uint len = r_size(&pfp->list);
621
3.94M
    const char *dpath = dirs;
622
3.94M
    int code;
623
624
3.94M
    if (dirs == 0)
625
0
        return 0;
626
627
17.1M
    for (;;) {                  /* Find the end of the next directory name. */
628
17.1M
        const char *npath = dpath;
629
630
587M
        while (*npath != 0 && *npath != gp_file_name_list_separator)
631
570M
            npath++;
632
17.1M
        if (npath > dpath) {
633
17.1M
            code = gs_add_control_path_len(minst->heap, gs_permit_file_reading, dpath, npath - dpath);
634
17.1M
            if (code < 0) return code;
635
636
17.1M
            code = lib_path_insert_copy_of_string(minst, len, npath - dpath, dpath);
637
17.1M
            if (code < 0)
638
0
                return code;
639
17.1M
            len++;
640
            /* Update length/count so we don't lose entries if a later
641
             * iteration fails. */
642
17.1M
            r_set_size(&pfp->list, len);
643
17.1M
        }
644
17.1M
        if (!*npath)
645
3.94M
            break;
646
13.1M
        dpath = npath + 1;
647
13.1M
    }
648
3.94M
    return 0;
649
3.94M
}
650
651
static void
652
set_lib_path_length(gs_main_instance * minst, int newsize)
653
1.46M
{
654
1.46M
    gs_file_path * pfp = &minst->lib_path;
655
1.46M
    uint len = r_size(&pfp->list); /* Yes, list, not container */
656
1.46M
    uint i;
657
658
    /* Free any entries that are discarded by us shortening the list */
659
18.5M
    for (i = newsize; i < len; i++)
660
17.1M
        gs_free_object(minst->heap, pfp->container.value.refs[i].value.bytes, "lib_path entry");
661
1.46M
    r_set_size(&pfp->list, newsize);
662
1.46M
}
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
1.31M
{
696
1.31M
    int code = 0;
697
1.31M
    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
1.31M
    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
1.31M
    } 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
1.31M
    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
1.31M
    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
1.31M
    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
9.21M
    for (i = 0; i < gx_io_device_table_count; i++) {
759
9.21M
        const gx_io_device *iodev = gx_io_device_table[i];
760
9.21M
        const char *dname = iodev->dname;
761
9.21M
        const char *fcheckname = "Resource/Init/gs_init.ps";
762
763
9.21M
        if (dname && strlen(dname) == 5 && !memcmp("%rom%", dname, 5)) {
764
1.31M
            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
1.31M
            int code = iodev->procs.file_status((gx_io_device *)iodev, fcheckname, &pstat);
770
1.31M
            if (code != gs_error_unregistered && code != gs_error_undefinedfilename){
771
1.31M
                have_rom_device = 1;
772
1.31M
            }
773
1.31M
            break;
774
1.31M
        }
775
9.21M
    }
776
1.31M
    if (have_rom_device) {
777
1.31M
        code = lib_path_add(minst, "%rom%Resource/Init/");
778
1.31M
        if (code < 0)
779
0
            return code;
780
1.31M
        code = lib_path_add(minst, "%rom%lib/");
781
1.31M
    }
782
0
    else code = 0;
783
784
1.31M
    if (minst->lib_path.final != NULL && code >= 0)
785
1.31M
        code = lib_path_add(minst, minst->lib_path.final);
786
1.31M
    return code;
787
1.31M
}
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
147k
{
793
    /* This is a separate procedure only to avoid tying up */
794
    /* extra stack space while running the file. */
795
147k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
796
147k
#define maxfn 2048
797
147k
    char fn[maxfn];
798
147k
    uint len;
799
800
147k
    return lib_file_open(&minst->lib_path, imemory,
801
147k
                         NULL, /* Don't check permissions here, because permlist
802
                                  isn't ready running init files. */
803
147k
                          file_name, strlen(file_name), fn, maxfn, &len, pfile);
804
147k
}
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
147k
{
821
147k
    gs_main_set_lib_paths(minst);
822
147k
    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
147k
    r_set_attrs(pfref, a_execute + a_executable);
829
147k
    return 0;
830
147k
}
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
147k
{
836
147k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
837
147k
    ref ifile;
838
147k
    ref first_token;
839
147k
    int code;
840
147k
    scanner_state state;
841
842
147k
    gs_main_set_lib_paths(minst);
843
147k
    code = gs_main_run_file_open(minst, gs_init_file, &ifile);
844
147k
    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
147k
    gs_scanner_init(&state, &ifile);
851
147k
    code = gs_scan_token(i_ctx_p, &first_token, &state);
852
147k
    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
147k
    *++osp = first_token;
860
147k
    r_set_attrs(&ifile, a_executable);
861
147k
    return gs_main_interpret(minst, &ifile, minst->user_errors,
862
147k
                        pexit_code, perror_object);
863
147k
}
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
874k
{
870
874k
    return gs_main_run_string_with_length(minst, str, (uint) strlen(str),
871
874k
                                          user_errors,
872
874k
                                          pexit_code, perror_object);
873
874k
}
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
874k
{
878
874k
    int code;
879
880
874k
    code = gs_main_run_string_begin(minst, user_errors,
881
874k
                                    pexit_code, perror_object);
882
874k
    if (code < 0)
883
0
        return code;
884
874k
    code = gs_main_run_string_continue(minst, str, length, user_errors,
885
874k
                                       pexit_code, perror_object);
886
874k
    if (code != gs_error_NeedInput)
887
146k
        return code;
888
889
727k
    code = gs_main_run_string_end(minst, user_errors,
890
727k
                                  pexit_code, perror_object);
891
    /* Not okay for user to use .needinput
892
     * This treats it as a fatal error.
893
     */
894
727k
    if (code == gs_error_NeedInput)
895
0
        return_error(gs_error_Fatal);
896
727k
    return code;
897
727k
}
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
874k
{
904
874k
    const char *setup = ".runstringbegin";
905
874k
    ref rstr;
906
874k
    int code;
907
908
874k
    gs_main_set_lib_paths(minst);
909
874k
    make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
910
874k
                      strlen(setup), (const byte *)setup);
911
874k
    code = gs_main_interpret(minst, &rstr, user_errors, pexit_code,
912
874k
                             perror_object);
913
874k
    return (code == gs_error_NeedInput ? 0 : code == 0 ? gs_error_Fatal : code);
914
874k
}
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
874k
{
920
874k
    ref rstr;
921
922
874k
    if (length == 0)
923
0
        return 0;               /* empty string signals EOF */
924
874k
    make_const_string(&rstr, avm_foreign | a_readonly, length,
925
874k
                      (const byte *)str);
926
874k
    return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
927
874k
                             perror_object);
928
874k
}
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
727k
{
942
727k
    ref rstr;
943
944
727k
    make_empty_const_string(&rstr, avm_foreign | a_readonly);
945
727k
    return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
946
727k
                             perror_object);
947
727k
}
948
949
gs_memory_t *
950
gs_main_get_device_memory(gs_main_instance * minst)
951
11.0k
{
952
11.0k
  gs_memory_t *dev_mem = NULL;
953
11.0k
  if (minst && minst->init_done >= 1) {
954
11.0k
      i_ctx_t * i_ctx_p = minst->i_ctx_p;
955
11.0k
      dev_mem = imemory_global->stable_memory;
956
11.0k
  }
957
11.0k
  return dev_mem;
958
11.0k
}
959
960
int
961
gs_main_set_device(gs_main_instance * minst, gx_device *pdev)
962
1.80k
{
963
1.80k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
964
1.80k
    ref error_object;
965
1.80k
    int code;
966
967
1.80k
    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
901
        code = gs_main_run_string(minst,
974
901
                                 "true 0 startjob pop grestore false 0 startjob pop",
975
901
                                 0, &code, &error_object);
976
901
        if (code < 0) goto done;
977
901
    }
978
901
    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
901
        code = gs_main_run_string(minst,
982
901
                                  "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
901
                                  "<< /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
901
                                  "pop "
991
901
                                  ">> "
992
901
                                  , 0, &code, &error_object);
993
901
        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
901
        code = zsetdevice_no_safer(i_ctx_p, pdev);
997
901
        if (code < 0) goto done;
998
901
        code = zcurrentdevice(i_ctx_p);
999
901
        if (code < 0) goto done;
1000
901
        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
901
                                  "setdevice "
1005
901
                                  "setpagedevice "
1006
                                  /* GS specifics: Force the cached copy of the params to be updated. */
1007
901
                                  "currentpagedevice pop "
1008
                                  /* Setup the halftone */
1009
901
                                  ".setdefaultscreen "
1010
                                  /* Re-run the scheduled initialisation procs, in case we've just set pdfwrite */
1011
901
                                  "1183615869 internaldict /.execute_scheduled_inits get exec "
1012
                                  /* Re-enter job encapsulation */
1013
901
                                  "false 0 startjob pop "
1014
901
                                  , 0, &code, &error_object);
1015
901
        if (code < 0) goto done;
1016
901
    }
1017
1.80k
done:
1018
1.80k
    return code;
1019
1.80k
}
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
147k
{
1178
147k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1179
147k
    ref *SAFETY;
1180
147k
    ref *tempfiles;
1181
147k
    ref keyval[2];      /* for key and value */
1182
147k
    char *tempnames = NULL;
1183
147k
    int i;
1184
147k
    int idict;
1185
147k
    int len = 0;
1186
147k
    const byte *data = NULL;
1187
147k
    uint size;
1188
147k
    if (minst->init_done >= 2) {
1189
146k
        if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
1190
146k
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0)
1191
0
            return NULL;
1192
        /* get lengths of temporary filenames */
1193
146k
        idict = dict_first(tempfiles);
1194
229k
        while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
1195
82.4k
            if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0)
1196
82.4k
                len += size + 1;
1197
82.4k
        }
1198
146k
        if (len != 0)
1199
82.4k
            tempnames = (char *)malloc(len+1);
1200
146k
        if (tempnames) {
1201
82.4k
            memset(tempnames, 0, len+1);
1202
            /* copy temporary filenames */
1203
82.4k
            idict = dict_first(tempfiles);
1204
82.4k
            i = 0;
1205
164k
            while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
1206
82.4k
                if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0) {
1207
82.4k
                    memcpy(tempnames+i, (const char *)data, size);
1208
82.4k
                    i+= size;
1209
82.4k
                    tempnames[i++] = '\0';
1210
82.4k
                }
1211
82.4k
            }
1212
82.4k
        }
1213
146k
    }
1214
147k
    return tempnames;
1215
147k
}
1216
1217
static void
1218
gs_finit_push_systemdict(i_ctx_t *i_ctx_p)
1219
147k
{
1220
147k
    if (i_ctx_p == NULL)
1221
0
        return;
1222
147k
    if (dsp == dstop ) {
1223
6
        if (ref_stack_extend(&d_stack, 1) < 0) {
1224
            /* zend() cannot fail */
1225
0
            (void)zend(i_ctx_p);
1226
0
        }
1227
6
    }
1228
147k
    dsp++;
1229
147k
    ref_assign(dsp, systemdict);
1230
147k
}
1231
1232
/* Free all resources and return. */
1233
int
1234
gs_main_finit(gs_main_instance * minst, int exit_status, int env_code)
1235
147k
{
1236
147k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1237
147k
    gs_dual_memory_t dmem = {0};
1238
147k
    int exit_code;
1239
147k
    ref error_object;
1240
147k
    char *tempnames = NULL;
1241
147k
    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
147k
    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
147k
    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
147k
    if (minst->init_done >= 2) {
1268
146k
        gs_main_run_string(minst,
1269
146k
            "/BGPrint /GetDeviceParam .special_op \
1270
146k
            {{ <</BeginPage {pop} /EndPage {pop pop //false } \
1271
146k
              /BGPrint false /NumRenderingThreads 0>> setpagedevice} if} if \
1272
146k
              serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse \
1273
146k
              .systemvar exec",
1274
146k
            0 , &exit_code, &error_object);
1275
146k
    }
1276
1277
    /*
1278
     * Close the "main" device, because it may need to write out
1279
     * data before destruction. pdfwrite needs so.
1280
     */
1281
147k
    if (minst->init_done >= 2) {
1282
146k
        int code = 0;
1283
1284
146k
        if (idmemory->reclaim != 0) {
1285
            /* In extreme error conditions, these references can persist, despite the
1286
             * arrays themselves having been restored away.
1287
             */
1288
146k
            gs_main_run_string(minst,
1289
146k
                "$error /dstack undef \
1290
146k
                 $error /estack undef \
1291
146k
                 $error /ostack undef \
1292
146k
                 serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse \
1293
146k
                 .systemvar exec",
1294
146k
                 0 , &exit_code, &error_object);
1295
1296
146k
            ref_stack_clear(&o_stack);
1297
146k
            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
146k
            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
146k
            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
146k
            i_ctx_p = minst->i_ctx_p; /* interp_reclaim could change it. */
1327
146k
        }
1328
1329
146k
        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL &&
1330
146k
            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
77
            int code = gs_grestoreall(i_ctx_p->pgs);
1336
77
            if (code < 0) {
1337
0
                free(tempnames);
1338
0
                return_error(gs_error_Fatal);
1339
0
            }
1340
77
        }
1341
1342
146k
        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL) {
1343
146k
            gx_device *pdev = i_ctx_p->pgs->device;
1344
146k
            const char * dname = pdev->dname;
1345
146k
            gs_gc_root_t dev_root;
1346
146k
            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
146k
            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
146k
            rc_adjust(pdev, 1, "gs_main_finit");
1361
            /* deactivate the device just before we close it for the last time */
1362
146k
            gs_main_run_string(minst,
1363
                /* we need to do the 'quit' so we don't loop for input (double quit) */
1364
146k
                ".uninstallpagedevice serverdict \
1365
146k
                /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemvar exec",
1366
146k
                0 , &exit_code, &error_object);
1367
146k
            code = gs_closedevice(pdev);
1368
146k
            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
146k
            gs_unregister_root(pdev->memory, dev_root_ptr, "gs_main_finit");
1381
146k
            rc_decrement(pdev, "gs_main_finit");                /* device might be freed */
1382
146k
            if (exit_status == 0 || exit_status == gs_error_Quit)
1383
146k
                exit_status = code;
1384
146k
        }
1385
1386
      /* Flush stdout and stderr */
1387
146k
      gs_main_run_string(minst,
1388
146k
        "(%stdout) (w) file closefile (%stderr) (w) file closefile \
1389
146k
        serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemexec \
1390
146k
          systemdict /savedinitialgstate .forceundef",
1391
146k
        0 , &exit_code, &error_object);
1392
146k
    }
1393
147k
    gp_readline_finit(minst->readline_data);
1394
147k
    gs_free_object(minst->heap, minst->saved_pages_initial_arg, "gs_main_finit");
1395
147k
    i_ctx_p = minst->i_ctx_p;   /* get current interp context */
1396
147k
    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
1401
#ifdef MEMENTO
1402
    /* We only do this for Memento builds, because the strings themselves are allocated by one
1403
     * of the GS memory allocators, which are cleaned up and closed down by ialloc_finit()
1404
     * called at the end of this function, so they can't leak.
1405
     * But Memento can't know that, all it knows is we did an allocation without a corresponding free
1406
     * so this code just gets rid of the leak warnings to make the output cleaner.
1407
     */
1408
    if (i_ctx_p->system_params.FontResourceDir != NULL)
1409
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->system_params.FontResourceDir, "gs_main_finit");
1410
    if (i_ctx_p->system_params.GenericResourceDir != NULL)
1411
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->system_params.GenericResourceDir, "gs_main_finit");
1412
    if (i_ctx_p->system_params.GenericResourcePathSep != NULL)
1413
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->system_params.GenericResourcePathSep, "gs_main_finit");
1414
    if (i_ctx_p->system_params.PercentDiskFontResourceDir != NULL)
1415
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->system_params.PercentDiskFontResourceDir, "gs_main_finit");
1416
    if (i_ctx_p->system_params.PercentDiskGenericResourceDir != NULL)
1417
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->system_params.PercentDiskGenericResourceDir, "gs_main_finit");
1418
    if (i_ctx_p->system_params.StartJobPassword != NULL)
1419
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->system_params.StartJobPassword, "gs_main_finit");
1420
    if (i_ctx_p->system_params.SystemParamsPassword != NULL)
1421
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->system_params.SystemParamsPassword, "gs_main_finit");
1422
    if (i_ctx_p->user_params.JobName != NULL)
1423
        gs_free_object(i_ctx_p->memory.current->non_gc_memory, i_ctx_p->user_params.JobName, "gs_main_finit");
1424
#endif
1425
1426
    /* Do the equivalent of a restore "past the bottom". */
1427
    /* This will release all memory, close all open files, etc. */
1428
147k
    if (minst->init_done >= 1) {
1429
147k
        gs_memory_t *mem_raw = i_ctx_p->memory.current->non_gc_memory;
1430
147k
        i_plugin_holder *h = i_ctx_p->plugin_list;
1431
1432
147k
        dmem = *idmemory;
1433
147k
        env_code = alloc_restore_all(i_ctx_p);
1434
147k
        if (env_code < 0)
1435
0
            emprintf1(mem_raw,
1436
147k
                      "ERROR %d while the final restore. See gs/psi/ierrors.h for code explanation.\n",
1437
147k
                      env_code);
1438
147k
        i_iodev_finit(&dmem);
1439
147k
        i_plugin_finit(mem_raw, h);
1440
147k
    }
1441
1442
    /* clean up redirected stdout */
1443
147k
    core = minst->heap->gs_lib_ctx->core;
1444
147k
    if (core->fstdout2
1445
133k
        && (gp_get_file(core->fstdout2) != core->fstdout)
1446
133k
        && (gp_get_file(core->fstdout2) != core->fstderr)) {
1447
133k
        gp_fclose(core->fstdout2);
1448
133k
        core->fstdout2 = NULL;
1449
133k
    }
1450
1451
147k
    minst->heap->gs_lib_ctx->core->stdout_is_redirected = 0;
1452
147k
    minst->heap->gs_lib_ctx->core->stdout_to_stderr = 0;
1453
    /* remove any temporary files, after ghostscript has closed files */
1454
147k
    if (tempnames) {
1455
82.4k
        char *p = tempnames;
1456
164k
        while (*p) {
1457
82.4k
            gp_unlink(minst->heap, p);
1458
82.4k
            p += strlen(p) + 1;
1459
82.4k
        }
1460
82.4k
        free(tempnames);
1461
82.4k
    }
1462
147k
    gs_lib_finit(exit_status, env_code, minst->heap);
1463
1464
147k
    set_lib_path_length(minst, 0);
1465
147k
    gs_free_object(minst->heap, minst->lib_path.container.value.refs, "lib_path array");
1466
147k
    if (minst->init_done == 0 && i_ctx_p) {
1467
        /* This fixes leak if memento forces failure in gs_main_init1(). */
1468
0
        dmem = *idmemory;
1469
0
    }
1470
147k
    ialloc_finit(&dmem);
1471
147k
    return exit_status;
1472
147k
}
1473
int
1474
gs_to_exit_with_code(const gs_memory_t *mem, int exit_status, int code)
1475
147k
{
1476
147k
    return gs_main_finit(get_minst_from_memory(mem), exit_status, code);
1477
147k
}
1478
int
1479
gs_to_exit(const gs_memory_t *mem, int exit_status)
1480
147k
{
1481
147k
    return gs_to_exit_with_code(mem, exit_status, 0);
1482
147k
}
1483
void
1484
gs_abort(const gs_memory_t *mem)
1485
0
{
1486
    /* In previous versions, we tried to do a cleanup (using gs_to_exit),
1487
     * but more often than not, that will trip another abort and create
1488
     * an infinite recursion. So just abort without trying to cleanup.
1489
     */
1490
0
    gp_do_exit(1);
1491
0
}
1492
1493
/* ------ Debugging ------ */
1494
1495
/* Print resource usage statistics. */
1496
void
1497
print_resource_usage(const gs_main_instance * minst, gs_dual_memory_t * dmem,
1498
                     const char *msg)
1499
0
{
1500
0
    ulong used = 0;   /* this we accumulate for the PS memories */
1501
0
    long utime[2];
1502
0
    int i;
1503
0
    gs_memory_status_t status = { 0 };
1504
1505
0
    gp_get_realtime(utime);
1506
1507
0
    if (dmem)
1508
0
    {
1509
0
        for (i = 0; i < countof(dmem->spaces_indexed); ++i) {
1510
0
            gs_ref_memory_t *mem = dmem->spaces_indexed[i];
1511
1512
0
            if (mem != 0 && (i == 0 || mem != dmem->spaces_indexed[i - 1])) {
1513
0
                gs_ref_memory_t *mem_stable =
1514
0
                    (gs_ref_memory_t *)gs_memory_stable((gs_memory_t *)mem);
1515
1516
0
                gs_memory_status((gs_memory_t *)mem, &status);
1517
0
                used += status.used;
1518
0
                if (mem_stable != mem) {
1519
0
                    gs_memory_status((gs_memory_t *)mem_stable, &status);
1520
0
                    used += status.used;
1521
0
                }
1522
0
            }
1523
0
        }
1524
0
    }
1525
    /* Now get the overall values from the heap memory */
1526
0
    gs_memory_status(minst->heap, &status);
1527
0
    dmprintf5(minst->heap, "%% %s time = %g, memory allocated = %lu, used = %lu, max_used = %lu\n",
1528
0
              msg, utime[0] - minst->base_time[0] +
1529
0
              (utime[1] - minst->base_time[1]) / 1000000000.0,
1530
0
              status.allocated, used, status.max_used);
1531
0
}
1532
1533
/* Dump the stacks after interpretation */
1534
void
1535
gs_main_dump_stack(gs_main_instance *minst, int code, ref * perror_object)
1536
0
{
1537
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1538
1539
0
    zflush(i_ctx_p);            /* force out buffered output */
1540
0
    dmprintf1(minst->heap, "\nUnexpected interpreter error %d.\n", code);
1541
0
    if (perror_object != 0) {
1542
0
        dmputs(minst->heap, "Error object: ");
1543
0
        debug_print_ref(minst->heap, perror_object);
1544
0
        dmputc(minst->heap, '\n');
1545
0
    }
1546
0
    debug_dump_stack(minst->heap, &o_stack, "Operand stack");
1547
0
    debug_dump_stack(minst->heap, &e_stack, "Execution stack");
1548
0
    debug_dump_stack(minst->heap, &d_stack, "Dictionary stack");
1549
0
}
1550
1551
int
1552
gs_main_force_resolutions(gs_main_instance * minst, const float *resolutions)
1553
147k
{
1554
147k
    ref value;
1555
147k
    int code;
1556
1557
147k
    if (resolutions == NULL)
1558
0
        return 0;
1559
1560
147k
    if (minst == NULL)
1561
0
        return gs_error_Fatal;
1562
1563
147k
    make_true(&value);
1564
147k
    code = i_initial_enter_name(minst->i_ctx_p, "FIXEDRESOLUTION", &value);
1565
147k
    if (code < 0)
1566
0
        return code;
1567
147k
    make_real(&value, resolutions[0]);
1568
147k
    code = i_initial_enter_name(minst->i_ctx_p, "DEVICEXRESOLUTION", &value);
1569
147k
    if (code < 0)
1570
0
        return code;
1571
147k
    make_real(&value, resolutions[1]);
1572
147k
    return i_initial_enter_name(minst->i_ctx_p, "DEVICEYRESOLUTION", &value);
1573
147k
}
1574
1575
int
1576
gs_main_force_dimensions(gs_main_instance *minst, const long *dimensions)
1577
11.0k
{
1578
11.0k
    ref value;
1579
11.0k
    int code = 0;
1580
1581
11.0k
    if (dimensions == NULL)
1582
11.0k
        return 0;
1583
0
    if (minst == NULL)
1584
0
        return gs_error_Fatal;
1585
1586
0
    make_true(&value);
1587
0
    code = i_initial_enter_name(minst->i_ctx_p, "FIXEDMEDIA", &value);
1588
0
    if (code < 0)
1589
0
        return code;
1590
0
    make_int(&value, dimensions[0]);
1591
0
    code = i_initial_enter_name(minst->i_ctx_p, "DEVICEWIDTH", &value);
1592
0
    if (code < 0)
1593
0
        return code;
1594
0
    make_int(&value, dimensions[1]);
1595
0
    return i_initial_enter_name(minst->i_ctx_p, "DEVICEHEIGHT", &value);
1596
0
}