Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pl/plmain.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
/* plmain.c */
18
/* Main program command-line interpreter for PCL interpreters */
19
#include "std.h"
20
#include "gserrors.h"
21
#include "ctype_.h"
22
#include "string_.h"
23
#include <stdlib.h> /* atof */
24
#include "assert_.h"
25
#include "gdebug.h"
26
#include "gscdefs.h"
27
#include "gsio.h"
28
#include "gstypes.h"
29
#include "gserrors.h"
30
#include "gsmemory.h"
31
#include "gsmalloc.h"
32
#include "gsmchunk.h"
33
#include "gsstruct.h"
34
#include "gxalloc.h"
35
#include "gsalloc.h"
36
#include "gsargs.h"
37
#include "gp.h"
38
#include "gsdevice.h"
39
#include "gxdevice.h"
40
#include "gxdevsop.h"       /* for gxdso_* */
41
#include "gxclpage.h"
42
#include "gdevprn.h"
43
#include "gsparam.h"
44
#include "gslib.h"
45
#include "pjtop.h"
46
#include "plparse.h"
47
#include "plmain.h"
48
#include "pltop.h"
49
#include "plapi.h"
50
#include "gslibctx.h"
51
#include "gsicc_manage.h"
52
#include "gxiodev.h"
53
#include "stream.h"
54
#include "strmio.h"
55
#include "gp.h"
56
57
/* includes for the display device */
58
#include "gdevdevn.h"
59
#include "gsequivc.h"
60
#include "gdevdsp.h"
61
#include "gdevdsp2.h"
62
63
#define OMIT_SAVED_PAGES
64
#define OMIT_SAVED_PAGES_TEST
65
66
/* if we are not doing saved_pages, omit saved-pages-test mode as well */
67
#ifdef OMIT_SAVED_PAGES
68
#   ifndef OMIT_SAVED_PAGES_TEST
69
#       define OMIT_SAVED_PAGES_TEST
70
#   endif
71
#endif
72
/* Include the extern for the device list. */
73
extern_gs_lib_device_list();
74
75
/* Extern for PDL(s): currently in one of: plimpl.c (XL & PCL), */
76
/* pcimpl.c (PCL only), or pximpl (XL only) depending on make configuration.*/
77
extern pl_interp_implementation_t *pdl_implementations[];    /* zero-terminated list */
78
79
114
#define PJL_VERSION_STRING GS_STRINGIZE(PJLVERSION)
80
81
/* Define the usage message. */
82
static const char *pl_usage = "\
83
Usage: %s [option* file]+...\n\
84
Options: -dNOPAUSE -E[#] -h -L<PCL|PCLXL> -K<maxK> -l<PCL5C|PCL5E|RTL> -Z...\n\
85
         -sDEVICE=<dev> -g<W>x<H> -r<X>[x<Y>] -d{First|Last}Page=<#>\n\
86
         -H<l>x<b>x<r>x<t> -dNOCACHE\n\
87
         -sOutputFile=<file> (-s<option>=<string> | -d<option>[=<value>])*\n\
88
         -J<PJL commands>\n";
89
90
/* Simple structure to hold the contents of a buffered file.
91
 * We have a list of chunks of data held in an index. */
92
typedef struct
93
{
94
    gs_memory_t *memory;
95
    size_t index_max; /* Size of the index */
96
    size_t len;
97
    byte **index;
98
} buffered_file;
99
100
/* Work in 1 meg chunks for now. */
101
0
#define BUFFERED_FILE_CHUNK_SHIFT 20
102
0
#define BUFFERED_FILE_CHUNK_SIZE (1<<BUFFERED_FILE_CHUNK_SHIFT)
103
104
typedef enum {
105
    /* Default: Never reset resources automatically on job changes. */
106
    PL_RESET_RESOURCES_NEVER = 0,
107
108
    /* Reset resources whenver we drop back to PJL. */
109
    PL_RESET_RESOURCES_ON_PJL = 1,
110
111
    /* Reset resources whenever we change language (other than to drop
112
     * back to PJL). */
113
    PL_RESET_RESOURCES_ON_LANGUAGE_CHANGE = 2
114
} pl_resource_reset;
115
116
/*
117
 * Main instance for all interpreters.
118
 */
119
struct pl_main_instance_s
120
{
121
    /* The following are set at initialization time. */
122
    gs_memory_t *memory;
123
    gs_memory_t *device_memory;
124
    long base_time[2];          /* starting time */
125
    int error_report;           /* -E# */
126
    bool pause;                 /* -dNOPAUSE => false */
127
    bool safer;                  /* -dNOSAFER => false */
128
    gx_device *device;
129
    gs_gc_root_t *device_root;
130
    int device_index;
131
    pl_main_get_codepoint_t *get_codepoint;
132
                                /* Get next 'unicode' codepoint */
133
134
    pl_interp_implementation_t *implementation; /*-L<Language>*/
135
136
    char pcl_personality[6];    /* a character string to set pcl's
137
                                   personality - rtl, pcl5c, pcl5e, and
138
                                   pcl == default.  NB doesn't belong here. */
139
    bool interpolate;
140
    bool nocache;
141
    bool page_set_on_command_line;
142
    long page_size[2];
143
    bool res_set_on_command_line;
144
    float res[2];
145
    bool high_level_device;
146
    bool supports_rasterops;
147
#ifndef OMIT_SAVED_PAGES_TEST
148
    bool saved_pages_test_mode;
149
#endif
150
    bool pjl_from_args; /* pjl was passed on the command line */
151
    int scanconverter;
152
    /* we have to store these in the main instance until the languages
153
       state is sufficiently initialized to set the parameters. */
154
    char *piccdir;
155
    char *pdefault_gray_icc;
156
    char *pdefault_rgb_icc;
157
    char *pdefault_cmyk_icc;
158
    gs_c_param_list params;
159
    arg_list args;
160
    pl_interp_implementation_t **implementations;
161
    pl_interp_implementation_t *curr_implementation;
162
163
    /* We keep track of the last (non PJL) implementation we used.
164
     * This is used to conditionally reset soft fonts etc. */
165
    pl_interp_implementation_t *prev_non_pjl_implementation;
166
167
    pl_resource_reset reset_resources;
168
169
    /* When processing data via 'run_string', interpreters may not
170
     * completely consume the data they are passed each time. We use
171
     * this buffer to carry over data between calls. */
172
    byte *buf_ptr;
173
    int buf_fill;
174
    int buf_max;
175
176
    void *display; /* display device pointer - to support legacy API. Will
177
                    * be removed. */
178
    bool detect_runstring_language;
179
    bool revert_to_pjl_after_runstring;
180
181
    bool mid_runstring; /* True if we are mid-runstring */
182
183
    void *buffering_runstring_as_file;
184
185
    /* The state for gsapi param enumeration */
186
    gs_c_param_list enum_params;
187
    gs_param_enumerator_t enum_iter;
188
    char *enum_keybuf;
189
    int enum_keybuf_max;
190
191
    gp_alarm *timeout;
192
};
193
194
195
/* ---------------- Forward decls ------------------ */
196
197
static int pl_main_languages_init(gs_memory_t * mem, pl_main_instance_t * inst);
198
199
static pl_interp_implementation_t
200
    *pl_select_implementation(pl_interp_implementation_t * pjl_instance,
201
                              pl_main_instance_t * pmi,
202
                              const char *data,
203
                              int len);
204
205
/* Process the options on the command line. */
206
static stream *pl_main_arg_fopen(const char *fname, void *mem);
207
208
/* Process the options on the command line, including making the
209
   initial device and setting its parameters.  */
210
static int pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
211
                                   pl_interp_implementation_t * pjl_instance);
212
213
static pl_interp_implementation_t *pl_pjl_select(pl_main_instance_t * pmi, pl_interp_implementation_t *pjl_instance);
214
215
/* return index in gs device list -1 if not found */
216
static inline int
217
get_device_index(const gs_memory_t * mem, const char *value)
218
16.0k
{
219
16.0k
    const gx_device *const *dev_list;
220
16.0k
    int num_devs = gs_lib_device_list(&dev_list, NULL);
221
16.0k
    int di;
222
223
336k
    for (di = 0; di < num_devs; ++di)
224
336k
        if (!strcmp(gs_devicename(dev_list[di]), value))
225
16.0k
            break;
226
16.0k
    if (di == num_devs) {
227
0
        errprintf(mem, "Unknown device name %s.\n", value);
228
0
        return -1;
229
0
    }
230
16.0k
    return di;
231
16.0k
}
232
233
static int
234
legacy_display_callout(void *instance,
235
                       void *handle,
236
                       const char *dev_name,
237
                       int id,
238
                       int size,
239
                       void *data)
240
0
{
241
0
    pl_main_instance_t *inst = (pl_main_instance_t *)handle;
242
243
0
    if (dev_name == NULL)
244
0
        return -1;
245
0
    if (strcmp(dev_name, "display") != 0)
246
0
        return -1;
247
248
0
    if (id == DISPLAY_CALLOUT_GET_CALLBACK_LEGACY) {
249
        /* get display callbacks */
250
0
        gs_display_get_callback_t *cb = (gs_display_get_callback_t *)data;
251
0
        cb->callback = inst->display;
252
0
        return 0;
253
0
    }
254
0
    return -1;
255
0
}
256
257
int
258
pl_main_set_display_callback(pl_main_instance_t *inst, void *callback)
259
0
{
260
0
    int code;
261
262
0
    if (inst->display == NULL && callback != NULL) {
263
        /* First registration. */
264
0
        code = gs_lib_ctx_register_callout(inst->memory,
265
0
                                           legacy_display_callout,
266
0
                                           inst);
267
0
        if (code < 0)
268
0
            return code;
269
0
    }
270
0
    if (inst->display != NULL && callback == NULL) {
271
        /* Deregistered. */
272
0
        gs_lib_ctx_deregister_callout(inst->memory,
273
0
                                      legacy_display_callout,
274
0
                                      inst);
275
0
    }
276
0
    inst->display = callback;
277
0
    return 0;
278
0
}
279
280
int
281
pl_main_init_with_args(pl_main_instance_t *inst, int argc, char *argv[])
282
16.0k
{
283
16.0k
    gs_memory_t *mem = inst->memory;
284
16.0k
    pl_interp_implementation_t *pjli;
285
16.0k
    int code;
286
287
16.0k
    gp_init();
288
    /* debug flags we reset this out of gs_lib_init0 which sets these
289
       and the allocator we want the debug setting but we do our own
290
       allocator */
291
#if defined(PACIFY_VALGRIND) && defined VALGRIND_HG_DISABLE_CHECKING
292
    VALGRIND_HG_DISABLE_CHECKING(gs_debug, 128);
293
#endif
294
16.0k
    memset(gs_debug, 0, 128);
295
16.0k
    gs_log_errors = 0;
296
297
16.0k
    if (gs_lib_init1(mem) < 0)
298
0
        return -1;
299
300
16.0k
    {
301
        /*
302
         * gs_iodev_init has to be called here (late), rather than
303
         * with the rest of the library init procedures, because of
304
         * some hacks specific to MS Windows for patching the
305
         * stdxxx IODevices.
306
         */
307
308
16.0k
        if (gs_iodev_init(mem) < 0)
309
0
            return gs_error_Fatal;
310
16.0k
    }
311
312
16.0k
    gp_get_realtime(inst->base_time);
313
314
16.0k
    if (arg_init(&inst->args, (const char **)argv, argc, pl_main_arg_fopen, mem,
315
16.0k
                 inst->get_codepoint, mem) < 0)
316
0
        return gs_error_Fatal;
317
318
    /* Create PDL instances, etc */
319
16.0k
    if (pl_main_languages_init(mem, inst) < 0) {
320
0
        return gs_error_Fatal;
321
0
    }
322
323
16.0k
    inst->curr_implementation = pjli = inst->implementations[0];
324
325
    /* initialize pjl, needed for option processing. */
326
16.0k
    if (pl_init_job(pjli, inst->device) < 0) {
327
0
        return gs_error_Fatal;
328
0
    }
329
330
16.0k
    code = pl_main_process_options(inst,
331
16.0k
                                   &inst->args,
332
16.0k
                                   pjli);
333
16.0k
    if (code == gs_error_invalidexit)
334
0
        code = 0; /* This is given by someone running "quit" in PS. */
335
16.0k
    else if (argc == 1 || code < 0) {
336
        /* Print error verbage and return */
337
114
        int i;
338
114
        const gx_device **dev_list;
339
114
        int num_devs =
340
114
            gs_lib_device_list((const gx_device * const **)&dev_list,
341
114
                               NULL);
342
114
        if (code != gs_error_Info)
343
114
            errprintf(mem, pl_usage, argv[0]);
344
345
114
        errprintf(mem, "Version: %s\n", PJL_VERSION_STRING);
346
114
        errprintf(mem, "Languages:");
347
1.71k
        for (i = 0; inst->implementations[i] != NULL; i++) {
348
1.59k
            if (((i + 1)) % 9 == 0)
349
114
                errprintf(mem, "\n");
350
1.59k
            errprintf(mem, " %s", pl_characteristics(inst->implementations[i])->language);
351
1.59k
        }
352
114
        errprintf(mem, "\nDevices:");
353
2.50k
        for (i = 0; i < num_devs; ++i) {
354
2.39k
            if (((i + 1)) % 9 == 0)
355
228
                errprintf(mem, "\n");
356
2.39k
            errprintf(mem, " %s", gs_devicename(dev_list[i]));
357
2.39k
        }
358
114
        errprintf(mem, "\n");
359
114
        return code == gs_error_Info ? 0 : gs_error_Fatal;
360
114
    }
361
15.8k
    return 0;
362
16.0k
}
363
364
static int
365
revert_to_pjli(pl_main_instance_t *minst)
366
53.8k
{
367
53.8k
    pl_interp_implementation_t *pjli =
368
53.8k
        minst->implementations[0];
369
53.8k
    int code;
370
371
    /* If we're already in PJL, don't clear the state. */
372
53.8k
    if (minst->curr_implementation == pjli)
373
25.8k
        return 0;
374
375
27.9k
    if (minst->curr_implementation) {
376
27.9k
        code = pl_dnit_job(minst->curr_implementation);
377
27.9k
        if (code < 0) {
378
114
            minst->curr_implementation = NULL;
379
114
            return code;
380
114
        }
381
27.9k
    }
382
27.8k
    minst->curr_implementation = NULL;
383
    /* We may want to reset the fonts. */
384
27.8k
    if (minst->prev_non_pjl_implementation &&
385
27.8k
        minst->reset_resources == PL_RESET_RESOURCES_ON_PJL) {
386
0
        if_debug1m('I', minst->memory, "Resetting resources (%s)\n",
387
0
                   pl_characteristics(minst->curr_implementation)->language);
388
0
        code = pl_reset(minst->prev_non_pjl_implementation, PL_RESET_RESOURCES);
389
0
        if (code < 0)
390
0
            return code;
391
0
    }
392
27.8k
    minst->curr_implementation = pjli;
393
394
27.8k
    code = pl_init_job(minst->curr_implementation, minst->device);
395
396
27.8k
    return code;
397
27.8k
}
398
399
int
400
pl_main_run_string_begin(pl_main_instance_t *minst)
401
0
{
402
0
    int code;
403
404
0
    if (minst->mid_runstring == 1) {
405
0
        dmprintf(minst->memory, "Can't begin a run_string during a run_string\n");
406
0
        return -1;
407
0
    }
408
0
    minst->mid_runstring = 1;
409
410
    /* If the current implementation is PJL (language 0) then don't
411
     * actually init here. Instead, just mark us as needing to auto
412
     * detect the language type when we get some data. */
413
0
    minst->detect_runstring_language = (minst->curr_implementation == minst->implementations[0]);
414
0
    minst->revert_to_pjl_after_runstring = minst->detect_runstring_language;
415
0
    if (minst->detect_runstring_language)
416
0
        return 0;
417
418
0
    code = pl_process_begin(minst->curr_implementation);
419
420
0
    if (code < 0)
421
0
        minst->mid_runstring = 0;
422
423
0
    return code;
424
0
}
425
426
static int
427
ensure_buf_size(pl_main_instance_t *minst, int len)
428
0
{
429
0
    int max = minst->buf_max;
430
431
0
    if (len < max)
432
0
        return 0;
433
434
0
    if (max == 0)
435
0
        max = 4096;
436
437
0
    while (max < len) {
438
0
        max *= 2;
439
0
        if (max < 0)
440
0
            return_error(gs_error_VMerror);
441
0
    }
442
443
0
    if (minst->buf_max == 0) {
444
0
        minst->buf_ptr = gs_alloc_bytes(minst->memory, max, "minst_buffer");
445
0
        if (minst->buf_ptr == NULL)
446
0
            return_error(gs_error_VMerror);
447
0
    } else {
448
0
        byte *newbuf = gs_resize_object(minst->memory, minst->buf_ptr, max, "minst_buffer");
449
0
        if (newbuf == NULL)
450
0
            return_error(gs_error_VMerror);
451
0
        minst->buf_ptr = newbuf;
452
0
    }
453
0
    minst->buf_max = max;
454
455
0
    return 0;
456
0
}
457
458
static
459
int buffer_data(pl_main_instance_t *minst, const char *data, unsigned int len)
460
0
{
461
0
    buffered_file *bf = minst->buffering_runstring_as_file;
462
0
    size_t newlen = bf->len + len;
463
0
    size_t start = bf->len;
464
0
    size_t chunk_max;
465
0
    size_t num_chunks = (bf->len + BUFFERED_FILE_CHUNK_SIZE-1)>>BUFFERED_FILE_CHUNK_SHIFT;
466
467
0
    if (len == 0)
468
0
         return 0;
469
470
    /* Copy anything that fits into the next chunk. */
471
0
    if (start < num_chunks<<BUFFERED_FILE_CHUNK_SHIFT) {
472
0
        size_t max = (num_chunks<<BUFFERED_FILE_CHUNK_SHIFT) - start;
473
0
        if (max > len)
474
0
            max = len;
475
0
        memcpy(&bf->index[start>>BUFFERED_FILE_CHUNK_SHIFT][start & (BUFFERED_FILE_CHUNK_SIZE-1)],
476
0
               data, max);
477
0
        bf->len += max;
478
0
        data += max;
479
0
        start += max;
480
0
        len -= (unsigned int)max;
481
0
        if (len == 0)
482
0
             return 0;
483
0
    }
484
485
    /* Do we need to extend the chunk index? */
486
0
    chunk_max = bf->index_max<<BUFFERED_FILE_CHUNK_SHIFT;
487
0
    if (newlen > chunk_max) {
488
0
        byte **new_index;
489
0
        if (chunk_max < 32*BUFFERED_FILE_CHUNK_SIZE)
490
0
            chunk_max = 32*BUFFERED_FILE_CHUNK_SIZE;
491
0
        while (newlen > chunk_max)
492
0
            chunk_max *= 2;
493
0
        chunk_max >>= BUFFERED_FILE_CHUNK_SHIFT;
494
0
        if (bf->index == NULL) {
495
0
            new_index = (byte **)gs_alloc_bytes(bf->memory,
496
0
                                                (size_t)sizeof(byte *) * chunk_max,
497
0
                                                "buffered_file_index");
498
0
        } else {
499
0
            new_index = (byte **)gs_resize_object(bf->memory,
500
0
                                                  bf->index,
501
0
                                                  (size_t)sizeof(byte *) * chunk_max,
502
0
                                                  "buffered_file_index");
503
0
        }
504
0
        if (new_index == NULL)
505
0
            return_error(gs_error_VMerror);
506
0
        bf->index = new_index;
507
0
        bf->index_max = chunk_max;
508
0
    }
509
510
    /* Now allocate chunks and copy in the data. */
511
0
    do {
512
0
        unsigned int max;
513
0
        byte *chunk = gs_alloc_bytes(bf->memory,
514
0
                                     BUFFERED_FILE_CHUNK_SIZE,
515
0
                                     "buffered_file_chunk");
516
0
        if (chunk == NULL)
517
0
            return_error(gs_error_VMerror);
518
0
        bf->index[start>>BUFFERED_FILE_CHUNK_SHIFT] = chunk;
519
0
        max = len;
520
0
        if (max > BUFFERED_FILE_CHUNK_SIZE)
521
0
            max = BUFFERED_FILE_CHUNK_SIZE;
522
0
        memcpy(chunk, data, max);
523
0
        data += max;
524
0
        bf->len = (start += max);
525
0
        len -= max;
526
0
    } while (len);
527
528
0
    return 0;
529
0
}
530
531
static int
532
start_need_file(pl_main_instance_t *minst, const char *data, unsigned int len)
533
0
{
534
0
    buffered_file *bf = (buffered_file *)gs_alloc_bytes(minst->memory->non_gc_memory,
535
0
                                                        sizeof(*bf), "buffered_file");
536
0
    if (bf == NULL)
537
0
        return_error(gs_error_VMerror);
538
539
0
    memset(bf, 0, sizeof(*bf));
540
0
    bf->memory = minst->memory->non_gc_memory;
541
0
    minst->buffering_runstring_as_file = bf;
542
543
0
    return buffer_data(minst, data, len);
544
0
}
545
546
static void
547
drop_buffered_file(buffered_file *bf)
548
16.0k
{
549
16.0k
    size_t i;
550
551
16.0k
    if (bf == NULL)
552
16.0k
        return;
553
554
0
    for (i = (bf->len+BUFFERED_FILE_CHUNK_SIZE-1)>>BUFFERED_FILE_CHUNK_SHIFT; i > 0; i--)
555
0
    {
556
0
        gs_free_object(bf->memory, bf->index[i-1], "buffered_file_chunk");
557
0
    }
558
0
    gs_free_object(bf->memory, bf->index, "buffered_file_index");
559
0
    gs_free_object(bf->memory, bf, "buffered_file_index");
560
0
}
561
562
typedef struct
563
{
564
   gp_file base;
565
   buffered_file *bf;
566
   gs_offset_t pos;
567
} gp_file_buffered;
568
569
static int
570
buffered_file_getc(gp_file *gp_)
571
0
{
572
0
    gp_file_buffered *gp = (gp_file_buffered *)gp_;
573
0
    gs_offset_t pos = gp->pos;
574
575
0
    if (pos >= gp->bf->len)
576
0
        return -1;
577
0
    gp->pos++;
578
579
0
    return (int)gp->bf->index[pos>>BUFFERED_FILE_CHUNK_SHIFT][pos & ((1<<BUFFERED_FILE_CHUNK_SHIFT)-1)];
580
0
}
581
582
static int
583
buffered_file_read(gp_file *gp_, size_t size, unsigned int count, void *buf)
584
0
{
585
0
    gp_file_buffered *gp = (gp_file_buffered *)gp_;
586
0
    gs_offset_t pos = gp->pos;
587
0
    gs_offset_t end;
588
0
    gs_offset_t n = 0;
589
0
    size_t bytes;
590
591
0
    bytes = size * count;
592
0
    end = pos + bytes;
593
594
0
    if (end > gp->bf->len)
595
0
        end = gp->bf->len;
596
0
    if (end <= pos)
597
0
        return 0;
598
0
    if (bytes > end - pos)
599
0
        bytes = end - pos;
600
601
0
    while (bytes > 0) {
602
0
        gs_offset_t off = pos & (BUFFERED_FILE_CHUNK_SIZE-1);
603
0
        gs_offset_t left = BUFFERED_FILE_CHUNK_SIZE - off;
604
0
        if (left > bytes)
605
0
            left = bytes;
606
0
        memcpy(buf, &gp->bf->index[pos>>BUFFERED_FILE_CHUNK_SHIFT][off],
607
0
               left);
608
0
        bytes -= left;
609
0
        n += left;
610
0
    }
611
0
    gp->pos += n;
612
613
0
    return n/size;
614
0
}
615
616
static int
617
buffered_file_seek(gp_file *gp_, gs_offset_t offset, int whence)
618
0
{
619
0
    gp_file_buffered *gp = (gp_file_buffered *)gp_;
620
0
    gs_offset_t pos;
621
622
0
    if (whence == SEEK_END)
623
0
        pos = gp->bf->len + offset;
624
0
    else if (whence == SEEK_CUR)
625
0
        pos = gp->pos + offset;
626
0
    else
627
0
        pos = offset;
628
629
0
    if (pos < 0)
630
0
        pos = 0;
631
0
    else if (pos > gp->bf->len)
632
0
        pos = gp->bf->len;
633
0
    gp->pos = pos;
634
635
0
    return 0;
636
0
}
637
638
static gs_offset_t
639
buffered_file_tell(gp_file *gp_)
640
0
{
641
0
    gp_file_buffered *gp = (gp_file_buffered *)gp_;
642
643
0
    return gp->pos;
644
0
}
645
646
static int
647
buffered_file_eof(gp_file *gp_)
648
0
{
649
0
    gp_file_buffered *gp = (gp_file_buffered *)gp_;
650
651
0
    return gp->pos == gp->bf->len;
652
0
}
653
654
static int
655
buffered_file_seekable(gp_file *gp)
656
0
{
657
0
    return 1;
658
0
}
659
660
static gp_file_ops_t buffered_file_ops = {
661
    NULL, /* close */
662
    buffered_file_getc,
663
    NULL, /* putc */
664
    buffered_file_read,
665
    NULL, /* write */
666
    buffered_file_seek,
667
    buffered_file_tell,
668
    buffered_file_eof,
669
    NULL, /* dup */
670
    buffered_file_seekable,
671
    NULL, /* pread */
672
    NULL, /* pwrite */
673
    NULL, /* is_char_buffered */
674
    NULL, /* fflush */
675
    NULL, /* ferror */
676
    NULL, /* get_file */
677
    NULL, /* clearerr */
678
    NULL /* reopen */
679
};
680
681
static int
682
buffered_file_fs_open_file(const gs_memory_t *mem,
683
                           void *secret,
684
                     const char *fname,
685
                     const char *mode,
686
                           gp_file **file)
687
0
{
688
0
    gp_file_buffered *gp;
689
690
0
    if (strcmp(fname, "gpdl_buffered_file:"))
691
0
        return 0;
692
693
0
    if (mode[0] != 'r')
694
0
        return_error(gs_error_invalidaccess);
695
696
0
    gp = (gp_file_buffered *)gp_file_alloc(mem, &buffered_file_ops,
697
0
                                           sizeof(*gp), "gp_file_buffered");
698
0
    if (gp == NULL)
699
0
        return_error(gs_error_VMerror); /* Allocation failed */
700
701
    /* Setup the crypt-specific state */
702
0
    gp->bf = (buffered_file *)secret;
703
704
    /* Return the new instance */
705
0
    *file = &gp->base;
706
707
0
    return 0;
708
0
}
709
710
static gsapi_fs_t buffered_file_fs = {
711
    buffered_file_fs_open_file,
712
    NULL,
713
    NULL,
714
    NULL,
715
    NULL
716
};
717
718
static int
719
do_run_string_continue(pl_main_instance_t *minst, const char *str, unsigned int length)
720
0
{
721
0
    stream_cursor_read cursor;
722
0
    int code;
723
0
    pl_interp_implementation_t *pjli = minst->implementations[0];
724
0
    const byte *initial_pos;
725
0
    int unread;
726
727
0
    if (minst->buffering_runstring_as_file)
728
0
        return buffer_data(minst, str, length);
729
730
    /* First off, get all our data into a single buffer (both anything
731
     * buffered from previous calls, and anything we have now). */
732
0
    if (minst->buf_fill > 0) {
733
        /* Ensure we have a buffer large enough. */
734
0
        code = ensure_buf_size(minst, length + minst->buf_fill);
735
0
        if (code < 0)
736
0
            return code;
737
738
0
        memcpy(&minst->buf_ptr[minst->buf_fill], str, length);
739
0
        minst->buf_fill += length;
740
0
        stream_cursor_read_init(&cursor, (const byte *)minst->buf_ptr, length);
741
0
    } else {
742
        /* Use the callers buffer directly. */
743
0
        stream_cursor_read_init(&cursor, (const byte *)str, length);
744
0
    }
745
746
    /* Now process that buffer. The outside loop here is used as we
747
     * try different languages. */
748
0
    do {
749
        /* Remember where we started this attempt so we can spot us
750
         * failing to make progress. */
751
0
        initial_pos = cursor.ptr;
752
753
0
        if (minst->detect_runstring_language) {
754
0
            pl_interp_implementation_t *desired_implementation;
755
756
0
            minst->detect_runstring_language = 0;
757
758
0
            desired_implementation = pl_select_implementation(pjli,
759
0
                                                              minst,
760
0
                                                (const char *)cursor.ptr+1,
761
0
                                                         (int)length);
762
763
            /* Possibly this never happens? But attempt to cope anyway. */
764
0
            if (desired_implementation == NULL) {
765
0
                code = -1;
766
0
                break;
767
0
            }
768
0
            if (gs_debug_c('I') || gs_debug_c(':'))
769
0
                dmlprintf1(minst->memory, "PDL detected as %s\n",
770
0
                           pl_characteristics(desired_implementation)->language);
771
772
            /* If the language implementation needs changing, change it. */
773
0
            if (desired_implementation != pjli) {
774
0
                code = pl_init_job(desired_implementation, minst->device);
775
0
                minst->curr_implementation = desired_implementation;
776
0
                if (code < 0)
777
0
                    return code;
778
0
            }
779
0
            code = pl_process_begin(minst->curr_implementation);
780
0
            if (code < 0)
781
0
                return code;
782
0
        }
783
784
0
        code = pl_process(minst->curr_implementation, &cursor);
785
0
        if (code == gs_error_NeedFile) {
786
0
            code = start_need_file(minst, (const char *)cursor.ptr + 1, cursor.limit - cursor.ptr);
787
0
            cursor.ptr = cursor.limit;
788
0
            break;
789
0
        }
790
0
        if (code == gs_error_NeedInput) {
791
0
            code = 0;
792
0
            break;
793
0
        }
794
0
        if (code == 0 && cursor.ptr != cursor.limit) {
795
0
            code = gs_error_InterpreterExit;
796
0
        }
797
0
        if (code == gs_error_InterpreterExit) {
798
0
            if (minst->curr_implementation == pjli) {
799
                /* We might have just hit a ENTER LANGUAGE. */
800
                /* Ideally, we should look at what language ENTER LANGUAGE
801
                 * said to use, and then swap to that. That means looking up
802
                 * a variable in the pjl interpreter, and we don't have the
803
                 * means to do that at the moment. For now let's assume it
804
                 * says "auto" and let's process it based on that. */
805
0
                minst->detect_runstring_language = 1;
806
0
            } else {
807
                /* The interpreter itself has hit UEL. Automatically guess
808
                 * what comes next. Probably back to PJL. */
809
0
                minst->detect_runstring_language = 1;
810
0
                if (minst->revert_to_pjl_after_runstring) {
811
0
                    code = revert_to_pjli(minst);
812
0
                    if (code < 0)
813
0
                        break;
814
0
                }
815
0
            }
816
0
            code = 0;
817
0
        }
818
        /* If we have data left, and we made progress last time,
819
         * head back to the top to try again with the remaining
820
         * data in the buffer. */
821
0
    } while (code >= 0 && cursor.ptr != initial_pos);
822
823
    /* Now, deal with any unread data. */
824
0
    unread = (int)(cursor.limit - cursor.ptr);
825
0
    if (unread) {
826
        /* We used count bytes, but still have unread bytes left. */
827
0
        if (minst->buf_fill > 0) {
828
            /* Move the remaining data down our buffer. */
829
0
            int count = (int)(cursor.ptr + 1 - minst->buf_ptr);
830
0
            memmove(&minst->buf_ptr[0], &minst->buf_ptr[count],
831
0
                    unread);
832
0
        } else {
833
            /* Store the remaining data in the buffer. */
834
0
            int count = (int)(cursor.ptr + 1 - (const byte *)str);
835
0
            int code2 = ensure_buf_size(minst, unread);
836
0
            if (code2 < 0)
837
0
                return code < 0 ? code : code2;
838
0
            memcpy(&minst->buf_ptr[0], str + count, unread);
839
0
        }
840
0
    }
841
0
    minst->buf_fill = (int)unread;
842
843
0
    return code;
844
0
}
845
846
int
847
pl_main_run_string_continue(pl_main_instance_t *minst, const char *str, unsigned int length)
848
0
{
849
0
    int code;
850
851
0
    code = do_run_string_continue(minst, str, length);
852
0
    if (code < 0)
853
0
        minst->mid_runstring = 0;
854
855
0
    return code;
856
0
}
857
858
static int
859
pl_main_run_file_utf8(pl_main_instance_t *minst, const char *prefix_commands, const char *filename)
860
16.0k
{
861
16.0k
    bool new_job = true;
862
16.0k
    pl_interp_implementation_t *pjli =
863
16.0k
        minst->implementations[0];
864
16.0k
    gs_memory_t *mem = minst->memory;
865
16.0k
    stream *s;
866
16.0k
    int code = 0;
867
16.0k
    bool is_stdin = filename[0] == '-' && filename[1] == 0;
868
16.0k
    bool use_process_file = false;
869
16.0k
    bool first_job = true;
870
16.0k
    pl_interp_implementation_t *desired_implementation = NULL;
871
872
16.0k
    if (is_stdin) {
873
0
        code = gs_get_callout_stdin(&s, mem);
874
0
        if (code < 0)
875
0
            return code;
876
16.0k
    } else {
877
16.0k
        s = sfopen(filename, "r", mem);
878
16.0k
    }
879
16.0k
    if (s == NULL)
880
0
        return gs_error_undefinedfilename;
881
882
    /* This function can run in 2 modes. Either it can run a file directly
883
     * using the run_file mechanism, or it can feed the data piecemeal
884
     * using the run_string mechanism. Which one depends on several things:
885
     *
886
     * If we're being piped data, then we have to use run_string.
887
     * If we are entered (as is usually the case) with PJL as the selected
888
     * interpreter, then we do a quick assessment of the file contents to
889
     * pick an interpreter. If the first interpreter has a run_file method
890
     * then we'll use that.
891
     *
892
     * This means that files that start with PJL data will always be run
893
     * using run_string.
894
     */
895
896
67.1k
    for (;;) {
897
67.1k
        if_debug1m('I', mem, "[i][file pos=%ld]\n",
898
67.1k
                   sftell(s));
899
900
        /* Check for EOF and prepare the next block of data. */
901
67.1k
        if (s->cursor.r.ptr == s->cursor.r.limit && sfeof(s)) {
902
14.1k
            if_debug0m('I', mem, "End of of data\n");
903
14.1k
            if (pl_process_end(minst->curr_implementation) < 0)
904
14
                 goto error_fatal;
905
14.1k
            pl_process_eof(minst->curr_implementation);
906
14.1k
            if (revert_to_pjli(minst) < 0)
907
0
                goto error_fatal_reverted;
908
14.1k
            break;
909
14.1k
        }
910
52.9k
        code = s_process_read_buf(s);
911
52.9k
        if (code < 0)
912
0
            break;
913
52.9k
        if (s->end_status == ERRC)
914
0
            break;
915
916
52.9k
        if (new_job) {
917
            /* The only time the current implementation won't be PJL,
918
             * is if someone has preselected a particular language
919
             * before calling this function. */
920
38.2k
            if (minst->curr_implementation == pjli) {
921
                /* Autodetect the language based on the content. */
922
38.2k
                desired_implementation = pl_select_implementation(
923
38.2k
                                                    pjli,
924
38.2k
                                                    minst,
925
38.2k
                                      (const char *)s->cursor.r.ptr+1,
926
38.2k
                                               (int)(s->cursor.r.limit -
927
38.2k
                                                     s->cursor.r.ptr));
928
929
                /* Possibly this never happens? But attempt to cope anyway. */
930
38.2k
                if (desired_implementation == NULL)
931
0
                    goto flush_to_end_of_job;
932
38.2k
                if (gs_debug_c('I') || gs_debug_c(':'))
933
0
                    dmlprintf1(mem, "PDL detected as %s\n",
934
38.2k
                               pl_characteristics(desired_implementation)->language);
935
936
                /* If the language implementation needs changing, change it. */
937
38.2k
                if (desired_implementation != pjli) {
938
939
                    /* If we are being asked to swap to a language implementation
940
                     * that is different to the last (non-PJL) implementation that
941
                     * we were using, we may want to clear soft-fonts. */
942
27.9k
                    if (minst->prev_non_pjl_implementation &&
943
11.9k
                        minst->reset_resources == PL_RESET_RESOURCES_ON_LANGUAGE_CHANGE &&
944
0
                        desired_implementation != minst->prev_non_pjl_implementation) {
945
0
                        if_debug1m('I', mem, "Resetting resources (%s)\n",
946
0
                                   pl_characteristics(minst->curr_implementation)->language);
947
0
                        code = pl_reset(minst->prev_non_pjl_implementation, PL_RESET_RESOURCES);
948
0
                        if (code < 0)
949
0
                            goto error_fatal;
950
0
                    }
951
952
27.9k
                    code = pl_dnit_job(pjli);
953
27.9k
                    minst->curr_implementation = NULL;
954
27.9k
                    if (code >= 0)
955
27.9k
                        code = pl_init_job(desired_implementation, minst->device);
956
27.9k
                    minst->curr_implementation = desired_implementation;
957
27.9k
                    minst->prev_non_pjl_implementation = desired_implementation;
958
27.9k
                    if (code < 0)
959
0
                        goto error_fatal;
960
27.9k
                }
961
962
                /* Run any prefix commands */
963
38.2k
                code = pl_run_prefix_commands(minst->curr_implementation, prefix_commands);
964
38.2k
                if (code < 0)
965
0
                    goto error_fatal;
966
38.2k
                prefix_commands = NULL;
967
38.2k
            }
968
969
38.2k
            if (minst->curr_implementation != pjli) {
970
27.9k
                if_debug1m('I', mem, "initialised (%s)\n",
971
27.9k
                           pl_characteristics(minst->curr_implementation)->language);
972
27.9k
                if (first_job &&
973
16.0k
                    !is_stdin &&
974
16.0k
                    minst->curr_implementation->proc_process_file) {
975
                    /* If we aren't being piped data, and this interpreter
976
                     * is capable of coping with running a file directly,
977
                     * let's do that. */
978
1.75k
                    use_process_file = true;
979
1.75k
                    break;
980
1.75k
                }
981
27.9k
            }
982
983
36.4k
            first_job = false;
984
36.4k
            new_job = false;
985
986
36.4k
            if (pl_process_begin(minst->curr_implementation) < 0)
987
0
                 goto error_fatal;
988
36.4k
        }
989
990
52.9k
        if_debug2m('I', mem, "processing (%s) job from offset %ld\n",
991
51.2k
                   pl_characteristics(minst->curr_implementation)->language,
992
51.2k
                   sftell(s));
993
51.2k
        code = pl_process(minst->curr_implementation, &s->cursor.r);
994
51.2k
        if_debug2m('I', mem, "processed (%s) job to offset %ld\n",
995
51.2k
                   pl_characteristics(minst->curr_implementation)->language,
996
51.2k
                   sftell(s));
997
51.2k
        if (code == gs_error_NeedInput) {
998
25.6k
            if (sfeof(s))
999
11.8k
                s->cursor.r.ptr = s->cursor.r.limit;
1000
25.6k
            continue;
1001
25.6k
        }
1002
25.5k
        if (code >= 0) {
1003
1.81k
            continue;
1004
1.81k
        }
1005
23.7k
        if (code != e_ExitLanguage) {
1006
            /* error and not exit language */
1007
3.96k
            dmprintf1(mem,
1008
3.96k
                      "Warning interpreter exited with error code %d\n",
1009
3.96k
                      code);
1010
3.96k
flush_to_end_of_job:
1011
3.96k
            dmprintf(mem, "Flushing to end of job\n");
1012
            /* flush eoj may require more data */
1013
5.02k
            while ((pl_flush_to_eoj(minst->curr_implementation, &s->cursor.r)) == 0) {
1014
2.52k
                int code2;
1015
2.52k
                if (s->cursor.r.ptr == s->cursor.r.limit && sfeof(s)) {
1016
1.46k
                    if_debug0m('I', mem,
1017
1.46k
                               "end of data found while flushing\n");
1018
1.46k
                    break;
1019
1.46k
                }
1020
1.06k
                code2 = s_process_read_buf(s);
1021
1.06k
                if (code2 < 0)
1022
0
                    break;
1023
1.06k
            }
1024
3.96k
            pl_report_errors(minst->curr_implementation, code,
1025
3.96k
                             sftell(s),
1026
3.96k
                             minst->error_report > 0);
1027
3.96k
        }
1028
1029
23.7k
        if (pl_process_end(minst->curr_implementation) < 0)
1030
100
            goto error_fatal;
1031
23.6k
        new_job = true;
1032
        /* Always revert to PJL after each job. We avoid reinitialising PJL
1033
         * if we are already in PJL to avoid clearing the state. */
1034
23.6k
        if (revert_to_pjli(minst))
1035
0
            goto error_fatal_reverted;
1036
23.6k
    }
1037
15.8k
    sfclose(s);
1038
15.8k
    s = NULL;
1039
15.8k
    if (use_process_file)
1040
1.75k
    {
1041
1.75k
        if_debug1m('I', mem, "processing job from file (%s)\n",
1042
1.75k
                   filename);
1043
1044
1.75k
        code = pl_process_file(minst->curr_implementation, (char *)filename);
1045
1.75k
        if (code == gs_error_InterpreterExit)
1046
0
            code = 0;
1047
1.75k
        if (code < 0) {
1048
738
            errprintf(mem, "Warning interpreter exited with error code %d\n",
1049
738
                      code);
1050
738
        }
1051
1.75k
    }
1052
15.8k
    if (revert_to_pjli(minst) < 0)
1053
0
        goto error_fatal_reverted;
1054
15.8k
    return 0;
1055
1056
114
error_fatal:
1057
114
    (void)revert_to_pjli(minst);
1058
114
error_fatal_reverted:
1059
114
    sfclose(s);
1060
114
    return gs_error_Fatal;
1061
114
}
1062
1063
int
1064
pl_main_run_string_end(pl_main_instance_t *minst)
1065
0
{
1066
0
    int code;
1067
1068
0
    if (minst->buffering_runstring_as_file) {
1069
0
        buffered_file *bf = minst->buffering_runstring_as_file;
1070
0
        minst->buffering_runstring_as_file = NULL;
1071
0
        code = gsapi_add_fs(minst, &buffered_file_fs, bf);
1072
0
        if (code >= 0) {
1073
0
            code = pl_process_end(minst->curr_implementation);
1074
0
            if (code >= 0)
1075
0
                code = pl_process_file(minst->curr_implementation,
1076
0
                                       "gpdl_buffered_file:");
1077
0
            gsapi_remove_fs(minst, &buffered_file_fs, bf);
1078
0
        }
1079
0
        drop_buffered_file(bf);
1080
0
    } else {
1081
0
        code = pl_process_end(minst->curr_implementation);
1082
1083
0
        if (code >= 0)
1084
0
            code = pl_process_eof(minst->curr_implementation);
1085
1086
0
        if (minst->buf_fill != 0)
1087
0
            code = gs_note_error(gs_error_syntaxerror);
1088
0
        minst->buf_fill = 0;
1089
0
    }
1090
1091
0
    if (minst->revert_to_pjl_after_runstring) {
1092
0
        int code2 = revert_to_pjli(minst);
1093
0
        if (code2 < 0)
1094
0
            code = code < 0 ? code : code2;
1095
0
        else
1096
0
            minst->revert_to_pjl_after_runstring = 0;
1097
0
    }
1098
1099
0
    minst->mid_runstring = 0;
1100
1101
0
    return code;
1102
0
}
1103
1104
/* We assume that the desired language has been set as minst->implementation here. */
1105
static int
1106
pl_main_run_prefix(pl_main_instance_t *minst, const char *prefix_commands)
1107
0
{
1108
0
    int code;
1109
1110
0
    if (minst->curr_implementation != minst->implementation) {
1111
0
        code = pl_dnit_job(minst->curr_implementation);
1112
0
        minst->curr_implementation = NULL;
1113
0
        if (code < 0)
1114
0
            return code;
1115
0
    }
1116
0
    code = pl_init_job(minst->implementation, minst->device);
1117
0
    if (code < 0)
1118
0
        return code;
1119
0
    minst->curr_implementation = minst->implementation;
1120
1121
0
    code = pl_run_prefix_commands(minst->curr_implementation, prefix_commands);
1122
1123
0
    return code;
1124
0
}
1125
1126
void
1127
pl_main_set_arg_decode(pl_main_instance_t *minst,
1128
                       pl_main_get_codepoint_t *get_codepoint)
1129
16.0k
{
1130
16.0k
    if (minst == NULL)
1131
0
        return;
1132
1133
16.0k
    minst->get_codepoint = get_codepoint;
1134
16.0k
}
1135
1136
int
1137
pl_main_run_file(pl_main_instance_t *minst, const char *file_name)
1138
0
{
1139
0
    char *d, *temp;
1140
0
    const char *c = file_name;
1141
0
    char dummy[6];
1142
0
    int rune, code, len;
1143
1144
0
    if (minst == NULL)
1145
0
        return 0;
1146
1147
0
    if (minst->mid_runstring == 1) {
1148
0
        dmprintf(minst->memory, "Can't run_file during a run_string\n");
1149
0
        return -1;
1150
0
    }
1151
1152
    /* Convert the file_name to utf8 */
1153
0
    if (minst->get_codepoint) {
1154
0
        len = 1;
1155
0
        while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
1156
0
            len += codepoint_to_utf8(dummy, rune);
1157
0
        temp = (char *)gs_alloc_bytes_immovable(minst->memory, len, "gsapi_run_file");
1158
0
        if (temp == NULL)
1159
0
            return gs_error_VMerror;
1160
0
        c = file_name;
1161
0
        d = temp;
1162
0
        while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
1163
0
           d += codepoint_to_utf8(d, rune);
1164
0
        *d = 0;
1165
0
    }
1166
0
    else {
1167
0
      temp = (char *)file_name;
1168
0
    }
1169
0
    code = pl_main_run_file_utf8(minst, NULL, temp);
1170
0
    if (temp != file_name)
1171
0
        gs_free_object(minst->memory, temp, "gsapi_run_file");
1172
0
    return code;
1173
0
}
1174
1175
int
1176
pl_main_delete_instance(pl_main_instance_t *minst)
1177
16.0k
{
1178
    /* Dnit PDLs */
1179
16.0k
    gs_memory_t *mem;
1180
16.0k
    pl_interp_implementation_t **impl;
1181
1182
16.0k
    if (minst == NULL)
1183
0
        return 0;
1184
1185
    /* close and deallocate the device */
1186
16.0k
    if (minst->device) {
1187
16.0k
        gs_closedevice(minst->device);
1188
16.0k
        if (minst->device_root) {
1189
16.0k
            gs_unregister_root(minst->device->memory, minst->device_root,
1190
16.0k
                               "pl_main_languages_delete_instance");
1191
16.0k
        }
1192
16.0k
        minst->device_root = NULL;
1193
16.0k
        gx_device_retain(minst->device, false);
1194
16.0k
        minst->device = NULL;
1195
16.0k
    }
1196
16.0k
    mem = minst->memory;
1197
16.0k
    impl = minst->implementations;
1198
16.0k
    if (impl != NULL) {
1199
        /* dnit interps */
1200
16.0k
        int index;
1201
240k
        for (index = 0; impl[index] != 0; ++index) {
1202
224k
            if (pl_deallocate_interp_instance(impl[index]) < 0) {
1203
0
                return -1;
1204
0
            }
1205
224k
            gs_free_object(mem, impl[index], "pl_main_languages_init interp");
1206
224k
        }
1207
1208
16.0k
        gs_free_object(mem, impl, "pl_main_languages_delete_instance()");
1209
16.0k
    }
1210
1211
16.0k
    drop_buffered_file(minst->buffering_runstring_as_file);
1212
1213
16.0k
    gs_free_object(mem, minst->buf_ptr, "minst_buffer");
1214
1215
16.0k
    gs_c_param_list_release(&minst->params);
1216
16.0k
    gs_c_param_list_release(&minst->enum_params);
1217
16.0k
    gs_free_object(mem, minst->enum_keybuf, "param enumerator keybuf");
1218
1219
16.0k
    gs_iodev_finit(mem);
1220
16.0k
    gs_lib_finit(0, 0, mem);
1221
16.0k
    gs_free_object(mem, minst, "pl_main_instance");
1222
16.0k
    mem->gs_lib_ctx->top_of_system = NULL;
1223
1224
#ifdef PL_LEAK_CHECK
1225
    gs_memory_chunk_dump_memory(mem);
1226
#endif
1227
16.0k
    gs_malloc_release(gs_memory_chunk_unwrap(mem));
1228
1229
16.0k
    return 0;
1230
16.0k
}
1231
1232
int
1233
pl_to_exit(gs_memory_t *mem)
1234
16.0k
{
1235
16.0k
    int ret = 0;
1236
16.0k
    pl_main_instance_t *minst = mem->gs_lib_ctx->top_of_system;
1237
    /* Deselect last-selected device */
1238
16.0k
    if (minst->curr_implementation
1239
15.8k
        && pl_dnit_job(minst->curr_implementation) < 0) {
1240
0
        ret = -1;
1241
0
    }
1242
1243
16.0k
    gs_c_param_list_release(&minst->params);
1244
16.0k
    arg_finit(&minst->args);
1245
16.0k
    return ret;
1246
16.0k
}
1247
1248
static int                             /* 0 ok, else -1 error */
1249
pl_main_languages_init(gs_memory_t * mem,        /* deallocator for devices */
1250
                      pl_main_instance_t * minst         /* instance for pre/post print */
1251
    )
1252
16.0k
{
1253
16.0k
    int index;
1254
16.0k
    int count;
1255
16.0k
    size_t sz;
1256
16.0k
    pl_interp_implementation_t **impls;
1257
1258
240k
    for (count = 0; pdl_implementations[count] != 0; ++count)
1259
224k
        ;
1260
1261
    /* add one so we can zero terminate the table */
1262
16.0k
    sz = sizeof(pl_interp_implementation_t *) * (count + 1);
1263
1264
16.0k
    impls = (pl_interp_implementation_t **)gs_alloc_bytes_immovable(mem, sz, "pl_main_languages_init");
1265
1266
16.0k
    if (impls == NULL)
1267
0
        goto pmui_err;
1268
1269
16.0k
    minst->implementations = impls;
1270
16.0k
    minst->curr_implementation = NULL;
1271
16.0k
    memset(impls, 0, sz);
1272
1273
    /* Create & init PDL all instances. Could do this lazily to save memory, */
1274
    /* but for now it's simpler to just create all instances up front. */
1275
240k
    for (index = 0; index < count; ++index) {
1276
224k
        int code;
1277
224k
        impls[index] = (pl_interp_implementation_t *)
1278
224k
            gs_alloc_bytes_immovable(mem,
1279
224k
                                     sizeof(pl_interp_implementation_t),
1280
224k
                                     "pl_main_languages_init interp");
1281
1282
224k
        if (impls[index] == NULL)
1283
0
            goto pmui_err;
1284
1285
224k
        *impls[index] = *pdl_implementations[index];
1286
1287
        /* Whatever instance we allocate here will become the current
1288
         * instance during initialisation; this allows init files to be
1289
         * successfully read etc. */
1290
224k
        code = pl_allocate_interp_instance(impls[index], mem);
1291
1292
224k
        if (code < 0) {
1293
0
            errprintf(mem, "Unable to create %s interpreter.\n",
1294
0
                        pl_characteristics(impls[index])->
1295
0
                        language);
1296
0
            gs_free_object(mem, impls[index], "pl_main_languages_init interp");
1297
0
            impls[index] = NULL;
1298
0
            goto pmui_err;
1299
0
        }
1300
1301
224k
    }
1302
16.0k
    return 0;
1303
1304
0
 pmui_err:
1305
0
    return -1;
1306
16.0k
}
1307
1308
pl_main_instance_t *
1309
pl_main_get_instance(const gs_memory_t *mem)
1310
278k
{
1311
278k
    return mem->gs_lib_ctx->top_of_system;
1312
278k
}
1313
1314
char *
1315
pl_main_get_pcl_personality(const gs_memory_t *mem)
1316
15.6k
{
1317
15.6k
    return pl_main_get_instance(mem)->pcl_personality;
1318
15.6k
}
1319
1320
/* ------- Functions related to pl_main_instance_t ------ */
1321
1322
/* Initialize the instance parameters. */
1323
pl_main_instance_t *
1324
pl_main_alloc_instance(gs_memory_t * mem)
1325
16.0k
{
1326
16.0k
    pl_main_instance_t *minst;
1327
16.0k
    if (mem == NULL)
1328
0
        return NULL;
1329
1330
16.0k
    minst = (pl_main_instance_t *)gs_alloc_bytes_immovable(mem,
1331
16.0k
                                                           sizeof(pl_main_instance_t),
1332
16.0k
                                                           "pl_main_instance");
1333
16.0k
    if (minst == NULL)
1334
0
        return 0;
1335
1336
16.0k
    memset(minst, 0, sizeof(*minst));
1337
1338
16.0k
    minst->memory = minst->device_memory = mem;
1339
1340
16.0k
    minst->pjl_from_args = false;
1341
16.0k
    minst->error_report = -1;
1342
16.0k
    minst->pause = true;
1343
16.0k
    minst->safer = true;
1344
16.0k
    minst->device = 0;
1345
16.0k
    minst->implementation = NULL;
1346
16.0k
    minst->prev_non_pjl_implementation = NULL;
1347
16.0k
    minst->reset_resources = PL_RESET_RESOURCES_NEVER;
1348
16.0k
    minst->base_time[0] = 0;
1349
16.0k
    minst->base_time[1] = 0;
1350
16.0k
    minst->interpolate = false;
1351
16.0k
    minst->nocache = false;
1352
16.0k
    minst->page_set_on_command_line = false;
1353
16.0k
    minst->res_set_on_command_line = false;
1354
16.0k
    minst->high_level_device = false;
1355
#ifndef OMIT_SAVED_PAGES_TEST
1356
    minst->saved_pages_test_mode = false;
1357
#endif
1358
16.0k
    minst->scanconverter = GS_SCANCONVERTER_DEFAULT;
1359
16.0k
    minst->piccdir = NULL;
1360
16.0k
    minst->pdefault_gray_icc = NULL;
1361
16.0k
    minst->pdefault_rgb_icc = NULL;
1362
16.0k
    minst->pdefault_cmyk_icc = NULL;
1363
16.0k
    strncpy(&minst->pcl_personality[0], "PCL",
1364
16.0k
            sizeof(minst->pcl_personality) - 1);
1365
16.0k
    mem->gs_lib_ctx->top_of_system = minst;
1366
16.0k
    gs_c_param_list_write(&minst->params, mem);
1367
16.0k
    gs_param_list_set_persistent_keys((gs_param_list *)&minst->params, false);
1368
16.0k
    return minst;
1369
16.0k
}
1370
1371
/* -------- Command-line processing ------ */
1372
1373
/* Create a default device if not already defined. */
1374
static int
1375
pl_top_create_device(pl_main_instance_t * pti)
1376
16.0k
{
1377
16.0k
    int code = 0;
1378
1379
16.0k
    if (!pti->device) {
1380
16.0k
        const gx_device *dev;
1381
16.0k
        pl_interp_implementation_t **impl;
1382
16.0k
        gs_memory_t *mem = pti->device_memory;
1383
        /* We assume that nobody else changes pti->device,
1384
           and this function is called from this module only.
1385
           Due to that device_root is always consistent with pti->device,
1386
           and it is regisrtered if and only if pti->device != NULL.
1387
         */
1388
16.0k
        if (pti->device != NULL)
1389
0
            pti->device = NULL;
1390
1391
16.0k
        if (pti->device_index == -1) {
1392
0
            dev = gs_getdefaultlibdevice(pti->memory);
1393
0
        }
1394
16.0k
        else {
1395
16.0k
            dev = gs_getdevice(pti->device_index);
1396
16.0k
            if (dev == NULL) /* Shouldn't ever happen */
1397
0
                return -1;
1398
16.0k
        }
1399
96.0k
        for (impl = pti->implementations; *impl != 0; ++impl) {
1400
96.0k
           mem = pl_get_device_memory(*impl);
1401
96.0k
           if (mem)
1402
16.0k
               break;
1403
96.0k
        }
1404
16.0k
        if (mem)
1405
16.0k
            pti->device_memory = mem;
1406
#ifdef DEBUG
1407
        for (; *impl != 0; ++impl) {
1408
            mem = pl_get_device_memory(*impl);
1409
            assert(mem == NULL || mem == pti->device_memory);
1410
        }
1411
#endif
1412
16.0k
        code = gs_copydevice(&pti->device, dev, pti->device_memory);
1413
1414
16.0k
        if (code < 0)
1415
0
            return code;
1416
1417
16.0k
        if (pti->device == NULL)
1418
0
            return gs_error_VMerror;
1419
1420
16.0k
        pti->device_root = NULL;
1421
16.0k
        code = gs_register_struct_root(pti->device_memory, &pti->device_root,
1422
16.0k
                                (void **)&pti->device,
1423
16.0k
                                "pl_top_create_device");
1424
16.0k
        if (code < 0)
1425
0
            return code;
1426
1427
16.0k
        {
1428
16.0k
            gs_c_param_list list;
1429
1430
            /* Check if the device is a high level device (pdfwrite etc) */
1431
16.0k
            gs_c_param_list_write(&list, pti->device->memory);
1432
16.0k
            code = gs_getdeviceparams(pti->device, (gs_param_list *)&list);
1433
16.0k
            if (code >= 0) {
1434
16.0k
                gs_c_param_list_read(&list);
1435
16.0k
                code = param_read_bool((gs_param_list *)&list, "HighLevelDevice", &pti->high_level_device);
1436
16.0k
            }
1437
16.0k
            gs_c_param_list_release(&list);
1438
16.0k
            if (code < 0)
1439
0
                return code;
1440
16.0k
        }
1441
16.0k
        if (pti->high_level_device) {
1442
0
            gs_c_param_list list;
1443
1444
            /* Check if the high level device supports RasterOPs */
1445
0
            gs_c_param_list_write(&list, pti->device->memory);
1446
0
            code = gs_getdeviceparams(pti->device, (gs_param_list *)&list);
1447
0
            if (code >= 0) {
1448
0
                gs_c_param_list_read(&list);
1449
0
                code = param_read_bool((gs_param_list *)&list, "SupportsRasterOPs", &pti->supports_rasterops);
1450
0
            }
1451
0
            gs_c_param_list_release(&list);
1452
0
            if (code < 0)
1453
0
                return code;
1454
0
        } else
1455
16.0k
            pti->supports_rasterops = true;
1456
1457
16.0k
        if (pti->device->is_open &&
1458
0
            dev_proc(pti->device, dev_spec_op)(pti->device,
1459
0
                                               gxdso_reopen_after_init,
1460
0
                                               NULL, 0) == 1) {
1461
0
            code = gs_closedevice(pti->device);
1462
0
            if (code < 0)
1463
0
                return code;
1464
1465
0
            code = gs_opendevice(pti->device);
1466
0
            if (code < 0) {
1467
0
                dmprintf(pti->device->memory,
1468
0
                         "**** Unable to open the device, quitting.\n");
1469
0
                return code;
1470
0
            }
1471
0
        }
1472
16.0k
    }
1473
16.0k
    return code;
1474
16.0k
}
1475
1476
/* Process the options on the command line. */
1477
static stream *
1478
pl_main_arg_fopen(const char *fname, void *data)
1479
0
{
1480
0
    gs_memory_t *mem = (gs_memory_t *)data;
1481
0
    return sfopen(fname, "r", mem);
1482
0
}
1483
1484
static void
1485
set_debug_flags(const char *arg, char *flags)
1486
0
{
1487
0
    byte value = (*arg == '-' ? (++arg, 0) : 0xff);
1488
1489
0
    while (*arg)
1490
0
        flags[*arg++ & 127] = value;
1491
0
}
1492
1493
/*
1494
 * scan floats delimited by spaces, tabs and/or 'x'.  Return the
1495
 * number of arguments parsed which will be less than or equal to the
1496
 * number of arguments requested in the parameter arg_count.
1497
 */
1498
static int
1499
parse_floats(gs_memory_t * mem, uint arg_count, const char *arg, float *f)
1500
16.0k
{
1501
16.0k
    int float_index = 0;
1502
16.0k
    char *tok, *l = NULL;
1503
    /* copy the input because strtok() steps on the string */
1504
16.0k
    char *s = arg_copy(arg, mem);
1505
16.0k
    if (s == NULL)
1506
0
        return -1;
1507
1508
    /* allow 'x', tab or spaces to delimit arguments */
1509
16.0k
    tok = gs_strtok(s, " \tx", &l);
1510
48.0k
    while (tok != NULL && float_index < arg_count) {
1511
32.0k
        f[float_index++] = atof(tok);
1512
32.0k
        tok = gs_strtok(NULL, " \tx", &l);
1513
32.0k
    }
1514
1515
16.0k
    gs_free_object(mem, s, "parse_floats()");
1516
1517
    /* return the number of args processed */
1518
16.0k
    return float_index;
1519
16.0k
}
1520
1521
#define argis(A, S) \
1522
512k
    (!strncmp((A), (S), sizeof(S)-1) && ((A)[sizeof(S)-1] == 0 || (A)[sizeof(S)-1] == '=' || (A)[sizeof(S)-1] == '#'))
1523
1524
static int check_for_special_int(pl_main_instance_t * pmi, const char *arg, int64_t b)
1525
64.0k
{
1526
64.0k
    if (argis(arg, "NOSAFER")) {
1527
0
        pmi->safer = !b;
1528
0
        return 1;
1529
0
    }
1530
64.0k
    if (argis(arg, "BATCH"))
1531
16.0k
        return (b == 1) ? 0 : gs_note_error(gs_error_rangecheck);
1532
48.0k
    if (argis(arg, "NOPAUSE")) {
1533
16.0k
        pmi->pause = !b;
1534
16.0k
        return 1;
1535
16.0k
    }
1536
32.0k
    if (argis(arg, "DOINTERPOLATE")) {
1537
0
        pmi->interpolate = !!b;
1538
0
        return 0;
1539
0
    }
1540
32.0k
    if (argis(arg, "NOCACHE")) {
1541
0
        pmi->nocache = !!b;
1542
0
        return 0;
1543
0
    }
1544
32.0k
    if (argis(arg, "RESETRESOURCES")) {
1545
0
        pmi->reset_resources = b;
1546
0
        return 0;
1547
0
    }
1548
32.0k
    if (argis(arg, "NODISPLAY")) {
1549
0
        pmi->pause = !b;
1550
0
        pmi->device_index = get_device_index(pmi->memory, "nullpage");
1551
0
        if (pmi->device_index == -1)
1552
0
            return -1;
1553
0
        return 1;
1554
0
    }
1555
32.0k
    return 1;
1556
32.0k
}
1557
1558
static int check_for_special_float(pl_main_instance_t * pmi, const char *arg, float f)
1559
0
{
1560
0
    if (argis(arg, "BATCH") ||
1561
0
        argis(arg, "NOPAUSE") ||
1562
0
        argis(arg, "DOINTERPOLATE") ||
1563
0
        argis(arg, "NOCACHE") ||
1564
0
        argis(arg, "SCANCONVERTERTYPE") ||
1565
0
        argis(arg, "RESETRESOURCES") ||
1566
0
        argis(arg, "NOSAFER")) {
1567
0
        return gs_note_error(gs_error_rangecheck);
1568
0
    }
1569
0
    return 1;
1570
0
}
1571
1572
static int check_for_special_str(pl_main_instance_t * pmi, const char *arg, gs_param_string *f)
1573
0
{
1574
0
    if (argis(arg, "BATCH") ||
1575
0
        argis(arg, "NOPAUSE") ||
1576
0
        argis(arg, "DOINTERPOLATE") ||
1577
0
        argis(arg, "NOCACHE") ||
1578
0
        argis(arg, "SCANCONVERTERTYPE") ||
1579
0
        argis(arg, "RESETRESOURCES") ||
1580
0
        argis(arg, "NOSAFER")) {
1581
0
        return gs_note_error(gs_error_rangecheck);
1582
0
    }
1583
0
    return 1;
1584
0
}
1585
1586
static int
1587
pass_param_to_languages(pl_main_instance_t *pmi,
1588
                        gs_param_list      *plist)
1589
64.0k
{
1590
64.0k
    pl_interp_implementation_t **imp;
1591
64.0k
    int code = 0;
1592
1593
960k
    for (imp = pmi->implementations; *imp != NULL; imp++) {
1594
896k
        code = pl_set_param(*imp, plist);
1595
896k
        if (code < 0)
1596
0
            break;
1597
896k
    }
1598
1599
64.0k
    return code;
1600
64.0k
}
1601
1602
static int
1603
pass_path_to_languages(pl_main_instance_t *pmi,
1604
                       const char         *path)
1605
0
{
1606
0
    pl_interp_implementation_t **imp;
1607
0
    int code = 0;
1608
1609
0
    for (imp = pmi->implementations; *imp != NULL; imp++) {
1610
0
        code = pl_add_path(*imp, path);
1611
0
        if (code < 0)
1612
0
            break;
1613
0
    }
1614
1615
0
    return code;
1616
0
}
1617
1618
static int
1619
pl_main_post_args_init(pl_main_instance_t * pmi)
1620
16.0k
{
1621
16.0k
    pl_interp_implementation_t **imp;
1622
16.0k
    int code = 0;
1623
1624
240k
    for (imp = pmi->implementations; *imp != NULL; imp++) {
1625
224k
        code = pl_post_args_init(*imp);
1626
224k
        if (code != 0)
1627
0
            break;
1628
224k
    }
1629
1630
16.0k
    return code;
1631
16.0k
}
1632
1633
static int
1634
handle_dash_c(pl_main_instance_t *pmi, arg_list *pal, char **collected_commands, const char **arg)
1635
0
{
1636
0
    bool ats = pal->expand_ats;
1637
0
    int code = 0;
1638
1639
0
    *arg = NULL;
1640
0
    pal->expand_ats = false;
1641
0
    while ((code = arg_next(pal, (const char **)arg, pmi->memory)) > 0) {
1642
0
        size_t arglen;
1643
0
        if ((*arg)[0] == '@' ||
1644
0
            ((*arg)[0] == '-' && !isdigit((unsigned char)(*arg)[1]))
1645
0
            )
1646
0
            break;
1647
0
        code = gs_lib_ctx_stash_sanitized_arg(pmi->memory->gs_lib_ctx, "?");
1648
0
        if (code < 0) {
1649
0
            goto end;
1650
0
        }
1651
0
        arglen = strlen(*arg);
1652
0
        if (*collected_commands == NULL) {
1653
0
            *collected_commands = (char *)gs_alloc_bytes(pmi->memory, arglen+1,
1654
0
                                                         "-c buffer");
1655
0
            if (*collected_commands == NULL) {
1656
0
                code = gs_note_error(gs_error_VMerror);
1657
0
                goto end;
1658
0
            }
1659
0
            memcpy(*collected_commands, *arg, arglen+1);
1660
0
        } else {
1661
0
            char *newc;
1662
0
            size_t oldlen = strlen(*collected_commands);
1663
0
            newc = (char *)gs_resize_object(pmi->memory,
1664
0
                                            *collected_commands,
1665
0
                                            oldlen + 1 + arglen + 1,
1666
0
                                            "-c buffer");
1667
0
            if (newc == NULL) {
1668
0
                code = gs_note_error(gs_error_VMerror);
1669
0
                goto end;
1670
0
            }
1671
0
            newc[oldlen] = 32;
1672
0
            memcpy(newc + oldlen + 1, *arg, arglen + 1);
1673
0
            *collected_commands = newc;
1674
0
        }
1675
0
        *arg = NULL;
1676
0
    }
1677
1678
0
end:
1679
0
    if (code == gs_error_VMerror) {
1680
0
        dmprintf(pmi->memory, "Failed to allocate memory while handling -c\n");
1681
0
    }
1682
0
    else if (code < 0) {
1683
0
        dmprintf(pmi->memory, "Syntax: -c <postscript commands>\n");
1684
0
    }
1685
1686
0
    pal->expand_ats = ats;
1687
1688
0
    return code;
1689
0
}
1690
1691
int
1692
pl_main_set_param(pl_main_instance_t * pmi, const char *arg)
1693
64.0k
{
1694
    /* We're setting a device parameter to a non-string value. */
1695
64.0k
    const char *eqp = strchr(arg, '=');
1696
64.0k
    const char *value;
1697
64.0k
    int64_t vi;
1698
64.0k
    float vf;
1699
64.0k
    bool bval = true;
1700
64.0k
    char buffer[128];
1701
64.0k
    static const char const_true_string[] = "true";
1702
64.0k
    int code = 0;
1703
64.0k
    gs_c_param_list *params = &pmi->params;
1704
1705
64.0k
    if (eqp || (eqp = strchr(arg, '#')))
1706
14
        value = eqp + 1;
1707
64.0k
    else {
1708
        /* -dDefaultBooleanIs_TRUE */
1709
64.0k
        value = const_true_string;
1710
64.0k
        eqp = arg + strlen(arg);
1711
64.0k
    }
1712
1713
    /* Arrange for a null terminated copy of the key name in buffer. */
1714
64.0k
    if (eqp-arg >= sizeof(buffer)-1) {
1715
0
        dmprintf1(pmi->memory, "Command line key is too long: %s\n", arg);
1716
0
        return -1;
1717
0
    }
1718
64.0k
    gs_c_param_list_write_more(params);
1719
64.0k
    strncpy(buffer, arg, eqp - arg);
1720
64.0k
    buffer[eqp - arg] = '\0';
1721
64.0k
    if (value && value[0] == '/') {
1722
        /* We have a name! */
1723
0
        gs_param_string str;
1724
1725
0
        code = check_for_special_str(pmi, arg, &str);
1726
0
        if (code <= 0)
1727
0
            return code;
1728
1729
0
        param_string_from_transient_string(str, value + 1);
1730
0
        code = param_write_name((gs_param_list *) params,
1731
0
                                buffer, &str);
1732
64.0k
    } else if (strchr(value, '#')) {
1733
        /* We have a non-decimal 'radix' number */
1734
0
        int64_t base = 0;
1735
0
        const char *val = strchr(value, '#') + 1;
1736
0
        const char *v = value;
1737
0
        char c;
1738
1739
0
        while ((c = *v++) >= '0' && c <= '9')
1740
0
            base = base*10 + (c - '0');
1741
0
        if (c != '#') {
1742
0
            dmprintf1(pmi->memory, "Malformed base value for radix. %s",
1743
0
                      value);
1744
0
            return -1;
1745
0
        }
1746
1747
0
        if (base < 2 || base > 36) {
1748
0
            dmprintf1(pmi->memory, "Base out of range %s",
1749
0
                      value);
1750
0
            return -1;
1751
0
        }
1752
0
        vi = 0;
1753
0
        while (*val) {
1754
0
            if (*val >= '0' && *val < ('0'+(base<=10?base:10))) {
1755
0
                vi = vi * base + (*val - '0');
1756
0
            } else if (base > 10) {
1757
0
                if (*val >= 'A' && *val < 'A'+base-10) {
1758
0
                    vi = vi * base + (*val - 'A' + 10);
1759
0
                } else if (*val >= 'a' && *val < 'a'+base-10) {
1760
0
                    vi = vi * base + (*val - 'a' + 10);
1761
0
                } else {
1762
0
                    dmprintf1(pmi->memory,
1763
0
                              "Value out of range %s\n",
1764
0
                              val);
1765
0
                    return -1;
1766
0
                }
1767
0
            }
1768
0
            val++;
1769
0
        }
1770
0
        code = check_for_special_int(pmi, arg, vi);
1771
0
        if (code < 0) code = 0;
1772
0
        if (code <= 0)
1773
0
            return code;
1774
0
        code = param_write_i64((gs_param_list *) params,
1775
0
                               buffer, &vi);
1776
64.0k
    } else if ((!strchr(value, '.')) &&
1777
64.0k
               (sscanf(value, "%"PRId64, &vi) == 1)) {
1778
        /* Here we have an int -- check for a scaling suffix */
1779
0
        char suffix = eqp[strlen(eqp) - 1];
1780
1781
0
        switch (suffix) {
1782
0
            case 'k':
1783
0
            case 'K':
1784
0
                vi *= 1024;
1785
0
                break;
1786
0
            case 'm':
1787
0
            case 'M':
1788
0
                vi *= 1024 * 1024;
1789
0
                break;
1790
0
            case 'g':
1791
0
            case 'G':
1792
                /* caveat emptor: more than 2g will overflow */
1793
                /* and really should produce a 'real', so don't do this */
1794
0
                vi *= 1024 * 1024 * 1024;
1795
0
                break;
1796
0
            default:
1797
0
                break;  /* not a valid suffix or last char was digit */
1798
0
        }
1799
0
        code = check_for_special_int(pmi, arg, vi);
1800
0
        if (code < 0) code = 0;
1801
0
        if (code <= 0)
1802
0
            return code;
1803
0
        code = param_write_i64((gs_param_list *) params,
1804
0
                               buffer, &vi);
1805
64.0k
    } else if (sscanf(value, "%f", &vf) == 1) {
1806
        /* We have a float */
1807
0
        code = check_for_special_float(pmi, arg, vf);
1808
0
        if (code <= 0)
1809
0
            return code;
1810
0
        code = param_write_float((gs_param_list *) params,
1811
0
                                 buffer, &vf);
1812
64.0k
    } else if (!strcmp(value, "null")) {
1813
0
        code = check_for_special_int(pmi, arg, (int)bval);
1814
0
        if (code < 0) code = 0;
1815
0
        if (code <= 0)
1816
0
            return code;
1817
0
        code = param_write_null((gs_param_list *) params,
1818
0
                                buffer);
1819
64.0k
    } else if (!strcmp(value, "true")) {
1820
        /* bval = true; */
1821
64.0k
        code = check_for_special_int(pmi, arg, (int)bval);
1822
64.0k
        if (code < 0) code = 0;
1823
64.0k
        if (code <= 0)
1824
16.0k
            return code;
1825
48.0k
        code = param_write_bool((gs_param_list *) params,
1826
48.0k
                                buffer, &bval);
1827
48.0k
    } else if (!strcmp(value, "false")) {
1828
0
        bval = false;
1829
0
        code = check_for_special_int(pmi, arg, (int)bval);
1830
0
        if (code < 0) code = 0;
1831
0
        if (code <= 0)
1832
0
            return code;
1833
0
        code = param_write_bool((gs_param_list *) params,
1834
0
                                buffer, &bval);
1835
14
    } else {
1836
14
        dmprintf(pmi->memory,
1837
14
                 "Usage for -d is -d<option>=[<integer>|<float>|null|true|false|name]\n");
1838
14
        arg = NULL;
1839
14
        return 0;
1840
14
    }
1841
48.0k
    if (code < 0)
1842
0
        return code;
1843
48.0k
    gs_c_param_list_read(params);
1844
48.0k
    code = pass_param_to_languages(pmi, (gs_param_list *) params);
1845
1846
    /* If we have a device, send it to the device, and clear it from
1847
     * the list. If we don't have a device, we leave it in the list for
1848
     * it to be sent to device later. */
1849
48.0k
    if (pmi->device) {
1850
22
        gs_c_param_list_read(params);
1851
22
        code = gs_putdeviceparams(pmi->device, (gs_param_list *) params);
1852
22
        gs_c_param_list_release(params);
1853
22
    }
1854
1855
48.0k
    return code;
1856
48.0k
}
1857
1858
int
1859
pl_main_set_string_param(pl_main_instance_t * pmi, const char *arg)
1860
16.0k
{
1861
    /* We're setting a device or user parameter to a string. */
1862
16.0k
    const char *eqp;
1863
16.0k
    const char *value;
1864
16.0k
    gs_param_string str;
1865
16.0k
    int code = 0;
1866
16.0k
    gs_c_param_list *params = &pmi->params;
1867
1868
16.0k
    eqp = strchr(arg, '=');
1869
16.0k
    if (!(eqp || (eqp = strchr(arg, '#')))) {
1870
0
        return -1;
1871
0
    }
1872
16.0k
    value = eqp + 1;
1873
16.0k
    if (argis(arg, "DEVICE")) {
1874
0
        dmprintf(pmi->memory, "DEVICE can only be set on the command line!\n");
1875
0
        return -1;
1876
16.0k
    } else if (argis(arg, "DefaultGrayProfile")) {
1877
0
        dmprintf(pmi->memory, "DefaultGrayProfile can only be set on the command line!\n");
1878
0
        return -1;
1879
16.0k
    } else if (argis(arg, "DefaultRGBProfile")) {
1880
0
        dmprintf(pmi->memory, "DefaultRGBProfile can only be set on the command line!\n");
1881
0
        return -1;
1882
16.0k
    } else if (argis(arg, "DefaultCMYKProfile")) {
1883
0
        dmprintf(pmi->memory, "DefaultCMYKProfile can only be set on the command line!\n");
1884
0
        return -1;
1885
16.0k
    } else if (argis(arg, "ICCProfileDir")) {
1886
0
        dmprintf(pmi->memory, "ICCProfileDir can only be set on the command line!\n");
1887
0
        return -1;
1888
16.0k
    } else {
1889
16.0k
        char buffer[128];
1890
1891
16.0k
        if (eqp-arg >= sizeof(buffer)-1) {
1892
0
            dmprintf1(pmi->memory, "Command line key is too long: %s\n", arg);
1893
0
            return -1;
1894
0
        }
1895
16.0k
        strncpy(buffer, arg, eqp - arg);
1896
16.0k
        buffer[eqp - arg] = '\0';
1897
1898
16.0k
        gs_c_param_list_write_more(params);
1899
16.0k
        param_string_from_transient_string(str, value);
1900
16.0k
        code = param_write_string((gs_param_list *) params,
1901
16.0k
                                  buffer, &str);
1902
16.0k
        if (code < 0)
1903
0
            return code;
1904
16.0k
        gs_c_param_list_read(params);
1905
16.0k
        code = pass_param_to_languages(pmi, (gs_param_list *)params);
1906
16.0k
        if (code < 0) {
1907
0
            gs_c_param_list_release(params);
1908
0
            return code;
1909
0
        }
1910
1911
16.0k
        if (pmi->device) {
1912
0
            code = gs_putdeviceparams(pmi->device, (gs_param_list *)params);
1913
0
            gs_c_param_list_release(params);
1914
0
        }
1915
16.0k
    }
1916
16.0k
    return code;
1917
16.0k
}
1918
1919
int
1920
pl_main_set_parsed_param(pl_main_instance_t * pmi, const char *arg)
1921
0
{
1922
0
    const char *eqp;
1923
0
    const char *value;
1924
0
    char buffer[128];
1925
1926
0
    eqp = strchr(arg, '=');
1927
0
    if (!(eqp || (eqp = strchr(arg, '#')))) {
1928
0
        return -1;
1929
0
    }
1930
0
    value = eqp + 1;
1931
0
    if (argis(arg, "DEVICE")) {
1932
0
        dmprintf(pmi->memory, "DEVICE cannot be set by -p!\n");
1933
0
        return -1;
1934
0
    } else if (argis(arg, "DefaultGrayProfile")) {
1935
0
        dmprintf(pmi->memory, "DefaultGrayProfile cannot be set by -p!\n");
1936
0
        return -1;
1937
0
    } else if (argis(arg, "DefaultRGBProfile")) {
1938
0
        dmprintf(pmi->memory, "DefaultRGBProfile cannot be set by -p!\n");
1939
0
        return -1;
1940
0
    } else if (argis(arg, "DefaultCMYKProfile")) {
1941
0
        dmprintf(pmi->memory, "DefaultCMYKProfile cannot be set by -p!\n");
1942
0
        return -1;
1943
0
    } else if (argis(arg, "ICCProfileDir")) {
1944
0
        dmprintf(pmi->memory, "ICCProfileDir cannot be set by -p!\n");
1945
0
        return -1;
1946
0
    }
1947
1948
0
    if (eqp-arg >= sizeof(buffer)-1) {
1949
0
        dmprintf1(pmi->memory, "Command line key is too long: %s\n", arg);
1950
0
        return -1;
1951
0
    }
1952
0
    strncpy(buffer, arg, eqp - arg);
1953
0
    buffer[eqp - arg] = '\0';
1954
1955
0
    return pl_main_set_typed_param(pmi, pl_spt_parsed, buffer, value);
1956
0
}
1957
1958
int
1959
pl_main_set_typed_param(pl_main_instance_t *pmi, pl_set_param_type type, const char *param, const void *value)
1960
0
{
1961
0
    int code = 0;
1962
0
    gs_c_param_list *params = &pmi->params;
1963
0
    gs_param_string str_value;
1964
0
    bool bval;
1965
0
    int more_to_come = type & pl_spt_more_to_come;
1966
1967
0
    if (pmi->mid_runstring) {
1968
0
        dmprintf(pmi->memory, "Can't set parameters mid run_string\n");
1969
0
        return -1;
1970
0
    }
1971
1972
0
    type &= ~pl_spt_more_to_come;
1973
1974
    /* First set it in the device params */
1975
0
    gs_c_param_list_write_more(params);
1976
0
    switch (type)
1977
0
    {
1978
0
    case pl_spt_null:
1979
0
        code = param_write_null((gs_param_list *) params,
1980
0
                                param);
1981
0
        break;
1982
0
    case pl_spt_bool:
1983
0
        bval = !!*(int *)value;
1984
0
        code = param_write_bool((gs_param_list *) params,
1985
0
                                param, &bval);
1986
0
        break;
1987
0
    case pl_spt_int:
1988
0
        code = param_write_int((gs_param_list *) params,
1989
0
                               param, (int *)value);
1990
0
        break;
1991
0
    case pl_spt_float:
1992
0
        code = param_write_float((gs_param_list *) params,
1993
0
                                 param, (float *)value);
1994
0
        break;
1995
0
    case pl_spt_name:
1996
0
        param_string_from_transient_string(str_value, value);
1997
0
        code = param_write_name((gs_param_list *) params,
1998
0
                                param, &str_value);
1999
0
        break;
2000
0
    case pl_spt_string:
2001
0
        param_string_from_transient_string(str_value, value);
2002
0
        code = param_write_string((gs_param_list *) params,
2003
0
                                  param, &str_value);
2004
0
        break;
2005
0
    case pl_spt_long:
2006
0
        code = param_write_long((gs_param_list *) params,
2007
0
                                param, (long *)value);
2008
0
        break;
2009
0
    case pl_spt_i64:
2010
0
        code = param_write_i64((gs_param_list *) params,
2011
0
                               param, (int64_t *)value);
2012
0
        break;
2013
0
    case pl_spt_size_t:
2014
0
        code = param_write_size_t((gs_param_list *) params,
2015
0
                                  param, (size_t *)value);
2016
0
        break;
2017
0
    case pl_spt_parsed:
2018
0
        code = gs_param_list_add_parsed_value((gs_param_list *)params,
2019
0
                                              param, (void *)value);
2020
0
        break;
2021
0
    default:
2022
0
        code = gs_note_error(gs_error_rangecheck);
2023
0
    }
2024
0
    if (code < 0) {
2025
0
        gs_c_param_list_release(params);
2026
0
        return code;
2027
0
    }
2028
0
    gs_c_param_list_read(params);
2029
2030
0
    if (pmi->implementations == NULL || more_to_come) {
2031
        /* Leave it in the param list for later. */
2032
0
        return 0;
2033
0
    }
2034
2035
    /* Then send it to the languages */
2036
0
    code = pass_param_to_languages(pmi, (gs_param_list *)params);
2037
0
    if (code < 0)
2038
0
        return code;
2039
2040
    /* Send it to the device, if there is one. */
2041
0
    if (pmi->device) {
2042
0
        code = gs_putdeviceparams(pmi->device, (gs_param_list *)params);
2043
0
        gs_c_param_list_release(params);
2044
0
    }
2045
2046
0
    return code;
2047
0
}
2048
2049
int
2050
pl_main_get_typed_param(pl_main_instance_t *pmi, pl_set_param_type type, const char *param, void *value)
2051
0
{
2052
0
    int code = 0;
2053
0
    gs_c_param_list params;
2054
0
    gs_param_string str_value;
2055
2056
0
    if (pmi->mid_runstring) {
2057
0
        dmprintf(pmi->memory, "Can't get parameters mid run_string\n");
2058
0
        return -1;
2059
0
    }
2060
2061
    /* The "more to come" bit should never be set, but clear it anyway. */
2062
0
    type &= ~pl_spt_more_to_come;
2063
2064
0
    gs_c_param_list_write(&params, pmi->memory);
2065
0
    code = gs_getdeviceparams(pmi->device, (gs_param_list *)&params);
2066
0
    if (code < 0) {
2067
0
        gs_c_param_list_release(&params);
2068
0
        return code;
2069
0
    }
2070
2071
0
    gs_c_param_list_read(&params);
2072
0
    switch (type)
2073
0
    {
2074
0
    case pl_spt_null:
2075
0
        code = param_read_null((gs_param_list *)&params, param);
2076
0
        if (code == 1)
2077
0
            code = gs_error_undefined;
2078
0
        if (code < 0)
2079
0
            break;
2080
0
        code = 0;
2081
0
        break;
2082
0
    case pl_spt_bool:
2083
0
    {
2084
0
        bool b;
2085
0
        code = param_read_bool((gs_param_list *)&params, param, &b);
2086
0
        if (code == 1)
2087
0
            code = gs_error_undefined;
2088
0
        if (code < 0)
2089
0
            break;
2090
0
        code = sizeof(int);
2091
0
        if (value != NULL)
2092
0
            *(int *)value = !!b;
2093
0
        break;
2094
0
    }
2095
0
    case pl_spt_int:
2096
0
    {
2097
0
        int i;
2098
0
        code = param_read_int((gs_param_list *)&params, param, &i);
2099
0
        if (code == 1)
2100
0
            code = gs_error_undefined;
2101
0
        if (code < 0)
2102
0
            break;
2103
0
        code = sizeof(int);
2104
0
        if (value != NULL)
2105
0
            *(int *)value = i;
2106
0
        break;
2107
0
    }
2108
0
    case pl_spt_float:
2109
0
    {
2110
0
        float f;
2111
0
        code = param_read_float((gs_param_list *)&params, param, &f);
2112
0
        if (code == 1)
2113
0
            code = gs_error_undefined;
2114
0
        if (code < 0)
2115
0
            break;
2116
0
        code = sizeof(float);
2117
0
        if (value != NULL)
2118
0
            *(float *)value = f;
2119
0
        break;
2120
0
    }
2121
0
    case pl_spt_name:
2122
0
        code = param_read_name((gs_param_list *)&params, param, &str_value);
2123
0
        if (code == 1)
2124
0
            code = gs_error_undefined;
2125
0
        if (code < 0)
2126
0
            break;
2127
0
        if (value != NULL) {
2128
0
            memcpy(value, str_value.data, str_value.size);
2129
0
            ((char *)value)[str_value.size] = 0;
2130
0
        }
2131
0
        code = str_value.size+1;
2132
0
        break;
2133
0
    case pl_spt_string:
2134
0
        code = param_read_string((gs_param_list *)&params, param, &str_value);
2135
0
        if (code == 1)
2136
0
            code = gs_error_undefined;
2137
0
        if (code < 0)
2138
0
            break;
2139
0
        else if (value != NULL) {
2140
0
            memcpy(value, str_value.data, str_value.size);
2141
0
            ((char *)value)[str_value.size] = 0;
2142
0
        }
2143
0
        code = str_value.size+1;
2144
0
        break;
2145
0
    case pl_spt_long:
2146
0
    {
2147
0
        long l;
2148
0
        code = param_read_long((gs_param_list *)&params, param, &l);
2149
0
        if (code == 1)
2150
0
            code = gs_error_undefined;
2151
0
        if (code < 0)
2152
0
            break;
2153
0
        if (value != NULL)
2154
0
            *(long *)value = l;
2155
0
        code = sizeof(long);
2156
0
        break;
2157
0
    }
2158
0
    case pl_spt_i64:
2159
0
    {
2160
0
        int64_t i64;
2161
0
        code = param_read_i64((gs_param_list *)&params, param, &i64);
2162
0
        if (code == 1)
2163
0
            code = gs_error_undefined;
2164
0
        if (code < 0)
2165
0
            break;
2166
0
        if (value != NULL)
2167
0
            *(int64_t *)value = i64;
2168
0
        code = sizeof(int64_t);
2169
0
        break;
2170
0
    }
2171
0
    case pl_spt_size_t:
2172
0
    {
2173
0
        size_t z;
2174
0
        code = param_read_size_t((gs_param_list *)&params, param, &z);
2175
0
        if (code == 1)
2176
0
            code = gs_error_undefined;
2177
0
        if (code < 0)
2178
0
            break;
2179
0
        if (value != NULL)
2180
0
            *(size_t *)value = z;
2181
0
        code = sizeof(size_t);
2182
0
        break;
2183
0
    }
2184
0
    case pl_spt_parsed:
2185
0
    {
2186
0
        int len;
2187
0
        code = gs_param_list_to_string((gs_param_list *)&params,
2188
0
                                       param, (char *)value, &len);
2189
0
        if (code == 1)
2190
0
            code = gs_error_undefined;
2191
0
        if (code >= 0)
2192
0
            code = len;
2193
0
        break;
2194
0
    }
2195
0
    default:
2196
0
        code = gs_note_error(gs_error_rangecheck);
2197
0
    }
2198
0
    gs_c_param_list_release(&params);
2199
2200
0
    return code;
2201
0
}
2202
2203
int pl_main_enumerate_params(pl_main_instance_t *pmi, void **iter, const char **key, pl_set_param_type *type)
2204
0
{
2205
0
    int code = 0;
2206
0
    gs_param_key_t keyp;
2207
2208
0
    if (key == NULL)
2209
0
        return -1;
2210
0
    *key = NULL;
2211
0
    if (pmi == NULL || iter == NULL)
2212
0
        return -1;
2213
2214
0
    if (*iter == NULL) {
2215
        /* Free any existing param list. */
2216
0
        gs_c_param_list_release(&pmi->enum_params);
2217
        /* No device -> no params. */
2218
0
        if (pmi->device == NULL)
2219
0
            return 1;
2220
        /* Set up a new one. */
2221
0
        gs_c_param_list_write(&pmi->enum_params, pmi->memory);
2222
        /* Get the keys. */
2223
0
        code = gs_getdeviceparams(pmi->device, (gs_param_list *)&pmi->enum_params);
2224
0
        if (code < 0)
2225
0
            return code;
2226
2227
0
        param_init_enumerator(&pmi->enum_iter);
2228
0
        *iter = &pmi->enum_iter;
2229
0
    } else if (*iter != &pmi->enum_iter)
2230
0
        return -1;
2231
2232
0
    gs_c_param_list_read(&pmi->enum_params);
2233
0
    code = param_get_next_key((gs_param_list *)&pmi->enum_params, &pmi->enum_iter, &keyp);
2234
0
    if (code < 0)
2235
0
        return code;
2236
0
    if (code != 0) {
2237
        /* End of iteration. */
2238
0
        *iter = NULL;
2239
0
        *key = NULL;
2240
0
        return 1;
2241
0
    }
2242
0
    if (pmi->enum_keybuf_max < keyp.size+1) {
2243
0
        int newsize = keyp.size+1;
2244
0
        char *newkey;
2245
0
        if (newsize < 128)
2246
0
            newsize = 128;
2247
0
        if (pmi->enum_keybuf == NULL) {
2248
0
            newkey = (char *)gs_alloc_bytes(pmi->memory, newsize, "enumerator key buffer");
2249
0
        } else {
2250
0
            newkey = (char *)gs_resize_object(pmi->memory, pmi->enum_keybuf, newsize, "enumerator key buffer");
2251
0
        }
2252
0
        if (newkey == NULL)
2253
0
            return_error(gs_error_VMerror);
2254
0
        pmi->enum_keybuf = newkey;
2255
0
        pmi->enum_keybuf_max = newsize;
2256
0
    }
2257
0
    memcpy(pmi->enum_keybuf, keyp.data, keyp.size);
2258
0
    pmi->enum_keybuf[keyp.size] = 0;
2259
0
    *key = pmi->enum_keybuf;
2260
2261
0
    if (type) {
2262
0
        gs_param_typed_value pvalue;
2263
0
        pvalue.type = gs_param_type_any;
2264
0
        code = param_read_typed((gs_param_list *)&pmi->enum_params, *key, &pvalue);
2265
0
        if (code < 0)
2266
0
            return code;
2267
0
        if (code > 0)
2268
0
            return_error(gs_error_unknownerror);
2269
2270
0
        switch (pvalue.type) {
2271
0
        case gs_param_type_null:
2272
0
            *type = pl_spt_null;
2273
0
            break;
2274
0
        case gs_param_type_bool:
2275
0
            *type = pl_spt_bool;
2276
0
            break;
2277
0
        case gs_param_type_int:
2278
0
            *type = pl_spt_int;
2279
0
            break;
2280
0
        case gs_param_type_long:
2281
0
            *type = pl_spt_long;
2282
0
            break;
2283
0
        case gs_param_type_size_t:
2284
0
            *type = pl_spt_size_t;
2285
0
            break;
2286
0
        case gs_param_type_i64:
2287
0
            *type = pl_spt_i64;
2288
0
            break;
2289
0
        case gs_param_type_float:
2290
0
            *type = pl_spt_float;
2291
0
            break;
2292
0
        case gs_param_type_string:
2293
0
            *type = pl_spt_string;
2294
0
            break;
2295
0
        case gs_param_type_name:
2296
0
            *type = pl_spt_name;
2297
0
            break;
2298
0
        default:
2299
0
            *type = pl_spt_parsed;
2300
0
            break;
2301
0
        }
2302
0
    }
2303
2304
0
    return code;
2305
0
}
2306
2307
static int
2308
handle_dash_s(pl_main_instance_t *pmi, const char *arg)
2309
32.0k
{
2310
32.0k
    int code = 0;
2311
32.0k
    const char *eqp;
2312
32.0k
    const char *value;
2313
2314
32.0k
    eqp = strchr(arg, '=');
2315
32.0k
    if (!(eqp || (eqp = strchr(arg, '#')))) {
2316
0
        dmprintf(pmi->memory,
2317
0
                 "Usage for -s is -s<option>=<string>\n");
2318
0
        return -1;
2319
0
    }
2320
32.0k
    value = eqp + 1;
2321
32.0k
    if (argis(arg, "DEVICE")) {
2322
16.0k
        if (pmi->device_index != -1) {
2323
0
            dmprintf(pmi->memory, "DEVICE already set!\n");
2324
0
            return -1;
2325
0
        }
2326
16.0k
        pmi->device_index = get_device_index(pmi->memory, value);
2327
16.0k
        if (pmi->device_index == -1)
2328
0
            return -1;
2329
16.0k
    } else if (argis(arg, "DefaultGrayProfile")) {
2330
0
        pmi->pdefault_gray_icc = arg_copy(value, pmi->memory);
2331
16.0k
    } else if (argis(arg, "DefaultRGBProfile")) {
2332
0
        pmi->pdefault_rgb_icc = arg_copy(value, pmi->memory);
2333
16.0k
    } else if (argis(arg, "DefaultCMYKProfile")) {
2334
0
        pmi->pdefault_cmyk_icc = arg_copy(value, pmi->memory);
2335
16.0k
    } else if (argis(arg, "ICCProfileDir")) {
2336
0
        pmi->piccdir = arg_copy(value, pmi->memory);
2337
16.0k
    } else if (argis(arg, "OutputFile") && strlen(eqp) > 0) {
2338
16.0k
        code = gs_add_outputfile_control_path(pmi->memory, eqp+1);
2339
16.0k
        if (code < 0)
2340
0
            return code;
2341
16.0k
        code = pl_main_set_string_param(pmi, arg);
2342
16.0k
    } else {
2343
0
        code = pl_main_set_string_param(pmi, arg);
2344
0
    }
2345
32.0k
    return code;
2346
32.0k
}
2347
2348
static int
2349
do_arg_match(const char **arg, const char *match, size_t match_len)
2350
0
{
2351
0
    const char *s = *arg;
2352
0
    if (strncmp(s, match, match_len) != 0)
2353
0
        return 0;
2354
0
    s += match_len;
2355
0
    if (*s == '=' || *s == '#')
2356
0
        *arg = ++s;
2357
0
    else if (*s != 0)
2358
0
        return 0;
2359
0
    else
2360
0
        *arg = NULL;
2361
0
    return 1;
2362
0
}
2363
2364
#ifdef GS_HAS_THREADS
2365
static void
2366
trigger_timeout(void *data)
2367
0
{
2368
0
    *(int *)data = 1;
2369
0
}
2370
#endif
2371
2372
0
#define arg_match(A, B) do_arg_match(A, B, sizeof(B)-1)
2373
2374
static int
2375
pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
2376
                        pl_interp_implementation_t * pjli)
2377
16.0k
{
2378
16.0k
    int code = 0;
2379
16.0k
    const char *arg = NULL;
2380
16.0k
    gs_c_param_list *params = &pmi->params;
2381
16.0k
    char *collected_commands = NULL;
2382
16.0k
    bool not_an_arg = 1;
2383
2384
16.0k
    pmi->device_index = -1;
2385
    /* By default, stdin_is_interactive = 1. This mirrors what stdin_init
2386
     * would have done in the iodev one time initialisation. We aren't
2387
     * getting our stdin via an iodev though, so we do it here. */
2388
16.0k
    pmi->memory->gs_lib_ctx->core->stdin_is_interactive = 1;
2389
2390
16.0k
    gs_c_param_list_write_more(params);
2391
128k
    while (arg != NULL || (code = arg_next(pal, (const char **)&arg, pmi->memory)) > 0) {
2392
128k
        if (*arg != '-') /* Stop when we hit something that isn't an option */
2393
16.0k
            break;
2394
112k
        code = gs_lib_ctx_stash_sanitized_arg(pmi->memory->gs_lib_ctx, arg);
2395
112k
        if (code < 0)
2396
0
            return code;
2397
112k
        if (arg[1] == 0) {
2398
            /* Stdin, not an option! */
2399
0
            not_an_arg = 1;
2400
0
            break;
2401
0
        }
2402
112k
        arg += 2;
2403
112k
        switch (arg[-1]) {
2404
0
            case '-':
2405
0
                if (strcmp(arg, "help") == 0) {
2406
0
                    goto help;
2407
0
                } else if (strcmp(arg, "debug") == 0) {
2408
0
                    gs_debug_flags_list(pmi->memory);
2409
0
                    break;
2410
0
                } else if (strncmp(arg, "debug=", 6) == 0 ||
2411
0
                           strncmp(arg, "debug#", 6) == 0) {
2412
0
                    gs_debug_flags_parse(pmi->memory, arg + 6);
2413
0
                    break;
2414
#ifndef OMIT_SAVED_PAGES  /* TBI */
2415
                } else if (strncmp(arg, "saved-pages=", 12) == 0) {
2416
                    gx_device *pdev = pmi->device;
2417
                    gx_device_printer *ppdev = (gx_device_printer *)pdev;
2418
2419
                    /* open the device if not yet open */
2420
                    if (pdev->is_open == 0 && (code = gs_opendevice(pdev)) < 0) {
2421
                        break;
2422
                    }
2423
                    if (dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_saved_pages, NULL, 0) <= 0) {
2424
                        errprintf(pmi->memory, "   --saved-pages not supported by the '%s' device.\n",
2425
                                  pdev->dname);
2426
                        return -1;
2427
                    }
2428
                    code = gx_saved_pages_param_process(ppdev, (byte *)arg+12, strlen(arg+12));
2429
                    if (code > 0) {
2430
                        /* erase the page */
2431
                        gx_color_index color;
2432
                        gx_color_value rgb_white[3] = { 65535, 65535, 65535 };
2433
                        gx_color_value cmyk_white[4] = { 0, 0, 0, 0 };
2434
2435
                        if (pdev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE)
2436
                            color = dev_proc(pdev, map_rgb_color)(pdev, rgb_white);
2437
                        else
2438
                            color = dev_proc(pdev, map_cmyk_color)(pdev, cmyk_white);
2439
                        code = dev_proc(pdev, fill_rectangle)(pdev, 0, 0, pdev->width, pdev->height, color);
2440
                    }
2441
                    break;
2442
#endif /* not defined OMIT_SAVED_PAGES */
2443
                /* The following code is only to allow regression testing of saved-pages */
2444
                /* if OMIT_SAVED_PAGES_TEST is defined, ignore it so testing can proceed */
2445
0
                } else if (strncmp(arg, "saved-pages-test", 16) == 0) {
2446
#ifndef OMIT_SAVED_PAGES_TEST
2447
                    gx_device *pdev = pmi->device;
2448
2449
                    if ((code = gs_opendevice(pdev)) < 0)
2450
                        break;
2451
2452
                    if (dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_saved_pages, NULL, 0) <= 0) {
2453
                        errprintf(pmi->memory, "   --saved-pages-test not supported by the '%s' device.\n",
2454
                                  pdev->dname);
2455
                        break;      /* just ignore it */
2456
                    }
2457
                    code = gx_saved_pages_param_process((gx_device_printer *)pdev, (byte *)"begin", 5);
2458
                    if (code > 0) {
2459
                        /* erase the page */
2460
                        gx_color_index color;
2461
                        gx_color_value rgb_white[3] = { 65535, 65535, 65535 };
2462
                        gx_color_value cmyk_white[4] = { 0, 0, 0, 0 };
2463
2464
                        if (pdev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE)
2465
                            color = dev_proc(pdev, map_rgb_color)(pdev, rgb_white);
2466
                        else
2467
                            color = dev_proc(pdev, map_cmyk_color)(pdev, cmyk_white);
2468
                        code = dev_proc(pdev, fill_rectangle)(pdev, 0, 0, pdev->width, pdev->height, color);
2469
                    }
2470
                    if (code >= 0)
2471
                        pmi->saved_pages_test_mode = true;
2472
#endif /* OMIT_SAVED_PAGES_TEST */
2473
0
                    break;
2474
0
                }
2475
                /* Now handle the explicitly added paths to the file control lists */
2476
0
                else if (arg_match(&arg, "permit-file-read")) {
2477
0
                    code = gs_add_explicit_control_path(pmi->memory, arg, gs_permit_file_reading);
2478
0
                    if (code < 0) return code;
2479
0
                    break;
2480
0
                } else if (arg_match(&arg, "permit-file-write")) {
2481
0
                    code = gs_add_explicit_control_path(pmi->memory, arg, gs_permit_file_writing);
2482
0
                    if (code < 0) return code;
2483
0
                    break;
2484
0
                } else if (arg_match(&arg, "permit-file-control")) {
2485
0
                    code = gs_add_explicit_control_path(pmi->memory, arg, gs_permit_file_control);
2486
0
                    if (code < 0) return code;
2487
0
                    break;
2488
0
                } else if (arg_match(&arg, "permit-file-all")) {
2489
0
                    code = gs_add_explicit_control_path(pmi->memory, arg, gs_permit_file_reading);
2490
0
                    if (code < 0) return code;
2491
0
                    code = gs_add_explicit_control_path(pmi->memory, arg, gs_permit_file_writing);
2492
0
                    if (code < 0) return code;
2493
0
                    code = gs_add_explicit_control_path(pmi->memory, arg, gs_permit_file_control);
2494
0
                    if (code < 0) return code;
2495
0
                    break;
2496
0
                } else if (arg_match(&arg, "permit-devices")) {
2497
0
                    code = gs_add_explicit_permitted_device(pmi->memory, arg);
2498
0
                    if (code < 0) return code;
2499
0
                    break;
2500
0
                } else if (strncmp(arg, "timeout=", 8) == 0) {
2501
0
#ifdef GS_HAS_THREADS
2502
0
                    int secs = atoi(arg+8);
2503
0
                    if (secs == 0)
2504
0
                    {
2505
0
                        dmprintf1(pmi->memory,
2506
0
                                  "   Illegal timeout value '%s' - should be in seconds.\n",
2507
0
                                  arg+8);
2508
0
                        arg_finit(pal);
2509
0
                        return gs_error_Fatal;
2510
0
                    }
2511
0
                    code = gp_alarm_start(&pmi->timeout, pmi->memory, secs, trigger_timeout, &pmi->memory->gs_lib_ctx->core->timedout);
2512
0
                    if (code < 0) return code;
2513
0
                    break;
2514
#else
2515
                    dmprintf(pmi->memory, "Timeouts not supported on builds without threading\n");
2516
                    return gs_error_Fatal;
2517
#endif
2518
0
                }
2519
0
                if (*arg != 0) {
2520
0
                    dmprintf1(pmi->memory, "Unrecognized switch: %s\n", arg-2);
2521
0
                    code = -1;
2522
0
                    break;
2523
0
                }
2524
0
                break;
2525
0
            default:
2526
0
                dmprintf1(pmi->memory, "Unrecognized switch: %s\n", arg-2);
2527
0
                code = -1;
2528
0
                break;
2529
0
            case 'c':
2530
0
                code = handle_dash_c(pmi, pal, &collected_commands, &arg);
2531
0
                if (code < 0)
2532
0
                    arg = NULL;
2533
0
                continue; /* Next arg has already been read, if there is one */
2534
64.0k
            case 'd':
2535
64.0k
            case 'D':
2536
64.0k
                code = pl_main_set_param(pmi, arg);
2537
64.0k
                if (code < 0)
2538
0
                    return code;
2539
64.0k
                break;
2540
64.0k
            case 'E':
2541
0
                if (*arg == 0)
2542
0
                    gs_debug['#'] = 1;
2543
0
                else
2544
0
                    (void)sscanf(arg, "%d", &pmi->error_report);
2545
0
                break;
2546
0
            case 'f':
2547
0
                code = arg_next(pal, (const char **)&arg, pmi->memory);
2548
0
                if (code < 0)
2549
0
                    return code;
2550
0
                if (arg == NULL) {
2551
0
                    dmprintf(pmi->memory, "-f must be followed by a filename\n");
2552
0
                    continue;
2553
0
                }
2554
0
                code = gs_lib_ctx_stash_sanitized_arg(pmi->memory->gs_lib_ctx, "?");
2555
0
                if (code < 0)
2556
0
                    return code;
2557
0
                goto out;
2558
0
            case 'g':
2559
0
                {
2560
0
                    int geom[2];
2561
0
                    gs_param_int_array ia;
2562
2563
0
                    if (sscanf(arg, "%ux%u", &geom[0], &geom[1]) != 2) {
2564
0
                        dmprintf(pmi->memory,
2565
0
                                 "-g must be followed by <width>x<height>\n");
2566
0
                        return -1;
2567
0
                    }
2568
0
                    ia.data = geom;
2569
0
                    ia.size = 2;
2570
0
                    ia.persistent = false;
2571
0
                    gs_c_param_list_write_more(params);
2572
0
                    code =
2573
0
                        param_write_int_array((gs_param_list *) params,
2574
0
                                              "HWSize", &ia);
2575
0
                    if (code >= 0) {
2576
0
                        pmi->page_set_on_command_line = true;
2577
0
                        pmi->page_size[0] = geom[0];
2578
0
                        pmi->page_size[1] = geom[1];
2579
0
                    }
2580
0
                }
2581
0
                break;
2582
0
            case 'h':
2583
0
help:
2584
0
                arg_finit(pal);
2585
0
                gs_c_param_list_release(params);
2586
0
                return gs_error_Info;
2587
0
            case 'H':
2588
0
                {
2589
0
                    float hwmarg[4];
2590
0
                    gs_param_float_array fa;
2591
0
                    uint sz = countof(hwmarg);
2592
0
                    uint parsed = parse_floats(pmi->memory, sz, arg, hwmarg);
2593
0
                    if (parsed != sz) {
2594
0
                        dmprintf(pmi->memory,
2595
0
                                 "-H must be followed by <left>x<bottom>x<right>x<top>\n");
2596
0
                        return -1;
2597
0
                    }
2598
0
                    fa.data = hwmarg;
2599
0
                    fa.size = parsed;
2600
0
                    fa.persistent = false;
2601
0
                    gs_c_param_list_write_more(params);
2602
0
                    code =
2603
0
                        param_write_float_array((gs_param_list *) params,
2604
0
                                              ".HWMargins", &fa);
2605
0
                }
2606
0
                break;
2607
0
            case 'I':               /* specify search path */
2608
0
                {
2609
0
                    const char *path;
2610
2611
0
                    if (arg[0] == 0) {
2612
0
                        code = arg_next(pal, (const char **)&path, pmi->memory);
2613
0
                        if (code < 0)
2614
0
                            return code;
2615
0
                        code = gs_lib_ctx_stash_sanitized_arg(pmi->memory->gs_lib_ctx, "?");
2616
0
                        if (code < 0)
2617
0
                            return code;
2618
0
                    } else
2619
0
                        path = arg;
2620
0
                    if (path == NULL)
2621
0
                        return gs_error_Fatal;
2622
0
                    code = pass_path_to_languages(pmi, path);
2623
0
                }
2624
0
                break;
2625
                /* job control line follows - PJL */
2626
0
            case 'j':
2627
0
            case 'J':
2628
                /* set up the read cursor and send it to the pjl parser */
2629
0
                {
2630
0
                    stream_cursor_read cursor;
2631
                    /* PJL lines have max length of 80 character + null terminator */
2632
0
                    byte buf[512];
2633
                    /* length of arg + newline (expected by PJL parser) + null */
2634
0
                    int buf_len = strlen(arg) + 2;
2635
0
                    if ((buf_len) > sizeof(buf)) {
2636
0
                        dmprintf(pmi->memory, "pjl sequence too long\n");
2637
0
                        return -1;
2638
0
                    }
2639
2640
                    /* replace ";" with newline for the PJL parser and
2641
                       concatenate NULL. */
2642
0
                    {
2643
0
                        int i;
2644
2645
0
                        for (i = 0; i < buf_len - 2; i++) {
2646
0
                            if (arg[i] == ';')
2647
0
                                buf[i] = '\n';
2648
0
                            else
2649
0
                                buf[i] = arg[i];
2650
0
                        }
2651
0
                        buf[i] = '\n';
2652
0
                        i++;
2653
0
                        buf[i] = '\0';
2654
0
                    }
2655
0
                    stream_cursor_read_init(&cursor, (const byte *)buf, buf_len);
2656
2657
                    /* process the pjl */
2658
0
                    code = pl_process(pjli, &cursor);
2659
0
                    pmi->pjl_from_args = true;
2660
                    /* we expect the language to exit properly otherwise
2661
                       there was some sort of problem */
2662
0
                    if (code != e_ExitLanguage) {
2663
0
                        if (code == 0) code = -1;
2664
0
                    } else
2665
0
                        code = 0;
2666
0
                }
2667
0
                break;
2668
0
            case 'K':          /* max memory in K */
2669
0
                {
2670
0
                    int maxk;
2671
0
                    gs_malloc_memory_t *rawheap =
2672
0
                        (gs_malloc_memory_t *) gs_memory_chunk_target(pmi->
2673
0
                                                                      memory)->
2674
0
                        non_gc_memory;
2675
0
                    if (sscanf(arg, "%d", &maxk) != 1) {
2676
0
                        dmprintf(pmi->memory,
2677
0
                                 "-K must be followed by a number\n");
2678
0
                        code = -1;
2679
0
                    }
2680
0
                    else {
2681
0
                        if (rawheap != NULL)
2682
0
                            rawheap->limit = (long)maxk << 10;
2683
0
                    }
2684
0
                }
2685
0
                break;
2686
0
            case 'l':          /* personality */
2687
0
                {
2688
0
                    if (!strcmp(arg, "RTL") || !strcmp(arg, "PCL5E") ||
2689
0
                        !strcmp(arg, "PCL5C"))
2690
0
                        strcpy(pmi->pcl_personality, arg);
2691
0
                    else
2692
0
                        dmprintf(pmi->memory,
2693
0
                                 "PCL personality must be RTL, PCL5E or PCL5C\n");
2694
0
                }
2695
0
                break;
2696
0
            case 'L':          /* language */
2697
0
                {
2698
0
                    int index;
2699
0
                    pl_interp_implementation_t **impls = pmi->implementations;
2700
2701
                    /*
2702
                     * the 0th entry always holds the PJL
2703
                     * implementation, which is never explicitly
2704
                     * selected.
2705
                     */
2706
0
                    for (index = 1; impls[index] != 0; ++index)
2707
0
                        if (!strcmp(arg,
2708
0
                                    pl_characteristics(impls[index])->
2709
0
                                    language))
2710
0
                            break;
2711
0
                    if (impls[index] != 0)
2712
0
                        pmi->implementation = impls[index];
2713
0
                    else {
2714
0
                        dmprintf(pmi->memory,
2715
0
                                 "Choose language in -L<language> from: ");
2716
0
                        for (index = 1; impls[index] != 0; ++index)
2717
0
                            dmprintf1(pmi->memory, "%s ",
2718
0
                                      pl_characteristics(impls[index])->
2719
0
                                      language);
2720
0
                        dmprintf(pmi->memory, "\n");
2721
0
                        return -1;
2722
0
                    }
2723
0
                    break;
2724
0
                }
2725
0
            case 'm':
2726
0
                {
2727
0
                    float marg[2];
2728
0
                    gs_param_float_array fa;
2729
0
                    uint sz = countof(marg);
2730
0
                    uint parsed = parse_floats(pmi->memory, sz, arg, marg);
2731
0
                    if (parsed != sz) {
2732
0
                        dmprintf(pmi->memory,
2733
0
                                 "-m must be followed by <left>x<bottom>\n");
2734
0
                        return -1;
2735
0
                    }
2736
0
                    fa.data = marg;
2737
0
                    fa.size = parsed;
2738
0
                    fa.persistent = false;
2739
0
                    gs_c_param_list_write_more(params);
2740
0
                    code =
2741
0
                        param_write_float_array((gs_param_list *) params,
2742
0
                                                "Margins", &fa);
2743
2744
0
                }
2745
0
                break;
2746
0
            case 'o':
2747
0
                {
2748
0
                    const char *adef;
2749
0
                    gs_param_string str;
2750
2751
0
                    if (arg[0] == 0) {
2752
0
                        code = arg_next(pal, (const char **)&adef, pmi->memory);
2753
0
                        if (code < 0)
2754
0
                            break;
2755
0
                        code = gs_lib_ctx_stash_sanitized_arg(pmi->memory->gs_lib_ctx, "?");
2756
0
                        if (code < 0)
2757
0
                            return code;
2758
0
                    } else
2759
0
                        adef = arg;
2760
0
                    if (adef == NULL)
2761
0
                    {
2762
0
                        code = gs_error_undefinedfilename;
2763
0
                        break;
2764
0
                    }
2765
0
                    code = gs_add_outputfile_control_path(pmi->memory, adef);
2766
0
                    if (code < 0)
2767
0
                        break;
2768
0
                    param_string_from_transient_string(str, adef);
2769
0
                    gs_c_param_list_write_more(params);
2770
0
                    code = param_write_string((gs_param_list *) params,
2771
0
                                              "OutputFile", &str);
2772
0
                    if (code < 0)
2773
0
                        break;
2774
0
                    code = pl_main_set_param(pmi, "NOPAUSE");
2775
0
                    pmi->pause = false;
2776
0
                    break;
2777
0
                }
2778
0
            case 'p':
2779
0
                code = pl_main_set_parsed_param(pmi, arg);
2780
0
                if (code < 0)
2781
0
                    return code;
2782
0
                break;
2783
16.0k
            case 'r':
2784
16.0k
                {
2785
16.0k
                    float res[2];
2786
16.0k
                    gs_param_float_array fa;
2787
16.0k
                    uint sz = countof(res);
2788
16.0k
                    uint parsed = parse_floats(pmi->memory, sz, arg, res);
2789
16.0k
                    switch (parsed) {
2790
0
                        default:
2791
0
                            dmprintf(pmi->memory,
2792
0
                                     "-r must be followed by <res> or <xres>x<yres>\n");
2793
0
                            return -1;
2794
0
                        case 1:        /* -r<res> */
2795
0
                            res[1] = res[0];
2796
16.0k
                        case 2:        /* -r<xres>x<yres> */
2797
16.0k
                            ;
2798
16.0k
                    }
2799
16.0k
                    fa.data = res;
2800
16.0k
                    fa.size = sz;
2801
16.0k
                    fa.persistent = false;
2802
16.0k
                    gs_c_param_list_write_more(params);
2803
16.0k
                    code =
2804
16.0k
                        param_write_float_array((gs_param_list *) params,
2805
16.0k
                                                "HWResolution", &fa);
2806
16.0k
                    if (code == 0) {
2807
16.0k
                        pmi->res_set_on_command_line = true;
2808
16.0k
                        pmi->res[0] = res[0];
2809
16.0k
                        pmi->res[1] = res[1];
2810
16.0k
                    }
2811
16.0k
                }
2812
0
                break;
2813
32.0k
            case 's':
2814
32.0k
            case 'S':
2815
32.0k
                code = handle_dash_s(pmi, arg);
2816
32.0k
                if (code < 0)
2817
0
                    return code;
2818
32.0k
                break;
2819
32.0k
            case 'q':
2820
                /* Silently accept -q to match gs. We are pretty quiet
2821
                 * on startup anyway. */
2822
0
                code = pl_main_set_param(pmi, "QUIET");
2823
0
                break;
2824
0
            case 'v':               /* print revision */
2825
0
                errprintf(pmi->memory, "%s\n", PJL_VERSION_STRING);
2826
0
                arg_finit(pal);
2827
0
                gs_c_param_list_release(params);
2828
0
                return 0;
2829
0
            case 'Z':
2830
0
                set_debug_flags(arg, gs_debug);
2831
0
                break;
2832
112k
        }
2833
112k
        if (code < 0)
2834
0
            return code;
2835
112k
        arg = NULL;
2836
112k
    }
2837
16.0k
  out:
2838
    /* Do any last minute language specific device initialisation
2839
     * (i.e. let gs_init.ps do its worst). */
2840
16.0k
    code = pl_main_post_args_init(pmi);
2841
16.0k
    if (code < 0)
2842
0
        return code;
2843
2844
    /* We must not activate path control until after the main args, because if we are running
2845
     * the PostScript interpreter then gs_init.ps needs to set the default device, and that
2846
     * will fail if we have active path control.
2847
     */
2848
16.0k
    if (pmi->safer && !gs_is_path_control_active(pmi->memory))
2849
0
        gs_activate_path_control(pmi->memory, pmi->safer);
2850
2851
16.0k
    gs_c_param_list_read(params);
2852
16.0k
    code = pl_top_create_device(pmi); /* create default device if needed */
2853
16.0k
    if (code < 0)
2854
0
        return code;
2855
2856
16.0k
    code = gs_putdeviceparams(pmi->device, (gs_param_list *) params);
2857
16.0k
    if (code < 0)
2858
0
        return code;
2859
2860
    /* If we have (at least one) filename to process */
2861
16.0k
    if (arg) {
2862
        /* From here on in, we can only accept -c, -d, -f, -s, -p and filenames */
2863
        /* In the unlikely event that someone wants to run a file starting with
2864
         * a '-', they'll do "-f -blah". The - of the "-blah" must not be accepted
2865
         * by the arg processing in the loop below. We use 'not_an_arg' to handle
2866
         * this. */
2867
31.8k
        while (1) {
2868
31.8k
            if (arg == NULL) {
2869
15.8k
                code = arg_next(pal, (const char **)&arg, pmi->memory);
2870
15.8k
                if (code < 0)
2871
0
                    break;
2872
15.8k
                if (arg == NULL)
2873
15.8k
                    break;
2874
0
                code = gs_lib_ctx_stash_sanitized_arg(pmi->memory->gs_lib_ctx, arg);
2875
0
                if (code < 0)
2876
0
                    return code;
2877
0
            }
2878
16.0k
            if (!not_an_arg && arg[0] == '-' && arg[1] == 'c') {
2879
0
                code = handle_dash_c(pmi, pal, &collected_commands, &arg);
2880
0
                if (code < 0)
2881
0
                    break;
2882
0
                not_an_arg = 0;
2883
0
                continue; /* We've already read any -f into arg */
2884
16.0k
            } else if (!not_an_arg && arg[0] == '-' &&
2885
0
                       (arg[1] == 's' || arg[1] == 'S')) {
2886
0
                code = handle_dash_s(pmi, arg+2);
2887
0
                if (code < 0)
2888
0
                    break;
2889
0
                arg = NULL;
2890
0
                not_an_arg = 0;
2891
0
                continue; /* We've already read any -f into arg */
2892
16.0k
            } else if (!not_an_arg && arg[0] == '-' &&
2893
0
                       (arg[1] == 'd' || arg[1] == 'D')) {
2894
0
                code = pl_main_set_param(pmi, arg+2);
2895
0
                if (code < 0)
2896
0
                    break;
2897
0
                arg = NULL;
2898
0
                not_an_arg = 0;
2899
0
                continue; /* We've already read any -f into arg */
2900
16.0k
            } else if (!not_an_arg && arg[0] == '-' && arg[1] == 'p') {
2901
0
                code = pl_main_set_parsed_param(pmi, arg+2);
2902
0
                if (code < 0)
2903
0
                    break;
2904
0
                arg = NULL;
2905
0
                not_an_arg = 0;
2906
0
                continue; /* We've already read any -f into arg */
2907
16.0k
            } else if (!not_an_arg && arg[0] == '-' && arg[1] == 'f') {
2908
0
                code = arg_next(pal, (const char **)&arg, pmi->memory);
2909
0
                if (code < 0)
2910
0
                    return code;
2911
0
                if (arg == NULL) {
2912
0
                    dmprintf(pmi->memory, "-f must be followed by a filename\n");
2913
0
                    continue;
2914
0
                }
2915
0
                code = gs_lib_ctx_stash_sanitized_arg(pmi->memory->gs_lib_ctx, "?");
2916
0
                if (code < 0)
2917
0
                    return code;
2918
0
                not_an_arg = 1;
2919
0
                continue;
2920
16.0k
            } else {
2921
16.0k
                code = gs_add_control_path(pmi->memory, gs_permit_file_reading, arg);
2922
16.0k
                if (code < 0)
2923
0
                    break;
2924
16.0k
                code = pl_main_run_file_utf8(pmi, collected_commands, arg);
2925
16.0k
                (void)gs_remove_control_path(pmi->memory, gs_permit_file_reading, arg);
2926
16.0k
                if (code == gs_error_undefinedfilename)
2927
0
                    errprintf(pmi->memory, "Failed to open file '%s'\n", arg);
2928
16.0k
                gs_free_object(pmi->memory, collected_commands, "-c buffer");
2929
16.0k
                collected_commands = NULL;
2930
16.0k
                if (code < 0)
2931
114
                    break;
2932
16.0k
            }
2933
15.8k
            arg = NULL;
2934
15.8k
            not_an_arg = 0;
2935
15.8k
        }
2936
16.0k
    }
2937
2938
16.0k
    if (code == 0 && collected_commands != NULL) {
2939
        /* Find the PS interpreter */
2940
0
        int index;
2941
0
        pl_interp_implementation_t **impls = pmi->implementations;
2942
2943
        /* Start at 1 to skip PJL */
2944
0
        for (index = 1; impls[index] != 0; ++index)
2945
0
            if (!strcmp("POSTSCRIPT",
2946
0
                        pl_characteristics(impls[index])->language))
2947
0
                break;
2948
0
        if (impls[index] == 0) {
2949
0
            dmprintf(pmi->memory, "-c can only be used in a built with POSTSCRIPT included.\n");
2950
0
            return gs_error_Fatal;
2951
0
        }
2952
0
        pmi->implementation = impls[index];
2953
0
        code = pl_main_run_prefix(pmi, collected_commands);
2954
0
    }
2955
16.0k
    gs_free_object(pmi->memory, collected_commands, "-c buffer");
2956
16.0k
    collected_commands = NULL;
2957
2958
16.0k
    return code;
2959
16.0k
}
2960
2961
68.6k
#define PJL_UEL "\033%-12345X"
2962
2963
/* Find default language implementation */
2964
static pl_interp_implementation_t *
2965
pl_auto_sense(pl_main_instance_t *minst, const char *buffer,  int buffer_length)
2966
34.7k
{
2967
    /* Lookup this string in the auto sense field for each implementation */
2968
34.7k
    pl_interp_implementation_t **impls = minst->implementations;
2969
34.7k
    pl_interp_implementation_t **impl;
2970
34.7k
    size_t uel_len = strlen(PJL_UEL);
2971
34.7k
    pl_interp_implementation_t *best = NULL;
2972
34.7k
    int max_score = 0;
2973
2974
    /* first check for a UEL */
2975
34.7k
    if (buffer_length >= uel_len) {
2976
33.9k
        if (!memcmp(buffer, PJL_UEL, uel_len))
2977
3.52k
            return impls[0];
2978
33.9k
    }
2979
2980
    /* Defaults to language 1 (if there is one): PJL is language 0, PCL is language 1. */
2981
31.1k
    best = impls[1] ? impls[1] : impls[0];
2982
467k
    for (impl = impls; *impl != NULL; ++impl) {
2983
436k
        int score = pl_characteristics(*impl)->auto_sense(buffer, buffer_length);
2984
436k
        if (score > max_score) {
2985
33.8k
            best = *impl;
2986
33.8k
            max_score = score;
2987
33.8k
        }
2988
436k
    }
2989
31.1k
    return best;
2990
34.7k
}
2991
2992
/* either the (1) implementation has been selected on the command line or
2993
   (2) it has been selected in PJL or (3) we need to auto sense. */
2994
static pl_interp_implementation_t *
2995
pl_select_implementation(pl_interp_implementation_t * pjli,
2996
                         pl_main_instance_t * pmi,
2997
                         const char *ptr,
2998
                         int len)
2999
38.2k
{
3000
    /* Determine language of file to interpret. We're making the incorrect */
3001
    /* assumption that any file only contains jobs in one PDL. The correct */
3002
    /* way to implement this would be to have a language auto-detector. */
3003
38.2k
    pl_interp_implementation_t *impl;
3004
3005
38.2k
    if (pmi->implementation)
3006
0
        return pmi->implementation;     /* was specified as cmd opt */
3007
    /* select implementation */
3008
38.2k
    if ((impl = pl_pjl_select(pmi, pjli)) != 0)
3009
3.51k
        return impl;
3010
    /* lookup string in name field for each implementation */
3011
34.7k
    return pl_auto_sense(pmi, ptr, len);
3012
38.2k
}
3013
3014
/* Find default language implementation */
3015
static pl_interp_implementation_t *
3016
pl_pjl_select(pl_main_instance_t * pmi, pl_interp_implementation_t * pjli)
3017
38.2k
{
3018
38.2k
    pjl_envvar_t *language;
3019
38.2k
    pl_interp_implementation_t **impls = pmi->implementations;
3020
38.2k
    pl_interp_implementation_t **impl;
3021
3022
38.2k
    language = pjl_proc_get_envvar(pjli, "language");
3023
530k
    for (impl = impls; *impl != 0; ++impl) {
3024
495k
        if (!strcmp(pl_characteristics(*impl)->language, language))
3025
3.51k
            return *impl;
3026
495k
    }
3027
34.7k
    return 0;
3028
38.2k
}
3029
3030
/* Print memory and time usage. */
3031
void
3032
pl_print_usage(const pl_main_instance_t * pti, const char *msg)
3033
0
{
3034
0
    long utime[2];
3035
0
    gx_device *pdev = pti->device;
3036
3037
0
    gp_get_realtime(utime);
3038
0
    dmprintf3(pti->memory, "%% %s time = %g, pages = %ld\n",
3039
0
              msg, utime[0] - pti->base_time[0] +
3040
0
              (utime[1] - pti->base_time[1]) / 1000000000.0, pdev->PageCount);
3041
0
}
3042
3043
/* Log a string to console, optionally wait for input */
3044
static void
3045
pl_log_string(const gs_memory_t * mem, const char *str, int wait_for_key)
3046
0
{
3047
0
    errwrite(mem, str, strlen(str));
3048
0
    if (wait_for_key)
3049
0
        (void)fgetc(mem->gs_lib_ctx->core->fstdin);
3050
0
}
3051
3052
bool pl_main_get_interpolate(const gs_memory_t *mem)
3053
22.2k
{
3054
22.2k
    return pl_main_get_instance(mem)->interpolate;
3055
22.2k
}
3056
3057
bool pl_main_get_nocache(const gs_memory_t *mem)
3058
22.3k
{
3059
22.3k
    return pl_main_get_instance(mem)->nocache;
3060
22.3k
}
3061
3062
bool pl_main_get_page_set_on_command_line(const gs_memory_t *mem)
3063
15.6k
{
3064
15.6k
    return pl_main_get_instance(mem)->page_set_on_command_line;
3065
15.6k
}
3066
3067
bool pl_main_get_res_set_on_command_line(const gs_memory_t *mem)
3068
15.6k
{
3069
15.6k
    return pl_main_get_instance(mem)->res_set_on_command_line;
3070
15.6k
}
3071
3072
void pl_main_get_forced_geometry(const gs_memory_t *mem, const float **resolutions, const long **dimensions)
3073
16.0k
{
3074
16.0k
    pl_main_instance_t *minst = pl_main_get_instance(mem);
3075
3076
16.0k
    if (resolutions) {
3077
16.0k
        if (minst->res_set_on_command_line)
3078
16.0k
            *resolutions = minst->res;
3079
0
        else
3080
0
            *resolutions = NULL;
3081
16.0k
    }
3082
16.0k
    if (dimensions) {
3083
16.0k
        if (minst->page_set_on_command_line)
3084
0
            *dimensions = minst->page_size;
3085
16.0k
        else
3086
16.0k
            *dimensions = NULL;
3087
16.0k
    }
3088
16.0k
}
3089
3090
bool pl_main_get_high_level_device(const gs_memory_t *mem)
3091
22.2k
{
3092
22.2k
    return pl_main_get_instance(mem)->high_level_device;
3093
22.2k
}
3094
3095
bool pl_main_get_rasterop_support(const gs_memory_t *mem)
3096
22.2k
{
3097
22.2k
    return pl_main_get_instance(mem)->supports_rasterops;
3098
22.2k
}
3099
3100
bool pl_main_get_scanconverter(const gs_memory_t *mem)
3101
7.31k
{
3102
7.31k
    return pl_main_get_instance(mem)->scanconverter;
3103
7.31k
}
3104
3105
int
3106
pl_set_icc_params(const gs_memory_t *mem, gs_gstate *pgs)
3107
22.3k
{
3108
22.3k
    pl_main_instance_t *minst = pl_main_get_instance(mem);
3109
22.3k
    gs_param_string p;
3110
22.3k
    int code = 0;
3111
3112
22.3k
    if (minst->pdefault_gray_icc) {
3113
0
        param_string_from_transient_string(p, minst->pdefault_gray_icc);
3114
0
        code = gs_setdefaultgrayicc(pgs, &p);
3115
0
        if (code < 0)
3116
0
            return gs_throw_code(gs_error_Fatal);
3117
0
    }
3118
3119
22.3k
    if (minst->pdefault_rgb_icc) {
3120
0
        param_string_from_transient_string(p, minst->pdefault_rgb_icc);
3121
0
        code = gs_setdefaultrgbicc(pgs, &p);
3122
0
        if (code < 0)
3123
0
            return gs_throw_code(gs_error_Fatal);
3124
0
    }
3125
3126
22.3k
    if (minst->piccdir) {
3127
0
        param_string_from_transient_string(p, minst->piccdir);
3128
0
        code = gs_seticcdirectory(pgs, &p);
3129
0
        if (code < 0)
3130
0
            return gs_throw_code(gs_error_Fatal);
3131
0
    }
3132
22.3k
    return code;
3133
22.3k
}
3134
3135
int
3136
pl_finish_page(pl_main_instance_t * pmi, gs_gstate * pgs, int num_copies, int flush)
3137
154k
{
3138
154k
    int code        = 0;
3139
154k
    gx_device *pdev = pmi->device;
3140
3141
    /* output the page */
3142
154k
    if (gs_debug_c(':'))
3143
0
        pl_print_usage(pmi, "parse done :");
3144
154k
    code = gs_output_page(pgs, num_copies, flush);
3145
154k
    if (code < 0)
3146
0
        return code;
3147
3148
154k
    if (pmi->pause) {
3149
0
        char strbuf[256];
3150
3151
0
        gs_snprintf(strbuf, sizeof(strbuf), "End of page %d, press <enter> to continue.\n",
3152
0
                pdev->PageCount);
3153
0
        pl_log_string(pmi->memory, strbuf, 1);
3154
154k
    } else if (gs_debug_c(':'))
3155
0
        pl_print_usage(pmi, "render done :");
3156
154k
    return 0;
3157
154k
}
3158
3159
pl_interp_implementation_t *
3160
pl_main_get_language_instance(const gs_memory_t *mem, const char *name)
3161
48.9k
{
3162
48.9k
    pl_main_instance_t *minst = pl_main_get_instance(mem);
3163
48.9k
    pl_interp_implementation_t **inst = minst->implementations;
3164
3165
65.8k
    while (*inst)
3166
65.8k
    {
3167
65.8k
        const pl_interp_characteristics_t *chars = (*inst)->proc_characteristics(*inst);
3168
3169
65.8k
        if (strcmp(chars->language, name) == 0)
3170
48.9k
            return *inst;
3171
16.9k
        inst++;
3172
16.9k
    }
3173
3174
0
    return NULL;
3175
48.9k
}
3176
3177
pl_interp_implementation_t *pl_main_get_pdf_instance(const gs_memory_t *mem)
3178
0
{
3179
0
    return pl_main_get_language_instance(mem, "PDF");
3180
0
}
3181
3182
pl_interp_implementation_t *
3183
pl_main_get_pcl_instance(const gs_memory_t *mem)
3184
16.9k
{
3185
16.9k
    return pl_main_get_language_instance(mem, "PCL");
3186
16.9k
}
3187
3188
pl_interp_implementation_t *
3189
pl_main_get_pjl_instance(const gs_memory_t *mem)
3190
32.0k
{
3191
32.0k
    return pl_main_get_language_instance(mem, "PJL");
3192
32.0k
}
3193
3194
pl_interp_implementation_t *
3195
pl_main_get_xps_instance(const gs_memory_t *mem)
3196
0
{
3197
0
    return pl_main_get_language_instance(mem, "XPS");
3198
0
}