Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/imainarg.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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
/* Command line parsing and dispatching */
18
19
#include "ctype_.h"
20
#include "memory_.h"
21
#include "string_.h"
22
#include <stdlib.h>     /* for qsort */
23
24
#include "ghost.h"
25
#include "gp.h"
26
#include "gsargs.h"
27
#include "gscdefs.h"
28
#include "gsmalloc.h"           /* for gs_malloc_limit */
29
#include "gsmdebug.h"
30
#include "gspaint.h"    /* for gs_erasepage */
31
#include "gxdevice.h"
32
#include "gxdevmem.h"
33
#include "gsdevice.h"
34
#include "gxdevsop.h"   /* for gxdso_* enums */
35
#include "gxclpage.h"
36
#include "gdevprn.h"
37
#include "stream.h"
38
#include "ierrors.h"
39
#include "estack.h"
40
#include "ialloc.h"
41
#include "strimpl.h"            /* for sfilter.h */
42
#include "sfilter.h"            /* for iscan.h */
43
#include "ostack.h"             /* must precede iscan.h */
44
#include "iscan.h"
45
#include "iconf.h"
46
#include "imain.h"
47
#include "imainarg.h"
48
#include "iapi.h"
49
#include "iminst.h"
50
#include "iname.h"
51
#include "store.h"
52
#include "files.h"              /* requires stream.h */
53
#include "interp.h"
54
#include "iutil.h"
55
#include "ivmspace.h"
56
57
/* Import operator procedures */
58
extern int zflush(i_ctx_t *);
59
extern int zflushpage(i_ctx_t *);
60
61
#ifndef GS_LIB
62
162k
#  define GS_LIB "GS_LIB"
63
#endif
64
65
#ifndef GS_OPTIONS
66
162k
#  define GS_OPTIONS "GS_OPTIONS"
67
#endif
68
69
/* This is now the default number of entries we initially
70
 * allocate for the search path array objects. The arrays
71
 * will now enlarge as required -
72
 * see imain.c: file_path_add()/extend_path_list_container()
73
 */
74
75
#ifndef GS_MAX_LIB_DIRS
76
162k
#  define GS_MAX_LIB_DIRS 25
77
#endif
78
79
0
#define MAX_BUFFERED_SIZE 1024
80
81
/* Note: sscanf incorrectly defines its first argument as char * */
82
/* rather than const char *.  This accounts for the ugly casts below. */
83
84
/* Redefine puts to use outprintf, */
85
/* so it will work even without stdio. */
86
#undef puts
87
0
#define puts(mem, str) outprintf(mem, "%s\n", str)
88
89
/* Forward references */
90
0
#define runInit 1
91
324k
#define runFlush 2
92
#define runBuffer 4
93
static int swproc(gs_main_instance *, const char *, arg_list *);
94
static int argproc(gs_main_instance *, const char *);
95
static int run_buffered(gs_main_instance *, const char *);
96
static int esc_strlen(const char *);
97
static void esc_strcat(char *, const char *);
98
static int runarg(gs_main_instance *, const char *, const char *, const char *, int, int, int *, ref *);
99
static int run_string(gs_main_instance *, const char *, int, int, int *, ref *);
100
static int run_finish(gs_main_instance *, int, int, ref *);
101
static int try_stdout_redirect(gs_main_instance * minst,
102
                                const char *command, const char *filename);
103
104
/* Forward references for help printout */
105
static void print_help(gs_main_instance *);
106
static void print_revision(const gs_main_instance *);
107
static void print_version(const gs_main_instance *);
108
static void print_usage(const gs_main_instance *);
109
static void print_devices(const gs_main_instance *);
110
static void print_emulators(const gs_main_instance *);
111
static void print_paths(gs_main_instance *);
112
static void print_help_trailer(const gs_main_instance *);
113
114
/* ------ Main program ------ */
115
116
/* Process the command line with a given instance. */
117
static stream *
118
gs_main_arg_sopen(const char *fname, void *vminst)
119
0
{
120
0
    gs_main_set_lib_paths((gs_main_instance *) vminst);
121
0
    return lib_sopen(&((gs_main_instance *)vminst)->lib_path,
122
0
                     ((gs_main_instance *)vminst)->heap, fname);
123
0
}
124
static void
125
set_debug_flags(const char *arg, char *flags)
126
0
{
127
0
    byte value = (*arg == '-' ? (++arg, 0) : 0xff);
128
129
0
    while (*arg)
130
0
        flags[*arg++ & 127] = value;
131
0
}
132
133
int
134
gs_main_init_with_args01(gs_main_instance * minst, int argc, char *argv[])
135
162k
{
136
162k
    const char *arg;
137
162k
    arg_list args;
138
162k
    int code;
139
162k
    int have_dumped_args = 0;
140
141
    /* Now we actually process them */
142
162k
    code = arg_init(&args, (const char **)argv, argc,
143
162k
                    gs_main_arg_sopen, (void *)minst,
144
162k
                    minst->get_codepoint,
145
162k
                    minst->heap);
146
162k
    if (code < 0)
147
0
        return code;
148
162k
    code = gs_main_init0(minst, 0, 0, 0, GS_MAX_LIB_DIRS);
149
162k
    if (code < 0)
150
0
        return code;
151
/* This first check is not needed on VMS since GS_LIB evaluates to the same
152
   value as that returned by gs_lib_default_path.  Also, since GS_LIB is
153
   defined as a searchlist logical and getenv only returns the first entry
154
   in the searchlist, it really doesn't make sense to search that particular
155
   directory twice.
156
*/
157
162k
#ifndef __VMS
158
162k
    {
159
162k
        int len = 0;
160
162k
        int code = gp_getenv(GS_LIB, (char *)0, &len);
161
162
162k
        if (code < 0) {         /* key present, value doesn't fit */
163
0
            char *path = (char *)gs_alloc_bytes(minst->heap, len, "GS_LIB");
164
165
0
            if (path == NULL)
166
0
                return_error(gs_error_VMerror);
167
168
0
            gp_getenv(GS_LIB, path, &len);      /* can't fail */
169
0
            minst->lib_path.env = path;
170
0
        }
171
162k
    }
172
162k
#endif /* __VMS */
173
162k
    minst->lib_path.final = gs_lib_default_path;
174
162k
    code = gs_main_set_lib_paths(minst);
175
162k
    if (code < 0)
176
0
        goto error;
177
    /* Prescan the command line for --help and --version. */
178
162k
    {
179
162k
        int i;
180
162k
        bool helping = false;
181
182
2.92M
        for (i = 1; i < argc; ++i) {
183
2.76M
            if (!arg_strcmp(&args, argv[i], "--")) {
184
                /* A PostScript program will be interpreting all the */
185
                /* remaining switches, so stop scanning. */
186
0
                helping = false;
187
0
                break;
188
2.76M
            } else if (!arg_strcmp(&args, argv[i], "--help")) {
189
0
                print_help(minst);
190
0
                helping = true;
191
2.76M
            } else if (!arg_strcmp(&args, argv[i], "--debug")) {
192
0
                gs_debug_flags_list(minst->heap);
193
0
                helping = true;
194
2.76M
            } else if (!arg_strcmp(&args, argv[i], "--version")) {
195
0
                print_version(minst);
196
0
                puts(minst->heap, "");  /* \n */
197
0
                helping = true;
198
0
            }
199
2.76M
        }
200
162k
        if (helping) {
201
0
            code = gs_note_error(gs_error_Info);
202
0
            goto error;
203
0
        }
204
162k
    }
205
    /* Execute files named in the command line, */
206
    /* processing options along the way. */
207
    /* Wait until the first file name (or the end */
208
    /* of the line) to finish initialization. */
209
162k
    minst->run_start = true;
210
211
162k
    {
212
162k
        int len = 0;
213
162k
        int code = gp_getenv(GS_OPTIONS, (char *)0, &len);
214
215
162k
        if (code < 0) {         /* key present, value doesn't fit */
216
0
            char *opts =
217
0
            (char *)gs_alloc_bytes(minst->heap, len, "GS_OPTIONS");
218
219
0
            if (opts == NULL) {
220
0
                code = gs_note_error(gs_error_VMerror);
221
0
                    goto error;
222
0
            }
223
0
            gp_getenv(GS_OPTIONS, opts, &len);  /* can't fail */
224
0
            if (arg_push_decoded_memory_string(&args, opts, false, true, minst->heap)) {
225
0
                if (opts != NULL)
226
0
                    gs_free_object(minst->heap, opts, "error in gs_main_init_with_args");
227
0
                code = gs_note_error(gs_error_Fatal);
228
0
                goto error;
229
0
            }
230
0
        }
231
162k
    }
232
2.88M
    while ((code = arg_next(&args, (const char **)&arg, minst->heap)) > 0) {
233
2.76M
        code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, arg);
234
2.76M
        if (code < 0)
235
0
            goto error;
236
2.76M
        switch (*arg) {
237
2.76M
            case '-':
238
2.76M
                code = swproc(minst, arg, &args);
239
2.76M
                if (code < 0)
240
44.1k
                    goto error;
241
2.71M
                if (code > 0)
242
0
                    outprintf(minst->heap, "Unknown switch %s - ignoring\n", arg);
243
2.71M
                if (gs_debug[':'] && !have_dumped_args) {
244
0
                    int i;
245
246
0
                    if (gs_debug_c(gs_debug_flag_init_details))
247
0
                        dmprintf1(minst->heap, "%% Args passed to instance "PRI_INTPTR": ",
248
0
                              (intptr_t)minst);
249
0
                    for (i=1; i<argc; i++)
250
0
                        dmprintf1(minst->heap, "%s ", argv[i]);
251
0
                    dmprintf(minst->heap, "\n");
252
0
                    have_dumped_args = 1;
253
0
                }
254
2.71M
                break;
255
0
            default:
256
                /* default is to treat this as a file name to be run */
257
0
                code = argproc(minst, arg);
258
0
                if (code < 0)
259
0
                    goto error;
260
0
                if (minst->saved_pages_test_mode) {
261
0
                    gx_device *pdev;
262
0
                    int ret;
263
0
                    gxdso_device_child_request child_dev_data;
264
265
                    /* get the real target (printer) device */
266
0
                    pdev = gs_currentdevice(minst->i_ctx_p->pgs);
267
0
                    do {
268
0
                        child_dev_data.target = pdev;
269
0
                        ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
270
0
                                                          sizeof(child_dev_data));
271
0
                        if (ret > 0)
272
0
                            pdev = child_dev_data.target;
273
0
                    } while ((ret > 0) && (child_dev_data.n != 0));
274
0
                    if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
275
0
                               (byte *)"print normal flush", 18)) < 0)
276
0
                        goto error;
277
0
                    if (code > 0)
278
0
                        if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
279
0
                            goto error;
280
0
                }
281
2.76M
        }
282
2.76M
    }
283
284
118k
    return code;
285
286
44.1k
error:
287
44.1k
    if (minst->lib_path.env != NULL) {
288
0
        gs_free_object(minst->heap, (char *)minst->lib_path.env, "error in gs_main_init_with_args");
289
0
        minst->lib_path.env = NULL;
290
0
    }
291
44.1k
    return code;
292
162k
}
293
294
int
295
gs_main_init_with_args2(gs_main_instance * minst)
296
118k
{
297
118k
    int code;
298
299
118k
    code = gs_main_init2(minst);
300
118k
    if (code < 0)
301
0
        return code;
302
303
118k
    if (!minst->run_start)
304
118k
        return gs_error_Quit;
305
0
    return code;
306
118k
}
307
308
int
309
gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[])
310
162k
{
311
162k
    int code = gs_main_init_with_args01(minst, argc, argv);
312
313
162k
    if (code < 0)
314
44.1k
        return code;
315
118k
    return gs_main_init_with_args2(minst);
316
162k
}
317
318
/*
319
 * Specify a decoding function
320
 */
321
void gs_main_inst_arg_decode(gs_main_instance * minst,
322
                             gs_arg_get_codepoint *get_codepoint)
323
324k
{
324
324k
    minst->get_codepoint = get_codepoint;
325
324k
}
326
327
gs_arg_get_codepoint *gs_main_inst_get_arg_decode(gs_main_instance * minst)
328
0
{
329
0
    return minst->get_codepoint;
330
0
}
331
332
/*
333
 * Run the 'start' procedure (after processing the command line).
334
 */
335
int
336
gs_main_run_start(gs_main_instance * minst)
337
0
{
338
0
    return run_string(minst, "systemdict /start get exec", runFlush, minst->user_errors, NULL, NULL);
339
0
}
340
341
static int
342
do_arg_match(const char **arg, const char *match, size_t match_len)
343
0
{
344
0
    const char *s = *arg;
345
0
    if (strncmp(s, match, match_len) != 0)
346
0
        return 0;
347
0
    s += match_len;
348
0
    if (*s == '=')
349
0
        *arg = ++s;
350
0
    else if (*s != 0)
351
0
        return 0;
352
0
    else
353
0
        *arg = NULL;
354
0
    return 1;
355
0
}
356
357
0
#define arg_match(A, B) do_arg_match(A, B, sizeof(B)-1)
358
359
/* Process switches.  Return 0 if processed, 1 for unknown switch, */
360
/* <0 if error. */
361
static int
362
swproc(gs_main_instance * minst, const char *arg, arg_list * pal)
363
2.92M
{
364
2.92M
    char sw = arg[1];
365
2.92M
    ref vtrue;
366
2.92M
    int code = 0;
367
368
2.92M
    make_true(&vtrue);
369
2.92M
    arg += 2;                   /* skip - and letter */
370
2.92M
    switch (sw) {
371
0
        default:
372
0
            return 1;
373
0
        case 0:         /* read stdin as a file char-by-char */
374
            /* This is a ******HACK****** for Ghostview. */
375
0
            minst->heap->gs_lib_ctx->core->stdin_is_interactive = true;
376
0
            goto run_stdin;
377
162k
        case '_':       /* read stdin with normal buffering */
378
162k
            minst->heap->gs_lib_ctx->core->stdin_is_interactive = false;
379
162k
run_stdin:
380
162k
            minst->run_start = false;   /* don't run 'start' */
381
            /* Set NOPAUSE so showpage won't try to read from stdin. */
382
162k
            code = swproc(minst, "-dNOPAUSE", pal);
383
162k
            if (code)
384
0
                return code;
385
162k
            code = gs_main_init2(minst);        /* Finish initialization */
386
162k
            if (code < 0)
387
20
                return code;
388
389
162k
            code = run_string(minst, ".runstdin", runFlush, minst->user_errors, NULL, NULL);
390
162k
            if (code < 0)
391
44.1k
                return code;
392
            /* If in saved_pages_test_mode, print and flush previous job before the next file */
393
118k
            if (minst->saved_pages_test_mode) {
394
0
                gx_device *pdev;
395
0
                int ret;
396
0
                gxdso_device_child_request child_dev_data;
397
398
                /* get the real target (printer) device */
399
0
                pdev = gs_currentdevice(minst->i_ctx_p->pgs);
400
0
                do {
401
0
                    child_dev_data.target = pdev;
402
0
                    ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
403
0
                                                      sizeof(child_dev_data));
404
0
                    if (ret > 0)
405
0
                        pdev = child_dev_data.target;
406
0
                } while ((ret > 0) && (child_dev_data.n != 0));
407
0
                if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
408
0
                           (byte *)"print normal flush", 18)) < 0)
409
0
                    return code;
410
0
                if (code > 0)
411
0
                    if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
412
0
                        return code;
413
0
            }
414
118k
            break;
415
118k
        case '-':               /* run with command line args */
416
0
            if (strncmp(arg, "debug=", 6) == 0) {
417
0
                code = gs_debug_flags_parse(minst->heap, arg+6);
418
0
                if (code < 0)
419
0
                    return code;
420
0
                break;
421
0
            } else if (strncmp(arg, "saved-pages=", 12) == 0) {
422
0
                gx_device *pdev;
423
424
                /* If init2 not yet done, just save the argument for processing then */
425
0
                if (minst->init_done < 2) {
426
0
                    if (minst->saved_pages_initial_arg == NULL) {
427
                        /* Tuck the parameters away for later when init2 is done (usually "begin") */
428
0
                        minst->saved_pages_initial_arg = (char *)gs_alloc_bytes(minst->heap,
429
0
                                                                                1+strlen((char *)arg+12),
430
0
                                                                               "GS_OPTIONS");
431
0
                        if (minst->saved_pages_initial_arg != NULL) {
432
0
                            strcpy(minst->saved_pages_initial_arg,(char *)arg+12);
433
0
                        } else {
434
0
                            outprintf(minst->heap,
435
0
                                      "   saved_pages_initial_arg larger than expected\n");
436
0
                            arg_finit(pal);
437
0
                            return gs_error_Fatal;
438
0
                        }
439
0
                    } else {
440
0
                        outprintf(minst->heap,
441
0
                                  "   Only one --saved-pages=... command allowed before processing input\n");
442
0
                        arg_finit(pal);
443
0
                        return gs_error_Fatal;
444
0
                    }
445
0
                } else {
446
0
                    int ret;
447
0
                    gxdso_device_child_request child_dev_data;
448
449
                    /* get the current device */
450
0
                    pdev = gs_currentdevice(minst->i_ctx_p->pgs);
451
0
                    if (dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_saved_pages, NULL, 0) <= 0) {
452
0
                        outprintf(minst->heap,
453
0
                                  "   --saved-pages not supported by the '%s' device.\n",
454
0
                                  pdev->dname);
455
0
                        arg_finit(pal);
456
0
                        return gs_error_Fatal;
457
0
                    }
458
                    /* get the real target (printer) device */
459
0
                    do {
460
0
                        child_dev_data.target = pdev;
461
0
                        ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
462
0
                                                          sizeof(child_dev_data));
463
0
                        if (ret > 0)
464
0
                            pdev = child_dev_data.target;
465
0
                    } while ((ret > 0) && (child_dev_data.n != 0));
466
0
                    if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
467
0
                                                              (byte *)arg+12, strlen(arg+12))) < 0)
468
0
                        return code;
469
0
                    if (code > 0)
470
0
                        if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
471
0
                            return code;
472
0
                }
473
0
                break;
474
            /* The following code is only to allow regression testing of saved-pages */
475
0
            } else if (strncmp(arg, "saved-pages-test", 16) == 0) {
476
0
                minst->saved_pages_test_mode = true;
477
0
                break;
478
            /* Now handle the explicitly added paths to the file control lists */
479
0
            } else if (arg_match(&arg, "permit-file-read")) {
480
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_reading);
481
0
                if (code < 0) return code;
482
0
                break;
483
0
            } else if (arg_match(&arg, "permit-file-write")) {
484
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_writing);
485
0
                if (code < 0) return code;
486
0
                break;
487
0
            } else if (arg_match(&arg, "permit-file-control")) {
488
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_control);
489
0
                if (code < 0) return code;
490
0
                break;
491
0
            } else if (arg_match(&arg, "permit-file-all")) {
492
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_reading);
493
0
                if (code < 0) return code;
494
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_writing);
495
0
                if (code < 0) return code;
496
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_control);
497
0
                if (code < 0) return code;
498
0
                break;
499
0
            } else if (arg_match(&arg, "permit-devices")) {
500
0
                code = gs_add_explicit_permitted_device(minst->heap, arg);
501
0
                if (code < 0) return code;
502
0
                break;
503
0
            }
504
0
            if (*arg != 0) {
505
                /* Unmatched switch. */
506
0
                outprintf(minst->heap,
507
0
                          "   Unknown switch '--%s'.\n",
508
0
                          arg);
509
0
                arg_finit(pal);
510
0
                return gs_error_Fatal;
511
0
            }
512
            /* FALLTHROUGH */
513
0
        case '+':
514
0
            pal->expand_ats = false;
515
            /* FALLTHROUGH */
516
0
        case '@':               /* ditto with @-expansion */
517
0
            {
518
0
                char *psarg;
519
520
0
                code = arg_next(pal, (const char **)&psarg, minst->heap);
521
                /* Don't stash the @ file name */
522
523
0
                if (code < 0)
524
0
                    return gs_error_Fatal;
525
0
                if (psarg == NULL) {
526
0
                    outprintf(minst->heap, "Usage: gs ... -%c file.ps arg1 ... argn\n", sw);
527
0
                    arg_finit(pal);
528
0
                    return gs_error_Fatal;
529
0
                }
530
0
                psarg = arg_copy(psarg, minst->heap);
531
0
                if (psarg == NULL)
532
0
                    code = gs_error_Fatal;
533
0
                else
534
0
                    code = gs_main_init2(minst);
535
0
                if (code >= 0)
536
0
                    code = run_string(minst, "userdict/ARGUMENTS[", 0, minst->user_errors, NULL, NULL);
537
0
                if (code >= 0)
538
0
                    while ((code = arg_next(pal, (const char **)&arg, minst->heap)) > 0) {
539
0
                        code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, arg);
540
0
                        if (code < 0)
541
0
                            break;
542
0
                        code = runarg(minst, "", arg, "", runInit, minst->user_errors, NULL, NULL);
543
0
                        if (code < 0)
544
0
                            break;
545
0
                    }
546
0
                if (code >= 0)
547
0
                    code = run_string(minst, "]put", 0, minst->user_errors, NULL, NULL);
548
0
                if (code >= 0)
549
0
                    code = argproc(minst, psarg);
550
0
                arg_free((char *)psarg, minst->heap);
551
0
                if (code >= 0)
552
0
                    code = gs_error_Quit;
553
554
0
                return code;
555
0
            }
556
0
        case 'B':               /* set run_string buffer size */
557
0
            if (*arg == '-')
558
0
                minst->run_buffer_size = 0;
559
0
            else {
560
0
                uint bsize;
561
562
0
                if (sscanf((const char *)arg, "%u", &bsize) != 1 ||
563
0
                    bsize <= 0 || bsize > MAX_BUFFERED_SIZE
564
0
                    ) {
565
0
                    outprintf(minst->heap,
566
0
                              "-B must be followed by - or size between 1 and %u\n",
567
0
                              MAX_BUFFERED_SIZE);
568
0
                    return gs_error_Fatal;
569
0
                }
570
0
                minst->run_buffer_size = bsize;
571
0
            }
572
0
            break;
573
0
        case 'c':               /* code follows */
574
0
            {
575
0
                bool ats = pal->expand_ats;
576
577
0
                code = gs_main_init2(minst);
578
0
                if (code < 0)
579
0
                    return code;
580
0
                pal->expand_ats = false;
581
0
                while ((code = arg_next(pal, (const char **)&arg, minst->heap)) > 0) {
582
0
                    if (arg[0] == '@' ||
583
0
                        (arg[0] == '-' && !isdigit((unsigned char)arg[1]))
584
0
                        )
585
0
                        break;
586
0
                    code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, "?");
587
0
                    if (code < 0)
588
0
                        return code;
589
0
                    code = runarg(minst, "", arg, ".runstring", 0, minst->user_errors, NULL, NULL);
590
0
                    if (code < 0)
591
0
                        return code;
592
0
                }
593
0
                if (code < 0)
594
0
                    return gs_error_Fatal;
595
0
                if (arg != NULL) {
596
0
                    char *p = arg_copy(arg, minst->heap);
597
0
                    if (p == NULL)
598
0
                        return gs_error_Fatal;
599
0
                    arg_push_string(pal, p, true);
600
0
                }
601
0
                pal->expand_ats = ats;
602
0
                break;
603
0
            }
604
0
        case 'f':               /* run file of arbitrary name */
605
0
            if (*arg != 0) {
606
0
                code = argproc(minst, arg);
607
0
                if (code < 0)
608
0
                    return code;
609
                /* If in saved_pages_test_mode, print and flush previous job before the next file */
610
0
                if (minst->saved_pages_test_mode) {
611
0
                    gx_device *pdev;
612
0
                    int ret;
613
0
                    gxdso_device_child_request child_dev_data;
614
615
                    /* get the real target (printer) device */
616
0
                    pdev = gs_currentdevice(minst->i_ctx_p->pgs);
617
0
                    do {
618
0
                        child_dev_data.target = pdev;
619
0
                        ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
620
0
                                                          sizeof(child_dev_data));
621
0
                        if (ret > 0)
622
0
                            pdev = child_dev_data.target;
623
0
                    } while ((ret > 0) && (child_dev_data.n != 0));
624
0
                    if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
625
0
                               (byte *)"print normal flush", 18)) < 0)
626
0
                        return code;
627
0
                    if (code > 0)
628
0
                        if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
629
0
                            return code;
630
0
                }
631
0
            }
632
0
            break;
633
0
        case 'F':               /* run file with buffer_size = 1 */
634
0
            if (!*arg) {
635
0
                puts(minst->heap, "-F requires a file name");
636
0
                return gs_error_Fatal;
637
0
            } {
638
0
                uint bsize = minst->run_buffer_size;
639
640
0
                minst->run_buffer_size = 1;
641
0
                code = argproc(minst, arg);
642
0
                minst->run_buffer_size = bsize;
643
0
                if (code < 0)
644
0
                    return code;
645
                /* If in saved_pages_test_mode, print and flush previous job before the next file */
646
0
                if (minst->saved_pages_test_mode) {
647
0
                    gx_device *pdev;
648
0
                    int ret;
649
0
                    gxdso_device_child_request child_dev_data;
650
651
                    /* get the real target (printer) device */
652
0
                    pdev = gs_currentdevice(minst->i_ctx_p->pgs);
653
0
                    do {
654
0
                        child_dev_data.target = pdev;
655
0
                        ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
656
0
                                                          sizeof(child_dev_data));
657
0
                        if (ret > 0)
658
0
                            pdev = child_dev_data.target;
659
0
                    } while ((ret > 0) && (child_dev_data.n != 0));
660
0
                    if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
661
0
                               (byte *)"print normal flush", 18)) < 0)
662
0
                        return code;
663
0
                    if (code > 0)
664
0
                        if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
665
0
                            return code;
666
0
                }
667
0
            }
668
0
            break;
669
0
        case 'g':               /* define device geometry */
670
0
            {
671
0
                long dimensions[2];
672
673
0
                if ((code = gs_main_init1(minst)) < 0)
674
0
                    return code;
675
0
                if (sscanf((const char *)arg, "%ldx%ld", &dimensions[0], &dimensions[1]) != 2) {
676
0
                    puts(minst->heap, "-g must be followed by <width>x<height>");
677
0
                    return gs_error_Fatal;
678
0
                }
679
0
                gs_main_force_dimensions(minst, dimensions);
680
0
                break;
681
0
            }
682
0
        case 'h':               /* print help */
683
0
        case '?':               /* ditto */
684
0
            print_help(minst);
685
0
            return gs_error_Info;      /* show usage info on exit */
686
0
        case 'I':               /* specify search path */
687
0
            {
688
0
                const char *path;
689
690
0
                if (arg[0] == 0) {
691
0
                    code = arg_next(pal, (const char **)&path, minst->heap);
692
0
                    if (code < 0)
693
0
                        return code;
694
0
                    code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, "?");
695
0
                    if (code < 0)
696
0
                        return code;
697
0
                } else
698
0
                    path = arg;
699
0
                if (path == NULL)
700
0
                    return gs_error_Fatal;
701
0
                gs_main_add_lib_path(minst, path);
702
0
            }
703
0
            break;
704
162k
        case 'K':               /* set malloc limit */
705
162k
            {
706
162k
                long msize = 0;
707
162k
                gs_malloc_memory_t *rawheap = gs_malloc_wrapped_contents(minst->heap);
708
709
162k
                (void)sscanf((const char *)arg, "%ld", &msize);
710
162k
                if (msize <= 0 || msize > max_long >> 10) {
711
0
                    outprintf(minst->heap, "-K<numK> must have 1 <= numK <= %ld\n",
712
0
                              max_long >> 10);
713
0
                    return gs_error_Fatal;
714
0
                }
715
162k
                rawheap->limit = msize << 10;
716
162k
            }
717
0
            break;
718
0
        case 'M':               /* set memory allocation increment */
719
0
            {
720
0
                unsigned msize = 0;
721
722
0
                (void)sscanf((const char *)arg, "%u", &msize);
723
0
                if (msize <= 0 || msize >= (max_uint >> 10)) {
724
0
                    outprintf(minst->heap, "-M must be between 1 and %d\n", (int)((max_uint >> 10) - 1));
725
0
                    return gs_error_Fatal;
726
0
                }
727
0
                minst->memory_clump_size = msize << 10;
728
0
            }
729
0
            break;
730
0
        case 'N':               /* set size of name table */
731
0
            {
732
0
                unsigned int nsize = 0;
733
734
0
                (void)sscanf((const char *)arg, "%ud", &nsize);
735
0
                if (nsize < 2 || nsize > (max_uint >> 10)) {
736
0
                    outprintf(minst->heap, "-N must be between 2 and %d\n", (int)(max_uint >> 10));
737
0
                    return gs_error_Fatal;
738
0
                }
739
0
                minst->name_table_size = (ulong) nsize << 10;
740
0
            }
741
0
            break;
742
0
        case 'o':               /* set output file name and batch mode */
743
0
            {
744
0
                i_ctx_t *i_ctx_p;
745
0
                uint space;
746
0
                const char *adef;
747
0
                byte *str;
748
0
                ref value;
749
0
                int len;
750
751
0
                if ((code = gs_main_init1(minst)) < 0)
752
0
                    return code;
753
754
0
                i_ctx_p = minst->i_ctx_p;
755
0
                space = icurrent_space;
756
0
                if (arg[0] == 0) {
757
0
                    code = arg_next(pal, (const char **)&adef, minst->heap);
758
0
                    if (code < 0)
759
0
                        return code;
760
0
                    if (code == 0)
761
0
                        return gs_error_undefinedfilename;
762
0
                    code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, "?");
763
0
                    if (code < 0)
764
0
                        return code;
765
0
                } else
766
0
                    adef = arg;
767
0
                if ((code = gs_main_init1(minst)) < 0)
768
0
                    return code;
769
770
0
                if (strlen(adef) > 0) {
771
0
                    code = gs_add_outputfile_control_path(minst->heap, adef);
772
0
                    if (code < 0) return code;
773
0
                }
774
775
0
                ialloc_set_space(idmemory, avm_system);
776
0
                len = strlen(adef);
777
0
                str = ialloc_string(len, "-o");
778
0
                if (str == NULL)
779
0
                    return gs_error_VMerror;
780
0
                memcpy(str, adef, len);
781
0
                make_const_string(&value, a_readonly | avm_system, len, str);
782
0
                ialloc_set_space(idmemory, space);
783
0
                i_initial_enter_name(minst->i_ctx_p, "OutputFile", &value);
784
0
                i_initial_enter_name(minst->i_ctx_p, "NOPAUSE", &vtrue);
785
0
                i_initial_enter_name(minst->i_ctx_p, "BATCH", &vtrue);
786
0
            }
787
0
            break;
788
0
        case 'P':               /* choose whether search '.' first */
789
0
            if (!strcmp(arg, ""))
790
0
                minst->search_here_first = true;
791
0
            else if (!strcmp(arg, "-"))
792
0
                minst->search_here_first = false;
793
0
            else {
794
0
                puts(minst->heap, "Only -P or -P- is allowed.");
795
0
                return gs_error_Fatal;
796
0
            }
797
0
            break;
798
0
        case 'q':               /* quiet startup */
799
0
            if ((code = gs_main_init1(minst)) < 0)
800
0
                return code;
801
0
            i_initial_enter_name(minst->i_ctx_p, "QUIET", &vtrue);
802
0
            break;
803
162k
        case 'r':               /* define device resolution */
804
162k
            {
805
162k
                float res[2];
806
807
162k
                if ((code = gs_main_init1(minst)) < 0)
808
0
                    return code;
809
162k
                switch (sscanf((const char *)arg, "%fx%f", &res[0], &res[1])) {
810
0
                    default:
811
0
                        puts(minst->heap, "-r must be followed by <res> or <xres>x<yres>");
812
0
                        return gs_error_Fatal;
813
0
                    case 1:     /* -r<res> */
814
0
                        res[1] = res[0];
815
                        /* fall through */
816
162k
                    case 2:     /* -r<xres>x<yres> */
817
162k
                        gs_main_force_resolutions(minst, res);
818
162k
                }
819
162k
                break;
820
162k
            }
821
162k
        case 'D':               /* define name */
822
1.78M
        case 'd':
823
1.78M
        case 'S':               /* define name as string */
824
2.43M
        case 's':
825
2.43M
            {
826
2.43M
                char *adef = arg_copy(arg, minst->heap);
827
2.43M
                char *eqp;
828
2.43M
                bool isd = (sw == 'D' || sw == 'd');
829
2.43M
                ref value;
830
831
2.43M
                if (adef == NULL)
832
0
                    return gs_error_Fatal;
833
2.43M
                eqp = strchr(adef, '=');
834
835
2.43M
                if (eqp == NULL)
836
1.13M
                    eqp = strchr(adef, '#');
837
                /* Initialize the object memory, scanner, and */
838
                /* name table now if needed. */
839
2.43M
                if ((code = gs_main_init1(minst)) < 0) {
840
0
                    arg_free((char *)adef, minst->heap);
841
0
                    return code;
842
0
                }
843
2.43M
                if (eqp == adef) {
844
0
                    puts(minst->heap, "Usage: -dNAME, -dNAME=TOKEN, -sNAME=STRING");
845
0
                    arg_free((char *)adef, minst->heap);
846
0
                    return gs_error_Fatal;
847
0
                }
848
2.43M
                if (eqp == NULL) {
849
1.13M
                    if (isd)
850
1.13M
                        make_true(&value);
851
0
                    else
852
1.13M
                        make_empty_string(&value, a_readonly);
853
1.29M
                } else {
854
1.29M
                    int code;
855
1.29M
                    i_ctx_t *i_ctx_p = minst->i_ctx_p;
856
1.29M
                    uint space = icurrent_space;
857
858
1.29M
                    *eqp++ = 0;
859
860
1.29M
                    if (strlen(adef) == 10 && strncmp(adef, "OutputFile", 10) == 0 && strlen(eqp) > 0) {
861
162k
                        code = gs_add_outputfile_control_path(minst->heap, eqp);
862
162k
                        if (code < 0) {
863
0
                            arg_free((char *)adef, minst->heap);
864
0
                            return code;
865
0
                        }
866
162k
                    }
867
868
1.29M
                    ialloc_set_space(idmemory, avm_system);
869
1.29M
                    if (isd) {
870
649k
                        int i;
871
649k
                        int64_t num;
872
873
                        /* Check for numbers so we can provide for suffix scalers */
874
                        /* Note the check for '#' is for PS "radix" numbers such as 16#ff */
875
                        /* and check for '.' and 'e' or 'E' which are 'real' numbers */
876
649k
                        if ((strchr(eqp, '#') == NULL) && (strchr(eqp, '.') == NULL) &&
877
649k
                            (strchr(eqp, 'e') == NULL) && (strchr(eqp, 'E') == NULL) &&
878
649k
                            ((i = sscanf((const char *)eqp, "%"PRIi64, &num)) == 1)) {
879
649k
                            char suffix = eqp[strlen(eqp) - 1];
880
881
649k
                            switch (suffix) {
882
162k
                                case 'k':
883
162k
                                case 'K':
884
162k
                                    num *= 1024;
885
162k
                                    break;
886
0
                                case 'm':
887
0
                                case 'M':
888
0
                                    num *= 1024 * 1024;
889
0
                                    break;
890
0
                                case 'g':
891
0
                                case 'G':
892
                                    /* caveat emptor: more than 2g will overflow */
893
                                    /* and really should produce a 'real', so don't do this */
894
0
                                    num *= 1024 * 1024 * 1024;
895
0
                                    break;
896
487k
                                default:
897
487k
                                    break;   /* not a valid suffix or last char was digit */
898
649k
                            }
899
649k
                            make_int(&value, (ps_int)num);
900
649k
                        } else {
901
                            /* use the PS scanner to capture other valid token types */
902
0
                            stream astream;
903
0
                            scanner_state state;
904
905
0
                            s_init(&astream, NULL);
906
0
                            sread_string(&astream,
907
0
                                         (const byte *)eqp, strlen(eqp));
908
0
                            gs_scanner_init_stream(&state, &astream);
909
0
                            code = gs_scan_token(minst->i_ctx_p, &value, &state);
910
0
                            if (code) {
911
0
                                outprintf(minst->heap, "Invalid value for option -d%s, -dNAME= must be followed by a valid token\n", arg);
912
0
                                arg_free((char *)adef, minst->heap);
913
0
                                return gs_error_Fatal;
914
0
                            }
915
0
                            if (r_has_type_attrs(&value, t_name,
916
0
                                                 a_executable)) {
917
0
                                ref nsref;
918
919
0
                                name_string_ref(minst->heap, &value, &nsref);
920
0
#undef string_is
921
0
#define string_is(nsref, str, len)\
922
0
       (r_size(&(nsref)) == (len) &&\
923
0
       !strncmp((const char *)(nsref).value.const_bytes, str, (len)))
924
0
                                if (string_is(nsref, "null", 4))
925
0
                                    make_null(&value);
926
0
                                else if (string_is(nsref, "true", 4))
927
0
                                    make_true(&value);
928
0
                                else if (string_is(nsref, "false", 5))
929
0
                                    make_false(&value);
930
0
                                else {
931
0
                                    outprintf(minst->heap, "Invalid value for option -d%s, use -sNAME= to define string constants\n", arg);
932
0
                                    arg_free((char *)adef, minst->heap);
933
0
                                    return gs_error_Fatal;
934
0
                                }
935
0
                            }
936
0
                        }
937
649k
                    } else {
938
649k
                        int len = strlen(eqp);
939
649k
                        byte *body = ialloc_string(len, "-s");
940
941
649k
                        if (body == NULL) {
942
0
                            lprintf("Out of memory!\n");
943
0
                            arg_free((char *)adef, minst->heap);
944
0
                            return gs_error_Fatal;
945
0
                        }
946
649k
                        memcpy(body, eqp, len);
947
649k
                        make_const_string(&value, a_readonly | avm_system, len, body);
948
649k
                        if ((code = try_stdout_redirect(minst, adef, eqp)) < 0) {
949
0
                            arg_free((char *)adef, minst->heap);
950
0
                            return code;
951
0
                        }
952
649k
                    }
953
1.29M
                    ialloc_set_space(idmemory, space);
954
1.29M
                }
955
                /* Enter the name in systemdict. */
956
2.43M
                i_initial_enter_name_copy(minst->i_ctx_p, adef, &value);
957
2.43M
                arg_free((char *)adef, minst->heap);
958
2.43M
                break;
959
2.43M
            }
960
0
        case 'p':
961
0
            {
962
0
                char *adef = arg_copy(arg, minst->heap);
963
0
                char *eqp;
964
965
0
                if (adef == NULL)
966
0
                    return gs_error_Fatal;
967
0
                eqp = strchr(adef, '=');
968
969
0
                if (eqp == NULL)
970
0
                    eqp = strchr(adef, '#');
971
0
                if (eqp == NULL) {
972
0
                    outprintf(minst->heap, "Usage: -pNAME=STRING\n");
973
0
                    arg_free((char *)adef, minst->heap);
974
0
                    return gs_error_Fatal;
975
0
                }
976
0
                *eqp++ = 0;
977
                /* Slightly uncomfortable calling back up to a higher
978
                 * level, but we'll live with it. */
979
0
                code = gsapi_set_param(gs_lib_ctx_get_interp_instance(minst->heap),
980
0
                                       adef, eqp, gs_spt_parsed);
981
0
                if (code < 0) {
982
0
                    arg_free((char *)adef, minst->heap);
983
0
                    return code;
984
0
                }
985
0
                break;
986
0
            }
987
0
        case 'u':               /* undefine name */
988
0
            if (!*arg) {
989
0
                puts(minst->heap, "-u requires a name to undefine.");
990
0
                return gs_error_Fatal;
991
0
            }
992
0
            if ((code = gs_main_init1(minst)) < 0)
993
0
                return code;
994
0
            i_initial_remove_name(minst->i_ctx_p, arg);
995
0
            break;
996
0
        case 'v':               /* print revision */
997
0
            print_revision(minst);
998
0
            return gs_error_Info;
999
/*#ifdef DEBUG */
1000
            /*
1001
             * Here we provide a place for inserting debugging code that can be
1002
             * run in place of the normal interpreter code.
1003
             */
1004
0
        case 'X':
1005
0
            code = gs_main_init2(minst);
1006
0
            if (code < 0)
1007
0
                return code;
1008
0
            {
1009
0
                int xec;        /* exit_code */
1010
0
                ref xeo;        /* error_object */
1011
1012
0
#define start_x()\
1013
0
  gs_main_run_string_begin(minst, 1, &xec, &xeo)
1014
0
#define run_x(str)\
1015
0
  gs_main_run_string_continue(minst, str, strlen(str), 1, &xec, &xeo)
1016
0
#define stop_x()\
1017
0
  gs_main_run_string_end(minst, 1, &xec, &xeo)
1018
0
                start_x();
1019
0
                run_x("\216\003abc");
1020
0
                run_x("== flush\n");
1021
0
                stop_x();
1022
0
            }
1023
0
            return gs_error_Quit;
1024
/*#endif */
1025
0
        case 'Z':
1026
0
            set_debug_flags(arg, gs_debug);
1027
0
            break;
1028
2.92M
    }
1029
2.88M
    return 0;
1030
2.92M
}
1031
1032
/* Define versions of strlen and strcat that encode strings in hex. */
1033
/* This is so we can enter escaped characters regardless of whether */
1034
/* the Level 1 convention of ignoring \s in strings-within-strings */
1035
/* is being observed (sigh). */
1036
static int
1037
esc_strlen(const char *str)
1038
0
{
1039
0
    return strlen(str) * 2 + 2;
1040
0
}
1041
static void
1042
esc_strcat(char *dest, const char *src)
1043
0
{
1044
0
    char *d = dest + strlen(dest);
1045
0
    const char *p;
1046
0
    static const char *const hex = "0123456789abcdef";
1047
1048
0
    *d++ = '<';
1049
0
    for (p = src; *p; p++) {
1050
0
        byte c = (byte) * p;
1051
1052
0
        *d++ = hex[c >> 4];
1053
0
        *d++ = hex[c & 0xf];
1054
0
    }
1055
0
    *d++ = '>';
1056
0
    *d = 0;
1057
0
}
1058
1059
/* Process file names */
1060
static int
1061
argproc(gs_main_instance * minst, const char *arg)
1062
0
{
1063
0
    int code1, code = gs_main_init1(minst);            /* need i_ctx_p to proceed */
1064
1065
0
    if (code < 0)
1066
0
        return code;
1067
1068
0
    code = gs_add_control_path(minst->heap, gs_permit_file_reading, arg);
1069
0
    if (code < 0) return code;
1070
1071
0
    if (minst->run_buffer_size) {
1072
        /* Run file with run_string. */
1073
0
        code = run_buffered(minst, arg);
1074
0
    } else {
1075
        /* Run file directly in the normal way. */
1076
0
        code = runarg(minst, "", arg, ".runfile", runInit | runFlush, minst->user_errors, NULL, NULL);
1077
0
    }
1078
1079
0
    code1 = gs_remove_control_path(minst->heap, gs_permit_file_reading, arg);
1080
0
    if (code >= 0 && code1 < 0) code = code1;
1081
1082
0
    return code;
1083
0
}
1084
static int
1085
run_buffered(gs_main_instance * minst, const char *arg)
1086
0
{
1087
0
    gp_file *in = gp_fopen(minst->heap, arg, gp_fmode_rb);
1088
0
    int exit_code;
1089
0
    ref error_object;
1090
0
    int code;
1091
1092
0
    if (in == 0) {
1093
0
        outprintf(minst->heap, "Unable to open %s for reading", arg);
1094
0
        return_error(gs_error_invalidfileaccess);
1095
0
    }
1096
0
    code = gs_main_init2(minst);
1097
0
    if (code < 0) {
1098
0
        gp_fclose(in);
1099
0
        return code;
1100
0
    }
1101
0
    code = gs_main_run_string_begin(minst, minst->user_errors,
1102
0
                                    &exit_code, &error_object);
1103
0
    if (!code) {
1104
0
        char buf[MAX_BUFFERED_SIZE];
1105
0
        int count;
1106
1107
0
        code = gs_error_NeedInput;
1108
0
        while ((count = gp_fread(buf, 1, minst->run_buffer_size, in)) > 0) {
1109
0
            code = gs_main_run_string_continue(minst, buf, count,
1110
0
                                               minst->user_errors,
1111
0
                                               &exit_code, &error_object);
1112
0
            if (code != gs_error_NeedInput)
1113
0
                break;
1114
0
        }
1115
0
        if (code == gs_error_NeedInput) {
1116
0
            code = gs_main_run_string_end(minst, minst->user_errors,
1117
0
                                          &exit_code, &error_object);
1118
0
        }
1119
0
    }
1120
0
    gp_fclose(in);
1121
0
    zflush(minst->i_ctx_p);
1122
0
    zflushpage(minst->i_ctx_p);
1123
0
    return run_finish(minst, code, exit_code, &error_object);
1124
0
}
1125
static int
1126
runarg(gs_main_instance *minst,
1127
       const char       *pre,
1128
       const char       *arg,
1129
       const char       *post,
1130
       int               options,
1131
       int               user_errors,
1132
       int              *pexit_code,
1133
       ref              *perror_object)
1134
0
{
1135
0
    int len = strlen(pre) + esc_strlen(arg) + strlen(post) + 1;
1136
0
    int code;
1137
0
    char *line;
1138
1139
0
    if (options & runInit) {
1140
0
        code = gs_main_init2(minst);    /* Finish initialization */
1141
1142
0
        if (code < 0)
1143
0
            return code;
1144
0
    }
1145
0
    line = (char *)gs_alloc_bytes(minst->heap, len, "runarg");
1146
0
    if (line == 0) {
1147
0
        lprintf("Out of memory!\n");
1148
0
        return_error(gs_error_VMerror);
1149
0
    }
1150
0
    strcpy(line, pre);
1151
0
    esc_strcat(line, arg);
1152
0
    strcat(line, post);
1153
0
    minst->i_ctx_p->starting_arg_file = true;
1154
0
    code = run_string(minst, line, options, user_errors, pexit_code, perror_object);
1155
0
    minst->i_ctx_p->starting_arg_file = false;
1156
0
    gs_free_object(minst->heap, line, "runarg");
1157
0
    return code;
1158
0
}
1159
int
1160
gs_main_run_file2(gs_main_instance *minst,
1161
                  const char       *filename,
1162
                  int               user_errors,
1163
                  int              *pexit_code,
1164
                  ref              *perror_object)
1165
0
{
1166
0
    int code, code1;
1167
1168
0
    code = gs_add_control_path(minst->heap, gs_permit_file_reading, filename);
1169
0
    if (code < 0) return code;
1170
1171
0
    code = runarg(minst, "", filename, ".runfile", runFlush, user_errors, pexit_code, perror_object);
1172
1173
0
    code1 = gs_remove_control_path(minst->heap, gs_permit_file_reading, filename);
1174
0
    if (code >= 0 && code1 < 0) code = code1;
1175
1176
0
    return code;
1177
0
}
1178
static int
1179
run_string(gs_main_instance *minst,
1180
           const char       *str,
1181
           int               options,
1182
           int               user_errors,
1183
           int              *pexit_code,
1184
           ref              *perror_object)
1185
162k
{
1186
162k
    int exit_code;
1187
162k
    ref error_object;
1188
162k
    int code;
1189
1190
162k
    if (pexit_code == NULL)
1191
162k
        pexit_code = &exit_code;
1192
162k
    if (perror_object == NULL)
1193
162k
        perror_object = &error_object;
1194
1195
162k
    code = gs_main_run_string(minst, str, user_errors,
1196
162k
                              pexit_code, perror_object);
1197
1198
162k
    if ((options & runFlush) || code != 0) {
1199
162k
        zflush(minst->i_ctx_p);         /* flush stdout */
1200
162k
        zflushpage(minst->i_ctx_p);     /* force display update */
1201
162k
    }
1202
162k
    return run_finish(minst, code, *pexit_code, perror_object);
1203
162k
}
1204
static int
1205
run_finish(gs_main_instance *minst, int code, int exit_code,
1206
           ref * perror_object)
1207
162k
{
1208
162k
    switch (code) {
1209
16
        case gs_error_Quit:
1210
118k
        case 0:
1211
118k
            break;
1212
44.0k
        case gs_error_Fatal:
1213
44.0k
            if (exit_code == gs_error_InterpreterExit)
1214
0
                code = exit_code;
1215
44.0k
            else
1216
44.0k
                emprintf1(minst->heap,
1217
44.0k
                          "Unrecoverable error, exit code %d\n",
1218
44.0k
                          exit_code);
1219
44.0k
            break;
1220
0
        default:
1221
0
            gs_main_dump_stack(minst, code, perror_object);
1222
162k
    }
1223
162k
    return code;
1224
162k
}
1225
1226
/* Redirect stdout to a file:
1227
 *  -sstdout=filename
1228
 *  -sstdout=-
1229
 *  -sstdout=%stdout
1230
 *  -sstdout=%stderr
1231
 * -sOutputFile=- is not affected.
1232
 * File is closed at program exit (if not stdout/err)
1233
 * or when -sstdout is used again.
1234
 */
1235
static int
1236
try_stdout_redirect(gs_main_instance * minst,
1237
    const char *command, const char *filename)
1238
649k
{
1239
649k
    gs_lib_ctx_core_t *core = minst->heap->gs_lib_ctx->core;
1240
649k
    if (strcmp(command, "stdout") == 0) {
1241
162k
        core->stdout_to_stderr = 0;
1242
162k
        core->stdout_is_redirected = 0;
1243
        /* If stdout already being redirected and it is not stdout
1244
         * or stderr, close it
1245
         */
1246
162k
        if (core->fstdout2
1247
162k
            && (gp_get_file(core->fstdout2) != core->fstdout)
1248
162k
            && (gp_get_file(core->fstdout2) != core->fstderr)) {
1249
0
            gp_fclose(core->fstdout2);
1250
0
            core->fstdout2 = NULL;
1251
0
        }
1252
        /* If stdout is being redirected, set minst->fstdout2 */
1253
162k
        if ( (filename != 0) && strlen(filename) &&
1254
162k
            strcmp(filename, "-") && strcmp(filename, "%stdout") ) {
1255
162k
            if (strcmp(filename, "%stderr") == 0) {
1256
0
                core->stdout_to_stderr = 1;
1257
162k
            } else {
1258
162k
                core->fstdout2 = gp_fopen(minst->heap, filename, "w");
1259
162k
                if (core->fstdout2 == NULL)
1260
0
                    return_error(gs_error_invalidfileaccess);
1261
162k
            }
1262
162k
            core->stdout_is_redirected = 1;
1263
162k
        }
1264
162k
        return 0;
1265
162k
    }
1266
487k
    return 1;
1267
649k
}
1268
1269
/* ---------------- Print information ---------------- */
1270
1271
/*
1272
 * Help strings.  We have to break them up into parts, because
1273
 * the Watcom compiler has a limit of 510 characters for a single token.
1274
 * For PC displays, we want to limit the strings to 24 lines.
1275
 */
1276
static const char help_usage1[] = "\
1277
Usage: gs [switches] [file1.ps file2.ps ...]\n\
1278
Most frequently used switches: (you can use # in place of =)\n\
1279
 -dNOPAUSE           no pause after page   | -q       `quiet', fewer messages\n\
1280
 -g<width>x<height>  page size in pixels   | -r<res>  pixels/inch resolution\n";
1281
static const char help_usage2[] = "\
1282
 -sDEVICE=<devname>  select device         | -dBATCH  exit after last file\n\
1283
 -sOutputFile=<file> select output file: - for stdout, |command for pipe,\n\
1284
                                         embed %d or %ld for page #\n";
1285
#ifdef DEBUG
1286
static const char help_debug[] = "\
1287
 --debug=<option>[,<option>]*  select debugging options\n\
1288
 --debug                       list debugging options\n";
1289
#endif
1290
static const char help_trailer[] = "\
1291
For more information, see %s\n\
1292
Please report bugs to bugs.ghostscript.com.\n";
1293
static const char help_devices[] = "Available devices:";
1294
static const char help_default_device[] = "Default output device:";
1295
static const char help_emulators[] = "Input formats:";
1296
static const char help_paths[] = "Search path:";
1297
#ifdef HAVE_FONTCONFIG
1298
static const char help_fontconfig[] = "Ghostscript is also using fontconfig to search for font files\n";
1299
#else
1300
static const char help_fontconfig[] = "";
1301
#endif
1302
1303
extern_gx_io_device_table();
1304
1305
/* Print the standard help message. */
1306
static void
1307
print_help(gs_main_instance * minst)
1308
0
{
1309
0
    int i, have_rom_device = 0;
1310
1311
0
    print_revision(minst);
1312
0
    print_usage(minst);
1313
0
    print_emulators(minst);
1314
0
    print_devices(minst);
1315
0
    print_paths(minst);
1316
    /* Check if we have the %rom device */
1317
0
    for (i = 0; i < gx_io_device_table_count; i++) {
1318
0
        const gx_io_device *iodev = gx_io_device_table[i];
1319
0
        const char *dname = iodev->dname;
1320
1321
0
        if (dname && strlen(dname) == 5 && !memcmp("%rom%", dname, 5)) {
1322
0
            struct stat pstat;
1323
            /* gs_error_unregistered means no usable romfs is available */
1324
0
            int code = iodev->procs.file_status((gx_io_device *)iodev, dname, &pstat);
1325
0
            if (code != gs_error_unregistered){
1326
0
                have_rom_device = 1;
1327
0
            }
1328
0
            break;
1329
0
        }
1330
0
    }
1331
0
    if (have_rom_device) {
1332
0
        outprintf(minst->heap, "Initialization files are compiled into the executable.\n");
1333
0
    }
1334
0
    print_help_trailer(minst);
1335
0
}
1336
1337
/* Print the revision, revision date, and copyright. */
1338
static void
1339
print_revision(const gs_main_instance *minst)
1340
0
{
1341
0
    printf_program_ident(minst->heap, gs_product, gs_revision);
1342
0
    outprintf(minst->heap, " (%d-%02d-%02d)\n%s\n",
1343
0
            (int)(gs_revisiondate / 10000),
1344
0
            (int)(gs_revisiondate / 100 % 100),
1345
0
            (int)(gs_revisiondate % 100),
1346
0
            gs_copyright);
1347
0
}
1348
1349
/* Print the version number. */
1350
static void
1351
print_version(const gs_main_instance *minst)
1352
0
{
1353
0
    printf_program_ident(minst->heap, NULL, gs_revision);
1354
0
}
1355
1356
/* Print usage information. */
1357
static void
1358
print_usage(const gs_main_instance *minst)
1359
0
{
1360
0
    outprintf(minst->heap, "%s", help_usage1);
1361
0
    outprintf(minst->heap, "%s", help_usage2);
1362
#ifdef DEBUG
1363
    outprintf(minst->heap, "%s", help_debug);
1364
#endif
1365
0
}
1366
1367
/* compare function for qsort */
1368
static int
1369
cmpstr(const void *v1, const void *v2)
1370
0
{
1371
0
    return strcmp( *(char * const *)v1, *(char * const *)v2 );
1372
0
}
1373
1374
/* Print the list of available devices. */
1375
static void
1376
print_devices(const gs_main_instance *minst)
1377
0
{
1378
0
    outprintf(minst->heap, "%s", help_default_device);
1379
0
    outprintf(minst->heap, " %s\n", gs_devicename(gs_getdefaultdevice()));
1380
0
    outprintf(minst->heap, "%s", help_devices);
1381
0
    {
1382
0
        int i;
1383
0
        int pos = 100;
1384
0
        const gx_device *pdev;
1385
0
        const char **names;
1386
0
        size_t ndev = 0;
1387
1388
0
        for (i = 0; gs_getdevice(i) != 0; i++)
1389
0
            ;
1390
0
        ndev = (size_t)i;
1391
0
        names = (const char **)gs_alloc_bytes(minst->heap, ndev * sizeof(const char*), "print_devices");
1392
0
        if (names == (const char **)NULL) { /* old-style unsorted device list */
1393
0
            for (i = 0; (pdev = gs_getdevice(i)) != 0; i++) {
1394
0
                const char *dname = gs_devicename(pdev);
1395
0
                int len = strlen(dname);
1396
1397
0
                if (pos + 1 + len > 76)
1398
0
                    outprintf(minst->heap, "\n  "), pos = 2;
1399
0
                outprintf(minst->heap, " %s", dname);
1400
0
                pos += 1 + len;
1401
0
            }
1402
0
        }
1403
0
        else {                          /* new-style sorted device list */
1404
0
            for (i = 0; (pdev = gs_getdevice(i)) != 0; i++)
1405
0
                names[i] = gs_devicename(pdev);
1406
0
            qsort((void*)names, ndev, sizeof(const char*), cmpstr);
1407
0
            for (i = 0; i < ndev; i++) {
1408
0
                int len = strlen(names[i]);
1409
1410
0
                if (pos + 1 + len > 76)
1411
0
                    outprintf(minst->heap, "\n  "), pos = 2;
1412
0
                outprintf(minst->heap, " %s", names[i]);
1413
0
                pos += 1 + len;
1414
0
            }
1415
0
            gs_free(minst->heap, (char *)names, ndev * sizeof(const char*), 1, "print_devices");
1416
0
        }
1417
0
    }
1418
0
    outprintf(minst->heap, "\n");
1419
0
}
1420
1421
/* Print the list of language emulators. */
1422
static void
1423
print_emulators(const gs_main_instance *minst)
1424
0
{
1425
0
    outprintf(minst->heap, "%s", help_emulators);
1426
0
    {
1427
0
        const byte *s;
1428
1429
0
        for (s = gs_emulators; s[0] != 0; s += strlen((const char *)s) + 1)
1430
0
            outprintf(minst->heap, " %s", s);
1431
0
    }
1432
0
    outprintf(minst->heap, "\n");
1433
0
}
1434
1435
/* Print the search paths. */
1436
static void
1437
print_paths(gs_main_instance * minst)
1438
0
{
1439
0
    outprintf(minst->heap, "%s", help_paths);
1440
0
    gs_main_set_lib_paths(minst);
1441
0
    {
1442
0
        uint count = r_size(&minst->lib_path.list);
1443
0
        uint i;
1444
0
        int pos = 100;
1445
0
        char fsepr[3];
1446
1447
0
        fsepr[0] = ' ', fsepr[1] = gp_file_name_list_separator,
1448
0
            fsepr[2] = 0;
1449
0
        for (i = 0; i < count; ++i) {
1450
0
            const ref *prdir =
1451
0
            minst->lib_path.list.value.refs + i;
1452
0
            uint len = r_size(prdir);
1453
0
            const char *sepr = (i == count - 1 ? "" : fsepr);
1454
1455
0
            if (1 + pos + strlen(sepr) + len > 76)
1456
0
                outprintf(minst->heap, "\n  "), pos = 2;
1457
0
            outprintf(minst->heap, " ");
1458
            /*
1459
             * This is really ugly, but it's necessary because some
1460
             * platforms rely on all console output being funneled through
1461
             * outprintf.  We wish we could just do:
1462
             fwrite(prdir->value.bytes, 1, len, minst->fstdout);
1463
             */
1464
0
            {
1465
0
                const char *p = (const char *)prdir->value.bytes;
1466
0
                uint j;
1467
1468
0
                for (j = len; j; j--)
1469
0
                    outprintf(minst->heap, "%c", *p++);
1470
0
            }
1471
0
            outprintf(minst->heap, "%s", sepr);
1472
0
            pos += 1 + len + strlen(sepr);
1473
0
        }
1474
0
    }
1475
0
    outprintf(minst->heap, "\n");
1476
0
    outprintf(minst->heap, "%s", help_fontconfig);
1477
0
}
1478
1479
/* Print the help trailer. */
1480
static void
1481
print_help_trailer(const gs_main_instance *minst)
1482
0
{
1483
0
    char buffer[gp_file_name_sizeof];
1484
0
    const char *use_htm = "Use.html", *p = buffer;
1485
0
    const char *rtd_url = "https://ghostscript.readthedocs.io/en";
1486
0
    const char *latest_ver="latest";
1487
0
    const char *vers = latest_ver;
1488
0
    const char *gs_str = "gs";
1489
0
    const char *gs = "";
1490
0
    uint blen = sizeof(buffer);
1491
1492
0
    if (strlen(GS_PRODUCT) == strlen(GS_PRODUCTFAMILY)) {
1493
0
        vers = GS_STRINGIZE(GS_DOT_VERSION);
1494
0
        gs = gs_str;
1495
0
    }
1496
1497
0
    snprintf(buffer, blen, "%s/%s%s/%s", rtd_url, gs, vers, use_htm);
1498
0
    outprintf(minst->heap, help_trailer, p);
1499
0
}