]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters, texttotext: Converted texttotext into a filter function
authorPratyush Ranjan <pratyush.ranjan911@gmail.com>
Thu, 7 Oct 2021 21:40:54 +0000 (03:10 +0530)
committerGitHub <noreply@github.com>
Thu, 7 Oct 2021 21:40:54 +0000 (23:40 +0200)
Pull request #425

Makefile.am
cupsfilters/filter.h
cupsfilters/texttotext.c [new file with mode: 0644]
filter/texttotext.c

index e0e0b11402da46fbfaa1695a8b44fea2403197c1..edeebb3398be14b29bb4dd081d282c4362f22935 100644 (file)
@@ -402,6 +402,7 @@ libcupsfilters_la_SOURCES = \
        cupsfilters/rgb.c \
        cupsfilters/srgb.c \
        cupsfilters/texttopdf.c \
+       cupsfilters/texttotext.c \
        $(pkgfiltersinclude_DATA)
 EXTRA_libcupsfilters_la_SOURCES = \
        cupsfilters/getline.c \
@@ -946,18 +947,12 @@ endif
 
 texttotext_SOURCES = \
        filter/texttotext.c
-EXTRA_texttotext_SOURCES = cupsfilters/strcasestr.c
 texttotext_CFLAGS = \
-       -I$(srcdir)/ppd/ \
+       -I$(srcdir)/cupsfilters/ \
        $(CUPS_CFLAGS)
 texttotext_LDADD = \
-       libppd.la \
-       $(STRCASESTR) \
-       $(CUPS_LIBS) \
-       $(LIBICONV)
-texttotext_DEPENDENCIES = \
-       $(STRCASESTR) \
-       libppd.la
+       libcupsfilters.la \
+       $(CUPS_LIBS)
 
 texttopdf_SOURCES = \
        filter/texttopdf.c
index 135be02badd6252a5ffb3cd206d8baded2d015a9..7462290778b2501d51c8167db281f03259a8e6e6 100644 (file)
@@ -320,6 +320,11 @@ extern int texttopdf(int inputfd,
    Data directory (fonts, charsets), charset, content type (for prettyprint),
    classification (for overprint/watermark) */
 
+extern int texttotext(int inputfd,
+                    int outputfd,
+                    int inputseekable,
+                    filter_data_t *data,
+                    void *parameters);
 
 extern void filterSetCommonOptions(ppd_file_t *ppd,
                                   int num_options,
diff --git a/cupsfilters/texttotext.c b/cupsfilters/texttotext.c
new file mode 100644 (file)
index 0000000..1f952c2
--- /dev/null
@@ -0,0 +1,1080 @@
+/*
+ *   texttotext
+ *
+ *   Filter to print text files on text-only printers. The filter has
+ *   several configuration options controlled by a PPD file so that it
+ *   should work with most printer models.
+ *
+ *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 1997-2006 by Easy Software Products.
+ *   Copyright 2011-2016 by Till Kamppeter
+ *
+ *   Distribution and use rights are outlined in the file "COPYING"
+ *   which should have been included with this file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <config.h>
+#include <cups/cups.h>
+#include <ppd/ppd.h>
+#include <cups/file.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <iconv.h>
+#include <cupsfilters/image-private.h>
+#include "filter.h"
+
+/*
+ * Type definitions
+ */
+
+typedef enum overlong_line_e {
+  TRUNCATE = 0,
+  WORDWRAP = 1,
+  WRAPATWIDTH = 2
+} overlong_line_t;
+
+typedef enum newline_char_e {
+  LF = 0,
+  CR = 1,
+  CRLF = 2
+} newline_char_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int              is_true(const char *value);
+static int              is_false(const char *value);
+static int             check_range(char *page_ranges, int even_pages,
+                                   int odd_pages, int page);
+
+int texttotext(int inputfd,         /* I - File descriptor input stream */
+       int outputfd,                 /* I - File descriptor output stream */
+       int inputseekable,            /* I - Is input stream seekable? (unused)*/
+       filter_data_t *data,          /* I - Job and printer data */
+       void *parameters)             /* I - Filter-specific parameters */
+{
+  int          i, j;                   /* Looping vars */
+  char          *p;
+  int          exit_status = 0;        /* Exit status */
+  int          fd;                     /* Copy file descriptor */
+
+  char         buffer[8192];           /* Copy buffer */
+  int           num_copies;             /* Number of copies */
+  ppd_file_t   *ppd;                   /* PPD file */
+  int          num_options;            /* Number of options */
+  cups_option_t        *options;               /* Options */
+  const char   *val, *val2;                    /* Option value */
+  ppd_attr_t    *ppd_attr;              /* Attribute taken from the PPD */
+  int           num_lines = 66,         /* Lines per page */
+                num_columns = 80;       /* Characters per line */
+  int           page_left = 0,          /* Page margins */
+                page_right = 0,
+                page_top = 0,
+                page_bottom = 0,
+                num_lines_per_inch = 6,
+                num_chars_per_inch = 10;
+  int           text_width,             /* Width of the text area on the page */
+                text_height;            /* Height of the text area on the
+                                          page */
+  char          encoding[64];           /* The printer'a encoding, to which
+                                          the incoming UTF-8 is converted,
+                                          must be 1-byte-per-character */
+  overlong_line_t overlong_lines = WRAPATWIDTH;
+                                        /* How to treat overlong lines */
+  int           tab_width = 8;          /* Turn tabs to spaces with given
+                                          width */
+  int           pagination = 1;         /* Paginate text to allow margins
+                                           and page management */
+  int           send_ff = 1;            /* Send form-feed char at the end of
+                                          each page */
+  newline_char_t newline_char = CRLF;   /* Character to send at end of line */
+  char          *newline_char_str;
+  char          *page_ranges = NULL;    /* Selection of pages to print */
+  int           even_pages = 1;         /* Print the even pages */
+  int           odd_pages = 1;          /* Print the odd pages */
+  int           reverse_order = 0;      /* Ouput pages in reverse order? */
+  int           collate = 1;            /* Collate multiple copies? */
+  int           page_size;              /* Number of bytes needed for a page,
+                                          to allocate the memory for the
+                                          output page buffer */
+  char          *out_page = NULL;       /* Output page buffer */
+  cups_array_t  *page_array = NULL;     /* Array to hold the output pages
+                                          for collated copies and reverse
+                                          output order */
+  iconv_t       cd;                     /* Conversion descriptor, describes
+                                          between which encodings iconv
+                                          should convert */
+  char          outbuf[4096];           /* Output buffer for iconv */
+  char          inbuf[2048];            /* Input buffer for iconv */
+  size_t        outsize;                /* Space left in outbuf */
+  size_t        insize = 0;             /* Bytes still to be converted in
+                                          inbuf */
+  char          *outptr = outbuf;       /* Pointer for next converted
+                                          character to be dropped */
+  char          *inptr = inbuf;         /* Pointer to next character to be
+                                          converted */
+  size_t        nread;                  /* Number of bytes read from file */
+  size_t        nconv;                  /* -1 on conversion error */
+  int           incomplete_char = 0;    /* Was last character in input buffer
+                                          incomplete */
+  int           result = 0;             /* Conversion result (-1 on error) */
+  char          *procptr,               /* Pointer into conversion output
+                                           to indicate next byte to process
+                                          for output page creation */
+                *destptr;               /* Pointer into output page buffer
+                                           where next character will be put */
+  int           page,                   /* Number of current output page */
+                line, column;           /* Character coordiantes on output
+                                          page */
+  int           page_empty;             /* Is the current output page still
+                                          empty (no visible characters)? */
+  int           previous_is_cr;         /* Is the previous character processed
+                                          a Carriage Return? */
+  int           skip_rest_of_line = 0;  /* Are we truncating an overlong
+                                          line? */
+  int           skip_spaces = 0;        /* Are we skipping spaces at a line
+                                          break when word-wrapping? */
+  char          *wrapped_word = NULL;   /* Section of a word wrapped over
+                                          to the next line */
+  int           num_pages = 0;          /* Number of pages which get actually
+                                          printed */
+  ipp_t *printer_attrs = NULL;
+  ipp_t *job_attrs = NULL;
+  ipp_attribute_t *ipp;
+  ipp_t *defsize;
+  char buf[2048];
+
+  filter_logfunc_t     log = data->logfunc;
+  void          *ld = data->logdata;
+
+  filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
+  void                 *icd = data->iscanceleddata;
+  cups_file_t *outputfp;
+
+ /*
+  * Make sure status messages are not buffered...
+  */
+
+  setbuf(stderr, NULL);
+
+
+  if ((outputfp = cupsFileOpenFd(outputfd, "w")) == NULL)
+  {
+    if (!iscanceled || !iscanceled(icd))
+    {
+      if (log) log(ld, FILTER_LOGLEVEL_DEBUG,
+                    "bannertopdf: Unable to open output data stream.");
+    }
+    return (1);
+  }
+
+ /*
+  * Number of copies
+  */
+
+  num_copies = data->copies;
+  if (num_copies < 1)
+    num_copies = 1;
+
+ /*
+  * Get the options from the fifth command line argument
+  */
+
+  num_options = data->num_options;
+
+ /*
+  * Load the PPD file and mark options...
+  */
+
+  ppd = data->ppd;
+  options = data->options;
+  if (ppd)
+  {
+    ppdMarkOptions(ppd, num_options, options);
+  }
+
+ /*
+  * Parse the options
+  */
+
+  /*  Default page size attributes as per printer attributes  */
+  defsize = ippGetCollection(ippFindAttribute(printer_attrs,       
+                          "media-col-default", IPP_TAG_ZERO), 0);
+  
+  if((val = cupsGetOption("NumLinesPerInch", num_options, options))!= NULL         ||
+    (ipp = ippFindAttribute(job_attrs,"num-lines-per-inch", IPP_TAG_INTEGER)) != NULL ||
+    (ipp = ippFindAttribute(printer_attrs,"num-lines-per-inch-default", IPP_TAG_INTEGER)) != NULL ||
+    (ppd_attr = ppdFindAttr(ppd, "DefaultNumLinesPerInch",NULL))!=NULL){
+      if(val == NULL && ipp!=NULL){
+        ippAttributeString(ipp, buf, sizeof(buf));
+        val = buf;
+      }
+      if(val == NULL){
+        val = ppd_attr->value;
+      }
+      num_lines_per_inch = atoi(val);
+    }
+
+  if((val = cupsGetOption("NumCharsPerInch", num_options, options))!= NULL          ||
+    (ipp = ippFindAttribute(job_attrs,"num-chars-per-inch", IPP_TAG_INTEGER)) != NULL  ||
+    (ipp = ippFindAttribute(printer_attrs,"num-chars-per-inch-default", IPP_TAG_INTEGER)) != NULL  ||
+    (ppd_attr = ppdFindAttr(ppd, "DefautlNumCharsPerInch", NULL))!=NULL){
+      if(val == NULL && ipp!=NULL){
+        ippAttributeString(ipp, buf, sizeof(buf));
+        val = buf;
+      }
+      if(val == NULL){
+        val = ppd_attr->value;
+      }
+      num_chars_per_inch = atoi(val);
+    }
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG,"texttotext: num of lines per inch = %d",num_lines_per_inch);
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG,"texttotext: num of chars per inch = %d",num_chars_per_inch);
+
+  /* With the "PageSize"/"PageRegion" options we only determine the number
+     of lines and columns of a page, we do not use the geometry defined by
+     "PaperDimension" and "ImageableArea" in the PPD */
+  if ((val = cupsGetOption("PageSize", num_options, options)) != NULL       ||
+      (val = cupsGetOption("PageRegion", num_options, options)) != NULL     ||
+      (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO ))!=NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-region", IPP_TAG_ZERO))!=NULL||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultPageSize", NULL)) != NULL        ||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultPageRegion", NULL)) != NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val==NULL)
+      val = ppd_attr->value;
+
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG,"texttotext: PageSize: %s", val);
+    snprintf(buffer, sizeof(buffer), "Default%sNumLines", val);
+    if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
+  (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!= NULL   ||
+  (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
+  (ppd_attr = ppdFindAttr(ppd, buffer, NULL)) != NULL) {
+    char buf2[2048];
+      if (val2 == NULL && ipp!=NULL){
+        ippAttributeString(ipp, buf2, sizeof(buf2));
+        val2 = buf2;
+      }
+      if(val2==NULL)
+             val2 = ppd_attr->value;
+      if (!strncasecmp(val2, "Custom.", 7))
+       val2 += 7;
+      num_lines = atoi(val2);
+    }
+    snprintf(buffer, sizeof(buffer), "Default%sNumColumns", val);
+    if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!=NULL  ||
+      (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, buffer, NULL))!=NULL) {
+    char buf2[2048];
+      if (val2 == NULL && ipp!=NULL){
+        ippAttributeString(ipp, buf2, sizeof(buf2));
+        val2 = buf2;
+      }
+if(val2==NULL)
+       val2 = ppd_attr->value;
+      if (!strncasecmp(val2, "Custom.", 7))
+       val2 += 7;
+      num_columns = atoi(val2);
+    }
+    if (num_lines <= 0) {
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG,"texttotext: Invalid number of lines %d, using default: 66",
+             num_lines);
+      num_lines = 66;
+    }
+    if (num_columns <= 0) {
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG,"texttotext: Invalid number of columns %d, using default: 80",
+             num_columns);
+      num_columns = 80;
+    }
+  }
+  else if((ipp = ippFindAttribute(defsize, "media-size", IPP_TAG_ZERO))!= NULL){
+    ipp_t *media_size = ippGetCollection(ipp, 0);
+    int x_dim = ippGetInteger(ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO),0);
+    int y_dim = ippGetInteger(ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO),0);
+    num_lines = (int)((y_dim/72.0)*(num_lines_per_inch));         /*  Since y_dim and x_dim are in points, 
+                                                                      divide them by 72 to convert in inch  */
+    num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
+  }
+  else if((ipp = ippFindAttribute(printer_attrs, "media-default", IPP_TAG_ZERO))!=NULL){
+    pwg_media_t *pwg = pwgMediaForPWG(ippGetString(ipp, 0, NULL));
+    int x_dim = pwg->width;
+    int y_dim = pwg->length;
+    num_lines = (int)((y_dim/72.0)*(num_lines_per_inch));
+    num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
+  }
+  if (num_lines <= 0) {
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG,"texttotext: Invalid number of lines %d, using default: 66",
+             num_lines);
+    num_lines = 66;
+  }
+  if (num_columns <= 0) {
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG,"texttotext: Invalid number of columns %d, using default: 80",
+             num_columns);
+    num_columns = 80;
+  }
+
+  /* Direct specification of number of lines/columns, mainly for debugging
+     and development */
+  if ((val = cupsGetOption("page-height", num_options, options)) != NULL  ||
+      (ipp = ippFindAttribute(job_attrs, "page-height", IPP_TAG_INTEGER))!=NULL) {
+        if(val == NULL){
+          ippAttributeString(ipp, buf, sizeof(buf));
+          val = buf;
+        }
+    i = atoi(val);
+    if (i > 0)
+      num_lines = i;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid number of lines %d, using default value: %d",
+             i, num_lines);
+  }
+  if ((val = cupsGetOption("page-width", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-width", IPP_TAG_INTEGER))!=NULL) {
+    if(val == NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    i = atoi(val);
+    if (i > 0)
+      num_columns = i;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid number of columns %d, using default value: %d",
+             i, num_columns);
+  }
+
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Lines per page: %d; Characters per line: %d",
+         num_lines, num_columns);
+  
+  if ((val = cupsGetOption("page-left", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-left", IPP_TAG_INTEGER))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-left", NULL)) != NULL ||
+      (ipp = ippFindAttribute(defsize, "media-left-margin", IPP_TAG_INTEGER))!=NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (!strncasecmp(val, "Custom.", 7))
+      val += 7;
+    page_left = atoi(val);
+    if (page_left < 0 || page_left > num_columns - 1) {
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid left margin %d, setting to 0",
+             page_left);
+      page_left = 0;
+    }
+  }
+  if ((val = cupsGetOption("page-right", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "page-right", IPP_TAG_INTEGER))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-right", NULL)) != NULL  ||
+        (ipp = ippFindAttribute(defsize, "media-right-margin", IPP_TAG_INTEGER))!=NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (!strncasecmp(val, "Custom.", 7))
+      val += 7;
+    page_right = atoi(val);
+    if (page_right < 0 || page_right > num_columns - page_left - 1) {
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid right margin %d, setting to 0",
+             page_right);
+      page_right = 0;
+    }
+  }
+  if ((val = cupsGetOption("page-top", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs,"page-top", IPP_TAG_INTEGER))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-top", NULL)) != NULL  ||
+      (ipp = ippFindAttribute(defsize, "media-top-margin", IPP_TAG_INTEGER))!=NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    
+    if (!strncasecmp(val, "Custom.", 7))
+      val += 7;
+    page_top = atoi(val);
+    if (page_top < 0 || page_top > num_lines - 1) {
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid top margin %d, setting to 0",
+             page_top);
+      page_top = 0;
+    }
+  }
+  if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs,"page-bottom",IPP_TAG_INTEGER))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-bottom", NULL)) != NULL ||
+      (ipp = ippFindAttribute(defsize, "media-bottom-margin", IPP_TAG_INTEGER))!=NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val==NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (!strncasecmp(val, "Custom.", 7))
+      val += 7;
+    page_bottom = atoi(val);
+    if (page_bottom < 0 || page_bottom > num_lines - page_top - 1) {
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid bottom margin %d, setting to 0",
+             page_bottom);
+      page_bottom = 0;
+    }
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Margins: Left (Columns): %d; Right (Columns): %d; Top (Lines): %d; Bottom (Lines): %d",
+         page_left, page_right, page_top, page_bottom);
+
+  text_width = num_columns - page_left - page_right;
+  text_height = num_lines - page_top - page_bottom;
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Text area: Lines per page: %d; Characters per line: %d",
+         text_height, text_width);
+
+  strcpy(encoding, "ASCII//IGNORE");
+  if ((val = cupsGetOption("PrinterEncoding", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "printer-encoding", IPP_TAG_ZERO))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultPrinterEncoding", NULL)) != NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "printer-encoding-default", IPP_TAG_ZERO))!= NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (!strncasecmp(val, "Custom.", 7))
+      val += 7;
+    if (val[0] != '\0') {
+      snprintf(encoding, sizeof(encoding), "%.55s//IGNORE", val);
+      for (p = encoding; *p; p ++)
+       *p = toupper(*p);
+    }
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Output encoding: %s", encoding);
+  
+  if ((val = cupsGetOption("OverlongLines", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "overlong-lines", IPP_TAG_ENUM))!=NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "overlong-lines-default", IPP_TAG_ENUM))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultOverlongLines", NULL)) != NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL)
+      val = ppd_attr->value;
+    if (!strcasecmp(val, "Truncate"))
+      overlong_lines = TRUNCATE;
+    else if (!strcasecmp(val, "WordWrap"))
+      overlong_lines = WORDWRAP;
+    else if (!strcasecmp(val, "WrapAtWidth"))
+      overlong_lines = WRAPATWIDTH;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid value for OverlongLines: %s, using default value",
+             val);
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Handling of overlong lines: %s",
+         (overlong_lines == TRUNCATE ? "Truncate at maximum width" :
+          (overlong_lines == WORDWRAP ? "Word-wrap" :
+           "Wrap exactly at maximum width")));
+
+  if ((val = cupsGetOption("TabWidth", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs,"tab-width", IPP_TAG_INTEGER))!=NULL ||
+      (ipp = ippFindAttribute(printer_attrs,"tab-width-default",  IPP_TAG_INTEGER ))!=NULL  ||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultTabWidth", NULL)) != NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (!strncasecmp(val, "Custom.", 7))
+      val += 7;
+    i = atoi(val);
+    if (i > 0)
+      tab_width = i;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid tab width %d, using default value: %d",
+             i, tab_width);
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Tab width: %d", tab_width);
+
+  if ((val = cupsGetOption("Pagination", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "pagination", IPP_TAG_BOOLEAN))!=NULL  ||
+      (ipp = ippFindAttribute(printer_attrs, "pagination-default", IPP_TAG_BOOLEAN))!=NULL  ||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultPagination", NULL)) != NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf,sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (is_true(val))
+      pagination = 1;
+    else if (is_false(val))
+      pagination = 0;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid value for Pagination: %s, using default value",
+             val);
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Pagination (Print in defined pages): %s",
+         (pagination ? "Yes" : "No"));
+
+  if ((val = cupsGetOption("SendFF", num_options, options)) != NULL ||
+      (ipp = ippFindAttribute(job_attrs, "sendff", IPP_TAG_BOOLEAN))!=NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "sendff-default", IPP_TAG_BOOLEAN))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultSendFF", NULL)) != NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val==NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (is_true(val))
+      send_ff = 1;
+    else if (is_false(val))
+      send_ff = 0;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid value for SendFF: %s, using default value",
+             val);
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Send Form Feed character at end of page: %s",
+         (send_ff ? "Yes" : "No"));
+
+  if ((val = cupsGetOption("NewlineCharacters", num_options, options)) !=
+      NULL ||
+      (ipp = ippFindAttribute(job_attrs, "newline-characters", IPP_TAG_ENUM))!=NULL ||
+      (ipp = ippFindAttribute(printer_attrs, "newline-characters-default", IPP_TAG_ENUM))!=NULL ||
+      (ppd_attr = ppdFindAttr(ppd, "DefaultNewlineCharacters", NULL)) != NULL) {
+    if (val == NULL && ipp!=NULL){
+      ippAttributeString(ipp, buf, sizeof(buf));
+      val = buf;
+    }
+    if(val == NULL && ppd_attr!=NULL)
+      val = ppd_attr->value;
+    if (!strcasecmp(val, "LF"))
+      newline_char = LF;
+    else if (!strcasecmp(val, "CR"))
+      newline_char = CR;
+    else if (!strcasecmp(val, "CRLF"))
+      newline_char = CRLF;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid value for NewlineCharacters: %s, using default value",
+             val);
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Characters sent to make printer start a new line: %s",
+         (newline_char == LF ? "Line Feed (LF)" :
+          (newline_char == CR ? "Carriage Return (CR)" :
+           "Carriage Return (CR) and Line Feed (LF)")));
+
+  if ((val = cupsGetOption("page-ranges", num_options, options)) !=
+      NULL  ||
+      (ipp = ippFindAttribute(job_attrs, "page-ranges", IPP_TAG_ZERO))!=NULL) {
+        if(val == NULL){
+          ippAttributeString(ipp, buf, sizeof(buf));
+          val = buf;
+        }
+    if (val[0] != '\0')
+      page_ranges = strdup(val);
+  }
+  if (page_ranges)
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Page selection: %s", page_ranges);
+
+  if ((val = cupsGetOption("page-set", num_options, options)) !=
+      NULL  ||
+      (ipp = ippFindAttribute(job_attrs, "page-set", IPP_TAG_ZERO))!=NULL) {
+        if(val == NULL){
+          ippAttributeString(ipp, buf, sizeof(buf));
+          val = buf;
+        }
+    if (!strcasecmp(val, "even")) {
+      even_pages = 1;
+      odd_pages = 0;
+    } else if (!strcasecmp(val, "odd")) {
+      even_pages = 0;
+      odd_pages = 1;
+    } else if (!strcasecmp(val, "all")) {
+      even_pages = 1;
+      odd_pages = 1;
+    } else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid value for page-set: %s, using default value",
+             val);
+  }
+  if (!even_pages || !odd_pages)
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Print %s",
+           (even_pages ? "only the even pages" :
+            (odd_pages ? "only the odd pages" :
+             "no pages")));
+  
+  if ((val = cupsGetOption("output-order", num_options, options)) !=
+      NULL  ||
+      (ipp = ippFindAttribute(job_attrs,"output-order", IPP_TAG_ZERO))!=NULL) {
+        if(val == NULL){
+          ippAttributeString(ipp, buf, sizeof(buf));
+          val = buf;
+        }
+    if (!strcasecmp(val, "reverse"))
+      reverse_order = 1;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid value for OutputOrder: %s, using default value",
+             val);
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Print pages in reverse order: %s",
+         (reverse_order ? "Yes" : "No"));
+
+  if ((val = cupsGetOption("Collate", num_options, options)) != NULL  ||
+    (ipp = ippFindAttribute(job_attrs, "collate", IPP_TAG_ZERO))!=NULL) {
+      if(val == NULL){
+        ippAttributeString(ipp, buf, sizeof(buf));
+        val = buf;
+      }
+    if (is_true(val))
+      collate = 1;
+    else if (is_false(val))
+      collate = 0;
+    else
+      if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Invalid value for Collate: %s, using default value",
+             val);
+  }
+  if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Collate copies: %s",
+         (collate ? "Yes" : "No"));
+
+  /* Create a string to insert as the newline mark */
+  if (newline_char == LF)
+    newline_char_str = "\n";
+  else if (newline_char == CR)
+    newline_char_str = "\r";
+  else if (newline_char == CRLF)
+    newline_char_str = "\r\n";
+
+  /* Size of the output page in bytes (only 1-byte-per-character supported)
+     in the worst case, no blank lines at top and bottom, no blank right
+     margin, 2 characters for newline (CR + LF) plus form feed plus closing
+     zero */
+  page_size = (num_columns + 2) * num_lines + 2;
+
+  /* Allocate output page buffer */
+  out_page = calloc(page_size, sizeof(char));
+
+  /* Set conversion mode of iconv */
+  cd = iconv_open(encoding, "UTF-8");
+  if (cd == (iconv_t) -1) {
+    /* Something went wrong.  */
+    if (errno == EINVAL)
+    {
+      if(log) log(ld, FILTER_LOGLEVEL_ERROR, "texttotext: Conversion from UTF-8 to %s not available",
+             encoding);
+    }else
+    {
+      if(log) log(ld, FILTER_LOGLEVEL_ERROR, "texttotext: Error setting up conversion from UTF-8 to %s",
+             encoding);
+    }
+    goto error;
+  }
+
+  /* Open the input file */
+  fd = inputfd;
+  if (fd < 0) {
+    if(log) log(ld, FILTER_LOGLEVEL_ERROR, "texttotext: Unable to open input text file");
+    goto error;
+  }
+
+  /* Create an array to hold the output pages for collated copies or
+     reverse output order (only when printing paginated) */
+  if (pagination &&
+      ((num_copies != 1 && collate) || reverse_order)) {
+    /* Create page array */
+    page_array = cupsArrayNew(NULL, NULL);
+  }
+
+  /* Main loop for readin the input file, converting the encoding, formatting
+     the output, and printing the pages */
+  destptr = out_page;
+  page_empty = 1;
+  page = 1;
+  line = 0;
+  column = 0;
+  previous_is_cr = 0;
+  insize = 0;
+  do {
+    /* Reset input pointer */
+    inptr = inbuf;
+    
+    /* Mark the output buffer empty */
+    outsize = sizeof(outbuf);
+    outptr = outbuf;
+
+    /* Read from the input file */
+    nread = read (fd, inbuf + insize, sizeof (inbuf) - insize);
+    if (nread == 0) {
+      /* When we come here the file is completely read.
+        This still could mean there are some unused
+        characters in the inbuf, meaning that the file
+         ends with an incomplete UTF-8 character. Log
+         this fact. */
+      if (insize > 0 && incomplete_char){
+             if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Input text file ends with incomplete UTF-8 character sequence, file possibly incomplete, but printing the successfully read part anyway");
+      }
+
+      /* Now write out the byte sequence to get into the
+        initial state if this is necessary.  */
+      iconv (cd, NULL, NULL, &outptr, &outsize);
+    }
+
+    insize += nread;
+
+    /* Convert the incoming UTF-8-encoded text to the printer's encoding */
+    if (insize > 0) { /* Do we have data to convert? */
+      /* Do the conversion.  */
+      nconv = iconv (cd, &inptr, &insize, &outptr, &outsize);
+      if (nconv == (size_t) -1) {
+       /* Not everything went right. It might only be
+          an unfinished byte sequence at the end of the
+          buffer. Or it is a real problem. */
+       if (errno == EINVAL || errno == E2BIG) {
+         /* This is harmless.  Simply move the unused
+            bytes to the beginning of the buffer so that
+            they can be used in the next round. */
+         if (errno == EINVAL)
+           incomplete_char = 1;
+         memmove (inbuf, inptr, insize);
+       } else {
+         /* We found an illegal UTF-8 byte sequence here,
+            so error out at this point. */
+         if(log) log(ld, FILTER_LOGLEVEL_ERROR, "texttotext: Illegal UTF-8 sequence found. Input file perhaps not UTF-8-encoded");
+         result = -1;
+         break;
+       }
+      }
+    }
+
+    /* Process the output to generate the output pages */
+    if (outptr == outbuf) /* End of input file */
+      *(outptr ++) = '\0';
+    for (procptr = outbuf; procptr < outptr; procptr ++) {
+      if ((column >= text_width && /* Current line is full */
+          *procptr != '\n' && *procptr != '\r' && *procptr != '\f') ||
+                                  /* Next character is not newline or
+                                     formfeed */
+         (outbuf[0] == '\0' && column > 0)) {    /* End of input file */
+       if (overlong_lines == TRUNCATE && outbuf[0] != '\0')
+         skip_rest_of_line = 1;
+       else {
+         if (overlong_lines == WORDWRAP && outbuf[0] != '\0') {
+           if (*procptr > ' ') {
+             *destptr = '\0';
+             for (p = destptr - 1, i = column - 1; *p != ' ' && i >= 0;
+                  p --, i--);
+             if (i >= 0 && i < column - 1) {
+               wrapped_word = strdup(p + 1);
+               for (; *p == ' ' && i >= 0; p --, i--);
+               if (*p != ' ' && i >= 0)
+                 destptr = p + 1;
+               else {
+                 free(wrapped_word);
+                 wrapped_word = NULL;
+               }
+             }
+           } else
+             skip_spaces = 1;
+         }
+         /* Remove trailing whitespace */
+         while (destptr > out_page && *(destptr - 1) == ' ')
+           destptr --;
+         /* Put newline character(s) */
+         for (j = 0; newline_char_str[j]; j ++)
+           *(destptr ++) = newline_char_str[j];
+         /* Position cursor in next line */
+         line ++;
+         column = 0;
+       }
+      }
+      if ((line >= text_height && /* Current page is full */
+          *procptr != '\f') ||   /* Next character is not formfeed */
+         outbuf[0] == '\0' ) {   /* End of input file */
+       /* Do we actually print this page? */
+       if (!pagination ||
+           check_range(page_ranges, even_pages, odd_pages, page)) {
+         /* Finalize the page */
+         if (pagination) {
+           if (send_ff) {
+             if (page_empty)
+               destptr = out_page; /* Remove unneeded white space */
+             /* Send Form Feed */
+             *(destptr ++) = '\f';
+           } else if (outbuf[0] != '\0') {
+             /* Fill up page with blank lines */
+             for (i = 0; i < page_bottom; i ++)
+               for (j = 0; newline_char_str[j]; j ++)
+                 *(destptr ++) = newline_char_str[j];
+           }
+         }
+         /* Allow to handle the finished page as a C string */
+         *(destptr ++) = '\0';
+         /* Count pages which will actually get printed */
+         num_pages ++;
+         if (!pagination) {
+           /* Log the page output (only once, when printing the first buffer
+              load) */
+           if (num_pages == 1)
+      {
+            if(log) log(ld, FILTER_LOGLEVEL_INFO, "texttotext: 1 1");
+      }
+         } else if ((num_copies == 1 || !collate) && !reverse_order) {
+      
+           /* Log the page output */
+           if(log) log(ld, FILTER_LOGLEVEL_INFO, "texttotext: %d %d", num_pages, num_copies);
+         } else {
+           /* Save the page in the page array */
+           cupsArrayAdd(page_array, strdup(out_page));
+         }
+       }
+       /* Reset for next page */
+       destptr = out_page;
+       page_empty = 1;
+       line = 0;
+       column = 0;
+       page ++;
+      }
+      if (outbuf[0] == '\0') /* End of input file */
+       break;
+      if (column == 0) { /* Start of new line */ 
+       if (line == 0 && pagination)   /* Start of new page */
+         for (i = 0; i < page_top; i ++)
+           for (j = 0; newline_char_str[j]; j ++)
+             *(destptr ++) = newline_char_str[j];
+       for (i = 0; i < page_left; i ++)
+         *(destptr ++) = ' ';
+       /* Did we wrap a word from the previous line? */
+       if (wrapped_word) {
+         for (p = wrapped_word; *p != '\0'; p ++, column ++)
+           *(destptr ++) = *p;
+         free(wrapped_word);
+         wrapped_word = NULL;
+         page_empty = 0;
+         skip_spaces = 0;
+       }
+      }
+      if (*procptr == '\r' || *procptr == '\n') { /* CR or LF */
+       /* Only write newline if we are not on the LF of a CR+LF */
+       if (*procptr == '\r' || previous_is_cr == 0) {
+         /* Remove trailing whitespace */
+         while (destptr > out_page && *(destptr - 1) == ' ')
+           destptr --;
+         /* Put newline character(s) */
+         for (j = 0; newline_char_str[j]; j ++)
+           *(destptr ++) = newline_char_str[j];
+         /* Position cursor in next line */
+         line ++;
+         column = 0;
+         /* Finished truncating an overlong line */
+         skip_rest_of_line = 0;
+         skip_spaces = 0;
+       }
+       if (*procptr == '\r')
+         previous_is_cr = 1;
+       else
+         previous_is_cr = 0;
+      } else {
+       previous_is_cr = 0;
+       if (*procptr == '\t') { /* Tab character */
+         if (!skip_rest_of_line && !skip_spaces) {
+           *(destptr ++) = ' '; /* Always at least one space */
+           column ++;
+           /* Add spaces to reach next multiple of the tab width */
+           for (; column % tab_width != 0 && column < text_width; column ++)
+             *(destptr ++) = ' ';
+         }
+       } else if (*procptr == '\f') { /* Form feed */
+         /* Skip to end of page */       
+         if (send_ff)
+           /* Mark page full */
+           line = text_height;
+         else if (pagination)
+           /* Fill page with newlines */
+           for (; line < text_height; line ++)
+             for (j = 0; newline_char_str[j]; j ++)
+               *(destptr ++) = newline_char_str[j];
+         column = 0;
+         /* Finished truncating an overlong line */
+         skip_rest_of_line = 0;
+         skip_spaces = 0;
+       } else if (*procptr == ' ') { /* Space */
+         if (!skip_rest_of_line && !skip_spaces) {
+           *(destptr ++) = *procptr;
+           column ++;
+         }
+       } else if (*procptr > ' ' || *procptr < '\0') { /* Regular character */
+         if (!skip_rest_of_line) {
+           *(destptr ++) = *procptr;
+           column ++;
+           page_empty = 0;
+           skip_spaces = 0;
+         }
+       }
+      }
+    }
+    cupsFilePuts(outputfp, out_page);
+  } while (outbuf[0] != '\0'); /* End of input file */
+
+  close(fd);
+  
+  if (iconv_close (cd) != 0)
+    if(log) log(ld, FILTER_LOGLEVEL_DEBUG, "texttotext: Error closing iconv encoding conversion session");
+
+  /* Error out on an illegal UTF-8 sequence in the input file */
+  if (result < 0)
+    goto error;
+
+  /* Print out the page array if we created one */
+  if (pagination &&
+      ((num_copies != 1 && collate) || reverse_order)) {
+    /* If we print collated copies, the outer loop (i) goes through the
+       copies, if we do not collate, the inner loop (j) goes through the
+       copies. The other loop only runs for one cycle. */
+    for (i = 0; i < (collate ? num_copies : 1); i ++)
+      for (page = (reverse_order ? num_pages : 1);
+          (reverse_order ? (page >= 1) : (page <= num_pages));
+          page += (reverse_order ? -1 : 1)) {
+       p = (char *)cupsArrayIndex(page_array, page - 1);
+       if(log) log(ld, FILTER_LOGLEVEL_INFO, "texttotext: %d %d", page, (collate ? 1 : num_copies));
+      }
+    /* Clean up */
+    for (page = 0; page < num_pages; page ++) {
+      p = (char *)cupsArrayIndex(page_array, page);
+      free(p);
+    }
+    cupsArrayDelete(page_array);
+  }
+
+ /*
+  * Cleanup and exit...
+  */
+
+ error:
+
+  if(outputfp)
+    cupsFileClose(outputfp);
+
+  free(page_ranges);
+  free(out_page);
+
+  return (exit_status);
+}
+
+
+/*
+ * 'is_true()' - Check option value for boolean true
+ */
+
+static int is_true(const char *value)
+{
+  if (!value)
+    return 0;
+  return (strcasecmp(value, "yes") == 0) ||
+    (strcasecmp(value, "on") == 0) ||
+    (strcasecmp(value, "true") == 0) ||
+    (strcasecmp(value, "1") == 0);
+}
+
+
+/*
+ * 'is_false()' - Check option value for boolean false
+ */
+
+static int is_false(const char *value)
+{
+  if (!value)
+    return 0;
+  return (strcasecmp(value, "no") == 0) ||
+    (strcasecmp(value, "off") == 0) ||
+    (strcasecmp(value, "false") == 0) ||
+    (strcasecmp(value, "0") == 0);
+}
+
+
+/*
+ * 'check_range()' - Check to see if the current page is selected for
+ *                   printing.
+ */
+
+static int                             /* O - 1 if selected, 0 otherwise */
+check_range(char *page_ranges,          /* I - Selection of pages to print */
+           int even_pages,             /* I - Print the even pages */
+           int odd_pages,              /* I - Print the odd pages */
+            int page)                  /* I - Page number */
+{
+  const char   *range;                 /* Pointer into range string */
+  int          lower, upper;           /* Lower and upper page numbers */
+
+ /*
+  * See if we only print even or odd pages...
+  */
+
+  if (!odd_pages && (page & 1))
+    return (0);
+
+  if (!even_pages && !(page & 1))
+    return (0);
+
+ /*
+  * page-ranges option
+  */
+  
+  if (!page_ranges || page_ranges[0] == '\0')
+    return (1);                                /* No range, print all pages... */
+
+  for (range = page_ranges; *range != '\0';)
+  {
+    if (*range == '-')
+    {
+      lower = 1;
+      range ++;
+      upper = (int)strtol(range, (char **)&range, 10);
+    }
+    else
+    {
+      lower = (int)strtol(range, (char **)&range, 10);
+
+      if (*range == '-')
+      {
+        range ++;
+       if (!isdigit(*range & 255))
+         upper = 65535;
+       else
+         upper = (int)strtol(range, (char **)&range, 10);
+      }
+      else
+        upper = lower;
+    }
+
+    if (page >= lower && page <= upper)
+      return (1);
+
+    if (*range == ',')
+      range ++;
+    else
+      break;
+  }
+
+  return (0);
+}
+
+/*
+ * End
+ */
index b25611a2f9b9e26801bc378bbfbd92aa69eba1f6..00d2b1cf2cfb0b53210ebb2ab20bb5c2f5bd2570 100644 (file)
-/*
- *   texttotext
- *
- *   Filter to print text files on text-only printers. The filter has
- *   several configuration options controlled by a PPD file so that it
- *   should work with most printer models.
- *
- *   Copyright 2007-2011 by Apple Inc.
- *   Copyright 1997-2006 by Easy Software Products.
- *   Copyright 2011-2016 by Till Kamppeter
- *
- *   Distribution and use rights are outlined in the file "COPYING"
- *   which should have been included with this file.
- */
-
 /*
  * Include necessary headers...
  */
 
-#include <config.h>
-#include <cups/cups.h>
-#include <ppd/ppd.h>
-#include <cups/file.h>
+#include <cupsfilters/filter.h>
 #include <signal.h>
-#include <sys/wait.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-#include <iconv.h>
-#include <cupsfilters/image-private.h>
 
 /*
- * Type definitions
+ * Local globals...
  */
 
-typedef enum overlong_line_e {
-  TRUNCATE = 0,
-  WORDWRAP = 1,
-  WRAPATWIDTH = 2
-} overlong_line_t;
-
-typedef enum newline_char_e {
-  LF = 0,
-  CR = 1,
-  CRLF = 2
-} newline_char_t;
+static int             JobCanceled = 0;/* Set to 1 on SIGTERM */
 
 
 /*
  * Local functions...
  */
 
-static int              is_true(const char *value);
-static int              is_false(const char *value);
-static int             check_range(char *page_ranges, int even_pages,
-                                   int odd_pages, int page);
 static void            cancel_job(int sig);
 
 
 /*
- * Local globals...
+ * 'main()' - Main entry and processing of driver.
  */
 
-static int             job_canceled = 0;
-
-
-/*
- * 'main()' - Main entry for filter...
- */
-
-int                                    /* O - Exit status */
-main(int  argc,                                /* I - Number of command-line args */
-     char *argv[])                     /* I - Command-line arguments */
+int               /* O - Exit status */
+main(int  argc,           /* I - Number of command-line arguments */
+     char *argv[]) /* I - Command-line arguments */
 {
-  int          i, j;                   /* Looping vars */
-  char          *p;
-  int          exit_status = 0;        /* Exit status */
-  int          fd = 0;                 /* Copy file descriptor */
-  char         *filename,              /* Text file to convert */
-               tempfile[1024];         /* Temporary file */
-  char         buffer[8192];           /* Copy buffer */
-  int          bytes;                  /* Bytes copied */
-  int           num_copies;             /* Number of copies */
-  ppd_file_t   *ppd;                   /* PPD file */
-  int          num_options;            /* Number of options */
-  cups_option_t        *options;               /* Options */
-  const char   *val, *val2;                    /* Option value */
-  ppd_attr_t    *ppd_attr;              /* Attribute taken from the PPD */
-  int           num_lines = 66,         /* Lines per page */
-                num_columns = 80;       /* Characters per line */
-  int           page_left = 0,          /* Page margins */
-                page_right = 0,
-                page_top = 0,
-                page_bottom = 0,
-                num_lines_per_inch = 6,
-                num_chars_per_inch = 10;
-  int           text_width,             /* Width of the text area on the page */
-                text_height;            /* Height of the text area on the
-                                          page */
-  char          encoding[64];           /* The printer'a encoding, to which
-                                          the incoming UTF-8 is converted,
-                                          must be 1-byte-per-character */
-  overlong_line_t overlong_lines = WRAPATWIDTH;
-                                        /* How to treat overlong lines */
-  int           tab_width = 8;          /* Turn tabs to spaces with given
-                                          width */
-  int           pagination = 1;         /* Paginate text to allow margins
-                                           and page management */
-  int           send_ff = 1;            /* Send form-feed char at the end of
-                                          each page */
-  newline_char_t newline_char = CRLF;   /* Character to send at end of line */
-  char          *newline_char_str;
-  char          *page_ranges = NULL;    /* Selection of pages to print */
-  int           even_pages = 1;         /* Print the even pages */
-  int           odd_pages = 1;          /* Print the odd pages */
-  int           reverse_order = 0;      /* Ouput pages in reverse order? */
-  int           collate = 1;            /* Collate multiple copies? */
-  int           page_size;              /* Number of bytes needed for a page,
-                                          to allocate the memory for the
-                                          output page buffer */
-  char          *out_page = NULL;       /* Output page buffer */
-  cups_array_t  *page_array = NULL;     /* Array to hold the output pages
-                                          for collated copies and reverse
-                                          output order */
-  iconv_t       cd;                     /* Conversion descriptor, describes
-                                          between which encodings iconv
-                                          should convert */
-  char          outbuf[4096];           /* Output buffer for iconv */
-  char          inbuf[2048];            /* Input buffer for iconv */
-  size_t        outsize;                /* Space left in outbuf */
-  size_t        insize = 0;             /* Bytes still to be converted in
-                                          inbuf */
-  char          *outptr = outbuf;       /* Pointer for next converted
-                                          character to be dropped */
-  char          *inptr = inbuf;         /* Pointer to next character to be
-                                          converted */
-  size_t        nread;                  /* Number of bytes read from file */
-  size_t        nconv;                  /* -1 on conversion error */
-  int           incomplete_char = 0;    /* Was last character in input buffer
-                                          incomplete */
-  int           result = 0;             /* Conversion result (-1 on error) */
-  char          *procptr,               /* Pointer into conversion output
-                                           to indicate next byte to process
-                                          for output page creation */
-                *destptr;               /* Pointer into output page buffer
-                                           where next character will be put */
-  int           page,                   /* Number of current output page */
-                line, column;           /* Character coordiantes on output
-                                          page */
-  int           page_empty;             /* Is the current output page still
-                                          empty (no visible characters)? */
-  int           previous_is_cr;         /* Is the previous character processed
-                                          a Carriage Return? */
-  int           skip_rest_of_line = 0;  /* Are we truncating an overlong
-                                          line? */
-  int           skip_spaces = 0;        /* Are we skipping spaces at a line
-                                          break when word-wrapping? */
-  char          *wrapped_word = NULL;   /* Section of a word wrapped over
-                                          to the next line */
-  int           num_pages = 0;          /* Number of pages which get actually
-                                          printed */
-  ipp_t *printer_attrs = NULL;
-  ipp_t *job_attrs = NULL;
-  ipp_attribute_t *ipp;
-  ipp_t *defsize;
-  char buf[2048];
-  
+  int           ret;
 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
   struct sigaction action;             /* Actions for POSIX signals */
 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
 
- /*
-  * Make sure status messages are not buffered...
-  */
-
-  setbuf(stderr, NULL);
-
- /*
-  * Ignore broken pipe signals...
-  */
-
-  signal(SIGPIPE, SIG_IGN);
-
- /*
-  * Make sure we have the right number of arguments for CUPS!
-  */
-
-  if (argc < 6 || argc > 7)
-  {
-    fprintf(stderr, "Usage: %s job user title copies options [file]\n",
-           argv[0]);
-    return (1);
-  }
-
  /*
   * Register a signal handler to cleanly cancel a job.
   */
@@ -212,931 +49,16 @@ main(int  argc,                           /* I - Number of command-line args */
 #endif /* HAVE_SIGSET */
 
  /*
-  * Copy stdin if needed...
-  */
-
-  if (argc == 6)
-  {
-   /*
-    * Copy stdin to a temp file...
-    */
-
-    if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
-    {
-      fprintf(stderr, "ERROR: Unable to copy input text file");
-      goto error;
-    }
-
-    fprintf(stderr, "DEBUG: texttotext - Copying stdin to temp print file \"%s\"\n",
-            tempfile);
-
-    while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
-      bytes = write(fd, buffer, bytes);
-
-    close(fd);
-
-    filename = tempfile;
-  }
-  else
-  {
-   /*
-    * Use the filename on the command-line...
-    */
-
-    filename    = argv[6];
-    tempfile[0] = '\0';
-  }
-
- /*
-  * Number of copies
-  */
-
-  num_copies = atoi(argv[4]);
-  if (num_copies < 1)
-    num_copies = 1;
-
- /*
-  * Get the options from the fifth command line argument
-  */
-
-  num_options = cupsParseOptions(argv[5], 0, &options);
-
- /*
-  * Load the PPD file and mark options...
-  */
-
-  ppd = ppdOpenFile(getenv("PPD"));
-  if (ppd)
-  {
-    ppdMarkDefaults(ppd);
-    ppdMarkOptions(ppd, num_options, options);
-  }
-
- /*
-  * Parse the options
-  */
-
-  /*  Default page size attributes as per printer attributes  */
-  defsize = ippGetCollection(ippFindAttribute(printer_attrs,       
-                          "media-col-default", IPP_TAG_ZERO), 0);
-  
-  if((val = cupsGetOption("NumLinesPerInch", num_options, options))!= NULL         ||
-    (ipp = ippFindAttribute(job_attrs,"num-lines-per-inch", IPP_TAG_INTEGER)) != NULL ||
-    (ipp = ippFindAttribute(printer_attrs,"num-lines-per-inch-default", IPP_TAG_INTEGER)) != NULL ||
-    (ppd_attr = ppdFindAttr(ppd, "DefaultNumLinesPerInch",NULL))!=NULL){
-      if(val == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf, sizeof(buf));
-        val = buf;
-      }
-      if(val == NULL){
-        val = ppd_attr->value;
-      }
-      num_lines_per_inch = atoi(val);
-    }
-
-  if((val = cupsGetOption("NumCharsPerInch", num_options, options))!= NULL          ||
-    (ipp = ippFindAttribute(job_attrs,"num-chars-per-inch", IPP_TAG_INTEGER)) != NULL  ||
-    (ipp = ippFindAttribute(printer_attrs,"num-chars-per-inch-default", IPP_TAG_INTEGER)) != NULL  ||
-    (ppd_attr = ppdFindAttr(ppd, "DefautlNumCharsPerInch", NULL))!=NULL){
-      if(val == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf, sizeof(buf));
-        val = buf;
-      }
-      if(val == NULL){
-        val = ppd_attr->value;
-      }
-      num_chars_per_inch = atoi(val);
-    }
-    fprintf(stderr, "Debug: num of lines per inch = %d\n",num_lines_per_inch);
-    fprintf(stderr, "Debug: num of chars per inch = %d\n",num_chars_per_inch);
-
-  /* With the "PageSize"/"PageRegion" options we only determine the number
-     of lines and columns of a page, we do not use the geometry defined by
-     "PaperDimension" and "ImageableArea" in the PPD */
-  if ((val = cupsGetOption("PageSize", num_options, options)) != NULL       ||
-      (val = cupsGetOption("PageRegion", num_options, options)) != NULL     ||
-      (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO ))!=NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-region", IPP_TAG_ZERO))!=NULL||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPageSize", NULL)) != NULL        ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPageRegion", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val==NULL)
-      val = ppd_attr->value;
-    fprintf(stderr, "DEBUG: PageSize: %s\n", val);
-    snprintf(buffer, sizeof(buffer), "Default%sNumLines", val);
-    if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
-  (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!= NULL   ||
-  (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
-  (ppd_attr = ppdFindAttr(ppd, buffer, NULL)) != NULL) {
-    char buf2[2048];
-      if (val2 == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf2, sizeof(buf2));
-        val2 = buf2;
-      }
-      if(val2==NULL)
-             val2 = ppd_attr->value;
-      if (!strncasecmp(val2, "Custom.", 7))
-       val2 += 7;
-      num_lines = atoi(val2);
-    }
-    snprintf(buffer, sizeof(buffer), "Default%sNumColumns", val);
-    if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!=NULL  ||
-      (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, buffer, NULL))!=NULL) {
-    char buf2[2048];
-      if (val2 == NULL && ipp!=NULL){
-        ippAttributeString(ipp, buf2, sizeof(buf2));
-        val2 = buf2;
-      }
-if(val2==NULL)
-       val2 = ppd_attr->value;
-      if (!strncasecmp(val2, "Custom.", 7))
-       val2 += 7;
-      num_columns = atoi(val2);
-    }
-    if (num_lines <= 0) {
-      fprintf(stderr, "DEBUG: Invalid number of lines %d, using default: 66\n",
-             num_lines);
-      num_lines = 66;
-    }
-    if (num_columns <= 0) {
-      fprintf(stderr, "DEBUG: Invalid number of columns %d, using default: 80\n",
-             num_columns);
-      num_columns = 80;
-    }
-  }
-  else if((ipp = ippFindAttribute(defsize, "media-size", IPP_TAG_ZERO))!= NULL){
-    ipp_t *media_size = ippGetCollection(ipp, 0);
-    int x_dim = ippGetInteger(ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO),0);
-    int y_dim = ippGetInteger(ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO),0);
-    num_lines = (int)((y_dim/72.0)*(num_lines_per_inch));         /*  Since y_dim and x_dim are in points, 
-                                                                      divide them by 72 to convert in inch  */
-    num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
-  }
-  else if((ipp = ippFindAttribute(printer_attrs, "media-default", IPP_TAG_ZERO))!=NULL){
-    pwg_media_t *pwg = pwgMediaForPWG(ippGetString(ipp, 0, NULL));
-    int x_dim = pwg->width;
-    int y_dim = pwg->length;
-    num_lines = (int)((y_dim/72.0)*(num_lines_per_inch));
-    num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
-  }
-  if (num_lines <= 0) {
-    fprintf(stderr, "DEBUG: Invalid number of lines %d, using default: 66\n",
-      num_lines);
-    num_lines = 66;
-  }
-  if (num_columns <= 0) {
-    fprintf(stderr, "DEBUG: Invalid number of columns %d, using default: 80\n",
-      num_columns);
-    num_columns = 80;
-  }
-
-  /* Direct specification of number of lines/columns, mainly for debugging
-     and development */
-  if ((val = cupsGetOption("page-height", num_options, options)) != NULL  ||
-      (ipp = ippFindAttribute(job_attrs, "page-height", IPP_TAG_INTEGER))!=NULL) {
-        if(val == NULL){
-          ippAttributeString(ipp, buf, sizeof(buf));
-          val = buf;
-        }
-    i = atoi(val);
-    if (i > 0)
-      num_lines = i;
-    else
-      fprintf(stderr, "DEBUG: Invalid number of lines %d, using default value: %d\n",
-             i, num_lines);
-  }
-  if ((val = cupsGetOption("page-width", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-width", IPP_TAG_INTEGER))!=NULL) {
-    if(val == NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    i = atoi(val);
-    if (i > 0)
-      num_columns = i;
-    else
-      fprintf(stderr, "DEBUG: Invalid number of columns %d, using default value: %d\n",
-             i, num_columns);
-  }
-
-  fprintf(stderr, "DEBUG: Lines per page: %d; Characters per line: %d\n",
-         num_lines, num_columns);
-  
-  if ((val = cupsGetOption("page-left", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-left", IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-left", NULL)) != NULL ||
-      (ipp = ippFindAttribute(defsize, "media-left-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_left = atoi(val);
-    if (page_left < 0 || page_left > num_columns - 1) {
-      fprintf(stderr, "DEBUG: Invalid left margin %d, setting to 0.\n",
-             page_left);
-      page_left = 0;
-    }
-  }
-  if ((val = cupsGetOption("page-right", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "page-right", IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-right", NULL)) != NULL  ||
-        (ipp = ippFindAttribute(defsize, "media-right-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_right = atoi(val);
-    if (page_right < 0 || page_right > num_columns - page_left - 1) {
-      fprintf(stderr, "DEBUG: Invalid right margin %d, setting to 0.\n",
-             page_right);
-      page_right = 0;
-    }
-  }
-  if ((val = cupsGetOption("page-top", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs,"page-top", IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-top", NULL)) != NULL  ||
-      (ipp = ippFindAttribute(defsize, "media-top-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_top = atoi(val);
-    if (page_top < 0 || page_top > num_lines - 1) {
-      fprintf(stderr, "DEBUG: Invalid top margin %d, setting to 0.\n",
-             page_top);
-      page_top = 0;
-    }
-  }
-  if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs,"page-bottom",IPP_TAG_INTEGER))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "Defaultpage-bottom", NULL)) != NULL ||
-      (ipp = ippFindAttribute(defsize, "media-bottom-margin", IPP_TAG_INTEGER))!=NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val==NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    page_bottom = atoi(val);
-    if (page_bottom < 0 || page_bottom > num_lines - page_top - 1) {
-      fprintf(stderr, "DEBUG: Invalid bottom margin %d, setting to 0.\n",
-             page_bottom);
-      page_bottom = 0;
-    }
-  }
-  fprintf(stderr, "DEBUG: Margins: Left (Columns): %d; Right (Columns): %d; Top (Lines): %d; Bottom (Lines): %d\n",
-         page_left, page_right, page_top, page_bottom);
-
-  text_width = num_columns - page_left - page_right;
-  text_height = num_lines - page_top - page_bottom;
-  fprintf(stderr, "DEBUG: Text area: Lines per page: %d; Characters per line: %d\n",
-         text_height, text_width);
-
-  strcpy(encoding, "ASCII//IGNORE");
-  if ((val = cupsGetOption("PrinterEncoding", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "printer-encoding", IPP_TAG_ZERO))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPrinterEncoding", NULL)) != NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "printer-encoding-default", IPP_TAG_ZERO))!= NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    if (val[0] != '\0') {
-      snprintf(encoding, sizeof(encoding), "%.55s//IGNORE", val);
-      for (p = encoding; *p; p ++)
-       *p = toupper(*p);
-    }
-  }
-  fprintf(stderr, "DEBUG: Output encoding: %s\n", encoding);
-  
-  if ((val = cupsGetOption("OverlongLines", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "overlong-lines", IPP_TAG_ENUM))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "overlong-lines-default", IPP_TAG_ENUM))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultOverlongLines", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL)
-      val = ppd_attr->value;
-    if (!strcasecmp(val, "Truncate"))
-      overlong_lines = TRUNCATE;
-    else if (!strcasecmp(val, "WordWrap"))
-      overlong_lines = WORDWRAP;
-    else if (!strcasecmp(val, "WrapAtWidth"))
-      overlong_lines = WRAPATWIDTH;
-    else
-      fprintf(stderr, "DEBUG: Invalid value for OverlongLines: %s, using default value.\n",
-             val);
-  }
-  fprintf(stderr, "DEBUG: Handling of overlong lines: %s\n",
-         (overlong_lines == TRUNCATE ? "Truncate at maximum width" :
-          (overlong_lines == WORDWRAP ? "Word-wrap" :
-           "Wrap exactly at maximum width")));
-
-  if ((val = cupsGetOption("TabWidth", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs,"tab-width", IPP_TAG_INTEGER))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs,"tab-width-default",  IPP_TAG_INTEGER ))!=NULL  ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultTabWidth", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strncasecmp(val, "Custom.", 7))
-      val += 7;
-    i = atoi(val);
-    if (i > 0)
-      tab_width = i;
-    else
-      fprintf(stderr, "DEBUG: Invalid tab width %d, using default value: %d\n",
-             i, tab_width);
-  }
-  fprintf(stderr, "DEBUG: Tab width: %d\n", tab_width);
-
-  if ((val = cupsGetOption("Pagination", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "pagination", IPP_TAG_BOOLEAN))!=NULL  ||
-      (ipp = ippFindAttribute(printer_attrs, "pagination-default", IPP_TAG_BOOLEAN))!=NULL  ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultPagination", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf,sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (is_true(val))
-      pagination = 1;
-    else if (is_false(val))
-      pagination = 0;
-    else
-      fprintf(stderr, "DEBUG: Invalid value for Pagination: %s, using default value.\n",
-             val);
-  }
-  fprintf(stderr, "DEBUG: Pagination (Print in defined pages): %s\n",
-         (pagination ? "Yes" : "No"));
-
-  if ((val = cupsGetOption("SendFF", num_options, options)) != NULL ||
-      (ipp = ippFindAttribute(job_attrs, "sendff", IPP_TAG_BOOLEAN))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "sendff-default", IPP_TAG_BOOLEAN))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultSendFF", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val==NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (is_true(val))
-      send_ff = 1;
-    else if (is_false(val))
-      send_ff = 0;
-    else
-      fprintf(stderr, "DEBUG: Invalid value for SendFF: %s, using default value.\n",
-             val);
-  }
-  fprintf(stderr, "DEBUG: Send Form Feed character at end of page: %s\n",
-         (send_ff ? "Yes" : "No"));
-
-  if ((val = cupsGetOption("NewlineCharacters", num_options, options)) !=
-      NULL ||
-      (ipp = ippFindAttribute(job_attrs, "newline-characters", IPP_TAG_ENUM))!=NULL ||
-      (ipp = ippFindAttribute(printer_attrs, "newline-characters-default", IPP_TAG_ENUM))!=NULL ||
-      (ppd_attr = ppdFindAttr(ppd, "DefaultNewlineCharacters", NULL)) != NULL) {
-    if (val == NULL && ipp!=NULL){
-      ippAttributeString(ipp, buf, sizeof(buf));
-      val = buf;
-    }
-    if(val == NULL && ppd_attr!=NULL)
-      val = ppd_attr->value;
-    if (!strcasecmp(val, "LF"))
-      newline_char = LF;
-    else if (!strcasecmp(val, "CR"))
-      newline_char = CR;
-    else if (!strcasecmp(val, "CRLF"))
-      newline_char = CRLF;
-    else
-      fprintf(stderr, "DEBUG: Invalid value for NewlineCharacters: %s, using default value.\n",
-             val);
-  }
-  fprintf(stderr, "DEBUG: Characters sent to make printer start a new line: %s\n",
-         (newline_char == LF ? "Line Feed (LF)" :
-          (newline_char == CR ? "Carriage Return (CR)" :
-           "Carriage Return (CR) and Line Feed (LF)")));
-
-  if ((val = cupsGetOption("page-ranges", num_options, options)) !=
-      NULL  ||
-      (ipp = ippFindAttribute(job_attrs, "page-ranges", IPP_TAG_ZERO))!=NULL) {
-        if(val == NULL){
-          ippAttributeString(ipp, buf, sizeof(buf));
-          val = buf;
-        }
-    if (val[0] != '\0')
-      page_ranges = strdup(val);
-  }
-  if (page_ranges)
-    fprintf(stderr, "DEBUG: Page selection: %s\n", page_ranges);
-
-  if ((val = cupsGetOption("page-set", num_options, options)) !=
-      NULL  ||
-      (ipp = ippFindAttribute(job_attrs, "page-set", IPP_TAG_ZERO))!=NULL) {
-        if(val == NULL){
-          ippAttributeString(ipp, buf, sizeof(buf));
-          val = buf;
-        }
-    if (!strcasecmp(val, "even")) {
-      even_pages = 1;
-      odd_pages = 0;
-    } else if (!strcasecmp(val, "odd")) {
-      even_pages = 0;
-      odd_pages = 1;
-    } else if (!strcasecmp(val, "all")) {
-      even_pages = 1;
-      odd_pages = 1;
-    } else
-      fprintf(stderr, "DEBUG: Invalid value for page-set: %s, using default value.\n",
-             val);
-  }
-  if (!even_pages || !odd_pages)
-    fprintf(stderr, "DEBUG: Print %s.\n",
-           (even_pages ? "only the even pages" :
-            (odd_pages ? "only the odd pages" :
-             "no pages")));
-  
-  if ((val = cupsGetOption("output-order", num_options, options)) !=
-      NULL  ||
-      (ipp = ippFindAttribute(job_attrs,"output-order", IPP_TAG_ZERO))!=NULL) {
-        if(val == NULL){
-          ippAttributeString(ipp, buf, sizeof(buf));
-          val = buf;
-        }
-    if (!strcasecmp(val, "reverse"))
-      reverse_order = 1;
-    else
-      fprintf(stderr, "DEBUG: Invalid value for OutputOrder: %s, using default value.\n",
-             val);
-  }
-  fprintf(stderr, "DEBUG: Print pages in reverse order: %s\n",
-         (reverse_order ? "Yes" : "No"));
-
-  if ((val = cupsGetOption("Collate", num_options, options)) != NULL  ||
-    (ipp = ippFindAttribute(job_attrs, "collate", IPP_TAG_ZERO))!=NULL) {
-      if(val == NULL){
-        ippAttributeString(ipp, buf, sizeof(buf));
-        val = buf;
-      }
-    if (is_true(val))
-      collate = 1;
-    else if (is_false(val))
-      collate = 0;
-    else
-      fprintf(stderr, "DEBUG: Invalid value for Collate: %s, using default value.\n",
-             val);
-  }
-  fprintf(stderr, "DEBUG: Collate copies: %s\n",
-         (collate ? "Yes" : "No"));
-
-  /* Create a string to insert as the newline mark */
-  if (newline_char == LF)
-    newline_char_str = "\n";
-  else if (newline_char == CR)
-    newline_char_str = "\r";
-  else if (newline_char == CRLF)
-    newline_char_str = "\r\n";
-
-  /* Size of the output page in bytes (only 1-byte-per-character supported)
-     in the worst case, no blank lines at top and bottom, no blank right
-     margin, 2 characters for newline (CR + LF) plus form feed plus closing
-     zero */
-  page_size = (num_columns + 2) * num_lines + 2;
-
-  /* Allocate output page buffer */
-  out_page = calloc(page_size, sizeof(char));
-
-  /* Set conversion mode of iconv */
-  cd = iconv_open(encoding, "UTF-8");
-  if (cd == (iconv_t) -1) {
-    /* Something went wrong.  */
-    if (errno == EINVAL)
-      fprintf(stderr, "ERROR: Conversion from UTF-8 to %s not available\n",
-             encoding);
-    else
-      fprintf(stderr, "ERROR: Error setting up conversion from UTF-8 to %s\n",
-             encoding);
-    goto error;
-  }
-
-  /* Open the input file */
-  fd = open(filename, O_RDONLY);
-  if (fd < 0) {
-    fprintf(stderr, "ERROR: Unable to open input text file %s\n", filename);
-    goto error;
-  }
-
-  /* Create an array to hold the output pages for collated copies or
-     reverse output order (only when printing paginated) */
-  if (pagination &&
-      ((num_copies != 1 && collate) || reverse_order)) {
-    /* Create page array */
-    page_array = cupsArrayNew(NULL, NULL);
-  }
-
-  /* Main loop for readin the input file, converting the encoding, formatting
-     the output, and printing the pages */
-  destptr = out_page;
-  page_empty = 1;
-  page = 1;
-  line = 0;
-  column = 0;
-  previous_is_cr = 0;
-  insize = 0;
-  do {
-    /* Reset input pointer */
-    inptr = inbuf;
-    
-    /* Mark the output buffer empty */
-    outsize = sizeof(outbuf);
-    outptr = outbuf;
-
-    /* Read from the input file */
-    nread = read (fd, inbuf + insize, sizeof (inbuf) - insize);
-    if (nread == 0) {
-      /* When we come here the file is completely read.
-        This still could mean there are some unused
-        characters in the inbuf, meaning that the file
-         ends with an incomplete UTF-8 character. Log
-         this fact. */
-      if (insize > 0 && incomplete_char)
-       fprintf(stderr, "DEBUG: Input text file ends with incomplete UTF-8 character sequence, file possibly incomplete, but printing the successfully read part anyway.\n");
-
-      /* Now write out the byte sequence to get into the
-        initial state if this is necessary.  */
-      iconv (cd, NULL, NULL, &outptr, &outsize);
-    }
-
-    insize += nread;
-
-    /* Convert the incoming UTF-8-encoded text to the printer's encoding */
-    if (insize > 0) { /* Do we have data to convert? */
-      /* Do the conversion.  */
-      nconv = iconv (cd, &inptr, &insize, &outptr, &outsize);
-      if (nconv == (size_t) -1) {
-       /* Not everything went right. It might only be
-          an unfinished byte sequence at the end of the
-          buffer. Or it is a real problem. */
-       if (errno == EINVAL || errno == E2BIG) {
-         /* This is harmless.  Simply move the unused
-            bytes to the beginning of the buffer so that
-            they can be used in the next round. */
-         if (errno == EINVAL)
-           incomplete_char = 1;
-         memmove (inbuf, inptr, insize);
-       } else {
-         /* We found an illegal UTF-8 byte sequence here,
-            so error out at this point. */
-         fprintf(stderr, "ERROR: Illegal UTF-8 sequence found. Input file perhaps not UTF-8-encoded\n");
-         result = -1;
-         break;
-       }
-      }
-    }
-
-    /* Process the output to generate the output pages */
-    if (outptr == outbuf) /* End of input file */
-      *(outptr ++) = '\0';
-    for (procptr = outbuf; procptr < outptr; procptr ++) {
-      if ((column >= text_width && /* Current line is full */
-          *procptr != '\n' && *procptr != '\r' && *procptr != '\f') ||
-                                  /* Next character is not newline or
-                                     formfeed */
-         (outbuf[0] == '\0' && column > 0)) {    /* End of input file */
-       if (overlong_lines == TRUNCATE && outbuf[0] != '\0')
-         skip_rest_of_line = 1;
-       else {
-         if (overlong_lines == WORDWRAP && outbuf[0] != '\0') {
-           if (*procptr > ' ') {
-             *destptr = '\0';
-             for (p = destptr - 1, i = column - 1; *p != ' ' && i >= 0;
-                  p --, i--);
-             if (i >= 0 && i < column - 1) {
-               wrapped_word = strdup(p + 1);
-               for (; *p == ' ' && i >= 0; p --, i--);
-               if (*p != ' ' && i >= 0)
-                 destptr = p + 1;
-               else {
-                 free(wrapped_word);
-                 wrapped_word = NULL;
-               }
-             }
-           } else
-             skip_spaces = 1;
-         }
-         /* Remove trailing whitespace */
-         while (destptr > out_page && *(destptr - 1) == ' ')
-           destptr --;
-         /* Put newline character(s) */
-         for (j = 0; newline_char_str[j]; j ++)
-           *(destptr ++) = newline_char_str[j];
-         /* Position cursor in next line */
-         line ++;
-         column = 0;
-       }
-      }
-      if ((line >= text_height && /* Current page is full */
-          *procptr != '\f') ||   /* Next character is not formfeed */
-         outbuf[0] == '\0' ) {   /* End of input file */
-       /* Do we actually print this page? */
-       if (!pagination ||
-           check_range(page_ranges, even_pages, odd_pages, page)) {
-         /* Finalize the page */
-         if (pagination) {
-           if (send_ff) {
-             if (page_empty)
-               destptr = out_page; /* Remove unneeded white space */
-             /* Send Form Feed */
-             *(destptr ++) = '\f';
-           } else if (outbuf[0] != '\0') {
-             /* Fill up page with blank lines */
-             for (i = 0; i < page_bottom; i ++)
-               for (j = 0; newline_char_str[j]; j ++)
-                 *(destptr ++) = newline_char_str[j];
-           }
-         }
-         /* Allow to handle the finished page as a C string */
-         *(destptr ++) = '\0';
-         /* Count pages which will actually get printed */
-         num_pages ++;
-         if (!pagination) {
-           /* Send out the output page buffer content */
-           printf("%s", out_page);
-           /* Log the page output (only once, when printing the first buffer
-              load) */
-           if (num_pages == 1)
-             fprintf(stderr, "PAGE: 1 1\n");
-         } else if ((num_copies == 1 || !collate) && !reverse_order) {
-           /* Send out the page */
-           for (i = 0; i < num_copies; i ++)
-             printf("%s", out_page);
-           /* Log the page output */
-           fprintf(stderr, "PAGE: %d %d\n", num_pages, num_copies);
-         } else {
-           /* Save the page in the page array */
-           cupsArrayAdd(page_array, strdup(out_page));
-         }
-       }
-       /* Reset for next page */
-       destptr = out_page;
-       page_empty = 1;
-       line = 0;
-       column = 0;
-       page ++;
-      }
-      if (outbuf[0] == '\0') /* End of input file */
-       break;
-      if (column == 0) { /* Start of new line */ 
-       if (line == 0 && pagination)   /* Start of new page */
-         for (i = 0; i < page_top; i ++)
-           for (j = 0; newline_char_str[j]; j ++)
-             *(destptr ++) = newline_char_str[j];
-       for (i = 0; i < page_left; i ++)
-         *(destptr ++) = ' ';
-       /* Did we wrap a word from the previous line? */
-       if (wrapped_word) {
-         for (p = wrapped_word; *p != '\0'; p ++, column ++)
-           *(destptr ++) = *p;
-         free(wrapped_word);
-         wrapped_word = NULL;
-         page_empty = 0;
-         skip_spaces = 0;
-       }
-      }
-      if (*procptr == '\r' || *procptr == '\n') { /* CR or LF */
-       /* Only write newline if we are not on the LF of a CR+LF */
-       if (*procptr == '\r' || previous_is_cr == 0) {
-         /* Remove trailing whitespace */
-         while (destptr > out_page && *(destptr - 1) == ' ')
-           destptr --;
-         /* Put newline character(s) */
-         for (j = 0; newline_char_str[j]; j ++)
-           *(destptr ++) = newline_char_str[j];
-         /* Position cursor in next line */
-         line ++;
-         column = 0;
-         /* Finished truncating an overlong line */
-         skip_rest_of_line = 0;
-         skip_spaces = 0;
-       }
-       if (*procptr == '\r')
-         previous_is_cr = 1;
-       else
-         previous_is_cr = 0;
-      } else {
-       previous_is_cr = 0;
-       if (*procptr == '\t') { /* Tab character */
-         if (!skip_rest_of_line && !skip_spaces) {
-           *(destptr ++) = ' '; /* Always at least one space */
-           column ++;
-           /* Add spaces to reach next multiple of the tab width */
-           for (; column % tab_width != 0 && column < text_width; column ++)
-             *(destptr ++) = ' ';
-         }
-       } else if (*procptr == '\f') { /* Form feed */
-         /* Skip to end of page */       
-         if (send_ff)
-           /* Mark page full */
-           line = text_height;
-         else if (pagination)
-           /* Fill page with newlines */
-           for (; line < text_height; line ++)
-             for (j = 0; newline_char_str[j]; j ++)
-               *(destptr ++) = newline_char_str[j];
-         column = 0;
-         /* Finished truncating an overlong line */
-         skip_rest_of_line = 0;
-         skip_spaces = 0;
-       } else if (*procptr == ' ') { /* Space */
-         if (!skip_rest_of_line && !skip_spaces) {
-           *(destptr ++) = *procptr;
-           column ++;
-         }
-       } else if (*procptr > ' ' || *procptr < '\0') { /* Regular character */
-         if (!skip_rest_of_line) {
-           *(destptr ++) = *procptr;
-           column ++;
-           page_empty = 0;
-           skip_spaces = 0;
-         }
-       }
-      }
-    }
-  } while (outbuf[0] != '\0'); /* End of input file */
-
-  close(fd);
-  
-  if (iconv_close (cd) != 0)
-    fprintf (stderr, "DEBUG: Error closing iconv encoding conversion session\n");
-
-  /* Error out on an illegal UTF-8 sequence in the input file */
-  if (result < 0)
-    goto error;
-
-  /* Print out the page array if we created one */
-  if (pagination &&
-      ((num_copies != 1 && collate) || reverse_order)) {
-    /* If we print collated copies, the outer loop (i) goes through the
-       copies, if we do not collate, the inner loop (j) goes through the
-       copies. The other loop only runs for one cycle. */
-    for (i = 0; i < (collate ? num_copies : 1); i ++)
-      for (page = (reverse_order ? num_pages : 1);
-          (reverse_order ? (page >= 1) : (page <= num_pages));
-          page += (reverse_order ? -1 : 1)) {
-       p = (char *)cupsArrayIndex(page_array, page - 1);
-       for (j = 0; j < (collate ? 1 : num_copies); j ++)
-         printf("%s", p);
-       fprintf(stderr, "PAGE: %d %d\n", page, (collate ? 1 : num_copies));
-      }
-    /* Clean up */
-    for (page = 0; page < num_pages; page ++) {
-      p = (char *)cupsArrayIndex(page_array, page);
-      free(p);
-    }
-    cupsArrayDelete(page_array);
-  }
-
- /*
-  * Cleanup and exit...
+  * Fire up the texttotext() filter function
   */
 
- error:
-
-  free(page_ranges);
-  free(out_page);
-  
-  if (tempfile[0])
-    unlink(tempfile);
-
-  return (exit_status);
-}
 
+  ret = filterCUPSWrapper(argc, argv, texttotext, NULL, &JobCanceled);
 
-/*
- * 'is_true()' - Check option value for boolean true
- */
+  if (ret)
+    fprintf(stderr, "ERROR: texttotext filter function failed.\n");
 
-static int is_true(const char *value)
-{
-  if (!value)
-    return 0;
-  return (strcasecmp(value, "yes") == 0) ||
-    (strcasecmp(value, "on") == 0) ||
-    (strcasecmp(value, "true") == 0) ||
-    (strcasecmp(value, "1") == 0);
-}
-
-
-/*
- * 'is_false()' - Check option value for boolean false
- */
-
-static int is_false(const char *value)
-{
-  if (!value)
-    return 0;
-  return (strcasecmp(value, "no") == 0) ||
-    (strcasecmp(value, "off") == 0) ||
-    (strcasecmp(value, "false") == 0) ||
-    (strcasecmp(value, "0") == 0);
-}
-
-
-/*
- * 'check_range()' - Check to see if the current page is selected for
- *                   printing.
- */
-
-static int                             /* O - 1 if selected, 0 otherwise */
-check_range(char *page_ranges,          /* I - Selection of pages to print */
-           int even_pages,             /* I - Print the even pages */
-           int odd_pages,              /* I - Print the odd pages */
-            int page)                  /* I - Page number */
-{
-  const char   *range;                 /* Pointer into range string */
-  int          lower, upper;           /* Lower and upper page numbers */
-
- /*
-  * See if we only print even or odd pages...
-  */
-
-  if (!odd_pages && (page & 1))
-    return (0);
-
-  if (!even_pages && !(page & 1))
-    return (0);
-
- /*
-  * page-ranges option
-  */
-  
-  if (!page_ranges || page_ranges[0] == '\0')
-    return (1);                                /* No range, print all pages... */
-
-  for (range = page_ranges; *range != '\0';)
-  {
-    if (*range == '-')
-    {
-      lower = 1;
-      range ++;
-      upper = (int)strtol(range, (char **)&range, 10);
-    }
-    else
-    {
-      lower = (int)strtol(range, (char **)&range, 10);
-
-      if (*range == '-')
-      {
-        range ++;
-       if (!isdigit(*range & 255))
-         upper = 65535;
-       else
-         upper = (int)strtol(range, (char **)&range, 10);
-      }
-      else
-        upper = lower;
-    }
-
-    if (page >= lower && page <= upper)
-      return (1);
-
-    if (*range == ',')
-      range ++;
-    else
-      break;
-  }
-
-  return (0);
+  return (ret);
 }
 
 
@@ -1149,10 +71,5 @@ cancel_job(int sig)                        /* I - Signal number (unused) */
 {
   (void)sig;
 
-  job_canceled = 1;
+  JobCanceled = 1;
 }
-
-
-/*
- * End
- */