Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/imainarg.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
/* 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
1.00k
#define runInit 1
91
293k
#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.66M
        for (i = 1; i < argc; ++i) {
183
2.50M
            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.50M
            } else if (!arg_strcmp(&args, argv[i], "--help")) {
189
0
                print_help(minst);
190
0
                helping = true;
191
2.50M
            } else if (!arg_strcmp(&args, argv[i], "--debug")) {
192
0
                gs_debug_flags_list(minst->heap);
193
0
                helping = true;
194
2.50M
            } 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.50M
        }
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.62M
    while ((code = arg_next(&args, (const char **)&arg, minst->heap)) > 0) {
233
2.50M
        code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, arg);
234
2.50M
        if (code < 0)
235
0
            goto error;
236
2.50M
        switch (*arg) {
237
2.50M
            case '-':
238
2.50M
                code = swproc(minst, arg, &args);
239
2.50M
                if (code < 0)
240
38.0k
                    goto error;
241
2.46M
                if (code > 0)
242
0
                    outprintf(minst->heap, "Unknown switch %s - ignoring\n", arg);
243
2.46M
                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.46M
                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.50M
        }
282
2.50M
    }
283
284
124k
    return code;
285
286
38.0k
error:
287
38.0k
    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
38.0k
    return code;
292
162k
}
293
294
int
295
gs_main_init_with_args2(gs_main_instance * minst)
296
124k
{
297
124k
    int code;
298
299
124k
    code = gs_main_init2(minst);
300
124k
    if (code < 0)
301
0
        return code;
302
303
124k
    if (!minst->run_start)
304
108k
        return gs_error_Quit;
305
16.0k
    return code;
306
124k
}
307
308
int
309
gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[])
310
146k
{
311
146k
    int code = gs_main_init_with_args01(minst, argc, argv);
312
313
146k
    if (code < 0)
314
38.0k
        return code;
315
108k
    return gs_main_init_with_args2(minst);
316
146k
}
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 == '=' || *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
#ifdef GS_HAS_THREADS
358
static void
359
trigger_timeout(void *data)
360
0
{
361
0
    *(int *)data = 1;
362
0
}
363
#endif
364
365
0
#define arg_match(A, B) do_arg_match(A, B, sizeof(B)-1)
366
367
/* Process switches.  Return 0 if processed, 1 for unknown switch, */
368
/* <0 if error. */
369
static int
370
swproc(gs_main_instance * minst, const char *arg, arg_list * pal)
371
2.64M
{
372
2.64M
    char sw = arg[1];
373
2.64M
    ref vtrue;
374
2.64M
    int code = 0;
375
376
2.64M
    make_true(&vtrue);
377
2.64M
    arg += 2;                   /* skip - and letter */
378
2.64M
    switch (sw) {
379
0
        default:
380
0
            return 1;
381
0
        case 0:         /* read stdin as a file char-by-char */
382
            /* This is a ******HACK****** for Ghostview. */
383
0
            minst->heap->gs_lib_ctx->core->stdin_is_interactive = true;
384
0
            goto run_stdin;
385
146k
        case '_':       /* read stdin with normal buffering */
386
146k
            minst->heap->gs_lib_ctx->core->stdin_is_interactive = false;
387
146k
run_stdin:
388
146k
            minst->run_start = false;   /* don't run 'start' */
389
            /* Set NOPAUSE so showpage won't try to read from stdin. */
390
146k
            code = swproc(minst, "-dNOPAUSE", pal);
391
146k
            if (code)
392
0
                return code;
393
146k
            code = gs_main_init2(minst);        /* Finish initialization */
394
146k
            if (code < 0)
395
385
                return code;
396
397
145k
            code = run_string(minst, ".runstdin", runFlush, minst->user_errors, NULL, NULL);
398
145k
            if (code < 0)
399
37.6k
                return code;
400
            /* If in saved_pages_test_mode, print and flush previous job before the next file */
401
108k
            if (minst->saved_pages_test_mode) {
402
0
                gx_device *pdev;
403
0
                int ret;
404
0
                gxdso_device_child_request child_dev_data;
405
406
                /* get the real target (printer) device */
407
0
                pdev = gs_currentdevice(minst->i_ctx_p->pgs);
408
0
                do {
409
0
                    child_dev_data.target = pdev;
410
0
                    ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
411
0
                                                      sizeof(child_dev_data));
412
0
                    if (ret > 0)
413
0
                        pdev = child_dev_data.target;
414
0
                } while ((ret > 0) && (child_dev_data.n != 0));
415
0
                if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
416
0
                           (byte *)"print normal flush", 18)) < 0)
417
0
                    return code;
418
0
                if (code > 0)
419
0
                    if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
420
0
                        return code;
421
0
            }
422
108k
            break;
423
108k
        case '-':               /* run with command line args */
424
0
            if (strncmp(arg, "debug=", 6) == 0) {
425
0
                code = gs_debug_flags_parse(minst->heap, arg+6);
426
0
                if (code < 0)
427
0
                    return code;
428
0
                break;
429
0
            } else if (strncmp(arg, "saved-pages=", 12) == 0) {
430
0
                gx_device *pdev;
431
432
                /* If init2 not yet done, just save the argument for processing then */
433
0
                if (minst->init_done < 2) {
434
0
                    if (minst->saved_pages_initial_arg == NULL) {
435
                        /* Tuck the parameters away for later when init2 is done (usually "begin") */
436
0
                        minst->saved_pages_initial_arg = (char *)gs_alloc_bytes(minst->heap,
437
0
                                                                                1+strlen((char *)arg+(size_t)12),
438
0
                                                                               "GS_OPTIONS");
439
0
                        if (minst->saved_pages_initial_arg != NULL) {
440
0
                            strcpy(minst->saved_pages_initial_arg,(char *)arg+12);
441
0
                        } else {
442
0
                            outprintf(minst->heap,
443
0
                                      "   saved_pages_initial_arg larger than expected\n");
444
0
                            arg_finit(pal);
445
0
                            return gs_error_Fatal;
446
0
                        }
447
0
                    } else {
448
0
                        outprintf(minst->heap,
449
0
                                  "   Only one --saved-pages=... command allowed before processing input\n");
450
0
                        arg_finit(pal);
451
0
                        return gs_error_Fatal;
452
0
                    }
453
0
                } else {
454
0
                    int ret;
455
0
                    gxdso_device_child_request child_dev_data;
456
457
                    /* get the current device */
458
0
                    pdev = gs_currentdevice(minst->i_ctx_p->pgs);
459
0
                    if (dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_saved_pages, NULL, 0) <= 0) {
460
0
                        outprintf(minst->heap,
461
0
                                  "   --saved-pages not supported by the '%s' device.\n",
462
0
                                  pdev->dname);
463
0
                        arg_finit(pal);
464
0
                        return gs_error_Fatal;
465
0
                    }
466
                    /* get the real target (printer) device */
467
0
                    do {
468
0
                        child_dev_data.target = pdev;
469
0
                        ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
470
0
                                                          sizeof(child_dev_data));
471
0
                        if (ret > 0)
472
0
                            pdev = child_dev_data.target;
473
0
                    } while ((ret > 0) && (child_dev_data.n != 0));
474
0
                    if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
475
0
                                                              (byte *)arg+12, strlen(arg+12))) < 0)
476
0
                        return code;
477
0
                    if (code > 0)
478
0
                        if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
479
0
                            return code;
480
0
                }
481
0
                break;
482
            /* The following code is only to allow regression testing of saved-pages */
483
0
            } else if (strncmp(arg, "saved-pages-test", 16) == 0) {
484
0
                minst->saved_pages_test_mode = true;
485
0
                break;
486
            /* Now handle the explicitly added paths to the file control lists */
487
0
            } else if (arg_match(&arg, "permit-file-read")) {
488
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_reading);
489
0
                if (code < 0) return code;
490
0
                break;
491
0
            } else if (arg_match(&arg, "permit-file-write")) {
492
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_writing);
493
0
                if (code < 0) return code;
494
0
                break;
495
0
            } else if (arg_match(&arg, "permit-file-control")) {
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-file-all")) {
500
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_reading);
501
0
                if (code < 0) return code;
502
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_writing);
503
0
                if (code < 0) return code;
504
0
                code = gs_add_explicit_control_path(minst->heap, arg, gs_permit_file_control);
505
0
                if (code < 0) return code;
506
0
                break;
507
0
            } else if (arg_match(&arg, "permit-devices")) {
508
0
                code = gs_add_explicit_permitted_device(minst->heap, arg);
509
0
                if (code < 0) return code;
510
0
                break;
511
0
            } else if (strncmp(arg, "timeout=", 8) == 0) {
512
0
#ifdef GS_HAS_THREADS
513
0
                int secs = atoi(arg+8);
514
0
                if (secs == 0)
515
0
                {
516
0
                    outprintf(minst->heap,
517
0
                          "   Illegal timeout value '%s' - should be in seconds.\n",
518
0
                          arg+8);
519
0
                    arg_finit(pal);
520
0
                    return gs_error_Fatal;
521
0
                }
522
0
                code = gp_alarm_start(&minst->timeout, minst->heap, secs, trigger_timeout, &minst->heap->gs_lib_ctx->core->timedout);
523
0
                if (code < 0) return code;
524
0
                break;
525
#else
526
                outprintf(minst->heap, "Timeouts not supported on builds without threading\n");
527
                return gs_error_Fatal;
528
#endif
529
0
            }
530
0
            if (*arg != 0) {
531
                /* Unmatched switch. */
532
0
                outprintf(minst->heap,
533
0
                          "   Unknown switch '--%s'.\n",
534
0
                          arg);
535
0
                arg_finit(pal);
536
0
                return gs_error_Fatal;
537
0
            }
538
            /* FALLTHROUGH */
539
0
        case '+':
540
0
            pal->expand_ats = false;
541
            /* FALLTHROUGH */
542
0
        case '@':               /* ditto with @-expansion */
543
0
            {
544
0
                char *psarg;
545
546
0
                code = arg_next(pal, (const char **)&psarg, minst->heap);
547
                /* Don't stash the @ file name */
548
549
0
                if (code < 0)
550
0
                    return gs_error_Fatal;
551
0
                if (psarg == NULL) {
552
0
                    outprintf(minst->heap, "Usage: gs ... -%c file.ps arg1 ... argn\n", sw);
553
0
                    arg_finit(pal);
554
0
                    return gs_error_Fatal;
555
0
                }
556
0
                psarg = arg_copy(psarg, minst->heap);
557
0
                if (psarg == NULL)
558
0
                    code = gs_error_Fatal;
559
0
                else
560
0
                    code = gs_main_init2(minst);
561
0
                if (code >= 0)
562
0
                    code = run_string(minst, "userdict/ARGUMENTS[", 0, minst->user_errors, NULL, NULL);
563
0
                if (code >= 0)
564
0
                    while ((code = arg_next(pal, (const char **)&arg, minst->heap)) > 0) {
565
0
                        code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, arg);
566
0
                        if (code < 0)
567
0
                            break;
568
0
                        code = runarg(minst, "", arg, "", runInit, minst->user_errors, NULL, NULL);
569
0
                        if (code < 0)
570
0
                            break;
571
0
                    }
572
0
                if (code >= 0)
573
0
                    code = run_string(minst, "]put", 0, minst->user_errors, NULL, NULL);
574
0
                if (code >= 0)
575
0
                    code = argproc(minst, psarg);
576
0
                arg_free((char *)psarg, minst->heap);
577
0
                if (code >= 0)
578
0
                    code = gs_error_Quit;
579
580
0
                return code;
581
0
            }
582
0
        case 'B':               /* set run_string buffer size */
583
0
            if (*arg == '-')
584
0
                minst->run_buffer_size = 0;
585
0
            else {
586
0
                uint bsize;
587
588
0
                if (sscanf((const char *)arg, "%u", &bsize) != 1 ||
589
0
                    bsize <= 0 || bsize > MAX_BUFFERED_SIZE
590
0
                    ) {
591
0
                    outprintf(minst->heap,
592
0
                              "-B must be followed by - or size between 1 and %u\n",
593
0
                              MAX_BUFFERED_SIZE);
594
0
                    return gs_error_Fatal;
595
0
                }
596
0
                minst->run_buffer_size = bsize;
597
0
            }
598
0
            break;
599
0
        case 'c':               /* code follows */
600
0
            {
601
0
                bool ats = pal->expand_ats;
602
603
0
                code = gs_main_init2(minst);
604
0
                if (code < 0)
605
0
                    return code;
606
0
                pal->expand_ats = false;
607
0
                while ((code = arg_next(pal, (const char **)&arg, minst->heap)) > 0) {
608
0
                    if (arg[0] == '@' ||
609
0
                        (arg[0] == '-' && !isdigit((unsigned char)arg[1]))
610
0
                        )
611
0
                        break;
612
0
                    code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, "?");
613
0
                    if (code < 0)
614
0
                        return code;
615
0
                    code = runarg(minst, "", arg, ".runstring", 0, minst->user_errors, NULL, NULL);
616
0
                    if (code < 0)
617
0
                        return code;
618
0
                }
619
0
                if (code < 0)
620
0
                    return gs_error_Fatal;
621
0
                if (arg != NULL) {
622
0
                    char *p = arg_copy(arg, minst->heap);
623
0
                    if (p == NULL)
624
0
                        return gs_error_Fatal;
625
0
                    arg_push_string(pal, p, true);
626
0
                }
627
0
                pal->expand_ats = ats;
628
0
                break;
629
0
            }
630
0
        case 'f':               /* run file of arbitrary name */
631
0
            if (*arg != 0) {
632
0
                code = argproc(minst, arg);
633
0
                if (code < 0)
634
0
                    return code;
635
                /* If in saved_pages_test_mode, print and flush previous job before the next file */
636
0
                if (minst->saved_pages_test_mode) {
637
0
                    gx_device *pdev;
638
0
                    int ret;
639
0
                    gxdso_device_child_request child_dev_data;
640
641
                    /* get the real target (printer) device */
642
0
                    pdev = gs_currentdevice(minst->i_ctx_p->pgs);
643
0
                    do {
644
0
                        child_dev_data.target = pdev;
645
0
                        ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
646
0
                                                          sizeof(child_dev_data));
647
0
                        if (ret > 0)
648
0
                            pdev = child_dev_data.target;
649
0
                    } while ((ret > 0) && (child_dev_data.n != 0));
650
0
                    if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
651
0
                               (byte *)"print normal flush", 18)) < 0)
652
0
                        return code;
653
0
                    if (code > 0)
654
0
                        if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
655
0
                            return code;
656
0
                }
657
0
            }
658
0
            break;
659
0
        case 'F':               /* run file with buffer_size = 1 */
660
0
            if (!*arg) {
661
0
                puts(minst->heap, "-F requires a file name");
662
0
                return gs_error_Fatal;
663
0
            } {
664
0
                uint bsize = minst->run_buffer_size;
665
666
0
                minst->run_buffer_size = 1;
667
0
                code = argproc(minst, arg);
668
0
                minst->run_buffer_size = bsize;
669
0
                if (code < 0)
670
0
                    return code;
671
                /* If in saved_pages_test_mode, print and flush previous job before the next file */
672
0
                if (minst->saved_pages_test_mode) {
673
0
                    gx_device *pdev;
674
0
                    int ret;
675
0
                    gxdso_device_child_request child_dev_data;
676
677
                    /* get the real target (printer) device */
678
0
                    pdev = gs_currentdevice(minst->i_ctx_p->pgs);
679
0
                    do {
680
0
                        child_dev_data.target = pdev;
681
0
                        ret = dev_proc(pdev, dev_spec_op)(pdev, gxdso_device_child, &child_dev_data,
682
0
                                                          sizeof(child_dev_data));
683
0
                        if (ret > 0)
684
0
                            pdev = child_dev_data.target;
685
0
                    } while ((ret > 0) && (child_dev_data.n != 0));
686
0
                    if ((code = gx_saved_pages_param_process((gx_device_printer *)pdev,
687
0
                               (byte *)"print normal flush", 18)) < 0)
688
0
                        return code;
689
0
                    if (code > 0)
690
0
                        if ((code = gs_erasepage(minst->i_ctx_p->pgs)) < 0)
691
0
                            return code;
692
0
                }
693
0
            }
694
0
            break;
695
0
        case 'g':               /* define device geometry */
696
0
            {
697
0
                long dimensions[2];
698
699
0
                if ((code = gs_main_init1(minst)) < 0)
700
0
                    return code;
701
0
                if (sscanf((const char *)arg, "%ldx%ld", &dimensions[0], &dimensions[1]) != 2) {
702
0
                    puts(minst->heap, "-g must be followed by <width>x<height>");
703
0
                    return gs_error_Fatal;
704
0
                }
705
0
                gs_main_force_dimensions(minst, dimensions);
706
0
                break;
707
0
            }
708
0
        case 'h':               /* print help */
709
0
        case '?':               /* ditto */
710
0
            print_help(minst);
711
0
            return gs_error_Info;      /* show usage info on exit */
712
0
        case 'I':               /* specify search path */
713
0
            {
714
0
                const char *path;
715
716
0
                if (arg[0] == 0) {
717
0
                    code = arg_next(pal, (const char **)&path, minst->heap);
718
0
                    if (code < 0)
719
0
                        return code;
720
0
                    code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, "?");
721
0
                    if (code < 0)
722
0
                        return code;
723
0
                } else
724
0
                    path = arg;
725
0
                if (path == NULL)
726
0
                    return gs_error_Fatal;
727
0
                gs_main_add_lib_path(minst, path);
728
0
            }
729
0
            break;
730
146k
        case 'K':               /* set malloc limit */
731
146k
            {
732
146k
                long msize = 0;
733
146k
                gs_malloc_memory_t *rawheap = gs_malloc_wrapped_contents(minst->heap);
734
735
146k
                (void)sscanf((const char *)arg, "%ld", &msize);
736
146k
                if (msize <= 0 || msize > max_long >> 10) {
737
0
                    outprintf(minst->heap, "-K<numK> must have 1 <= numK <= %ld\n",
738
0
                              max_long >> 10);
739
0
                    return gs_error_Fatal;
740
0
                }
741
146k
                rawheap->limit = msize << 10;
742
146k
            }
743
0
            break;
744
0
        case 'M':               /* set memory allocation increment */
745
0
            {
746
0
                unsigned msize = 0;
747
748
0
                (void)sscanf((const char *)arg, "%u", &msize);
749
0
                if (msize <= 0 || msize >= (max_uint >> 10)) {
750
0
                    outprintf(minst->heap, "-M must be between 1 and %d\n", (int)((max_uint >> 10) - 1));
751
0
                    return gs_error_Fatal;
752
0
                }
753
0
                minst->memory_clump_size = msize << 10;
754
0
            }
755
0
            break;
756
0
        case 'N':               /* set size of name table */
757
0
            {
758
0
                unsigned int nsize = 0;
759
760
0
                (void)sscanf((const char *)arg, "%ud", &nsize);
761
0
                if (nsize < 2 || nsize > (max_uint >> 10)) {
762
0
                    outprintf(minst->heap, "-N must be between 2 and %d\n", (int)(max_uint >> 10));
763
0
                    return gs_error_Fatal;
764
0
                }
765
0
                minst->name_table_size = (ulong) nsize << 10;
766
0
            }
767
0
            break;
768
0
        case 'o':               /* set output file name and batch mode */
769
0
            {
770
0
                i_ctx_t *i_ctx_p;
771
0
                uint space;
772
0
                const char *adef;
773
0
                byte *str;
774
0
                ref value;
775
0
                int len;
776
777
0
                if ((code = gs_main_init1(minst)) < 0)
778
0
                    return code;
779
780
0
                i_ctx_p = minst->i_ctx_p;
781
0
                space = icurrent_space;
782
0
                if (arg[0] == 0) {
783
0
                    code = arg_next(pal, (const char **)&adef, minst->heap);
784
0
                    if (code < 0)
785
0
                        return code;
786
0
                    if (code == 0)
787
0
                        return gs_error_undefinedfilename;
788
0
                    code = gs_lib_ctx_stash_sanitized_arg(minst->heap->gs_lib_ctx, "?");
789
0
                    if (code < 0)
790
0
                        return code;
791
0
                } else
792
0
                    adef = arg;
793
0
                if ((code = gs_main_init1(minst)) < 0)
794
0
                    return code;
795
796
0
                if (strlen(adef) > 0) {
797
0
                    code = gs_add_outputfile_control_path(minst->heap, adef);
798
0
                    if (code < 0) return code;
799
0
                }
800
801
0
                ialloc_set_space(idmemory, avm_system);
802
0
                len = strlen(adef);
803
0
                str = ialloc_string(len, "-o");
804
0
                if (str == NULL)
805
0
                    return gs_error_VMerror;
806
0
                memcpy(str, adef, len);
807
0
                make_const_string(&value, a_readonly | avm_system, len, str);
808
0
                ialloc_set_space(idmemory, space);
809
0
                i_initial_enter_name(minst->i_ctx_p, "OutputFile", &value);
810
0
                i_initial_enter_name(minst->i_ctx_p, "NOPAUSE", &vtrue);
811
0
                i_initial_enter_name(minst->i_ctx_p, "BATCH", &vtrue);
812
0
            }
813
0
            break;
814
0
        case 'P':               /* choose whether search '.' first */
815
0
            if (!strcmp(arg, ""))
816
0
                minst->search_here_first = true;
817
0
            else if (!strcmp(arg, "-"))
818
0
                minst->search_here_first = false;
819
0
            else {
820
0
                puts(minst->heap, "Only -P or -P- is allowed.");
821
0
                return gs_error_Fatal;
822
0
            }
823
0
            break;
824
0
        case 'q':               /* quiet startup */
825
0
            if ((code = gs_main_init1(minst)) < 0)
826
0
                return code;
827
0
            i_initial_enter_name(minst->i_ctx_p, "QUIET", &vtrue);
828
0
            break;
829
146k
        case 'r':               /* define device resolution */
830
146k
            {
831
146k
                float res[2];
832
833
146k
                if ((code = gs_main_init1(minst)) < 0)
834
0
                    return code;
835
146k
                switch (sscanf((const char *)arg, "%fx%f", &res[0], &res[1])) {
836
0
                    default:
837
0
                        puts(minst->heap, "-r must be followed by <res> or <xres>x<yres>");
838
0
                        return gs_error_Fatal;
839
0
                    case 1:     /* -r<res> */
840
0
                        res[1] = res[0];
841
                        /* fall through */
842
146k
                    case 2:     /* -r<xres>x<yres> */
843
146k
                        gs_main_force_resolutions(minst, res);
844
146k
                }
845
146k
                break;
846
146k
            }
847
146k
        case 'D':               /* define name */
848
1.61M
        case 'd':
849
1.61M
        case 'S':               /* define name as string */
850
2.20M
        case 's':
851
2.20M
            {
852
2.20M
                char *adef = arg_copy(arg, minst->heap);
853
2.20M
                char *eqp;
854
2.20M
                bool isd = (sw == 'D' || sw == 'd');
855
2.20M
                ref value;
856
857
2.20M
                if (adef == NULL)
858
0
                    return gs_error_Fatal;
859
2.20M
                eqp = strchr(adef, '=');
860
861
2.20M
                if (eqp == NULL)
862
1.03M
                    eqp = strchr(adef, '#');
863
                /* Initialize the object memory, scanner, and */
864
                /* name table now if needed. */
865
2.20M
                if ((code = gs_main_init1(minst)) < 0) {
866
0
                    arg_free((char *)adef, minst->heap);
867
0
                    return code;
868
0
                }
869
2.20M
                if (eqp == adef) {
870
0
                    puts(minst->heap, "Usage: -dNAME, -dNAME=TOKEN, -sNAME=STRING");
871
0
                    arg_free((char *)adef, minst->heap);
872
0
                    return gs_error_Fatal;
873
0
                }
874
2.20M
                if (eqp == NULL) {
875
1.03M
                    if (isd)
876
1.03M
                        make_true(&value);
877
0
                    else
878
1.03M
                        make_empty_string(&value, a_readonly);
879
1.17M
                } else {
880
1.17M
                    int code;
881
1.17M
                    i_ctx_t *i_ctx_p = minst->i_ctx_p;
882
1.17M
                    uint space = icurrent_space;
883
884
1.17M
                    *eqp++ = 0;
885
886
1.17M
                    if (strlen(adef) == 10 && strncmp(adef, "OutputFile", 10) == 0 && strlen(eqp) > 0) {
887
146k
                        code = gs_add_outputfile_control_path(minst->heap, eqp);
888
146k
                        if (code < 0) {
889
0
                            arg_free((char *)adef, minst->heap);
890
0
                            return code;
891
0
                        }
892
146k
                    }
893
894
1.17M
                    ialloc_set_space(idmemory, avm_system);
895
1.17M
                    if (isd) {
896
573k
                        int i;
897
573k
                        int64_t num;
898
899
                        /* Check for numbers so we can provide for suffix scalers */
900
                        /* Note the check for '#' is for PS "radix" numbers such as 16#ff */
901
                        /* and check for '.' and 'e' or 'E' which are 'real' numbers */
902
573k
                        if ((strchr(eqp, '#') == NULL) && (strchr(eqp, '.') == NULL) &&
903
573k
                            (strchr(eqp, 'e') == NULL) && (strchr(eqp, 'E') == NULL) &&
904
573k
                            ((i = sscanf((const char *)eqp, "%"PRIi64, &num)) == 1)) {
905
573k
                            char suffix = eqp[strlen(eqp) - 1];
906
907
573k
                            switch (suffix) {
908
143k
                                case 'k':
909
143k
                                case 'K':
910
143k
                                    num *= 1024;
911
143k
                                    break;
912
0
                                case 'm':
913
0
                                case 'M':
914
0
                                    num *= 1024 * 1024;
915
0
                                    break;
916
0
                                case 'g':
917
0
                                case 'G':
918
                                    /* caveat emptor: more than 2g will overflow */
919
                                    /* and really should produce a 'real', so don't do this */
920
0
                                    num *= 1024 * 1024 * 1024;
921
0
                                    break;
922
430k
                                default:
923
430k
                                    break;   /* not a valid suffix or last char was digit */
924
573k
                            }
925
573k
                            make_int(&value, (ps_int)num);
926
573k
                        } else {
927
                            /* use the PS scanner to capture other valid token types */
928
0
                            stream astream;
929
0
                            scanner_state state;
930
931
0
                            s_init(&astream, NULL);
932
0
                            sread_string(&astream,
933
0
                                         (const byte *)eqp, strlen(eqp));
934
0
                            gs_scanner_init_stream(&state, &astream);
935
0
                            code = gs_scan_token(minst->i_ctx_p, &value, &state);
936
0
                            if (code) {
937
0
                                outprintf(minst->heap, "Invalid value for option -d%s, -dNAME= must be followed by a valid token\n", arg);
938
0
                                arg_free((char *)adef, minst->heap);
939
0
                                return gs_error_Fatal;
940
0
                            }
941
0
                            if (r_has_type_attrs(&value, t_name,
942
0
                                                 a_executable)) {
943
0
                                ref nsref;
944
945
0
                                name_string_ref(minst->heap, &value, &nsref);
946
0
#undef string_is
947
0
#define string_is(nsref, str, len)\
948
0
       (r_size(&(nsref)) == (len) &&\
949
0
       !strncmp((const char *)(nsref).value.const_bytes, str, (len)))
950
0
                                if (string_is(nsref, "null", 4))
951
0
                                    make_null(&value);
952
0
                                else if (string_is(nsref, "true", 4))
953
0
                                    make_true(&value);
954
0
                                else if (string_is(nsref, "false", 5))
955
0
                                    make_false(&value);
956
0
                                else {
957
0
                                    outprintf(minst->heap, "Invalid value for option -d%s, use -sNAME= to define string constants\n", arg);
958
0
                                    arg_free((char *)adef, minst->heap);
959
0
                                    return gs_error_Fatal;
960
0
                                }
961
0
                            }
962
0
                        }
963
598k
                    } else {
964
598k
                        int len = strlen(eqp);
965
598k
                        byte *body = ialloc_string(len, "-s");
966
967
598k
                        if (body == NULL) {
968
0
                            lprintf("Out of memory!\n");
969
0
                            arg_free((char *)adef, minst->heap);
970
0
                            return gs_error_Fatal;
971
0
                        }
972
598k
                        memcpy(body, eqp, len);
973
598k
                        make_const_string(&value, a_readonly | avm_system, len, body);
974
598k
                        if ((code = try_stdout_redirect(minst, adef, eqp)) < 0) {
975
0
                            arg_free((char *)adef, minst->heap);
976
0
                            return code;
977
0
                        }
978
598k
                    }
979
1.17M
                    ialloc_set_space(idmemory, space);
980
1.17M
                }
981
                /* Enter the name in systemdict. */
982
2.20M
                i_initial_enter_name_copy(minst->i_ctx_p, adef, &value);
983
2.20M
                arg_free((char *)adef, minst->heap);
984
2.20M
                break;
985
2.20M
            }
986
0
        case 'p':
987
0
            {
988
0
                char *adef = arg_copy(arg, minst->heap);
989
0
                char *eqp;
990
991
0
                if (adef == NULL)
992
0
                    return gs_error_Fatal;
993
0
                eqp = strchr(adef, '=');
994
995
0
                if (eqp == NULL)
996
0
                    eqp = strchr(adef, '#');
997
0
                if (eqp == NULL) {
998
0
                    outprintf(minst->heap, "Usage: -pNAME=STRING\n");
999
0
                    arg_free((char *)adef, minst->heap);
1000
0
                    return gs_error_Fatal;
1001
0
                }
1002
0
                *eqp++ = 0;
1003
                /* Slightly uncomfortable calling back up to a higher
1004
                 * level, but we'll live with it. */
1005
0
                code = gsapi_set_param(gs_lib_ctx_get_interp_instance(minst->heap),
1006
0
                                       adef, eqp, gs_spt_parsed | gs_spt_more_to_come);
1007
0
                if (code < 0) {
1008
0
                    arg_free((char *)adef, minst->heap);
1009
0
                    return code;
1010
0
                }
1011
0
                break;
1012
0
            }
1013
0
        case 'u':               /* undefine name */
1014
0
            if (!*arg) {
1015
0
                puts(minst->heap, "-u requires a name to undefine.");
1016
0
                return gs_error_Fatal;
1017
0
            }
1018
0
            if ((code = gs_main_init1(minst)) < 0)
1019
0
                return code;
1020
0
            i_initial_remove_name(minst->i_ctx_p, arg);
1021
0
            break;
1022
0
        case 'v':               /* print revision */
1023
0
            print_revision(minst);
1024
0
            return gs_error_Info;
1025
/*#ifdef DEBUG */
1026
            /*
1027
             * Here we provide a place for inserting debugging code that can be
1028
             * run in place of the normal interpreter code.
1029
             */
1030
0
        case 'X':
1031
0
            code = gs_main_init2(minst);
1032
0
            if (code < 0)
1033
0
                return code;
1034
0
            {
1035
0
                int xec;        /* exit_code */
1036
0
                ref xeo;        /* error_object */
1037
1038
0
#define start_x()\
1039
0
  gs_main_run_string_begin(minst, 1, &xec, &xeo)
1040
0
#define run_x(str)\
1041
0
  gs_main_run_string_continue(minst, str, strlen(str), 1, &xec, &xeo)
1042
0
#define stop_x()\
1043
0
  gs_main_run_string_end(minst, 1, &xec, &xeo)
1044
0
                start_x();
1045
0
                run_x("\216\003abc");
1046
0
                run_x("== flush\n");
1047
0
                stop_x();
1048
0
            }
1049
0
            return gs_error_Quit;
1050
/*#endif */
1051
0
        case 'Z':
1052
0
            set_debug_flags(arg, gs_debug);
1053
0
            break;
1054
2.64M
    }
1055
2.60M
    return 0;
1056
2.64M
}
1057
1058
/* Define versions of strlen and strcat that encode strings in hex. */
1059
/* This is so we can enter escaped characters regardless of whether */
1060
/* the Level 1 convention of ignoring \s in strings-within-strings */
1061
/* is being observed (sigh). */
1062
static int
1063
esc_strlen(const char *str)
1064
1.00k
{
1065
1.00k
    return strlen(str) * 2 + 2;
1066
1.00k
}
1067
static void
1068
esc_strcat(char *dest, const char *src)
1069
1.00k
{
1070
1.00k
    char *d = dest + strlen(dest);
1071
1.00k
    const char *p;
1072
1.00k
    static const char *const hex = "0123456789abcdef";
1073
1074
1.00k
    *d++ = '<';
1075
19.0k
    for (p = src; *p; p++) {
1076
18.0k
        byte c = (byte) * p;
1077
1078
18.0k
        *d++ = hex[c >> 4];
1079
18.0k
        *d++ = hex[c & 0xf];
1080
18.0k
    }
1081
1.00k
    *d++ = '>';
1082
1.00k
    *d = 0;
1083
1.00k
}
1084
1085
/* Process file names */
1086
static int
1087
argproc(gs_main_instance * minst, const char *arg)
1088
0
{
1089
0
    int code1, code = gs_main_init1(minst);            /* need i_ctx_p to proceed */
1090
1091
0
    if (code < 0)
1092
0
        return code;
1093
1094
0
    code = gs_add_control_path(minst->heap, gs_permit_file_reading, arg);
1095
0
    if (code < 0) return code;
1096
1097
0
    if (minst->run_buffer_size) {
1098
        /* Run file with run_string. */
1099
0
        code = run_buffered(minst, arg);
1100
0
    } else {
1101
        /* Run file directly in the normal way. */
1102
0
        code = runarg(minst, "", arg, ".runfile", runInit | runFlush, minst->user_errors, NULL, NULL);
1103
0
    }
1104
1105
0
    code1 = gs_remove_control_path(minst->heap, gs_permit_file_reading, arg);
1106
0
    if (code >= 0 && code1 < 0) code = code1;
1107
1108
0
    return code;
1109
0
}
1110
static int
1111
run_buffered(gs_main_instance * minst, const char *arg)
1112
0
{
1113
0
    gp_file *in = gp_fopen(minst->heap, arg, gp_fmode_rb);
1114
0
    int exit_code;
1115
0
    ref error_object;
1116
0
    int code;
1117
1118
0
    if (in == 0) {
1119
0
        outprintf(minst->heap, "Unable to open %s for reading", arg);
1120
0
        return_error(gs_error_invalidfileaccess);
1121
0
    }
1122
0
    code = gs_main_init2(minst);
1123
0
    if (code < 0) {
1124
0
        gp_fclose(in);
1125
0
        return code;
1126
0
    }
1127
0
    code = gs_main_run_string_begin(minst, minst->user_errors,
1128
0
                                    &exit_code, &error_object);
1129
0
    if (!code) {
1130
0
        char buf[MAX_BUFFERED_SIZE];
1131
0
        int count;
1132
1133
0
        code = gs_error_NeedInput;
1134
0
        while ((count = gp_fread(buf, 1, minst->run_buffer_size, in)) > 0) {
1135
0
            code = gs_main_run_string_continue(minst, buf, count,
1136
0
                                               minst->user_errors,
1137
0
                                               &exit_code, &error_object);
1138
0
            if (code != gs_error_NeedInput)
1139
0
                break;
1140
0
        }
1141
0
        if (code == gs_error_NeedInput) {
1142
0
            code = gs_main_run_string_end(minst, minst->user_errors,
1143
0
                                          &exit_code, &error_object);
1144
0
        }
1145
0
    }
1146
0
    gp_fclose(in);
1147
0
    zflush(minst->i_ctx_p);
1148
0
    zflushpage(minst->i_ctx_p);
1149
0
    return run_finish(minst, code, exit_code, &error_object);
1150
0
}
1151
static int
1152
runarg(gs_main_instance *minst,
1153
       const char       *pre,
1154
       const char       *arg,
1155
       const char       *post,
1156
       int               options,
1157
       int               user_errors,
1158
       int              *pexit_code,
1159
       ref              *perror_object)
1160
1.00k
{
1161
1.00k
    int len = strlen(pre) + esc_strlen(arg) + strlen(post) + 1;
1162
1.00k
    int code;
1163
1.00k
    char *line;
1164
1165
1.00k
    if (len < 0)
1166
0
        return gs_note_error(gs_error_rangecheck);
1167
1168
1.00k
    if (options & runInit) {
1169
0
        code = gs_main_init2(minst);    /* Finish initialization */
1170
1171
0
        if (code < 0)
1172
0
            return code;
1173
0
    }
1174
1.00k
    line = (char *)gs_alloc_bytes(minst->heap, len, "runarg");
1175
1.00k
    if (line == 0) {
1176
0
        lprintf("Out of memory!\n");
1177
0
        return_error(gs_error_VMerror);
1178
0
    }
1179
1.00k
    strcpy(line, pre);
1180
1.00k
    esc_strcat(line, arg);
1181
1.00k
    strcat(line, post);
1182
1.00k
    minst->i_ctx_p->starting_arg_file = true;
1183
1.00k
    code = run_string(minst, line, options, user_errors, pexit_code, perror_object);
1184
1.00k
    minst->i_ctx_p->starting_arg_file = false;
1185
1.00k
    gs_free_object(minst->heap, line, "runarg");
1186
1.00k
    return code;
1187
1.00k
}
1188
int
1189
gs_main_run_file2(gs_main_instance *minst,
1190
                  const char       *filename,
1191
                  int               user_errors,
1192
                  int              *pexit_code,
1193
                  ref              *perror_object)
1194
1.00k
{
1195
1.00k
    int code, code1;
1196
1197
1.00k
    code = gs_add_control_path(minst->heap, gs_permit_file_reading, filename);
1198
1.00k
    if (code < 0) return code;
1199
1200
1.00k
    code = runarg(minst, "", filename, ".runfile", runFlush, user_errors, pexit_code, perror_object);
1201
1202
1.00k
    code1 = gs_remove_control_path(minst->heap, gs_permit_file_reading, filename);
1203
1.00k
    if (code >= 0 && code1 < 0) code = code1;
1204
1205
1.00k
    return code;
1206
1.00k
}
1207
static int
1208
run_string(gs_main_instance *minst,
1209
           const char       *str,
1210
           int               options,
1211
           int               user_errors,
1212
           int              *pexit_code,
1213
           ref              *perror_object)
1214
146k
{
1215
146k
    int exit_code;
1216
146k
    ref error_object;
1217
146k
    int code;
1218
1219
146k
    if (pexit_code == NULL)
1220
145k
        pexit_code = &exit_code;
1221
146k
    if (perror_object == NULL)
1222
145k
        perror_object = &error_object;
1223
1224
146k
    code = gs_main_run_string(minst, str, user_errors,
1225
146k
                              pexit_code, perror_object);
1226
1227
146k
    if ((options & runFlush) || code != 0) {
1228
146k
        zflush(minst->i_ctx_p);         /* flush stdout */
1229
146k
        zflushpage(minst->i_ctx_p);     /* force display update */
1230
146k
    }
1231
146k
    return run_finish(minst, code, *pexit_code, perror_object);
1232
146k
}
1233
static int
1234
run_finish(gs_main_instance *minst, int code, int exit_code,
1235
           ref * perror_object)
1236
146k
{
1237
146k
    switch (code) {
1238
14
        case gs_error_Quit:
1239
108k
        case 0:
1240
108k
            break;
1241
37.8k
        case gs_error_Fatal:
1242
37.8k
            if (exit_code == gs_error_InterpreterExit)
1243
0
                code = exit_code;
1244
37.8k
            else
1245
37.8k
                emprintf1(minst->heap,
1246
37.8k
                          "Unrecoverable error, exit code %d\n",
1247
37.8k
                          exit_code);
1248
37.8k
            break;
1249
0
        default:
1250
0
            gs_main_dump_stack(minst, code, perror_object);
1251
146k
    }
1252
146k
    return code;
1253
146k
}
1254
1255
/* Redirect stdout to a file:
1256
 *  -sstdout=filename
1257
 *  -sstdout=-
1258
 *  -sstdout=%stdout
1259
 *  -sstdout=%stderr
1260
 * -sOutputFile=- is not affected.
1261
 * File is closed at program exit (if not stdout/err)
1262
 * or when -sstdout is used again.
1263
 */
1264
static int
1265
try_stdout_redirect(gs_main_instance * minst,
1266
    const char *command, const char *filename)
1267
598k
{
1268
598k
    gs_lib_ctx_core_t *core = minst->heap->gs_lib_ctx->core;
1269
598k
    if (strcmp(command, "stdout") == 0) {
1270
143k
        core->stdout_to_stderr = 0;
1271
143k
        core->stdout_is_redirected = 0;
1272
        /* If stdout already being redirected and it is not stdout
1273
         * or stderr, close it
1274
         */
1275
143k
        if (core->fstdout2
1276
0
            && (gp_get_file(core->fstdout2) != core->fstdout)
1277
0
            && (gp_get_file(core->fstdout2) != core->fstderr)) {
1278
0
            gp_fclose(core->fstdout2);
1279
0
            core->fstdout2 = NULL;
1280
0
        }
1281
        /* If stdout is being redirected, set minst->fstdout2 */
1282
143k
        if ( (filename != 0) && strlen(filename) &&
1283
143k
            strcmp(filename, "-") && strcmp(filename, "%stdout") ) {
1284
143k
            if (strcmp(filename, "%stderr") == 0) {
1285
0
                core->stdout_to_stderr = 1;
1286
143k
            } else {
1287
143k
                core->fstdout2 = gp_fopen(minst->heap, filename, "w");
1288
143k
                if (core->fstdout2 == NULL)
1289
0
                    return_error(gs_error_invalidfileaccess);
1290
143k
            }
1291
143k
            core->stdout_is_redirected = 1;
1292
143k
        }
1293
143k
        return 0;
1294
143k
    }
1295
454k
    return 1;
1296
598k
}
1297
1298
/* ---------------- Print information ---------------- */
1299
1300
/*
1301
 * Help strings.  We have to break them up into parts, because
1302
 * the Watcom compiler has a limit of 510 characters for a single token.
1303
 * For PC displays, we want to limit the strings to 24 lines.
1304
 */
1305
static const char help_usage1[] = "\
1306
Usage: gs [switches] [file1.ps file2.ps ...]\n\
1307
Most frequently used switches: (you can use # in place of =)\n\
1308
 -dNOPAUSE           no pause after page   | -q       `quiet', fewer messages\n\
1309
 -g<width>x<height>  page size in pixels   | -r<res>  pixels/inch resolution\n";
1310
static const char help_usage2[] = "\
1311
 -sDEVICE=<devname>  select device         | -dBATCH  exit after last file\n\
1312
 -sOutputFile=<file> select output file: - for stdout, |command for pipe,\n\
1313
                                         embed %d or %ld for page #\n";
1314
#ifdef DEBUG
1315
static const char help_debug[] = "\
1316
 --debug=<option>[,<option>]*  select debugging options\n\
1317
 --debug                       list debugging options\n";
1318
#endif
1319
static const char help_trailer[] = "\
1320
For more information, see %s\n\
1321
Please report bugs to bugs.ghostscript.com.\n";
1322
static const char help_devices[] = "Available devices:";
1323
static const char help_default_device[] = "Default output device:";
1324
static const char help_emulators[] = "Input formats:";
1325
static const char help_paths[] = "Search path:";
1326
#ifdef HAVE_FONTCONFIG
1327
static const char help_fontconfig[] = "Ghostscript is also using fontconfig to search for font files\n";
1328
#else
1329
static const char help_fontconfig[] = "";
1330
#endif
1331
1332
extern_gx_io_device_table();
1333
1334
/* Print the standard help message. */
1335
static void
1336
print_help(gs_main_instance * minst)
1337
0
{
1338
0
    int i, have_rom_device = 0;
1339
1340
0
    print_revision(minst);
1341
0
    print_usage(minst);
1342
0
    print_emulators(minst);
1343
0
    print_devices(minst);
1344
0
    print_paths(minst);
1345
    /* Check if we have the %rom device */
1346
0
    for (i = 0; i < gx_io_device_table_count; i++) {
1347
0
        const gx_io_device *iodev = gx_io_device_table[i];
1348
0
        const char *dname = iodev->dname;
1349
1350
0
        if (dname && strlen(dname) == 5 && !memcmp("%rom%", dname, 5)) {
1351
0
            struct stat pstat;
1352
            /* gs_error_unregistered means no usable romfs is available */
1353
0
            int code = iodev->procs.file_status((gx_io_device *)iodev, dname, &pstat);
1354
0
            if (code != gs_error_unregistered){
1355
0
                have_rom_device = 1;
1356
0
            }
1357
0
            break;
1358
0
        }
1359
0
    }
1360
0
    if (have_rom_device) {
1361
0
        outprintf(minst->heap, "Initialization files are compiled into the executable.\n");
1362
0
    }
1363
0
    print_help_trailer(minst);
1364
0
}
1365
1366
/* Print the revision, revision date, and copyright. */
1367
static void
1368
print_revision(const gs_main_instance *minst)
1369
0
{
1370
0
    printf_program_ident(minst->heap, gs_product, gs_revision);
1371
0
    outprintf(minst->heap, " (%d-%02d-%02d)\n%s\n",
1372
0
            (int)(gs_revisiondate / 10000),
1373
0
            (int)(gs_revisiondate / 100 % 100),
1374
0
            (int)(gs_revisiondate % 100),
1375
0
            gs_copyright);
1376
0
}
1377
1378
/* Print the version number. */
1379
static void
1380
print_version(const gs_main_instance *minst)
1381
0
{
1382
0
    printf_program_ident(minst->heap, NULL, gs_revision);
1383
0
}
1384
1385
/* Print usage information. */
1386
static void
1387
print_usage(const gs_main_instance *minst)
1388
0
{
1389
0
    outprintf(minst->heap, "%s", help_usage1);
1390
0
    outprintf(minst->heap, "%s", help_usage2);
1391
#ifdef DEBUG
1392
    outprintf(minst->heap, "%s", help_debug);
1393
#endif
1394
0
}
1395
1396
/* compare function for qsort */
1397
static int
1398
cmpstr(const void *v1, const void *v2)
1399
0
{
1400
0
    return strcmp( *(char * const *)v1, *(char * const *)v2 );
1401
0
}
1402
1403
/* Print the list of available devices. */
1404
static void
1405
print_devices(const gs_main_instance *minst)
1406
0
{
1407
0
    outprintf(minst->heap, "%s", help_default_device);
1408
0
    outprintf(minst->heap, " %s\n", gs_devicename(gs_getdefaultdevice()));
1409
0
    outprintf(minst->heap, "%s", help_devices);
1410
0
    {
1411
0
        int i;
1412
0
        int pos = 100;
1413
0
        const gx_device *pdev;
1414
0
        const char **names;
1415
0
        size_t ndev = 0;
1416
1417
0
        for (i = 0; gs_getdevice(i) != 0; i++)
1418
0
            ;
1419
0
        ndev = (size_t)i;
1420
0
        names = (const char **)gs_alloc_bytes(minst->heap, (size_t)ndev * sizeof(const char*), "print_devices");
1421
0
        if (names == (const char **)NULL) { /* old-style unsorted device list */
1422
0
            for (i = 0; (pdev = gs_getdevice(i)) != 0; i++) {
1423
0
                const char *dname = gs_devicename(pdev);
1424
0
                int len = strlen(dname);
1425
1426
0
                if (pos + 1 + len > 76)
1427
0
                    outprintf(minst->heap, "\n  "), pos = 2;
1428
0
                outprintf(minst->heap, " %s", dname);
1429
0
                pos += 1 + len;
1430
0
            }
1431
0
        }
1432
0
        else {                          /* new-style sorted device list */
1433
0
            for (i = 0; (pdev = gs_getdevice(i)) != 0; i++)
1434
0
                names[i] = gs_devicename(pdev);
1435
0
            qsort((void*)names, ndev, sizeof(const char*), cmpstr);
1436
0
            for (i = 0; i < ndev; i++) {
1437
0
                int len = strlen(names[i]);
1438
1439
0
                if (pos + 1 + len > 76)
1440
0
                    outprintf(minst->heap, "\n  "), pos = 2;
1441
0
                outprintf(minst->heap, " %s", names[i]);
1442
0
                pos += 1 + len;
1443
0
            }
1444
0
            gs_free(minst->heap, (char *)names, ndev * sizeof(const char*), 1, "print_devices");
1445
0
        }
1446
0
    }
1447
0
    outprintf(minst->heap, "\n");
1448
0
}
1449
1450
/* Print the list of language emulators. */
1451
static void
1452
print_emulators(const gs_main_instance *minst)
1453
0
{
1454
0
    outprintf(minst->heap, "%s", help_emulators);
1455
0
    {
1456
0
        const byte *s;
1457
1458
0
        for (s = gs_emulators; s[0] != 0; s += strlen((const char *)s) + 1)
1459
0
            outprintf(minst->heap, " %s", s);
1460
0
    }
1461
0
    outprintf(minst->heap, "\n");
1462
0
}
1463
1464
/* Print the search paths. */
1465
static void
1466
print_paths(gs_main_instance * minst)
1467
0
{
1468
0
    outprintf(minst->heap, "%s", help_paths);
1469
0
    gs_main_set_lib_paths(minst);
1470
0
    {
1471
0
        uint count = r_size(&minst->lib_path.list);
1472
0
        uint i;
1473
0
        int pos = 100;
1474
0
        char fsepr[3];
1475
1476
0
        fsepr[0] = ' ', fsepr[1] = gp_file_name_list_separator,
1477
0
            fsepr[2] = 0;
1478
0
        for (i = 0; i < count; ++i) {
1479
0
            const ref *prdir =
1480
0
            minst->lib_path.list.value.refs + i;
1481
0
            uint len = r_size(prdir);
1482
0
            const char *sepr = (i == count - 1 ? "" : fsepr);
1483
1484
0
            if (1 + pos + strlen(sepr) + len > 76)
1485
0
                outprintf(minst->heap, "\n  "), pos = 2;
1486
0
            outprintf(minst->heap, " ");
1487
            /*
1488
             * This is really ugly, but it's necessary because some
1489
             * platforms rely on all console output being funneled through
1490
             * outprintf.  We wish we could just do:
1491
             fwrite(prdir->value.bytes, 1, len, minst->fstdout);
1492
             */
1493
0
            {
1494
0
                const char *p = (const char *)prdir->value.bytes;
1495
0
                uint j;
1496
1497
0
                for (j = len; j; j--)
1498
0
                    outprintf(minst->heap, "%c", *p++);
1499
0
            }
1500
0
            outprintf(minst->heap, "%s", sepr);
1501
0
            pos += 1 + len + strlen(sepr);
1502
0
        }
1503
0
    }
1504
0
    outprintf(minst->heap, "\n");
1505
0
    outprintf(minst->heap, "%s", help_fontconfig);
1506
0
}
1507
1508
/* Print the help trailer. */
1509
static void
1510
print_help_trailer(const gs_main_instance *minst)
1511
0
{
1512
0
    char buffer[gp_file_name_sizeof];
1513
0
    const char *use_htm = "Use.html", *p = buffer;
1514
0
    const char *rtd_url = "https://ghostscript.readthedocs.io/en";
1515
0
    const char *latest_ver="latest";
1516
0
    const char *vers = latest_ver;
1517
0
    const char *gs_str = "gs";
1518
0
    const char *gs = "";
1519
0
    uint blen = sizeof(buffer);
1520
1521
0
    if (strlen(GS_PRODUCT) == strlen(GS_PRODUCTFAMILY)) {
1522
0
        vers = GS_STRINGIZE(GS_DOT_VERSION);
1523
0
        gs = gs_str;
1524
0
    }
1525
1526
0
    snprintf(buffer, blen, "%s/%s%s/%s", rtd_url, gs, vers, use_htm);
1527
0
    outprintf(minst->heap, help_trailer, p);
1528
0
}