]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/pstops.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / pstops.c
CommitLineData
ef416fc2 1/*
4744bd90 2 * "$Id: pstops.c 5205 2006-02-28 21:05:24Z mike $"
ef416fc2 3 *
4 * PostScript filter for the Common UNIX Printing System (CUPS).
5 *
bd7854cb 6 * Copyright 1993-2006 by Easy Software Products.
ef416fc2 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Main entry...
bd7854cb 29 * add_page() - Add a page to the Pages array...
ef416fc2 30 * check_range() - Check to see if the current page is selected for
31 * copy_bytes() - Copy bytes from the input file to stdout...
32 * do_prolog() - Send the necessary document prolog commands...
33 * do_setup() - Send the necessary document setup commands...
34 * end_nup() - End processing for N-up printing...
35 * include_feature() - Include a printer option/feature command.
ef416fc2 36 * psgets() - Get a line from a file.
ef416fc2 37 * start_nup() - Start processing for N-up printing...
38 */
39
40/*
41 * Include necessary headers...
42 */
43
44#include "common.h"
bd7854cb 45#include <math.h>
46#include <cups/file.h>
47#include <cups/array.h>
ef416fc2 48
49
50/*
51 * Constants...
52 */
53
ef416fc2 54#define BORDER_NONE 0 /* No border or hairline border */
55#define BORDER_THICK 1 /* Think border */
56#define BORDER_SINGLE 2 /* Single-line hairline border */
57#define BORDER_SINGLE2 3 /* Single-line thick border */
58#define BORDER_DOUBLE 4 /* Double-line hairline border */
59#define BORDER_DOUBLE2 5 /* Double-line thick border */
60
61#define LAYOUT_LRBT 0 /* Left to right, bottom to top */
62#define LAYOUT_LRTB 1 /* Left to right, top to bottom */
63#define LAYOUT_RLBT 2 /* Right to left, bottom to top */
64#define LAYOUT_RLTB 3 /* Right to left, top to bottom */
65#define LAYOUT_BTLR 4 /* Bottom to top, left to right */
66#define LAYOUT_TBLR 5 /* Top to bottom, left to right */
67#define LAYOUT_BTRL 6 /* Bottom to top, right to left */
68#define LAYOUT_TBRL 7 /* Top to bottom, right to left */
69
70#define LAYOUT_NEGATEY 1 /* The bits for the layout */
71#define LAYOUT_NEGATEX 2 /* definitions above... */
72#define LAYOUT_VERTICAL 4
73
74#define PROT_STANDARD 0 /* Adobe standard protocol */
75#define PROT_BCP 1 /* Adobe BCP protocol */
76#define PROT_TBCP 2 /* Adobe TBCP protocol */
77
78
bd7854cb 79/*
80 * Types...
81 */
82
83typedef struct /**** Page information ****/
84{
85 char *label; /* Page label */
86 off_t offset; /* Offset to start of page */
87 ssize_t length; /* Number of bytes for page */
88 int lbrt[4]; /* PageBoundingBox */
89 const char *input_slot, /* Input slot option or NULL */
90 *manual_feed; /* Manual feed option or NULL */
91} page_info_t;
92
93
ef416fc2 94/*
95 * Globals...
96 */
97
98int NumPages = 0; /* Number of pages in file */
bd7854cb 99cups_array_t *Pages; /* Info on each page */
ef416fc2 100const char *PageRanges = NULL; /* Range of pages selected */
101const char *PageSet = NULL; /* All, Even, Odd pages */
102int Order = 0, /* 0 = normal, 1 = reverse pages */
103 Flip = 0, /* Flip/mirror pages */
bd7854cb 104 FitPlot = 0, /* Fit pages to media */
ef416fc2 105 NUp = 1, /* Number of pages on each sheet (1, 2, 4) */
106 Collate = 0, /* Collate copies? */
107 Copies = 1, /* Number of copies */
108 UseESPsp = 0, /* Use ESPshowpage? */
109 Border = BORDER_NONE, /* Border around pages */
110 Layout = LAYOUT_LRTB, /* Layout of N-up pages */
bd7854cb 111 NormalLandscape = 0; /* Normal rotation for landscape? */
ef416fc2 112
113
114/*
115 * Local functions...
116 */
117
bd7854cb 118static page_info_t *add_page(const char *label, off_t offset,
119 const int *lbrt);
120static int check_range(int page);
121static void copy_bytes(cups_file_t *fp, off_t offset,
122 size_t length);
123static void do_prolog(ppd_file_t *ppd);
124static void do_setup(ppd_file_t *ppd, int copies, int collate,
125 int slowcollate, float g, float b);
126static void end_nup(int number);
127static void include_feature(ppd_file_t *ppd, const char *line,
128 cups_file_t *out);
129#define is_first_page(p) (NUp == 1 || (((p)+1) % NUp) == 1)
130#define is_last_page(p) (NUp > 1 && (((p)+1) % NUp) == 0)
131#define is_not_last_page(p) (NUp > 1 && ((p) % NUp) != 0)
132static char *psgets(char *buf, size_t *bytes, FILE *fp);
133static void start_nup(int number, int show_border, const int *lbrt);
ef416fc2 134
135
136/*
137 * 'main()' - Main entry...
138 */
139
bd7854cb 140int /* O - Exit status */
141main(int argc, /* I - Number of command-line args */
142 char *argv[]) /* I - Command-line arguments */
ef416fc2 143{
bd7854cb 144 FILE *fp; /* Print file */
145 ppd_file_t *ppd; /* PPD file */
146 ppd_attr_t *attr; /* Attribute in PPD file */
147 ppd_option_t *option; /* Option */
148 ppd_choice_t *choice; /* Marked option choice */
149 int num_options; /* Number of print options */
150 cups_option_t *options; /* Print options */
151 const char *val; /* Option value */
152 char tempfile[255]; /* Temporary file name */
153 cups_file_t *temp; /* Temporary file */
154 int number; /* Page number */
155 int slowcollate; /* 1 if we need to collate manually */
156 int sloworder; /* 1 if we need to order manually */
157 int slowduplex; /* 1 if we need an even page count */
158 char line[8192]; /* Line buffer */
159 int lbrt[4], /* BoundingBox */
160 pagelbrt[4]; /* PageBoundingBox */
161 size_t len; /* Length of line buffer */
162 float g; /* Gamma correction value */
163 float b; /* Brightness factor */
164 int level; /* Nesting level for embedded files */
165 int nbytes, /* Number of bytes read */
166 tbytes; /* Bytes to read for binary data */
167 int page; /* Current page sequence number */
168 int real_page; /* "Real" page number in document */
169 int page_count; /* Page count for NUp */
170 int basepage; /* Base page number */
171 int subpage; /* Sub-page number */
172 int copy; /* Current copy */
173 int saweof; /* Did we see a %%EOF tag? */
174 int sent_espsp, /* Did we send ESPshowpage commands? */
175 sent_prolog, /* Did we send the prolog commands? */
176 sent_setup, /* Did we send the setup commands? */
177 emit_jcl; /* Emit JCL? */
178 float min_order; /* Minimum output order for selection */
179 char label[256]; /* Page label */
180 page_info_t *pageinfo; /* Page information */
181 const char *ap_input_slot, /* First page InputSlot option */
182 *ap_manual_feed, /* First page ManualFeed option */
183 *input_slot, /* Original InputSlot option */
184 *manual_feed; /* Original ManualFeed option */
ef416fc2 185
186 /*
187 * Make sure status messages are not buffered...
188 */
189
190 setbuf(stderr, NULL);
191
192 /*
193 * Check command-line...
194 */
195
196 if (argc < 6 || argc > 7)
197 {
198 fputs("ERROR: pstops job-id user title copies options [file]\n", stderr);
199 return (1);
200 }
201
202 /*
203 * If we have 7 arguments, print the file named on the command-line.
204 * Otherwise, send stdin instead...
205 */
206
207 if (argc == 6)
208 fp = stdin;
209 else
210 {
211 /*
212 * Try to open the print file...
213 */
214
215 if ((fp = fopen(argv[6], "rb")) == NULL)
216 {
217 fprintf(stderr, "ERROR: unable to open print file \"%s\" - %s\n",
218 argv[6], strerror(errno));
219 return (1);
220 }
221 }
222
223 /*
224 * Process command-line options and write the prolog...
225 */
226
227 g = 1.0;
228 b = 1.0;
229
230 Copies = atoi(argv[4]);
231
232 options = NULL;
233 num_options = cupsParseOptions(argv[5], 0, &options);
234
235 ppd = SetCommonOptions(num_options, options, 1);
236
237 if (ppd && ppd->landscape > 0)
238 NormalLandscape = 1;
239
240 if ((val = cupsGetOption("page-ranges", num_options, options)) != NULL)
241 PageRanges = val;
242
243 if ((val = cupsGetOption("page-set", num_options, options)) != NULL)
244 PageSet = val;
245
246 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
247 {
248 /*
249 * This IPP attribute is unnecessarily complicated...
250 *
251 * single-document, separate-documents-collated-copies, and
252 * single-document-new-sheet all require collated copies.
253 *
254 * separate-documents-uncollated-copies allows for uncollated copies.
255 */
256
257 Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
258 }
259
260 if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
261 (!strcasecmp(val, "true") ||!strcasecmp(val, "on") ||
262 !strcasecmp(val, "yes")))
263 Collate = 1;
264
bd7854cb 265 if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL)
266 {
267 if (!strcasecmp(val, "Reverse"))
268 Order = 1;
269 }
270 else if (ppd)
271 {
272 /*
273 * Figure out the right default output order from the PPD file...
274 */
275
276 if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL &&
277 (attr = ppdFindAttr(ppd, "PageStackOrder", choice->choice)) != NULL &&
278 attr->value)
279 Order = !strcasecmp(attr->value, "Reverse");
280 else if ((attr = ppdFindAttr(ppd, "DefaultOutputOrder", NULL)) != NULL &&
281 attr->value)
282 Order = !strcasecmp(attr->value, "Reverse");
283 }
ef416fc2 284
285 if ((val = cupsGetOption("number-up", num_options, options)) != NULL)
286 NUp = atoi(val);
287
288 if ((val = cupsGetOption("page-border", num_options, options)) != NULL)
289 {
290 if (!strcasecmp(val, "none"))
291 Border = BORDER_NONE;
292 else if (!strcasecmp(val, "single"))
293 Border = BORDER_SINGLE;
294 else if (!strcasecmp(val, "single-thick"))
295 Border = BORDER_SINGLE2;
296 else if (!strcasecmp(val, "double"))
297 Border = BORDER_DOUBLE;
298 else if (!strcasecmp(val, "double-thick"))
299 Border = BORDER_DOUBLE2;
300 }
301
302 if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL)
303 {
304 if (!strcasecmp(val, "lrtb"))
305 Layout = LAYOUT_LRTB;
306 else if (!strcasecmp(val, "lrbt"))
307 Layout = LAYOUT_LRBT;
308 else if (!strcasecmp(val, "rltb"))
309 Layout = LAYOUT_RLTB;
310 else if (!strcasecmp(val, "rlbt"))
311 Layout = LAYOUT_RLBT;
312 else if (!strcasecmp(val, "tblr"))
313 Layout = LAYOUT_TBLR;
314 else if (!strcasecmp(val, "tbrl"))
315 Layout = LAYOUT_TBRL;
316 else if (!strcasecmp(val, "btlr"))
317 Layout = LAYOUT_BTLR;
318 else if (!strcasecmp(val, "btrl"))
319 Layout = LAYOUT_BTRL;
320 }
321
322 if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
bd7854cb 323 {
324 /*
325 * Get gamma value from 1 to 10000...
326 */
327
ef416fc2 328 g = atoi(val) * 0.001f;
329
bd7854cb 330 if (g < 0.001f)
331 g = 0.001f;
332 else if (g > 10.0f)
333 g = 10.0f;
334 }
335
ef416fc2 336 if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
bd7854cb 337 {
338 /*
339 * Get brightness value from 10 to 1000.
340 */
341
ef416fc2 342 b = atoi(val) * 0.01f;
343
bd7854cb 344 if (b < 0.1f)
345 b = 0.1f;
346 else if (b > 10.0f)
347 b = 10.0f;
348 }
349
ef416fc2 350 if ((val = cupsGetOption("mirror", num_options, options)) != NULL &&
bd7854cb 351 (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
ef416fc2 352 !strcasecmp(val, "yes")))
353 Flip = 1;
354
bd7854cb 355 if ((val = cupsGetOption("fitplot", num_options, options)) != NULL &&
356 (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
357 !strcasecmp(val, "yes")))
358 FitPlot = 1;
359
360 if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
361 (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
362 !strcasecmp(val, "no") || !strcmp(val, "0")))
363 emit_jcl = 0;
364 else
365 emit_jcl = 1;
366
ef416fc2 367 /*
bd7854cb 368 * Handle input slot/manual feed selections...
ef416fc2 369 */
370
bd7854cb 371 if ((choice = ppdFindMarkedChoice(ppd, "InputSlot")) != NULL)
372 input_slot = choice->choice;
373 else
374 input_slot = NULL;
375
376 if ((choice = ppdFindMarkedChoice(ppd, "ManualFeed")) != NULL)
377 manual_feed = choice->choice;
378 else
379 manual_feed = NULL;
380
381 ap_input_slot = cupsGetOption("AP_FIRSTPAGE_InputSlot", num_options,
382 options);
383 ap_manual_feed = cupsGetOption("AP_FIRSTPAGE_ManualFeed", num_options,
384 options);
385 min_order = 999.0f;
386
387 if (ppd && (ap_input_slot || ap_manual_feed))
388 {
389 /*
390 * The first page/sheet will be using different options than
391 * the rest, so figure out the minimum order dependency for
392 * each of the options...
393 */
394
395 if ((option = ppdFindOption(ppd, "PageRegion")) != NULL &&
396 option->order < min_order)
397 min_order = option->order;
398
399 if ((option = ppdFindOption(ppd, "InputSlot")) != NULL &&
400 option->order < min_order)
401 min_order = option->order;
402
403 if ((option = ppdFindOption(ppd, "ManualFeed")) != NULL &&
404 option->order < min_order)
405 min_order = option->order;
406 }
407
ef416fc2 408 if (ppd && ppd->manual_copies && Duplex && Copies > 1)
409 {
410 /*
411 * Force collated copies when printing a duplexed document to
412 * a non-PS printer that doesn't do hardware copy generation.
413 * Otherwise the copies will end up on the front/back side of
bd7854cb 414 * each page.
ef416fc2 415 */
416
bd7854cb 417 Collate = 1;
ef416fc2 418 }
ef416fc2 419
bd7854cb 420 /*
421 * See if we have to filter the fast or slow way...
422 */
423
424 if (Collate && Copies > 1)
425 {
426 /*
427 * See if we need to manually collate the pages...
428 */
429
ef416fc2 430 slowcollate = 1;
bd7854cb 431
432 if ((choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
433 !strcasecmp(choice->choice, "True"))
434 {
435 /*
436 * Hardware collate option is selected, see if the option is
437 * conflicting - if not, collate in hardware. Otherwise,
438 * turn the hardware collate option off...
439 */
440
441 if ((option = ppdFindOption(ppd, "Option")) != NULL &&
442 !option->conflicted)
443 slowcollate = 0;
444 else
445 ppdMarkOption(ppd, "Collate", "False");
446 }
447 }
ef416fc2 448 else
449 slowcollate = 0;
450
451 if (ppdFindOption(ppd, "OutputOrder") == NULL && Order)
452 sloworder = 1;
453 else
454 sloworder = 0;
455
bd7854cb 456 if ((slowcollate || sloworder) && Duplex)
457 slowduplex = 1;
458 else
459 slowduplex = 0;
460
ef416fc2 461 /*
462 * If we need to filter slowly, then create a temporary file for page data...
463 *
464 * If the temp file can't be created, then we'll ignore the collating/output
465 * order options...
466 */
467
468 if (sloworder || slowcollate)
469 {
bd7854cb 470 if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
ef416fc2 471 slowcollate = sloworder = 0;
472 }
473 else
474 temp = NULL;
475
ef416fc2 476 /*
477 * Write any "exit server" options that have been selected...
478 */
479
480 ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
481
482 /*
483 * Write any JCL commands that are needed to print PostScript code...
484 */
485
bd7854cb 486 if (emit_jcl)
487 ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
ef416fc2 488
489 /*
490 * Read the first line to see if we have DSC comments...
491 */
492
493 len = sizeof(line);
494 if (psgets(line, &len, fp) == NULL)
495 {
496 fputs("ERROR: Empty print file!\n", stderr);
497 ppdClose(ppd);
498 return (1);
499 }
500
501 /*
502 * Handle leading PJL fun...
503 */
504
505 while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
506 {
507 /*
508 * Yup, we have leading PJL fun, so skip it until we hit the line
509 * with "ENTER LANGUAGE"...
510 */
511
512 fputs("DEBUG: Skipping PJL header...\n", stderr);
513
514 while (strstr(line, "ENTER LANGUAGE") == NULL)
515 {
516 len = sizeof(line);
517 if (psgets(line, &len, fp) == NULL)
518 break;
519 }
520
521 len = sizeof(line);
522 if (psgets(line, &len, fp) == NULL)
523 break;
524 }
525
ef416fc2 526 /*
527 * Start sending the document with any commands needed...
528 */
529
530 fwrite(line, 1, len, stdout);
531
532 saweof = 0;
533 sent_espsp = 0;
534 sent_prolog = 0;
535 sent_setup = 0;
536
537 if (Copies != 1 && (!Collate || !slowcollate))
538 {
539 /*
540 * Tell the document processor the copy and duplex options
541 * that are required...
542 */
543
544 printf("%%%%Requirements: numcopies(%d)%s%s\n", Copies,
545 Collate ? " collate" : "",
546 Duplex ? " duplex" : "");
547
548 /*
549 * Apple uses RBI comments for various non-PPD options...
550 */
551
552 printf("%%RBINumCopies: %d\n", Copies);
553 }
554 else
555 {
556 /*
557 * Tell the document processor the duplex option that is required...
558 */
559
560 if (Duplex)
561 puts("%%Requirements: duplex");
562
563 /*
564 * Apple uses RBI comments for various non-PPD options...
565 */
566
567 puts("%RBINumCopies: 1");
568 }
569
570 /*
571 * Figure out if we should use ESPshowpage or not...
572 */
573
574 val = cupsGetOption("page-label", num_options, options);
575
576 if (val != NULL || getenv("CLASSIFICATION") != NULL || NUp > 1 ||
577 Border || strstr(line, "EPS") != NULL)
578 {
579 /*
580 * Yes, use ESPshowpage...
581 */
582
583 UseESPsp = 1;
584 }
585
586 fprintf(stderr, "DEBUG: slowcollate=%d, slowduplex=%d, sloworder=%d\n",
587 slowcollate, slowduplex, sloworder);
588
589 if (!strncmp(line, "%!PS-Adobe-", 11) && !strstr(line, "EPSF"))
590 {
591 /*
592 * OK, we have DSC comments and this isn't an EPS file; read until we
593 * find a %%Page comment...
594 */
595
596 puts("%%Pages: (atend)");
bd7854cb 597 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
598 PageRight, PageTop);
ef416fc2 599
bd7854cb 600 level = 0;
601 lbrt[0] = 0;
602 lbrt[1] = 0;
603 lbrt[2] = (int)PageWidth;
604 lbrt[3] = (int)PageLength;
ef416fc2 605
606 while (!feof(fp))
607 {
608 len = sizeof(line);
609 if (psgets(line, &len, fp) == NULL)
610 break;
611
612 if (!strncmp(line, "%%", 2))
613 fprintf(stderr, "DEBUG: %d %s", level, line);
614 else if (line[0] != '%' && line[0] && !sent_espsp && UseESPsp)
615 {
616 /*
617 * Send ESPshowpage stuff...
618 */
619
620 sent_espsp = 1;
621
622 puts("userdict/ESPshowpage/showpage load put\n"
623 "userdict/showpage{}put");
624 }
625
626 if (!strncmp(line, "%%BeginDocument:", 16) ||
627 !strncmp(line, "%%BeginDocument ", 16) || /* Adobe Acrobat BUG */
628 !strncmp(line, "%ADO_BeginApplication", 21))
629 {
630 fputs(line, stdout);
631 level ++;
632 }
633 else if ((!strncmp(line, "%%EndDocument", 13) ||
634 !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
635 {
636 fputs(line, stdout);
637 level --;
638 }
639 else if (!strncmp(line, "%cupsRotation:", 14) && level == 0)
640 {
641 /*
642 * Reset orientation of document?
643 */
644
645 int orient = (atoi(line + 14) / 90) & 3;
646
647 if (orient != Orientation)
648 {
649 Orientation = (4 - Orientation + orient) & 3;
650 UpdatePageVars();
651 Orientation = orient;
652 }
653 }
654 else if (!strncmp(line, "%%BeginProlog", 13) && level == 0)
655 {
656 /*
657 * Write the existing comment line, and then follow with patches
658 * and prolog commands...
659 */
660
661 fputs(line, stdout);
662
663 if (!sent_prolog)
664 {
665 sent_prolog = 1;
666 do_prolog(ppd);
667 }
668 }
669 else if (!strncmp(line, "%%BeginSetup", 12) && level == 0)
670 {
671 /*
672 * Write the existing comment line, and then follow with document
673 * setup commands...
674 */
675
676 fputs(line, stdout);
677
678 if (!sent_prolog)
679 {
680 sent_prolog = 1;
681 do_prolog(ppd);
682 }
683
684 if (!sent_setup)
685 {
686 sent_setup = 1;
687 do_setup(ppd, Copies, Collate, slowcollate, g, b);
688 }
689 }
bd7854cb 690 else if (!strncmp(line, "%%BoundingBox:", 14) && level == 0)
691 {
692 if (sscanf(line + 14, "%d%d%d%d", pagelbrt + 0, pagelbrt + 1,
693 pagelbrt + 2, pagelbrt + 3) == 4)
694 memcpy(lbrt, pagelbrt, sizeof(lbrt));
695 }
ef416fc2 696 else if (!strncmp(line, "%%Page:", 7) && level == 0)
697 break;
bd7854cb 698 else if (!strncmp(line, "%%IncludeFeature:", 17) && level == 0 &&
699 NUp == 1 && !FitPlot)
700 include_feature(ppd, line, NULL);
ef416fc2 701 else if (!strncmp(line, "%%BeginBinary:", 14) ||
702 (!strncmp(line, "%%BeginData:", 12) &&
703 !strstr(line, "ASCII") && !strstr(line, "Hex")))
704 {
705 /*
706 * Copy binary data...
707 */
708
709 tbytes = atoi(strchr(line, ':') + 1);
710 fputs(line, stdout);
711
712 while (tbytes > 0)
713 {
714 if (tbytes > sizeof(line))
715 nbytes = fread(line, 1, sizeof(line), fp);
716 else
717 nbytes = fread(line, 1, tbytes, fp);
718
719 if (nbytes < 1)
720 {
721 perror("ERROR: Early end-of-file while reading binary data");
722 return (1);
723 }
724
bd7854cb 725 fwrite(line, 1, nbytes, stdout);
ef416fc2 726 tbytes -= nbytes;
727 }
728 }
729 else if (strncmp(line, "%%Pages:", 8) != 0)
bd7854cb 730 fwrite(line, 1, len, stdout);
ef416fc2 731 }
732
733 /*
734 * Make sure we have the prolog and setup commands written...
735 */
736
737 if (!sent_prolog)
738 {
739 puts("%%BeginProlog");
740
741 sent_prolog = 1;
742 do_prolog(ppd);
743
744 puts("%%EndProlog");
745 }
746
747 if (!sent_setup)
748 {
749 puts("%%BeginSetup");
750
751 sent_setup = 1;
752 do_setup(ppd, Copies, Collate, slowcollate, g, b);
753
754 puts("%%EndSetup");
755 }
756
757 if (!sent_espsp && UseESPsp)
758 {
759 /*
760 * Send ESPshowpage stuff...
761 */
762
763 sent_espsp = 1;
764
765 puts("userdict/ESPshowpage/showpage load put\n"
766 "userdict/showpage{}put");
767 }
768
769 /*
770 * Write the page and label prologs...
771 */
772
773 if (NUp == 2 || NUp == 6)
774 {
775 /*
776 * For 2- and 6-up output, rotate the labels to match the orientation
777 * of the pages...
778 */
779
780 if (Orientation & 1)
781 WriteLabelProlog(val, PageBottom, PageWidth - PageLength + PageTop,
782 PageLength);
783 else
784 WriteLabelProlog(val, PageLeft, PageRight, PageLength);
785 }
786 else
787 WriteLabelProlog(val, PageBottom, PageTop, PageWidth);
788
789 /*
790 * Then read all of the pages, filtering as needed...
791 */
792
bd7854cb 793 for (page = 1, real_page = 1, pageinfo = NULL;;)
ef416fc2 794 {
795 if (!strncmp(line, "%%", 2))
796 fprintf(stderr, "DEBUG: %d %s", level, line);
797
798 if (!strncmp(line, "%%BeginDocument:", 16) ||
bd7854cb 799 !strncmp(line, "%%BeginDocument ", 16) || /* Adobe Acrobat BUG */
800 !strncmp(line, "%ADO_BeginApplication", 21))
801 {
ef416fc2 802 level ++;
bd7854cb 803
804 if (!sloworder)
805 fputs(line, stdout);
806
807 if (slowcollate || sloworder)
808 cupsFilePuts(temp, line);
809 }
810 else if ((!strncmp(line, "%%EndDocument", 13) ||
811 !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
812 {
ef416fc2 813 level --;
bd7854cb 814
815 if (!sloworder)
816 fputs(line, stdout);
817
818 if (slowcollate || sloworder)
819 cupsFilePuts(temp, line);
820 }
ef416fc2 821 else if (!strcmp(line, "\004") && len == 1)
822 break;
823 else if (!strncmp(line, "%%EOF", 5) && level == 0)
824 {
825 fputs("DEBUG: Saw EOF!\n", stderr);
826 saweof = 1;
827 break;
828 }
829 else if (!strncmp(line, "%%Page:", 7) && level == 0)
830 {
831 if (!check_range(real_page))
832 {
833 while (!feof(fp))
834 {
835 len = sizeof(line);
836 if (psgets(line, &len, fp) == NULL)
837 break;
838
839 if (!strncmp(line, "%%", 2))
840 fprintf(stderr, "DEBUG: %d %s", level, line);
841
842 if (!strncmp(line, "%%BeginDocument:", 16) ||
bd7854cb 843 !strncmp(line, "%%BeginDocument ", 16) || /* Adobe Acrobat BUG */
844 !strncmp(line, "%ADO_BeginApplication", 21))
ef416fc2 845 level ++;
bd7854cb 846 else if ((!strncmp(line, "%%EndDocument", 13) ||
847 !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
ef416fc2 848 level --;
849 else if (!strncmp(line, "%%Page:", 7) && level == 0)
850 {
851 real_page ++;
852 break;
853 }
854 else if (!strncmp(line, "%%BeginBinary:", 14) ||
855 (!strncmp(line, "%%BeginData:", 12) &&
856 !strstr(line, "ASCII") && !strstr(line, "Hex")))
857 {
858 /*
859 * Skip binary data...
860 */
861
862 tbytes = atoi(strchr(line, ':') + 1);
863
864 while (tbytes > 0)
865 {
866 if (tbytes > sizeof(line))
867 nbytes = fread(line, 1, sizeof(line), fp);
868 else
869 nbytes = fread(line, 1, tbytes, fp);
870
871 if (nbytes < 1)
872 {
873 perror("ERROR: Early end-of-file while reading binary data");
874 return (1);
875 }
876
877 tbytes -= nbytes;
878 }
879 }
880 }
881
882 continue;
883 }
884
885 if (!sloworder && NumPages > 0)
886 end_nup(NumPages - 1);
887
bd7854cb 888 if (sscanf(line, "%%%%Page:%255s%*d", label) != 1)
889 sprintf(label, "%d", page);
890
ef416fc2 891 if (slowcollate || sloworder)
bd7854cb 892 {
893 pageinfo = add_page(label, cupsFileTell(temp), lbrt);
894
895 if (ap_input_slot || ap_manual_feed)
896 {
897 if (page == 0)
898 {
899 pageinfo->input_slot = ap_input_slot;
900 pageinfo->manual_feed = ap_manual_feed;
901 }
902 else if (page == (1 + Duplex))
903 {
904 pageinfo->input_slot = input_slot;
905 pageinfo->manual_feed = manual_feed;
906 }
907 }
908 }
909 else
910 pageinfo = NULL;
ef416fc2 911
912 if (!sloworder)
913 {
914 if (is_first_page(NumPages))
915 {
916 if (ppd == NULL || ppd->num_filters == 0)
917 fprintf(stderr, "PAGE: %d %d\n", page, slowcollate ? 1 : Copies);
918
bd7854cb 919 if (NUp > 1)
920 printf("%%%%Page: %d %d\n", page, page);
921 else
922 printf("%%%%Page: %s %d\n", label, page);
923
924 if (ap_input_slot || ap_manual_feed)
925 {
926 if (page == 0)
927 {
928 if (ap_input_slot)
929 ppdMarkOption(ppd, "InputSlot", ap_input_slot);
930 if (ap_manual_feed)
931 ppdMarkOption(ppd, "ManualFeed", ap_manual_feed);
932 }
933 else if (page == (1 + Duplex))
934 {
935 if (input_slot)
936 ppdMarkOption(ppd, "InputSlot", input_slot);
937 if (manual_feed)
938 ppdMarkOption(ppd, "ManualFeed", manual_feed);
939 }
940
941 ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_DOCUMENT, 1, min_order);
942 ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_ANY, 1, min_order);
943 }
944
ef416fc2 945 page ++;
946 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
947 }
948
bd7854cb 949 start_nup(NumPages, 1, lbrt);
ef416fc2 950 }
951
952 NumPages ++;
953 real_page ++;
954 }
bd7854cb 955 else if (!strncmp(line, "%%PageBoundingBox:", 18) && level == 0 &&
956 pageinfo)
957 {
958 if (sscanf(line + 18, "%d%d%d%d", pagelbrt + 0, pagelbrt + 1,
959 pagelbrt + 2, pagelbrt + 3) == 4)
960 memcpy(pageinfo->lbrt, pagelbrt, sizeof(pageinfo->lbrt));
961 }
ef416fc2 962 else if (!strncmp(line, "%%BeginBinary:", 14) ||
963 (!strncmp(line, "%%BeginData:", 12) &&
964 !strstr(line, "ASCII") && !strstr(line, "Hex")))
965 {
966 /*
967 * Copy binary data...
968 */
969
970 tbytes = atoi(strchr(line, ':') + 1);
971
972 if (!sloworder)
973 fputs(line, stdout);
974 if (slowcollate || sloworder)
bd7854cb 975 cupsFilePuts(temp, line);
ef416fc2 976
977 while (tbytes > 0)
978 {
979 if (tbytes > sizeof(line))
980 nbytes = fread(line, 1, sizeof(line), fp);
981 else
982 nbytes = fread(line, 1, tbytes, fp);
983
984 if (nbytes < 1)
985 {
986 perror("ERROR: Early end-of-file while reading binary data");
987 return (1);
988 }
989
990 if (!sloworder)
bd7854cb 991 fwrite(line, 1, nbytes, stdout);
ef416fc2 992
993 if (slowcollate || sloworder)
bd7854cb 994 cupsFileWrite(temp, line, nbytes);
ef416fc2 995
996 tbytes -= nbytes;
997 }
998 }
bd7854cb 999 else if (!strncmp(line, "%%IncludeFeature:", 17) && level == 0 &&
1000 NUp == 1 && !FitPlot)
ef416fc2 1001 {
1002 /*
1003 * Embed printer commands as needed...
1004 */
1005
1006 if (level == 0 && NUp == 1)
1007 {
bd7854cb 1008 include_feature(ppd, line, NULL);
ef416fc2 1009
1010 if (slowcollate || sloworder)
1011 include_feature(ppd, line, temp);
1012 }
1013 }
bd7854cb 1014 else if (!strncmp(line, "%%BeginFeature:", 15) && (NUp > 1 || FitPlot))
ef416fc2 1015 {
1016 /*
bd7854cb 1017 * Strip page options for N-up > 1 or "fitplot"...
ef416fc2 1018 */
1019
1020 do
1021 {
1022 len = sizeof(line);
1023 if (psgets(line, &len, fp) == NULL)
1024 break;
1025 }
1026 while (strncmp(line, "%%EndFeature", 12));
1027 }
1028 else if (!strncmp(line, "%%Trailer", 9) && level == 0)
1029 {
1030 fputs("DEBUG: Saw Trailer!\n", stderr);
1031 break;
1032 }
1033 else
1034 {
1035 if (!sloworder)
bd7854cb 1036 fwrite(line, 1, len, stdout);
ef416fc2 1037
1038 if (slowcollate || sloworder)
bd7854cb 1039 cupsFileWrite(temp, line, len);
ef416fc2 1040 }
1041
bd7854cb 1042 /*
1043 * Get next line from file...
1044 */
1045
1046 if (pageinfo)
1047 pageinfo->length = cupsFileTell(temp) - pageinfo->offset;
1048
ef416fc2 1049 len = sizeof(line);
1050 if (psgets(line, &len, fp) == NULL)
1051 break;
1052 }
1053
1054 if (!sloworder)
1055 {
1056 end_nup(NumPages - 1);
1057
1058 if (is_not_last_page(NumPages))
1059 {
bd7854cb 1060 start_nup(NUp - 1, 0, lbrt);
ef416fc2 1061 end_nup(NUp - 1);
1062 }
1063
bd7854cb 1064 if (slowduplex && !(page & 1))
ef416fc2 1065 {
1066 /*
1067 * Make sure we have an even number of pages...
1068 */
1069
1070 if (ppd == NULL || ppd->num_filters == 0)
1071 fprintf(stderr, "PAGE: %d %d\n", page, slowcollate ? 1 : Copies);
1072
1073 printf("%%%%Page: %d %d\n", page, page);
1074 page ++;
1075 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
1076
bd7854cb 1077 start_nup(NUp - 1, 0, lbrt);
ef416fc2 1078 puts("showpage");
1079 end_nup(NUp - 1);
1080 }
1081 }
1082
1083 if (slowcollate || sloworder)
1084 {
ef416fc2 1085 if (!sloworder)
1086 {
1087 while (Copies > 1)
1088 {
bd7854cb 1089 for (number = 0, pageinfo = (page_info_t *)cupsArrayFirst(Pages);
1090 number < NumPages && pageinfo;
1091 number ++, pageinfo = (page_info_t *)cupsArrayNext(Pages))
ef416fc2 1092 {
1093 if (is_first_page(number))
1094 {
1095 if (ppd == NULL || ppd->num_filters == 0)
1096 fprintf(stderr, "PAGE: %d 1\n", page);
1097
bd7854cb 1098 if (NUp == 1)
1099 printf("%%%%Page: %s %d\n", pageinfo->label, page);
1100 else
1101 printf("%%%%Page: %d %d\n", page, page);
1102
1103 if (pageinfo->input_slot || pageinfo->manual_feed)
1104 {
1105 if (pageinfo->input_slot)
1106 ppdMarkOption(ppd, "InputSlot", pageinfo->input_slot);
1107 if (pageinfo->manual_feed)
1108 ppdMarkOption(ppd, "ManualFeed", pageinfo->manual_feed);
1109
1110 ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_DOCUMENT, 1, min_order);
1111 ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_ANY, 1, min_order);
1112 }
1113
ef416fc2 1114 page ++;
1115 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
1116 }
1117
bd7854cb 1118 start_nup(number, 1, pageinfo->lbrt);
1119 copy_bytes(temp, pageinfo->offset, pageinfo->length);
ef416fc2 1120 end_nup(number);
1121 }
1122
1123 if (is_not_last_page(NumPages))
1124 {
bd7854cb 1125 start_nup(NUp - 1, 0, lbrt);
ef416fc2 1126 end_nup(NUp - 1);
1127 }
1128
bd7854cb 1129 if (slowduplex && !(page & 1))
ef416fc2 1130 {
1131 /*
1132 * Make sure we have an even number of pages...
1133 */
1134
1135 if (ppd == NULL || ppd->num_filters == 0)
1136 fprintf(stderr, "PAGE: %d 1\n", page);
1137
1138 printf("%%%%Page: %d %d\n", page, page);
1139 page ++;
1140 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
1141
bd7854cb 1142 start_nup(NUp - 1, 0, lbrt);
ef416fc2 1143 puts("showpage");
1144 end_nup(NUp - 1);
1145 }
1146
1147 Copies --;
1148 }
1149 }
1150 else
1151 {
1152 page_count = (NumPages + NUp - 1) / NUp;
1153 copy = 0;
1154
1155 fprintf(stderr, "DEBUG: page_count=%d\n", page_count);
1156
1157 do
1158 {
bd7854cb 1159 if (slowduplex && (page_count & 1))
ef416fc2 1160 basepage = page_count;
1161 else
1162 basepage = page_count - 1;
1163
1164 for (; basepage >= 0; basepage --)
1165 {
1166 if (ppd == NULL || ppd->num_filters == 0)
1167 fprintf(stderr, "PAGE: %d %d\n", page,
1168 slowcollate ? 1 : Copies);
1169
bd7854cb 1170 pageinfo = (page_info_t *)cupsArrayIndex(Pages, basepage);
1171
1172 if (NUp == 1)
1173 printf("%%%%Page: %s %d\n", pageinfo->label, page);
1174 else
1175 printf("%%%%Page: %d %d\n", page, page);
1176
1177 if (pageinfo->input_slot || pageinfo->manual_feed)
1178 {
1179 if (pageinfo->input_slot)
1180 ppdMarkOption(ppd, "InputSlot", pageinfo->input_slot);
1181 if (pageinfo->manual_feed)
1182 ppdMarkOption(ppd, "ManualFeed", pageinfo->manual_feed);
1183
1184 ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_DOCUMENT, 1, min_order);
1185 ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_ANY, 1, min_order);
1186 }
1187
ef416fc2 1188 page ++;
1189
1190 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
1191
1192 if (basepage >= page_count)
1193 {
bd7854cb 1194 start_nup(NUp - 1, 0, pageinfo->lbrt);
ef416fc2 1195 puts("showpage");
1196 end_nup(NUp - 1);
1197 }
1198 else
1199 {
1200 for (subpage = 0, number = basepage * NUp;
1201 subpage < NUp && number < NumPages;
1202 subpage ++, number ++)
1203 {
bd7854cb 1204 pageinfo = (page_info_t *)cupsArrayIndex(Pages, number);
1205
1206 start_nup(number, 1, pageinfo->lbrt);
1207 copy_bytes(temp, pageinfo->offset, pageinfo->length);
ef416fc2 1208 end_nup(number);
1209 }
1210
1211 if (is_not_last_page(number))
1212 {
bd7854cb 1213 start_nup(NUp - 1, 0, lbrt);
ef416fc2 1214 end_nup(NUp - 1);
1215 }
1216 }
1217 }
1218
1219 copy ++;
1220 }
1221 while (copy < Copies && slowcollate);
1222 }
1223 }
1224
1225 /*
1226 * Copy the trailer, if any...
1227 */
1228
1229 puts("%%Trailer");
1230 printf("%%%%Pages: %d\n", page - 1);
1231
1232 if (UseESPsp)
1233 puts("userdict/showpage/ESPshowpage load put\n");
1234
1235 while (!feof(fp))
1236 {
1237 len = sizeof(line);
1238 if (psgets(line, &len, fp) == NULL)
1239 break;
1240
1241 if (!(!strcmp(line, "\004") && len == 1) &&
1242 strncmp(line, "%%Pages:", 8) != 0)
bd7854cb 1243 fwrite(line, 1, len, stdout);
ef416fc2 1244
1245 if (!strncmp(line, "%%EOF", 5))
1246 {
1247 fputs("DEBUG: Saw EOF!\n", stderr);
1248 saweof = 1;
1249 break;
1250 }
1251 }
1252 }
1253 else
1254 {
1255 /*
1256 * No DSC comments - write any page commands and then the rest of the file...
1257 */
1258
1259 if (slowcollate && Copies > 1)
1260 printf("%%%%Pages: %d\n", Copies);
1261 else
1262 puts("%%Pages: 1");
1263
1264 if (UseESPsp)
1265 puts("userdict/ESPshowpage/showpage load put\n"
1266 "userdict/showpage{}put");
1267
1268 puts("%%BeginProlog");
1269 WriteLabelProlog(val, PageBottom, PageTop, PageWidth);
1270 do_prolog(ppd);
1271 puts("%%EndProlog");
1272
1273 puts("%%BeginSetup");
1274 do_setup(ppd, Copies, Collate, slowcollate, g, b);
1275 puts("%%EndSetup");
1276
1277 if (ppd == NULL || ppd->num_filters == 0)
1278 fprintf(stderr, "PAGE: 1 %d\n", slowcollate ? 1 : Copies);
1279
1280 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
1281
1282 saweof = 1;
1283
1284 while ((nbytes = fread(line, 1, sizeof(line), fp)) > 0)
1285 {
bd7854cb 1286 fwrite(line, 1, nbytes, stdout);
ef416fc2 1287
1288 if (slowcollate)
bd7854cb 1289 cupsFileWrite(temp, line, nbytes);
ef416fc2 1290 }
1291
1292 if (UseESPsp)
1293 {
1294 WriteLabels(Orientation);
1295 puts("ESPshowpage");
1296 }
1297
1298 if (slowcollate)
1299 {
1300 while (Copies > 1)
1301 {
1302 if (ppd == NULL || ppd->num_filters == 0)
1303 fputs("PAGE: 1 1\n", stderr);
1304
1305 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
bd7854cb 1306 copy_bytes(temp, 0, 0);
ef416fc2 1307 Copies --;
1308
1309 if (UseESPsp)
1310 {
1311 WriteLabels(Orientation);
1312 puts("ESPshowpage");
1313 }
1314 }
1315 }
1316 }
1317
1318 /*
1319 * Send %%EOF if needed...
1320 */
1321
1322 if (!saweof)
1323 puts("%%EOF");
1324
1325 /*
1326 * End the job with the appropriate JCL command or CTRL-D otherwise.
1327 */
1328
bd7854cb 1329 if (emit_jcl)
1330 {
1331 if (ppd && ppd->jcl_end)
1332 ppdEmitJCLEnd(ppd, stdout);
1333 else
1334 putchar(0x04);
1335 }
ef416fc2 1336
1337 /*
1338 * Close files and remove the temporary file if needed...
1339 */
1340
1341 if (slowcollate || sloworder)
1342 {
bd7854cb 1343 cupsFileClose(temp);
ef416fc2 1344 unlink(tempfile);
1345 }
1346
1347 ppdClose(ppd);
1348
1349 if (fp != stdin)
1350 fclose(fp);
1351
1352 return (0);
1353}
1354
1355
1356/*
1357 * 'check_range()' - Check to see if the current page is selected for
1358 * printing.
1359 */
1360
1361static int /* O - 1 if selected, 0 otherwise */
1362check_range(int page) /* I - Page number */
1363{
1364 const char *range; /* Pointer into range string */
1365 int lower, upper; /* Lower and upper page numbers */
1366
1367
1368 if (PageSet != NULL)
1369 {
1370 /*
1371 * See if we only print even or odd pages...
1372 */
1373
1374 if (!strcasecmp(PageSet, "even") && ((page - 1) % (NUp << 1)) < NUp)
1375 return (0);
1376 if (!strcasecmp(PageSet, "odd") && ((page - 1) % (NUp << 1)) >= NUp)
1377 return (0);
1378 }
1379
1380 if (PageRanges == NULL)
1381 return (1); /* No range, print all pages... */
1382
1383 for (range = PageRanges; *range != '\0';)
1384 {
1385 if (*range == '-')
1386 {
1387 lower = 1;
1388 range ++;
1389 upper = strtol(range, (char **)&range, 10);
1390 }
1391 else
1392 {
1393 lower = strtol(range, (char **)&range, 10);
1394
1395 if (*range == '-')
1396 {
1397 range ++;
1398 if (!isdigit(*range & 255))
1399 upper = 65535;
1400 else
1401 upper = strtol(range, (char **)&range, 10);
1402 }
1403 else
1404 upper = lower;
1405 }
1406
1407 if (page >= lower && page <= upper)
1408 return (1);
1409
1410 if (*range == ',')
1411 range ++;
1412 else
1413 break;
1414 }
1415
1416 return (0);
1417}
1418
1419
bd7854cb 1420/*
1421 * 'add_page()' - Add a page to the Pages array...
1422 */
1423
1424static page_info_t * /* O - New page info object */
1425add_page(const char *label, /* I - Page label */
1426 off_t offset, /* I - Offset in file */
1427 const int *lbrt) /* I - BoundingBox for page */
1428{
1429 page_info_t *pageinfo; /* New page info object */
1430
1431
1432 if (!Pages)
1433 Pages = cupsArrayNew(NULL, NULL);
1434
1435 if (!Pages)
1436 {
1437 fprintf(stderr, "EMERG: Unable to allocate memory for pages array: %s\n",
1438 strerror(errno));
1439 exit(1);
1440 }
1441
1442 if ((pageinfo = calloc(1, sizeof(page_info_t))) == NULL)
1443 {
1444 fprintf(stderr, "EMERG: Unable to allocate memory for page info: %s\n",
1445 strerror(errno));
1446 exit(1);
1447 }
1448
1449 pageinfo->label = strdup(label);
1450 pageinfo->offset = offset;
1451
1452 memcpy(pageinfo->lbrt, lbrt, sizeof(pageinfo->lbrt));
1453
1454 cupsArrayAdd(Pages, pageinfo);
1455
1456 return (pageinfo);
1457}
1458
1459
ef416fc2 1460/*
1461 * 'copy_bytes()' - Copy bytes from the input file to stdout...
1462 */
1463
1464static void
bd7854cb 1465copy_bytes(cups_file_t *fp, /* I - File to read from */
1466 off_t offset, /* I - Offset to page data */
1467 size_t length) /* I - Length of page data */
ef416fc2 1468{
bd7854cb 1469 char buffer[8192]; /* Data buffer */
1470 ssize_t nbytes; /* Number of bytes read */
1471 size_t nleft; /* Number of bytes left/remaining */
ef416fc2 1472
1473
1474 nleft = length;
1475
bd7854cb 1476 cupsFileSeek(fp, offset);
1477
ef416fc2 1478 while (nleft > 0 || length == 0)
1479 {
1480 if (nleft > sizeof(buffer) || length == 0)
1481 nbytes = sizeof(buffer);
1482 else
1483 nbytes = nleft;
1484
bd7854cb 1485 if ((nbytes = cupsFileRead(fp, buffer, nbytes)) < 1)
ef416fc2 1486 return;
1487
1488 nleft -= nbytes;
1489
bd7854cb 1490 fwrite(buffer, 1, nbytes, stdout);
ef416fc2 1491 }
1492}
1493
1494
1495/*
1496 * 'do_prolog()' - Send the necessary document prolog commands...
1497 */
1498
1499static void
1500do_prolog(ppd_file_t *ppd) /* I - PPD file */
1501{
1502 /*
1503 * Send the document prolog commands...
1504 */
1505
bd7854cb 1506 if (ppd && ppd->patches)
ef416fc2 1507 {
1508 puts("%%BeginFeature: *JobPatchFile 1");
1509 puts(ppd->patches);
1510 puts("%%EndFeature");
1511 }
1512
1513 ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
1514}
1515
1516
1517/*
1518 * 'do_setup()' - Send the necessary document setup commands...
1519 */
1520
1521static void
1522do_setup(ppd_file_t *ppd, /* I - PPD file */
1523 int copies, /* I - Number of copies */
1524 int collate, /* I - Collate output? */
1525 int slowcollate, /* I - Slow collate */
1526 float g, /* I - Gamma value */
1527 float b) /* I - Brightness value */
1528{
1529 /*
1530 * Send all the printer-specific setup commands...
1531 */
1532
1533 ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
1534 ppdEmit(ppd, stdout, PPD_ORDER_ANY);
1535
1536 /*
1537 * Set the number of copies for the job...
1538 */
1539
1540 if (copies != 1 && (!collate || !slowcollate))
1541 {
1542 printf("%%RBIBeginNonPPDFeature: *NumCopies %d\n", copies);
1543 printf("%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse{1 dict begin"
1544 "/NumCopies exch def currentdict end "
1545 "setpagedevice}{userdict/#copies 3 -1 roll put}ifelse\n", copies);
1546 printf("%%RBIEndNonPPDFeature\n");
1547 }
1548
1549 /*
1550 * If we are doing N-up printing, disable setpagedevice...
1551 */
1552
1553 if (NUp > 1)
1554 puts("userdict/setpagedevice{pop}bind put");
1555
1556 /*
1557 * Changes to the transfer function must be made AFTER any
1558 * setpagedevice code...
1559 */
1560
1561 if (g != 1.0 || b != 1.0)
1562 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
1563 "ifelse %.3f mul } bind settransfer\n", g, b);
1564
1565 /*
1566 * Make sure we have rectclip and rectstroke procedures of some sort...
1567 */
1568
1569 WriteCommon();
1570}
1571
1572
1573/*
1574 * 'end_nup()' - End processing for N-up printing...
1575 */
1576
1577static void
1578end_nup(int number) /* I - Page number */
1579{
1580 puts("");
1581
1582 if (Flip || Orientation || NUp > 1)
1583 puts("userdict /ESPsave get restore");
1584
1585 switch (NUp)
1586 {
1587 case 1 :
1588 if (UseESPsp)
1589 {
1590 WriteLabels(Orientation);
1591 puts("ESPshowpage");
1592 }
1593 break;
1594
1595 case 2 :
1596 case 6 :
1597 if (is_last_page(number) && UseESPsp)
1598 {
1599 if (Orientation & 1)
1600 {
1601 /*
1602 * Rotate the labels back to portrait...
1603 */
1604
1605 WriteLabels(Orientation - 1);
1606 }
1607 else if (Orientation == 0)
1608 {
1609 /*
1610 * Rotate the labels to landscape...
1611 */
1612
1613 WriteLabels(NormalLandscape ? 1 : 3);
1614 }
1615 else
1616 {
1617 /*
1618 * Rotate the labels to landscape...
1619 */
1620
1621 WriteLabels(NormalLandscape ? 3 : 1);
1622 }
1623
1624 puts("ESPshowpage");
1625 }
1626 break;
1627
1628 default :
1629 if (is_last_page(number) && UseESPsp)
1630 {
1631 WriteLabels(Orientation);
1632 puts("ESPshowpage");
1633 }
1634 break;
1635 }
1636
1637 fflush(stdout);
1638}
1639
1640
1641/*
1642 * 'include_feature()' - Include a printer option/feature command.
1643 */
1644
1645static void
bd7854cb 1646include_feature(ppd_file_t *ppd, /* I - PPD file */
1647 const char *line, /* I - DSC line */
1648 cups_file_t *out) /* I - Output file */
ef416fc2 1649{
1650 char name[255], /* Option name */
1651 value[255]; /* Option value */
1652 ppd_option_t *option; /* Option in file */
1653 ppd_choice_t *choice; /* Choice */
1654
1655
1656 /*
1657 * Get the "%%IncludeFeature: *Keyword OptionKeyword" values...
1658 */
1659
1660 if (sscanf(line + 17, "%254s%254s", name, value) != 2)
1661 {
1662 fprintf(stderr, "ERROR: Bad line: \"%s\"!\n", line);
1663 return;
1664 }
1665
1666 /*
1667 * Find the option and choice...
1668 */
1669
1670 if ((option = ppdFindOption(ppd, name + 1)) == NULL)
1671 {
1672 fprintf(stderr, "WARNING: Unknown option \"%s\"!\n", name + 1);
1673 return;
1674 }
1675
1676 if (option->section == PPD_ORDER_EXIT ||
1677 option->section == PPD_ORDER_JCL)
1678 {
bd7854cb 1679 fprintf(stderr, "WARNING: Option \"%s\" cannot be included via "
1680 "IncludeFeature!\n", name + 1);
ef416fc2 1681 return;
1682 }
1683
1684 if ((choice = ppdFindChoice(option, value)) == NULL)
1685 {
1686 fprintf(stderr, "WARNING: Unknown choice \"%s\" for option \"%s\"!\n",
1687 value, name + 1);
1688 return;
1689 }
1690
1691 /*
1692 * Emit the option...
1693 */
1694
bd7854cb 1695 if (out)
ef416fc2 1696 {
bd7854cb 1697 cupsFilePuts(out, "[{\n");
1698 cupsFilePrintf(out, "%%%%BeginFeature: %s %s\n", name, value);
1699 if (choice->code && choice->code[0])
1700 {
1701 if (choice->code[strlen(choice->code) - 1] != '\n')
1702 cupsFilePrintf(out, "%s\n", choice->code);
1703 else
1704 cupsFilePuts(out, choice->code);
1705 }
1706 cupsFilePuts(out, "%%EndFeature\n");
1707 cupsFilePuts(out, "} stopped cleartomark\n");
ef416fc2 1708 }
1709 else
1710 {
bd7854cb 1711 puts("[{");
1712 printf("%%%%BeginFeature: %s %s\n", name, value);
1713 if (choice->code && choice->code[0])
1714 {
1715 if (choice->code[strlen(choice->code) - 1] != '\n')
1716 printf("%s\n", choice->code);
1717 else
1718 fputs(choice->code, stdout);
1719 }
1720 puts("%%EndFeature");
1721 puts("} stopped cleartomark");
ef416fc2 1722 }
ef416fc2 1723}
1724
1725
1726/*
1727 * 'psgets()' - Get a line from a file.
1728 *
1729 * Note:
1730 *
1731 * This function differs from the gets() function in that it
1732 * handles any combination of CR, LF, or CR LF to end input
1733 * lines.
1734 */
1735
1736static char * /* O - String or NULL if EOF */
1737psgets(char *buf, /* I - Buffer to read into */
1738 size_t *bytes, /* IO - Length of buffer */
1739 FILE *fp) /* I - File to read from */
1740{
1741 char *bufptr; /* Pointer into buffer */
1742 int ch; /* Character from file */
1743 size_t len; /* Max length of string */
1744
1745
1746 len = *bytes - 1;
1747 bufptr = buf;
1748 ch = EOF;
1749
1750 while ((bufptr - buf) < len)
1751 {
1752 if ((ch = getc(fp)) == EOF)
1753 break;
1754
1755 if (ch == '\r')
1756 {
1757 /*
1758 * Got a CR; see if there is a LF as well...
1759 */
1760
1761 ch = getc(fp);
1762
1763 if (ch != EOF && ch != '\n')
1764 {
1765 ungetc(ch, fp); /* Nope, save it for later... */
1766 ch = '\r';
1767 }
1768 else
1769 *bufptr++ = '\r';
1770 break;
1771 }
1772 else if (ch == '\n')
1773 break;
1774 else
1775 *bufptr++ = ch;
1776 }
1777
1778 /*
1779 * Add a trailing newline if it is there...
1780 */
1781
1782 if (ch == '\n' || ch == '\r')
1783 {
1784 if ((bufptr - buf) < len)
1785 *bufptr++ = ch;
1786 else
1787 ungetc(ch, fp);
1788 }
1789
1790 /*
1791 * Nul-terminate the string and return it (or NULL for EOF).
1792 */
1793
1794 *bufptr = '\0';
1795 *bytes = bufptr - buf;
1796
1797 if (ch == EOF && bufptr == buf)
1798 return (NULL);
1799 else
1800 return (buf);
1801}
1802
1803
ef416fc2 1804/*
1805 * 'start_nup()' - Start processing for N-up printing...
1806 */
1807
1808static void
bd7854cb 1809start_nup(int number, /* I - Page number */
1810 int show_border, /* I - Show the page border? */
1811 const int *lbrt) /* I - Page BoundingBox */
ef416fc2 1812{
1813 int pos; /* Position on page */
1814 int x, y; /* Relative position of subpage */
1815 float w, l, /* Width and length of subpage */
1816 tx, ty; /* Translation values for subpage */
1817 float pw, pl; /* Printable width and length of full page */
1818
1819
1820 if (Flip || Orientation || NUp > 1)
1821 puts("userdict/ESPsave save put");
1822
1823 if (Flip)
1824 printf("%.1f 0.0 translate -1 1 scale\n", PageWidth);
1825
1826 pos = number % NUp;
bd7854cb 1827 pw = lbrt[2] - lbrt[0];
1828 pl = lbrt[3] - lbrt[1];
ef416fc2 1829
1830 fprintf(stderr, "DEBUG: pw = %.1f, pl = %.1f\n", pw, pl);
1831 fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n", PageLeft, PageRight);
1832 fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n", PageTop, PageBottom);
1833 fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", PageWidth, PageLength);
1834
1835 switch (Orientation)
1836 {
1837 case 1 : /* Landscape */
1838 printf("%.1f 0.0 translate 90 rotate\n", PageLength);
1839 break;
1840 case 2 : /* Reverse Portrait */
1841 printf("%.1f %.1f translate 180 rotate\n", PageWidth, PageLength);
1842 break;
1843 case 3 : /* Reverse Landscape */
1844 printf("0.0 %.1f translate -90 rotate\n", PageWidth);
1845 break;
1846 }
1847
1848 if (Duplex && NUp > 1 && ((number / NUp) & 1))
1849 printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
bd7854cb 1850 else if (NUp > 1 || FitPlot)
ef416fc2 1851 printf("%.1f %.1f translate\n", PageLeft, PageBottom);
1852
1853 switch (NUp)
1854 {
1855 default :
bd7854cb 1856 if (FitPlot)
1857 {
1858 w = PageRight - PageLeft;
1859 l = w * pl / pw;
1860
1861 if (l > (PageTop - PageBottom))
1862 {
1863 l = PageTop - PageBottom;
1864 w = l * pw / pl;
1865 }
1866
1867 tx = 0.5 * (PageRight - PageLeft - w);
1868 ty = 0.5 * (PageTop - PageBottom - l);
1869
1870 printf("%.1f %.1f translate %.3f %.3f scale\n", tx, ty, w / pw,
1871 l / pl);
1872 }
1873 else
1874 {
1875 w = PageWidth;
1876 l = PageLength;
1877 }
ef416fc2 1878 break;
1879
1880 case 2 :
1881 if (Orientation & 1)
1882 {
1883 x = pos & 1;
1884
1885 if (Layout & LAYOUT_NEGATEY)
1886 x = 1 - x;
1887
1888 w = pl;
1889 l = w * PageLength / PageWidth;
1890
1891 if (l > (pw * 0.5))
1892 {
1893 l = pw * 0.5;
1894 w = l * PageWidth / PageLength;
1895 }
1896
1897 tx = 0.5 * (pw * 0.5 - l);
1898 ty = 0.5 * (pl - w);
1899
1900 if (NormalLandscape)
1901 printf("0.0 %.1f translate -90 rotate\n", pl);
1902 else
1903 printf("%.1f 0.0 translate 90 rotate\n", pw);
1904
1905 printf("%.1f %.1f translate %.3f %.3f scale\n",
1906 ty, tx + l * x, w / PageWidth, l / PageLength);
1907 }
1908 else
1909 {
1910 x = pos & 1;
1911
1912 if (Layout & LAYOUT_NEGATEX)
1913 x = 1 - x;
1914
1915 l = pw;
1916 w = l * PageWidth / PageLength;
1917
1918 if (w > (pl * 0.5))
1919 {
1920 w = pl * 0.5;
1921 l = w * PageLength / PageWidth;
1922 }
1923
1924 tx = 0.5 * (pl * 0.5 - w);
1925 ty = 0.5 * (pw - l);
1926
1927 if (NormalLandscape)
1928 printf("%.1f 0.0 translate 90 rotate\n", pw);
1929 else
1930 printf("0.0 %.1f translate -90 rotate\n", pl);
1931
1932 printf("%.1f %.1f translate %.3f %.3f scale\n",
1933 tx + w * x, ty, w / PageWidth, l / PageLength);
1934 }
1935 break;
1936
1937 case 4 :
1938 if (Layout & LAYOUT_VERTICAL)
1939 {
1940 x = (pos / 2) & 1;
1941 y = pos & 1;
1942 }
1943 else
1944 {
1945 x = pos & 1;
1946 y = (pos / 2) & 1;
1947 }
1948
1949 if (Layout & LAYOUT_NEGATEX)
1950 x = 1 - x;
1951
1952 if (Layout & LAYOUT_NEGATEY)
1953 y = 1 - y;
1954
1955 w = pw * 0.5;
1956 l = w * PageLength / PageWidth;
1957
1958 if (l > (pl * 0.5))
1959 {
1960 l = pl * 0.5;
1961 w = l * PageWidth / PageLength;
1962 }
1963
1964 tx = 0.5 * (pw * 0.5 - w);
1965 ty = 0.5 * (pl * 0.5 - l);
1966
1967 printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
1968 w / PageWidth, l / PageLength);
1969 break;
1970
1971 case 6 :
1972 if (Orientation & 1)
1973 {
1974 if (Layout & LAYOUT_VERTICAL)
1975 {
1976 x = pos / 3;
1977 y = pos % 3;
1978
1979 if (Layout & LAYOUT_NEGATEX)
1980 x = 1 - x;
1981
1982 if (Layout & LAYOUT_NEGATEY)
1983 y = 2 - y;
1984 }
1985 else
1986 {
1987 x = pos & 1;
1988 y = pos / 2;
1989
1990 if (Layout & LAYOUT_NEGATEX)
1991 x = 1 - x;
1992
1993 if (Layout & LAYOUT_NEGATEY)
1994 y = 2 - y;
1995 }
1996
1997 w = pl * 0.5;
1998 l = w * PageLength / PageWidth;
1999
2000 if (l > (pw * 0.333))
2001 {
2002 l = pw * 0.333;
2003 w = l * PageWidth / PageLength;
2004 }
2005
2006 tx = 0.5 * (pl - 2 * w);
2007 ty = 0.5 * (pw - 3 * l);
2008
2009 if (NormalLandscape)
2010 printf("0.0 %.1f translate -90 rotate\n", pl);
2011 else
2012 printf("%.1f 0.0 translate 90 rotate\n", pw);
2013
2014 printf("%.1f %.1f translate %.3f %.3f scale\n",
2015 tx + x * w, ty + y * l, w / PageWidth, l / PageLength);
2016 }
2017 else
2018 {
2019 if (Layout & LAYOUT_VERTICAL)
2020 {
2021 x = pos / 2;
2022 y = pos & 1;
2023
2024 if (Layout & LAYOUT_NEGATEX)
2025 x = 2 - x;
2026
2027 if (Layout & LAYOUT_NEGATEY)
2028 y = 1 - y;
2029 }
2030 else
2031 {
2032 x = pos % 3;
2033 y = pos / 3;
2034
2035 if (Layout & LAYOUT_NEGATEX)
2036 x = 2 - x;
2037
2038 if (Layout & LAYOUT_NEGATEY)
2039 y = 1 - y;
2040 }
2041
2042 l = pw * 0.5;
2043 w = l * PageWidth / PageLength;
2044
2045 if (w > (pl * 0.333))
2046 {
2047 w = pl * 0.333;
2048 l = w * PageLength / PageWidth;
2049 }
2050
2051 tx = 0.5 * (pl - 3 * w);
2052 ty = 0.5 * (pw - 2 * l);
2053
2054 if (NormalLandscape)
2055 printf("%.1f 0.0 translate 90 rotate\n", pw);
2056 else
2057 printf("0.0 %.1f translate -90 rotate\n", pl);
2058
2059 printf("%.1f %.1f translate %.3f %.3f scale\n",
2060 tx + w * x, ty + l * y, w / PageWidth, l / PageLength);
2061 }
2062 break;
2063
2064 case 9 :
2065 if (Layout & LAYOUT_VERTICAL)
2066 {
2067 x = (pos / 3) % 3;
2068 y = pos % 3;
2069 }
2070 else
2071 {
2072 x = pos % 3;
2073 y = (pos / 3) % 3;
2074 }
2075
2076 if (Layout & LAYOUT_NEGATEX)
2077 x = 2 - x;
2078
2079 if (Layout & LAYOUT_NEGATEY)
2080 y = 2 - y;
2081
2082 w = pw * 0.333;
2083 l = w * PageLength / PageWidth;
2084
2085 if (l > (pl * 0.333))
2086 {
2087 l = pl * 0.333;
2088 w = l * PageWidth / PageLength;
2089 }
2090
2091 tx = 0.5 * (pw * 0.333 - w);
2092 ty = 0.5 * (pl * 0.333 - l);
2093
2094 printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
2095 w / PageWidth, l / PageLength);
2096 break;
2097
2098 case 16 :
2099 if (Layout & LAYOUT_VERTICAL)
2100 {
2101 x = (pos / 4) & 3;
2102 y = pos & 3;
2103 }
2104 else
2105 {
2106 x = pos & 3;
2107 y = (pos / 4) & 3;
2108 }
2109
2110 if (Layout & LAYOUT_NEGATEX)
2111 x = 3 - x;
2112
2113 if (Layout & LAYOUT_NEGATEY)
2114 y = 3 - y;
2115
2116 w = pw * 0.25;
2117 l = w * PageLength / PageWidth;
2118
2119 if (l > (pl * 0.25))
2120 {
2121 l = pl * 0.25;
2122 w = l * PageWidth / PageLength;
2123 }
2124
2125 tx = 0.5 * (pw * 0.25 - w);
2126 ty = 0.5 * (pl * 0.25 - l);
2127
2128 printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
2129 w / PageWidth, l / PageLength);
2130 break;
2131 }
2132
2133 /*
2134 * Draw borders as necessary...
2135 */
2136
2137 if (Border && show_border)
2138 {
2139 int rects; /* Number of border rectangles */
2140 float fscale, /* Scaling value for points */
2141 margin; /* Current margin for borders */
2142
2143
2144 rects = (Border & BORDER_DOUBLE) ? 2 : 1;
2145 fscale = PageWidth / w;
2146 margin = 2.25 * fscale;
2147
2148 /*
2149 * Set the line width and color...
2150 */
2151
2152 puts("gsave");
2153 printf("%.3f setlinewidth 0 setgray newpath\n",
2154 (Border & BORDER_THICK) ? 0.5 * fscale : 0.24 * fscale);
2155
2156 /*
2157 * Draw border boxes...
2158 */
2159
2160 for (; rects > 0; rects --, margin += 2 * fscale)
2161 if (NUp > 1)
2162 printf("%.1f %.1f %.1f %.1f ESPrs\n",
2163 margin,
2164 margin,
2165 PageWidth - 2 * margin,
2166 PageLength - 2 * margin);
2167 else
2168 printf("%.1f %.1f %.1f %.1f ESPrs\n",
2169 PageLeft + margin,
2170 PageBottom + margin,
2171 PageRight - PageLeft - 2 * margin,
2172 PageTop - PageBottom - 2 * margin);
2173
2174 /*
2175 * Restore pen settings...
2176 */
2177
2178 puts("grestore");
2179 }
2180
2181 if (NUp > 1)
2182 {
2183 /*
2184 * Clip the page that follows to the bounding box of the page...
2185 */
2186
bd7854cb 2187 printf("%d %d translate\n", -lbrt[0], -lbrt[1]);
4744bd90 2188 printf("0 0 %d %d ESPrc\n", lbrt[2] - lbrt[0], lbrt[3] - lbrt[1]);
ef416fc2 2189 }
2190}
2191
2192
2193/*
4744bd90 2194 * End of "$Id: pstops.c 5205 2006-02-28 21:05:24Z mike $".
ef416fc2 2195 */