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