1 /* Copyright (C) 1992, 1994, 1996 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gserver.c,v 1.2.6.1.2.1 2003/01/17 00:49:02 giles Exp $ */
20 /* Server front end for Ghostscript, replacing gs.c. */
21 #include "memory_.h"
22 #include "string_.h"
23 #include "ghost.h"
24 #include "imemory.h" /* for iutil.h */
25 #include "interp.h" /* for gs_interp_reset */
26 #include "iutil.h" /* for obj_cvs */
27 #include "main.h"
28 #include "ostack.h"
29 #include "store.h"
30 #include "gspaint.h" /* for gs_erasepage */
31
32 /*
33 * This file provides a very simple procedural interface to the Ghostscript
34 * PostScript/PDF language interpreter, with a rudimentary provision for
35 * saving and restoring state around "jobs".
36 * See below for the descriptions of individual procedures.
37 *
38 * All routines in this file return an integer value which is 0 if the
39 * routine completed successfully, non-0 if an error occurred.
40 */
41
42 /* ------ Public interface ------ */
43
44 /*
45 * Initialize Ghostscript. fno_stdin, fno_stdout, and fno_stderr are
46 * file handles that Ghostscript will use in place of stdin, stdout,
47 * and stderr respectively. This routine should be called once at the
48 * beginning of execution, and not after that.
49 *
50 * This routine establishes a "baseline" initial state for Ghostscript,
51 * which includes reading in the standard Ghostscript initialization files
52 * such as gs_init.ps and gs_fonts.ps. This baseline is always used as the
53 * starting state for gs_server_run_string and gs_server_run_files, unless
54 * modified as described below.
55 *
56 * This routine 'opens' the default driver.
57 */
58
59 int gs_server_initialize(P4(int fno_stdin, int fno_stdout, int fno_stderr,
60 const char *init_str));
61
62 /*
63 * Execute a string containing PostScript code. The effects of this code
64 * do modify the baseline state for future calls of ...run_string and
65 * ...run_files. There are four cases of return values:
66 * value = 0: normal return.
67 * value = e_Quit: the PostScript code executed a `quit'.
68 * value = e_Fatal: the PostScript code encountered a fatal error.
69 * *exit_code_ptr holds the C exit code.
70 * other value: the PostScript code encountered a PostScript error
71 * while processing another error, or some other fatal
72 * PostScript error.
73 *
74 * errstr points to a string area of length errstr_max_len for reporting
75 * the PostScript object causing the error. In the case of an error return,
76 * the characters from errstr[0] through errstr[*errstr_len_ptr-1] will
77 * contain a representation of the error object. *errstr_len_ptr will not
78 * exceed errstr_max_len.
79 */
80
81 int gs_server_run_string(P5(const char *str, int *exit_code_ptr,
82 char *errstr, int errstr_max_len,
83 int *errstr_len_ptr));
84
85 /*
86 * Run a sequence of files containing PostScript code. If permanent is 0,
87 * the files do not affect the baseline state; if permanent is 1, they do
88 * affect the baseline state, just like ...run_string. The returned value,
89 * exit code, and error string are the same as for gs_server_run_string.
90 *
91 * If permanent is 0, the output page buffer is cleared before running the
92 * first file (equivalent to `erasepage').
93 */
94
95 int gs_server_run_files(P6(const char **file_names, int permanent,
96 int *exit_code_ptr, char *errstr,
97 int errstr_max_len, int *errstr_len_ptr));
98
99 /*
100 * Terminate Ghostscript. Ghostscript will release all memory and close
101 * all files it has opened, including the ones referenced by fno_stdin,
102 * fno_stdout, and fno_stderr.
103 *
104 * This routine 'closes' the default driver.
105 */
106
107 int gs_server_terminate(P0());
108
109 /* ------ Example of use ------ */
110
111 /* To run this example, change the 0 to 1 in the following line. */
112 #if 0
113
114 /*
115 * This example predefines the name fubar, prints out its value,
116 * and then renders the golfer art file supplied with Ghostscript.
117 */
118
119 #include <fcntl.h>
120 #include <sys/stat.h>
121 int
122 main(int argc, char *argv[])
123 {
124 int code, exit_code;
125
126 #define emax 50
127 char errstr[emax + 1];
128 int errlen;
129 static const char *fnames[] =
130 {"golfer.ps", 0};
131 FILE *cin = fopen("stdin.tmp", "w+");
132 int sout = open("stdout.tmp", O_WRONLY | O_CREAT | O_TRUNC,
133 S_IREAD | S_IWRITE);
134 int serr = open("stderr.tmp", O_WRONLY | O_CREAT | O_TRUNC,
135 S_IREAD | S_IWRITE);
136
137 code = gs_server_initialize(fileno(cin), sout, serr,
138 "/fubar 42 def");
139 fprintf(stdout, "init: code %d\n", code);
140 if (code < 0)
141 goto x;
142 code = gs_server_run_string("fubar == flush", &exit_code,
143 errstr, emax, &errlen);
144 fprintf(stdout, "print: code %d\n", code);
145 if (code < 0)
146 goto x;
147 code = gs_server_run_files(fnames, 0, &exit_code,
148 errstr, emax, &errlen);
149 fprintf(stdout, "golfer: code %d\n", code);
150 if (code < 0)
151 goto x;
152 errlen = 0;
153 code = gs_server_run_string("fubar 0 div", &exit_code,
154 errstr, emax, &errlen);
155 errstr[errlen] = 0;
156 fprintf(stdout, "0 div: code %d object %s\n", code, errstr);
157 errlen = 0;
158 code = gs_server_run_string("xxx", &exit_code,
159 errstr, emax, &errlen);
160 errstr[errlen] = 0;
161 fprintf(stdout, "undef: code %d object %s\n", code, errstr);
162 x:code = gs_server_terminate();
163 fprintf(stdout, "end: code %d\n", code);
164 fflush(stdout);
165 close(serr);
166 close(sout);
167 fclose(cin);
168 return code;
169 }
170
171 #endif
172
173 /* ------ Private definitions ------ */
174
175 /* Forward references */
176 private int job_begin(P0());
177 private int job_end(P0());
178 private void errstr_report(P4(ref *, char *, int, int *));
179
180 /* ------ Public routines ------ */
181
182 /* Initialize Ghostscript. */
183
184 int
gs_server_initialize(int fno_stdin,int fno_stdout,int fno_stderr,const char * init_str)185 gs_server_initialize(int fno_stdin, int fno_stdout, int fno_stderr,
186 const char *init_str)
187 {
188 int code, exit_code; /* discard exit_code for now */
189 int errstr_len; /* discard */
190 FILE *c_stdin, *c_stdout, *c_stderr;
191
192 /* Establish C-compatible files for stdout and stderr. */
193 c_stdin = fdopen(fno_stdin, "r");
194 if (c_stdin == NULL)
195 return -1;
196 c_stdout = fdopen(fno_stdout, "w");
197 if (c_stdout == NULL)
198 return -1;
199 c_stderr = fdopen(fno_stderr, "w");
200 if (c_stderr == NULL)
201 return -1;
202 /* Initialize the Ghostscript interpreter. */
203 gs_init0(c_stdin, c_stdout, c_stderr, 0);
204 gs_init1();
205 gs_init2();
206 code = gs_server_run_string("/QUIET true def /NOPAUSE true def",
207 &exit_code,
208 (char *)0, 0, &errstr_len);
209 if (code < 0)
210 return code;
211 return (init_str == NULL ? 0 :
212 gs_server_run_string(init_str, &exit_code,
213 (char *)0, 0, &errstr_len));
214 }
215
216 /* Run a string. */
217
218 int
gs_server_run_string(const char * str,int * exit_code_ptr,char * errstr,int errstr_max_len,int * errstr_len_ptr)219 gs_server_run_string(const char *str, int *exit_code_ptr,
220 char *errstr, int errstr_max_len, int *errstr_len_ptr)
221 {
222 ref error_object;
223 int code;
224
225 make_tasv(&error_object, t_string, 0, 0, bytes, 0);
226 code = gs_run_string(str, 0, exit_code_ptr, &error_object);
227 if (code < 0)
228 errstr_report(&error_object, errstr, errstr_max_len,
229 errstr_len_ptr);
230 return code;
231 }
232
233 /* Run files. */
234
235 int
gs_server_run_files(const char ** file_names,int permanent,int * exit_code_ptr,char * errstr,int errstr_max_len,int * errstr_len_ptr)236 gs_server_run_files(const char **file_names, int permanent,
237 int *exit_code_ptr, char *errstr, int errstr_max_len, int *errstr_len_ptr)
238 {
239 int code = 0;
240 ref error_object;
241 const char **pfn;
242
243 if (!permanent)
244 job_begin();
245 make_tasv(&error_object, t_string, 0, 0, bytes, 0);
246 for (pfn = file_names; *pfn != NULL && code == 0; pfn++)
247 code = gs_run_file(*pfn, 0, exit_code_ptr, &error_object);
248 if (!permanent)
249 job_end();
250 if (code < 0)
251 errstr_report(&error_object, errstr, errstr_max_len,
252 errstr_len_ptr);
253 return code;
254 }
255
256 /* Terminate Ghostscript. */
257
258 int
gs_server_terminate()259 gs_server_terminate()
260 {
261 gs_finit(0, 0);
262 return 0;
263 }
264
265 /* ------ Private routines ------ */
266
267 private ref job_save; /* 'save' object for baseline state */
268
269 extern int zsave(P1(os_ptr)), zrestore(P1(os_ptr));
270
271 /* Start a 'job' by restoring the baseline state. */
272
273 private int
job_begin()274 job_begin()
275 {
276 int code;
277
278 /* Ghostscript doesn't provide erasepage as an operator. */
279 /* However, we can get the same effect by calling gs_erasepage. */
280 extern gs_state *igs;
281
282 if ((code = gs_erasepage(igs)) < 0)
283 return code;
284 code = zsave(osp);
285 if (code == 0)
286 job_save = *osp--;
287 return code;
288 }
289
290 /* End a 'job'. */
291
292 private int
job_end()293 job_end()
294 {
295 gs_interp_reset();
296 *++osp = job_save;
297 return zrestore(osp);
298 }
299
300 /* Produce a printable representation of an error object. */
301
302 private void
errstr_report(ref * perror_object,char * errstr,int errstr_max_len,int * errstr_len_ptr)303 errstr_report(ref * perror_object, char *errstr, int errstr_max_len,
304 int *errstr_len_ptr)
305 {
306 int code = obj_cvs(perror_object, (byte *) errstr,
307 (uint) errstr_max_len, (uint *) errstr_len_ptr,
308 false);
309
310 if (code < 0) {
311 const char *ustr = "[unprintable]";
312 int len = min(strlen(ustr), errstr_max_len);
313
314 memcpy(errstr, ustr, len);
315 *errstr_len_ptr = len;
316 }
317 }
318