/* Copyright (C) 1992, 1994, 1996 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gserver.c,v 1.2.6.1.2.1 2003/01/17 00:49:02 giles Exp $ */ /* Server front end for Ghostscript, replacing gs.c. */ #include "memory_.h" #include "string_.h" #include "ghost.h" #include "imemory.h" /* for iutil.h */ #include "interp.h" /* for gs_interp_reset */ #include "iutil.h" /* for obj_cvs */ #include "main.h" #include "ostack.h" #include "store.h" #include "gspaint.h" /* for gs_erasepage */ /* * This file provides a very simple procedural interface to the Ghostscript * PostScript/PDF language interpreter, with a rudimentary provision for * saving and restoring state around "jobs". * See below for the descriptions of individual procedures. * * All routines in this file return an integer value which is 0 if the * routine completed successfully, non-0 if an error occurred. */ /* ------ Public interface ------ */ /* * Initialize Ghostscript. fno_stdin, fno_stdout, and fno_stderr are * file handles that Ghostscript will use in place of stdin, stdout, * and stderr respectively. This routine should be called once at the * beginning of execution, and not after that. * * This routine establishes a "baseline" initial state for Ghostscript, * which includes reading in the standard Ghostscript initialization files * such as gs_init.ps and gs_fonts.ps. This baseline is always used as the * starting state for gs_server_run_string and gs_server_run_files, unless * modified as described below. * * This routine 'opens' the default driver. */ int gs_server_initialize(P4(int fno_stdin, int fno_stdout, int fno_stderr, const char *init_str)); /* * Execute a string containing PostScript code. The effects of this code * do modify the baseline state for future calls of ...run_string and * ...run_files. There are four cases of return values: * value = 0: normal return. * value = e_Quit: the PostScript code executed a `quit'. * value = e_Fatal: the PostScript code encountered a fatal error. * *exit_code_ptr holds the C exit code. * other value: the PostScript code encountered a PostScript error * while processing another error, or some other fatal * PostScript error. * * errstr points to a string area of length errstr_max_len for reporting * the PostScript object causing the error. In the case of an error return, * the characters from errstr[0] through errstr[*errstr_len_ptr-1] will * contain a representation of the error object. *errstr_len_ptr will not * exceed errstr_max_len. */ int gs_server_run_string(P5(const char *str, int *exit_code_ptr, char *errstr, int errstr_max_len, int *errstr_len_ptr)); /* * Run a sequence of files containing PostScript code. If permanent is 0, * the files do not affect the baseline state; if permanent is 1, they do * affect the baseline state, just like ...run_string. The returned value, * exit code, and error string are the same as for gs_server_run_string. * * If permanent is 0, the output page buffer is cleared before running the * first file (equivalent to `erasepage'). */ int gs_server_run_files(P6(const char **file_names, int permanent, int *exit_code_ptr, char *errstr, int errstr_max_len, int *errstr_len_ptr)); /* * Terminate Ghostscript. Ghostscript will release all memory and close * all files it has opened, including the ones referenced by fno_stdin, * fno_stdout, and fno_stderr. * * This routine 'closes' the default driver. */ int gs_server_terminate(P0()); /* ------ Example of use ------ */ /* To run this example, change the 0 to 1 in the following line. */ #if 0 /* * This example predefines the name fubar, prints out its value, * and then renders the golfer art file supplied with Ghostscript. */ #include #include int main(int argc, char *argv[]) { int code, exit_code; #define emax 50 char errstr[emax + 1]; int errlen; static const char *fnames[] = {"golfer.ps", 0}; FILE *cin = fopen("stdin.tmp", "w+"); int sout = open("stdout.tmp", O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); int serr = open("stderr.tmp", O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); code = gs_server_initialize(fileno(cin), sout, serr, "/fubar 42 def"); fprintf(stdout, "init: code %d\n", code); if (code < 0) goto x; code = gs_server_run_string("fubar == flush", &exit_code, errstr, emax, &errlen); fprintf(stdout, "print: code %d\n", code); if (code < 0) goto x; code = gs_server_run_files(fnames, 0, &exit_code, errstr, emax, &errlen); fprintf(stdout, "golfer: code %d\n", code); if (code < 0) goto x; errlen = 0; code = gs_server_run_string("fubar 0 div", &exit_code, errstr, emax, &errlen); errstr[errlen] = 0; fprintf(stdout, "0 div: code %d object %s\n", code, errstr); errlen = 0; code = gs_server_run_string("xxx", &exit_code, errstr, emax, &errlen); errstr[errlen] = 0; fprintf(stdout, "undef: code %d object %s\n", code, errstr); x:code = gs_server_terminate(); fprintf(stdout, "end: code %d\n", code); fflush(stdout); close(serr); close(sout); fclose(cin); return code; } #endif /* ------ Private definitions ------ */ /* Forward references */ private int job_begin(P0()); private int job_end(P0()); private void errstr_report(P4(ref *, char *, int, int *)); /* ------ Public routines ------ */ /* Initialize Ghostscript. */ int gs_server_initialize(int fno_stdin, int fno_stdout, int fno_stderr, const char *init_str) { int code, exit_code; /* discard exit_code for now */ int errstr_len; /* discard */ FILE *c_stdin, *c_stdout, *c_stderr; /* Establish C-compatible files for stdout and stderr. */ c_stdin = fdopen(fno_stdin, "r"); if (c_stdin == NULL) return -1; c_stdout = fdopen(fno_stdout, "w"); if (c_stdout == NULL) return -1; c_stderr = fdopen(fno_stderr, "w"); if (c_stderr == NULL) return -1; /* Initialize the Ghostscript interpreter. */ gs_init0(c_stdin, c_stdout, c_stderr, 0); gs_init1(); gs_init2(); code = gs_server_run_string("/QUIET true def /NOPAUSE true def", &exit_code, (char *)0, 0, &errstr_len); if (code < 0) return code; return (init_str == NULL ? 0 : gs_server_run_string(init_str, &exit_code, (char *)0, 0, &errstr_len)); } /* Run a string. */ int gs_server_run_string(const char *str, int *exit_code_ptr, char *errstr, int errstr_max_len, int *errstr_len_ptr) { ref error_object; int code; make_tasv(&error_object, t_string, 0, 0, bytes, 0); code = gs_run_string(str, 0, exit_code_ptr, &error_object); if (code < 0) errstr_report(&error_object, errstr, errstr_max_len, errstr_len_ptr); return code; } /* Run files. */ 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) { int code = 0; ref error_object; const char **pfn; if (!permanent) job_begin(); make_tasv(&error_object, t_string, 0, 0, bytes, 0); for (pfn = file_names; *pfn != NULL && code == 0; pfn++) code = gs_run_file(*pfn, 0, exit_code_ptr, &error_object); if (!permanent) job_end(); if (code < 0) errstr_report(&error_object, errstr, errstr_max_len, errstr_len_ptr); return code; } /* Terminate Ghostscript. */ int gs_server_terminate() { gs_finit(0, 0); return 0; } /* ------ Private routines ------ */ private ref job_save; /* 'save' object for baseline state */ extern int zsave(P1(os_ptr)), zrestore(P1(os_ptr)); /* Start a 'job' by restoring the baseline state. */ private int job_begin() { int code; /* Ghostscript doesn't provide erasepage as an operator. */ /* However, we can get the same effect by calling gs_erasepage. */ extern gs_state *igs; if ((code = gs_erasepage(igs)) < 0) return code; code = zsave(osp); if (code == 0) job_save = *osp--; return code; } /* End a 'job'. */ private int job_end() { gs_interp_reset(); *++osp = job_save; return zrestore(osp); } /* Produce a printable representation of an error object. */ private void errstr_report(ref * perror_object, char *errstr, int errstr_max_len, int *errstr_len_ptr) { int code = obj_cvs(perror_object, (byte *) errstr, (uint) errstr_max_len, (uint *) errstr_len_ptr, false); if (code < 0) { const char *ustr = "[unprintable]"; int len = min(strlen(ustr), errstr_max_len); memcpy(errstr, ustr, len); *errstr_len_ptr = len; } }