~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to filter/foomatic-rip/postscript.c

  • Committer: Package Import Robot
  • Author(s): Didier Raboud
  • Date: 2015-01-15 18:06:05 UTC
  • mfrom: (1.2.25)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: package-import@ubuntu.com-20150115180605-fnfbqv85k3y5zggk
Tags: upstream-1.0.62
ImportĀ upstreamĀ versionĀ 1.0.62

Show diffs side-by-side

added added

removed removed

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