]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - filter/pstops.c
Merge changes from CUPS 1.4svn-r7696.
[thirdparty/cups.git] / filter / pstops.c
index 5aea4696b3dda9c0fa5b2fedc136d396dc625f27..7517a4978ae1df69206189db27b5a676d40cf991 100644 (file)
@@ -1,25 +1,16 @@
 /*
- * "$Id: pstops.c 6391 2007-03-24 14:35:56Z mike $"
+ * "$Id: pstops.c 7689 2008-06-24 20:50:57Z mike $"
  *
  *   PostScript filter for the Common UNIX Printing System (CUPS).
  *
+ *   Copyright 2007-2008 by Apple Inc.
  *   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
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  *   This file is subject to the Apple OS-Developed Software exception.
  *
@@ -27,6 +18,7 @@
  *
  *   main()               - Main entry...
  *   add_page()           - Add a page to the pages array...
+ *   cancel_job()         - Flag the job as canceled.
  *   check_range()        - Check to see if the current page is selected for
  *   copy_bytes()         - Copy bytes from the input file to stdout...
  *   copy_comments()      - Copy all of the comments section...
@@ -61,6 +53,8 @@
 #include <math.h>
 #include <cups/file.h>
 #include <cups/array.h>
+#include <cups/i18n.h>
+#include <signal.h>
 
 
 /*
@@ -154,35 +148,43 @@ typedef struct                            /**** Document information ****/
                                 ((p) % doc->number_up) != 0)
 
 
+/*
+ * Local globals...
+ */
+
+static int             JobCanceled = 0;/* Set to 1 on SIGTERM */
+
+
 /*
  * Local functions...
  */
 
 static pstops_page_t   *add_page(pstops_doc_t *doc, const char *label);
+static void            cancel_job(int sig);
 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,
+static ssize_t         copy_comments(cups_file_t *fp, pstops_doc_t *doc,
                                      ppd_file_t *ppd, char *line,
-                                     size_t linelen, size_t linesize);
+                                     ssize_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,
+                                ppd_file_t *ppd, char *line, ssize_t linelen,
                                 size_t linesize);
 static void            copy_non_dsc(cups_file_t *fp, pstops_doc_t *doc,
                                     ppd_file_t *ppd, char *line,
-                                    size_t linelen, size_t linesize);
-static size_t          copy_page(cups_file_t *fp, pstops_doc_t *doc,
+                                    ssize_t linelen, size_t linesize);
+static ssize_t         copy_page(cups_file_t *fp, pstops_doc_t *doc,
                                  ppd_file_t *ppd, int number, char *line,
-                                 size_t linelen, size_t linesize);
-static size_t          copy_prolog(cups_file_t *fp, pstops_doc_t *doc,
+                                 ssize_t linelen, size_t linesize);
+static ssize_t         copy_prolog(cups_file_t *fp, pstops_doc_t *doc,
                                    ppd_file_t *ppd, char *line,
-                                   size_t linelen, size_t linesize);
-static size_t          copy_setup(cups_file_t *fp, pstops_doc_t *doc,
+                                   ssize_t linelen, size_t linesize);
+static ssize_t         copy_setup(cups_file_t *fp, pstops_doc_t *doc,
                                   ppd_file_t *ppd, char *line,
-                                  size_t linelen, size_t linesize);
-static size_t          copy_trailer(cups_file_t *fp, pstops_doc_t *doc,
+                                  ssize_t linelen, size_t linesize);
+static ssize_t         copy_trailer(cups_file_t *fp, pstops_doc_t *doc,
                                     ppd_file_t *ppd, int number, char *line,
-                                    size_t linelen, size_t linesize);
+                                    ssize_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, ...)
@@ -201,7 +203,7 @@ static char         *parse_text(const char *start, char **end, char *buffer,
 static void            set_pstops_options(pstops_doc_t *doc, ppd_file_t *ppd,
                                           char *argv[], int num_options,
                                           cups_option_t *options);
-static size_t          skip_page(cups_file_t *fp, char *line, size_t linelen,
+static ssize_t         skip_page(cups_file_t *fp, char *line, ssize_t linelen,
                                  size_t linesize);
 static void            start_nup(pstops_doc_t *doc, int number,
                                  int show_border, const int *bounding_box);
@@ -226,6 +228,9 @@ main(int  argc,                             /* I - Number of command-line args */
   cups_option_t        *options;               /* Print options */
   char         line[8192];             /* Line buffer */
   size_t       len;                    /* Length of line buffer */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+  struct sigaction action;             /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
 
 
  /*
@@ -240,10 +245,27 @@ main(int  argc,                           /* I - Number of command-line args */
 
   if (argc < 6 || argc > 7)
   {
-    fputs("ERROR: pstops job-id user title copies options [file]\n", stderr);
+    fprintf(stderr, _("Usage: %s job-id user title copies options [file]\n"),
+            argv[0]);
     return (1);
   }
 
+ /*
+  * Register a signal handler to cleanly cancel a job.
+  */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+  sigset(SIGTERM, cancel_job);
+#elif defined(HAVE_SIGACTION)
+  memset(&action, 0, sizeof(action));
+
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = cancel_job;
+  sigaction(SIGTERM, &action, NULL);
+#else
+  signal(SIGTERM, cancel_job);
+#endif /* HAVE_SIGSET */
+
  /*
   * If we have 7 arguments, print the file named on the command-line.
   * Otherwise, send stdin instead...
@@ -259,7 +281,7 @@ main(int  argc,                             /* I - Number of command-line args */
 
     if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
     {
-      fprintf(stderr, "ERROR: Unable to open print file \"%s\" - %s\n",
+      fprintf(stderr, _("ERROR: Unable to open file \"%s\" - %s\n"),
               argv[6], strerror(errno));
       return (1);
     }
@@ -271,7 +293,7 @@ main(int  argc,                             /* I - Number of command-line args */
 
   if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0)
   {
-    fputs("ERROR: Empty print file!\n", stderr);
+    fputs(_("ERROR: Empty print file!\n"), stderr);
     return (1);
   }
 
@@ -405,14 +427,14 @@ add_page(pstops_doc_t *doc,               /* I - Document information */
 
   if (!doc->pages)
   {
-    fprintf(stderr, "EMERG: Unable to allocate memory for pages array: %s\n",
+    fprintf(stderr, _("EMERG: Unable to allocate memory for pages array: %s\n"),
             strerror(errno));
     exit(1);
   }
 
   if ((pageinfo = calloc(1, sizeof(pstops_page_t))) == NULL)
   {
-    fprintf(stderr, "EMERG: Unable to allocate memory for page info: %s\n",
+    fprintf(stderr, _("EMERG: Unable to allocate memory for page info: %s\n"),
             strerror(errno));
     exit(1);
   }
@@ -428,6 +450,19 @@ add_page(pstops_doc_t *doc,                /* I - Document information */
 }
 
 
+/*
+ * 'cancel_job()' - Flag the job as canceled.
+ */
+
+static void
+cancel_job(int sig)                    /* I - Signal number (unused) */
+{
+  (void)sig;
+
+  JobCanceled = 1;
+}
+
+
 /*
  * 'check_range()' - Check to see if the current page is selected for
  *                   printing.
@@ -512,8 +547,12 @@ copy_bytes(cups_file_t *fp,                /* I - File to read from */
 
   if (cupsFileSeek(fp, offset) < 0)
   {
-    fprintf(stderr, "ERROR: Unable to seek to offset " CUPS_LLFMT
-                    " in file - %s\n",
+    fprintf(stderr,
+#ifdef HAVE_LONG_LONG
+            _("ERROR: Unable to seek to offset %lld in file - %s\n"),
+#else
+            _("ERROR: Unable to seek to offset %ld in file - %s\n"),
+#endif /* HAVE_LONG_LONG */
             CUPS_LLCAST offset, strerror(errno));
     return;
   }
@@ -542,12 +581,12 @@ copy_bytes(cups_file_t *fp,               /* I - File to read from */
  * On return, "line" will contain the next line in the file, if any.
  */
 
-static size_t                          /* O - Length of next line */
+static ssize_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 */
+             ssize_t      linelen,     /* I - Length of initial line */
              size_t       linesize)    /* I - Size of line buffer */
 {
   int  saw_bounding_box,               /* Saw %%BoundingBox: comment? */
@@ -597,7 +636,7 @@ copy_comments(cups_file_t  *fp,             /* I - File to read from */
 
 
       if (saw_pages)
-        fputs("ERROR: Duplicate %%Pages: comment seen!\n", stderr);
+        fputs(_("ERROR: Duplicate %%Pages: comment seen!\n"), stderr);
 
       saw_pages = 1;
 
@@ -644,7 +683,7 @@ copy_comments(cups_file_t  *fp,             /* I - File to read from */
     else if (!strncmp(line, "%%BoundingBox:", 14))
     {
       if (saw_bounding_box)
-        fputs("ERROR: Duplicate %%BoundingBox: comment seen!\n", stderr);
+        fputs(_("ERROR: Duplicate %%BoundingBox: comment seen!\n"), stderr);
       else if (strstr(line + 14, "(atend)"))
       {
        /*
@@ -655,7 +694,7 @@ copy_comments(cups_file_t  *fp,             /* I - File to read from */
                      doc->bounding_box + 1, doc->bounding_box + 2,
                      doc->bounding_box + 3) != 4)
       {
-       fputs("ERROR: Bad %%BoundingBox: comment seen!\n", stderr);
+       fputs(_("ERROR: Bad %%BoundingBox: comment seen!\n"), stderr);
 
        doc->bounding_box[0] = (int)PageLeft;
        doc->bounding_box[1] = (int)PageBottom;
@@ -707,10 +746,10 @@ copy_comments(cups_file_t  *fp,           /* I - File to read from */
   }
 
   if (!saw_bounding_box)
-    fputs("ERROR: No %%BoundingBox: comment in header!\n", stderr);
+    fputs(_("ERROR: No %%BoundingBox: comment in header!\n"), stderr);
 
   if (!saw_pages)
-    fputs("ERROR: No %%Pages: comment in header!\n", stderr);
+    fputs(_("ERROR: No %%Pages: comment in header!\n"), stderr);
 
   if (!saw_for)
     WriteTextComment("For", doc->user);
@@ -770,7 +809,7 @@ copy_dsc(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 */
+        ssize_t      linelen,          /* I - Length of initial line */
         size_t       linesize)         /* I - Size of line buffer */
 {
   int          number;                 /* Page number */
@@ -829,6 +868,9 @@ copy_dsc(cups_file_t  *fp,          /* I - File to read from */
   fprintf(stderr, "DEBUG: Before page loop - %s", line);
   while (!strncmp(line, "%%Page:", 7))
   {
+    if (JobCanceled)
+      break;
+
     number ++;
 
     if (check_range(doc, (number - 1) / doc->number_up + 1))
@@ -847,7 +889,8 @@ copy_dsc(cups_file_t  *fp,          /* I - File to read from */
   * Finish up the last page(s)...
   */
 
-  if (number && is_not_last_page(number) && cupsArrayLast(doc->pages))
+  if (number && is_not_last_page(number) && cupsArrayLast(doc->pages) &&
+      check_range(doc, (number - 1) / doc->number_up + 1))
   {
     pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
 
@@ -888,7 +931,7 @@ copy_dsc(cups_file_t  *fp,          /* I - File to read from */
 
   number = doc->slow_order ? 0 : doc->page;
 
-  if (doc->temp)
+  if (doc->temp && !JobCanceled && cupsArrayCount(doc->pages) > 0)
   {
     int        copy;                           /* Current copy */
 
@@ -905,8 +948,16 @@ copy_dsc(cups_file_t  *fp,         /* I - File to read from */
     * Make the copies...
     */
 
-    for (copy = !doc->slow_order; copy < doc->copies; copy ++)
+    if (doc->slow_collate)
+      copy = !doc->slow_order;
+    else
+      copy = doc->copies - 1;
+
+    for (; copy < doc->copies; copy ++)
     {
+      if (JobCanceled)
+       break;
+
      /*
       * Send end-of-job stuff followed by any start-of-job stuff required
       * for the JCL options...
@@ -960,10 +1011,14 @@ copy_dsc(cups_file_t  *fp,               /* I - File to read from */
 
       while (pageinfo)
       {
+        if (JobCanceled)
+         break;
+
         number ++;
 
        if (!ppd || !ppd->num_filters)
-         fprintf(stderr, "PAGE: %d 1\n", number);
+         fprintf(stderr, "PAGE: %d %d\n", number,
+                 doc->slow_collate ? 1 : doc->copies);
 
        if (doc->number_up > 1)
        {
@@ -998,7 +1053,8 @@ copy_dsc(cups_file_t  *fp,         /* I - File to read from */
   * Write/copy the trailer...
   */
 
-  linelen = copy_trailer(fp, doc, ppd, number, line, linelen, linesize);
+  if (!JobCanceled)
+    linelen = copy_trailer(fp, doc, ppd, number, line, linelen, linesize);
 }
 
 
@@ -1013,7 +1069,7 @@ copy_non_dsc(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 */
+            ssize_t      linelen,      /* I - Length of initial line */
             size_t       linesize)     /* I - Size of line buffer */
 {
   int  copy;                           /* Current copy */
@@ -1026,8 +1082,8 @@ copy_non_dsc(cups_file_t  *fp,            /* I - File to read from */
   * that may not print correctly...
   */
 
-  fputs("WARNING: This document does not conform to the Adobe Document "
-        "Structuring Conventions and may not print correctly!\n", stderr);
+  fputs(_("WARNING: This document does not conform to the Adobe Document "
+          "Structuring Conventions and may not print correctly!\n"), stderr);
 
  /*
   * Then write a standard DSC comment section...
@@ -1133,7 +1189,7 @@ copy_non_dsc(cups_file_t  *fp,            /* I - File to read from */
     puts("ESPshowpage");
   }
 
-  if (doc->temp)
+  if (doc->temp && !JobCanceled)
   {
    /*
     * Reopen the temporary file for reading...
@@ -1149,6 +1205,9 @@ copy_non_dsc(cups_file_t  *fp,            /* I - File to read from */
 
     for (copy = 1; copy < doc->copies; copy ++)
     {
+      if (JobCanceled)
+       break;
+
       if (!ppd || !ppd->num_filters)
        fputs("PAGE: 1 1\n", stderr);
 
@@ -1186,13 +1245,13 @@ copy_non_dsc(cups_file_t  *fp,          /* I - File to read from */
  * On return, "line" will contain the next line in the file, if any.
  */
 
-static size_t                          /* O - Length of next line */
+static ssize_t                         /* O - Length of next line */
 copy_page(cups_file_t  *fp,            /* I - File to read from */
           pstops_doc_t *doc,           /* I - Document info */
           ppd_file_t   *ppd,           /* I - PPD file */
          int          number,          /* I - Current page number */
          char         *line,           /* I - Line buffer */
-         size_t       linelen,         /* I - Length of initial line */
+         ssize_t      linelen,         /* I - Length of initial line */
          size_t       linesize)        /* I - Size of line buffer */
 {
   char         label[256],             /* Page label string */
@@ -1200,6 +1259,7 @@ copy_page(cups_file_t  *fp,               /* I - File to read from */
   int          level;                  /* Embedded document level */
   pstops_page_t        *pageinfo;              /* Page information */
   int          first_page;             /* First page on N-up output? */
+  int          has_page_setup;         /* Does the page have %%Begin/EndPageSetup? */
   int          bounding_box[4];        /* PageBoundingBox */
 
 
@@ -1211,13 +1271,13 @@ copy_page(cups_file_t  *fp,             /* I - File to read from */
 
   if (!parse_text(line + 7, &ptr, label, sizeof(label)))
   {
-    fputs("ERROR: Bad %%Page: comment in file!\n", stderr);
+    fputs(_("ERROR: Bad %%Page: comment in file!\n"), stderr);
     label[0] = '\0';
     number   = doc->page;
   }
   else if (strtol(ptr, &ptr, 10) == LONG_MAX || !isspace(*ptr & 255))
   {
-    fputs("ERROR: Bad %%Page: comment in file!\n", stderr);
+    fputs(_("ERROR: Bad %%Page: comment in file!\n"), stderr);
     number = doc->page;
   }
 
@@ -1245,7 +1305,9 @@ copy_page(cups_file_t  *fp,               /* I - File to read from */
       pageinfo->num_options = cupsAddOption("InputSlot", doc->ap_input_slot,
                                             pageinfo->num_options,
                                            &(pageinfo->options));
-      pageinfo->num_options = cupsAddOption("ManualFeed", doc->ap_manual_feed,
+      pageinfo->num_options = cupsAddOption("ManualFeed",
+                                            doc->ap_input_slot ? "False" :
+                                               doc->ap_manual_feed,
                                             pageinfo->num_options,
                                            &(pageinfo->options));
     }
@@ -1258,7 +1320,9 @@ copy_page(cups_file_t  *fp,               /* I - File to read from */
       pageinfo->num_options = cupsAddOption("InputSlot", doc->input_slot,
                                             pageinfo->num_options,
                                            &(pageinfo->options));
-      pageinfo->num_options = cupsAddOption("ManualFeed", doc->manual_feed,
+      pageinfo->num_options = cupsAddOption("ManualFeed",
+                                            doc->input_slot ? "False" :
+                                               doc->manual_feed,
                                             pageinfo->num_options,
                                            &(pageinfo->options));
     }
@@ -1283,7 +1347,7 @@ copy_page(cups_file_t  *fp,               /* I - File to read from */
                  bounding_box + 1, bounding_box + 2,
                 bounding_box + 3) != 4)
       {
-        fputs("ERROR: Bad %%PageBoundingBox: comment in file!\n", stderr);
+        fputs(_("ERROR: Bad %%PageBoundingBox: comment in file!\n"), stderr);
         memcpy(bounding_box, doc->bounding_box,
               sizeof(bounding_box));
       }
@@ -1443,11 +1507,62 @@ copy_page(cups_file_t  *fp,             /* I - File to read from */
   */
 
   if (first_page)
+    doc_puts(doc, "%%BeginPageSetup\n");
+
+  if ((has_page_setup = !strncmp(line, "%%BeginPageSetup", 16)) != 0)
   {
-    char       *page_setup;            /* PageSetup commands to send */
+    int        feature = 0;                    /* In a Begin/EndFeature block? */
 
+    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", 12))
+      {
+       feature = 0;
+
+       if (doc->number_up > 1 || doc->fitplot)
+         continue;
+      }
+      else if (!strncmp(line, "%%IncludeFeature:", 17))
+      {
+       pageinfo->num_options = include_feature(ppd, line,
+                                               pageinfo->num_options,
+                                               &(pageinfo->options));
+       continue;
+      }
+      else if (!strncmp(line, "%%Include", 9))
+       continue;
+
+      if (line[0] != '%' && !feature)
+        break;
+
+      if (!feature || (doc->number_up == 1 && !doc->fitplot))
+       doc_write(doc, line, linelen);
+    }
+
+   /*
+    * Skip %%EndPageSetup...
+    */
+
+    if (linelen > 0 && !strncmp(line, "%%EndPageSetup", 14))
+    {
+      linelen        = cupsFileGetLine(fp, line, linesize);
+      has_page_setup = 0;
+    }
+  }
+
+  if (first_page)
+  {
+    char       *page_setup;            /* PageSetup commands to send */
 
-    doc_puts(doc, "%%BeginPageSetup\n");
 
     if (pageinfo->num_options > 0)
     {
@@ -1518,34 +1633,35 @@ copy_page(cups_file_t  *fp,             /* I - File to read from */
   start_nup(doc, number, 1, bounding_box);
 
  /*
-  * Copy page setup commands as needed...
+  * Finish the PageSetup section as needed...
   */
 
-  if (!strncmp(line, "%%BeginPageSetup", 16))
+  if (has_page_setup)
   {
     int        feature = 0;                    /* In a Begin/EndFeature block? */
 
+    doc_write(doc, line, linelen);
 
     while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
     {
       if (!strncmp(line, "%%EndPageSetup", 14))
-        break;
+       break;
       else if (!strncmp(line, "%%BeginFeature:", 15))
       {
-        feature = 1;
+       feature = 1;
 
        if (doc->number_up > 1 || doc->fitplot)
          continue;
       }
       else if (!strncmp(line, "%%EndFeature", 12))
       {
-        feature = 0;
+       feature = 0;
 
        if (doc->number_up > 1 || doc->fitplot)
          continue;
       }
       else if (!strncmp(line, "%%Include", 9))
-        continue;
+       continue;
 
       if (!feature || (doc->number_up == 1 && !doc->fitplot))
        doc_write(doc, line, linelen);
@@ -1555,14 +1671,10 @@ copy_page(cups_file_t  *fp,             /* I - File to read from */
     * Skip %%EndPageSetup...
     */
 
-    if (linelen > 0)
+    if (linelen > 0 && !strncmp(line, "%%EndPageSetup", 14))
       linelen = cupsFileGetLine(fp, line, linesize);
   }
 
- /*
-  * Finish the PageSetup section as needed...
-  */
-
   if (first_page)
     doc_puts(doc, "%%EndPageSetup\n");
 
@@ -1651,12 +1763,12 @@ copy_page(cups_file_t  *fp,             /* I - File to read from */
  * On return, "line" will contain the next line in the file, if any.
  */
 
-static size_t                          /* O - Length of next line */
+static ssize_t                         /* O - Length of next line */
 copy_prolog(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 */
+           ssize_t      linelen,       /* I - Length of initial line */
            size_t       linesize)      /* I - Size of line buffer */
 {
   while (strncmp(line, "%%BeginProlog", 13))
@@ -1689,7 +1801,7 @@ copy_prolog(cups_file_t  *fp,             /* I - File to read from */
     if (!strncmp(line, "%%EndProlog", 11))
       linelen = cupsFileGetLine(fp, line, linesize);
     else
-      fputs("ERROR: Missing %%EndProlog!\n", stderr);
+      fputs(_("ERROR: Missing %%EndProlog!\n"), stderr);
   }
 
   doc_puts(doc, "%%EndProlog\n");
@@ -1705,12 +1817,12 @@ copy_prolog(cups_file_t  *fp,           /* I - File to read from */
  * On return, "line" will contain the next line in the file, if any.
  */
 
-static size_t                          /* O - Length of next line */
+static ssize_t                         /* O - Length of next line */
 copy_setup(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 */
+          ssize_t      linelen,        /* I - Length of initial line */
           size_t       linesize)       /* I - Size of line buffer */
 {
   while (strncmp(line, "%%BeginSetup", 12))
@@ -1726,8 +1838,6 @@ copy_setup(cups_file_t  *fp,              /* I - File to read from */
 
   doc_puts(doc, "%%BeginSetup\n");
   
-  do_setup(doc, ppd);
-
   if (!strncmp(line, "%%BeginSetup", 12))
   {
     while (strncmp(line, "%%EndSetup", 10))
@@ -1754,9 +1864,11 @@ copy_setup(cups_file_t  *fp,             /* I - File to read from */
     if (!strncmp(line, "%%EndSetup", 10))
       linelen = cupsFileGetLine(fp, line, linesize);
     else
-      fputs("ERROR: Missing %%EndSetup!\n", stderr);
+      fputs(_("ERROR: Missing %%EndSetup!\n"), stderr);
   }
 
+  do_setup(doc, ppd);
+
   doc_puts(doc, "%%EndSetup\n");
 
   return (linelen);
@@ -1770,13 +1882,13 @@ copy_setup(cups_file_t  *fp,            /* I - File to read from */
  * On return, "line" will contain the next line in the file, if any.
  */
 
-static size_t                          /* O - Length of next line */
+static ssize_t                         /* O - Length of next line */
 copy_trailer(cups_file_t  *fp,         /* I - File to read from */
              pstops_doc_t *doc,                /* I - Document info */
              ppd_file_t   *ppd,                /* I - PPD file */
             int          number,       /* I - Number of pages */
             char         *line,        /* I - Line buffer */
-            size_t       linelen,      /* I - Length of initial line */
+            ssize_t      linelen,      /* I - Length of initial line */
             size_t       linesize)     /* I - Size of line buffer */
 {
  /*
@@ -1993,7 +2105,7 @@ doc_printf(pstops_doc_t *doc,             /* I - Document information */
   if (bytes > sizeof(buffer))
   {
     fprintf(stderr,
-            "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n",
+            _("ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"),
             (int)bytes);
     exit(1);
   }
@@ -2124,7 +2236,7 @@ include_feature(
 
   if (sscanf(line + 17, "%254s%254s", name, value) != 2)
   {
-    fputs("ERROR: Bad %%IncludeFeature: comment!\n", stderr);
+    fputs(_("ERROR: Bad %%IncludeFeature: comment!\n"), stderr);
     return (num_options);
   }
 
@@ -2134,21 +2246,21 @@ include_feature(
 
   if ((option = ppdFindOption(ppd, name + 1)) == NULL)
   {
-    fprintf(stderr, "WARNING: Unknown option \"%s\"!\n", name + 1);
+    fprintf(stderr, _("WARNING: Unknown option \"%s\"!\n"), name + 1);
     return (num_options);
   }
 
   if (option->section == PPD_ORDER_EXIT ||
       option->section == PPD_ORDER_JCL)
   {
-    fprintf(stderr, "WARNING: Option \"%s\" cannot be included via "
-                    "IncludeFeature!\n", name + 1);
+    fprintf(stderr, _("WARNING: Option \"%s\" cannot be included via "
+                      "IncludeFeature!\n"), name + 1);
     return (num_options);
   }
 
   if ((choice = ppdFindChoice(option, value)) == NULL)
   {
-    fprintf(stderr, "WARNING: Unknown choice \"%s\" for option \"%s\"!\n",
+    fprintf(stderr, _("WARNING: Unknown choice \"%s\" for option \"%s\"!\n"),
             value, name + 1);
     return (num_options);
   }
@@ -2321,8 +2433,8 @@ set_pstops_options(
 
     if (intval < 10 || intval > 1000)
     {
-      fprintf(stderr, "ERROR: Unsupported brightness value %s, using "
-                      "brightness=100!\n", val);
+      fprintf(stderr, _("ERROR: Unsupported brightness value %s, using "
+                        "brightness=100!\n"), val);
       doc->brightness = 1.0f;
     }
     else
@@ -2388,8 +2500,8 @@ set_pstops_options(
 
     if (intval < 1 || intval > 10000)
     {
-      fprintf(stderr, "ERROR: Unsupported gamma value %s, using "
-                      "gamma=1000!\n", val);
+      fprintf(stderr, _("ERROR: Unsupported gamma value %s, using "
+                        "gamma=1000!\n"), val);
       doc->gamma = 1.0f;
     }
     else
@@ -2412,9 +2524,16 @@ set_pstops_options(
   if ((choice = ppdFindMarkedChoice(ppd, "ManualFeed")) != NULL)
     doc->manual_feed = choice->choice;
 
-  if ((val = cupsGetOption("mirror", num_options, options)) != NULL &&
-      (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
-       !strcasecmp(val, "yes")))
+  if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
+  {
+    val = choice->choice;
+    choice->marked = 0;
+  }
+  else
+    val = cupsGetOption("mirror", num_options, options);
+
+  if (val && (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+              !strcasecmp(val, "yes")))
     doc->mirror = 1;
 
  /*
@@ -2435,8 +2554,8 @@ set_pstops_options(
          break;
       default :
           fprintf(stderr,
-                 "ERROR: Unsupported number-up value %d, using number-up=1!\n",
-                 intval);
+                 _("ERROR: Unsupported number-up value %d, using "
+                   "number-up=1!\n"), intval);
           doc->number_up = 1;
          break;
     }
@@ -2468,8 +2587,8 @@ set_pstops_options(
       doc->number_up_layout = PSTOPS_LAYOUT_BTRL;
     else
     {
-      fprintf(stderr, "ERROR: Unsupported number-up-layout value %s, using "
-                      "number-up-layout=lrtb!\n", val);
+      fprintf(stderr, _("ERROR: Unsupported number-up-layout value %s, using "
+                        "number-up-layout=lrtb!\n"), val);
       doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
     }
   }
@@ -2518,8 +2637,8 @@ set_pstops_options(
       doc->page_border = PSTOPS_BORDERDOUBLE2;
     else
     {
-      fprintf(stderr, "ERROR: Unsupported page-border value %s, using "
-                      "page-border=none!\n", val);
+      fprintf(stderr, _("ERROR: Unsupported page-border value %s, using "
+                        "page-border=none!\n"), val);
       doc->page_border = PSTOPS_BORDERNONE;
     }
   }
@@ -2613,7 +2732,7 @@ set_pstops_options(
     if ((doc->temp = cupsTempFile2(doc->tempfile,
                                    sizeof(doc->tempfile))) == NULL)
     {
-      fprintf(stderr, "ERROR: Unable to create temporary file: %s\n",
+      fprintf(stderr, _("ERROR: Unable to create temporary file: %s\n"),
               strerror(errno));
       exit(1);
     }
@@ -2642,10 +2761,10 @@ set_pstops_options(
  * 'skip_page()' - Skip past a page that won't be printed...
  */
 
-static size_t                          /* O - Length of next line */
+static ssize_t                         /* O - Length of next line */
 skip_page(cups_file_t *fp,             /* I - File to read from */
           char        *line,           /* I - Line buffer */
-         size_t      linelen,          /* I - Length of initial line */
+         ssize_t     linelen,          /* I - Length of initial line */
           size_t      linesize)                /* I - Size of line buffer */
 {
   int  level;                          /* Embedded document level */
@@ -2716,8 +2835,11 @@ start_nup(pstops_doc_t *doc,             /* I - Document information */
                tx, ty;                 /* Translation values for subpage */
   float                pagew,                  /* Printable width of page */
                pagel;                  /* Printable height of page */
-  int          bboxw,                  /* BoundingBox width */
+  int          bboxx,                  /* BoundingBox X origin */
+               bboxy,                  /* BoundingBox Y origin */
+               bboxw,                  /* BoundingBox width */
                bboxl;                  /* BoundingBox height */
+  float                margin = 0;             /* Current margin for border */
 
 
   if (doc->number_up > 1)
@@ -2732,17 +2854,22 @@ start_nup(pstops_doc_t *doc,            /* I - Document information */
 
   if (doc->fitplot)
   {
+    bboxx = bounding_box[0];
+    bboxy = bounding_box[1];
     bboxw = bounding_box[2] - bounding_box[0];
     bboxl = bounding_box[3] - bounding_box[1];
   }
   else
   {
+    bboxx = 0;
+    bboxy = 0;
     bboxw = PageWidth;
     bboxl = PageLength;
   }
 
   fprintf(stderr, "DEBUG: pagew = %.1f, pagel = %.1f\n", pagew, pagel);
-  fprintf(stderr, "DEBUG: bboxw = %d, bboxl = %d\n", bboxw, bboxl);
+  fprintf(stderr, "DEBUG: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d\n",
+          bboxx, bboxy, bboxw, bboxl);
   fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n",
           PageLeft, PageRight);
   fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n",
@@ -3060,8 +3187,7 @@ start_nup(pstops_doc_t *doc,              /* I - Document information */
   if (doc->page_border && show_border)
   {
     int                rects;                  /* Number of border rectangles */
-    float      fscale,                 /* Scaling value for points */
-               margin;                 /* Current margin for borders */
+    float      fscale;                 /* Scaling value for points */
 
 
     rects  = (doc->page_border & PSTOPS_BORDERDOUBLE) ? 2 : 1;
@@ -3084,10 +3210,10 @@ start_nup(pstops_doc_t *doc,            /* I - Document information */
     for (; rects > 0; rects --, margin += 2 * fscale)
       if (doc->number_up > 1)
        doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
-                  margin - 2.25 * fscale,
-                  margin - 2.25 * fscale,
-                  bboxw + 4.5 * fscale - 2 * margin,
-                  bboxl + 4.5 * fscale - 2 * margin);
+                  margin,
+                  margin,
+                  bboxw - 2 * margin,
+                  bboxl - 2 * margin);
       else
        doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
                   PageLeft + margin,
@@ -3105,21 +3231,22 @@ start_nup(pstops_doc_t *doc,            /* I - Document information */
   if (doc->fitplot)
   {
    /*
-    * Clip the page that follows to the bounding box of the page...
+    * Offset the page by its bounding box...
     */
 
     doc_printf(doc, "%d %d translate\n", -bounding_box[0],
                -bounding_box[1]);
-    doc_printf(doc, "%d %d %d %d ESPrc\n", bounding_box[0], bounding_box[1],
-               bboxw, bboxl);
   }
-  else if (doc->number_up > 1)
+
+  if (doc->fitplot || doc->number_up > 1)
   {
    /*
-    * Clip the page that follows to the default page size...
+    * Clip the page to the page's bounding box...
     */
 
-    doc_printf(doc, "0 0 %d %d ESPrc\n", bboxw, bboxl);
+    doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrc\n",
+               bboxx + margin, bboxy + margin,
+               bboxw - 2 * margin, bboxl - 2 * margin);
   }
 }
 
@@ -3288,5 +3415,5 @@ write_labels(pstops_doc_t *doc,           /* I - Document information */
 
 
 /*
- * End of "$Id: pstops.c 6391 2007-03-24 14:35:56Z mike $".
+ * End of "$Id: pstops.c 7689 2008-06-24 20:50:57Z mike $".
  */