1 /* Copyright (C) 2001-2007 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, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: imainarg.c 10463 2009-12-08 06:31:51Z alexcher $ */
15 /* Command line parsing and dispatching */
16 #include "ctype_.h"
17 #include "memory_.h"
18 #include "string_.h"
19 #include <stdlib.h> /* for qsort */
20
21 #include "ghost.h"
22 #include "gp.h"
23 #include "gsargs.h"
24 #include "gscdefs.h"
25 #include "gsmalloc.h" /* for gs_malloc_limit */
26 #include "gsmdebug.h"
27 #include "gxdevice.h"
28 #include "gxdevmem.h"
29 #include "gsdevice.h"
30 #include "stream.h"
31 #include "ierrors.h"
32 #include "estack.h"
33 #include "ialloc.h"
34 #include "strimpl.h" /* for sfilter.h */
35 #include "sfilter.h" /* for iscan.h */
36 #include "ostack.h" /* must precede iscan.h */
37 #include "iscan.h"
38 #include "iconf.h"
39 #include "imain.h"
40 #include "imainarg.h"
41 #include "iapi.h"
42 #include "iminst.h"
43 #include "iname.h"
44 #include "store.h"
45 #include "files.h" /* requires stream.h */
46 #include "interp.h"
47 #include "iutil.h"
48 #include "ivmspace.h"
49 #include "vdtrace.h"
50
51 /* Import operator procedures */
52 extern int zflush(i_ctx_t *);
53 extern int zflushpage(i_ctx_t *);
54
55 #ifndef GS_LIB
56 # define GS_LIB "GS_LIB"
57 #endif
58
59 #ifndef GS_OPTIONS
60 # define GS_OPTIONS "GS_OPTIONS"
61 #endif
62
63 #ifndef GS_MAX_LIB_DIRS
64 # define GS_MAX_LIB_DIRS 25
65 #endif
66
67 #define MAX_BUFFERED_SIZE 1024
68
69 /* Note: sscanf incorrectly defines its first argument as char * */
70 /* rather than const char *. This accounts for the ugly casts below. */
71
72 /* Redefine puts to use outprintf, */
73 /* so it will work even without stdio. */
74 #undef puts
75 #define puts(mem, str) outprintf(mem, "%s\n", str)
76
77 /* Forward references */
78 #define runInit 1
79 #define runFlush 2
80 #define runBuffer 4
81 static int swproc(gs_main_instance *, const char *, arg_list *);
82 static int argproc(gs_main_instance *, const char *);
83 static int run_buffered(gs_main_instance *, const char *);
84 static int esc_strlen(const char *);
85 static void esc_strcat(char *, const char *);
86 static int runarg(gs_main_instance *, const char *, const char *, const char *, int);
87 static int run_string(gs_main_instance *, const char *, int);
88 static int run_finish(gs_main_instance *, int, int, ref *);
89 static int try_stdout_redirect(gs_main_instance * minst,
90 const char *command, const char *filename);
91
92 /* Forward references for help printout */
93 static void print_help(gs_main_instance *);
94 static void print_revision(const gs_main_instance *);
95 static void print_version(const gs_main_instance *);
96 static void print_usage(const gs_main_instance *);
97 static void print_devices(const gs_main_instance *);
98 static void print_emulators(const gs_main_instance *);
99 static void print_paths(gs_main_instance *);
100 static void print_help_trailer(const gs_main_instance *);
101
102 /* ------ Main program ------ */
103
104 /* Process the command line with a given instance. */
105 static FILE *
gs_main_arg_fopen(const char * fname,void * vminst)106 gs_main_arg_fopen(const char *fname, void *vminst)
107 {
108 gs_main_set_lib_paths((gs_main_instance *) vminst);
109 return lib_fopen(&((gs_main_instance *)vminst)->lib_path,
110 ((gs_main_instance *)vminst)->heap, fname);
111 }
112 static void
set_debug_flags(const char * arg,char * flags)113 set_debug_flags(const char *arg, char *flags)
114 {
115 byte value = (*arg == '-' ? (++arg, 0) : 0xff);
116
117 while (*arg)
118 flags[*arg++ & 127] = value;
119 }
120
121 int
gs_main_init_with_args(gs_main_instance * minst,int argc,char * argv[])122 gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[])
123 {
124 const char *arg;
125 arg_list args;
126 int code;
127
128 arg_init(&args, (const char **)argv, argc,
129 gs_main_arg_fopen, (void *)minst);
130 code = gs_main_init0(minst, 0, 0, 0, GS_MAX_LIB_DIRS);
131 if (code < 0)
132 return code;
133 /* This first check is not needed on VMS since GS_LIB evaluates to the same
134 value as that returned by gs_lib_default_path. Also, since GS_LIB is
135 defined as a searchlist logical and getenv only returns the first entry
136 in the searchlist, it really doesn't make sense to search that particular
137 directory twice.
138 */
139 #ifndef __VMS
140 {
141 int len = 0;
142 int code = gp_getenv(GS_LIB, (char *)0, &len);
143
144 if (code < 0) { /* key present, value doesn't fit */
145 char *path = (char *)gs_alloc_bytes(minst->heap, len, "GS_LIB");
146
147 gp_getenv(GS_LIB, path, &len); /* can't fail */
148 minst->lib_path.env = path;
149 }
150 }
151 #endif /* __VMS */
152 minst->lib_path.final = gs_lib_default_path;
153 code = gs_main_set_lib_paths(minst);
154 if (code < 0)
155 return code;
156 /* Prescan the command line for --help and --version. */
157 {
158 int i;
159 bool helping = false;
160
161 for (i = 1; i < argc; ++i)
162 if (!strcmp(argv[i], "--")) {
163 /* A PostScript program will be interpreting all the */
164 /* remaining switches, so stop scanning. */
165 helping = false;
166 break;
167 } else if (!strcmp(argv[i], "--help")) {
168 print_help(minst);
169 helping = true;
170 } else if (!strcmp(argv[i], "--version")) {
171 print_version(minst);
172 puts(minst->heap, ""); /* \n */
173 helping = true;
174 }
175 if (helping)
176 return e_Info;
177 }
178 /* Execute files named in the command line, */
179 /* processing options along the way. */
180 /* Wait until the first file name (or the end */
181 /* of the line) to finish initialization. */
182 minst->run_start = true;
183
184 {
185 int len = 0;
186 int code = gp_getenv(GS_OPTIONS, (char *)0, &len);
187
188 if (code < 0) { /* key present, value doesn't fit */
189 char *opts =
190 (char *)gs_alloc_bytes(minst->heap, len, "GS_OPTIONS");
191
192 gp_getenv(GS_OPTIONS, opts, &len); /* can't fail */
193 if (arg_push_memory_string(&args, opts, false, minst->heap))
194 return e_Fatal;
195 }
196 }
197 while ((arg = arg_next(&args, &code)) != 0) {
198 switch (*arg) {
199 case '-':
200 code = swproc(minst, arg, &args);
201 if (code < 0)
202 return code;
203 if (code > 0)
204 outprintf(minst->heap, "Unknown switch %s - ignoring\n", arg);
205 if (gs_debug[':'] && arg[1] == 'Z') {
206 int i;
207
208 dprintf1("%% Init started, instance 0x%p, with args: ", minst);
209 for (i=1; i<argc; i++)
210 dprintf1("%s ", argv[i]);
211 dprintf("\n");
212 }
213 break;
214 default:
215 code = argproc(minst, arg);
216 if (code < 0)
217 return code;
218 }
219 }
220 if (code < 0)
221 return code;
222
223 code = gs_main_init2(minst);
224 if (code < 0)
225 return code;
226
227 if (gs_debug[':']) {
228 int i;
229
230 dprintf1("%% Init done, instance 0x%p, with args: ", minst);
231 for (i=1; i<argc; i++)
232 dprintf1("%s ", argv[i]);
233 dprintf("\n");
234 }
235 if (!minst->run_start)
236 return e_Quit;
237 return code ;
238 }
239
240 /*
241 * Run the 'start' procedure (after processing the command line).
242 */
243 int
gs_main_run_start(gs_main_instance * minst)244 gs_main_run_start(gs_main_instance * minst)
245 {
246 return run_string(minst, "systemdict /start get exec", runFlush);
247 }
248
249 /* Process switches. Return 0 if processed, 1 for unknown switch, */
250 /* <0 if error. */
251 static int
swproc(gs_main_instance * minst,const char * arg,arg_list * pal)252 swproc(gs_main_instance * minst, const char *arg, arg_list * pal)
253 {
254 char sw = arg[1];
255 ref vtrue;
256 int code = 0;
257 #undef initial_enter_name
258 #define initial_enter_name(nstr, pvalue)\
259 i_initial_enter_name(minst->i_ctx_p, nstr, pvalue)
260
261 make_true(&vtrue);
262 arg += 2; /* skip - and letter */
263 switch (sw) {
264 default:
265 return 1;
266 case 0: /* read stdin as a file char-by-char */
267 /* This is a ******HACK****** for Ghostview. */
268 minst->heap->gs_lib_ctx->stdin_is_interactive = true;
269 goto run_stdin;
270 case '_': /* read stdin with normal buffering */
271 minst->heap->gs_lib_ctx->stdin_is_interactive = false;
272 run_stdin:
273 minst->run_start = false; /* don't run 'start' */
274 /* Set NOPAUSE so showpage won't try to read from stdin. */
275 code = swproc(minst, "-dNOPAUSE", pal);
276 if (code)
277 return code;
278 code = gs_main_init2(minst); /* Finish initialization */
279 if (code < 0)
280 return code;
281
282 code = run_string(minst, ".runstdin", runFlush);
283 if (code < 0)
284 return code;
285 break;
286 case '-': /* run with command line args */
287 case '+':
288 pal->expand_ats = false;
289 case '@': /* ditto with @-expansion */
290 {
291 const char *psarg = arg_next(pal, &code);
292
293 if (code < 0)
294 return e_Fatal;
295 if (psarg == 0) {
296 outprintf(minst->heap, "Usage: gs ... -%c file.ps arg1 ... argn\n", sw);
297 arg_finit(pal);
298 return e_Fatal;
299 }
300 psarg = arg_copy(psarg, minst->heap);
301 if (psarg == NULL)
302 return e_Fatal;
303 code = gs_main_init2(minst);
304 if (code < 0)
305 return code;
306 code = run_string(minst, "userdict/ARGUMENTS[", 0);
307 if (code < 0)
308 return code;
309 while ((arg = arg_next(pal, &code)) != 0) {
310 char *fname = arg_copy(arg, minst->heap);
311 if (fname == NULL)
312 return e_Fatal;
313 code = runarg(minst, "", fname, "", runInit);
314 if (code < 0)
315 return code;
316 }
317 if (code < 0)
318 return e_Fatal;
319 runarg(minst, "]put", psarg, ".runfile", runInit | runFlush);
320 return e_Quit;
321 }
322 case 'A': /* trace allocator */
323 switch (*arg) {
324 case 0:
325 gs_alloc_debug = 1;
326 break;
327 case '-':
328 gs_alloc_debug = 0;
329 break;
330 default:
331 puts(minst->heap, "-A may only be followed by -");
332 return e_Fatal;
333 }
334 break;
335 case 'B': /* set run_string buffer size */
336 if (*arg == '-')
337 minst->run_buffer_size = 0;
338 else {
339 uint bsize;
340
341 if (sscanf((const char *)arg, "%u", &bsize) != 1 ||
342 bsize <= 0 || bsize > MAX_BUFFERED_SIZE
343 ) {
344 outprintf(minst->heap,
345 "-B must be followed by - or size between 1 and %u\n",
346 MAX_BUFFERED_SIZE);
347 return e_Fatal;
348 }
349 minst->run_buffer_size = bsize;
350 }
351 break;
352 case 'c': /* code follows */
353 {
354 bool ats = pal->expand_ats;
355
356 code = gs_main_init2(minst);
357 if (code < 0)
358 return code;
359 pal->expand_ats = false;
360 while ((arg = arg_next(pal, &code)) != 0) {
361 char *sarg;
362
363 if (arg[0] == '@' ||
364 (arg[0] == '-' && !isdigit((unsigned char)arg[1]))
365 )
366 break;
367 sarg = arg_copy(arg, minst->heap);
368 if (sarg == NULL)
369 return e_Fatal;
370 code = runarg(minst, "", sarg, ".runstring", 0);
371 if (code < 0)
372 return code;
373 }
374 if (code < 0)
375 return e_Fatal;
376 if (arg != 0) {
377 char *p = arg_copy(arg, minst->heap);
378 if (p == NULL)
379 return e_Fatal;
380 arg_push_string(pal, p, true);
381 }
382 pal->expand_ats = ats;
383 break;
384 }
385 case 'E': /* log errors */
386 switch (*arg) {
387 case 0:
388 gs_log_errors = 1;
389 break;
390 case '-':
391 gs_log_errors = 0;
392 break;
393 default:
394 puts(minst->heap, "-E may only be followed by -");
395 return e_Fatal;
396 }
397 break;
398 case 'f': /* run file of arbitrary name */
399 if (*arg != 0) {
400 code = argproc(minst, arg);
401 if (code < 0)
402 return code;
403 }
404 break;
405 case 'F': /* run file with buffer_size = 1 */
406 if (!*arg) {
407 puts(minst->heap, "-F requires a file name");
408 return e_Fatal;
409 } {
410 uint bsize = minst->run_buffer_size;
411
412 minst->run_buffer_size = 1;
413 code = argproc(minst, arg);
414 minst->run_buffer_size = bsize;
415 if (code < 0)
416 return code;
417 }
418 break;
419 case 'g': /* define device geometry */
420 {
421 long width, height;
422 ref value;
423
424 if ((code = gs_main_init1(minst)) < 0)
425 return code;
426 if (sscanf((const char *)arg, "%ldx%ld", &width, &height) != 2) {
427 puts(minst->heap, "-g must be followed by <width>x<height>");
428 return e_Fatal;
429 }
430 make_int(&value, width);
431 initial_enter_name("DEVICEWIDTH", &value);
432 make_int(&value, height);
433 initial_enter_name("DEVICEHEIGHT", &value);
434 initial_enter_name("FIXEDMEDIA", &vtrue);
435 break;
436 }
437 case 'h': /* print help */
438 case '?': /* ditto */
439 print_help(minst);
440 return e_Info; /* show usage info on exit */
441 case 'I': /* specify search path */
442 {
443 char *path = arg_copy(arg, minst->heap);
444 if (path == NULL)
445 return e_Fatal;
446 gs_main_add_lib_path(minst, path);
447 }
448 break;
449 case 'K': /* set malloc limit */
450 {
451 long msize = 0;
452 gs_malloc_memory_t *rawheap = gs_malloc_wrapped_contents(minst->heap);
453
454 sscanf((const char *)arg, "%ld", &msize);
455 if (msize <= 0 || msize > max_long >> 10) {
456 outprintf(minst->heap, "-K<numK> must have 1 <= numK <= %ld\n",
457 max_long >> 10);
458 return e_Fatal;
459 }
460 rawheap->limit = msize << 10;
461 }
462 break;
463 case 'M': /* set memory allocation increment */
464 {
465 unsigned msize = 0;
466
467 sscanf((const char *)arg, "%u", &msize);
468 #if ARCH_INTS_ARE_SHORT
469 if (msize <= 0 || msize >= 64) {
470 puts(minst->heap, "-M must be between 1 and 63");
471 return e_Fatal;
472 }
473 #endif
474 minst->memory_chunk_size = msize << 10;
475 }
476 break;
477 case 'N': /* set size of name table */
478 {
479 unsigned nsize = 0;
480
481 sscanf((const char *)arg, "%d", &nsize);
482 #if ARCH_INTS_ARE_SHORT
483 if (nsize < 2 || nsize > 64) {
484 puts(minst->heap, "-N must be between 2 and 64");
485 return e_Fatal;
486 }
487 #endif
488 minst->name_table_size = (ulong) nsize << 10;
489 }
490 break;
491 case 'o': /* set output file name and batch mode */
492 {
493 const char *adef;
494 char *str;
495 ref value;
496 int len;
497
498 if (arg[0] == 0) {
499 adef = arg_next(pal, &code);
500 if (code < 0)
501 return code;
502 } else
503 adef = arg;
504 if ((code = gs_main_init1(minst)) < 0)
505 return code;
506 len = strlen(adef);
507 str = (char *)gs_alloc_bytes(minst->heap, (uint)len, "-o");
508 memcpy(str, adef, len);
509 make_const_string(&value, a_readonly | avm_foreign,
510 len, (const byte *)str);
511 initial_enter_name("OutputFile", &value);
512 initial_enter_name("NOPAUSE", &vtrue);
513 initial_enter_name("BATCH", &vtrue);
514 }
515 break;
516 case 'P': /* choose whether search '.' first */
517 if (!strcmp(arg, ""))
518 minst->search_here_first = true;
519 else if (!strcmp(arg, "-"))
520 minst->search_here_first = false;
521 else {
522 puts(minst->heap, "Only -P or -P- is allowed.");
523 return e_Fatal;
524 }
525 break;
526 case 'q': /* quiet startup */
527 if ((code = gs_main_init1(minst)) < 0)
528 return code;
529 initial_enter_name("QUIET", &vtrue);
530 break;
531 case 'r': /* define device resolution */
532 {
533 float xres, yres;
534 ref value;
535
536 if ((code = gs_main_init1(minst)) < 0)
537 return code;
538 switch (sscanf((const char *)arg, "%fx%f", &xres, &yres)) {
539 default:
540 puts(minst->heap, "-r must be followed by <res> or <xres>x<yres>");
541 return e_Fatal;
542 case 1: /* -r<res> */
543 yres = xres;
544 case 2: /* -r<xres>x<yres> */
545 make_real(&value, xres);
546 initial_enter_name("DEVICEXRESOLUTION", &value);
547 make_real(&value, yres);
548 initial_enter_name("DEVICEYRESOLUTION", &value);
549 initial_enter_name("FIXEDRESOLUTION", &vtrue);
550 }
551 break;
552 }
553 case 'D': /* define name */
554 case 'd':
555 case 'S': /* define name as string */
556 case 's':
557 {
558 char *adef = arg_copy(arg, minst->heap);
559 char *eqp;
560 bool isd = (sw == 'D' || sw == 'd');
561 ref value;
562
563 if (adef == NULL)
564 return e_Fatal;
565 eqp = strchr(adef, '=');
566
567 if (eqp == NULL)
568 eqp = strchr(adef, '#');
569 /* Initialize the object memory, scanner, and */
570 /* name table now if needed. */
571 if ((code = gs_main_init1(minst)) < 0)
572 return code;
573 if (eqp == adef) {
574 puts(minst->heap, "Usage: -dname, -dname=token, -sname=string");
575 return e_Fatal;
576 }
577 if (eqp == NULL) {
578 if (isd)
579 make_true(&value);
580 else
581 make_empty_string(&value, a_readonly);
582 } else {
583 int code;
584 i_ctx_t *i_ctx_p = minst->i_ctx_p;
585 uint space = icurrent_space;
586
587 *eqp++ = 0;
588 ialloc_set_space(idmemory, avm_system);
589 if (isd) {
590 stream astream;
591 scanner_state state;
592
593 s_init(&astream, NULL);
594 sread_string(&astream,
595 (const byte *)eqp, strlen(eqp));
596 scanner_init_stream(&state, &astream);
597 code = scan_token(minst->i_ctx_p, &value, &state);
598 if (code) {
599 puts(minst->heap, "-dname= must be followed by a valid token");
600 return e_Fatal;
601 }
602 if (r_has_type_attrs(&value, t_name,
603 a_executable)) {
604 ref nsref;
605
606 name_string_ref(minst->heap, &value, &nsref);
607 #define string_is(nsref, str, len)\
608 (r_size(&(nsref)) == (len) &&\
609 !strncmp((const char *)(nsref).value.const_bytes, str, (len)))
610 if (string_is(nsref, "null", 4))
611 make_null(&value);
612 else if (string_is(nsref, "true", 4))
613 make_true(&value);
614 else if (string_is(nsref, "false", 5))
615 make_false(&value);
616 else {
617 puts(minst->heap,
618 "-dvar=name requires name=null, true, or false");
619 return e_Fatal;
620 }
621 #undef name_is_string
622 }
623 } else {
624 int len = strlen(eqp);
625 char *str =
626 (char *)gs_alloc_bytes(minst->heap,
627 (uint) len, "-s");
628
629 if (str == 0) {
630 lprintf("Out of memory!\n");
631 return e_Fatal;
632 }
633 memcpy(str, eqp, len);
634 make_const_string(&value,
635 a_readonly | avm_foreign,
636 len, (const byte *)str);
637 if ((code = try_stdout_redirect(minst, adef, eqp)) < 0)
638 return code;
639 }
640 ialloc_set_space(idmemory, space);
641 }
642 /* Enter the name in systemdict. */
643 initial_enter_name(adef, &value);
644 break;
645 }
646 case 'T':
647 set_debug_flags(arg, vd_flags);
648 break;
649 case 'u': /* undefine name */
650 if (!*arg) {
651 puts(minst->heap, "-u requires a name to undefine.");
652 return e_Fatal;
653 }
654 if ((code = gs_main_init1(minst)) < 0)
655 return code;
656 i_initial_remove_name(minst->i_ctx_p, arg);
657 break;
658 case 'v': /* print revision */
659 print_revision(minst);
660 return e_Info;
661 /*#ifdef DEBUG */
662 /*
663 * Here we provide a place for inserting debugging code that can be
664 * run in place of the normal interpreter code.
665 */
666 case 'X':
667 code = gs_main_init2(minst);
668 if (code < 0)
669 return code;
670 {
671 int xec; /* exit_code */
672 ref xeo; /* error_object */
673
674 #define start_x()\
675 gs_main_run_string_begin(minst, 1, &xec, &xeo)
676 #define run_x(str)\
677 gs_main_run_string_continue(minst, str, strlen(str), 1, &xec, &xeo)
678 #define stop_x()\
679 gs_main_run_string_end(minst, 1, &xec, &xeo)
680 start_x();
681 run_x("\216\003abc");
682 run_x("== flush\n");
683 stop_x();
684 }
685 return e_Quit;
686 /*#endif */
687 case 'Z':
688 set_debug_flags(arg, gs_debug);
689 break;
690 }
691 return 0;
692 }
693
694 /* Define versions of strlen and strcat that encode strings in hex. */
695 /* This is so we can enter escaped characters regardless of whether */
696 /* the Level 1 convention of ignoring \s in strings-within-strings */
697 /* is being observed (sigh). */
698 static int
esc_strlen(const char * str)699 esc_strlen(const char *str)
700 {
701 return strlen(str) * 2 + 2;
702 }
703 static void
esc_strcat(char * dest,const char * src)704 esc_strcat(char *dest, const char *src)
705 {
706 char *d = dest + strlen(dest);
707 const char *p;
708 static const char *const hex = "0123456789abcdef";
709
710 *d++ = '<';
711 for (p = src; *p; p++) {
712 byte c = (byte) * p;
713
714 *d++ = hex[c >> 4];
715 *d++ = hex[c & 0xf];
716 }
717 *d++ = '>';
718 *d = 0;
719 }
720
721 /* Process file names */
722 static int
argproc(gs_main_instance * minst,const char * arg)723 argproc(gs_main_instance * minst, const char *arg)
724 {
725 int code = gs_main_init1(minst); /* need i_ctx_p to proceed */
726 char *filearg;
727
728 if (code < 0)
729 return code;
730 filearg = arg_copy(arg, minst->heap);
731 if (filearg == NULL)
732 return e_Fatal;
733 if (minst->run_buffer_size) {
734 /* Run file with run_string. */
735 return run_buffered(minst, filearg);
736 } else {
737 /* Run file directly in the normal way. */
738 return runarg(minst, "", filearg, ".runfile", runInit | runFlush);
739 }
740 }
741 static int
run_buffered(gs_main_instance * minst,const char * arg)742 run_buffered(gs_main_instance * minst, const char *arg)
743 {
744 FILE *in = gp_fopen(arg, gp_fmode_rb);
745 int exit_code;
746 ref error_object;
747 int code;
748
749 if (in == 0) {
750 outprintf(minst->heap, "Unable to open %s for reading", arg);
751 return_error(e_invalidfileaccess);
752 }
753 code = gs_main_init2(minst);
754 if (code < 0) {
755 fclose(in);
756 return code;
757 }
758 code = gs_main_run_string_begin(minst, minst->user_errors,
759 &exit_code, &error_object);
760 if (!code) {
761 char buf[MAX_BUFFERED_SIZE];
762 int count;
763
764 code = e_NeedInput;
765 while ((count = fread(buf, 1, minst->run_buffer_size, in)) > 0) {
766 code = gs_main_run_string_continue(minst, buf, count,
767 minst->user_errors,
768 &exit_code, &error_object);
769 if (code != e_NeedInput)
770 break;
771 }
772 if (code == e_NeedInput) {
773 code = gs_main_run_string_end(minst, minst->user_errors,
774 &exit_code, &error_object);
775 }
776 }
777 fclose(in);
778 zflush(minst->i_ctx_p);
779 zflushpage(minst->i_ctx_p);
780 return run_finish(minst, code, exit_code, &error_object);
781 }
782 static int
runarg(gs_main_instance * minst,const char * pre,const char * arg,const char * post,int options)783 runarg(gs_main_instance * minst, const char *pre, const char *arg,
784 const char *post, int options)
785 {
786 int len = strlen(pre) + esc_strlen(arg) + strlen(post) + 1;
787 int code;
788 char *line;
789
790 if (options & runInit) {
791 code = gs_main_init2(minst); /* Finish initialization */
792
793 if (code < 0)
794 return code;
795 }
796 line = (char *)gs_alloc_bytes(minst->heap, len, "argproc");
797 if (line == 0) {
798 lprintf("Out of memory!\n");
799 return_error(e_VMerror);
800 }
801 strcpy(line, pre);
802 esc_strcat(line, arg);
803 strcat(line, post);
804 minst->i_ctx_p->starting_arg_file = true;
805 code = run_string(minst, line, options);
806 minst->i_ctx_p->starting_arg_file = false;
807 return code;
808 }
809 static int
run_string(gs_main_instance * minst,const char * str,int options)810 run_string(gs_main_instance * minst, const char *str, int options)
811 {
812 int exit_code;
813 ref error_object;
814 int code = gs_main_run_string(minst, str, minst->user_errors,
815 &exit_code, &error_object);
816
817 if ((options & runFlush) || code != 0) {
818 zflush(minst->i_ctx_p); /* flush stdout */
819 zflushpage(minst->i_ctx_p); /* force display update */
820 }
821 return run_finish(minst, code, exit_code, &error_object);
822 }
823 static int
run_finish(gs_main_instance * minst,int code,int exit_code,ref * perror_object)824 run_finish(gs_main_instance *minst, int code, int exit_code,
825 ref * perror_object)
826 {
827 switch (code) {
828 case e_Quit:
829 case 0:
830 break;
831 case e_Fatal:
832 eprintf1("Unrecoverable error, exit code %d\n", exit_code);
833 break;
834 default:
835 gs_main_dump_stack(minst, code, perror_object);
836 }
837 return code;
838 }
839
840 /* Redirect stdout to a file:
841 * -sstdout=filename
842 * -sstdout=-
843 * -sstdout=%stdout
844 * -sstdout=%stderr
845 * -sOutputFile=- is not affected.
846 * File is closed at program exit (if not stdout/err)
847 * or when -sstdout is used again.
848 */
849 static int
try_stdout_redirect(gs_main_instance * minst,const char * command,const char * filename)850 try_stdout_redirect(gs_main_instance * minst,
851 const char *command, const char *filename)
852 {
853 if (strcmp(command, "stdout") == 0) {
854 minst->heap->gs_lib_ctx->stdout_to_stderr = 0;
855 minst->heap->gs_lib_ctx->stdout_is_redirected = 0;
856 /* If stdout already being redirected and it is not stdout
857 * or stderr, close it
858 */
859 if (minst->heap->gs_lib_ctx->fstdout2
860 && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstdout)
861 && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstderr)) {
862 fclose(minst->heap->gs_lib_ctx->fstdout2);
863 minst->heap->gs_lib_ctx->fstdout2 = (FILE *)NULL;
864 }
865 /* If stdout is being redirected, set minst->fstdout2 */
866 if ( (filename != 0) && strlen(filename) &&
867 strcmp(filename, "-") && strcmp(filename, "%stdout") ) {
868 if (strcmp(filename, "%stderr") == 0) {
869 minst->heap->gs_lib_ctx->stdout_to_stderr = 1;
870 }
871 else if ((minst->heap->gs_lib_ctx->fstdout2 =
872 fopen(filename, "w")) == (FILE *)NULL)
873 return_error(e_invalidfileaccess);
874 minst->heap->gs_lib_ctx->stdout_is_redirected = 1;
875 }
876 return 0;
877 }
878 return 1;
879 }
880
881 /* ---------------- Print information ---------------- */
882
883 /*
884 * Help strings. We have to break them up into parts, because
885 * the Watcom compiler has a limit of 510 characters for a single token.
886 * For PC displays, we want to limit the strings to 24 lines.
887 */
888 static const char help_usage1[] = "\
889 Usage: gs [switches] [file1.ps file2.ps ...]\n\
890 Most frequently used switches: (you can use # in place of =)\n\
891 -dNOPAUSE no pause after page | -q `quiet', fewer messages\n\
892 -g<width>x<height> page size in pixels | -r<res> pixels/inch resolution\n";
893 static const char help_usage2[] = "\
894 -sDEVICE=<devname> select device | -dBATCH exit after last file\n\
895 -sOutputFile=<file> select output file: - for stdout, |command for pipe,\n\
896 embed %d or %ld for page #\n";
897 static const char help_trailer[] = "\
898 For more information, see %s.\n\
899 Please report bugs to bugs.ghostscript.com.\n";
900 static const char help_devices[] = "Available devices:";
901 static const char help_default_device[] = "Default output device:";
902 static const char help_emulators[] = "Input formats:";
903 static const char help_paths[] = "Search path:";
904
905 extern_gx_io_device_table();
906
907 /* Print the standard help message. */
908 static void
print_help(gs_main_instance * minst)909 print_help(gs_main_instance * minst)
910 {
911 int i, have_rom_device = 0;
912
913 print_revision(minst);
914 print_usage(minst);
915 print_emulators(minst);
916 print_devices(minst);
917 print_paths(minst);
918 /* Check if we have the %rom device */
919 for (i = 0; i < gx_io_device_table_count; i++) {
920 const gx_io_device *iodev = gx_io_device_table[i];
921 const char *dname = iodev->dname;
922
923 if (dname && strlen(dname) == 5 && !memcmp("%rom%", dname, 5)) {
924 have_rom_device = 1;
925 break;
926 }
927 }
928 if (have_rom_device) {
929 outprintf(minst->heap, "Initialization files are compiled into the executable.\n");
930 }
931 print_help_trailer(minst);
932 }
933
934 /* Print the revision, revision date, and copyright. */
935 static void
print_revision(const gs_main_instance * minst)936 print_revision(const gs_main_instance *minst)
937 {
938 printf_program_ident(minst->heap, gs_product, gs_revision);
939 outprintf(minst->heap, " (%d-%02d-%02d)\n%s\n",
940 (int)(gs_revisiondate / 10000),
941 (int)(gs_revisiondate / 100 % 100),
942 (int)(gs_revisiondate % 100),
943 gs_copyright);
944 }
945
946 /* Print the version number. */
947 static void
print_version(const gs_main_instance * minst)948 print_version(const gs_main_instance *minst)
949 {
950 printf_program_ident(minst->heap, NULL, gs_revision);
951 }
952
953 /* Print usage information. */
954 static void
print_usage(const gs_main_instance * minst)955 print_usage(const gs_main_instance *minst)
956 {
957 outprintf(minst->heap, "%s", help_usage1);
958 outprintf(minst->heap, "%s", help_usage2);
959 }
960
961 /* compare function for qsort */
962 static int
cmpstr(const void * v1,const void * v2)963 cmpstr(const void *v1, const void *v2)
964 {
965 return strcmp( *(char * const *)v1, *(char * const *)v2 );
966 }
967
968 /* Print the list of available devices. */
969 static void
print_devices(const gs_main_instance * minst)970 print_devices(const gs_main_instance *minst)
971 {
972 outprintf(minst->heap, "%s", help_default_device);
973 outprintf(minst->heap, " %s\n", gs_devicename(gs_getdefaultdevice()));
974 outprintf(minst->heap, "%s", help_devices);
975 {
976 int i;
977 int pos = 100;
978 const gx_device *pdev;
979 const char **names;
980 size_t ndev = 0;
981
982 for (i = 0; gs_getdevice(i) != 0; i++)
983 ;
984 ndev = (size_t)i;
985 names = (const char **)gs_alloc_bytes(minst->heap, ndev * sizeof(const char*), "print_devices");
986 if (names == (const char **)NULL) { /* old-style unsorted device list */
987 for (i = 0; (pdev = gs_getdevice(i)) != 0; i++) {
988 const char *dname = gs_devicename(pdev);
989 int len = strlen(dname);
990
991 if (pos + 1 + len > 76)
992 outprintf(minst->heap, "\n "), pos = 2;
993 outprintf(minst->heap, " %s", dname);
994 pos += 1 + len;
995 }
996 }
997 else { /* new-style sorted device list */
998 for (i = 0; (pdev = gs_getdevice(i)) != 0; i++)
999 names[i] = gs_devicename(pdev);
1000 qsort((void*)names, ndev, sizeof(const char*), cmpstr);
1001 for (i = 0; i < ndev; i++) {
1002 int len = strlen(names[i]);
1003
1004 if (pos + 1 + len > 76)
1005 outprintf(minst->heap, "\n "), pos = 2;
1006 outprintf(minst->heap, " %s", names[i]);
1007 pos += 1 + len;
1008 }
1009 gs_free(minst->heap, (char *)names, ndev * sizeof(const char*), 1, "print_devices");
1010 }
1011 }
1012 outprintf(minst->heap, "\n");
1013 }
1014
1015 /* Print the list of language emulators. */
1016 static void
print_emulators(const gs_main_instance * minst)1017 print_emulators(const gs_main_instance *minst)
1018 {
1019 outprintf(minst->heap, "%s", help_emulators);
1020 {
1021 const ref *pes;
1022
1023 for (pes = gs_emulator_name_array;
1024 pes->value.const_bytes != 0; pes++
1025 )
1026 /*
1027 * Even though gs_emulator_name_array is declared and used as
1028 * an array of string refs, each string is actually a
1029 * (null terminated) C string.
1030 */
1031 outprintf(minst->heap, " %s", (const char *)pes->value.const_bytes);
1032 }
1033 outprintf(minst->heap, "\n");
1034 }
1035
1036 /* Print the search paths. */
1037 static void
print_paths(gs_main_instance * minst)1038 print_paths(gs_main_instance * minst)
1039 {
1040 outprintf(minst->heap, "%s", help_paths);
1041 gs_main_set_lib_paths(minst);
1042 {
1043 uint count = r_size(&minst->lib_path.list);
1044 uint i;
1045 int pos = 100;
1046 char fsepr[3];
1047
1048 fsepr[0] = ' ', fsepr[1] = gp_file_name_list_separator,
1049 fsepr[2] = 0;
1050 for (i = 0; i < count; ++i) {
1051 const ref *prdir =
1052 minst->lib_path.list.value.refs + i;
1053 uint len = r_size(prdir);
1054 const char *sepr = (i == count - 1 ? "" : fsepr);
1055
1056 if (1 + pos + strlen(sepr) + len > 76)
1057 outprintf(minst->heap, "\n "), pos = 2;
1058 outprintf(minst->heap, " ");
1059 /*
1060 * This is really ugly, but it's necessary because some
1061 * platforms rely on all console output being funneled through
1062 * outprintf. We wish we could just do:
1063 fwrite(prdir->value.bytes, 1, len, minst->fstdout);
1064 */
1065 {
1066 const char *p = (const char *)prdir->value.bytes;
1067 uint j;
1068
1069 for (j = len; j; j--)
1070 outprintf(minst->heap, "%c", *p++);
1071 }
1072 outprintf(minst->heap, "%s", sepr);
1073 pos += 1 + len + strlen(sepr);
1074 }
1075 }
1076 outprintf(minst->heap, "\n");
1077 }
1078
1079 /* Print the help trailer. */
1080 static void
print_help_trailer(const gs_main_instance * minst)1081 print_help_trailer(const gs_main_instance *minst)
1082 {
1083 char buffer[gp_file_name_sizeof];
1084 const char *use_htm = "Use.htm", *p = buffer;
1085 uint blen = sizeof(buffer);
1086
1087 if (gp_file_name_combine(gs_doc_directory, strlen(gs_doc_directory),
1088 use_htm, strlen(use_htm), false, buffer, &blen) != gp_combine_success)
1089 p = use_htm;
1090 outprintf(minst->heap, help_trailer, p);
1091 }
1092