386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / gs.c
CommitLineData
c2d43213
WJ
1/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* gs.c */
21/* Driver program for Ghostscript */
22#include <stdio.h>
23#include "memory_.h"
24#include "string_.h"
25#include "ghost.h"
26#include "alloc.h"
27#include "estack.h"
28#include "ostack.h"
29#include "store.h"
30#include "stream.h"
31
32#ifndef GS_LIB
33# define GS_LIB "GS_LIB"
34#endif
35
36#ifndef PROGRAM_NAME
37# define PROGRAM_NAME "Ghostscript"
38#endif
39
40/* Library routines not declared in a standard header */
41extern char *getenv(P1(const char *));
42
43/* Exported data */
44uint memory_chunk_size = 20000;
45/* File name search paths */
46const char **gs_lib_paths;
47private int gs_lib_count;
48private char *gs_lib_env_path;
49
50/* Configuration information imported from gconfig.c. */
51extern const char *gs_lib_default_path;
52extern const char *gs_init_file;
53extern ref gs_init_file_array[];
54
55/* Device procedures imported from gsdevice.c. */
56typedef struct gx_device_s gx_device;
57extern gx_device *gs_getdevice(P1(int));
58extern char *gs_devicename(P1(gx_device *));
59
60/* Help string */
61private char *gs_help1 = "\
62Usage: gs [switches] [file1.ps file2.ps ...]\n\
63 or : gs [switches] [file1.ps ...] -- filen.ps arg1 arg2 ...\n\
64The latter passes arg1 ... to the program in filen.ps.\n\
65Available devices:\n ";
66/* We have to break help2 up into two parts, because the Watcom compiler */
67/* has a limit of 510 characters for a single token. */
68private char *gs_help2a = "\n\
69Switches: (you can use # in place of =)\n\
70 -d<name>[=<token>] define name as token, or null if no token given\n\
71 -g<width>x<height> set width and height (`geometry') for device\n\
72 -I<prefix> add prefix to search path\n\
73 -q `quiet' mode, suppress most messages\n\
74 -r<res> set resolution for initial device\n";
75private char *gs_help2b = "\
76 -r<xres>x<yres> set device X and Y resolution separately\n\
77 -s<name>=<string> define name as string\n\
78 -sDEVICE=<devname> select initial device\n\
79 -sOUTPUTFILE=<file> select output file, embed %d for page #,\n\
80 |command to pipe\n\
81`-' alone as a file name means read from stdin non-interactively.\n\
82For more information, please read the use.doc file.\n";
83
84/* Forward references */
85private int esc_strlen(P1(const char *));
86private void esc_strcat(P2(char *, const char *));
87private void runarg(P4(char **, char *, char *, int));
88private void run_string(P1(char *));
89private void init1(), init2();
90private void set_lib_paths();
91private void run_file(P2(const char *file_name, int user_errors));
92private void debug_dump_stack(P1(int code));
93
94/* Parameters set by swproc */
95private int user_errors;
96private int quiet;
97private int batch;
98
99/* Static versions of argc and argv (for -- only) */
100private int static_argc;
101private char **static_argv;
102
103main(int argc, char *argv[])
104{ int num_files;
105 int swproc(P2(char **, char *));
106 void argproc(P2(char **, int));
107 static_argc = argc;
108 static_argv = argv;
109 /* Do platform-dependent initialization. */
110 /* We have to do this as the very first thing, */
111 /* because it detects attempts to run 80N86 executables (N>0) */
112 /* on incompatible processors. */
113 gp_init();
114 /* Initialize the file search paths */
115 gs_lib_env_path = 0;
116 { char *lib = getenv(GS_LIB);
117 if ( lib != 0 )
118 { int len = strlen(lib);
119 gs_lib_env_path = gs_malloc(len + 1, 1, "GS_LIB");
120 strcpy(gs_lib_env_path, lib);
121 }
122 }
123 gs_lib_paths =
124 (const char **)gs_malloc(argc + 2, sizeof(char *), "-I array");
125 gs_lib_count = 0;
126 set_lib_paths();
127 /* Execute files named in the command line, */
128 /* processing options along the way. */
129 /* Wait until the first file name (or the end */
130 /* of the line) to finish initialization. */
131 batch = 0;
132 quiet = 0;
133 user_errors = 1;
134 num_files = gs_main(argc, argv, swproc, argproc);
135 if ( num_files == 0 )
136 { init2();
137 }
138 if ( !batch ) run_string("start");
139 gs_exit(0);
140}
141
142/* Process switches */
143int
144swproc(char **swp, char *arg)
145{ char sw = (*swp)[1];
146 switch ( sw )
147 {
148 default:
149 return -1;
150 case 0: /* read stdin as a file */
151 batch = 1;
152 /* Set NOPAUSE so showpage won't try to read from stdin. */
153 { char *d = "-dNOPAUSE";
154 swproc(&d, d);
155 }
156 init2(); /* Finish initialization */
157 run_string("(%stdin) (r) file cvx execute");
158 break;
159 case '-': /* run with command line args */
160 case '+': /* ditto */
161 { int nstrs = static_argv + static_argc - (swp + 2);
162 if ( nstrs < 0 ) /* no file to run! */
163 { printf("Usage: gs ... -- file.ps arg1 ... argn\n");
164 gs_exit(1);
165 }
166 runarg(swp + 1, "{userdict /ARGUMENTS [", "] put (", nstrs);
167 }
168 gs_exit(0);
169 case 'h': /* print help */
170 case '?':
171 fputs(gs_help1, stdout);
172 { int i;
173 gx_device *pdev;
174 for ( i = 0; (pdev = gs_getdevice(i)) != 0; i++ )
175 printf(" %s", gs_devicename(pdev));
176 }
177 fputs(gs_help2a, stdout);
178 fputs(gs_help2b, stdout);
179 gs_exit(0);
180 case 'I': /* specify search path */
181 gs_lib_paths[gs_lib_count] = arg;
182 gs_lib_count++;
183 set_lib_paths();
184 break;
185 case 'q': /* quiet startup */
186 { ref vnull;
187 quiet = 1;
188 init1();
189 make_null(&vnull);
190 initial_enter_name("QUIET", &vnull);
191 } break;
192 case 'D': /* define name */
193 case 'd':
194 case 'S': /* define name as string */
195 case 's':
196 { char *eqp = strchr(arg, '=');
197 int isd = (sw == 'D' || sw == 'd');
198 ref value;
199 if ( eqp == NULL ) eqp = strchr(arg, '#');
200 /* Initialize the object memory, scanner, and */
201 /* name table now if needed. */
202 init1();
203 if ( eqp == arg )
204 { printf("Usage: -dname, -dname=token, -sname=string\n");
205 gs_exit(1);
206 }
207 if ( eqp == NULL )
208 { if ( isd ) make_null(&value);
209 else make_tasv(&value, t_string, a_read+a_execute,
210 0, bytes, (byte *)"");
211 }
212 else
213 { int code;
214 *eqp++ = 0; /* delimit name */
215 if ( isd )
216 { stream astream;
217 sread_string(&astream,
218 (byte *)eqp, strlen(eqp));
219 code = scan_token(&astream, 0, &value);
220 if ( code )
221 { printf("-dname= must be followed by a valid token\n");
222 gs_exit(1);
223 }
224 }
225 else
226 { int len = strlen(eqp);
227 char *str = gs_malloc((uint)len, 1, "-s");
228 if ( str == 0 )
229 { lprintf("Out of memory!\n");
230 gs_exit(1);
231 }
232 memcpy(str, eqp, len);
233 make_tasv(&value, t_string, a_read+a_execute,
234 len, bytes, (byte *)str);
235 }
236 }
237 /* Enter the name in systemdict */
238 initial_enter_name(arg, &value);
239 break;
240 }
241 case 'g': /* define device geometry */
242 { long width, height;
243 ref value;
244 init1();
245 if ( sscanf(arg, "%ldx%ld", &width, &height) != 2 )
246 { printf("-g must be followed by <width>x<height>\n");
247 gs_exit(1);
248 }
249 make_int(&value, width);
250 initial_enter_name("DEVICEWIDTH", &value);
251 make_int(&value, height);
252 initial_enter_name("DEVICEHEIGHT", &value);
253 break;
254 }
255 case 'M': /* set memory allocation increment */
256 { unsigned msize = 0;
257 sscanf(arg, "%d", &msize);
258 if ( msize <= 0 || msize >= 64 )
259 { printf("-M must be between 1 and 64\n");
260 gs_exit(1);
261 }
262 memory_chunk_size = msize << 10;
263 }
264 break;
265 case 'r': /* define device resolution */
266 { long xres, yres;
267 ref value;
268 init1();
269 switch ( sscanf(arg, "%ldx%ld", &xres, &yres) )
270 {
271 default:
272 printf("-r must be followed by <res> or <xres>x<yres>\n");
273 gs_exit(1);
274 case 1: /* -r<res> */
275 yres = xres;
276 case 2: /* -r<xres>x<yres> */
277 make_int(&value, xres);
278 initial_enter_name("DEVICEXRESOLUTION", &value);
279 make_int(&value, yres);
280 initial_enter_name("DEVICEYRESOLUTION", &value);
281 }
282 break;
283 }
284 }
285 return 0;
286}
287
288/* Define versions of strlen and strcat that insert \ escapes */
289/* before \, (, and ). */
290#define needs_esc(ch) ((ch) == '(' || (ch) == ')' || (ch) == '\\')
291private int
292esc_strlen(const char *str)
293{ int n = strlen(str);
294 const char *p;
295 for ( p = str; *p; p++ ) if ( needs_esc(*p) ) n++;
296 return n;
297}
298private void
299esc_strcat(char *dest, const char *src)
300{ char *d = dest + strlen(dest);
301 const char *p;
302 for ( p = src; *p; p++ )
303 { if ( needs_esc(*p) ) *d++ = '\\';
304 *d++ = *p;
305 }
306 *d = 0;
307}
308
309/* Process file names */
310void
311argproc(char **argp, int index)
312{ runarg(argp, "{", "(", 0);
313}
314private void
315runarg(char **argp, char *pre, char *post, int nstrs)
316{ char *arg = *argp;
317 static char *pex = ")run}execute";
318 int len = strlen(pre) + esc_strlen(arg) + strlen(post) + strlen(pex) + 1;
319 char *line;
320 int i;
321 for ( i = 1; i <= nstrs; i++ )
322 len += esc_strlen(argp[i]) + 2;
323 init2(); /* Finish initialization */
324 line = gs_malloc(len, 1, "argproc");
325 if ( line == 0 )
326 { lprintf("Out of memory!\n");
327 gs_exit(1);
328 }
329 strcpy(line, pre);
330 for ( i = 1; i <= nstrs; i++ )
331 { strcat(line, "(");
332 esc_strcat(line, argp[i]);
333 strcat(line, ")");
334 }
335 strcat(line, post);
336 esc_strcat(line, arg);
337 strcat(line, pex);
338 run_string(line);
339}
340private void
341run_string(char *str)
342{ int code;
343 ref stref;
344 make_tasv(&stref, t_string, a_executable + a_read + a_execute,
345 strlen(str), bytes, (byte *)str);
346 code = gs_interpret(&stref, user_errors);
347 zflush((ref *)0); /* flush stdout */
348 zflushpage((ref *)0); /* force display update */
349 if ( code ) debug_dump_stack(code), gs_exit(2);
350}
351
352private int init1_done = 0, init2_done = 0;
353private void
354init1()
355{ if ( !init1_done )
356 { alloc_init(gs_malloc, gs_free, memory_chunk_size);
357 name_init();
358 obj_init(); /* requires name_init */
359 scan_init(); /* ditto */
360 init1_done = 1;
361 }
362}
363private void
364init2()
365{ init1();
366 if ( !init2_done )
367 { gs_init();
368 zop_init();
369 interp_init(1); /* requires obj_init */
370 op_init(); /* requires obj_init, scan_init */
371 /* Set up the array of additional initialization files. */
372 { ref *ifp = gs_init_file_array;
373 ref ifa;
374 for ( ; ifp->value.bytes != 0; ifp++ )
375 r_set_size(ifp, strlen((const char *)ifp->value.bytes));
376 make_tasv(&ifa, t_array, a_read + a_execute,
377 ifp - gs_init_file_array, refs,
378 gs_init_file_array);
379 initial_enter_name("INITFILES", &ifa);
380 }
381 /* Execute the standard initialization file. */
382 run_file(gs_init_file, user_errors);
383 init2_done = 1;
384 }
385 }
386
387/* Complete the list of library search paths. */
388private void
389set_lib_paths()
390{ const char **ppath = &gs_lib_paths[gs_lib_count];
391 if ( gs_lib_env_path != 0 ) *ppath++ = gs_lib_env_path;
392 if ( gs_lib_default_path != 0 ) *ppath++ = gs_lib_default_path;
393 *ppath = 0;
394}
395
396/* Open and execute a file */
397private int
398run_open(const char *file_name, ref *pfile)
399{
400#define maxfn 200
401 byte fn[maxfn];
402 uint len;
403 return lib_file_open(file_name, strlen(file_name), fn, maxfn,
404 &len, pfile);
405}
406private void
407run_file(const char *file_name, int user_errors)
408{ ref initial_file;
409 int code;
410 if ( run_open(file_name, &initial_file) < 0 )
411 { eprintf1("Can't find initialization file %s\n", file_name);
412 gs_exit(1);
413 }
414 r_set_attrs(&initial_file, a_execute + a_executable);
415 code = gs_interpret(&initial_file, user_errors);
416 if ( code < 0 )
417 debug_dump_stack(code), gs_exit(1);
418}
419
420/* Debugging code */
421extern void debug_print_ref(P1(ref *));
422extern void debug_dump_refs(P3(ref *, uint, char *));
423extern ref error_object;
424
425/* Dump the stacks after interpretation */
426private void
427debug_dump_stack(int code)
428{ zflush(osp); /* force out buffered output */
429 dprintf1("\nUnexpected interpreter error %d!\nError object: ", code);
430 debug_print_ref(&error_object);
431 dputc('\n');
432 debug_dump_refs(osbot, osp + 1 - osbot, "Operand stack");
433 debug_dump_refs(esbot, esp + 1 - esbot, "Execution stack");
434}