Coverage Report

Created: 2022-04-16 11:23

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