Coverage Report

Created: 2026-04-01 07:17

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