"Fossies" - the Fresh Open Source Software Archive

Member "foomatic-filters-4.0-20160212/postscript.c" (12 Feb 2016, 65069 Bytes) of package /linux/misc/foomatic-filters-4.0-20160212.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "postscript.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.0.17_vs_4.0-20160212.

    1 /* postscript.c
    2  *
    3  * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
    4  * Copyright (C) 2008 Lars Uebernickel <larsuebernickel@gmx.de>
    5  *
    6  * This file is part of foomatic-rip.
    7  *
    8  * Foomatic-rip is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
   10  * the Free Software Foundation; either version 2 of the License, or
   11  * (at your option) any later version.
   12  *
   13  * Foomatic-rip is distributed in the hope that it will be useful, but
   14  * WITHOUT ANY WARRANTY; without even the implied warranty of
   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16  * General Public License for more details.
   17  *
   18  * You should have received a copy of the GNU Lesser General Public
   19  * License along with this library; if not, write to the
   20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   21  * Boston, MA 02111-1307, USA.
   22  */
   23 
   24 #include "foomaticrip.h"
   25 #include "util.h"
   26 #include "options.h"
   27 #include "fileconverter.h"
   28 #include "renderer.h"
   29 #include "process.h"
   30 
   31 #include <errno.h>
   32 #include <unistd.h>
   33 #include <ctype.h>
   34 #include <stdlib.h>
   35 
   36 void get_renderer_handle(const dstr_t *prepend, FILE **fd, pid_t *pid);
   37 int close_renderer_handle(FILE *rendererhandle, pid_t rendererpid);
   38 
   39 #define LT_BEGIN_FEATURE 1
   40 #define LT_FOOMATIC_RIP_OPTION_SETTING 2
   41 int line_type(const char *line)
   42 {
   43     const char *p;
   44     if (startswith(line, "%%BeginFeature:"))
   45         return LT_BEGIN_FEATURE;
   46     p = line;
   47     while (*p && isspace(*p)) p++;
   48     if (!startswith(p, "%%"))
   49         return 0;
   50     p += 2;
   51     while (*p && isspace(*p)) p++;
   52     if (startswith(p, "FoomaticRIPOptionSetting:"))
   53         return LT_FOOMATIC_RIP_OPTION_SETTING;
   54     return 0;
   55 }
   56 
   57 
   58 /*  Next, examine the PostScript job for traces of command-line and
   59     JCL options. PPD-aware applications and spoolers stuff option
   60     settings directly into the file, they do not necessarily send
   61     PPD options by the command line. Also stuff in PostScript code
   62     to apply option settings given by the command line and to set
   63     the defaults given in the PPD file.
   64 
   65     Examination strategy: read lines from STDIN until the first
   66     %%Page: comment appears and save them as @psheader. This is the
   67     page-independent header part of the PostScript file. The
   68     PostScript interpreter (renderer) must execute this part once
   69     before rendering any assortment of pages. Then pages can be
   70     printed in any arbitrary selection or order. All option
   71     settings we find here will be collected in the default option
   72     set for the RIP command line.
   73 
   74     Now the pages will be read and sent to the renderer, one after
   75     the other. Every page is read into memory until the
   76     %%EndPageSetup comment appears (or a certain amount of lines was
   77     read). So we can get option settings only valid for this
   78     page. If we have such settings we set them in the modified
   79     command set for this page.
   80 
   81     If the renderer is not running yet (first page) we start it with
   82     the command line built from the current modified command set and
   83     send the first page to it, in the end we leave the renderer
   84     running and keep input and output pipes open, so that it can
   85     accept further pages. If the renderer is still running from
   86     the previous page and the current modified command set is the
   87     same as the one for the previous page, we send the page. If
   88     the command set is different, we close the renderer, re-start
   89     it with the command line built from the new modified command
   90     set, send the header again, and then the page.
   91 
   92     After the last page the trailer (%%Trailer) is sent.
   93 
   94     The output pipe of this program stays open all the time so that
   95     the spooler does not assume that the job has finished when the
   96     renderer is re-started.
   97 
   98     Non DSC-conforming documents will be read until a certain line
   99     number is reached. Command line or JCL options inserted later
  100     will be ignored.
  101 
  102     If options are implemented by PostScript code supposed to be
  103     stuffed into the job's PostScript data we stuff the code for all
  104     these options into our job data, So all default settings made in
  105     the PPD file (the user can have edited the PPD file to change
  106     them) are taken care of and command line options get also
  107     applied. To give priority to settings made by applications we
  108     insert the options's code in the beginnings of their respective
  109     sections, so that sommething, which is already inserted, gets
  110     executed after our code. Missing sections are automatically
  111     created. In non-DSC-conforming files we insert the option code
  112     in the beginning of the file. This is the same policy as used by
  113     the "pstops" filter of CUPS.
  114 
  115     If CUPS is the spooler, the option settings were already
  116     inserted by the "pstops" filter, so we don't insert them
  117     again. The only thing we do is correcting settings of numerical
  118     options when they were set to a value not available as choice in
  119     the PPD file, As "pstops" does not support "real" numerical
  120     options, it sees these settings as an invalid choice and stays
  121     with the default setting. In this case we correct the setting in
  122     the first occurence of the option's code, as this one is the one
  123     added by CUPS, later occurences come from applications and
  124     should not be touched.
  125 
  126     If the input is not PostScript (if there is no "%!" after
  127     $maxlinestopsstart lines) a file conversion filter will
  128     automatically be applied to the incoming data, so that we will
  129     process the resulting PostScript here. This way we have always
  130     PostScript data here and so we can apply the printer/driver
  131     features described in the PPD file.
  132 
  133     Supported file conversion filters are "a2ps", "enscript",
  134     "mpage", "paps", and spooler-specific filters. All filters
  135     convert plain text to PostScript, "a2ps" also other formats.
  136     The conversion filter is always used when one prints the
  137     documentation pages, as they are created as plain text,
  138     when CUPS is the spooler "pstops" is executed after the
  139     filter so that the default option settings from the PPD file
  140     and CUPS-specific options as N-up get applied. On regular
  141     printouts one gets always PostScript when CUPS or PPR is
  142     the spooler, so the filter is only used for regular
  143     printouts under LPD, LPRng, GNUlpr or without spooler.
  144 */
  145 
  146 /* PostScript sections */
  147 #define PS_SECTION_JCLSETUP 1
  148 #define PS_SECTION_PROLOG 2
  149 #define PS_SECTION_SETUP 3
  150 #define PS_SECTION_PAGESETUP 4
  151 
  152 #define MAX_NON_DSC_LINES_IN_HEADER 1000
  153 #define MAX_LINES_FOR_PAGE_OPTIONS 200
  154 
  155 typedef struct {
  156     size_t pos;
  157 
  158     FILE *file;
  159     const char *alreadyread;
  160     size_t len;
  161 } stream_t;
  162 
  163 void _print_ps(stream_t *stream);
  164 
  165 int stream_next_line(dstr_t *line, stream_t *s)
  166 {
  167     int c;
  168     size_t cnt = 0;
  169 
  170     dstrclear(line);
  171     while (s->pos < s->len) {
  172         c = s->alreadyread[s->pos++];
  173         dstrputc(line, c);
  174         cnt++;
  175         if (c == '\n')
  176             return cnt;
  177     }
  178 
  179     while ((c = fgetc(s->file)) != EOF) {
  180         dstrputc(line, c);
  181         cnt++;
  182         if (c == '\n')
  183             return cnt;
  184     }
  185     return cnt;
  186 }
  187 
  188 int print_ps(FILE *file, const char *alreadyread, size_t len, const char *filename)
  189 {
  190     stream_t stream;
  191 
  192     if (file != stdin && (dup2(fileno(file), fileno(stdin)) < 0)) {
  193         _log("Could not dup %s to stdin.\n", filename);
  194         return 0;
  195     }
  196 
  197     stream.pos = 0;
  198     stream.file = stdin;
  199     stream.alreadyread = alreadyread;
  200     stream.len = len;
  201     _print_ps(&stream);
  202     return 1;
  203 }
  204 
  205 void _print_ps(stream_t *stream)
  206 {
  207     char *p;
  208 
  209     int maxlines = 1000;    /* Maximum number of lines to be read  when the
  210                                documenent is not  DSC-conforming.
  211                                "$maxlines = 0"  means that all will be read and
  212                                examined. If it is  discovered that the input
  213                                file  is DSC-conforming, this will  be set to 0. */
  214 
  215     int maxlinestopsstart = 200;    /* That many lines are allowed until the
  216                                       "%!" indicating PS comes. These
  217                                       additional lines in the
  218                                       beginning are usually JCL
  219                                       commands. The lines will be
  220                                       ignored by our parsing but
  221                                       passed through. */
  222 
  223     int printprevpage = 0;  /* We set this when encountering "%%Page:" and the
  224                                previous page is not printed yet. Then it will
  225                                be printed and the new page will be prepared in
  226                                the next run of the loop (we don't read a new
  227                                line and don't increase the $linect then). */
  228 
  229     int linect = 0;         /* how many lines have we examined */
  230     int nonpslines = 0;     /* lines before "%!" found yet. */
  231     int more_stuff = 1;     /* there is more stuff in stdin */
  232     int saved = 0;          /* DSC line not precessed yet */
  233     int isdscjob = 0;       /* is the job dsc conforming */
  234     int inheader = 1;       /* Are we still in the header, before first
  235                                "%%Page:" comment= */
  236 
  237     int optionsalsointoheader = 0; /* 1: We are in a "%%BeginSetup...
  238                                     %%EndSetup" section after the first
  239                                     "%%Page:..." line (OpenOffice.org
  240                                     does this and intends the options here
  241                                     apply to the whole document and not
  242                                     only to the current page). We have to
  243                                     add all lines also to the end of the
  244                                     @psheader now and we have to set
  245                                     non-PostScript options also in the
  246                                     "header" optionset. 0: otherwise. */
  247 
  248     int insertoptions = 1;  /* If we find out that a file with a DSC magic
  249                                string ("%!PS-Adobe-") is not really DSC-
  250                                conforming, we insert the options directly
  251                                after the line with the magic string. We use
  252                                this variable to store the number of the line
  253                                with the magic string */
  254 
  255     int prologfound = 0;    /* Did we find the
  256                                "%%BeginProlog...%%EndProlog" section? */
  257     int setupfound = 0;     /* Did we find the
  258                                %%BeginSetup...%%EndSetup" section? */
  259     int pagesetupfound = 0; /* special page setup handling needed */
  260 
  261     int inprolog = 0;       /* We are between "%%BeginProlog" and "%%EndProlog" */
  262     int insetup = 0;        /* We are between "%%BeginSetup" and "%%EndSetup" */
  263     int infeature = 0;      /* We are between "%%BeginFeature" and "%%EndFeature" */
  264 
  265     int optionreplaced = 0; /* Will be set to 1 when we are in an
  266                                option ("%%BeginFeature...
  267                                %%EndFeature") which we have replaced. */
  268 
  269     int postscriptsection = PS_SECTION_JCLSETUP; /* In which section of the PostScript file
  270                                                    are we currently ? */
  271 
  272     int nondsclines = 0;    /* Number of subsequent lines found which are at a
  273                                non-DSC-conforming place, between the sections
  274                                of the header.*/
  275 
  276     int nestinglevel = 0;   /* Are we in the main document (0) or in an
  277                                embedded document bracketed by "%%BeginDocument"
  278                                and "%%EndDocument" (>0) We do not parse the
  279                                PostScript in an embedded document. */
  280 
  281     int inpageheader = 0;   /* Are we in the header of a page,
  282                                between "%%BeginPageSetup" and
  283                                "%%EndPageSetup" (1) or not (0). */
  284 
  285     int passthru = 0;       /* 0: write data into psfifo,
  286                                1: pass data directly to the renderer */
  287 
  288     int lastpassthru = 0;   /* State of 'passthru' in previous line
  289                                (to allow debug output when $passthru
  290                                switches. */
  291 
  292     int ignorepageheader = 0; /* Will be set to 1 as soon as active
  293                                  code (not between "%%BeginPageSetup"
  294                                  and "%%EndPageSetup") appears after a
  295                                  "%%Page:" comment. In this case
  296                                  "%%BeginPageSetup" and
  297                                  "%%EndPageSetup" is not allowed any
  298                                  more on this page and will be ignored.
  299                                  Will be set to 0 when a new "%%Page:"
  300                                  comment appears. */
  301 
  302     int optset = optionset("header"); /* Where do the option settings which
  303                                          we have found go? */
  304 
  305     /* current line */
  306     dstr_t *line = create_dstr();
  307 
  308     dstr_t *onelinebefore = create_dstr();
  309     dstr_t *twolinesbefore = create_dstr();
  310 
  311     /* The header of the PostScript file, to be send after each start of the renderer */
  312     dstr_t *psheader = create_dstr();
  313 
  314     /* The input FIFO, data which we have pulled from stdin for examination,
  315        but not send to the renderer yet */
  316     dstr_t *psfifo = create_dstr();
  317 
  318     FILE *fileconverter_handle = NULL; /* File handle to converter process */
  319     pid_t fileconverter_pid = 0;  /* PID of the fileconverter process */
  320 
  321     int ignoreline;
  322 
  323     int ooo110 = 0;         /* Flag to work around an application bug */
  324 
  325     int currentpage = 0;   /* The page which we are currently printing */
  326 
  327     option_t *o;
  328     const char *val;
  329 
  330     int linetype;
  331 
  332     dstr_t *linesafterlastbeginfeature = create_dstr(); /* All codelines after the last "%%BeginFeature" */
  333 
  334     char optionname [128];
  335     char value [128];
  336     int fromcomposite = 0;
  337 
  338     dstr_t *pdest;
  339 
  340     double width, height;
  341 
  342     pid_t rendererpid = 0;
  343     FILE *rendererhandle = NULL;
  344 
  345     int retval;
  346 
  347     dstr_t *tmp = create_dstr();
  348     jobhasjcl = 0;
  349 
  350     /* We do not parse the PostScript to find Foomatic options, we check
  351         only whether we have PostScript. */
  352     if (dontparse)
  353         maxlines = 1;
  354 
  355     _log("Reading PostScript input ...\n");
  356 
  357     do {
  358         ignoreline = 0;
  359 
  360         if (printprevpage || saved || stream_next_line(line, stream)) {
  361             saved = 0;
  362             if (linect == nonpslines) {
  363                 /* In the beginning should be the postscript leader,
  364                    sometimes after some JCL commands */
  365                 if ( !(line->data[0] == '%' && line->data[1] == '!') &&
  366                      !(line->data[1] == '%' && line->data[2] == '!')) /* There can be a Windows control character before "%!" */
  367                 {
  368                     nonpslines++;
  369                     if (maxlines == nonpslines)
  370                         maxlines ++;
  371                     jobhasjcl = 1;
  372 
  373                     if (nonpslines > maxlinestopsstart) {
  374                         /* This is not a PostScript job, we must convert it */
  375                         _log("Job does not start with \"%%!\", is it Postscript?\n"
  376                              "Starting file converter\n");
  377 
  378                         /* Reset all variables but conserve the data which we have already read */
  379                         jobhasjcl = 0;
  380                         linect = 0;
  381                         nonpslines = 1; /* Take into account that the line of this run of the loop
  382                                         will be put into @psheader, so the first line read by
  383                                         the file converter is already the second line */
  384                         maxlines = 1001;
  385 
  386                         dstrclear(onelinebefore);
  387                         dstrclear(twolinesbefore);
  388 
  389                         dstrcpyf(tmp, "%s%s%s", psheader, psfifo, line);
  390                         dstrclear(psheader);
  391                         dstrclear(psfifo);
  392                         dstrclear(line);
  393 
  394                         /* Start the file conversion filter */
  395                         if (!fileconverter_pid)
  396                             get_fileconverter_handle(tmp->data, &fileconverter_handle, &fileconverter_pid);
  397                         else
  398                             rip_die(EXIT_JOBERR, "File conversion filter probably crashed\n");
  399 
  400                         /* Read the further data from the file converter and not from STDIN */
  401                         if (close(fileno(stdin)) == -1 && errno != ESPIPE)
  402                             rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Couldn't close STDIN\n");
  403                         if (dup2(fileno(stdin), fileno(fileconverter_handle)) == -1)
  404                             rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Couldn't dup fileconverter_handle\n");
  405                     }
  406                 }
  407                 else {
  408                     /* Do we have a DSC-conforming document? */
  409                     if ((line->data[0] == '%' && startswith(line->data, "%!PS-Adobe-")) ||
  410                         (line->data[1] == '%' && startswith(line->data, "%!PS-Adobe-")))
  411                     {
  412                         /* Do not stop parsing the document */
  413                         if (!dontparse) {
  414                             maxlines = 0;
  415                             isdscjob = 1;
  416                             insertoptions = linect + 1;
  417                             /* We have written into psfifo before, now we continue in
  418                                psheader and move over the data which is already in psfifo */
  419                             dstrcat(psheader, psfifo->data);
  420                             dstrclear(psfifo);
  421                         }
  422                         _log("--> This document is DSC-conforming!\n");
  423                     }
  424                     else {
  425                         /* Job is not DSC-conforming, stick in all PostScript
  426                            option settings in the beginning */
  427                         append_prolog_section(line, optset, 1);
  428                         append_setup_section(line, optset, 1);
  429                         append_page_setup_section(line, optset, 1);
  430                         prologfound = 1;
  431                         setupfound = 1;
  432                         pagesetupfound = 1;
  433                     }
  434                 }
  435             }
  436             else {
  437                 if (startswith(line->data, "%")) {
  438                     if (startswith(line->data, "%%BeginDocument")) {
  439                         /* Beginning of an embedded document
  440                         Note that Adobe Acrobat has a bug and so uses
  441                         "%%BeginDocument " instead of "%%BeginDocument:" */
  442                         nestinglevel++;
  443                         _log("Embedded document, nesting level now: %d\n", nestinglevel);
  444                     }
  445                     else if (nestinglevel > 0 && startswith(line->data, "%%EndDocument")) {
  446                         /* End of an embedded document */
  447                         nestinglevel--;
  448                         _log("End of embedded document, nesting level now: %d\n", nestinglevel);
  449                     }
  450                     else if (nestinglevel == 0 && startswith(line->data, "%%Creator")) {
  451                         /* Here we set flags to treat particular bugs of the
  452                         PostScript produced by certain applications */
  453                         p = strstr(line->data, "%%Creator") + 9;
  454                         while (*p && (isspace(*p) || *p == ':')) p++;
  455                         if (!strcmp(p, "OpenOffice.org")) {
  456                             p += 14;
  457                             while (*p && isspace(*p)) p++;
  458                             if (sscanf(p, "1.1.%d", &ooo110) == 1) {
  459                                 _log("Document created with OpenOffice.org 1.1.x\n");
  460                                 ooo110 = 1;
  461                             }
  462                         } else if (!strcmp(p, "StarOffice 8")) {
  463                             p += 12;
  464                 _log("Document created with StarOffice 8\n");
  465                 ooo110 = 1;
  466                         }
  467                     }
  468                     else if (nestinglevel == 0 && startswith(line->data, "%%BeginProlog")) {
  469                         /* Note: Below is another place where a "Prolog" section
  470                         start will be considered. There we assume start of the
  471                         "Prolog" if the job is DSC-Conformimg, but an arbitrary
  472                         comment starting with "%%Begin", but not a comment
  473                         explicitly treated here, is found. This is done because
  474                         many "dvips" (TeX/LaTeX) files miss the "%%BeginProlog"
  475                         comment.
  476                         Beginning of Prolog */
  477                         _log("\n-----------\nFound: %%%%BeginProlog\n");
  478                         inprolog = 1;
  479                         if (inheader)
  480                             postscriptsection = PS_SECTION_PROLOG;
  481                         nondsclines = 0;
  482                         /* Insert options for "Prolog" */
  483                         if (!prologfound) {
  484                             append_prolog_section(line, optset, 0);
  485                             prologfound = 1;
  486                         }
  487                     }
  488                     else if (nestinglevel == 0 && startswith(line->data, "%%EndProlog")) {
  489                         /* End of Prolog */
  490                         _log("Found: %%%%EndProlog\n");
  491                         inprolog = 0;
  492                         insertoptions = linect +1;
  493                     }
  494                     else if (nestinglevel == 0 && startswith(line->data, "%%BeginSetup")) {
  495                         /* Beginning of Setup */
  496                         _log("\n-----------\nFound: %%%%BeginSetup\n");
  497                         insetup = 1;
  498                         nondsclines = 0;
  499                         /* We need to distinguish with the $inheader variable
  500                         here whether we are in the header or on a page, as
  501                         OpenOffice.org inserts a "%%BeginSetup...%%EndSetup"
  502                         section after the first "%%Page:..." line and assumes
  503                         this section to be valid for all pages. */
  504                         if (inheader) {
  505                             postscriptsection = PS_SECTION_SETUP;
  506                             /* If there was no "Prolog" but there are
  507                             options for the "Prolog", push a "Prolog"
  508                             with these options onto the psfifo here */
  509                             if (!prologfound) {
  510                                 dstrclear(tmp);
  511                                 append_prolog_section(tmp, optset, 1);
  512                                 dstrprepend(line, tmp->data);
  513                                 prologfound = 1;
  514                             }
  515                             /* Insert options for "DocumentSetup" or "AnySetup" */
  516                             if (spooler != SPOOLER_CUPS && !setupfound) {
  517                                 /* For non-CUPS spoolers or no spooler at all,
  518                                 we leave everythnig as it is */
  519                                 append_setup_section(line, optset, 0);
  520                                 setupfound = 1;
  521                             }
  522                         }
  523                         else {
  524                             /* Found option settings must be stuffed into both
  525                             the header and the currrent page now. They will
  526                             be written into both the "header" and the
  527                             "currentpage" optionsets and the PostScript code
  528                             lines of this section will not only go into the
  529                             output stream, but also added to the end of the
  530                             @psheader, so that they get repeated (to preserve
  531                             the embedded PostScript option settings) on a
  532                             restart of the renderer due to command line
  533                             option changes */
  534                             optionsalsointoheader = 1;
  535                             _log("\"%%%%BeginSetup\" in page header\n");
  536                         }
  537                     }
  538                     else if (nestinglevel == 0 && startswith(line->data, "%%EndSetup")) {
  539                         /* End of Setup */
  540                         _log("Found: %%%%EndSetup\n");
  541                         insetup = 0;
  542                         if (inheader) {
  543                             if (spooler == SPOOLER_CUPS) {
  544                                 /* In case of CUPS, we must insert the
  545                                 accounting stuff just before the
  546                                 %%EndSetup comment in order to leave any
  547                                 EndPage procedures that have been
  548                                 defined by either the pstops filter or
  549                                 the PostScript job itself fully
  550                                 functional. */
  551                                 if (!setupfound) {
  552                                     dstrclear(tmp);
  553                                     append_setup_section(tmp, optset, 0);
  554                                     dstrprepend(line, tmp->data);
  555                                     setupfound = 1;
  556                                 }
  557                             }
  558                             insertoptions = linect +1;
  559                         }
  560                         else {
  561                             /* The "%%BeginSetup...%%EndSetup" which
  562                             OpenOffice.org has inserted after the first
  563                             "%%Page:..." line ends here, so the following
  564                             options go only onto the current page again */
  565                             optionsalsointoheader = 0;
  566                         }
  567                     }
  568                     else if (nestinglevel == 0 && startswith(line->data, "%%Page:")) {
  569                         if (!lastpassthru && !inheader) {
  570                             /* In the last line we were not in passthru mode,
  571                             so the last page is not printed. Prepare to do
  572                             it now. */
  573                             printprevpage = 1;
  574                             passthru = 1;
  575                             _log("New page found but previous not printed, print it now.\n");
  576                         }
  577                         else {
  578                             /* the previous page is printed, so we can prepare
  579                             the current one */
  580                             _log("\n-----------\nNew page: %s", line->data);
  581                             printprevpage = 0;
  582                             currentpage++;
  583                             /* We consider the beginning of the page already as
  584                             page setup section, as some apps do not use
  585                             "%%PageSetup" tags. */
  586                             postscriptsection = PS_SECTION_PAGESETUP;
  587 
  588                             /* TODO can this be removed?
  589                             Save PostScript state before beginning the page
  590                             $line .= "/foomatic-saved-state save def\n"; */
  591 
  592                             /* Here begins a new page */
  593                             if (inheader) {
  594                                 build_commandline(optset, NULL, 0);
  595                                 /* Here we add some stuff which still
  596                                 belongs into the header */
  597                                 dstrclear(tmp);
  598 
  599                                 /* If there was no "Setup" but there are
  600                                 options for the "Setup", push a "Setup"
  601                                 with these options onto the @psfifo here */
  602                                 if (!setupfound) {
  603                                     append_setup_section(tmp, optset, 1);
  604                                     setupfound = 1;
  605                                 }
  606                                 /* If there was no "Prolog" but there are
  607                                 options for the "Prolog", push a "Prolog"
  608                                 with these options onto the @psfifo here */
  609                                 if (!prologfound) {
  610                                     append_prolog_section(tmp, optset, 1);
  611                                     prologfound = 1;
  612                                 }
  613                                 /* Now we push this into the header */
  614                                 dstrcat(psheader, tmp->data);
  615 
  616                                 /* The first page starts, so header ends */
  617                                 inheader = 0;
  618                                 nondsclines = 0;
  619                                 /* Option setting should go into the page
  620                                 specific option set now */
  621                                 optset = optionset("currentpage");
  622                             }
  623                             else {
  624                                 /*  Restore PostScript state after completing the
  625                                     previous page:
  626 
  627                                         foomatic-saved-state restore
  628                                         %%Page: ...
  629                                         /foomatic-saved-state save def
  630 
  631                                     Print this directly, so that if we need to
  632                                     restart the renderer for this page due to
  633                                     a command line change this is done under the
  634                                     old instance of the renderer
  635                                     rint $rendererhandle
  636                                     "foomatic-saved-state restore\n"; */
  637 
  638                                 /* Save the option settings of the previous page */
  639                                 optionset_copy_values(optionset("currentpage"), optionset("previouspage"));
  640                                 optionset_delete_values(optionset("currentpage"));
  641                             }
  642                             /* Initialize the option set */
  643                             optionset_copy_values(optionset("header"), optionset("currentpage"));
  644 
  645                             /* Set the command line options which apply only
  646                                 to given pages */
  647                             set_options_for_page(optionset("currentpage"), currentpage);
  648                             pagesetupfound = 0;
  649                             if (spooler == SPOOLER_CUPS) {
  650                                 /* Remove the "notfirst" flag from all options
  651                                     forseen for the "PageSetup" section, because
  652                                     when these are numerical options for CUPS.
  653                                     they have to be set to the correct value
  654                                     for every page */
  655                                 for (o = optionlist; o; o = o->next) {
  656                                     if (option_get_section(o ) == SECTION_PAGESETUP)
  657                                         o->notfirst = 0;
  658                                 }
  659                             }
  660                             /* Now the page header comes, so buffer the data,
  661                                 because we must perhaps shut down and restart
  662                                 the renderer */
  663                             passthru = 0;
  664                             ignorepageheader = 0;
  665                             optionsalsointoheader = 0;
  666                         }
  667                     }
  668                     else if (nestinglevel == 0 && !ignorepageheader &&
  669                             startswith(line->data, "%%BeginPageSetup")) {
  670                         /* Start of the page header, up to %%EndPageSetup
  671                         nothing of the page will be drawn, page-specific
  672                         option settngs (as letter-head paper for page 1)
  673                         go here*/
  674                         _log("\nFound: %%%%BeginPageSetup\n");
  675                         passthru = 0;
  676                         inpageheader = 1;
  677                         postscriptsection = PS_SECTION_PAGESETUP;
  678                         optionsalsointoheader = (ooo110 && currentpage == 1) ? 1 : 0;
  679                         /* Insert PostScript option settings
  680                            (options for section "PageSetup") */
  681                         if (isdscjob) {
  682                             append_page_setup_section(line, optset, 0);
  683                             pagesetupfound = 1;
  684                         }
  685                     }
  686                     else if (nestinglevel == 0 && !ignorepageheader &&
  687                             startswith(line->data, "%%BeginPageSetup")) {
  688                         /* End of the page header, the page is ready to be printed */
  689                         _log("Found: %%%%EndPageSetup\n");
  690                         _log("End of page header\n");
  691                         /* We cannot for sure say that the page header ends here
  692                         OpenOffice.org puts (due to a bug) a "%%BeginSetup...
  693                         %%EndSetup" section after the first "%%Page:...". It
  694                         is possible that CUPS inserts a "%%BeginPageSetup...
  695                         %%EndPageSetup" before this section, which means that
  696                         the options in the "%%BeginSetup...%%EndSetup"
  697                         section are after the "%%EndPageSetup", so we
  698                         continue for searching options up to the buffer size
  699                         limit $maxlinesforpageoptions. */
  700                         passthru = 0;
  701                         inpageheader = 0;
  702                         optionsalsointoheader = 0;
  703                     }
  704                     else if (nestinglevel == 0 && !optionreplaced && (!passthru || !isdscjob) &&
  705                             ((linetype = line_type(line->data)) &&
  706                             (linetype == LT_BEGIN_FEATURE || linetype == LT_FOOMATIC_RIP_OPTION_SETTING))) {
  707 
  708                         /* parse */
  709                         if (linetype == LT_BEGIN_FEATURE) {
  710                             dstrcpy(tmp, line->data);
  711                             p = strtok(tmp->data, " \t"); /* %%BeginFeature: */
  712                             p = strtok(NULL, " \t="); /* Option */
  713                             if (*p == '*') p++;
  714                             strlcpy(optionname, p, 128);
  715                             p = strtok(NULL, " \t\r\n"); /* value */
  716                             fromcomposite = 0;
  717                             strlcpy(value, p, 128);
  718                         }
  719                         else { /* LT_FOOMATIC_RIP_OPTION_SETTING */
  720                             dstrcpy(tmp, line->data);
  721                             p = strstr(tmp->data, "FoomaticRIPOptionSetting:");
  722                             p = strtok(p, " \t");  /* FoomaticRIPOptionSetting */
  723                             p = strtok(NULL, " \t="); /* Option */
  724                             strlcpy(optionname, p, 128);
  725                             p = strtok(NULL, " \t\r\n"); /* value */
  726                             if (*p == '@') { /* fromcomposite */
  727                                 p++;
  728                                 fromcomposite = 1;
  729                             }
  730                             else
  731                                 fromcomposite = 0;
  732                             strlcpy(value, p, 128);
  733                         }
  734 
  735                         /* Mark that we are in a "Feature" section */
  736                         if (linetype == LT_BEGIN_FEATURE) {
  737                             infeature = 1;
  738                             dstrclear(linesafterlastbeginfeature);
  739                         }
  740 
  741                         /* OK, we have an option.  If it's not a
  742                         Postscript-style option (ie, it's command-line or
  743                         JCL) then we should note that fact, since the
  744                         attribute-to-filter option passing in CUPS is kind of
  745                         funky, especially wrt boolean options. */
  746                         _log("Found: %s", line->data);
  747                         if ((o = find_option(optionname)) &&
  748                 (o->type != TYPE_NONE)) {
  749                             _log("   Option: %s=%s%s\n", optionname, fromcomposite ? "From" : "", value);
  750                             if (spooler == SPOOLER_CUPS &&
  751                                 linetype == LT_BEGIN_FEATURE &&
  752                                 !option_get_value(o, optionset("notfirst")) &&
  753                 strcmp(option_get_value(o, optset) ?: "", value) != 0 &&
  754                                 (inheader || option_get_section(o) == SECTION_PAGESETUP)) {
  755 
  756                                 /* We have the first occurence of an option
  757                                 setting and the spooler is CUPS, so this
  758                                 setting is inserted by "pstops" or
  759                                 "imagetops". The value from the command
  760                                 line was not inserted by "pstops" or
  761                                 "imagetops" so it seems to be not under
  762                                 the choices in the PPD. Possible
  763                                 reasons:
  764 
  765                                 - "pstops" and "imagetops" ignore settings
  766                                 of numerical or string options which are
  767                                 not one of the choices in the PPD file,
  768                                 and inserts the default value instead.
  769 
  770                                 - On the command line an option was applied
  771                                 only to selected pages:
  772                                 "-o <page ranges>:<option>=<values>
  773                                 This is not supported by CUPS, so not
  774                                 taken care of by "pstops".
  775 
  776                                 We must fix this here by replacing the
  777                                 setting inserted by "pstops" or "imagetops"
  778                                 with the exact setting given on the command
  779                                 line. */
  780 
  781                                 /* $arg->{$optionset} is already
  782                                 range-checked, so do not check again here
  783                                 Insert DSC comment */
  784                                 pdest = (inheader && isdscjob) ? psheader : psfifo;
  785                                 if (option_is_ps_command(o)) {
  786                                     /* PostScript option, insert the code */
  787 
  788                                     option_get_command(tmp, o, optset, -1);
  789                                     if (!(val = option_get_value(o, optset)))
  790                                         val = "";
  791 
  792                                     /* Boolean and enumerated choice options can only be set in the
  793                                      * PageSetup section */
  794                                     if ((inheader && option_is_custom_value(o, val)) || !inheader)
  795                                     {
  796                                         if (o->type == TYPE_BOOL)
  797                                             dstrcatf(pdest, "%%%%BeginFeature: *%s %s\n", o->name,
  798                                                      val && !strcmp(val, "1") ? "True" : "False");
  799                                         else
  800                                             dstrcatf(pdest, "%%%%BeginFeature: *%s %s\n", o->name, val);
  801 
  802                                         dstrcatf(pdest, "%s\n", tmp->data);
  803 
  804                                         /* We have replaced this option on the FIFO */
  805                                         optionreplaced = 1;
  806                                     }
  807                                 }
  808                                 else { /* Command line or JCL option */
  809                                     val = option_get_value(o, optset);
  810 
  811                                     if (!inheader || option_is_custom_value(o, val)) {
  812                                         dstrcatf(pdest, "%%%% FoomaticRIPOptionSetting: %s=%s\n",
  813                                                  o->name, val ? val : "");
  814                                         optionreplaced = 1;
  815                                     }
  816                                 }
  817 
  818                                 if (optionreplaced) {
  819                                     val = option_get_value(o, optset);
  820                                     _log(" --> Correcting numerical/string option to %s=%s (Command line argument)\n",
  821                                             o->name, val ? val : "");
  822                                 }
  823                             }
  824 
  825                             /* Mark that we have already found this option */
  826                             o->notfirst = 1;
  827                             if (!optionreplaced) {
  828                                 if (o->style != 'G') {
  829                                     /* Controlled by '<Composite>' setting of
  830                                     a member option of a composite option */
  831                                     if (fromcomposite) {
  832                                         dstrcpyf(tmp, "From%s", value);
  833                                         strlcpy(value, tmp->data, 128);
  834                                     }
  835 
  836                                     /* Non PostScript option
  837                                     Check whether it is valid */
  838                                     if (option_set_value(o, optset, value)) {
  839                                         _log("Setting option\n");
  840                                         strlcpy(value, option_get_value(o, optset), 128);
  841                                         if (optionsalsointoheader)
  842                                             option_set_value(o, optionset("header"), value);
  843                                         if (o->type == TYPE_ENUM &&
  844                                                 (!strcmp(o->name, "PageSize") || !strcmp(o->name, "PageRegion")) &&
  845                                                 startswith(value, "Custom") &&
  846                                                 linetype == LT_FOOMATIC_RIP_OPTION_SETTING) {
  847                                             /* Custom Page size */
  848                                             width = height = 0.0;
  849                                             p = linesafterlastbeginfeature->data;
  850                                             while (*p && isspace(*p)) p++;
  851                                             width = strtod(p, &p);
  852                                             while (*p && isspace(*p)) p++;
  853                                             height = strtod(p, &p);
  854                                             if (width && height) {
  855                                                 dstrcpyf(tmp, "%s.%fx%f", value, width, height);
  856                                                 strlcpy(value, tmp->data, 128);
  857                                                 option_set_value(o, optset, value);
  858                                                 if (optionsalsointoheader)
  859                                                     option_set_value(o, optionset("header"), value);
  860                                             }
  861                                         }
  862                                         /* For a composite option insert the
  863                                         code from the member options with
  864                                         current setting "From<composite>"
  865                                         The code from the member options
  866                                         is chosen according to the setting
  867                                         of the composite option. */
  868                                         if (option_is_composite(o) && linetype == LT_FOOMATIC_RIP_OPTION_SETTING) {
  869                                             build_commandline(optset, NULL, 0); /* TODO can this be removed? */
  870 
  871                                             /* TODO merge section and ps_section */
  872                                             if (postscriptsection == PS_SECTION_JCLSETUP)
  873                                                 option_get_command(tmp, o, optset, SECTION_JCLSETUP);
  874                                             else if (postscriptsection == PS_SECTION_PROLOG)
  875                                                 option_get_command(tmp, o, optset, SECTION_PROLOG);
  876                                             else if (postscriptsection == PS_SECTION_SETUP)
  877                                                 option_get_command(tmp, o, optset, SECTION_DOCUMENTSETUP);
  878                                             else if (postscriptsection == PS_SECTION_PAGESETUP)
  879                                                 option_get_command(tmp, o, optset, SECTION_PAGESETUP);
  880                                             dstrcat(line, tmp->data);
  881                                         }
  882                                     }
  883                                     else
  884                                         _log(" --> Invalid option setting found in job\n");
  885                                 }
  886                                 else if (fromcomposite) {
  887                                     /* PostScript option, but we have to look up
  888                                     the PostScript code to be inserted from
  889                                     the setting of a composite option, as
  890                                     this option is set to "Controlled by
  891                                     '<Composite>'". */
  892                                     /* Set the option */
  893                                     dstrcpyf(tmp, "From%s", value);
  894                                     strlcpy(value, tmp->data, 128);
  895                                     if (option_set_value(o, optset, value)) {
  896                                         _log(" --> Looking up setting in composite option %s\n", value);
  897                                         if (optionsalsointoheader)
  898                                             option_set_value(o, optionset("header"), value);
  899                                         /* update composite options */
  900                                         build_commandline(optset, NULL, 0);
  901                                         /* Substitute PostScript comment by the real code */
  902                                         /* TODO what exactly is the next line doing? */
  903                                         /* dstrcpy(line, o->compositesubst->data); */
  904                                     }
  905                                     else
  906                                         _log(" --> Invalid option setting found in job\n");
  907                                 }
  908                                 else
  909                                     /* it is a PostScript style option with
  910                                     the code readily inserted, no option
  911                                     for the renderer command line/JCL to set,
  912                                     no lookup of a composite option needed,
  913                                     so nothing to do here... */
  914                                     _log(" --> Option will be set by PostScript interpreter\n");
  915                             }
  916                         }
  917                         else
  918                             /* This option is unknown to us, WTF? */
  919                             _log("Unknown option %s=%s found in the job\n", optionname, value);
  920                     }
  921                     else if (nestinglevel == 0 && startswith(line->data, "%%EndFeature")) {
  922                         /* End of feature */
  923                         infeature = 0;
  924                         /* If the option setting was replaced, it ends here,
  925                         too, and the next option is not necessarily also replaced */
  926                         optionreplaced = 0;
  927                         dstrclear(linesafterlastbeginfeature);
  928                     }
  929                     else if (nestinglevel == 0 && isdscjob && !prologfound &&
  930                                 startswith(line->data, "%%Begin")) {
  931                         /* In some PostScript files (especially when generated
  932                         by "dvips" of TeX/LaTeX) the "%%BeginProlog" is
  933                         missing, so assume that it was before the current
  934                         line (the first line starting with "%%Begin". */
  935                         _log("Job claims to be DSC-conforming, but \"%%%%BeginProlog\" "
  936                             "was missing before first line with another"
  937                             "\"%%%%BeginProlog\" comment (is this a TeX/LaTeX/dvips-generated"
  938                             " PostScript file?). Assuming start of \"Prolog\" here.\n");
  939                         /* Beginning of Prolog */
  940                         inprolog = 1;
  941                         nondsclines = 0;
  942                         /* Insert options for "Prolog" before the current line */
  943                         dstrcpyf(tmp, "%%%%BeginProlog\n");
  944                         append_prolog_section(tmp, optset, 0);
  945                         dstrprepend(line, tmp->data);
  946                         prologfound = 1;
  947                     }
  948                     else if (nestinglevel == 0 && (
  949                                 startswith(line->data, "%RBINumCopies:") ||
  950                                 startswith(line->data, "%%RBINumCopies:"))) {
  951                         p = strchr(line->data, ':') +1;
  952                         get_current_job()->rbinumcopies = atoi(p);
  953                         _log("Found %RBINumCopies: %d\n", get_current_job()->rbinumcopies);
  954                     }
  955                     else if (startswith(skip_whitespace(line->data), "%") ||
  956                             startswith(skip_whitespace(line->data), "$"))
  957                         /* This is an unknown PostScript comment or a blank
  958                         line, no active code */
  959                         ignoreline = 1;
  960                 }
  961                 else {
  962                     /* This line is active PostScript code */
  963                     if (infeature)
  964                         /* Collect coe in a "%%BeginFeature: ... %%EndFeature"
  965                         section, to get the values for a custom option
  966                         setting */
  967                         dstrcat(linesafterlastbeginfeature, line->data);
  968 
  969                     if (inheader) {
  970                         if (!inprolog && !insetup) {
  971                             /* Outside the "Prolog" and "Setup" section
  972                             a correct DSC-conforming document has no
  973                             active PostScript code, so consider the
  974                             file as non-DSC-conforming when there are
  975                             too many of such lines. */
  976                             nondsclines++;
  977                             if (nondsclines > MAX_NON_DSC_LINES_IN_HEADER) {
  978                                 /* Consider document as not DSC-conforming */
  979                                 _log("This job seems not to be DSC-conforming, "
  980                                     "DSC-comment for next section not found, "
  981                                     "stopping to parse the rest, passing it "
  982                                     "directly to the renderer.\n");
  983                                 /* Stop scanning for further option settings */
  984                                 maxlines = 1;
  985                                 isdscjob = 0;
  986                                 /* Insert defaults and command line settings in
  987                                 the beginning of the job or after the last valid
  988                                 section */
  989                                 dstrclear(tmp);
  990                                 if (prologfound)
  991                                     append_prolog_section(tmp, optset, 1);
  992                                 if (setupfound)
  993                                     append_setup_section(tmp, optset, 1);
  994                                 if (pagesetupfound)
  995                                     append_page_setup_section(tmp, optset, 1);
  996                                 dstrinsert(psheader, line_start(psheader->data, insertoptions), tmp->data);
  997 
  998                                 prologfound = 1;
  999                                 setupfound = 1;
 1000                                 pagesetupfound = 1;
 1001                             }
 1002                         }
 1003                     }
 1004                     else if (!inpageheader) {
 1005                         /* PostScript code inside a page, but not between
 1006                         "%%BeginPageSetup" and "%%EndPageSetup", so
 1007                         we are perhaps already drawing onto a page now */
 1008                         if (startswith(onelinebefore->data, "%%Page"))
 1009                             _log("No page header or page header not DSC-conforming\n");
 1010                         /* Stop buffering lines to search for options
 1011                         placed not DSC-conforming */
 1012                         if (line_count(psfifo->data) >= MAX_LINES_FOR_PAGE_OPTIONS) {
 1013                             _log("Stopping search for page header options\n");
 1014                             passthru = 1;
 1015                             /* If there comes a page header now, ignore it */
 1016                             ignorepageheader = 1;
 1017                             optionsalsointoheader = 0;
 1018                         }
 1019                         /* Insert PostScript option settings (options for the
 1020                          * section "PageSetup" */
 1021                         if (isdscjob && !pagesetupfound) {
 1022                             append_page_setup_section(psfifo, optset, 1);
 1023                             pagesetupfound = 1;
 1024                         }
 1025                     }
 1026                 }
 1027             }
 1028 
 1029             /* Debug Info */
 1030             if (lastpassthru != passthru) {
 1031                 if (passthru)
 1032                     _log("Found: %s --> Output goes directly to the renderer now.\n\n", line->data);
 1033                 else
 1034                     _log("Found: %s --> Output goes to the FIFO buffer now.\n\n", line->data);
 1035             }
 1036 
 1037             /* We are in an option which was replaced, do not output the current line */
 1038             if (optionreplaced)
 1039                 dstrclear(line);
 1040 
 1041             /* If we are in a "%%BeginSetup...%%EndSetup" section after
 1042             the first "%%Page:..." and the current line belongs to
 1043             an option setting, we have to copy the line also to the
 1044             @psheader. */
 1045             if (optionsalsointoheader && (infeature || startswith(line->data, "%%EndFeature")))
 1046                 dstrcat(psheader, line->data);
 1047 
 1048             /* Store or send the current line */
 1049             if (inheader && isdscjob) {
 1050                 /* We are still in the PostScript header, collect all lines
 1051                 in @psheader */
 1052                 dstrcat(psheader, line->data);
 1053             }
 1054             else {
 1055                 if (passthru && isdscjob) {
 1056                     if (!lastpassthru) {
 1057                         /*
 1058                          * We enter passthru mode with this line, so the
 1059                          * command line can have changed, check it and close
 1060                          * the renderer if needed
 1061                          */
 1062                         if (rendererpid && !optionset_equal(optionset("currentpage"), optionset("previouspage"), 0)) {
 1063                             _log("Command line/JCL options changed, restarting renderer\n");
 1064                             retval = close_renderer_handle(rendererhandle, rendererpid);
 1065                             if (retval != EXIT_PRINTED)
 1066                                 rip_die(retval, "Error closing renderer\n");
 1067                             rendererpid = 0;
 1068                         }
 1069                     }
 1070 
 1071                     /* Flush psfifo and send line directly to the renderer */
 1072                     if (!rendererpid) {
 1073                         /* No renderer running, start it */
 1074                         dstrcpy(tmp, psheader->data);
 1075                         dstrcat(tmp, psfifo->data);
 1076                         get_renderer_handle(tmp, &rendererhandle, &rendererpid);
 1077                         /* psfifo is sent out, flush it */
 1078                         dstrclear(psfifo);
 1079                     }
 1080 
 1081                     if (!isempty(psfifo->data)) {
 1082                         /* Send psfifo to renderer */
 1083                         fwrite(psfifo->data, psfifo->len, 1, rendererhandle);
 1084                         /* flush psfifo */
 1085                         dstrclear(psfifo);
 1086                     }
 1087 
 1088                     /* Send line to renderer */
 1089                     if (!printprevpage) {
 1090                         fwrite(line->data, line->len, 1, rendererhandle);
 1091 
 1092                         while (stream_next_line(line, stream) > 0) {
 1093                             if (startswith(line->data, "%%")) {
 1094                                 _log("Found: %s", line->data);
 1095                                 _log(" --> Continue DSC parsing now.\n\n");
 1096                                 saved = 1;
 1097                                 break;
 1098                             }
 1099                             else {
 1100                                 fwrite(line->data, line->len, 1, rendererhandle);
 1101                                 linect++;
 1102                             }
 1103                         }
 1104                     }
 1105                 }
 1106                 else {
 1107                     /* Push the line onto the stack to split up later */
 1108                     dstrcat(psfifo, line->data);
 1109                 }
 1110             }
 1111 
 1112             if (!printprevpage)
 1113                 linect++;
 1114         }
 1115         else {
 1116             /* EOF! */
 1117             more_stuff = 0;
 1118 
 1119             /* No PostScript header in the whole file? Then it's not
 1120             PostScript, convert it.
 1121             We open the file converter here when the file has less
 1122             lines than the amount which we search for the PostScript
 1123             header ($maxlinestopsstart). */
 1124             if (linect <= nonpslines) {
 1125                 /* This is not a PostScript job, we must convert it */
 1126                 _log("\nJob does not start with \"%%!\", is it PostScript?\n"
 1127                      "Starting file converter\n");
 1128 
 1129                 /* Reset all variables but conserve the data which
 1130                 we already have read */
 1131                 jobhasjcl = 0;
 1132                 linect = 0;
 1133                 maxlines = 1000;
 1134                 dstrclear(onelinebefore);
 1135                 dstrclear(twolinesbefore);
 1136                 dstrclear(line);
 1137 
 1138                 dstrcpy(tmp, psheader->data);
 1139                 dstrcat(tmp, psfifo->data);
 1140                 dstrclear(psfifo);
 1141                 dstrclear(psheader);
 1142 
 1143                 /* Start the file conversion filter */
 1144                 if (!fileconverter_pid)
 1145                     get_fileconverter_handle(tmp->data, &fileconverter_handle, &fileconverter_pid);
 1146                 else
 1147                     rip_die(EXIT_JOBERR, "File conversion filter probably crashed\n");
 1148 
 1149                 /* Read the further data from the file converter and
 1150                 not from STDIN */
 1151                 if (close(fileno(stdin)) != 0)
 1152                     rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Couldn't close STDIN\n");
 1153 
 1154                 if (dup2(fileno(fileconverter_handle), fileno(stdin)) == -1)
 1155                     rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Couldn't dup fileconverterhandle\n");
 1156 
 1157                 /* Now we have new (converted) stuff in STDIN, so
 1158                 continue in the loop */
 1159                 more_stuff = 1;
 1160             }
 1161         }
 1162 
 1163         lastpassthru = passthru;
 1164 
 1165         if (!ignoreline && !printprevpage) {
 1166             dstrcpy(twolinesbefore, onelinebefore->data);
 1167             dstrcpy(onelinebefore, line->data);
 1168         }
 1169 
 1170     } while ((maxlines == 0 || linect < maxlines) && more_stuff != 0);
 1171 
 1172     /* Some buffer still containing data? Send it out to the renderer */
 1173     if (more_stuff || inheader || !isempty(psfifo->data)) {
 1174         /* Flush psfifo and send the remaining data to the renderer, this
 1175         only happens with non-DSC-conforming jobs or non-Foomatic PPDs */
 1176         if (more_stuff)
 1177             _log("Stopped parsing the PostScript data, "
 1178                  "sending rest directly to the renderer.\n");
 1179         else
 1180             _log("Flushing FIFO.\n");
 1181 
 1182         if (inheader) {
 1183             build_commandline(optset, NULL, 0);
 1184             /* No page initialized yet? Copy the "header" option set into the
 1185             "currentpage" option set, so that the renderer will find the
 1186             options settings. */
 1187             optionset_copy_values(optionset("header"), optionset("currentpage"));
 1188             optset = optionset("currentpage");
 1189 
 1190             /* If not done yet, insert defaults and command line settings
 1191             in the beginning of the job or after the last valid section */
 1192             dstrclear(tmp);
 1193             if (prologfound)
 1194                 append_prolog_section(tmp, optset, 1);
 1195             if (setupfound)
 1196                 append_setup_section(tmp, optset, 1);
 1197             if (pagesetupfound)
 1198                 append_page_setup_section(tmp, optset, 1);
 1199             dstrinsert(psheader, line_start(psheader->data, insertoptions), tmp->data);
 1200 
 1201             prologfound = 1;
 1202             setupfound = 1;
 1203             pagesetupfound = 1;
 1204         }
 1205 
 1206         if (rendererpid > 0 && !optionset_equal(optionset("currentpage"), optionset("previouspage"), 0)) {
 1207             _log("Command line/JCL options changed, restarting renderer\n");
 1208             retval = close_renderer_handle(rendererhandle, rendererpid);
 1209             if (retval != EXIT_PRINTED)
 1210                 rip_die(retval, "Error closing renderer\n");
 1211             rendererpid = 0;
 1212         }
 1213 
 1214         if (!rendererpid) {
 1215             dstrcpy(tmp, psheader->data);
 1216             dstrcat(tmp, psfifo->data);
 1217             get_renderer_handle(tmp, &rendererhandle, &rendererpid);
 1218             /* We have sent psfifo now */
 1219             dstrclear(psfifo);
 1220         }
 1221 
 1222         if (psfifo->len) {
 1223             /* Send psfifo to the renderer */
 1224             fwrite(psfifo->data, psfifo->len, 1, rendererhandle);
 1225             dstrclear(psfifo);
 1226         }
 1227 
 1228         /* Print the rest of the input data */
 1229         if (more_stuff) {
 1230             while (stream_next_line(tmp, stream))
 1231                 fwrite(tmp->data, tmp->len, 1, rendererhandle);
 1232         }
 1233     }
 1234 
 1235     /*  At every "%%Page:..." comment we have saved the PostScript state
 1236     and we have increased the page number. So if the page number is
 1237     non-zero we had at least one "%%Page:..." comment and so we have
 1238     to give a restore the PostScript state.
 1239     if ($currentpage > 0) {
 1240         print $rendererhandle "foomatic-saved-state restore\n";
 1241     } */
 1242 
 1243     /* Close the renderer */
 1244     if (rendererpid) {
 1245         retval = close_renderer_handle(rendererhandle, rendererpid);
 1246         if (retval != EXIT_PRINTED)
 1247             rip_die(retval, "Error closing renderer\n");
 1248         rendererpid = 0;
 1249     }
 1250 
 1251     /* Close the file converter (if it was used) */
 1252     if (fileconverter_pid) {
 1253         retval = close_fileconverter_handle(fileconverter_handle, fileconverter_pid);
 1254         if (retval != EXIT_PRINTED)
 1255             rip_die(retval, "Error closing file converter\n");
 1256         fileconverter_pid = 0;
 1257     }
 1258 
 1259     free_dstr(line);
 1260     free_dstr(onelinebefore);
 1261     free_dstr(twolinesbefore);
 1262     free_dstr(psheader);
 1263     free_dstr(psfifo);
 1264     free_dstr(tmp);
 1265 }
 1266 
 1267 /*
 1268  * Run the renderer command line (and if defined also the postpipe) and returns
 1269  * a file handle for stuffing in the PostScript data.
 1270  */
 1271 void get_renderer_handle(const dstr_t *prepend, FILE **fd, pid_t *pid)
 1272 {
 1273     pid_t kid3;
 1274     FILE *kid3in;
 1275     dstr_t *cmdline = create_dstr();
 1276 
 1277     /* Build the command line and get the JCL commands */
 1278     build_commandline(optionset("currentpage"), cmdline, 0);
 1279     massage_gs_commandline(cmdline);
 1280 
 1281     _log("\nStarting renderer with command: \"%s\"\n", cmdline->data);
 1282     kid3 = start_process("kid3", exec_kid3, (void *)cmdline->data, &kid3in, NULL);
 1283     if (kid3 < 0)
 1284         rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Cannot fork for kid3\n");
 1285 
 1286     /* Feed the PostScript header and the FIFO contents */
 1287     if (prepend)
 1288         fwrite(prepend->data, prepend->len, 1, kid3in);
 1289 
 1290     /* We are the parent, return glob to the file handle */
 1291     *fd = kid3in;
 1292     *pid = kid3;
 1293 
 1294     free_dstr(cmdline);
 1295 }
 1296 
 1297 /* Close the renderer process and wait until all kid processes finish */
 1298 int close_renderer_handle(FILE *rendererhandle, pid_t rendererpid)
 1299 {
 1300     int status;
 1301 
 1302     _log("\nClosing renderer\n");
 1303     fclose(rendererhandle);
 1304 
 1305     status = wait_for_process(rendererpid);
 1306     if (WIFEXITED(status))
 1307         return WEXITSTATUS(status);
 1308     else
 1309         return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
 1310 }
 1311