]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - filter/pstops.c
Merge changes from CUPS 1.4svn-r8067 (tentative CUPS 1.4b1)
[thirdparty/cups.git] / filter / pstops.c
index 964df186719d13cc453700e66d66a1ef87079ac5..0e8ac48d05740b57a75effef8ba162b1ca121948 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: pstops.c 7006 2007-10-04 17:43:38Z mike $"
+ * "$Id: pstops.c 7977 2008-09-23 23:44:33Z mike $"
  *
  *   PostScript filter for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2008 by Apple Inc.
  *   Copyright 1993-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
  *
  * Contents:
  *
- *   main()               - Main entry...
- *   add_page()           - Add a page to the pages array...
+ *   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...
- *   copy_dsc()           - Copy a DSC-conforming document...
- *   copy_non_dsc()       - Copy a document that does not conform to the DSC...
- *   copy_page()          - Copy a page description...
- *   copy_prolog()        - Copy the document prolog section...
- *   copy_setup()         - Copy the document setup section...
- *   copy_trailer()       - Copy the document trailer...
- *   do_prolog()          - Send the necessary document prolog commands...
- *   do_setup()           - Send the necessary document setup commands...
+ *                          printing.
+ *   copy_bytes()         - Copy bytes from the input file to stdout.
+ *   copy_comments()      - Copy all of the comments section.
+ *   copy_dsc()           - Copy a DSC-conforming document.
+ *   copy_non_dsc()       - Copy a document that does not conform to the DSC.
+ *   copy_page()          - Copy a page description.
+ *   copy_prolog()        - Copy the document prolog section.
+ *   copy_setup()         - Copy the document setup section.
+ *   copy_trailer()       - Copy the document trailer.
+ *   do_prolog()          - Send the necessary document prolog commands.
+ *   do_setup()           - Send the necessary document setup commands.
  *   doc_printf()         - Send a formatted string to stdout and/or the temp
  *                          file.
  *   doc_puts()           - Send a nul-terminated string to stdout and/or the
  *                          temp file.
  *   doc_write()          - Send data to stdout and/or the temp file.
- *   end_nup()            - End processing for N-up printing...
+ *   end_nup()            - End processing for N-up printing.
  *   include_feature()    - Include a printer option/feature command.
- *   parse_text()         - Parse a text value in a comment...
- *   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...
+ *   parse_text()         - Parse a text value in a comment.
+ *   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_label_prolog() - Write the prolog with the classification and page
+ *                          label.
  *   write_labels()       - Write the actual page labels.
+ *   write_options()      - Write options provided via %%IncludeFeature.
  */
 
 /*
@@ -164,27 +168,27 @@ 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, ...)
@@ -203,7 +207,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);
@@ -211,10 +215,12 @@ 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);
+static void            write_options(pstops_doc_t  *doc, ppd_file_t *ppd,
+                                     int num_options, cups_option_t *options);
 
 
 /*
- * 'main()' - Main entry...
+ * 'main()' - Main entry.
  */
 
 int                                    /* O - Exit status */
@@ -412,7 +418,7 @@ main(int  argc,                             /* I - Number of command-line args */
 
 
 /*
- * 'add_page()' - Add a page to the pages array...
+ * 'add_page()' - Add a page to the pages array.
  */
 
 static pstops_page_t *                 /* O - New page info object */
@@ -530,7 +536,7 @@ check_range(pstops_doc_t *doc,              /* I - Document information */
 
 
 /*
- * 'copy_bytes()' - Copy bytes from the input file to stdout...
+ * 'copy_bytes()' - Copy bytes from the input file to stdout.
  */
 
 static void
@@ -575,18 +581,18 @@ copy_bytes(cups_file_t *fp,               /* I - File to read from */
 
 
 /*
- * 'copy_comments()' - Copy all of the comments section...
+ * 'copy_comments()' - Copy all of the comments section.
  *
  * This function expects "line" to be filled with a comment line.
  * 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? */
@@ -799,7 +805,7 @@ copy_comments(cups_file_t  *fp,             /* I - File to read from */
 
 
 /*
- * 'copy_dsc()' - Copy a DSC-conforming document...
+ * 'copy_dsc()' - Copy a DSC-conforming document.
  *
  * This function expects "line" to be filled with the %!PS-Adobe comment line.
  */
@@ -809,7 +815,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 */
@@ -889,7 +895,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);
 
@@ -930,7 +937,7 @@ copy_dsc(cups_file_t  *fp,          /* I - File to read from */
 
   number = doc->slow_order ? 0 : doc->page;
 
-  if (doc->temp && !JobCanceled)
+  if (doc->temp && !JobCanceled && cupsArrayCount(doc->pages) > 0)
   {
     int        copy;                           /* Current copy */
 
@@ -1053,12 +1060,12 @@ copy_dsc(cups_file_t  *fp,              /* I - File to read from */
   */
 
   if (!JobCanceled)
-    linelen = copy_trailer(fp, doc, ppd, number, line, linelen, linesize);
+    copy_trailer(fp, doc, ppd, number, line, linelen, linesize);
 }
 
 
 /*
- * 'copy_non_dsc()' - Copy a document that does not conform to the DSC...
+ * 'copy_non_dsc()' - Copy a document that does not conform to the DSC.
  *
  * This function expects "line" to be filled with the %! comment line.
  */
@@ -1068,7 +1075,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 */
@@ -1238,19 +1245,19 @@ copy_non_dsc(cups_file_t  *fp,          /* I - File to read from */
 
 
 /*
- * 'copy_page()' - Copy a page description...
+ * 'copy_page()' - Copy a page description.
  *
  * This function expects "line" to be filled with a %%Page comment line.
  * 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 */
@@ -1258,6 +1265,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 */
 
 
@@ -1505,60 +1513,65 @@ copy_page(cups_file_t  *fp,             /* I - File to read from */
   */
 
   if (first_page)
-  {
-    char       *page_setup;            /* PageSetup commands to send */
-
-
     doc_puts(doc, "%%BeginPageSetup\n");
 
-    if (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 */
+  if ((has_page_setup = !strncmp(line, "%%BeginPageSetup", 16)) != 0)
+  {
+    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;
 
-     /*
-      * Yes, figure out the minimum OrderDependency value...
-      */
+       if (doc->number_up > 1 || doc->fitplot)
+         continue;
+      }
+      else if (!strncmp(line, "%%EndFeature", 12))
+      {
+       feature = 0;
 
-      if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
-       min_order = option->order;
-      else
-       min_order = 999.0f;
+       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;
 
-      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 (line[0] != '%' && !feature)
+        break;
 
-     /*
-      * Mark and extract them...
-      */
+      if (!feature || (doc->number_up == 1 && !doc->fitplot))
+       doc_write(doc, line, linelen);
+    }
 
-      cupsMarkOptions(ppd, pageinfo->num_options, pageinfo->options);
+   /*
+    * Skip %%EndPageSetup...
+    */
 
-      doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
-      any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
+    if (linelen > 0 && !strncmp(line, "%%EndPageSetup", 14))
+    {
+      linelen        = cupsFileGetLine(fp, line, linesize);
+      has_page_setup = 0;
+    }
+  }
 
-     /*
-      * Then send them out...
-      */
+  if (first_page)
+  {
+    char       *page_setup;            /* PageSetup commands to send */
 
-      if (doc_setup)
-      {
-       doc_puts(doc, doc_setup);
-       free(doc_setup);
-      }
 
-      if (any_setup)
-      {
-       doc_puts(doc, any_setup);
-       free(any_setup);
-      }
-    }
+    if (pageinfo->num_options > 0)
+      write_options(doc, ppd, pageinfo->num_options, pageinfo->options);
 
    /*
     * Output commands for the current page...
@@ -1580,34 +1593,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);
@@ -1617,14 +1631,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");
 
@@ -1707,18 +1717,18 @@ copy_page(cups_file_t  *fp,             /* I - File to read from */
 
 
 /*
- * 'copy_prolog()' - Copy the document prolog section...
+ * 'copy_prolog()' - Copy the document prolog section.
  *
  * This function expects "line" to be filled with a %%BeginProlog comment line.
  * 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))
@@ -1761,20 +1771,24 @@ copy_prolog(cups_file_t  *fp,           /* I - File to read from */
 
 
 /*
- * 'copy_setup()' - Copy the document setup section...
+ * 'copy_setup()' - Copy the document setup section.
  *
  * This function expects "line" to be filled with a %%BeginSetup comment line.
  * 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 */
 {
+  int          num_options;            /* Number of options */
+  cups_option_t        *options;               /* Options */
+
+
   while (strncmp(line, "%%BeginSetup", 12))
   {
     if (!strncmp(line, "%%Page:", 7))
@@ -1790,6 +1804,9 @@ copy_setup(cups_file_t  *fp,              /* I - File to read from */
   
   do_setup(doc, ppd);
 
+  num_options = 0;
+  options     = NULL;
+
   if (!strncmp(line, "%%BeginSetup", 12))
   {
     while (strncmp(line, "%%EndSetup", 10))
@@ -1803,8 +1820,7 @@ copy_setup(cups_file_t  *fp,              /* I - File to read from */
        */
 
         if (doc->number_up == 1 && !doc->fitplot)
-         doc->num_options = include_feature(ppd, line, doc->num_options,
-                                             &(doc->options));
+         num_options = include_feature(ppd, line, num_options, &options);
       }
       else if (strncmp(line, "%%BeginSetup", 12))
         doc_write(doc, line, linelen);
@@ -1819,6 +1835,12 @@ copy_setup(cups_file_t  *fp,             /* I - File to read from */
       fputs(_("ERROR: Missing %%EndSetup!\n"), stderr);
   }
 
+  if (num_options > 0)
+  {
+    write_options(doc, ppd, num_options, options);
+    cupsFreeOptions(num_options, options);
+  }
+
   doc_puts(doc, "%%EndSetup\n");
 
   return (linelen);
@@ -1826,19 +1848,19 @@ copy_setup(cups_file_t  *fp,            /* I - File to read from */
 
 
 /*
- * 'copy_trailer()' - Copy the document trailer...
+ * 'copy_trailer()' - Copy the document trailer.
  *
  * This function expects "line" to be filled with a %%Trailer comment line.
  * 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 */
 {
  /*
@@ -1875,7 +1897,7 @@ copy_trailer(cups_file_t  *fp,            /* I - File to read from */
 
 
 /*
- * 'do_prolog()' - Send the necessary document prolog commands...
+ * 'do_prolog()' - Send the necessary document prolog commands.
  */
 
 static void
@@ -1914,7 +1936,7 @@ do_prolog(pstops_doc_t *doc,              /* I - Document information */
 
 
 /*
- * 'do_setup()' - Send the necessary document setup commands...
+ * 'do_setup()' - Send the necessary document setup commands.
  */
 
 static void
@@ -1933,7 +1955,7 @@ do_setup(pstops_doc_t *doc,               /* I - Document information */
   doc_puts(doc, "userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
 
  /*
-  * Mark any options from %%IncludeFeature: comments...
+  * Mark job options...
   */
 
   cupsMarkOptions(ppd, doc->num_options, doc->options);
@@ -2097,7 +2119,7 @@ doc_write(pstops_doc_t *doc,              /* I - Document information */
 
 
 /*
- * 'end_nup()' - End processing for N-up printing...
+ * 'end_nup()' - End processing for N-up printing.
  */
 
 static void
@@ -2177,7 +2199,6 @@ include_feature(
   char         name[255],              /* Option name */
                value[255];             /* Option value */
   ppd_option_t *option;                /* Option in file */
-  ppd_choice_t *choice;                /* Choice */
 
 
  /*
@@ -2208,7 +2229,7 @@ include_feature(
     return (num_options);
   }
 
-  if ((choice = ppdFindChoice(option, value)) == NULL)
+  if (!ppdFindChoice(option, value))
   {
     fprintf(stderr, _("WARNING: Unknown choice \"%s\" for option \"%s\"!\n"),
             value, name + 1);
@@ -2224,7 +2245,7 @@ include_feature(
 
 
 /*
- * 'parse_text()' - Parse a text value in a comment...
+ * 'parse_text()' - Parse a text value in a comment.
  *
  * This function parses a DSC text value as defined on page 36 of the
  * DSC specification.  Text values are either surrounded by parenthesis
@@ -2313,7 +2334,7 @@ parse_text(const char *start,             /* I - Start of text value */
 
 
 /*
- * 'set_pstops_options()' - Set pstops options...
+ * 'set_pstops_options()' - Set pstops options.
  */
 
 static void
@@ -2708,13 +2729,13 @@ set_pstops_options(
 
 
 /*
- * 'skip_page()' - Skip past a page that won't be printed...
+ * '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 */
@@ -2770,7 +2791,7 @@ skip_page(cups_file_t *fp,                /* I - File to read from */
 
 
 /*
- * 'start_nup()' - Start processing for N-up printing...
+ * 'start_nup()' - Start processing for N-up printing.
  */
 
 static void
@@ -2785,33 +2806,38 @@ 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)
     doc_puts(doc, "userdict/ESPsave save put\n");
 
-  if (doc->mirror)
-    doc_printf(doc, "%.1f 0.0 translate -1 1 scale\n", PageWidth);
-
   pos   = (number - 1) % doc->number_up;
   pagew = PageRight - PageLeft;
   pagel = PageTop - PageBottom;
 
   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",
@@ -2838,6 +2864,9 @@ start_nup(pstops_doc_t *doc,              /* I - Document information */
   else if (doc->number_up > 1 || doc->fitplot)
     doc_printf(doc, "%.1f %.1f translate\n", PageLeft, PageBottom);
 
+  if (doc->mirror)
+    doc_printf(doc, "%.1f 0.0 translate -1 1 scale\n", PageWidth);
+
   switch (doc->number_up)
   {
     default :
@@ -2859,10 +2888,7 @@ start_nup(pstops_doc_t *doc,             /* I - Document information */
                     w / bboxw, l / bboxl);
        }
        else
-       {
           w = PageWidth;
-         l = PageLength;
-       }
        break;
 
     case 2 :
@@ -3129,8 +3155,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;
@@ -3153,10 +3178,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,
@@ -3174,21 +3199,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);
   }
 }
 
@@ -3357,5 +3383,64 @@ write_labels(pstops_doc_t *doc,          /* I - Document information */
 
 
 /*
- * End of "$Id: pstops.c 7006 2007-10-04 17:43:38Z mike $".
+ * 'write_options()' - Write options provided via %%IncludeFeature.
+ */
+
+static void
+write_options(
+    pstops_doc_t  *doc,                /* I - Document */
+    ppd_file_t    *ppd,                /* I - PPD file */
+    int           num_options, /* I - Number of options */
+    cups_option_t *options)    /* I - Options */
+{
+  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 */
+
+
+ /*
+  * Figure out the minimum OrderDependency value...
+  */
+
+  if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
+    min_order = option->order;
+  else
+    min_order = 999.0f;
+
+  for (i = 0; i < num_options; i ++)
+    if ((option = ppdFindOption(ppd, options[i].name)) != NULL &&
+       option->order < min_order)
+      min_order = option->order;
+
+ /*
+  * Mark and extract them...
+  */
+
+  cupsMarkOptions(ppd, num_options, options);
+
+  doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
+  any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
+
+ /*
+  * Then send them out...
+  */
+
+  if (doc_setup)
+  {
+    doc_puts(doc, doc_setup);
+    free(doc_setup);
+  }
+
+  if (any_setup)
+  {
+    doc_puts(doc, any_setup);
+    free(any_setup);
+  }
+}
+
+
+/*
+ * End of "$Id: pstops.c 7977 2008-09-23 23:44:33Z mike $".
  */