Home | History | Annotate | Download | only in filter
      1 /*
      2  * PostScript filter for CUPS.
      3  *
      4  * Copyright 2007-2015 by Apple Inc.
      5  * Copyright 1993-2007 by Easy Software Products.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /*
     17  * Include necessary headers...
     18  */
     19 
     20 #include "common.h"
     21 #include <limits.h>
     22 #include <math.h>
     23 #include <cups/file.h>
     24 #include <cups/array.h>
     25 #include <cups/language-private.h>
     26 #include <signal.h>
     27 
     28 
     29 /*
     30  * Constants...
     31  */
     32 
     33 #define PSTOPS_BORDERNONE	0	/* No border or hairline border */
     34 #define PSTOPS_BORDERTHICK	1	/* Think border */
     35 #define PSTOPS_BORDERSINGLE	2	/* Single-line hairline border */
     36 #define PSTOPS_BORDERSINGLE2	3	/* Single-line thick border */
     37 #define PSTOPS_BORDERDOUBLE	4	/* Double-line hairline border */
     38 #define PSTOPS_BORDERDOUBLE2	5	/* Double-line thick border */
     39 
     40 #define PSTOPS_LAYOUT_LRBT	0	/* Left to right, bottom to top */
     41 #define PSTOPS_LAYOUT_LRTB	1	/* Left to right, top to bottom */
     42 #define PSTOPS_LAYOUT_RLBT	2	/* Right to left, bottom to top */
     43 #define PSTOPS_LAYOUT_RLTB	3	/* Right to left, top to bottom */
     44 #define PSTOPS_LAYOUT_BTLR	4	/* Bottom to top, left to right */
     45 #define PSTOPS_LAYOUT_TBLR	5	/* Top to bottom, left to right */
     46 #define PSTOPS_LAYOUT_BTRL	6	/* Bottom to top, right to left */
     47 #define PSTOPS_LAYOUT_TBRL	7	/* Top to bottom, right to left */
     48 
     49 #define PSTOPS_LAYOUT_NEGATEY	1	/* The bits for the layout */
     50 #define PSTOPS_LAYOUT_NEGATEX	2	/* definitions above... */
     51 #define PSTOPS_LAYOUT_VERTICAL	4
     52 
     53 
     54 /*
     55  * Types...
     56  */
     57 
     58 typedef struct				/**** Page information ****/
     59 {
     60   char		*label;			/* Page label */
     61   int		bounding_box[4];	/* PageBoundingBox */
     62   off_t		offset;			/* Offset to start of page */
     63   ssize_t	length;			/* Number of bytes for page */
     64   int		num_options;		/* Number of options for this page */
     65   cups_option_t	*options;		/* Options for this page */
     66 } pstops_page_t;
     67 
     68 typedef struct				/**** Document information ****/
     69 {
     70   int		page;			/* Current page */
     71   int		bounding_box[4];	/* BoundingBox from header */
     72   int		new_bounding_box[4];	/* New composite bounding box */
     73   int		num_options;		/* Number of document-wide options */
     74   cups_option_t	*options;		/* Document-wide options */
     75   int		normal_landscape,	/* Normal rotation for landscape? */
     76 		saw_eof,		/* Saw the %%EOF comment? */
     77 		slow_collate,		/* Collate copies by hand? */
     78 		slow_duplex,		/* Duplex pages slowly? */
     79 		slow_order,		/* Reverse pages slowly? */
     80 		use_ESPshowpage;	/* Use ESPshowpage? */
     81   cups_array_t	*pages;			/* Pages in document */
     82   cups_file_t	*temp;			/* Temporary file, if any */
     83   char		tempfile[1024];		/* Temporary filename */
     84   int		job_id;			/* Job ID */
     85   const char	*user,			/* User name */
     86 		*title;			/* Job name */
     87   int		copies;			/* Number of copies */
     88   const char	*ap_input_slot,		/* AP_FIRSTPAGE_InputSlot value */
     89 		*ap_manual_feed,	/* AP_FIRSTPAGE_ManualFeed value */
     90 		*ap_media_color,	/* AP_FIRSTPAGE_MediaColor value */
     91 		*ap_media_type,		/* AP_FIRSTPAGE_MediaType value */
     92 		*ap_page_region,	/* AP_FIRSTPAGE_PageRegion value */
     93 		*ap_page_size;		/* AP_FIRSTPAGE_PageSize value */
     94   int		collate,		/* Collate copies? */
     95 		emit_jcl,		/* Emit JCL commands? */
     96 		fit_to_page;		/* Fit pages to media */
     97   const char	*input_slot,		/* InputSlot value */
     98 		*manual_feed,		/* ManualFeed value */
     99 		*media_color,		/* MediaColor value */
    100 		*media_type,		/* MediaType value */
    101 		*page_region,		/* PageRegion value */
    102 		*page_size;		/* PageSize value */
    103   int		mirror,			/* doc->mirror/mirror pages */
    104 		number_up,		/* Number of pages on each sheet */
    105 		number_up_layout,	/* doc->number_up_layout of N-up pages */
    106 		output_order,		/* Requested reverse output order? */
    107 		page_border;		/* doc->page_border around pages */
    108   const char	*page_label,		/* page-label option, if any */
    109 		*page_ranges,		/* page-ranges option, if any */
    110 		*page_set;		/* page-set option, if any */
    111 } pstops_doc_t;
    112 
    113 
    114 /*
    115  * Convenience macros...
    116  */
    117 
    118 #define	is_first_page(p)	(doc->number_up == 1 || \
    119 				 ((p) % doc->number_up) == 1)
    120 #define	is_last_page(p)		(doc->number_up == 1 || \
    121 				 ((p) % doc->number_up) == 0)
    122 #define is_not_last_page(p)	(doc->number_up > 1 && \
    123 				 ((p) % doc->number_up) != 0)
    124 
    125 
    126 /*
    127  * Local globals...
    128  */
    129 
    130 static int		JobCanceled = 0;/* Set to 1 on SIGTERM */
    131 
    132 
    133 /*
    134  * Local functions...
    135  */
    136 
    137 static pstops_page_t	*add_page(pstops_doc_t *doc, const char *label);
    138 static void		cancel_job(int sig);
    139 static int		check_range(pstops_doc_t *doc, int page);
    140 static void		copy_bytes(cups_file_t *fp, off_t offset,
    141 			           size_t length);
    142 static ssize_t		copy_comments(cups_file_t *fp, pstops_doc_t *doc,
    143 			              ppd_file_t *ppd, char *line,
    144 				      ssize_t linelen, size_t linesize);
    145 static void		copy_dsc(cups_file_t *fp, pstops_doc_t *doc,
    146 			         ppd_file_t *ppd, char *line, ssize_t linelen,
    147 				 size_t linesize);
    148 static void		copy_non_dsc(cups_file_t *fp, pstops_doc_t *doc,
    149 			             ppd_file_t *ppd, char *line,
    150 				     ssize_t linelen, size_t linesize);
    151 static ssize_t		copy_page(cups_file_t *fp, pstops_doc_t *doc,
    152 			          ppd_file_t *ppd, int number, char *line,
    153 				  ssize_t linelen, size_t linesize);
    154 static ssize_t		copy_prolog(cups_file_t *fp, pstops_doc_t *doc,
    155 			            ppd_file_t *ppd, char *line,
    156 				    ssize_t linelen, size_t linesize);
    157 static ssize_t		copy_setup(cups_file_t *fp, pstops_doc_t *doc,
    158 			           ppd_file_t *ppd, char *line,
    159 				   ssize_t linelen, size_t linesize);
    160 static ssize_t		copy_trailer(cups_file_t *fp, pstops_doc_t *doc,
    161 			             ppd_file_t *ppd, int number, char *line,
    162 				     ssize_t linelen, size_t linesize);
    163 static void		do_prolog(pstops_doc_t *doc, ppd_file_t *ppd);
    164 static void 		do_setup(pstops_doc_t *doc, ppd_file_t *ppd);
    165 static void		doc_printf(pstops_doc_t *doc, const char *format, ...)
    166 			__attribute__ ((__format__ (__printf__, 2, 3)));
    167 static void		doc_puts(pstops_doc_t *doc, const char *s);
    168 static void		doc_write(pstops_doc_t *doc, const char *s, size_t len);
    169 static void		end_nup(pstops_doc_t *doc, int number);
    170 static int		include_feature(ppd_file_t *ppd, const char *line,
    171 			                int num_options,
    172 					cups_option_t **options);
    173 static char		*parse_text(const char *start, char **end, char *buffer,
    174 			            size_t bufsize);
    175 static void		set_pstops_options(pstops_doc_t *doc, ppd_file_t *ppd,
    176 			                   char *argv[], int num_options,
    177 			                   cups_option_t *options);
    178 static ssize_t		skip_page(cups_file_t *fp, char *line, ssize_t linelen,
    179 				  size_t linesize);
    180 static void		start_nup(pstops_doc_t *doc, int number,
    181 				  int show_border, const int *bounding_box);
    182 static void		write_label_prolog(pstops_doc_t *doc, const char *label,
    183 			                   float bottom, float top,
    184 					   float width);
    185 static void		write_labels(pstops_doc_t *doc, int orient);
    186 static void		write_options(pstops_doc_t  *doc, ppd_file_t *ppd,
    187 			              int num_options, cups_option_t *options);
    188 
    189 
    190 /*
    191  * 'main()' - Main entry.
    192  */
    193 
    194 int					/* O - Exit status */
    195 main(int  argc,				/* I - Number of command-line args */
    196      char *argv[])			/* I - Command-line arguments */
    197 {
    198   pstops_doc_t	doc;			/* Document information */
    199   cups_file_t	*fp;			/* Print file */
    200   ppd_file_t	*ppd;			/* PPD file */
    201   int		num_options;		/* Number of print options */
    202   cups_option_t	*options;		/* Print options */
    203   char		line[8192];		/* Line buffer */
    204   ssize_t	len;			/* Length of line buffer */
    205 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
    206   struct sigaction action;		/* Actions for POSIX signals */
    207 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
    208 
    209 
    210  /*
    211   * Make sure status messages are not buffered...
    212   */
    213 
    214   setbuf(stderr, NULL);
    215 
    216  /*
    217   * Ignore broken pipe signals...
    218   */
    219 
    220   signal(SIGPIPE, SIG_IGN);
    221 
    222  /*
    223   * Check command-line...
    224   */
    225 
    226   if (argc < 6 || argc > 7)
    227   {
    228     _cupsLangPrintf(stderr,
    229                     _("Usage: %s job-id user title copies options [file]"),
    230                     argv[0]);
    231     return (1);
    232   }
    233 
    234  /*
    235   * Register a signal handler to cleanly cancel a job.
    236   */
    237 
    238 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
    239   sigset(SIGTERM, cancel_job);
    240 #elif defined(HAVE_SIGACTION)
    241   memset(&action, 0, sizeof(action));
    242 
    243   sigemptyset(&action.sa_mask);
    244   action.sa_handler = cancel_job;
    245   sigaction(SIGTERM, &action, NULL);
    246 #else
    247   signal(SIGTERM, cancel_job);
    248 #endif /* HAVE_SIGSET */
    249 
    250  /*
    251   * If we have 7 arguments, print the file named on the command-line.
    252   * Otherwise, send stdin instead...
    253   */
    254 
    255   if (argc == 6)
    256     fp = cupsFileStdin();
    257   else
    258   {
    259    /*
    260     * Try to open the print file...
    261     */
    262 
    263     if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
    264     {
    265       if (!JobCanceled)
    266       {
    267         fprintf(stderr, "DEBUG: Unable to open \"%s\".\n", argv[6]);
    268         _cupsLangPrintError("ERROR", _("Unable to open print file"));
    269       }
    270 
    271       return (1);
    272     }
    273   }
    274 
    275  /*
    276   * Read the first line to see if we have DSC comments...
    277   */
    278 
    279   if ((len = (ssize_t)cupsFileGetLine(fp, line, sizeof(line))) == 0)
    280   {
    281     fputs("DEBUG: The print file is empty.\n", stderr);
    282     return (1);
    283   }
    284 
    285  /*
    286   * Process command-line options...
    287   */
    288 
    289   options     = NULL;
    290   num_options = cupsParseOptions(argv[5], 0, &options);
    291   ppd         = SetCommonOptions(num_options, options, 1);
    292 
    293   set_pstops_options(&doc, ppd, argv, num_options, options);
    294 
    295  /*
    296   * Write any "exit server" options that have been selected...
    297   */
    298 
    299   ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
    300 
    301  /*
    302   * Write any JCL commands that are needed to print PostScript code...
    303   */
    304 
    305   if (doc.emit_jcl)
    306     ppdEmitJCL(ppd, stdout, doc.job_id, doc.user, doc.title);
    307 
    308  /*
    309   * Start with a DSC header...
    310   */
    311 
    312   puts("%!PS-Adobe-3.0");
    313 
    314  /*
    315   * Skip leading PJL in the document...
    316   */
    317 
    318   while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
    319   {
    320    /*
    321     * Yup, we have leading PJL fun, so skip it until we hit the line
    322     * with "ENTER LANGUAGE"...
    323     */
    324 
    325     fputs("DEBUG: Skipping PJL header...\n", stderr);
    326 
    327     while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
    328       if ((len = (ssize_t)cupsFileGetLine(fp, line, sizeof(line))) == 0)
    329         break;
    330 
    331     if (!strncmp(line, "%!", 2))
    332       break;
    333 
    334     if ((len = (ssize_t)cupsFileGetLine(fp, line, sizeof(line))) == 0)
    335       break;
    336   }
    337 
    338  /*
    339   * Now see if the document conforms to the Adobe Document Structuring
    340   * Conventions...
    341   */
    342 
    343   if (!strncmp(line, "%!PS-Adobe-", 11))
    344   {
    345    /*
    346     * Yes, filter the document...
    347     */
    348 
    349     copy_dsc(fp, &doc, ppd, line, len, sizeof(line));
    350   }
    351   else
    352   {
    353    /*
    354     * No, display an error message and treat the file as if it contains
    355     * a single page...
    356     */
    357 
    358     copy_non_dsc(fp, &doc, ppd, line, len, sizeof(line));
    359   }
    360 
    361  /*
    362   * Send %%EOF as needed...
    363   */
    364 
    365   if (!doc.saw_eof)
    366     puts("%%EOF");
    367 
    368  /*
    369   * End the job with the appropriate JCL command or CTRL-D...
    370   */
    371 
    372   if (doc.emit_jcl)
    373   {
    374     if (ppd && ppd->jcl_end)
    375       ppdEmitJCLEnd(ppd, stdout);
    376     else
    377       putchar(0x04);
    378   }
    379 
    380  /*
    381   * Close files and remove the temporary file if needed...
    382   */
    383 
    384   if (doc.temp)
    385   {
    386     cupsFileClose(doc.temp);
    387     unlink(doc.tempfile);
    388   }
    389 
    390   ppdClose(ppd);
    391   cupsFreeOptions(num_options, options);
    392 
    393   cupsFileClose(fp);
    394 
    395   return (0);
    396 }
    397 
    398 
    399 /*
    400  * 'add_page()' - Add a page to the pages array.
    401  */
    402 
    403 static pstops_page_t *			/* O - New page info object */
    404 add_page(pstops_doc_t *doc,		/* I - Document information */
    405          const char   *label)		/* I - Page label */
    406 {
    407   pstops_page_t	*pageinfo;		/* New page info object */
    408 
    409 
    410   if (!doc->pages)
    411     doc->pages = cupsArrayNew(NULL, NULL);
    412 
    413   if (!doc->pages)
    414   {
    415     _cupsLangPrintError("EMERG", _("Unable to allocate memory for pages array"));
    416     exit(1);
    417   }
    418 
    419   if ((pageinfo = calloc(1, sizeof(pstops_page_t))) == NULL)
    420   {
    421     _cupsLangPrintError("EMERG", _("Unable to allocate memory for page info"));
    422     exit(1);
    423   }
    424 
    425   pageinfo->label  = strdup(label);
    426   pageinfo->offset = cupsFileTell(doc->temp);
    427 
    428   cupsArrayAdd(doc->pages, pageinfo);
    429 
    430   doc->page ++;
    431 
    432   return (pageinfo);
    433 }
    434 
    435 
    436 /*
    437  * 'cancel_job()' - Flag the job as canceled.
    438  */
    439 
    440 static void
    441 cancel_job(int sig)			/* I - Signal number (unused) */
    442 {
    443   (void)sig;
    444 
    445   JobCanceled = 1;
    446 }
    447 
    448 
    449 /*
    450  * 'check_range()' - Check to see if the current page is selected for
    451  *                   printing.
    452  */
    453 
    454 static int				/* O - 1 if selected, 0 otherwise */
    455 check_range(pstops_doc_t *doc,		/* I - Document information */
    456             int          page)		/* I - Page number */
    457 {
    458   const char	*range;			/* Pointer into range string */
    459   int		lower, upper;		/* Lower and upper page numbers */
    460 
    461 
    462   if (doc->page_set)
    463   {
    464    /*
    465     * See if we only print even or odd pages...
    466     */
    467 
    468     if (!_cups_strcasecmp(doc->page_set, "even") && (page & 1))
    469       return (0);
    470 
    471     if (!_cups_strcasecmp(doc->page_set, "odd") && !(page & 1))
    472       return (0);
    473   }
    474 
    475   if (!doc->page_ranges)
    476     return (1);				/* No range, print all pages... */
    477 
    478   for (range = doc->page_ranges; *range != '\0';)
    479   {
    480     if (*range == '-')
    481     {
    482       lower = 1;
    483       range ++;
    484       upper = (int)strtol(range, (char **)&range, 10);
    485     }
    486     else
    487     {
    488       lower = (int)strtol(range, (char **)&range, 10);
    489 
    490       if (*range == '-')
    491       {
    492         range ++;
    493 	if (!isdigit(*range & 255))
    494 	  upper = 65535;
    495 	else
    496 	  upper = (int)strtol(range, (char **)&range, 10);
    497       }
    498       else
    499         upper = lower;
    500     }
    501 
    502     if (page >= lower && page <= upper)
    503       return (1);
    504 
    505     if (*range == ',')
    506       range ++;
    507     else
    508       break;
    509   }
    510 
    511   return (0);
    512 }
    513 
    514 
    515 /*
    516  * 'copy_bytes()' - Copy bytes from the input file to stdout.
    517  */
    518 
    519 static void
    520 copy_bytes(cups_file_t *fp,		/* I - File to read from */
    521            off_t       offset,		/* I - Offset to page data */
    522            size_t      length)		/* I - Length of page data */
    523 {
    524   char		buffer[8192];		/* Data buffer */
    525   ssize_t	nbytes;			/* Number of bytes read */
    526   size_t	nleft;			/* Number of bytes left/remaining */
    527 
    528 
    529   nleft = length;
    530 
    531   if (cupsFileSeek(fp, offset) < 0)
    532   {
    533     _cupsLangPrintError("ERROR", _("Unable to see in file"));
    534     return;
    535   }
    536 
    537   while (nleft > 0 || length == 0)
    538   {
    539     if (nleft > sizeof(buffer) || length == 0)
    540       nbytes = sizeof(buffer);
    541     else
    542       nbytes = (ssize_t)nleft;
    543 
    544     if ((nbytes = cupsFileRead(fp, buffer, (size_t)nbytes)) < 1)
    545       return;
    546 
    547     nleft -= (size_t)nbytes;
    548 
    549     fwrite(buffer, 1, (size_t)nbytes, stdout);
    550   }
    551 }
    552 
    553 
    554 /*
    555  * 'copy_comments()' - Copy all of the comments section.
    556  *
    557  * This function expects "line" to be filled with a comment line.
    558  * On return, "line" will contain the next line in the file, if any.
    559  */
    560 
    561 static ssize_t				/* O - Length of next line */
    562 copy_comments(cups_file_t  *fp,		/* I - File to read from */
    563               pstops_doc_t *doc,	/* I - Document info */
    564 	      ppd_file_t   *ppd,	/* I - PPD file */
    565               char         *line,	/* I - Line buffer */
    566 	      ssize_t      linelen,	/* I - Length of initial line */
    567 	      size_t       linesize)	/* I - Size of line buffer */
    568 {
    569   int	saw_bounding_box,		/* Saw %%BoundingBox: comment? */
    570 	saw_for,			/* Saw %%For: comment? */
    571 	saw_pages,			/* Saw %%Pages: comment? */
    572 	saw_title;			/* Saw %%Title: comment? */
    573 
    574 
    575  /*
    576   * Loop until we see %%EndComments or a non-comment line...
    577   */
    578 
    579   saw_bounding_box = 0;
    580   saw_for          = 0;
    581   saw_pages        = 0;
    582   saw_title        = 0;
    583 
    584   while (line[0] == '%')
    585   {
    586    /*
    587     * Strip trailing whitespace...
    588     */
    589 
    590     while (linelen > 0)
    591     {
    592       linelen --;
    593 
    594       if (!isspace(line[linelen] & 255))
    595         break;
    596       else
    597         line[linelen] = '\0';
    598     }
    599 
    600    /*
    601     * Log the header...
    602     */
    603 
    604     fprintf(stderr, "DEBUG: %s\n", line);
    605 
    606    /*
    607     * Pull the headers out...
    608     */
    609 
    610     if (!strncmp(line, "%%Pages:", 8))
    611     {
    612       int	pages;			/* Number of pages */
    613 
    614       if (saw_pages)
    615 	fputs("DEBUG: A duplicate %%Pages: comment was seen.\n", stderr);
    616 
    617       saw_pages = 1;
    618 
    619       if (Duplex && (pages = atoi(line + 8)) > 0 && pages <= doc->number_up)
    620       {
    621        /*
    622         * Since we will only be printing on a single page, disable duplexing.
    623 	*/
    624 
    625 	Duplex           = 0;
    626 	doc->slow_duplex = 0;
    627 
    628 	if (cupsGetOption("sides", doc->num_options, doc->options))
    629 	  doc->num_options = cupsAddOption("sides", "one-sided",
    630 	                                   doc->num_options, &(doc->options));
    631 
    632 	if (cupsGetOption("Duplex", doc->num_options, doc->options))
    633 	  doc->num_options = cupsAddOption("Duplex", "None",
    634 	                                   doc->num_options, &(doc->options));
    635 
    636 	if (cupsGetOption("EFDuplex", doc->num_options, doc->options))
    637 	  doc->num_options = cupsAddOption("EFDuplex", "None",
    638 	                                   doc->num_options, &(doc->options));
    639 
    640 	if (cupsGetOption("EFDuplexing", doc->num_options, doc->options))
    641 	  doc->num_options = cupsAddOption("EFDuplexing", "False",
    642 	                                   doc->num_options, &(doc->options));
    643 
    644 	if (cupsGetOption("KD03Duplex", doc->num_options, doc->options))
    645 	  doc->num_options = cupsAddOption("KD03Duplex", "None",
    646 	                                   doc->num_options, &(doc->options));
    647 
    648 	if (cupsGetOption("JCLDuplex", doc->num_options, doc->options))
    649 	  doc->num_options = cupsAddOption("JCLDuplex", "None",
    650 	                                   doc->num_options, &(doc->options));
    651 
    652 	ppdMarkOption(ppd, "Duplex", "None");
    653 	ppdMarkOption(ppd, "EFDuplex", "None");
    654 	ppdMarkOption(ppd, "EFDuplexing", "False");
    655 	ppdMarkOption(ppd, "KD03Duplex", "None");
    656 	ppdMarkOption(ppd, "JCLDuplex", "None");
    657       }
    658     }
    659     else if (!strncmp(line, "%%BoundingBox:", 14))
    660     {
    661       if (saw_bounding_box)
    662 	fputs("DEBUG: A duplicate %%BoundingBox: comment was seen.\n", stderr);
    663       else if (strstr(line + 14, "(atend)"))
    664       {
    665        /*
    666         * Do nothing for now but use the default imageable area...
    667 	*/
    668       }
    669       else if (sscanf(line + 14, "%d%d%d%d", doc->bounding_box + 0,
    670 	              doc->bounding_box + 1, doc->bounding_box + 2,
    671 		      doc->bounding_box + 3) != 4)
    672       {
    673 	fputs("DEBUG: A bad %%BoundingBox: comment was seen.\n", stderr);
    674 
    675 	doc->bounding_box[0] = (int)PageLeft;
    676 	doc->bounding_box[1] = (int)PageBottom;
    677 	doc->bounding_box[2] = (int)PageRight;
    678 	doc->bounding_box[3] = (int)PageTop;
    679       }
    680 
    681       saw_bounding_box = 1;
    682     }
    683     else if (!strncmp(line, "%%For:", 6))
    684     {
    685       saw_for = 1;
    686       doc_printf(doc, "%s\n", line);
    687     }
    688     else if (!strncmp(line, "%%Title:", 8))
    689     {
    690       saw_title = 1;
    691       doc_printf(doc, "%s\n", line);
    692     }
    693     else if (!strncmp(line, "%cupsRotation:", 14))
    694     {
    695      /*
    696       * Reset orientation of document?
    697       */
    698 
    699       int orient = (atoi(line + 14) / 90) & 3;
    700 
    701       if (orient != Orientation)
    702       {
    703        /*
    704         * Yes, update things so that the pages come out right...
    705 	*/
    706 
    707 	Orientation = (4 - Orientation + orient) & 3;
    708 	UpdatePageVars();
    709 	Orientation = orient;
    710       }
    711     }
    712     else if (!strcmp(line, "%%EndComments"))
    713     {
    714       linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
    715       break;
    716     }
    717     else if (strncmp(line, "%!", 2) && strncmp(line, "%cups", 5))
    718       doc_printf(doc, "%s\n", line);
    719 
    720     if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
    721       break;
    722   }
    723 
    724   if (!saw_bounding_box)
    725     fputs("DEBUG: There wasn't a %%BoundingBox: comment in the header.\n",
    726           stderr);
    727 
    728   if (!saw_pages)
    729     fputs("DEBUG: There wasn't a %%Pages: comment in the header.\n", stderr);
    730 
    731   if (!saw_for)
    732     WriteTextComment("For", doc->user);
    733 
    734   if (!saw_title)
    735     WriteTextComment("Title", doc->title);
    736 
    737   if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
    738   {
    739    /*
    740     * Tell the document processor the copy and duplex options
    741     * that are required...
    742     */
    743 
    744     doc_printf(doc, "%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
    745                doc->collate ? " collate" : "",
    746 	       Duplex ? " duplex" : "");
    747 
    748    /*
    749     * Apple uses RBI comments for various non-PPD options...
    750     */
    751 
    752     doc_printf(doc, "%%RBINumCopies: %d\n", doc->copies);
    753   }
    754   else
    755   {
    756    /*
    757     * Tell the document processor the duplex option that is required...
    758     */
    759 
    760     if (Duplex)
    761       doc_puts(doc, "%%Requirements: duplex\n");
    762 
    763    /*
    764     * Apple uses RBI comments for various non-PPD options...
    765     */
    766 
    767     doc_puts(doc, "%RBINumCopies: 1\n");
    768   }
    769 
    770   doc_puts(doc, "%%Pages: (atend)\n");
    771   doc_puts(doc, "%%BoundingBox: (atend)\n");
    772   doc_puts(doc, "%%EndComments\n");
    773 
    774   return (linelen);
    775 }
    776 
    777 
    778 /*
    779  * 'copy_dsc()' - Copy a DSC-conforming document.
    780  *
    781  * This function expects "line" to be filled with the %!PS-Adobe comment line.
    782  */
    783 
    784 static void
    785 copy_dsc(cups_file_t  *fp,		/* I - File to read from */
    786          pstops_doc_t *doc,		/* I - Document info */
    787          ppd_file_t   *ppd,		/* I - PPD file */
    788 	 char         *line,		/* I - Line buffer */
    789 	 ssize_t      linelen,		/* I - Length of initial line */
    790 	 size_t       linesize)		/* I - Size of line buffer */
    791 {
    792   int		number;			/* Page number */
    793   pstops_page_t	*pageinfo;		/* Page information */
    794 
    795 
    796  /*
    797   * Make sure we use ESPshowpage for EPS files...
    798   */
    799 
    800   if (strstr(line, "EPSF"))
    801   {
    802     doc->use_ESPshowpage = 1;
    803     doc->number_up       = 1;
    804   }
    805 
    806  /*
    807   * Start sending the document with any commands needed...
    808   */
    809 
    810   fprintf(stderr, "DEBUG: Before copy_comments - %s", line);
    811   linelen = copy_comments(fp, doc, ppd, line, linelen, linesize);
    812 
    813  /*
    814   * Now find the prolog section, if any...
    815   */
    816 
    817   fprintf(stderr, "DEBUG: Before copy_prolog - %s", line);
    818   linelen = copy_prolog(fp, doc, ppd, line, linelen, linesize);
    819 
    820  /*
    821   * Then the document setup section...
    822   */
    823 
    824   fprintf(stderr, "DEBUG: Before copy_setup - %s", line);
    825   linelen = copy_setup(fp, doc, ppd, line, linelen, linesize);
    826 
    827  /*
    828   * Copy until we see %%Page:...
    829   */
    830 
    831   while (strncmp(line, "%%Page:", 7) && strncmp(line, "%%Trailer", 9))
    832   {
    833     doc_write(doc, line, (size_t)linelen);
    834 
    835     if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
    836       break;
    837   }
    838 
    839  /*
    840   * Then process pages until we have no more...
    841   */
    842 
    843   number = 0;
    844 
    845   fprintf(stderr, "DEBUG: Before page loop - %s", line);
    846   while (!strncmp(line, "%%Page:", 7))
    847   {
    848     if (JobCanceled)
    849       break;
    850 
    851     number ++;
    852 
    853     if (check_range(doc, (number - 1) / doc->number_up + 1))
    854     {
    855       fprintf(stderr, "DEBUG: Copying page %d...\n", number);
    856       linelen = copy_page(fp, doc, ppd, number, line, linelen, linesize);
    857     }
    858     else
    859     {
    860       fprintf(stderr, "DEBUG: Skipping page %d...\n", number);
    861       linelen = skip_page(fp, line, linelen, linesize);
    862     }
    863   }
    864 
    865  /*
    866   * Finish up the last page(s)...
    867   */
    868 
    869   if (number && is_not_last_page(number) && cupsArrayLast(doc->pages) &&
    870       check_range(doc, (number - 1) / doc->number_up + 1))
    871   {
    872     pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
    873 
    874     start_nup(doc, doc->number_up, 0, doc->bounding_box);
    875     doc_puts(doc, "showpage\n");
    876     end_nup(doc, doc->number_up);
    877 
    878     pageinfo->length = (ssize_t)(cupsFileTell(doc->temp) - pageinfo->offset);
    879   }
    880 
    881   if (doc->slow_duplex && (doc->page & 1))
    882   {
    883    /*
    884     * Make sure we have an even number of pages...
    885     */
    886 
    887     pageinfo = add_page(doc, "(filler)");
    888 
    889     if (!doc->slow_order)
    890     {
    891       if (!ppd || !ppd->num_filters)
    892 	fprintf(stderr, "PAGE: %d %d\n", doc->page,
    893         	doc->slow_collate ? 1 : doc->copies);
    894 
    895       printf("%%%%Page: (filler) %d\n", doc->page);
    896     }
    897 
    898     start_nup(doc, doc->number_up, 0, doc->bounding_box);
    899     doc_puts(doc, "showpage\n");
    900     end_nup(doc, doc->number_up);
    901 
    902     pageinfo->length = (ssize_t)(cupsFileTell(doc->temp) - pageinfo->offset);
    903   }
    904 
    905  /*
    906   * Make additional copies as necessary...
    907   */
    908 
    909   number = doc->slow_order ? 0 : doc->page;
    910 
    911   if (doc->temp && !JobCanceled && cupsArrayCount(doc->pages) > 0)
    912   {
    913     int	copy;				/* Current copy */
    914 
    915 
    916    /*
    917     * Reopen the temporary file for reading...
    918     */
    919 
    920     cupsFileClose(doc->temp);
    921 
    922     doc->temp = cupsFileOpen(doc->tempfile, "r");
    923 
    924    /*
    925     * Make the copies...
    926     */
    927 
    928     if (doc->slow_collate)
    929       copy = !doc->slow_order;
    930     else
    931       copy = doc->copies - 1;
    932 
    933     for (; copy < doc->copies; copy ++)
    934     {
    935       if (JobCanceled)
    936 	break;
    937 
    938      /*
    939       * Send end-of-job stuff followed by any start-of-job stuff required
    940       * for the JCL options...
    941       */
    942 
    943       if (number && doc->emit_jcl && ppd && ppd->jcl_end)
    944       {
    945        /*
    946         * Send the trailer...
    947 	*/
    948 
    949         puts("%%Trailer");
    950 	printf("%%%%Pages: %d\n", cupsArrayCount(doc->pages));
    951 	if (doc->number_up > 1 || doc->fit_to_page)
    952 	  printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
    953 		 PageLeft, PageBottom, PageRight, PageTop);
    954 	else
    955 	  printf("%%%%BoundingBox: %d %d %d %d\n",
    956 		 doc->new_bounding_box[0], doc->new_bounding_box[1],
    957 		 doc->new_bounding_box[2], doc->new_bounding_box[3]);
    958         puts("%%EOF");
    959 
    960        /*
    961         * Start a new document...
    962 	*/
    963 
    964         ppdEmitJCLEnd(ppd, stdout);
    965         ppdEmitJCL(ppd, stdout, doc->job_id, doc->user, doc->title);
    966 
    967 	puts("%!PS-Adobe-3.0");
    968 
    969 	number = 0;
    970       }
    971 
    972      /*
    973       * Copy the prolog as needed...
    974       */
    975 
    976       if (!number)
    977       {
    978         pageinfo = (pstops_page_t *)cupsArrayFirst(doc->pages);
    979 	copy_bytes(doc->temp, 0, (size_t)pageinfo->offset);
    980       }
    981 
    982      /*
    983       * Then copy all of the pages...
    984       */
    985 
    986       pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayLast(doc->pages) :
    987                                    (pstops_page_t *)cupsArrayFirst(doc->pages);
    988 
    989       while (pageinfo)
    990       {
    991         if (JobCanceled)
    992 	  break;
    993 
    994         number ++;
    995 
    996 	if (!ppd || !ppd->num_filters)
    997 	  fprintf(stderr, "PAGE: %d %d\n", number,
    998 	          doc->slow_collate ? 1 : doc->copies);
    999 
   1000 	if (doc->number_up > 1)
   1001 	{
   1002 	  printf("%%%%Page: (%d) %d\n", number, number);
   1003 	  printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
   1004 		 PageLeft, PageBottom, PageRight, PageTop);
   1005 	}
   1006 	else
   1007 	{
   1008           printf("%%%%Page: %s %d\n", pageinfo->label, number);
   1009 	  printf("%%%%PageBoundingBox: %d %d %d %d\n",
   1010 		 pageinfo->bounding_box[0], pageinfo->bounding_box[1],
   1011 		 pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
   1012 	}
   1013 
   1014 	copy_bytes(doc->temp, pageinfo->offset, (size_t)pageinfo->length);
   1015 
   1016 	pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayPrev(doc->pages) :
   1017                                      (pstops_page_t *)cupsArrayNext(doc->pages);
   1018       }
   1019     }
   1020   }
   1021 
   1022  /*
   1023   * Restore the old showpage operator as needed...
   1024   */
   1025 
   1026   if (doc->use_ESPshowpage)
   1027     puts("userdict/showpage/ESPshowpage load put\n");
   1028 
   1029  /*
   1030   * Write/copy the trailer...
   1031   */
   1032 
   1033   if (!JobCanceled)
   1034     copy_trailer(fp, doc, ppd, number, line, linelen, linesize);
   1035 }
   1036 
   1037 
   1038 /*
   1039  * 'copy_non_dsc()' - Copy a document that does not conform to the DSC.
   1040  *
   1041  * This function expects "line" to be filled with the %! comment line.
   1042  */
   1043 
   1044 static void
   1045 copy_non_dsc(cups_file_t  *fp,		/* I - File to read from */
   1046              pstops_doc_t *doc,		/* I - Document info */
   1047              ppd_file_t   *ppd,		/* I - PPD file */
   1048 	     char         *line,	/* I - Line buffer */
   1049 	     ssize_t      linelen,	/* I - Length of initial line */
   1050 	     size_t       linesize)	/* I - Size of line buffer */
   1051 {
   1052   int		copy;			/* Current copy */
   1053   char		buffer[8192];		/* Copy buffer */
   1054   ssize_t	bytes;			/* Number of bytes copied */
   1055 
   1056 
   1057   (void)linesize;
   1058 
   1059  /*
   1060   * First let the user know that they are attempting to print a file
   1061   * that may not print correctly...
   1062   */
   1063 
   1064   fputs("DEBUG: This document does not conform to the Adobe Document "
   1065         "Structuring Conventions and may not print correctly.\n", stderr);
   1066 
   1067  /*
   1068   * Then write a standard DSC comment section...
   1069   */
   1070 
   1071   printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
   1072          PageRight, PageTop);
   1073 
   1074   if (doc->slow_collate && doc->copies > 1)
   1075     printf("%%%%Pages: %d\n", doc->copies);
   1076   else
   1077     puts("%%Pages: 1");
   1078 
   1079   WriteTextComment("For", doc->user);
   1080   WriteTextComment("Title", doc->title);
   1081 
   1082   if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
   1083   {
   1084    /*
   1085     * Tell the document processor the copy and duplex options
   1086     * that are required...
   1087     */
   1088 
   1089     printf("%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
   1090            doc->collate ? " collate" : "",
   1091 	   Duplex ? " duplex" : "");
   1092 
   1093    /*
   1094     * Apple uses RBI comments for various non-PPD options...
   1095     */
   1096 
   1097     printf("%%RBINumCopies: %d\n", doc->copies);
   1098   }
   1099   else
   1100   {
   1101    /*
   1102     * Tell the document processor the duplex option that is required...
   1103     */
   1104 
   1105     if (Duplex)
   1106       puts("%%Requirements: duplex");
   1107 
   1108    /*
   1109     * Apple uses RBI comments for various non-PPD options...
   1110     */
   1111 
   1112     puts("%RBINumCopies: 1");
   1113   }
   1114 
   1115   puts("%%EndComments");
   1116 
   1117  /*
   1118   * Then the prolog...
   1119   */
   1120 
   1121   puts("%%BeginProlog");
   1122 
   1123   do_prolog(doc, ppd);
   1124 
   1125   puts("%%EndProlog");
   1126 
   1127  /*
   1128   * Then the setup section...
   1129   */
   1130 
   1131   puts("%%BeginSetup");
   1132 
   1133   do_setup(doc, ppd);
   1134 
   1135   puts("%%EndSetup");
   1136 
   1137  /*
   1138   * Finally, embed a copy of the file inside a %%Page...
   1139   */
   1140 
   1141   if (!ppd || !ppd->num_filters)
   1142     fprintf(stderr, "PAGE: 1 %d\n", doc->temp ? 1 : doc->copies);
   1143 
   1144   puts("%%Page: 1 1");
   1145   puts("%%BeginPageSetup");
   1146   ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
   1147   puts("%%EndPageSetup");
   1148   puts("%%BeginDocument: nondsc");
   1149 
   1150   fwrite(line, (size_t)linelen, 1, stdout);
   1151 
   1152   if (doc->temp)
   1153     cupsFileWrite(doc->temp, line, (size_t)linelen);
   1154 
   1155   while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
   1156   {
   1157     fwrite(buffer, 1, (size_t)bytes, stdout);
   1158 
   1159     if (doc->temp)
   1160       cupsFileWrite(doc->temp, buffer, (size_t)bytes);
   1161   }
   1162 
   1163   puts("%%EndDocument");
   1164 
   1165   if (doc->use_ESPshowpage)
   1166   {
   1167     WriteLabels(Orientation);
   1168     puts("ESPshowpage");
   1169   }
   1170 
   1171   if (doc->temp && !JobCanceled)
   1172   {
   1173    /*
   1174     * Reopen the temporary file for reading...
   1175     */
   1176 
   1177     cupsFileClose(doc->temp);
   1178 
   1179     doc->temp = cupsFileOpen(doc->tempfile, "r");
   1180 
   1181    /*
   1182     * Make the additional copies as needed...
   1183     */
   1184 
   1185     for (copy = 1; copy < doc->copies; copy ++)
   1186     {
   1187       if (JobCanceled)
   1188 	break;
   1189 
   1190       if (!ppd || !ppd->num_filters)
   1191 	fputs("PAGE: 1 1\n", stderr);
   1192 
   1193       printf("%%%%Page: %d %d\n", copy + 1, copy + 1);
   1194       puts("%%BeginPageSetup");
   1195       ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
   1196       puts("%%EndPageSetup");
   1197       puts("%%BeginDocument: nondsc");
   1198 
   1199       copy_bytes(doc->temp, 0, 0);
   1200 
   1201       puts("%%EndDocument");
   1202 
   1203       if (doc->use_ESPshowpage)
   1204       {
   1205 	WriteLabels(Orientation);
   1206         puts("ESPshowpage");
   1207       }
   1208     }
   1209   }
   1210 
   1211  /*
   1212   * Restore the old showpage operator as needed...
   1213   */
   1214 
   1215   if (doc->use_ESPshowpage)
   1216     puts("userdict/showpage/ESPshowpage load put\n");
   1217 }
   1218 
   1219 
   1220 /*
   1221  * 'copy_page()' - Copy a page description.
   1222  *
   1223  * This function expects "line" to be filled with a %%Page comment line.
   1224  * On return, "line" will contain the next line in the file, if any.
   1225  */
   1226 
   1227 static ssize_t				/* O - Length of next line */
   1228 copy_page(cups_file_t  *fp,		/* I - File to read from */
   1229           pstops_doc_t *doc,		/* I - Document info */
   1230           ppd_file_t   *ppd,		/* I - PPD file */
   1231 	  int          number,		/* I - Current page number */
   1232 	  char         *line,		/* I - Line buffer */
   1233 	  ssize_t      linelen,		/* I - Length of initial line */
   1234 	  size_t       linesize)	/* I - Size of line buffer */
   1235 {
   1236   char		label[256],		/* Page label string */
   1237 		*ptr;			/* Pointer into line */
   1238   int		level;			/* Embedded document level */
   1239   pstops_page_t	*pageinfo;		/* Page information */
   1240   int		first_page;		/* First page on N-up output? */
   1241   int		has_page_setup = 0;	/* Does the page have %%Begin/EndPageSetup? */
   1242   int		bounding_box[4];	/* PageBoundingBox */
   1243 
   1244 
   1245  /*
   1246   * Get the page label for this page...
   1247   */
   1248 
   1249   first_page = is_first_page(number);
   1250 
   1251   if (!parse_text(line + 7, &ptr, label, sizeof(label)))
   1252   {
   1253     fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr);
   1254     label[0] = '\0';
   1255     number   = doc->page;
   1256   }
   1257   else if (strtol(ptr, &ptr, 10) == LONG_MAX || !isspace(*ptr & 255))
   1258   {
   1259     fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr);
   1260     number = doc->page;
   1261   }
   1262 
   1263  /*
   1264   * Create or update the current output page...
   1265   */
   1266 
   1267   if (first_page)
   1268     pageinfo = add_page(doc, label);
   1269   else
   1270     pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
   1271 
   1272  /*
   1273   * Handle first page override...
   1274   */
   1275 
   1276   if (doc->ap_input_slot || doc->ap_manual_feed)
   1277   {
   1278     if ((doc->page == 1 && (!doc->slow_order || !Duplex)) ||
   1279         (doc->page == 2 && doc->slow_order && Duplex))
   1280     {
   1281      /*
   1282       * First page/sheet gets AP_FIRSTPAGE_* options...
   1283       */
   1284 
   1285       pageinfo->num_options = cupsAddOption("InputSlot", doc->ap_input_slot,
   1286                                             pageinfo->num_options,
   1287 					    &(pageinfo->options));
   1288       pageinfo->num_options = cupsAddOption("ManualFeed",
   1289                                             doc->ap_input_slot ? "False" :
   1290 					        doc->ap_manual_feed,
   1291                                             pageinfo->num_options,
   1292 					    &(pageinfo->options));
   1293       pageinfo->num_options = cupsAddOption("MediaColor", doc->ap_media_color,
   1294                                             pageinfo->num_options,
   1295 					    &(pageinfo->options));
   1296       pageinfo->num_options = cupsAddOption("MediaType", doc->ap_media_type,
   1297                                             pageinfo->num_options,
   1298 					    &(pageinfo->options));
   1299       pageinfo->num_options = cupsAddOption("PageRegion", doc->ap_page_region,
   1300                                             pageinfo->num_options,
   1301 					    &(pageinfo->options));
   1302       pageinfo->num_options = cupsAddOption("PageSize", doc->ap_page_size,
   1303                                             pageinfo->num_options,
   1304 					    &(pageinfo->options));
   1305     }
   1306     else if (doc->page == (Duplex + 2))
   1307     {
   1308      /*
   1309       * Second page/sheet gets default options...
   1310       */
   1311 
   1312       pageinfo->num_options = cupsAddOption("InputSlot", doc->input_slot,
   1313                                             pageinfo->num_options,
   1314 					    &(pageinfo->options));
   1315       pageinfo->num_options = cupsAddOption("ManualFeed",
   1316                                             doc->input_slot ? "False" :
   1317 					        doc->manual_feed,
   1318                                             pageinfo->num_options,
   1319 					    &(pageinfo->options));
   1320       pageinfo->num_options = cupsAddOption("MediaColor", doc->media_color,
   1321                                             pageinfo->num_options,
   1322 					    &(pageinfo->options));
   1323       pageinfo->num_options = cupsAddOption("MediaType", doc->media_type,
   1324                                             pageinfo->num_options,
   1325 					    &(pageinfo->options));
   1326       pageinfo->num_options = cupsAddOption("PageRegion", doc->page_region,
   1327                                             pageinfo->num_options,
   1328 					    &(pageinfo->options));
   1329       pageinfo->num_options = cupsAddOption("PageSize", doc->page_size,
   1330                                             pageinfo->num_options,
   1331 					    &(pageinfo->options));
   1332     }
   1333   }
   1334 
   1335  /*
   1336   * Scan comments until we see something other than %%Page*: or
   1337   * %%Include*...
   1338   */
   1339 
   1340   memcpy(bounding_box, doc->bounding_box, sizeof(bounding_box));
   1341 
   1342   while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
   1343   {
   1344     if (!strncmp(line, "%%PageBoundingBox:", 18))
   1345     {
   1346      /*
   1347       * %%PageBoundingBox: llx lly urx ury
   1348       */
   1349 
   1350       if (sscanf(line + 18, "%d%d%d%d", bounding_box + 0,
   1351                  bounding_box + 1, bounding_box + 2,
   1352 		 bounding_box + 3) != 4)
   1353       {
   1354 	fputs("DEBUG: There was a bad %%PageBoundingBox: comment in the file.\n", stderr);
   1355         memcpy(bounding_box, doc->bounding_box,
   1356 	       sizeof(bounding_box));
   1357       }
   1358       else if (doc->number_up == 1 && !doc->fit_to_page  && Orientation)
   1359       {
   1360         int	temp_bbox[4];		/* Temporary bounding box */
   1361 
   1362 
   1363         memcpy(temp_bbox, bounding_box, sizeof(temp_bbox));
   1364 
   1365         fprintf(stderr, "DEBUG: Orientation = %d\n", Orientation);
   1366         fprintf(stderr, "DEBUG: original bounding_box = [ %d %d %d %d ]\n",
   1367 		bounding_box[0], bounding_box[1],
   1368 		bounding_box[2], bounding_box[3]);
   1369         fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n",
   1370 	        PageWidth, PageLength);
   1371 
   1372         switch (Orientation)
   1373 	{
   1374 	  case 1 : /* Landscape */
   1375 	      bounding_box[0] = (int)(PageLength - temp_bbox[3]);
   1376 	      bounding_box[1] = temp_bbox[0];
   1377 	      bounding_box[2] = (int)(PageLength - temp_bbox[1]);
   1378 	      bounding_box[3] = temp_bbox[2];
   1379               break;
   1380 
   1381 	  case 2 : /* Reverse Portrait */
   1382 	      bounding_box[0] = (int)(PageWidth - temp_bbox[2]);
   1383 	      bounding_box[1] = (int)(PageLength - temp_bbox[3]);
   1384 	      bounding_box[2] = (int)(PageWidth - temp_bbox[0]);
   1385 	      bounding_box[3] = (int)(PageLength - temp_bbox[1]);
   1386               break;
   1387 
   1388 	  case 3 : /* Reverse Landscape */
   1389 	      bounding_box[0] = temp_bbox[1];
   1390 	      bounding_box[1] = (int)(PageWidth - temp_bbox[2]);
   1391 	      bounding_box[2] = temp_bbox[3];
   1392 	      bounding_box[3] = (int)(PageWidth - temp_bbox[0]);
   1393               break;
   1394 	}
   1395 
   1396         fprintf(stderr, "DEBUG: updated bounding_box = [ %d %d %d %d ]\n",
   1397 		bounding_box[0], bounding_box[1],
   1398 		bounding_box[2], bounding_box[3]);
   1399       }
   1400     }
   1401 #if 0
   1402     else if (!strncmp(line, "%%PageCustomColors:", 19) ||
   1403              !strncmp(line, "%%PageMedia:", 12) ||
   1404 	     !strncmp(line, "%%PageOrientation:", 18) ||
   1405 	     !strncmp(line, "%%PageProcessColors:", 20) ||
   1406 	     !strncmp(line, "%%PageRequirements:", 18) ||
   1407 	     !strncmp(line, "%%PageResources:", 16))
   1408     {
   1409      /*
   1410       * Copy literal...
   1411       */
   1412     }
   1413 #endif /* 0 */
   1414     else if (!strncmp(line, "%%PageCustomColors:", 19))
   1415     {
   1416      /*
   1417       * %%PageCustomColors: ...
   1418       */
   1419     }
   1420     else if (!strncmp(line, "%%PageMedia:", 12))
   1421     {
   1422      /*
   1423       * %%PageMedia: ...
   1424       */
   1425     }
   1426     else if (!strncmp(line, "%%PageOrientation:", 18))
   1427     {
   1428      /*
   1429       * %%PageOrientation: ...
   1430       */
   1431     }
   1432     else if (!strncmp(line, "%%PageProcessColors:", 20))
   1433     {
   1434      /*
   1435       * %%PageProcessColors: ...
   1436       */
   1437     }
   1438     else if (!strncmp(line, "%%PageRequirements:", 18))
   1439     {
   1440      /*
   1441       * %%PageRequirements: ...
   1442       */
   1443     }
   1444     else if (!strncmp(line, "%%PageResources:", 16))
   1445     {
   1446      /*
   1447       * %%PageResources: ...
   1448       */
   1449     }
   1450     else if (!strncmp(line, "%%IncludeFeature:", 17))
   1451     {
   1452      /*
   1453       * %%IncludeFeature: *MainKeyword OptionKeyword
   1454       */
   1455 
   1456       if (doc->number_up == 1 &&!doc->fit_to_page)
   1457 	pageinfo->num_options = include_feature(ppd, line,
   1458 	                                        pageinfo->num_options,
   1459                                         	&(pageinfo->options));
   1460     }
   1461     else if (!strncmp(line, "%%BeginPageSetup", 16))
   1462     {
   1463       has_page_setup = 1;
   1464       break;
   1465     }
   1466     else
   1467       break;
   1468   }
   1469 
   1470   if (doc->number_up == 1)
   1471   {
   1472    /*
   1473     * Update the document's composite and page bounding box...
   1474     */
   1475 
   1476     memcpy(pageinfo->bounding_box, bounding_box,
   1477            sizeof(pageinfo->bounding_box));
   1478 
   1479     if (bounding_box[0] < doc->new_bounding_box[0])
   1480       doc->new_bounding_box[0] = bounding_box[0];
   1481     if (bounding_box[1] < doc->new_bounding_box[1])
   1482       doc->new_bounding_box[1] = bounding_box[1];
   1483     if (bounding_box[2] > doc->new_bounding_box[2])
   1484       doc->new_bounding_box[2] = bounding_box[2];
   1485     if (bounding_box[3] > doc->new_bounding_box[3])
   1486       doc->new_bounding_box[3] = bounding_box[3];
   1487   }
   1488 
   1489  /*
   1490   * Output the page header as needed...
   1491   */
   1492 
   1493   if (!doc->slow_order && first_page)
   1494   {
   1495     if (!ppd || !ppd->num_filters)
   1496       fprintf(stderr, "PAGE: %d %d\n", doc->page,
   1497 	      doc->slow_collate ? 1 : doc->copies);
   1498 
   1499     if (doc->number_up > 1)
   1500     {
   1501       printf("%%%%Page: (%d) %d\n", doc->page, doc->page);
   1502       printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
   1503 	     PageLeft, PageBottom, PageRight, PageTop);
   1504     }
   1505     else
   1506     {
   1507       printf("%%%%Page: %s %d\n", pageinfo->label, doc->page);
   1508       printf("%%%%PageBoundingBox: %d %d %d %d\n",
   1509 	     pageinfo->bounding_box[0], pageinfo->bounding_box[1],
   1510 	     pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
   1511     }
   1512   }
   1513 
   1514  /*
   1515   * Copy any page setup commands...
   1516   */
   1517 
   1518   if (first_page)
   1519     doc_puts(doc, "%%BeginPageSetup\n");
   1520 
   1521   if (has_page_setup)
   1522   {
   1523     int	feature = 0;			/* In a Begin/EndFeature block? */
   1524 
   1525     while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
   1526     {
   1527       if (!strncmp(line, "%%EndPageSetup", 14))
   1528 	break;
   1529       else if (!strncmp(line, "%%BeginFeature:", 15))
   1530       {
   1531 	feature = 1;
   1532 
   1533 	if (doc->number_up > 1 || doc->fit_to_page)
   1534 	  continue;
   1535       }
   1536       else if (!strncmp(line, "%%EndFeature", 12))
   1537       {
   1538 	feature = 0;
   1539 
   1540 	if (doc->number_up > 1 || doc->fit_to_page)
   1541 	  continue;
   1542       }
   1543       else if (!strncmp(line, "%%IncludeFeature:", 17))
   1544       {
   1545 	pageinfo->num_options = include_feature(ppd, line,
   1546 						pageinfo->num_options,
   1547 						&(pageinfo->options));
   1548 	continue;
   1549       }
   1550       else if (!strncmp(line, "%%Include", 9))
   1551 	continue;
   1552 
   1553       if (line[0] != '%' && !feature)
   1554         break;
   1555 
   1556       if (!feature || (doc->number_up == 1 && !doc->fit_to_page))
   1557 	doc_write(doc, line, (size_t)linelen);
   1558     }
   1559 
   1560    /*
   1561     * Skip %%EndPageSetup...
   1562     */
   1563 
   1564     if (linelen > 0 && !strncmp(line, "%%EndPageSetup", 14))
   1565       linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
   1566   }
   1567 
   1568   if (first_page)
   1569   {
   1570     char	*page_setup;		/* PageSetup commands to send */
   1571 
   1572 
   1573     if (pageinfo->num_options > 0)
   1574       write_options(doc, ppd, pageinfo->num_options, pageinfo->options);
   1575 
   1576    /*
   1577     * Output commands for the current page...
   1578     */
   1579 
   1580     page_setup = ppdEmitString(ppd, PPD_ORDER_PAGE, 0);
   1581 
   1582     if (page_setup)
   1583     {
   1584       doc_puts(doc, page_setup);
   1585       free(page_setup);
   1586     }
   1587   }
   1588 
   1589  /*
   1590   * Prep for the start of the page description...
   1591   */
   1592 
   1593   start_nup(doc, number, 1, bounding_box);
   1594 
   1595   if (first_page)
   1596     doc_puts(doc, "%%EndPageSetup\n");
   1597 
   1598  /*
   1599   * Read the rest of the page description...
   1600   */
   1601 
   1602   level = 0;
   1603 
   1604   do
   1605   {
   1606     if (level == 0 &&
   1607         (!strncmp(line, "%%Page:", 7) ||
   1608 	 !strncmp(line, "%%Trailer", 9) ||
   1609 	 !strncmp(line, "%%EOF", 5)))
   1610       break;
   1611     else if (!strncmp(line, "%%BeginDocument", 15) ||
   1612 	     !strncmp(line, "%ADO_BeginApplication", 21))
   1613     {
   1614       doc_write(doc, line, (size_t)linelen);
   1615 
   1616       level ++;
   1617     }
   1618     else if ((!strncmp(line, "%%EndDocument", 13) ||
   1619 	      !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
   1620     {
   1621       doc_write(doc, line, (size_t)linelen);
   1622 
   1623       level --;
   1624     }
   1625     else if (!strncmp(line, "%%BeginBinary:", 14) ||
   1626              (!strncmp(line, "%%BeginData:", 12) &&
   1627 	      !strstr(line, "ASCII") && !strstr(line, "Hex")))
   1628     {
   1629      /*
   1630       * Copy binary data...
   1631       */
   1632 
   1633       int	bytes;			/* Bytes of data */
   1634 
   1635 
   1636       doc_write(doc, line, (size_t)linelen);
   1637 
   1638       bytes = atoi(strchr(line, ':') + 1);
   1639 
   1640       while (bytes > 0)
   1641       {
   1642 	if ((size_t)bytes > linesize)
   1643 	  linelen = cupsFileRead(fp, line, linesize);
   1644 	else
   1645 	  linelen = cupsFileRead(fp, line, (size_t)bytes);
   1646 
   1647 	if (linelen < 1)
   1648 	{
   1649 	  line[0] = '\0';
   1650 	  perror("ERROR: Early end-of-file while reading binary data");
   1651 	  return (0);
   1652 	}
   1653 
   1654         doc_write(doc, line, (size_t)linelen);
   1655 
   1656 	bytes -= linelen;
   1657       }
   1658     }
   1659     else
   1660       doc_write(doc, line, (size_t)linelen);
   1661   }
   1662   while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0);
   1663 
   1664  /*
   1665   * Finish up this page and return...
   1666   */
   1667 
   1668   end_nup(doc, number);
   1669 
   1670   pageinfo->length = (ssize_t)(cupsFileTell(doc->temp) - pageinfo->offset);
   1671 
   1672   return (linelen);
   1673 }
   1674 
   1675 
   1676 /*
   1677  * 'copy_prolog()' - Copy the document prolog section.
   1678  *
   1679  * This function expects "line" to be filled with a %%BeginProlog comment line.
   1680  * On return, "line" will contain the next line in the file, if any.
   1681  */
   1682 
   1683 static ssize_t				/* O - Length of next line */
   1684 copy_prolog(cups_file_t  *fp,		/* I - File to read from */
   1685             pstops_doc_t *doc,		/* I - Document info */
   1686             ppd_file_t   *ppd,		/* I - PPD file */
   1687 	    char         *line,		/* I - Line buffer */
   1688 	    ssize_t      linelen,	/* I - Length of initial line */
   1689 	    size_t       linesize)	/* I - Size of line buffer */
   1690 {
   1691   while (strncmp(line, "%%BeginProlog", 13))
   1692   {
   1693     if (!strncmp(line, "%%BeginSetup", 12) || !strncmp(line, "%%Page:", 7))
   1694       break;
   1695 
   1696     doc_write(doc, line, (size_t)linelen);
   1697 
   1698     if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
   1699       break;
   1700   }
   1701 
   1702   doc_puts(doc, "%%BeginProlog\n");
   1703 
   1704   do_prolog(doc, ppd);
   1705 
   1706   if (!strncmp(line, "%%BeginProlog", 13))
   1707   {
   1708     while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
   1709     {
   1710       if (!strncmp(line, "%%EndProlog", 11) ||
   1711           !strncmp(line, "%%BeginSetup", 12) ||
   1712           !strncmp(line, "%%Page:", 7))
   1713         break;
   1714 
   1715       doc_write(doc, line, (size_t)linelen);
   1716     }
   1717 
   1718     if (!strncmp(line, "%%EndProlog", 11))
   1719       linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
   1720     else
   1721       fputs("DEBUG: The %%EndProlog comment is missing.\n", stderr);
   1722   }
   1723 
   1724   doc_puts(doc, "%%EndProlog\n");
   1725 
   1726   return (linelen);
   1727 }
   1728 
   1729 
   1730 /*
   1731  * 'copy_setup()' - Copy the document setup section.
   1732  *
   1733  * This function expects "line" to be filled with a %%BeginSetup comment line.
   1734  * On return, "line" will contain the next line in the file, if any.
   1735  */
   1736 
   1737 static ssize_t				/* O - Length of next line */
   1738 copy_setup(cups_file_t  *fp,		/* I - File to read from */
   1739            pstops_doc_t *doc,		/* I - Document info */
   1740            ppd_file_t   *ppd,		/* I - PPD file */
   1741 	   char         *line,		/* I - Line buffer */
   1742 	   ssize_t      linelen,	/* I - Length of initial line */
   1743 	   size_t       linesize)	/* I - Size of line buffer */
   1744 {
   1745   int		num_options;		/* Number of options */
   1746   cups_option_t	*options;		/* Options */
   1747 
   1748 
   1749   while (strncmp(line, "%%BeginSetup", 12))
   1750   {
   1751     if (!strncmp(line, "%%Page:", 7))
   1752       break;
   1753 
   1754     doc_write(doc, line, (size_t)linelen);
   1755 
   1756     if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
   1757       break;
   1758   }
   1759 
   1760   doc_puts(doc, "%%BeginSetup\n");
   1761 
   1762   do_setup(doc, ppd);
   1763 
   1764   num_options = 0;
   1765   options     = NULL;
   1766 
   1767   if (!strncmp(line, "%%BeginSetup", 12))
   1768   {
   1769     while (strncmp(line, "%%EndSetup", 10))
   1770     {
   1771       if (!strncmp(line, "%%Page:", 7))
   1772         break;
   1773       else if (!strncmp(line, "%%IncludeFeature:", 17))
   1774       {
   1775        /*
   1776 	* %%IncludeFeature: *MainKeyword OptionKeyword
   1777 	*/
   1778 
   1779         if (doc->number_up == 1 && !doc->fit_to_page)
   1780 	  num_options = include_feature(ppd, line, num_options, &options);
   1781       }
   1782       else if (strncmp(line, "%%BeginSetup", 12))
   1783         doc_write(doc, line, (size_t)linelen);
   1784 
   1785       if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
   1786 	break;
   1787     }
   1788 
   1789     if (!strncmp(line, "%%EndSetup", 10))
   1790       linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
   1791     else
   1792       fputs("DEBUG: The %%EndSetup comment is missing.\n", stderr);
   1793   }
   1794 
   1795   if (num_options > 0)
   1796   {
   1797     write_options(doc, ppd, num_options, options);
   1798     cupsFreeOptions(num_options, options);
   1799   }
   1800 
   1801   doc_puts(doc, "%%EndSetup\n");
   1802 
   1803   return (linelen);
   1804 }
   1805 
   1806 
   1807 /*
   1808  * 'copy_trailer()' - Copy the document trailer.
   1809  *
   1810  * This function expects "line" to be filled with a %%Trailer comment line.
   1811  * On return, "line" will contain the next line in the file, if any.
   1812  */
   1813 
   1814 static ssize_t				/* O - Length of next line */
   1815 copy_trailer(cups_file_t  *fp,		/* I - File to read from */
   1816              pstops_doc_t *doc,		/* I - Document info */
   1817              ppd_file_t   *ppd,		/* I - PPD file */
   1818 	     int          number,	/* I - Number of pages */
   1819 	     char         *line,	/* I - Line buffer */
   1820 	     ssize_t      linelen,	/* I - Length of initial line */
   1821 	     size_t       linesize)	/* I - Size of line buffer */
   1822 {
   1823  /*
   1824   * Write the trailer comments...
   1825   */
   1826 
   1827   (void)ppd;
   1828 
   1829   puts("%%Trailer");
   1830 
   1831   while (linelen > 0)
   1832   {
   1833     if (!strncmp(line, "%%EOF", 5))
   1834       break;
   1835     else if (strncmp(line, "%%Trailer", 9) &&
   1836              strncmp(line, "%%Pages:", 8) &&
   1837              strncmp(line, "%%BoundingBox:", 14))
   1838       fwrite(line, 1, (size_t)linelen, stdout);
   1839 
   1840     linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
   1841   }
   1842 
   1843   fprintf(stderr, "DEBUG: Wrote %d pages...\n", number);
   1844 
   1845   printf("%%%%Pages: %d\n", number);
   1846   if (doc->number_up > 1 || doc->fit_to_page)
   1847     printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
   1848 	   PageLeft, PageBottom, PageRight, PageTop);
   1849   else
   1850     printf("%%%%BoundingBox: %d %d %d %d\n",
   1851 	   doc->new_bounding_box[0], doc->new_bounding_box[1],
   1852 	   doc->new_bounding_box[2], doc->new_bounding_box[3]);
   1853 
   1854   return (linelen);
   1855 }
   1856 
   1857 
   1858 /*
   1859  * 'do_prolog()' - Send the necessary document prolog commands.
   1860  */
   1861 
   1862 static void
   1863 do_prolog(pstops_doc_t *doc,		/* I - Document information */
   1864           ppd_file_t   *ppd)		/* I - PPD file */
   1865 {
   1866   char	*ps;				/* PS commands */
   1867 
   1868 
   1869  /*
   1870   * Send the document prolog commands...
   1871   */
   1872 
   1873   if (ppd && ppd->patches)
   1874   {
   1875     doc_puts(doc, "%%BeginFeature: *JobPatchFile 1\n");
   1876     doc_puts(doc, ppd->patches);
   1877     doc_puts(doc, "\n%%EndFeature\n");
   1878   }
   1879 
   1880   if ((ps = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL)
   1881   {
   1882     doc_puts(doc, ps);
   1883     free(ps);
   1884   }
   1885 
   1886  /*
   1887   * Define ESPshowpage here so that applications that define their
   1888   * own procedure to do a showpage pick it up...
   1889   */
   1890 
   1891   if (doc->use_ESPshowpage)
   1892     doc_puts(doc, "userdict/ESPshowpage/showpage load put\n"
   1893 	          "userdict/showpage{}put\n");
   1894 }
   1895 
   1896 
   1897 /*
   1898  * 'do_setup()' - Send the necessary document setup commands.
   1899  */
   1900 
   1901 static void
   1902 do_setup(pstops_doc_t *doc,		/* I - Document information */
   1903          ppd_file_t   *ppd)		/* I - PPD file */
   1904 {
   1905   char	*ps;				/* PS commands */
   1906 
   1907 
   1908  /*
   1909   * Disable CTRL-D so that embedded files don't cause printing
   1910   * errors...
   1911   */
   1912 
   1913   doc_puts(doc, "% Disable CTRL-D as an end-of-file marker...\n");
   1914   doc_puts(doc, "userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
   1915 
   1916  /*
   1917   * Mark job options...
   1918   */
   1919 
   1920   cupsMarkOptions(ppd, doc->num_options, doc->options);
   1921 
   1922  /*
   1923   * Send all the printer-specific setup commands...
   1924   */
   1925 
   1926   if ((ps = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL)
   1927   {
   1928     doc_puts(doc, ps);
   1929     free(ps);
   1930   }
   1931 
   1932   if ((ps = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL)
   1933   {
   1934     doc_puts(doc, ps);
   1935     free(ps);
   1936   }
   1937 
   1938  /*
   1939   * Set the number of copies for the job...
   1940   */
   1941 
   1942   if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
   1943   {
   1944     doc_printf(doc, "%%RBIBeginNonPPDFeature: *NumCopies %d\n", doc->copies);
   1945     doc_printf(doc,
   1946                "%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n"
   1947                "{1 dict begin/NumCopies exch def currentdict end "
   1948 	       "setpagedevice}\n"
   1949 	       "{userdict/#copies 3 -1 roll put}ifelse\n", doc->copies);
   1950     doc_puts(doc, "%RBIEndNonPPDFeature\n");
   1951   }
   1952 
   1953  /*
   1954   * If we are doing N-up printing, disable setpagedevice...
   1955   */
   1956 
   1957   if (doc->number_up > 1)
   1958   {
   1959     doc_puts(doc, "userdict/CUPSsetpagedevice/setpagedevice load put\n");
   1960     doc_puts(doc, "userdict/setpagedevice{pop}bind put\n");
   1961   }
   1962 
   1963  /*
   1964   * Make sure we have rectclip and rectstroke procedures of some sort...
   1965   */
   1966 
   1967   doc_puts(doc,
   1968            "% x y w h ESPrc - Clip to a rectangle.\n"
   1969 	   "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
   1970 	   "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
   1971 	   "neg 0 rlineto closepath clip newpath}bind}ifelse put\n");
   1972 
   1973   doc_puts(doc,
   1974            "% x y w h ESPrf - Fill a rectangle.\n"
   1975 	   "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
   1976 	   "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
   1977 	   "neg 0 rlineto closepath fill grestore}bind}ifelse put\n");
   1978 
   1979   doc_puts(doc,
   1980            "% x y w h ESPrs - Stroke a rectangle.\n"
   1981 	   "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
   1982 	   "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
   1983 	   "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n");
   1984 
   1985  /*
   1986   * Write the page and label prologs...
   1987   */
   1988 
   1989   if (doc->number_up == 2 || doc->number_up == 6)
   1990   {
   1991    /*
   1992     * For 2- and 6-up output, rotate the labels to match the orientation
   1993     * of the pages...
   1994     */
   1995 
   1996     if (Orientation & 1)
   1997       write_label_prolog(doc, doc->page_label, PageBottom,
   1998                          PageWidth - PageLength + PageTop, PageLength);
   1999     else
   2000       write_label_prolog(doc, doc->page_label, PageLeft, PageRight,
   2001                          PageLength);
   2002   }
   2003   else
   2004     write_label_prolog(doc, doc->page_label, PageBottom, PageTop, PageWidth);
   2005 }
   2006 
   2007 
   2008 /*
   2009  * 'doc_printf()' - Send a formatted string to stdout and/or the temp file.
   2010  *
   2011  * This function should be used for all page-level output that is affected
   2012  * by ordering, collation, etc.
   2013  */
   2014 
   2015 static void
   2016 doc_printf(pstops_doc_t *doc,		/* I - Document information */
   2017            const char   *format,	/* I - Printf-style format string */
   2018 	   ...)				/* I - Additional arguments as needed */
   2019 {
   2020   va_list	ap;			/* Pointer to arguments */
   2021   char		buffer[1024];		/* Output buffer */
   2022   ssize_t	bytes;			/* Number of bytes to write */
   2023 
   2024 
   2025   va_start(ap, format);
   2026   bytes = vsnprintf(buffer, sizeof(buffer), format, ap);
   2027   va_end(ap);
   2028 
   2029   if ((size_t)bytes > sizeof(buffer))
   2030   {
   2031     _cupsLangPrintFilter(stderr, "ERROR",
   2032                          _("Buffer overflow detected, aborting."));
   2033     exit(1);
   2034   }
   2035 
   2036   doc_write(doc, buffer, (size_t)bytes);
   2037 }
   2038 
   2039 
   2040 /*
   2041  * 'doc_puts()' - Send a nul-terminated string to stdout and/or the temp file.
   2042  *
   2043  * This function should be used for all page-level output that is affected
   2044  * by ordering, collation, etc.
   2045  */
   2046 
   2047 static void
   2048 doc_puts(pstops_doc_t *doc,		/* I - Document information */
   2049          const char   *s)		/* I - String to send */
   2050 {
   2051   doc_write(doc, s, strlen(s));
   2052 }
   2053 
   2054 
   2055 /*
   2056  * 'doc_write()' - Send data to stdout and/or the temp file.
   2057  */
   2058 
   2059 static void
   2060 doc_write(pstops_doc_t *doc,		/* I - Document information */
   2061           const char   *s,		/* I - Data to send */
   2062 	  size_t       len)		/* I - Number of bytes to send */
   2063 {
   2064   if (!doc->slow_order)
   2065     fwrite(s, 1, len, stdout);
   2066 
   2067   if (doc->temp)
   2068     cupsFileWrite(doc->temp, s, len);
   2069 }
   2070 
   2071 
   2072 /*
   2073  * 'end_nup()' - End processing for N-up printing.
   2074  */
   2075 
   2076 static void
   2077 end_nup(pstops_doc_t *doc,		/* I - Document information */
   2078         int          number)		/* I - Page number */
   2079 {
   2080   if (doc->number_up > 1)
   2081     doc_puts(doc, "userdict/ESPsave get restore\n");
   2082 
   2083   switch (doc->number_up)
   2084   {
   2085     case 1 :
   2086 	if (doc->use_ESPshowpage)
   2087 	{
   2088 	  write_labels(doc, Orientation);
   2089           doc_puts(doc, "ESPshowpage\n");
   2090 	}
   2091 	break;
   2092 
   2093     case 2 :
   2094     case 6 :
   2095 	if (is_last_page(number) && doc->use_ESPshowpage)
   2096 	{
   2097 	  if (Orientation & 1)
   2098 	  {
   2099 	   /*
   2100 	    * Rotate the labels back to portrait...
   2101 	    */
   2102 
   2103 	    write_labels(doc, Orientation - 1);
   2104 	  }
   2105 	  else if (Orientation == 0)
   2106 	  {
   2107 	   /*
   2108 	    * Rotate the labels to landscape...
   2109 	    */
   2110 
   2111 	    write_labels(doc, doc->normal_landscape ? 1 : 3);
   2112 	  }
   2113 	  else
   2114 	  {
   2115 	   /*
   2116 	    * Rotate the labels to landscape...
   2117 	    */
   2118 
   2119 	    write_labels(doc, doc->normal_landscape ? 3 : 1);
   2120 	  }
   2121 
   2122           doc_puts(doc, "ESPshowpage\n");
   2123 	}
   2124         break;
   2125 
   2126     default :
   2127 	if (is_last_page(number) && doc->use_ESPshowpage)
   2128 	{
   2129 	  write_labels(doc, Orientation);
   2130           doc_puts(doc, "ESPshowpage\n");
   2131 	}
   2132         break;
   2133   }
   2134 
   2135   fflush(stdout);
   2136 }
   2137 
   2138 
   2139 /*
   2140  * 'include_feature()' - Include a printer option/feature command.
   2141  */
   2142 
   2143 static int				/* O  - New number of options */
   2144 include_feature(
   2145     ppd_file_t    *ppd,			/* I  - PPD file */
   2146     const char    *line,		/* I  - DSC line */
   2147     int           num_options,		/* I  - Number of options */
   2148     cups_option_t **options)		/* IO - Options */
   2149 {
   2150   char		name[255],		/* Option name */
   2151 		value[255];		/* Option value */
   2152   ppd_option_t	*option;		/* Option in file */
   2153 
   2154 
   2155  /*
   2156   * Get the "%%IncludeFeature: *Keyword OptionKeyword" values...
   2157   */
   2158 
   2159   if (sscanf(line + 17, "%254s%254s", name, value) != 2)
   2160   {
   2161     fputs("DEBUG: The %%IncludeFeature: comment is not valid.\n", stderr);
   2162     return (num_options);
   2163   }
   2164 
   2165  /*
   2166   * Find the option and choice...
   2167   */
   2168 
   2169   if ((option = ppdFindOption(ppd, name + 1)) == NULL)
   2170   {
   2171     _cupsLangPrintFilter(stderr, "WARNING", _("Unknown option \"%s\"."),
   2172                          name + 1);
   2173     return (num_options);
   2174   }
   2175 
   2176   if (option->section == PPD_ORDER_EXIT ||
   2177       option->section == PPD_ORDER_JCL)
   2178   {
   2179     _cupsLangPrintFilter(stderr, "WARNING",
   2180                          _("Option \"%s\" cannot be included via "
   2181 			   "%%%%IncludeFeature."), name + 1);
   2182     return (num_options);
   2183   }
   2184 
   2185   if (!ppdFindChoice(option, value))
   2186   {
   2187     _cupsLangPrintFilter(stderr, "WARNING",
   2188 			 _("Unknown choice \"%s\" for option \"%s\"."),
   2189 			 value, name + 1);
   2190     return (num_options);
   2191   }
   2192 
   2193  /*
   2194   * Add the option to the option array and return...
   2195   */
   2196 
   2197   return (cupsAddOption(name + 1, value, num_options, options));
   2198 }
   2199 
   2200 
   2201 /*
   2202  * 'parse_text()' - Parse a text value in a comment.
   2203  *
   2204  * This function parses a DSC text value as defined on page 36 of the
   2205  * DSC specification.  Text values are either surrounded by parenthesis
   2206  * or whitespace-delimited.
   2207  *
   2208  * The value returned is the literal characters for the entire text
   2209  * string, including any parenthesis and escape characters.
   2210  */
   2211 
   2212 static char *				/* O - Value or NULL on error */
   2213 parse_text(const char *start,		/* I - Start of text value */
   2214            char       **end,		/* O - End of text value */
   2215 	   char       *buffer,		/* I - Buffer */
   2216            size_t     bufsize)		/* I - Size of buffer */
   2217 {
   2218   char	*bufptr,			/* Pointer in buffer */
   2219 	*bufend;			/* End of buffer */
   2220   int	level;				/* Parenthesis level */
   2221 
   2222 
   2223  /*
   2224   * Skip leading whitespace...
   2225   */
   2226 
   2227   while (isspace(*start & 255))
   2228     start ++;
   2229 
   2230  /*
   2231   * Then copy the value...
   2232   */
   2233 
   2234   level  = 0;
   2235   bufptr = buffer;
   2236   bufend = buffer + bufsize - 1;
   2237 
   2238   while (bufptr < bufend)
   2239   {
   2240     if (isspace(*start & 255) && !level)
   2241       break;
   2242 
   2243     *bufptr++ = *start;
   2244 
   2245     if (*start == '(')
   2246       level ++;
   2247     else if (*start == ')')
   2248     {
   2249       if (!level)
   2250       {
   2251         start ++;
   2252         break;
   2253       }
   2254       else
   2255         level --;
   2256     }
   2257     else if (*start == '\\')
   2258     {
   2259      /*
   2260       * Copy escaped character...
   2261       */
   2262 
   2263       int	i;			/* Looping var */
   2264 
   2265 
   2266       for (i = 1;
   2267            i <= 3 && isdigit(start[i] & 255) && bufptr < bufend;
   2268 	   *bufptr++ = start[i], i ++);
   2269     }
   2270 
   2271     start ++;
   2272   }
   2273 
   2274   *bufptr = '\0';
   2275 
   2276  /*
   2277   * Return the value and new pointer into the line...
   2278   */
   2279 
   2280   if (end)
   2281     *end = (char *)start;
   2282 
   2283   if (bufptr == bufend)
   2284     return (NULL);
   2285   else
   2286     return (buffer);
   2287 }
   2288 
   2289 
   2290 /*
   2291  * 'set_pstops_options()' - Set pstops options.
   2292  */
   2293 
   2294 static void
   2295 set_pstops_options(
   2296     pstops_doc_t  *doc,			/* I - Document information */
   2297     ppd_file_t    *ppd,			/* I - PPD file */
   2298     char          *argv[],		/* I - Command-line arguments */
   2299     int           num_options,		/* I - Number of options */
   2300     cups_option_t *options)		/* I - Options */
   2301 {
   2302   const char	*val;			/* Option value */
   2303   int		intval;			/* Integer option value */
   2304   ppd_attr_t	*attr;			/* PPD attribute */
   2305   ppd_option_t	*option;		/* PPD option */
   2306   ppd_choice_t	*choice;		/* PPD choice */
   2307   const char	*content_type;		/* Original content type */
   2308   int		max_copies;		/* Maximum number of copies supported */
   2309 
   2310 
   2311  /*
   2312   * Initialize document information structure...
   2313   */
   2314 
   2315   memset(doc, 0, sizeof(pstops_doc_t));
   2316 
   2317   doc->job_id = atoi(argv[1]);
   2318   doc->user   = argv[2];
   2319   doc->title  = argv[3];
   2320   doc->copies = atoi(argv[4]);
   2321 
   2322   if (ppd && ppd->landscape > 0)
   2323     doc->normal_landscape = 1;
   2324 
   2325   doc->bounding_box[0] = (int)PageLeft;
   2326   doc->bounding_box[1] = (int)PageBottom;
   2327   doc->bounding_box[2] = (int)PageRight;
   2328   doc->bounding_box[3] = (int)PageTop;
   2329 
   2330   doc->new_bounding_box[0] = INT_MAX;
   2331   doc->new_bounding_box[1] = INT_MAX;
   2332   doc->new_bounding_box[2] = INT_MIN;
   2333   doc->new_bounding_box[3] = INT_MIN;
   2334 
   2335  /*
   2336   * AP_FIRSTPAGE_* and the corresponding non-first-page options.
   2337   */
   2338 
   2339   doc->ap_input_slot  = cupsGetOption("AP_FIRSTPAGE_InputSlot", num_options,
   2340                                       options);
   2341   doc->ap_manual_feed = cupsGetOption("AP_FIRSTPAGE_ManualFeed", num_options,
   2342                                       options);
   2343   doc->ap_media_color = cupsGetOption("AP_FIRSTPAGE_MediaColor", num_options,
   2344                                       options);
   2345   doc->ap_media_type  = cupsGetOption("AP_FIRSTPAGE_MediaType", num_options,
   2346                                       options);
   2347   doc->ap_page_region = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options,
   2348                                       options);
   2349   doc->ap_page_size   = cupsGetOption("AP_FIRSTPAGE_PageSize", num_options,
   2350                                       options);
   2351 
   2352   if ((choice = ppdFindMarkedChoice(ppd, "InputSlot")) != NULL)
   2353     doc->input_slot = choice->choice;
   2354   if ((choice = ppdFindMarkedChoice(ppd, "ManualFeed")) != NULL)
   2355     doc->manual_feed = choice->choice;
   2356   if ((choice = ppdFindMarkedChoice(ppd, "MediaColor")) != NULL)
   2357     doc->media_color = choice->choice;
   2358   if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
   2359     doc->media_type = choice->choice;
   2360   if ((choice = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL)
   2361     doc->page_region = choice->choice;
   2362   if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL)
   2363     doc->page_size = choice->choice;
   2364 
   2365  /*
   2366   * collate, multiple-document-handling
   2367   */
   2368 
   2369   if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
   2370   {
   2371    /*
   2372     * This IPP attribute is unnecessarily complicated...
   2373     *
   2374     *   single-document, separate-documents-collated-copies, and
   2375     *   single-document-new-sheet all require collated copies.
   2376     *
   2377     *   separate-documents-uncollated-copies allows for uncollated copies.
   2378     */
   2379 
   2380     doc->collate = _cups_strcasecmp(val, "separate-documents-uncollated-copies") != 0;
   2381   }
   2382 
   2383   if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
   2384       (!_cups_strcasecmp(val, "true") ||!_cups_strcasecmp(val, "on") ||
   2385        !_cups_strcasecmp(val, "yes")))
   2386     doc->collate = 1;
   2387 
   2388  /*
   2389   * emit-jcl
   2390   */
   2391 
   2392   if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
   2393       (!_cups_strcasecmp(val, "false") || !_cups_strcasecmp(val, "off") ||
   2394        !_cups_strcasecmp(val, "no") || !strcmp(val, "0")))
   2395     doc->emit_jcl = 0;
   2396   else
   2397     doc->emit_jcl = 1;
   2398 
   2399  /*
   2400   * fit-to-page/ipp-attribute-fidelity
   2401   *
   2402   * (Only for original PostScript content)
   2403   */
   2404 
   2405   if ((content_type = getenv("CONTENT_TYPE")) == NULL)
   2406     content_type = "application/postscript";
   2407 
   2408   if (!_cups_strcasecmp(content_type, "application/postscript"))
   2409   {
   2410     if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL &&
   2411 	!_cups_strcasecmp(val, "true"))
   2412       doc->fit_to_page = 1;
   2413     else if ((val = cupsGetOption("ipp-attribute-fidelity", num_options,
   2414                                   options)) != NULL &&
   2415 	     !_cups_strcasecmp(val, "true"))
   2416       doc->fit_to_page = 1;
   2417   }
   2418 
   2419  /*
   2420   * mirror/MirrorPrint
   2421   */
   2422 
   2423   if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
   2424   {
   2425     val = choice->choice;
   2426     choice->marked = 0;
   2427   }
   2428   else
   2429     val = cupsGetOption("mirror", num_options, options);
   2430 
   2431   if (val && (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") ||
   2432               !_cups_strcasecmp(val, "yes")))
   2433     doc->mirror = 1;
   2434 
   2435  /*
   2436   * number-up
   2437   */
   2438 
   2439   if ((val = cupsGetOption("number-up", num_options, options)) != NULL)
   2440   {
   2441     switch (intval = atoi(val))
   2442     {
   2443       case 1 :
   2444       case 2 :
   2445       case 4 :
   2446       case 6 :
   2447       case 9 :
   2448       case 16 :
   2449           doc->number_up = intval;
   2450 	  break;
   2451       default :
   2452           _cupsLangPrintFilter(stderr, "ERROR",
   2453 	                       _("Unsupported number-up value %d, using "
   2454 				 "number-up=1."), intval);
   2455           doc->number_up = 1;
   2456 	  break;
   2457     }
   2458   }
   2459   else
   2460     doc->number_up = 1;
   2461 
   2462  /*
   2463   * number-up-layout
   2464   */
   2465 
   2466   if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL)
   2467   {
   2468     if (!_cups_strcasecmp(val, "lrtb"))
   2469       doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
   2470     else if (!_cups_strcasecmp(val, "lrbt"))
   2471       doc->number_up_layout = PSTOPS_LAYOUT_LRBT;
   2472     else if (!_cups_strcasecmp(val, "rltb"))
   2473       doc->number_up_layout = PSTOPS_LAYOUT_RLTB;
   2474     else if (!_cups_strcasecmp(val, "rlbt"))
   2475       doc->number_up_layout = PSTOPS_LAYOUT_RLBT;
   2476     else if (!_cups_strcasecmp(val, "tblr"))
   2477       doc->number_up_layout = PSTOPS_LAYOUT_TBLR;
   2478     else if (!_cups_strcasecmp(val, "tbrl"))
   2479       doc->number_up_layout = PSTOPS_LAYOUT_TBRL;
   2480     else if (!_cups_strcasecmp(val, "btlr"))
   2481       doc->number_up_layout = PSTOPS_LAYOUT_BTLR;
   2482     else if (!_cups_strcasecmp(val, "btrl"))
   2483       doc->number_up_layout = PSTOPS_LAYOUT_BTRL;
   2484     else
   2485     {
   2486       _cupsLangPrintFilter(stderr, "ERROR",
   2487                            _("Unsupported number-up-layout value %s, using "
   2488 			     "number-up-layout=lrtb."), val);
   2489       doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
   2490     }
   2491   }
   2492   else
   2493     doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
   2494 
   2495  /*
   2496   * OutputOrder
   2497   */
   2498 
   2499   if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL)
   2500   {
   2501     if (!_cups_strcasecmp(val, "Reverse"))
   2502       doc->output_order = 1;
   2503   }
   2504   else if (ppd)
   2505   {
   2506    /*
   2507     * Figure out the right default output order from the PPD file...
   2508     */
   2509 
   2510     if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL &&
   2511         (attr = ppdFindAttr(ppd, "PageStackOrder", choice->choice)) != NULL &&
   2512 	attr->value)
   2513       doc->output_order = !_cups_strcasecmp(attr->value, "Reverse");
   2514     else if ((attr = ppdFindAttr(ppd, "DefaultOutputOrder", NULL)) != NULL &&
   2515              attr->value)
   2516       doc->output_order = !_cups_strcasecmp(attr->value, "Reverse");
   2517   }
   2518 
   2519  /*
   2520   * page-border
   2521   */
   2522 
   2523   if ((val = cupsGetOption("page-border", num_options, options)) != NULL)
   2524   {
   2525     if (!_cups_strcasecmp(val, "none"))
   2526       doc->page_border = PSTOPS_BORDERNONE;
   2527     else if (!_cups_strcasecmp(val, "single"))
   2528       doc->page_border = PSTOPS_BORDERSINGLE;
   2529     else if (!_cups_strcasecmp(val, "single-thick"))
   2530       doc->page_border = PSTOPS_BORDERSINGLE2;
   2531     else if (!_cups_strcasecmp(val, "double"))
   2532       doc->page_border = PSTOPS_BORDERDOUBLE;
   2533     else if (!_cups_strcasecmp(val, "double-thick"))
   2534       doc->page_border = PSTOPS_BORDERDOUBLE2;
   2535     else
   2536     {
   2537       _cupsLangPrintFilter(stderr, "ERROR",
   2538                            _("Unsupported page-border value %s, using "
   2539 			     "page-border=none."), val);
   2540       doc->page_border = PSTOPS_BORDERNONE;
   2541     }
   2542   }
   2543   else
   2544     doc->page_border = PSTOPS_BORDERNONE;
   2545 
   2546  /*
   2547   * page-label
   2548   */
   2549 
   2550   doc->page_label = cupsGetOption("page-label", num_options, options);
   2551 
   2552  /*
   2553   * page-ranges
   2554   */
   2555 
   2556   doc->page_ranges = cupsGetOption("page-ranges", num_options, options);
   2557 
   2558  /*
   2559   * page-set
   2560   */
   2561 
   2562   doc->page_set = cupsGetOption("page-set", num_options, options);
   2563 
   2564  /*
   2565   * Now figure out if we have to force collated copies, etc.
   2566   */
   2567 
   2568   if ((attr = ppdFindAttr(ppd, "cupsMaxCopies", NULL)) != NULL)
   2569     max_copies = atoi(attr->value);
   2570   else if (ppd && ppd->manual_copies)
   2571     max_copies = 1;
   2572   else
   2573     max_copies = 9999;
   2574 
   2575   if (doc->copies > max_copies)
   2576     doc->collate = 1;
   2577   else if (ppd && ppd->manual_copies && Duplex && doc->copies > 1)
   2578   {
   2579    /*
   2580     * Force collated copies when printing a duplexed document to
   2581     * a non-PS printer that doesn't do hardware copy generation.
   2582     * Otherwise the copies will end up on the front/back side of
   2583     * each page.
   2584     */
   2585 
   2586     doc->collate = 1;
   2587   }
   2588 
   2589  /*
   2590   * See if we have to filter the fast or slow way...
   2591   */
   2592 
   2593   if (doc->collate && doc->copies > 1)
   2594   {
   2595    /*
   2596     * See if we need to manually collate the pages...
   2597     */
   2598 
   2599     doc->slow_collate = 1;
   2600 
   2601     if (doc->copies <= max_copies &&
   2602         (choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
   2603         !_cups_strcasecmp(choice->choice, "True"))
   2604     {
   2605      /*
   2606       * Hardware collate option is selected, see if the option is
   2607       * conflicting - if not, collate in hardware.  Otherwise,
   2608       * turn the hardware collate option off...
   2609       */
   2610 
   2611       if ((option = ppdFindOption(ppd, "Collate")) != NULL &&
   2612           !option->conflicted)
   2613 	doc->slow_collate = 0;
   2614       else
   2615         ppdMarkOption(ppd, "Collate", "False");
   2616     }
   2617   }
   2618   else
   2619     doc->slow_collate = 0;
   2620 
   2621   if (!ppdFindOption(ppd, "OutputOrder") && doc->output_order)
   2622     doc->slow_order = 1;
   2623   else
   2624     doc->slow_order = 0;
   2625 
   2626   if (Duplex &&
   2627        (doc->slow_collate || doc->slow_order ||
   2628         ((attr = ppdFindAttr(ppd, "cupsEvenDuplex", NULL)) != NULL &&
   2629 	 attr->value && !_cups_strcasecmp(attr->value, "true"))))
   2630     doc->slow_duplex = 1;
   2631   else
   2632     doc->slow_duplex = 0;
   2633 
   2634  /*
   2635   * Create a temporary file for page data if we need to filter slowly...
   2636   */
   2637 
   2638   if (doc->slow_order || doc->slow_collate)
   2639   {
   2640     if ((doc->temp = cupsTempFile2(doc->tempfile,
   2641                                    sizeof(doc->tempfile))) == NULL)
   2642     {
   2643       perror("DEBUG: Unable to create temporary file");
   2644       exit(1);
   2645     }
   2646   }
   2647 
   2648  /*
   2649   * Figure out if we should use ESPshowpage or not...
   2650   */
   2651 
   2652   if (doc->page_label || getenv("CLASSIFICATION") || doc->number_up > 1 ||
   2653       doc->page_border)
   2654   {
   2655    /*
   2656     * Yes, use ESPshowpage...
   2657     */
   2658 
   2659     doc->use_ESPshowpage = 1;
   2660   }
   2661 
   2662   fprintf(stderr, "DEBUG: slow_collate=%d, slow_duplex=%d, slow_order=%d\n",
   2663           doc->slow_collate, doc->slow_duplex, doc->slow_order);
   2664 }
   2665 
   2666 
   2667 /*
   2668  * 'skip_page()' - Skip past a page that won't be printed.
   2669  */
   2670 
   2671 static ssize_t				/* O - Length of next line */
   2672 skip_page(cups_file_t *fp,		/* I - File to read from */
   2673           char        *line,		/* I - Line buffer */
   2674 	  ssize_t     linelen,		/* I - Length of initial line */
   2675           size_t      linesize)		/* I - Size of line buffer */
   2676 {
   2677   int	level;				/* Embedded document level */
   2678 
   2679 
   2680   level = 0;
   2681 
   2682   while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
   2683   {
   2684     if (level == 0 &&
   2685         (!strncmp(line, "%%Page:", 7) || !strncmp(line, "%%Trailer", 9)))
   2686       break;
   2687     else if (!strncmp(line, "%%BeginDocument", 15) ||
   2688 	     !strncmp(line, "%ADO_BeginApplication", 21))
   2689       level ++;
   2690     else if ((!strncmp(line, "%%EndDocument", 13) ||
   2691 	      !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
   2692       level --;
   2693     else if (!strncmp(line, "%%BeginBinary:", 14) ||
   2694              (!strncmp(line, "%%BeginData:", 12) &&
   2695 	      !strstr(line, "ASCII") && !strstr(line, "Hex")))
   2696     {
   2697      /*
   2698       * Skip binary data...
   2699       */
   2700 
   2701       ssize_t	bytes;			/* Bytes of data */
   2702 
   2703       bytes = atoi(strchr(line, ':') + 1);
   2704 
   2705       while (bytes > 0)
   2706       {
   2707 	if ((size_t)bytes > linesize)
   2708 	  linelen = (ssize_t)cupsFileRead(fp, line, linesize);
   2709 	else
   2710 	  linelen = (ssize_t)cupsFileRead(fp, line, (size_t)bytes);
   2711 
   2712 	if (linelen < 1)
   2713 	{
   2714 	  line[0] = '\0';
   2715 	  perror("ERROR: Early end-of-file while reading binary data");
   2716 	  return (0);
   2717 	}
   2718 
   2719 	bytes -= linelen;
   2720       }
   2721     }
   2722   }
   2723 
   2724   return (linelen);
   2725 }
   2726 
   2727 
   2728 /*
   2729  * 'start_nup()' - Start processing for N-up printing.
   2730  */
   2731 
   2732 static void
   2733 start_nup(pstops_doc_t *doc,		/* I - Document information */
   2734           int          number,		/* I - Page number */
   2735 	  int          show_border,	/* I - Show the border? */
   2736 	  const int    *bounding_box)	/* I - BoundingBox value */
   2737 {
   2738   int		pos;			/* Position on page */
   2739   int		x, y;			/* Relative position of subpage */
   2740   double	w, l,			/* Width and length of subpage */
   2741 		tx, ty;			/* Translation values for subpage */
   2742   double	pagew,			/* Printable width of page */
   2743 		pagel;			/* Printable height of page */
   2744   int		bboxx,			/* BoundingBox X origin */
   2745 		bboxy,			/* BoundingBox Y origin */
   2746 		bboxw,			/* BoundingBox width */
   2747 		bboxl;			/* BoundingBox height */
   2748   double	margin = 0;		/* Current margin for border */
   2749 
   2750 
   2751   if (doc->number_up > 1)
   2752     doc_puts(doc, "userdict/ESPsave save put\n");
   2753 
   2754   pos   = (number - 1) % doc->number_up;
   2755   pagew = PageRight - PageLeft;
   2756   pagel = PageTop - PageBottom;
   2757 
   2758   if (doc->fit_to_page)
   2759   {
   2760     bboxx = bounding_box[0];
   2761     bboxy = bounding_box[1];
   2762     bboxw = bounding_box[2] - bounding_box[0];
   2763     bboxl = bounding_box[3] - bounding_box[1];
   2764   }
   2765   else
   2766   {
   2767     bboxx = 0;
   2768     bboxy = 0;
   2769     bboxw = (int)PageWidth;
   2770     bboxl = (int)PageLength;
   2771   }
   2772 
   2773   fprintf(stderr, "DEBUG: pagew = %.1f, pagel = %.1f\n", pagew, pagel);
   2774   fprintf(stderr, "DEBUG: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d\n",
   2775           bboxx, bboxy, bboxw, bboxl);
   2776   fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n",
   2777           PageLeft, PageRight);
   2778   fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n",
   2779           PageTop, PageBottom);
   2780   fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n",
   2781           PageWidth, PageLength);
   2782 
   2783   switch (Orientation)
   2784   {
   2785     case 1 : /* Landscape */
   2786         doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", PageLength);
   2787         break;
   2788     case 2 : /* Reverse Portrait */
   2789         doc_printf(doc, "%.1f %.1f translate 180 rotate\n", PageWidth,
   2790 	           PageLength);
   2791         break;
   2792     case 3 : /* Reverse Landscape */
   2793         doc_printf(doc, "0.0 %.1f translate -90 rotate\n", PageWidth);
   2794         break;
   2795   }
   2796 
   2797  /*
   2798   * Mirror the page as needed...
   2799   */
   2800 
   2801   if (doc->mirror)
   2802     doc_printf(doc, "%.1f 0.0 translate -1 1 scale\n", PageWidth);
   2803 
   2804  /*
   2805   * Offset and scale as necessary for fit_to_page/fit-to-page/number-up...
   2806   */
   2807 
   2808   if (Duplex && doc->number_up > 1 && ((number / doc->number_up) & 1))
   2809     doc_printf(doc, "%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
   2810   else if (doc->number_up > 1 || doc->fit_to_page)
   2811     doc_printf(doc, "%.1f %.1f translate\n", PageLeft, PageBottom);
   2812 
   2813   switch (doc->number_up)
   2814   {
   2815     default :
   2816         if (doc->fit_to_page)
   2817 	{
   2818           w = pagew;
   2819           l = w * bboxl / bboxw;
   2820 
   2821           if (l > pagel)
   2822           {
   2823             l = pagel;
   2824             w = l * bboxw / bboxl;
   2825           }
   2826 
   2827           tx = 0.5 * (pagew - w);
   2828           ty = 0.5 * (pagel - l);
   2829 
   2830 	  doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", tx, ty,
   2831 	             w / bboxw, l / bboxl);
   2832 	}
   2833 	else
   2834           w = PageWidth;
   2835 	break;
   2836 
   2837     case 2 :
   2838         if (Orientation & 1)
   2839 	{
   2840           x = pos & 1;
   2841 
   2842           if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   2843 	    x = 1 - x;
   2844 
   2845           w = pagel;
   2846           l = w * bboxl / bboxw;
   2847 
   2848           if (l > (pagew * 0.5))
   2849           {
   2850             l = pagew * 0.5;
   2851             w = l * bboxw / bboxl;
   2852           }
   2853 
   2854           tx = 0.5 * (pagew * 0.5 - l);
   2855           ty = 0.5 * (pagel - w);
   2856 
   2857           if (doc->normal_landscape)
   2858             doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
   2859 	  else
   2860 	    doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
   2861 
   2862           doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
   2863                      ty, tx + pagew * 0.5 * x, w / bboxw, l / bboxl);
   2864         }
   2865 	else
   2866 	{
   2867           x = pos & 1;
   2868 
   2869           if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   2870 	    x = 1 - x;
   2871 
   2872           l = pagew;
   2873           w = l * bboxw / bboxl;
   2874 
   2875           if (w > (pagel * 0.5))
   2876           {
   2877             w = pagel * 0.5;
   2878             l = w * bboxl / bboxw;
   2879           }
   2880 
   2881           tx = 0.5 * (pagel * 0.5 - w);
   2882           ty = 0.5 * (pagew - l);
   2883 
   2884           if (doc->normal_landscape)
   2885 	    doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
   2886 	  else
   2887             doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
   2888 
   2889           doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
   2890                      tx + pagel * 0.5 * x, ty, w / bboxw, l / bboxl);
   2891         }
   2892         break;
   2893 
   2894     case 4 :
   2895         if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
   2896 	{
   2897 	  x = (pos / 2) & 1;
   2898           y = pos & 1;
   2899         }
   2900 	else
   2901 	{
   2902           x = pos & 1;
   2903 	  y = (pos / 2) & 1;
   2904         }
   2905 
   2906         if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   2907 	  x = 1 - x;
   2908 
   2909 	if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   2910 	  y = 1 - y;
   2911 
   2912         w = pagew * 0.5;
   2913 	l = w * bboxl / bboxw;
   2914 
   2915 	if (l > (pagel * 0.5))
   2916 	{
   2917 	  l = pagel * 0.5;
   2918 	  w = l * bboxw / bboxl;
   2919 	}
   2920 
   2921         tx = 0.5 * (pagew * 0.5 - w);
   2922         ty = 0.5 * (pagel * 0.5 - l);
   2923 
   2924 	doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
   2925 	           tx + x * pagew * 0.5, ty + y * pagel * 0.5,
   2926 	           w / bboxw, l / bboxl);
   2927         break;
   2928 
   2929     case 6 :
   2930         if (Orientation & 1)
   2931 	{
   2932 	  if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
   2933 	  {
   2934 	    x = pos / 3;
   2935 	    y = pos % 3;
   2936 
   2937             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   2938 	      x = 1 - x;
   2939 
   2940             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   2941 	      y = 2 - y;
   2942 	  }
   2943 	  else
   2944 	  {
   2945 	    x = pos & 1;
   2946 	    y = pos / 2;
   2947 
   2948             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   2949 	      x = 1 - x;
   2950 
   2951             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   2952 	      y = 2 - y;
   2953 	  }
   2954 
   2955           w = pagel * 0.5;
   2956           l = w * bboxl / bboxw;
   2957 
   2958           if (l > (pagew * 0.333))
   2959           {
   2960             l = pagew * 0.333;
   2961             w = l * bboxw / bboxl;
   2962           }
   2963 
   2964           tx = 0.5 * (pagel - 2 * w);
   2965           ty = 0.5 * (pagew - 3 * l);
   2966 
   2967           if (doc->normal_landscape)
   2968             doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
   2969 	  else
   2970 	    doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
   2971 
   2972           doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
   2973                      tx + x * w, ty + y * l, l / bboxl, w / bboxw);
   2974         }
   2975 	else
   2976 	{
   2977 	  if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
   2978 	  {
   2979 	    x = pos / 2;
   2980 	    y = pos & 1;
   2981 
   2982             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   2983 	      x = 2 - x;
   2984 
   2985             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   2986 	      y = 1 - y;
   2987 	  }
   2988 	  else
   2989 	  {
   2990 	    x = pos % 3;
   2991 	    y = pos / 3;
   2992 
   2993             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   2994 	      x = 2 - x;
   2995 
   2996             if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   2997 	      y = 1 - y;
   2998 	  }
   2999 
   3000           l = pagew * 0.5;
   3001           w = l * bboxw / bboxl;
   3002 
   3003           if (w > (pagel * 0.333))
   3004           {
   3005             w = pagel * 0.333;
   3006             l = w * bboxl / bboxw;
   3007           }
   3008 
   3009 	  tx = 0.5 * (pagel - 3 * w);
   3010 	  ty = 0.5 * (pagew - 2 * l);
   3011 
   3012           if (doc->normal_landscape)
   3013 	    doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
   3014 	  else
   3015             doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
   3016 
   3017           doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
   3018                      tx + w * x, ty + l * y, w / bboxw, l / bboxl);
   3019 
   3020         }
   3021         break;
   3022 
   3023     case 9 :
   3024         if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
   3025 	{
   3026 	  x = (pos / 3) % 3;
   3027           y = pos % 3;
   3028         }
   3029 	else
   3030 	{
   3031           x = pos % 3;
   3032 	  y = (pos / 3) % 3;
   3033         }
   3034 
   3035         if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   3036 	  x = 2 - x;
   3037 
   3038 	if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   3039 	  y = 2 - y;
   3040 
   3041         w = pagew * 0.333;
   3042 	l = w * bboxl / bboxw;
   3043 
   3044 	if (l > (pagel * 0.333))
   3045 	{
   3046 	  l = pagel * 0.333;
   3047 	  w = l * bboxw / bboxl;
   3048 	}
   3049 
   3050         tx = 0.5 * (pagew * 0.333 - w);
   3051         ty = 0.5 * (pagel * 0.333 - l);
   3052 
   3053 	doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
   3054 	           tx + x * pagew * 0.333, ty + y * pagel * 0.333,
   3055 	           w / bboxw, l / bboxl);
   3056         break;
   3057 
   3058     case 16 :
   3059         if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
   3060 	{
   3061 	  x = (pos / 4) & 3;
   3062           y = pos & 3;
   3063         }
   3064 	else
   3065 	{
   3066           x = pos & 3;
   3067 	  y = (pos / 4) & 3;
   3068         }
   3069 
   3070         if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
   3071 	  x = 3 - x;
   3072 
   3073 	if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
   3074 	  y = 3 - y;
   3075 
   3076         w = pagew * 0.25;
   3077 	l = w * bboxl / bboxw;
   3078 
   3079 	if (l > (pagel * 0.25))
   3080 	{
   3081 	  l = pagel * 0.25;
   3082 	  w = l * bboxw / bboxl;
   3083 	}
   3084 
   3085         tx = 0.5 * (pagew * 0.25 - w);
   3086         ty = 0.5 * (pagel * 0.25 - l);
   3087 
   3088 	doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
   3089 	           tx + x * pagew * 0.25, ty + y * pagel * 0.25,
   3090 	           w / bboxw, l / bboxl);
   3091         break;
   3092   }
   3093 
   3094  /*
   3095   * Draw borders as necessary...
   3096   */
   3097 
   3098   if (doc->page_border && show_border)
   3099   {
   3100     int		rects;			/* Number of border rectangles */
   3101     double	fscale;			/* Scaling value for points */
   3102 
   3103 
   3104     rects  = (doc->page_border & PSTOPS_BORDERDOUBLE) ? 2 : 1;
   3105     fscale = PageWidth / w;
   3106     margin = 2.25 * fscale;
   3107 
   3108    /*
   3109     * Set the line width and color...
   3110     */
   3111 
   3112     doc_puts(doc, "gsave\n");
   3113     doc_printf(doc, "%.3f setlinewidth 0 setgray newpath\n",
   3114                (doc->page_border & PSTOPS_BORDERTHICK) ? 0.5 * fscale :
   3115 	                                                 0.24 * fscale);
   3116 
   3117    /*
   3118     * Draw border boxes...
   3119     */
   3120 
   3121     for (; rects > 0; rects --, margin += 2 * fscale)
   3122       if (doc->number_up > 1)
   3123 	doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
   3124 		   margin,
   3125 		   margin,
   3126 		   bboxw - 2 * margin,
   3127 		   bboxl - 2 * margin);
   3128       else
   3129 	doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
   3130         	   PageLeft + margin,
   3131 		   PageBottom + margin,
   3132 		   PageRight - PageLeft - 2 * margin,
   3133 		   PageTop - PageBottom - 2 * margin);
   3134 
   3135    /*
   3136     * Restore pen settings...
   3137     */
   3138 
   3139     doc_puts(doc, "grestore\n");
   3140   }
   3141 
   3142   if (doc->fit_to_page)
   3143   {
   3144    /*
   3145     * Offset the page by its bounding box...
   3146     */
   3147 
   3148     doc_printf(doc, "%d %d translate\n", -bounding_box[0],
   3149                -bounding_box[1]);
   3150   }
   3151 
   3152   if (doc->fit_to_page || doc->number_up > 1)
   3153   {
   3154    /*
   3155     * Clip the page to the page's bounding box...
   3156     */
   3157 
   3158     doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrc\n",
   3159                bboxx + margin, bboxy + margin,
   3160                bboxw - 2 * margin, bboxl - 2 * margin);
   3161   }
   3162 }
   3163 
   3164 
   3165 /*
   3166  * 'write_label_prolog()' - Write the prolog with the classification
   3167  *                          and page label.
   3168  */
   3169 
   3170 static void
   3171 write_label_prolog(pstops_doc_t *doc,	/* I - Document info */
   3172                    const char   *label,	/* I - Page label */
   3173 		   float        bottom,	/* I - Bottom position in points */
   3174 		   float        top,	/* I - Top position in points */
   3175 		   float        width)	/* I - Width in points */
   3176 {
   3177   const char	*classification;	/* CLASSIFICATION environment variable */
   3178   const char	*ptr;			/* Temporary string pointer */
   3179 
   3180 
   3181  /*
   3182   * First get the current classification...
   3183   */
   3184 
   3185   if ((classification = getenv("CLASSIFICATION")) == NULL)
   3186     classification = "";
   3187   if (strcmp(classification, "none") == 0)
   3188     classification = "";
   3189 
   3190  /*
   3191   * If there is nothing to show, bind an empty 'write labels' procedure
   3192   * and return...
   3193   */
   3194 
   3195   if (!classification[0] && (label == NULL || !label[0]))
   3196   {
   3197     doc_puts(doc, "userdict/ESPwl{}bind put\n");
   3198     return;
   3199   }
   3200 
   3201  /*
   3202   * Set the classification + page label string...
   3203   */
   3204 
   3205   doc_puts(doc, "userdict");
   3206   if (!strcmp(classification, "confidential"))
   3207     doc_puts(doc, "/ESPpl(CONFIDENTIAL");
   3208   else if (!strcmp(classification, "classified"))
   3209     doc_puts(doc, "/ESPpl(CLASSIFIED");
   3210   else if (!strcmp(classification, "secret"))
   3211     doc_puts(doc, "/ESPpl(SECRET");
   3212   else if (!strcmp(classification, "topsecret"))
   3213     doc_puts(doc, "/ESPpl(TOP SECRET");
   3214   else if (!strcmp(classification, "unclassified"))
   3215     doc_puts(doc, "/ESPpl(UNCLASSIFIED");
   3216   else
   3217   {
   3218     doc_puts(doc, "/ESPpl(");
   3219 
   3220     for (ptr = classification; *ptr; ptr ++)
   3221     {
   3222       if (*ptr < 32 || *ptr > 126)
   3223         doc_printf(doc, "\\%03o", *ptr);
   3224       else if (*ptr == '_')
   3225         doc_puts(doc, " ");
   3226       else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
   3227 	doc_printf(doc, "\\%c", *ptr);
   3228       else
   3229         doc_printf(doc, "%c", *ptr);
   3230     }
   3231   }
   3232 
   3233   if (label)
   3234   {
   3235     if (classification[0])
   3236       doc_puts(doc, " - ");
   3237 
   3238    /*
   3239     * Quote the label string as needed...
   3240     */
   3241 
   3242     for (ptr = label; *ptr; ptr ++)
   3243     {
   3244       if (*ptr < 32 || *ptr > 126)
   3245         doc_printf(doc, "\\%03o", *ptr);
   3246       else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
   3247 	doc_printf(doc, "\\%c", *ptr);
   3248       else
   3249         doc_printf(doc, "%c", *ptr);
   3250     }
   3251   }
   3252 
   3253   doc_puts(doc, ")put\n");
   3254 
   3255  /*
   3256   * Then get a 14 point Helvetica-Bold font...
   3257   */
   3258 
   3259   doc_puts(doc, "userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put\n");
   3260 
   3261  /*
   3262   * Finally, the procedure to write the labels on the page...
   3263   */
   3264 
   3265   doc_puts(doc, "userdict/ESPwl{\n");
   3266   doc_puts(doc, "  ESPpf setfont\n");
   3267   doc_printf(doc, "  ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
   3268              width * 0.5f);
   3269   doc_puts(doc, "  1 setgray\n");
   3270   doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
   3271   doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
   3272   doc_puts(doc, "  0 setgray\n");
   3273   doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
   3274   doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
   3275   doc_printf(doc, "  dup %.0f moveto ESPpl show\n", bottom + 2.0);
   3276   doc_printf(doc, "  %.0f moveto ESPpl show\n", top - 14.0);
   3277   doc_puts(doc, "pop\n");
   3278   doc_puts(doc, "}bind put\n");
   3279 }
   3280 
   3281 
   3282 /*
   3283  * 'write_labels()' - Write the actual page labels.
   3284  *
   3285  * This function is a copy of the one in common.c since we need to
   3286  * use doc_puts/doc_printf instead of puts/printf...
   3287  */
   3288 
   3289 static void
   3290 write_labels(pstops_doc_t *doc,		/* I - Document information */
   3291              int          orient)	/* I - Orientation of the page */
   3292 {
   3293   float	width,				/* Width of page */
   3294 	length;				/* Length of page */
   3295 
   3296 
   3297   doc_puts(doc, "gsave\n");
   3298 
   3299   if ((orient ^ Orientation) & 1)
   3300   {
   3301     width  = PageLength;
   3302     length = PageWidth;
   3303   }
   3304   else
   3305   {
   3306     width  = PageWidth;
   3307     length = PageLength;
   3308   }
   3309 
   3310   switch (orient & 3)
   3311   {
   3312     case 1 : /* Landscape */
   3313         doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", length);
   3314         break;
   3315     case 2 : /* Reverse Portrait */
   3316         doc_printf(doc, "%.1f %.1f translate 180 rotate\n", width, length);
   3317         break;
   3318     case 3 : /* Reverse Landscape */
   3319         doc_printf(doc, "0.0 %.1f translate -90 rotate\n", width);
   3320         break;
   3321   }
   3322 
   3323   doc_puts(doc, "ESPwl\n");
   3324   doc_puts(doc, "grestore\n");
   3325 }
   3326 
   3327 
   3328 /*
   3329  * 'write_options()' - Write options provided via %%IncludeFeature.
   3330  */
   3331 
   3332 static void
   3333 write_options(
   3334     pstops_doc_t  *doc,		/* I - Document */
   3335     ppd_file_t    *ppd,		/* I - PPD file */
   3336     int           num_options,	/* I - Number of options */
   3337     cups_option_t *options)	/* I - Options */
   3338 {
   3339   int		i;		/* Looping var */
   3340   ppd_option_t	*option;	/* PPD option */
   3341   float		min_order;	/* Minimum OrderDependency value */
   3342   char		*doc_setup,	/* DocumentSetup commands to send */
   3343 		*any_setup;	/* AnySetup commands to send */
   3344 
   3345 
   3346  /*
   3347   * Figure out the minimum OrderDependency value...
   3348   */
   3349 
   3350   if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
   3351     min_order = option->order;
   3352   else
   3353     min_order = 999.0f;
   3354 
   3355   for (i = 0; i < num_options; i ++)
   3356     if ((option = ppdFindOption(ppd, options[i].name)) != NULL &&
   3357 	option->order < min_order)
   3358       min_order = option->order;
   3359 
   3360  /*
   3361   * Mark and extract them...
   3362   */
   3363 
   3364   cupsMarkOptions(ppd, num_options, options);
   3365 
   3366   doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
   3367   any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
   3368 
   3369  /*
   3370   * Then send them out...
   3371   */
   3372 
   3373   if (doc->number_up > 1)
   3374   {
   3375    /*
   3376     * Temporarily restore setpagedevice so we can set the options...
   3377     */
   3378 
   3379     doc_puts(doc, "userdict/setpagedevice/CUPSsetpagedevice load put\n");
   3380   }
   3381 
   3382   if (doc_setup)
   3383   {
   3384     doc_puts(doc, doc_setup);
   3385     free(doc_setup);
   3386   }
   3387 
   3388   if (any_setup)
   3389   {
   3390     doc_puts(doc, any_setup);
   3391     free(any_setup);
   3392   }
   3393 
   3394   if (doc->number_up > 1)
   3395   {
   3396    /*
   3397     * Disable setpagedevice again...
   3398     */
   3399 
   3400     doc_puts(doc, "userdict/setpagedevice{pop}bind put\n");
   3401   }
   3402 }
   3403