]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - filter/pstops.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / pstops.c
index 72612191f2c7935d1a032a7ce033e49b03eeadb6..c7ee6fcafaebd000e206239f22f291b0d555d20f 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: pstops.c 5326 2006-03-23 19:33:35Z mike $"
+ * "$Id: pstops.c 6320 2007-03-08 13:36:56Z mike $"
  *
  *   PostScript filter for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1993-2006 by Easy Software Products.
+ *   Copyright 1993-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -49,6 +49,7 @@
  *   set_pstops_options() - Set pstops options...
  *   skip_page()          - Skip past a page that won't be printed...
  *   start_nup()          - Start processing for N-up printing...
+ *   write_labels()       - Write the actual page labels.
  */
 
 /*
@@ -56,6 +57,7 @@
  */
 
 #include "common.h"
+#include <limits.h>
 #include <math.h>
 #include <cups/file.h>
 #include <cups/array.h>
@@ -161,8 +163,8 @@ static int          check_range(pstops_doc_t *doc, int page);
 static void            copy_bytes(cups_file_t *fp, off_t offset,
                                   size_t length);
 static size_t          copy_comments(cups_file_t *fp, pstops_doc_t *doc,
-                                     char *line, size_t linelen,
-                                     size_t linesize);
+                                     ppd_file_t *ppd, char *line,
+                                     size_t linelen, size_t linesize);
 static void            copy_dsc(cups_file_t *fp, pstops_doc_t *doc,
                                 ppd_file_t *ppd, char *line, size_t linelen,
                                 size_t linesize);
@@ -183,7 +185,11 @@ static size_t              copy_trailer(cups_file_t *fp, pstops_doc_t *doc,
                                     size_t linelen, size_t linesize);
 static void            do_prolog(pstops_doc_t *doc, ppd_file_t *ppd);
 static void            do_setup(pstops_doc_t *doc, ppd_file_t *ppd);
-static void            doc_printf(pstops_doc_t *doc, const char *format, ...);
+static void            doc_printf(pstops_doc_t *doc, const char *format, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+;
 static void            doc_puts(pstops_doc_t *doc, const char *s);
 static void            doc_write(pstops_doc_t *doc, const char *s, size_t len);
 static void            end_nup(pstops_doc_t *doc, int number);
@@ -199,6 +205,10 @@ static size_t              skip_page(cups_file_t *fp, char *line, size_t linelen,
                                  size_t linesize);
 static void            start_nup(pstops_doc_t *doc, int number,
                                  int show_border, const int *bounding_box);
+static void            write_label_prolog(pstops_doc_t *doc, const char *label,
+                                          float bottom, float top,
+                                          float width);
+static void            write_labels(pstops_doc_t *doc, int orient);
 
 
 /*
@@ -307,10 +317,13 @@ main(int  argc,                           /* I - Number of command-line args */
 
     fputs("DEBUG: Skipping PJL header...\n", stderr);
 
-    while (strstr(line, "ENTER LANGUAGE") == NULL)
+    while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
       if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0)
         break;
 
+    if (!strncmp(line, "%!", 2))
+      break;
+
     if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0)
       break;
   }
@@ -434,12 +447,10 @@ check_range(pstops_doc_t *doc,            /* I - Document information */
     * See if we only print even or odd pages...
     */
 
-    if (!strcasecmp(doc->page_set, "even") &&
-        ((page - 1) % (doc->number_up << 1)) < doc->number_up)
+    if (!strcasecmp(doc->page_set, "even") && (page & 1))
       return (0);
 
-    if (!strcasecmp(doc->page_set, "odd") &&
-        ((page - 1) % (doc->number_up << 1)) >= doc->number_up)
+    if (!strcasecmp(doc->page_set, "odd") && !(page & 1))
       return (0);
   }
 
@@ -534,6 +545,7 @@ copy_bytes(cups_file_t *fp,         /* I - File to read from */
 static size_t                          /* O - Length of next line */
 copy_comments(cups_file_t  *fp,                /* I - File to read from */
               pstops_doc_t *doc,       /* I - Document info */
+             ppd_file_t   *ppd,        /* I - PPD file */
               char         *line,      /* I - Line buffer */
              size_t       linelen,     /* I - Length of initial line */
              size_t       linesize)    /* I - Size of line buffer */
@@ -581,15 +593,64 @@ copy_comments(cups_file_t  *fp,           /* I - File to read from */
 
     if (!strncmp(line, "%%Pages:", 8))
     {
+      int      pages;                  /* Number of pages */
+
+
       if (saw_pages)
         fputs("ERROR: Duplicate %%Pages: comment seen!\n", stderr);
 
       saw_pages = 1;
+
+      if (Duplex && (pages = atoi(line + 8)) > 0 && pages <= doc->number_up)
+      {
+       /*
+        * Since we will only be printing on a single page, disable duplexing.
+       */
+
+       Duplex           = 0;
+       doc->slow_duplex = 0;
+
+       if (cupsGetOption("sides", doc->num_options, doc->options))
+         doc->num_options = cupsAddOption("sides", "one-sided",
+                                          doc->num_options, &(doc->options));
+
+       if (cupsGetOption("Duplex", doc->num_options, doc->options))
+         doc->num_options = cupsAddOption("Duplex", "None",
+                                          doc->num_options, &(doc->options));
+
+       if (cupsGetOption("EFDuplex", doc->num_options, doc->options))
+         doc->num_options = cupsAddOption("EFDuplex", "None",
+                                          doc->num_options, &(doc->options));
+
+       if (cupsGetOption("EFDuplexing", doc->num_options, doc->options))
+         doc->num_options = cupsAddOption("EFDuplexing", "False",
+                                          doc->num_options, &(doc->options));
+
+       if (cupsGetOption("KD03Duplex", doc->num_options, doc->options))
+         doc->num_options = cupsAddOption("KD03Duplex", "None",
+                                          doc->num_options, &(doc->options));
+
+       if (cupsGetOption("JCLDuplex", doc->num_options, doc->options))
+         doc->num_options = cupsAddOption("JCLDuplex", "None",
+                                          doc->num_options, &(doc->options));
+
+       ppdMarkOption(ppd, "Duplex", "None");
+       ppdMarkOption(ppd, "EFDuplex", "None");
+       ppdMarkOption(ppd, "EFDuplexing", "False");
+       ppdMarkOption(ppd, "KD03Duplex", "None");
+       ppdMarkOption(ppd, "JCLDuplex", "None");
+      }
     }
     else if (!strncmp(line, "%%BoundingBox:", 14))
     {
       if (saw_bounding_box)
         fputs("ERROR: Duplicate %%BoundingBox: comment seen!\n", stderr);
+      else if (strstr(line + 14, "(atend)"))
+      {
+       /*
+        * Do nothing for now but use the default imageable area...
+       */
+      }
       else if (sscanf(line + 14, "%d%d%d%d", doc->bounding_box + 0,
                      doc->bounding_box + 1, doc->bounding_box + 2,
                      doc->bounding_box + 3) != 4)
@@ -607,12 +668,12 @@ copy_comments(cups_file_t  *fp,           /* I - File to read from */
     else if (!strncmp(line, "%%For:", 6))
     {
       saw_for = 1;
-      printf("%s\n", line);
+      doc_printf(doc, "%s\n", line);
     }
     else if (!strncmp(line, "%%Title:", 8))
     {
       saw_title = 1;
-      printf("%s\n", line);
+      doc_printf(doc, "%s\n", line);
     }
     else if (!strncmp(line, "%cupsRotation:", 14))
     {
@@ -639,7 +700,7 @@ copy_comments(cups_file_t  *fp,             /* I - File to read from */
       break;
     }
     else if (strncmp(line, "%!", 2) && strncmp(line, "%cups", 5))
-      printf("%s\n", line);
+      doc_printf(doc, "%s\n", line);
 
     if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
       break;
@@ -652,10 +713,10 @@ copy_comments(cups_file_t  *fp,           /* I - File to read from */
     fputs("ERROR: No %%Pages: comment in header!\n", stderr);
 
   if (!saw_for)
-    printf("%%%%For: %s\n", doc->user);
+    WriteTextComment("For", doc->user);
 
   if (!saw_title)
-    printf("%%%%Title: %s\n", doc->title);
+    WriteTextComment("Title", doc->title);
 
   if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
   {
@@ -664,15 +725,15 @@ copy_comments(cups_file_t  *fp,           /* I - File to read from */
     * that are required...
     */
 
-    printf("%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
-           doc->collate ? " collate" : "",
-          Duplex ? " duplex" : "");
+    doc_printf(doc, "%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
+               doc->collate ? " collate" : "",
+              Duplex ? " duplex" : "");
 
    /*
     * Apple uses RBI comments for various non-PPD options...
     */
 
-    printf("%%RBINumCopies: %d\n", doc->copies);
+    doc_printf(doc, "%%RBINumCopies: %d\n", doc->copies);
   }
   else
   {
@@ -681,18 +742,18 @@ copy_comments(cups_file_t  *fp,           /* I - File to read from */
     */
 
     if (Duplex)
-      puts("%%Requirements: duplex");
+      doc_puts(doc, "%%Requirements: duplex\n");
 
    /*
     * Apple uses RBI comments for various non-PPD options...
     */
 
-    puts("%RBINumCopies: 1");
+    doc_puts(doc, "%RBINumCopies: 1\n");
   }
 
-  puts("%%Pages: (atend)");
-  puts("%%BoundingBox: (atend)");
-  puts("%%EndComments");
+  doc_puts(doc, "%%Pages: (atend)\n");
+  doc_puts(doc, "%%BoundingBox: (atend)\n");
+  doc_puts(doc, "%%EndComments\n");
 
   return (linelen);
 }
@@ -731,21 +792,33 @@ copy_dsc(cups_file_t  *fp,                /* I - File to read from */
   */
 
   fprintf(stderr, "DEBUG: Before copy_comments - %s", line);
-  linelen = copy_comments(fp, doc, line, linelen, linesize);
+  linelen = copy_comments(fp, doc, ppd, line, linelen, linesize);
 
  /*
   * Now find the prolog section, if any...
   */
 
   fprintf(stderr, "DEBUG: Before copy_prolog - %s", line);
-  copy_prolog(fp, doc, ppd, line, linelen, linesize);
+  linelen = copy_prolog(fp, doc, ppd, line, linelen, linesize);
 
  /*
   * Then the document setup section...
   */
 
   fprintf(stderr, "DEBUG: Before copy_setup - %s", line);
-  copy_setup(fp, doc, ppd, line, linelen, linesize);
+  linelen = copy_setup(fp, doc, ppd, line, linelen, linesize);
+
+ /*
+  * Copy until we see %%Page:...
+  */
+
+  while (strncmp(line, "%%Page:", 7) && strncmp(line, "%%Trailer", 9))
+  {
+    doc_write(doc, line, linelen);
+
+    if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
+      break;
+  }
 
  /*
   * Then process pages until we have no more...
@@ -774,13 +847,13 @@ copy_dsc(cups_file_t  *fp,                /* I - File to read from */
   * Finish up the last page(s)...
   */
 
-  if (number && is_not_last_page(number))
+  if (number && is_not_last_page(number) && cupsArrayLast(doc->pages))
   {
     pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
 
-    start_nup(doc, doc->number_up - 1, 0, doc->bounding_box);
+    start_nup(doc, doc->number_up, 0, doc->bounding_box);
     doc_puts(doc, "showpage\n");
-    end_nup(doc, doc->number_up - 1);
+    end_nup(doc, doc->number_up);
 
     pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset;
   }
@@ -802,9 +875,9 @@ copy_dsc(cups_file_t  *fp,          /* I - File to read from */
       printf("%%%%Page: (filler) %d\n", doc->page);
     }
 
-    start_nup(doc, doc->number_up - 1, 0, doc->bounding_box);
+    start_nup(doc, doc->number_up, 0, doc->bounding_box);
     doc_puts(doc, "showpage\n");
-    end_nup(doc, doc->number_up - 1);
+    end_nup(doc, doc->number_up);
 
     pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset;
   }
@@ -834,6 +907,54 @@ copy_dsc(cups_file_t  *fp,         /* I - File to read from */
 
     for (copy = !doc->slow_order; copy < doc->copies; copy ++)
     {
+     /*
+      * Send end-of-job stuff followed by any start-of-job stuff required
+      * for the JCL options...
+      */
+
+      if (number && doc->emit_jcl && ppd && ppd->jcl_end)
+      {
+       /*
+        * Send the trailer...
+       */
+
+        puts("%%Trailer");
+       printf("%%%%Pages: %d\n", cupsArrayCount(doc->pages));
+       if (doc->number_up > 1 || doc->fitplot)
+         printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+                PageLeft, PageBottom, PageRight, PageTop);
+       else
+         printf("%%%%BoundingBox: %d %d %d %d\n",
+                doc->new_bounding_box[0], doc->new_bounding_box[1],
+                doc->new_bounding_box[2], doc->new_bounding_box[3]);
+        puts("%%EOF");
+
+       /*
+        * Start a new document...
+       */
+
+        ppdEmitJCLEnd(ppd, stdout);
+        ppdEmitJCL(ppd, stdout, doc->job_id, doc->user, doc->title);
+
+       puts("%!PS-Adobe-3.0");
+
+       number = 0;
+      }
+
+     /*
+      * Copy the prolog as needed...
+      */
+
+      if (!number)
+      {
+        pageinfo = (pstops_page_t *)cupsArrayFirst(doc->pages);
+       copy_bytes(doc->temp, 0, pageinfo->offset);
+      }
+
+     /*
+      * Then copy all of the pages...
+      */
+
       pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayLast(doc->pages) :
                                    (pstops_page_t *)cupsArrayFirst(doc->pages);
 
@@ -852,7 +973,7 @@ copy_dsc(cups_file_t  *fp,          /* I - File to read from */
        }
        else
        {
-         printf("%%%%Page: %s %d\n", pageinfo->label, number);
+          printf("%%%%Page: %s %d\n", pageinfo->label, number);
          printf("%%%%PageBoundingBox: %d %d %d %d\n",
                 pageinfo->bounding_box[0], pageinfo->bounding_box[1],
                 pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
@@ -866,6 +987,13 @@ copy_dsc(cups_file_t  *fp,         /* I - File to read from */
     }
   }
 
+ /*
+  * Restore the old showpage operator as needed...
+  */
+
+  if (doc->use_ESPshowpage)
+    puts("userdict/showpage/ESPshowpage load put\n");
+
  /*
   * Write/copy the trailer...
   */
@@ -913,8 +1041,8 @@ copy_non_dsc(cups_file_t  *fp,             /* I - File to read from */
   else
     puts("%%Pages: 1");
 
-  printf("%%%%For: %s\n", doc->user);
-  printf("%%%%Title: %s\n", doc->title);
+  WriteTextComment("For", doc->user);
+  WriteTextComment("Title", doc->title);
 
   if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
   {
@@ -1041,6 +1169,13 @@ copy_non_dsc(cups_file_t  *fp,           /* I - File to read from */
       }
     }
   }
+
+ /*
+  * Restore the old showpage operator as needed...
+  */
+
+  if (doc->use_ESPshowpage)
+    puts("userdict/showpage/ESPshowpage load put\n");
 }
 
 
@@ -1152,6 +1287,48 @@ copy_page(cups_file_t  *fp,              /* I - File to read from */
         memcpy(bounding_box, doc->bounding_box,
               sizeof(bounding_box));
       }
+      else if (doc->number_up == 1 && !doc->fitplot  && Orientation)
+      {
+        int    temp_bbox[4];           /* Temporary bounding box */
+
+
+        memcpy(temp_bbox, bounding_box, sizeof(temp_bbox));
+
+        fprintf(stderr, "DEBUG: Orientation = %d\n", Orientation);
+        fprintf(stderr, "DEBUG: original bounding_box = [ %d %d %d %d ]\n",
+               bounding_box[0], bounding_box[1],
+               bounding_box[2], bounding_box[3]);
+        fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n",
+               PageWidth, PageLength);
+
+        switch (Orientation)
+       {
+         case 1 : /* Landscape */
+             bounding_box[0] = PageLength - temp_bbox[3];
+             bounding_box[1] = temp_bbox[0];
+             bounding_box[2] = PageLength - temp_bbox[1];
+             bounding_box[3] = temp_bbox[2];
+              break;
+
+         case 2 : /* Reverse Portrait */
+             bounding_box[0] = PageWidth - temp_bbox[2];
+             bounding_box[1] = PageLength - temp_bbox[3];
+             bounding_box[2] = PageWidth - temp_bbox[0];
+             bounding_box[3] = PageLength - temp_bbox[1];
+              break;
+
+         case 3 : /* Reverse Landscape */
+             bounding_box[0] = temp_bbox[1];
+             bounding_box[1] = PageWidth - temp_bbox[2];
+             bounding_box[2] = temp_bbox[3];
+             bounding_box[3] = PageWidth - temp_bbox[0];
+              break;
+       }
+
+        fprintf(stderr, "DEBUG: updated bounding_box = [ %d %d %d %d ]\n",
+               bounding_box[0], bounding_box[1],
+               bounding_box[2], bounding_box[3]);
+      }
     }
 #if 0
     else if (!strncmp(line, "%%PageCustomColors:", 19) ||
@@ -1265,98 +1442,129 @@ copy_page(cups_file_t  *fp,            /* I - File to read from */
   * Copy any page setup commands...
   */
 
-  if (!strncmp(line, "%%BeginPageSetup", 16))
+  if (first_page)
   {
-   /*
-    * Copy page setup commands...
-    */
+    char       *page_setup;            /* PageSetup commands to send */
 
-    doc_write(doc, line, linelen);
 
-    while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+    doc_puts(doc, "%%BeginPageSetup\n");
+
+    if (pageinfo->num_options > 0)
     {
-      if (!strncmp(line, "%%EndPageSetup", 14))
-        break;
-      else if (!strncmp(line, "%%Include", 9))
-        continue;
+      int              i;              /* Looping var */
+      ppd_option_t     *option;        /* PPD option */
+      int              min_order;      /* Minimum OrderDependency value */
+      char             *doc_setup,     /* DocumentSetup commands to send */
+                       *any_setup;     /* AnySetup commands to send */
 
-      if (doc->number_up == 1 && !doc->fitplot)
-       doc_write(doc, line, linelen);
-    }
 
-   /*
-    * Skip %%EndPageSetup...
-    */
+     /*
+      * Yes, figure out the minimum OrderDependency value...
+      */
 
-    if (linelen > 0)
-      linelen = cupsFileGetLine(fp, line, linesize);
+      if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
+       min_order = option->order;
+      else
+       min_order = 999.0f;
 
-    if (pageinfo->num_options == 0)
-      doc_puts(doc, "%%EndPageSetup\n");
-  }
-  else if (first_page && pageinfo->num_options > 0)
-    doc_puts(doc, "%%BeginPageSetup\n");
+      for (i = 0; i < pageinfo->num_options; i ++)
+       if ((option = ppdFindOption(ppd, pageinfo->options[i].name)) != NULL &&
+            option->order < min_order)
+          min_order = option->order;
 
-  if (first_page && pageinfo->num_options > 0)
-  {
-    int                i;                      /* Looping var */
-    ppd_option_t *option;              /* PPD option */
-    int                min_order;              /* Minimum OrderDependency value */
-    char       *doc_setup,             /* DocumentSetup commands to send */
-               *any_setup;             /* AnySetup commands to send */
+     /*
+      * Mark and extract them...
+      */
 
+      cupsMarkOptions(ppd, pageinfo->num_options, pageinfo->options);
 
-   /*
-    * Yes, figure out the minimum OrderDependency value...
-    */
+      doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
+      any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
 
-    if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
-      min_order = option->order;
-    else
-      min_order = 999.0f;
+     /*
+      * Then send them out...
+      */
+
+      if (doc_setup)
+      {
+       doc_puts(doc, doc_setup);
+       free(doc_setup);
+      }
 
-    for (i = 0; i < pageinfo->num_options; i ++)
-      if ((option = ppdFindOption(ppd, pageinfo->options[i].name)) != NULL &&
-          option->order < min_order)
-        min_order = option->order;
+      if (any_setup)
+      {
+       doc_puts(doc, any_setup);
+       free(any_setup);
+      }
+    }
 
    /*
-    * Mark and extract them...
+    * Output commands for the current page...
     */
 
-    cupsMarkOptions(ppd, pageinfo->num_options, pageinfo->options);
+    page_setup = ppdEmitString(ppd, PPD_ORDER_PAGE, 0);
+
+    if (page_setup)
+    {
+      doc_puts(doc, page_setup);
+      free(page_setup);
+    }
+  }
 
-    doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
-    any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
+ /*
+  * Prep for the start of the page description...
+  */
 
-   /*
-    * Then send them out...
-    */
+  start_nup(doc, number, 1, bounding_box);
 
-    if (doc_setup)
-      doc_puts(doc, doc_setup);
+ /*
+  * Copy page setup commands as needed...
+  */
+
+  if (!strncmp(line, "%%BeginPageSetup", 16))
+  {
+    int        feature = 0;                    /* In a Begin/EndFeature block? */
 
-    if (any_setup)
-      doc_puts(doc, any_setup);
 
-   /*
-    * Free the command strings...
-    */
+    while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+    {
+      if (!strncmp(line, "%%EndPageSetup", 14))
+        break;
+      else if (!strncmp(line, "%%BeginFeature:", 15))
+      {
+        feature = 1;
+
+       if (doc->number_up > 1 || doc->fitplot)
+         continue;
+      }
+      else if (!strncmp(line, "%%EndFeature:", 13))
+      {
+        feature = 0;
+
+       if (doc->number_up > 1 || doc->fitplot)
+         continue;
+      }
+      else if (!strncmp(line, "%%Include", 9))
+        continue;
 
-    if (doc_setup)
-      free(doc_setup);
+      if (!feature || (doc->number_up == 1 && !doc->fitplot))
+       doc_write(doc, line, linelen);
+    }
 
-    if (any_setup)
-      free(any_setup);
+   /*
+    * Skip %%EndPageSetup...
+    */
 
-    doc_puts(doc, "%%EndPageSetup\n");
+    if (linelen > 0)
+      linelen = cupsFileGetLine(fp, line, linesize);
   }
 
  /*
-  * Prep for the start of the page description...
+  * Finish the PageSetup section as needed...
   */
 
-  start_nup(doc, number, 1, bounding_box);
+  if (first_page)
+    doc_puts(doc, "%%EndPageSetup\n");
 
  /*
   * Read the rest of the page description...
@@ -1368,7 +1576,7 @@ copy_page(cups_file_t  *fp,               /* I - File to read from */
   {
     if (level == 0 &&
         (!strncmp(line, "%%Page:", 7) ||
-        !strncmp(line, "%%Trailer:", 10) ||
+        !strncmp(line, "%%Trailer", 9) ||
         !strncmp(line, "%%EOF", 5)))
       break;
     else if (!strncmp(line, "%%BeginDocument", 15) ||
@@ -1456,13 +1664,13 @@ copy_prolog(cups_file_t  *fp,           /* I - File to read from */
     if (!strncmp(line, "%%BeginSetup", 12) || !strncmp(line, "%%Page:", 7))
       break;
 
-    fwrite(line, 1, linelen, stdout);
+    doc_write(doc, line, linelen);
 
     if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
       break;
   }
 
-  puts("%%BeginProlog");
+  doc_puts(doc, "%%BeginProlog\n");
 
   do_prolog(doc, ppd);
 
@@ -1475,7 +1683,7 @@ copy_prolog(cups_file_t  *fp,             /* I - File to read from */
           !strncmp(line, "%%Page:", 7))
         break;
 
-      fwrite(line, 1, linelen, stdout);
+      doc_write(doc, line, linelen);
     }
 
     if (!strncmp(line, "%%EndProlog", 11))
@@ -1484,7 +1692,7 @@ copy_prolog(cups_file_t  *fp,             /* I - File to read from */
       fputs("ERROR: Missing %%EndProlog!\n", stderr);
   }
 
-  puts("%%EndProlog");
+  doc_puts(doc, "%%EndProlog\n");
 
   return (linelen);
 }
@@ -1510,12 +1718,16 @@ copy_setup(cups_file_t  *fp,            /* I - File to read from */
     if (!strncmp(line, "%%Page:", 7))
       break;
 
-    fwrite(line, 1, linelen, stdout);
+    doc_write(doc, line, linelen);
 
     if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
       break;
   }
 
+  doc_puts(doc, "%%BeginSetup\n");
+  
+  do_setup(doc, ppd);
+
   if (!strncmp(line, "%%BeginSetup", 12))
   {
     while (strncmp(line, "%%EndSetup", 10))
@@ -1532,8 +1744,8 @@ copy_setup(cups_file_t  *fp,              /* I - File to read from */
          doc->num_options = include_feature(ppd, line, doc->num_options,
                                              &(doc->options));
       }
-      else
-        fwrite(line, 1, linelen, stdout);
+      else if (strncmp(line, "%%BeginSetup", 12))
+        doc_write(doc, line, linelen);
 
       if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
        break;
@@ -1544,12 +1756,8 @@ copy_setup(cups_file_t  *fp,             /* I - File to read from */
     else
       fputs("ERROR: Missing %%EndSetup!\n", stderr);
   }
-  else
-    puts("%%BeginSetup");
-
-  do_setup(doc, ppd);
 
-  puts("%%EndSetup");
+  doc_puts(doc, "%%EndSetup\n");
 
   return (linelen);
 }
@@ -1612,18 +1820,25 @@ static void
 do_prolog(pstops_doc_t *doc,           /* I - Document information */
           ppd_file_t   *ppd)           /* I - PPD file */
 {
+  char *ps;                            /* PS commands */
+
+
  /*
   * Send the document prolog commands...
   */
 
   if (ppd && ppd->patches)
   {
-    puts("%%BeginFeature: *JobPatchFile 1");
-    puts(ppd->patches);
-    puts("%%EndFeature");
+    doc_puts(doc, "%%BeginFeature: *JobPatchFile 1\n");
+    doc_puts(doc, ppd->patches);
+    doc_puts(doc, "\n%%EndFeature\n");
   }
 
-  ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
+  if ((ps = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL)
+  {
+    doc_puts(doc, ps);
+    free(ps);
+  }
 
  /*
   * Define ESPshowpage here so that applications that define their
@@ -1631,9 +1846,8 @@ do_prolog(pstops_doc_t *doc,              /* I - Document information */
   */
 
   if (doc->use_ESPshowpage)
-    puts("userdict/ESPshowpage/showpage load put\n"
-        "userdict/showpage{}put");
-
+    doc_puts(doc, "userdict/ESPshowpage/showpage load put\n"
+                 "userdict/showpage{}put\n");
 }
 
 
@@ -1645,6 +1859,17 @@ static void
 do_setup(pstops_doc_t *doc,            /* I - Document information */
          ppd_file_t   *ppd)            /* I - PPD file */
 {
+  char *ps;                            /* PS commands */
+
+
+ /*
+  * Disable CTRL-D so that embedded files don't cause printing
+  * errors...
+  */
+
+  doc_puts(doc, "% Disable CTRL-D as an end-of-file marker...\n");
+  doc_puts(doc, "userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
+
  /*
   * Mark any options from %%IncludeFeature: comments...
   */
@@ -1655,8 +1880,17 @@ do_setup(pstops_doc_t *doc,              /* I - Document information */
   * Send all the printer-specific setup commands...
   */
 
-  ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
-  ppdEmit(ppd, stdout, PPD_ORDER_ANY);
+  if ((ps = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL)
+  {
+    doc_puts(doc, ps);
+    free(ps);
+  }
+
+  if ((ps = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL)
+  {
+    doc_puts(doc, ps);
+    free(ps);
+  }
 
  /*
   * Set the number of copies for the job...
@@ -1664,11 +1898,13 @@ do_setup(pstops_doc_t *doc,             /* I - Document information */
 
   if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
   {
-    printf("%%RBIBeginNonPPDFeature: *NumCopies %d\n", doc->copies);
-    printf("%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n"
-           "{1 dict begin/NumCopies exch def currentdict end setpagedevice}\n"
-          "{userdict/#copies 3 -1 roll put}ifelse\n", doc->copies);
-    puts("%RBIEndNonPPDFeature");
+    doc_printf(doc, "%%RBIBeginNonPPDFeature: *NumCopies %d\n", doc->copies);
+    doc_printf(doc,
+               "%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n"
+               "{1 dict begin/NumCopies exch def currentdict end "
+              "setpagedevice}\n"
+              "{userdict/#copies 3 -1 roll put}ifelse\n", doc->copies);
+    doc_puts(doc, "%RBIEndNonPPDFeature\n");
   }
 
  /*
@@ -1676,7 +1912,7 @@ do_setup(pstops_doc_t *doc,               /* I - Document information */
   */
 
   if (doc->number_up > 1)
-    puts("userdict/setpagedevice{pop}bind put");
+    doc_puts(doc, "userdict/setpagedevice{pop}bind put\n");
 
  /*
   * Changes to the transfer function must be made AFTER any
@@ -1684,15 +1920,31 @@ do_setup(pstops_doc_t *doc,             /* I - Document information */
   */
 
   if (doc->gamma != 1.0f || doc->brightness != 1.0f)
-    printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
-          "ifelse %.3f mul } bind settransfer\n", doc->gamma,
-          doc->brightness);
+    doc_printf(doc, "{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
+                   "ifelse %.3f mul } bind settransfer\n",
+              doc->gamma, doc->brightness);
 
  /*
   * Make sure we have rectclip and rectstroke procedures of some sort...
   */
 
-  WriteCommon();
+  doc_puts(doc,
+           "% x y w h ESPrc - Clip to a rectangle.\n"
+          "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
+          "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+          "neg 0 rlineto closepath clip newpath}bind}ifelse put\n");
+
+  doc_puts(doc,
+           "% x y w h ESPrf - Fill a rectangle.\n"
+          "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
+          "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+          "neg 0 rlineto closepath fill grestore}bind}ifelse put\n");
+
+  doc_puts(doc,
+           "% x y w h ESPrs - Stroke a rectangle.\n"
+          "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
+          "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+          "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n");
 
  /*
   * Write the page and label prologs...
@@ -1706,13 +1958,14 @@ do_setup(pstops_doc_t *doc,             /* I - Document information */
     */
 
     if (Orientation & 1)
-      WriteLabelProlog(doc->page_label, PageBottom,
-                       PageWidth - PageLength + PageTop, PageLength);
+      write_label_prolog(doc, doc->page_label, PageBottom,
+                         PageWidth - PageLength + PageTop, PageLength);
     else
-      WriteLabelProlog(doc->page_label, PageLeft, PageRight, PageLength);
+      write_label_prolog(doc, doc->page_label, PageLeft, PageRight,
+                         PageLength);
   }
   else
-    WriteLabelProlog(doc->page_label, PageBottom, PageTop, PageWidth);
+    write_label_prolog(doc, doc->page_label, PageBottom, PageTop, PageWidth);
 }
 
 
@@ -1789,16 +2042,16 @@ static void
 end_nup(pstops_doc_t *doc,             /* I - Document information */
         int          number)           /* I - Page number */
 {
-  if (doc->mirror || Orientation || doc->number_up > 1)
-    puts("userdict /ESPsave get restore");
+  if (doc->number_up > 1)
+    doc_puts(doc, "userdict/ESPsave get restore\n");
 
   switch (doc->number_up)
   {
     case 1 :
        if (doc->use_ESPshowpage)
        {
-         WriteLabels(Orientation);
-          puts("ESPshowpage");
+         write_labels(doc, Orientation);
+          doc_puts(doc, "ESPshowpage\n");
        }
        break;
 
@@ -1812,7 +2065,7 @@ end_nup(pstops_doc_t *doc,                /* I - Document information */
            * Rotate the labels back to portrait...
            */
 
-           WriteLabels(Orientation - 1);
+           write_labels(doc, Orientation - 1);
          }
          else if (Orientation == 0)
          {
@@ -1820,7 +2073,7 @@ end_nup(pstops_doc_t *doc,                /* I - Document information */
            * Rotate the labels to landscape...
            */
 
-           WriteLabels(doc->normal_landscape ? 1 : 3);
+           write_labels(doc, doc->normal_landscape ? 1 : 3);
          }
          else
          {
@@ -1828,18 +2081,18 @@ end_nup(pstops_doc_t *doc,              /* I - Document information */
            * Rotate the labels to landscape...
            */
 
-           WriteLabels(doc->normal_landscape ? 3 : 1);
+           write_labels(doc, doc->normal_landscape ? 3 : 1);
          }
 
-          puts("ESPshowpage");
+          doc_puts(doc, "ESPshowpage\n");
        }
         break;
 
     default :
        if (is_last_page(number) && doc->use_ESPshowpage)
        {
-         WriteLabels(Orientation);
-          puts("ESPshowpage");
+         write_labels(doc, Orientation);
+          doc_puts(doc, "ESPshowpage\n");
        }
         break;
   }
@@ -2328,7 +2581,7 @@ set_pstops_options(
       * turn the hardware collate option off...
       */
 
-      if ((option = ppdFindOption(ppd, "Option")) != NULL &&
+      if ((option = ppdFindOption(ppd, "Collate")) != NULL &&
           !option->conflicted)
        doc->slow_collate = 0;
       else
@@ -2343,7 +2596,10 @@ set_pstops_options(
   else
     doc->slow_order = 0;
 
-  if ((doc->slow_collate || doc->slow_order) && Duplex)
+  if (Duplex &&
+       (doc->slow_collate || doc->slow_order ||
+        ((attr = ppdFindAttr(ppd, "cupsEvenDuplex", NULL)) != NULL &&
+        attr->value && !strcasecmp(attr->value, "true"))))
     doc->slow_duplex = 1;
   else
     doc->slow_duplex = 0;
@@ -2400,7 +2656,7 @@ skip_page(cups_file_t *fp,                /* I - File to read from */
   while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
   {
     if (level == 0 &&
-        (!strncmp(line, "%%Page:", 7) || !strncmp(line, "%%Trailer:", 10)))
+        (!strncmp(line, "%%Page:", 7) || !strncmp(line, "%%Trailer", 9)))
       break;
     else if (!strncmp(line, "%%BeginDocument", 15) ||
             !strncmp(line, "%ADO_BeginApplication", 21))
@@ -2464,7 +2720,7 @@ start_nup(pstops_doc_t *doc,              /* I - Document information */
                bboxl;                  /* BoundingBox height */
 
 
-  if (doc->mirror || Orientation || doc->number_up > 1)
+  if (doc->number_up > 1)
     doc_puts(doc, "userdict/ESPsave save put\n");
 
   if (doc->mirror)
@@ -2671,13 +2927,12 @@ start_nup(pstops_doc_t *doc,            /* I - Document information */
           ty = 0.5 * (pagew - 3 * l);
 
           if (doc->normal_landscape)
-            doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
+            doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
          else
-           doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
+           doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
 
           doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
-                     tx + x * y * pagel * 0.5, ty + pagew * 0.333,
-                    w / bboxw, l / bboxl);
+                     tx + x * w, ty + y * l, l / bboxl, w / bboxw);
         }
        else
        {
@@ -2713,17 +2968,17 @@ start_nup(pstops_doc_t *doc,            /* I - Document information */
             l = w * bboxl / bboxw;
           }
 
-          tx = 0.5 * (pagel - 3 * w);
-          ty = 0.5 * (pagew - 2 * l);
+         tx = 0.5 * (pagel - 3 * w);
+         ty = 0.5 * (pagew - 2 * l);
 
           if (doc->normal_landscape)
-           doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
+           doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
          else
-            doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
+            doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
 
           doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
-                     tx + x * pagel * 0.333, ty + y * pagew * 0.5,
-                    w / bboxw, l / bboxl);
+                     tx + w * x, ty + l * y, w / bboxw, l / bboxl);
+
         }
         break;
 
@@ -2870,5 +3125,168 @@ start_nup(pstops_doc_t *doc,            /* I - Document information */
 
 
 /*
- * End of "$Id: pstops.c 5326 2006-03-23 19:33:35Z mike $".
+ * 'write_label_prolog()' - Write the prolog with the classification
+ *                          and page label.
+ */
+
+static void
+write_label_prolog(pstops_doc_t *doc,  /* I - Document info */
+                   const char   *label,        /* I - Page label */
+                  float        bottom, /* I - Bottom position in points */
+                  float        top,    /* I - Top position in points */
+                  float        width)  /* I - Width in points */
+{
+  const char   *classification;        /* CLASSIFICATION environment variable */
+  const char   *ptr;                   /* Temporary string pointer */
+
+
+ /*
+  * First get the current classification...
+  */
+
+  if ((classification = getenv("CLASSIFICATION")) == NULL)
+    classification = "";
+  if (strcmp(classification, "none") == 0)
+    classification = "";
+
+ /*
+  * If there is nothing to show, bind an empty 'write labels' procedure
+  * and return...
+  */
+
+  if (!classification[0] && (label == NULL || !label[0]))
+  {
+    doc_puts(doc, "userdict/ESPwl{}bind put\n");
+    return;
+  }
+
+ /*
+  * Set the classification + page label string...
+  */
+
+  doc_puts(doc, "userdict");
+  if (!strcmp(classification, "confidential"))
+    doc_puts(doc, "/ESPpl(CONFIDENTIAL");
+  else if (!strcmp(classification, "classified"))
+    doc_puts(doc, "/ESPpl(CLASSIFIED");
+  else if (!strcmp(classification, "secret"))
+    doc_puts(doc, "/ESPpl(SECRET");
+  else if (!strcmp(classification, "topsecret"))
+    doc_puts(doc, "/ESPpl(TOP SECRET");
+  else if (!strcmp(classification, "unclassified"))
+    doc_puts(doc, "/ESPpl(UNCLASSIFIED");
+  else
+  {
+    doc_puts(doc, "/ESPpl(");
+
+    for (ptr = classification; *ptr; ptr ++)
+    {
+      if (*ptr < 32 || *ptr > 126)
+        doc_printf(doc, "\\%03o", *ptr);
+      else if (*ptr == '_')
+        doc_puts(doc, " ");
+      else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
+       doc_printf(doc, "\\%c", *ptr);
+      else
+        doc_printf(doc, "%c", *ptr);
+    }
+  }
+
+  if (label)
+  {
+    if (classification[0])
+      doc_puts(doc, " - ");
+
+   /*
+    * Quote the label string as needed...
+    */
+
+    for (ptr = label; *ptr; ptr ++)
+    {
+      if (*ptr < 32 || *ptr > 126)
+        doc_printf(doc, "\\%03o", *ptr);
+      else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
+       doc_printf(doc, "\\%c", *ptr);
+      else
+        doc_printf(doc, "%c", *ptr);
+    }
+  }
+
+  doc_puts(doc, ")put\n");
+
+ /*
+  * Then get a 14 point Helvetica-Bold font...
+  */
+
+  doc_puts(doc, "userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put\n");
+
+ /*
+  * Finally, the procedure to write the labels on the page...
+  */
+
+  doc_puts(doc, "userdict/ESPwl{\n");
+  doc_puts(doc, "  ESPpf setfont\n");
+  doc_printf(doc, "  ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
+             width * 0.5f);
+  doc_puts(doc, "  1 setgray\n");
+  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
+  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
+  doc_puts(doc, "  0 setgray\n");
+  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
+  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
+  doc_printf(doc, "  dup %.0f moveto ESPpl show\n", bottom + 2.0);
+  doc_printf(doc, "  %.0f moveto ESPpl show\n", top - 14.0);
+  doc_puts(doc, "pop\n");
+  doc_puts(doc, "}bind put\n");
+}
+
+
+/*
+ * 'write_labels()' - Write the actual page labels.
+ *
+ * This function is a copy of the one in common.c since we need to
+ * use doc_puts/doc_printf instead of puts/printf...
+ */
+
+static void
+write_labels(pstops_doc_t *doc,                /* I - Document information */
+             int          orient)      /* I - Orientation of the page */
+{
+  float        width,                          /* Width of page */
+       length;                         /* Length of page */
+
+
+  doc_puts(doc, "gsave\n");
+
+  if ((orient ^ Orientation) & 1)
+  {
+    width  = PageLength;
+    length = PageWidth;
+  }
+  else
+  {
+    width  = PageWidth;
+    length = PageLength;
+  }
+
+  switch (orient & 3)
+  {
+    case 1 : /* Landscape */
+        doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", length);
+        break;
+    case 2 : /* Reverse Portrait */
+        doc_printf(doc, "%.1f %.1f translate 180 rotate\n", width, length);
+        break;
+    case 3 : /* Reverse Landscape */
+        doc_printf(doc, "0.0 %.1f translate -90 rotate\n", width);
+        break;
+  }
+
+  doc_puts(doc, "ESPwl\n");
+  doc_puts(doc, "grestore\n");
+}
+
+
+/*
+ * End of "$Id: pstops.c 6320 2007-03-08 13:36:56Z mike $".
  */