Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/imain.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, 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
121M
{
72
121M
    return (gs_main_instance*)mem->gs_lib_ctx->top_of_system;
73
121M
}
74
75
/** construct main instance caller needs to retain */
76
gs_main_instance *
77
gs_main_alloc_instance(gs_memory_t *mem)
78
89.2k
{
79
89.2k
    gs_main_instance *minst;
80
89.2k
    if (mem == NULL)
81
0
        return NULL;
82
83
89.2k
    minst = (gs_main_instance *)gs_alloc_bytes_immovable(mem,
84
89.2k
                                                         sizeof(gs_main_instance),
85
89.2k
                                                         "init_main_instance");
86
89.2k
    if (minst == NULL)
87
0
        return NULL;
88
89.2k
    memset(minst, 0, sizeof(gs_main_instance));
89
89.2k
    memcpy(minst, &gs_main_instance_init_values, sizeof(gs_main_instance_init_values));
90
89.2k
    minst->heap = mem;
91
89.2k
    mem->gs_lib_ctx->top_of_system = minst;
92
89.2k
    return minst;
93
89.2k
}
94
95
op_array_table *
96
get_op_array(const gs_memory_t *mem, int size)
97
112M
{
98
112M
    gs_main_instance *minst = get_minst_from_memory(mem);
99
112M
    return op_index_op_array_table(minst->i_ctx_p,size);
100
112M
}
101
102
op_array_table *
103
get_global_op_array(const gs_memory_t *mem)
104
178k
{
105
178k
    gs_main_instance *minst = get_minst_from_memory(mem);
106
178k
    return &minst->i_ctx_p->op_array_table_global;
107
178k
}
108
109
op_array_table *
110
get_local_op_array(const gs_memory_t *mem)
111
178k
{
112
178k
    gs_main_instance *minst = get_minst_from_memory(mem);
113
178k
    return &minst->i_ctx_p->op_array_table_local;
114
178k
}
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
89.2k
{
129
89.2k
    ref *array;
130
89.2k
    int code = 0;
131
132
89.2k
    if (gs_debug_c(gs_debug_flag_init_details))
133
89.2k
        dmprintf1(minst->heap, "%% Init phase 0 started, instance "PRI_INTPTR"\n",
134
89.2k
                  (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
89.2k
    gp_init();
141
142
    /* Initialize the imager. */
143
144
    /* Reset debugging flags */
145
89.2k
#ifdef PACIFY_VALGRIND
146
89.2k
    VALGRIND_HG_DISABLE_CHECKING(gs_debug, 128);
147
89.2k
#endif
148
89.2k
    memset(gs_debug, 0, 128);
149
89.2k
    gs_log_errors = 0;  /* gs_debug['#'] = 0 */
150
151
89.2k
    gp_get_realtime(minst->base_time);
152
153
    /* Initialize the file search paths. */
154
89.2k
    array = (ref *) gs_alloc_byte_array(minst->heap, max_lib_paths, sizeof(ref),
155
89.2k
                                        "lib_path array");
156
89.2k
    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
89.2k
    make_array(&minst->lib_path.container, avm_foreign, max_lib_paths,
162
89.2k
               array);
163
89.2k
    make_array(&minst->lib_path.list, avm_foreign | a_readonly, 0,
164
89.2k
               minst->lib_path.container.value.refs);
165
89.2k
    minst->lib_path.env = NULL;
166
89.2k
    minst->lib_path.final = NULL;
167
89.2k
    minst->lib_path.count = 0;
168
89.2k
    minst->lib_path.first_is_current = 0;
169
89.2k
    minst->user_errors = 1;
170
89.2k
    minst->init_done = 0;
171
172
89.2k
fail:
173
89.2k
    if (gs_debug_c(gs_debug_flag_init_details))
174
89.2k
        dmprintf2(minst->heap, "%% Init phase 0 %s, instance "PRI_INTPTR"\n",
175
89.2k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
176
177
89.2k
    return code;
178
89.2k
}
179
180
/* Initialization to be done before constructing any objects. */
181
int
182
gs_main_init1(gs_main_instance * minst)
183
1.57M
{
184
1.57M
    gs_dual_memory_t idmem;
185
1.57M
    name_table *nt = NULL;
186
1.57M
    int code;
187
188
1.57M
    if (minst->init_done >= 1)
189
1.48M
        return 0;
190
191
89.2k
    if (gs_debug_c(gs_debug_flag_init_details))
192
89.2k
        dmprintf1(minst->heap, "%% Init phase 1 started, instance "PRI_INTPTR"\n",
193
89.2k
                  (intptr_t)minst);
194
195
89.2k
    code = ialloc_init(&idmem, minst->heap,
196
89.2k
                       minst->memory_clump_size, gs_have_level2());
197
198
89.2k
    if (code < 0)
199
0
        goto fail_early;
200
201
89.2k
    code = gs_lib_init1((gs_memory_t *)idmem.space_system);
202
89.2k
    if (code < 0)
203
0
        goto fail;
204
89.2k
    alloc_save_init(&idmem);
205
89.2k
    {
206
89.2k
        gs_memory_t *mem = (gs_memory_t *)idmem.space_system;
207
89.2k
        nt = names_init(minst->name_table_size, idmem.space_system);
208
209
89.2k
        if (nt == 0) {
210
0
            code = gs_note_error(gs_error_VMerror);
211
0
            goto fail;
212
0
        }
213
89.2k
        mem->gs_lib_ctx->gs_name_table = nt;
214
89.2k
        code = gs_register_struct_root(mem, &mem->gs_lib_ctx->name_table_root,
215
89.2k
                                       (void **)&mem->gs_lib_ctx->gs_name_table,
216
89.2k
                                       "the_gs_name_table");
217
89.2k
        if (code < 0)
218
0
            goto fail;
219
89.2k
        mem->gs_lib_ctx->client_check_file_permission = z_check_file_permissions;
220
89.2k
    }
221
0
    code = obj_init(&minst->i_ctx_p, &idmem);  /* requires name_init */
222
89.2k
    if (code < 0)
223
0
        goto fail;
224
89.2k
    minst->init_done = 1;
225
89.2k
    code = i_plugin_init(minst->i_ctx_p);
226
89.2k
    if (code < 0)
227
0
        goto fail;
228
89.2k
    code = i_iodev_init(&idmem);
229
89.2k
    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
89.2k
fail_early:
236
237
89.2k
    if (gs_debug_c(gs_debug_flag_init_details))
238
89.2k
        dmprintf2(minst->heap, "%% Init phase 1 %s, instance "PRI_INTPTR"\n",
239
89.2k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
240
241
89.2k
    return code;
242
89.2k
}
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
1.33M
{
252
1.33M
    int code;
253
254
    /* set interpreter pointer to lib_path */
255
1.33M
    minst->i_ctx_p->lib_path = &minst->lib_path;
256
257
1.33M
    code = gs_interpret(&minst->i_ctx_p, pref,
258
1.33M
                        user_errors, pexit_code, perror_object);
259
1.33M
    return code;
260
1.33M
}
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
89.2k
int gs_main_init2aux(gs_main_instance * minst) {
270
89.2k
    i_ctx_t * i_ctx_p = minst->i_ctx_p;
271
272
89.2k
    if (minst->init_done < 2) {
273
89.2k
        int code, exit_code;
274
89.2k
        ref error_object, ifa;
275
276
        /* Set up enough so that we can safely be garbage collected */
277
89.2k
        i_ctx_p->op_array_table_global = empty_table;
278
89.2k
        i_ctx_p->op_array_table_local = empty_table;
279
280
89.2k
        code = zop_init(i_ctx_p);
281
89.2k
        if (code < 0)
282
0
            return code;
283
89.2k
        code = op_init(i_ctx_p);        /* requires obj_init */
284
89.2k
        if (code < 0)
285
0
            return code;
286
287
        /* Set up the array of additional initialization files. */
288
89.2k
        make_const_string(&ifa, a_readonly | avm_foreign, gs_init_files_sizeof - 2, gs_init_files);
289
89.2k
        code = i_initial_enter_name(i_ctx_p, "INITFILES", &ifa);
290
89.2k
        if (code < 0)
291
0
            return code;
292
293
        /* Set up the array of emulator names. */
294
89.2k
        make_const_string(&ifa, a_readonly | avm_foreign, gs_emulators_sizeof - 2, gs_emulators);
295
89.2k
        code = i_initial_enter_name(i_ctx_p, "EMULATORS", &ifa);
296
89.2k
        if (code < 0)
297
0
            return code;
298
299
        /* Pass the search path. */
300
89.2k
        code = i_initial_enter_name(i_ctx_p, "LIBPATH", &minst->lib_path.list);
301
89.2k
        if (code < 0)
302
0
            return code;
303
304
        /* Execute the standard initialization file. */
305
89.2k
        code = gs_run_init_file(minst, &exit_code, &error_object);
306
89.2k
        if (code < 0)
307
28
            return code;
308
89.2k
        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
89.2k
        if ((code = reopen_device_if_required(minst)) < 0)
314
0
            return code;
315
316
89.2k
        if ((code = gs_main_run_string(minst,
317
89.2k
                "JOBSERVER "
318
89.2k
                " { false 0 .startnewjob } "
319
89.2k
                " { NOOUTERSAVE not { save pop } if } "
320
89.2k
                "ifelse", 0, &exit_code,
321
89.2k
                &error_object)) < 0)
322
0
           return code;
323
89.2k
    }
324
89.2k
    return 0;
325
89.2k
}
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
143k
{
450
143k
    int code;
451
143k
    gs_c_param_list *plist;
452
453
143k
    plist = minst->param_list;
454
143k
    if (!plist)
455
143k
        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
143k
{
474
143k
    i_ctx_t *i_ctx_p;
475
143k
    int code = gs_main_init1(minst);
476
477
143k
    if (code < 0)
478
0
        return code;
479
480
143k
    code = gs_main_push_params(minst);
481
143k
    if (code < 0)
482
0
        return code;
483
484
143k
    if (minst->init_done >= 2)
485
54.1k
        return 0;
486
487
89.2k
    if (gs_debug_c(gs_debug_flag_init_details))
488
89.2k
        dmprintf1(minst->heap, "%% Init phase 2 started, instance "PRI_INTPTR"\n",
489
89.2k
                  (intptr_t)minst);
490
491
89.2k
    code = gs_main_init2aux(minst);
492
89.2k
    if (code < 0)
493
28
       goto fail;
494
495
89.2k
    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
89.2k
    {
499
89.2k
       gx_device *pdev = gs_currentdevice(minst->i_ctx_p->pgs); /* get the current device */
500
89.2k
       gx_device_printer *ppdev = (gx_device_printer *)pdev;
501
502
89.2k
        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
89.2k
        } 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
89.2k
    }
530
531
89.2k
    if (code >= 0) {
532
89.2k
        if (gs_debug_c(':'))
533
0
            print_resource_usage(minst, &gs_imemory, "Start");
534
89.2k
        gp_readline_init(&minst->readline_data, minst->heap); /* lgtm [cpp/useless-expression] */
535
89.2k
    }
536
537
89.2k
fail:
538
89.2k
    if (gs_debug_c(gs_debug_flag_init_details))
539
89.2k
        dmprintf2(minst->heap, "%% Init phase 2 %s, instance "PRI_INTPTR"\n",
540
89.2k
                  code < 0 ? "failed" : "done", (intptr_t)minst);
541
542
89.2k
    return code;
543
89.2k
}
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
9.28M
{
577
9.28M
    ref *paths;
578
9.28M
    int listlen = r_size(&minst->lib_path.list); /* The real number of entries currently in the list */
579
9.28M
    byte *newstr;
580
9.28M
    int code;
581
582
    /* Extend the container if required */
583
9.28M
    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
9.28M
    newstr = gs_alloc_string(minst->heap, strlen, "lib_path_add");
593
9.28M
    if (newstr == NULL)
594
0
        return gs_error_VMerror;
595
9.28M
    memcpy(newstr, str, strlen);
596
597
    /* Shuffle up the entries */
598
9.28M
    paths = &minst->lib_path.container.value.refs[pos];
599
9.28M
    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
9.28M
    make_const_string(paths, avm_foreign | a_readonly,
604
9.28M
                      strlen,
605
9.28M
                      newstr);
606
607
    /* Update the list length */
608
9.28M
    r_set_size(&minst->lib_path.list, listlen+1);
609
610
9.28M
    return 0;
611
9.28M
}
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
2.14M
{
619
2.14M
    gs_file_path * pfp = &minst->lib_path;
620
2.14M
    uint len = r_size(&pfp->list);
621
2.14M
    const char *dpath = dirs;
622
2.14M
    int code;
623
624
2.14M
    if (dirs == 0)
625
0
        return 0;
626
627
9.28M
    for (;;) {                  /* Find the end of the next directory name. */
628
9.28M
        const char *npath = dpath;
629
630
318M
        while (*npath != 0 && *npath != gp_file_name_list_separator)
631
309M
            npath++;
632
9.28M
        if (npath > dpath) {
633
9.28M
            code = gs_add_control_path_len(minst->heap, gs_permit_file_reading, dpath, npath - dpath);
634
9.28M
            if (code < 0) return code;
635
636
9.28M
            code = lib_path_insert_copy_of_string(minst, len, npath - dpath, dpath);
637
9.28M
            if (code < 0)
638
0
                return code;
639
9.28M
            len++;
640
            /* Update length/count so we don't lose entries if a later
641
             * iteration fails. */
642
9.28M
            r_set_size(&pfp->list, len);
643
9.28M
        }
644
9.28M
        if (!*npath)
645
2.14M
            break;
646
7.13M
        dpath = npath + 1;
647
7.13M
    }
648
2.14M
    return 0;
649
2.14M
}
650
651
static void
652
set_lib_path_length(gs_main_instance * minst, int newsize)
653
803k
{
654
803k
    gs_file_path * pfp = &minst->lib_path;
655
803k
    uint len = r_size(&pfp->list); /* Yes, list, not container */
656
803k
    uint i;
657
658
    /* Free any entries that are discarded by us shortening the list */
659
10.0M
    for (i = newsize; i < len; i++)
660
9.28M
        gs_free_object(minst->heap, pfp->container.value.refs[i].value.bytes, "lib_path entry");
661
803k
    r_set_size(&pfp->list, newsize);
662
803k
}
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
713k
{
696
713k
    int code = 0;
697
713k
    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
713k
    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
713k
    } 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
713k
    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
713k
    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
713k
    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
4.99M
    for (i = 0; i < gx_io_device_table_count; i++) {
759
4.99M
        const gx_io_device *iodev = gx_io_device_table[i];
760
4.99M
        const char *dname = iodev->dname;
761
4.99M
        const char *fcheckname = "Resource/Init/gs_init.ps";
762
763
4.99M
        if (dname && strlen(dname) == 5 && !memcmp("%rom%", dname, 5)) {
764
713k
            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
713k
            int code = iodev->procs.file_status((gx_io_device *)iodev, fcheckname, &pstat);
770
713k
            if (code != gs_error_unregistered && code != gs_error_undefinedfilename){
771
713k
                have_rom_device = 1;
772
713k
            }
773
713k
            break;
774
713k
        }
775
4.99M
    }
776
713k
    if (have_rom_device) {
777
713k
        code = lib_path_add(minst, "%rom%Resource/Init/");
778
713k
        if (code < 0)
779
0
            return code;
780
713k
        code = lib_path_add(minst, "%rom%lib/");
781
713k
    }
782
0
    else code = 0;
783
784
713k
    if (minst->lib_path.final != NULL && code >= 0)
785
713k
        code = lib_path_add(minst, minst->lib_path.final);
786
713k
    return code;
787
713k
}
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
89.2k
{
793
    /* This is a separate procedure only to avoid tying up */
794
    /* extra stack space while running the file. */
795
89.2k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
796
89.2k
#define maxfn 2048
797
89.2k
    char fn[maxfn];
798
89.2k
    uint len;
799
800
89.2k
    return lib_file_open(&minst->lib_path, imemory,
801
89.2k
                         NULL, /* Don't check permissions here, because permlist
802
                                  isn't ready running init files. */
803
89.2k
                          file_name, strlen(file_name), fn, maxfn, &len, pfile);
804
89.2k
}
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
89.2k
{
821
89.2k
    gs_main_set_lib_paths(minst);
822
89.2k
    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
89.2k
    r_set_attrs(pfref, a_execute + a_executable);
829
89.2k
    return 0;
830
89.2k
}
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
89.2k
{
836
89.2k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
837
89.2k
    ref ifile;
838
89.2k
    ref first_token;
839
89.2k
    int code;
840
89.2k
    scanner_state state;
841
842
89.2k
    gs_main_set_lib_paths(minst);
843
89.2k
    code = gs_main_run_file_open(minst, gs_init_file, &ifile);
844
89.2k
    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
89.2k
    gs_scanner_init(&state, &ifile);
851
89.2k
    code = gs_scan_token(i_ctx_p, &first_token, &state);
852
89.2k
    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
89.2k
    *++osp = first_token;
860
89.2k
    r_set_attrs(&ifile, a_executable);
861
89.2k
    return gs_main_interpret(minst, &ifile, minst->user_errors,
862
89.2k
                        pexit_code, perror_object);
863
89.2k
}
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
446k
{
870
446k
    return gs_main_run_string_with_length(minst, str, (uint) strlen(str),
871
446k
                                          user_errors,
872
446k
                                          pexit_code, perror_object);
873
446k
}
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
446k
{
878
446k
    int code;
879
880
446k
    code = gs_main_run_string_begin(minst, user_errors,
881
446k
                                    pexit_code, perror_object);
882
446k
    if (code < 0)
883
0
        return code;
884
446k
    code = gs_main_run_string_continue(minst, str, length, user_errors,
885
446k
                                       pexit_code, perror_object);
886
446k
    if (code != gs_error_NeedInput)
887
89.2k
        return code;
888
889
356k
    code = gs_main_run_string_end(minst, user_errors,
890
356k
                                  pexit_code, perror_object);
891
    /* Not okay for user to use .needinput
892
     * This treats it as a fatal error.
893
     */
894
356k
    if (code == gs_error_NeedInput)
895
0
        return_error(gs_error_Fatal);
896
356k
    return code;
897
356k
}
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
446k
{
904
446k
    const char *setup = ".runstringbegin";
905
446k
    ref rstr;
906
446k
    int code;
907
908
446k
    gs_main_set_lib_paths(minst);
909
446k
    make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
910
446k
                      strlen(setup), (const byte *)setup);
911
446k
    code = gs_main_interpret(minst, &rstr, user_errors, pexit_code,
912
446k
                             perror_object);
913
446k
    return (code == gs_error_NeedInput ? 0 : code == 0 ? gs_error_Fatal : code);
914
446k
}
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
446k
{
920
446k
    ref rstr;
921
922
446k
    if (length == 0)
923
0
        return 0;               /* empty string signals EOF */
924
446k
    make_const_string(&rstr, avm_foreign | a_readonly, length,
925
446k
                      (const byte *)str);
926
446k
    return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
927
446k
                             perror_object);
928
446k
}
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
356k
{
942
356k
    ref rstr;
943
944
356k
    make_empty_const_string(&rstr, avm_foreign | a_readonly);
945
356k
    return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
946
356k
                             perror_object);
947
356k
}
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
1031
0
    if (code < 0)
1032
0
        return code;
1033
0
    *ref_stack_index(&o_stack, 0L) = *pvalue;
1034
0
    return 0;
1035
0
}
1036
1037
int
1038
gs_push_boolean(gs_main_instance * minst, bool value)
1039
0
{
1040
0
    ref vref;
1041
1042
0
    make_bool(&vref, value);
1043
0
    return push_value(minst, &vref);
1044
0
}
1045
1046
int
1047
gs_push_integer(gs_main_instance * minst, long value)
1048
0
{
1049
0
    ref vref;
1050
1051
0
    make_int(&vref, value);
1052
0
    return push_value(minst, &vref);
1053
0
}
1054
1055
int
1056
gs_push_real(gs_main_instance * minst, double value)
1057
0
{
1058
0
    ref vref;
1059
1060
0
    make_real(&vref, value);
1061
0
    return push_value(minst, &vref);
1062
0
}
1063
1064
int
1065
gs_push_string(gs_main_instance * minst, byte * chars, uint length,
1066
               bool read_only)
1067
0
{
1068
0
    ref vref;
1069
1070
0
    make_string(&vref, avm_foreign | (read_only ? a_readonly : a_all),
1071
0
                length, (byte *) chars);
1072
0
    return push_value(minst, &vref);
1073
0
}
1074
1075
static int
1076
pop_value(i_ctx_t *i_ctx_p, ref * pvalue)
1077
0
{
1078
0
    if (!ref_stack_count(&o_stack))
1079
0
        return_error(gs_error_stackunderflow);
1080
0
    *pvalue = *ref_stack_index(&o_stack, 0L);
1081
0
    return 0;
1082
0
}
1083
1084
int
1085
gs_pop_boolean(gs_main_instance * minst, bool * result)
1086
0
{
1087
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1088
0
    ref vref;
1089
0
    int code = pop_value(i_ctx_p, &vref);
1090
1091
0
    if (code < 0)
1092
0
        return code;
1093
0
    check_type_only(vref, t_boolean);
1094
0
    *result = vref.value.boolval;
1095
0
    ref_stack_pop(&o_stack, 1);
1096
0
    return 0;
1097
0
}
1098
1099
int
1100
gs_pop_integer(gs_main_instance * minst, long *result)
1101
0
{
1102
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1103
0
    ref vref;
1104
0
    int code = pop_value(i_ctx_p, &vref);
1105
1106
0
    if (code < 0)
1107
0
        return code;
1108
0
    check_type_only(vref, t_integer);
1109
0
    *result = vref.value.intval;
1110
0
    ref_stack_pop(&o_stack, 1);
1111
0
    return 0;
1112
0
}
1113
1114
int
1115
gs_pop_real(gs_main_instance * minst, float *result)
1116
0
{
1117
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1118
0
    ref vref;
1119
0
    int code = pop_value(i_ctx_p, &vref);
1120
1121
0
    if (code < 0)
1122
0
        return code;
1123
0
    switch (r_type(&vref)) {
1124
0
        case t_real:
1125
0
            *result = vref.value.realval;
1126
0
            break;
1127
0
        case t_integer:
1128
0
            *result = (float)(vref.value.intval);
1129
0
            break;
1130
0
        default:
1131
0
            return_error(gs_error_typecheck);
1132
0
    }
1133
0
    ref_stack_pop(&o_stack, 1);
1134
0
    return 0;
1135
0
}
1136
1137
int
1138
gs_pop_string(gs_main_instance * minst, gs_string * result)
1139
0
{
1140
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1141
0
    ref vref;
1142
0
    int code = pop_value(i_ctx_p, &vref);
1143
1144
0
    if (code < 0)
1145
0
        return code;
1146
0
    switch (r_type(&vref)) {
1147
0
        case t_name:
1148
0
            name_string_ref(minst->heap, &vref, &vref);
1149
0
            code = 1;
1150
0
            goto rstr;
1151
0
        case t_string:
1152
0
            code = (r_has_attr(&vref, a_write) ? 0 : 1);
1153
0
          rstr:result->data = vref.value.bytes;
1154
0
            result->size = r_size(&vref);
1155
0
            break;
1156
0
        default:
1157
0
            return_error(gs_error_typecheck);
1158
0
    }
1159
0
    ref_stack_pop(&o_stack, 1);
1160
0
    return code;
1161
0
}
1162
1163
/* ------ Termination ------ */
1164
1165
/* Get the names of temporary files.
1166
 * Each name is null terminated, and the last name is
1167
 * terminated by a double null.
1168
 * We retrieve the names of temporary files just before
1169
 * the interpreter finishes, and then delete the files
1170
 * after the interpreter has closed all files.
1171
 */
1172
static char *gs_main_tempnames(gs_main_instance *minst)
1173
89.2k
{
1174
89.2k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1175
89.2k
    ref *SAFETY;
1176
89.2k
    ref *tempfiles;
1177
89.2k
    ref keyval[2];      /* for key and value */
1178
89.2k
    char *tempnames = NULL;
1179
89.2k
    int i;
1180
89.2k
    int idict;
1181
89.2k
    int len = 0;
1182
89.2k
    const byte *data = NULL;
1183
89.2k
    uint size;
1184
89.2k
    if (minst->init_done >= 2) {
1185
89.2k
        if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
1186
89.2k
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0)
1187
0
            return NULL;
1188
        /* get lengths of temporary filenames */
1189
89.2k
        idict = dict_first(tempfiles);
1190
130k
        while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
1191
40.8k
            if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0)
1192
40.8k
                len += size + 1;
1193
40.8k
        }
1194
89.2k
        if (len != 0)
1195
40.8k
            tempnames = (char *)malloc(len+1);
1196
89.2k
        if (tempnames) {
1197
40.8k
            memset(tempnames, 0, len+1);
1198
            /* copy temporary filenames */
1199
40.8k
            idict = dict_first(tempfiles);
1200
40.8k
            i = 0;
1201
81.7k
            while ((idict = dict_next(tempfiles, idict, &keyval[0])) >= 0) {
1202
40.8k
                if (obj_string_data(minst->heap, &keyval[0], &data, &size) >= 0) {
1203
40.8k
                    memcpy(tempnames+i, (const char *)data, size);
1204
40.8k
                    i+= size;
1205
40.8k
                    tempnames[i++] = '\0';
1206
40.8k
                }
1207
40.8k
            }
1208
40.8k
        }
1209
89.2k
    }
1210
89.2k
    return tempnames;
1211
89.2k
}
1212
1213
static void
1214
gs_finit_push_systemdict(i_ctx_t *i_ctx_p)
1215
89.2k
{
1216
89.2k
    if (i_ctx_p == NULL)
1217
0
        return;
1218
89.2k
    if (dsp == dstop ) {
1219
2
        if (ref_stack_extend(&d_stack, 1) < 0) {
1220
            /* zend() cannot fail */
1221
0
            (void)zend(i_ctx_p);
1222
0
        }
1223
2
    }
1224
89.2k
    dsp++;
1225
89.2k
    ref_assign(dsp, systemdict);
1226
89.2k
}
1227
1228
/* Free all resources and return. */
1229
int
1230
gs_main_finit(gs_main_instance * minst, int exit_status, int env_code)
1231
89.2k
{
1232
89.2k
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1233
89.2k
    gs_dual_memory_t dmem = {0};
1234
89.2k
    int exit_code;
1235
89.2k
    ref error_object;
1236
89.2k
    char *tempnames = NULL;
1237
89.2k
    gs_lib_ctx_core_t *core;
1238
1239
    /* NB: need to free gs_name_table
1240
     */
1241
1242
    /*
1243
     * Previous versions of this code closed the devices in the
1244
     * device list here.  Since these devices are now prototypes,
1245
     * they cannot be opened, so they do not need to be closed;
1246
     * alloc_restore_all will close dynamically allocated devices.
1247
     */
1248
89.2k
    tempnames = gs_main_tempnames(minst);
1249
1250
    /* by the time we get here, we *must* avoid any random redefinitions of
1251
     * operators etc, so we push systemdict onto the top of the dict stack.
1252
     * We do this in C to avoid running into any other re-defininitions in the
1253
     * Postscript world.
1254
     */
1255
89.2k
    gs_finit_push_systemdict(i_ctx_p);
1256
1257
    /* We have to disable BGPrint before we call interp_reclaim() to prevent the
1258
     * parent rendering thread initialising for the next page, whilst we are
1259
     * removing objects it may want to access - for example, the I/O device table.
1260
     * We also have to mess with the BeginPage/EndPage procs so that we don't
1261
     * trigger a spurious extra page to be emitted.
1262
     */
1263
89.2k
    if (minst->init_done >= 2) {
1264
89.2k
        gs_main_run_string(minst,
1265
89.2k
            "/BGPrint /GetDeviceParam .special_op \
1266
89.2k
            {{ <</BeginPage {pop} /EndPage {pop pop //false } \
1267
89.2k
              /BGPrint false /NumRenderingThreads 0>> setpagedevice} if} if \
1268
89.2k
              serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse \
1269
89.2k
              .systemvar exec",
1270
89.2k
            0 , &exit_code, &error_object);
1271
89.2k
    }
1272
1273
    /*
1274
     * Close the "main" device, because it may need to write out
1275
     * data before destruction. pdfwrite needs so.
1276
     */
1277
89.2k
    if (minst->init_done >= 2) {
1278
89.2k
        int code = 0;
1279
1280
89.2k
        if (idmemory->reclaim != 0) {
1281
89.2k
            code = interp_reclaim(&minst->i_ctx_p, avm_global);
1282
1283
            /* We ignore gs_error_VMerror because it comes from gs_vmreclaim()
1284
            calling context_state_load(), and we don't seem to depend on the
1285
            missing fields. */
1286
89.2k
            if (code == gs_error_VMerror) {
1287
0
                if (exit_status == 0 || exit_status == gs_error_Quit) {
1288
0
                    exit_status = gs_error_VMerror;
1289
0
                }
1290
0
            }
1291
89.2k
            else if (code < 0) {
1292
0
                ref error_name;
1293
0
                if (tempnames)
1294
0
                    free(tempnames);
1295
1296
0
                if (gs_errorname(i_ctx_p, code, &error_name) >= 0) {
1297
0
                    char err_str[32] = {0};
1298
0
                    name_string_ref(imemory, &error_name, &error_name);
1299
0
                    memcpy(err_str, error_name.value.const_bytes, r_size(&error_name));
1300
0
                    emprintf2(imemory, "ERROR: %s (%d) reclaiming the memory while the interpreter finalization.\n", err_str, code);
1301
0
                }
1302
0
                else {
1303
0
                    emprintf1(imemory, "UNKNOWN ERROR %d reclaiming the memory while the interpreter finalization.\n", code);
1304
0
                }
1305
#ifdef MEMENTO
1306
                if (Memento_squeezing() && code != gs_error_VMerror ) return gs_error_Fatal;
1307
#endif
1308
0
                return gs_error_Fatal;
1309
0
            }
1310
89.2k
            i_ctx_p = minst->i_ctx_p; /* interp_reclaim could change it. */
1311
89.2k
        }
1312
1313
89.2k
        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL &&
1314
89.2k
            gx_device_is_null(i_ctx_p->pgs->device)) {
1315
            /* if the job replaced the device with the nulldevice, we we need to grestore
1316
               away that device, so the block below can properly dispense
1317
               with the default device.
1318
             */
1319
26
            int code = gs_grestoreall(i_ctx_p->pgs);
1320
26
            if (code < 0) {
1321
0
                free(tempnames);
1322
0
                return_error(gs_error_Fatal);
1323
0
            }
1324
26
        }
1325
1326
89.2k
        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL) {
1327
89.2k
            gx_device *pdev = i_ctx_p->pgs->device;
1328
89.2k
            const char * dname = pdev->dname;
1329
89.2k
            gs_gc_root_t dev_root;
1330
89.2k
            gs_gc_root_t *dev_root_ptr = &dev_root;
1331
            /* There is a chance that, during the call to gs_main_run_string(), the interpreter may
1332
             * decide to call the garbager - the device is in gc memory, and the only reference to it
1333
             * (in the gstate) has been removed, thus it can be destroyed by the garbager.
1334
             * Counter-intuitively, adjusting the reference count makes not difference to that.
1335
             * Register the device as a gc 'root' so it will be implicitely marked by garbager, and
1336
             * and thus surive until control returns here.
1337
             */
1338
89.2k
            if (gs_register_struct_root(pdev->memory, &dev_root_ptr, (void **)&pdev, "gs_main_finit") < 0) {
1339
0
                free(tempnames);
1340
0
                return_error(gs_error_Fatal);
1341
0
            }
1342
1343
            /* make sure device doesn't isn't freed by .uninstalldevice */
1344
89.2k
            rc_adjust(pdev, 1, "gs_main_finit");
1345
            /* deactivate the device just before we close it for the last time */
1346
89.2k
            gs_main_run_string(minst,
1347
                /* we need to do the 'quit' so we don't loop for input (double quit) */
1348
89.2k
                ".uninstallpagedevice serverdict \
1349
89.2k
                /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemvar exec",
1350
89.2k
                0 , &exit_code, &error_object);
1351
89.2k
            code = gs_closedevice(pdev);
1352
89.2k
            if (code < 0) {
1353
2
                ref error_name;
1354
2
                if (gs_errorname(i_ctx_p, code, &error_name) >= 0) {
1355
0
                    char err_str[32] = {0};
1356
0
                    name_string_ref(imemory, &error_name, &error_name);
1357
0
                    memcpy(err_str, error_name.value.const_bytes, r_size(&error_name));
1358
0
                    emprintf3(imemory, "ERROR: %s (%d) on closing %s device.\n", err_str, code, dname);
1359
0
                }
1360
2
                else {
1361
2
                    emprintf2(imemory, "UNKNOWN ERROR %d closing %s device.\n", code, dname);
1362
2
               }
1363
2
            }
1364
89.2k
            gs_unregister_root(pdev->memory, dev_root_ptr, "gs_main_finit");
1365
89.2k
            rc_decrement(pdev, "gs_main_finit");                /* device might be freed */
1366
89.2k
            if (exit_status == 0 || exit_status == gs_error_Quit)
1367
89.2k
                exit_status = code;
1368
89.2k
        }
1369
1370
      /* Flush stdout and stderr */
1371
89.2k
      gs_main_run_string(minst,
1372
89.2k
        "(%stdout) (w) file closefile (%stderr) (w) file closefile \
1373
89.2k
        serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemexec \
1374
89.2k
          systemdict /savedinitialgstate .forceundef",
1375
89.2k
        0 , &exit_code, &error_object);
1376
89.2k
    }
1377
89.2k
    gp_readline_finit(minst->readline_data);
1378
89.2k
    gs_free_object(minst->heap, minst->saved_pages_initial_arg, "gs_main_finit");
1379
89.2k
    i_ctx_p = minst->i_ctx_p;   /* get current interp context */
1380
89.2k
    if (gs_debug_c(':')) {
1381
0
        print_resource_usage(minst, &gs_imemory, "Final");
1382
0
        dmprintf1(minst->heap, "%% Exiting instance "PRI_INTPTR"\n", (intptr_t)minst);
1383
0
    }
1384
    /* Do the equivalent of a restore "past the bottom". */
1385
    /* This will release all memory, close all open files, etc. */
1386
89.2k
    if (minst->init_done >= 1) {
1387
89.2k
        gs_memory_t *mem_raw = i_ctx_p->memory.current->non_gc_memory;
1388
89.2k
        i_plugin_holder *h = i_ctx_p->plugin_list;
1389
1390
89.2k
        dmem = *idmemory;
1391
89.2k
        env_code = alloc_restore_all(i_ctx_p);
1392
89.2k
        if (env_code < 0)
1393
0
            emprintf1(mem_raw,
1394
89.2k
                      "ERROR %d while the final restore. See gs/psi/ierrors.h for code explanation.\n",
1395
89.2k
                      env_code);
1396
89.2k
        i_iodev_finit(&dmem);
1397
89.2k
        i_plugin_finit(mem_raw, h);
1398
89.2k
    }
1399
1400
    /* clean up redirected stdout */
1401
89.2k
    core = minst->heap->gs_lib_ctx->core;
1402
89.2k
    if (core->fstdout2
1403
89.2k
        && (gp_get_file(core->fstdout2) != core->fstdout)
1404
89.2k
        && (gp_get_file(core->fstdout2) != core->fstderr)) {
1405
89.2k
        gp_fclose(core->fstdout2);
1406
89.2k
        core->fstdout2 = NULL;
1407
89.2k
    }
1408
1409
89.2k
    minst->heap->gs_lib_ctx->core->stdout_is_redirected = 0;
1410
89.2k
    minst->heap->gs_lib_ctx->core->stdout_to_stderr = 0;
1411
    /* remove any temporary files, after ghostscript has closed files */
1412
89.2k
    if (tempnames) {
1413
40.8k
        char *p = tempnames;
1414
81.7k
        while (*p) {
1415
40.8k
            gp_unlink(minst->heap, p);
1416
40.8k
            p += strlen(p) + 1;
1417
40.8k
        }
1418
40.8k
        free(tempnames);
1419
40.8k
    }
1420
89.2k
    gs_lib_finit(exit_status, env_code, minst->heap);
1421
1422
89.2k
    set_lib_path_length(minst, 0);
1423
89.2k
    gs_free_object(minst->heap, minst->lib_path.container.value.refs, "lib_path array");
1424
89.2k
    if (minst->init_done == 0 && i_ctx_p) {
1425
        /* This fixes leak if memento forces failure in gs_main_init1(). */
1426
0
        dmem = *idmemory;
1427
0
    }
1428
89.2k
    ialloc_finit(&dmem);
1429
89.2k
    return exit_status;
1430
89.2k
}
1431
int
1432
gs_to_exit_with_code(const gs_memory_t *mem, int exit_status, int code)
1433
89.2k
{
1434
89.2k
    return gs_main_finit(get_minst_from_memory(mem), exit_status, code);
1435
89.2k
}
1436
int
1437
gs_to_exit(const gs_memory_t *mem, int exit_status)
1438
89.2k
{
1439
89.2k
    return gs_to_exit_with_code(mem, exit_status, 0);
1440
89.2k
}
1441
void
1442
gs_abort(const gs_memory_t *mem)
1443
0
{
1444
    /* In previous versions, we tried to do a cleanup (using gs_to_exit),
1445
     * but more often than not, that will trip another abort and create
1446
     * an infinite recursion. So just abort without trying to cleanup.
1447
     */
1448
0
    gp_do_exit(1);
1449
0
}
1450
1451
/* ------ Debugging ------ */
1452
1453
/* Print resource usage statistics. */
1454
void
1455
print_resource_usage(const gs_main_instance * minst, gs_dual_memory_t * dmem,
1456
                     const char *msg)
1457
0
{
1458
0
    ulong used = 0;   /* this we accumulate for the PS memories */
1459
0
    long utime[2];
1460
0
    int i;
1461
0
    gs_memory_status_t status;
1462
1463
0
    gp_get_realtime(utime);
1464
1465
0
    for (i = 0; i < countof(dmem->spaces_indexed); ++i) {
1466
0
        gs_ref_memory_t *mem = dmem->spaces_indexed[i];
1467
1468
0
        if (mem != 0 && (i == 0 || mem != dmem->spaces_indexed[i - 1])) {
1469
0
            gs_ref_memory_t *mem_stable =
1470
0
                (gs_ref_memory_t *)gs_memory_stable((gs_memory_t *)mem);
1471
1472
0
            gs_memory_status((gs_memory_t *)mem, &status);
1473
0
            used += status.used;
1474
0
            if (mem_stable != mem) {
1475
0
                gs_memory_status((gs_memory_t *)mem_stable, &status);
1476
0
                used += status.used;
1477
0
            }
1478
0
        }
1479
0
    }
1480
    /* Now get the overall values from the heap memory */
1481
0
    gs_memory_status(minst->heap, &status);
1482
0
    dmprintf5(minst->heap, "%% %s time = %g, memory allocated = %lu, used = %lu, max_used = %lu\n",
1483
0
              msg, utime[0] - minst->base_time[0] +
1484
0
              (utime[1] - minst->base_time[1]) / 1000000000.0,
1485
0
              status.allocated, used, status.max_used);
1486
0
}
1487
1488
/* Dump the stacks after interpretation */
1489
void
1490
gs_main_dump_stack(gs_main_instance *minst, int code, ref * perror_object)
1491
0
{
1492
0
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
1493
1494
0
    zflush(i_ctx_p);            /* force out buffered output */
1495
0
    dmprintf1(minst->heap, "\nUnexpected interpreter error %d.\n", code);
1496
0
    if (perror_object != 0) {
1497
0
        dmputs(minst->heap, "Error object: ");
1498
0
        debug_print_ref(minst->heap, perror_object);
1499
0
        dmputc(minst->heap, '\n');
1500
0
    }
1501
0
    debug_dump_stack(minst->heap, &o_stack, "Operand stack");
1502
0
    debug_dump_stack(minst->heap, &e_stack, "Execution stack");
1503
0
    debug_dump_stack(minst->heap, &d_stack, "Dictionary stack");
1504
0
}
1505
1506
int
1507
gs_main_force_resolutions(gs_main_instance * minst, const float *resolutions)
1508
89.2k
{
1509
89.2k
    ref value;
1510
89.2k
    int code;
1511
1512
89.2k
    if (resolutions == NULL)
1513
0
        return 0;
1514
1515
89.2k
    if (minst == NULL)
1516
0
        return gs_error_Fatal;
1517
1518
89.2k
    make_true(&value);
1519
89.2k
    code = i_initial_enter_name(minst->i_ctx_p, "FIXEDRESOLUTION", &value);
1520
89.2k
    if (code < 0)
1521
0
        return code;
1522
89.2k
    make_real(&value, resolutions[0]);
1523
89.2k
    code = i_initial_enter_name(minst->i_ctx_p, "DEVICEXRESOLUTION", &value);
1524
89.2k
    if (code < 0)
1525
0
        return code;
1526
89.2k
    make_real(&value, resolutions[1]);
1527
89.2k
    return i_initial_enter_name(minst->i_ctx_p, "DEVICEYRESOLUTION", &value);
1528
89.2k
}
1529
1530
int
1531
gs_main_force_dimensions(gs_main_instance *minst, const long *dimensions)
1532
0
{
1533
0
    ref value;
1534
0
    int code = 0;
1535
1536
0
    if (dimensions == NULL)
1537
0
        return 0;
1538
0
    if (minst == NULL)
1539
0
        return gs_error_Fatal;
1540
1541
0
    make_true(&value);
1542
0
    code = i_initial_enter_name(minst->i_ctx_p, "FIXEDMEDIA", &value);
1543
0
    if (code < 0)
1544
0
        return code;
1545
0
    make_int(&value, dimensions[0]);
1546
0
    code = i_initial_enter_name(minst->i_ctx_p, "DEVICEWIDTH", &value);
1547
0
    if (code < 0)
1548
0
        return code;
1549
0
    make_int(&value, dimensions[1]);
1550
0
    return i_initial_enter_name(minst->i_ctx_p, "DEVICEHEIGHT", &value);
1551
0
}