136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * PostScript filter for CUPS.
336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines *
436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Copyright 2007-2015 by Apple Inc.
536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Copyright 1993-2007 by Easy Software Products.
636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines *
736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * These coded instructions, statements, and computer programs are the
836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * property of Apple Inc. and are protected by Federal copyright
936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
1036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * which should have been included with this file.  If this file is
1136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * missing or damaged, see the license at "http://www.cups.org/".
1236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines *
1336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * This file is subject to the Apple OS-Developed Software exception.
1436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
1536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
1636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
1736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Include necessary headers...
1836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
1936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
2036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "common.h"
2136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include <limits.h>
2236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include <math.h>
2336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include <cups/file.h>
2436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include <cups/array.h>
2536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include <cups/language-private.h>
2636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include <signal.h>
2736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
2836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
2936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
3036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Constants...
3136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
3236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
330c7f116bb6950ef819323d855415b2f2b0aad987Pirama Arumuga Nainar#define PSTOPS_BORDERNONE	0	/* No border or hairline border */
3436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_BORDERTHICK	1	/* Think border */
3536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_BORDERSINGLE	2	/* Single-line hairline border */
3636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_BORDERSINGLE2	3	/* Single-line thick border */
3736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_BORDERDOUBLE	4	/* Double-line hairline border */
3836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_BORDERDOUBLE2	5	/* Double-line thick border */
3936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
4036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_LRBT	0	/* Left to right, bottom to top */
4136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_LRTB	1	/* Left to right, top to bottom */
4236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_RLBT	2	/* Right to left, bottom to top */
4336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_RLTB	3	/* Right to left, top to bottom */
4436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_BTLR	4	/* Bottom to top, left to right */
4536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_TBLR	5	/* Top to bottom, left to right */
4636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_BTRL	6	/* Bottom to top, right to left */
4736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_TBRL	7	/* Top to bottom, right to left */
4836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
4936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_NEGATEY	1	/* The bits for the layout */
5036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_NEGATEX	2	/* definitions above... */
5136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define PSTOPS_LAYOUT_VERTICAL	4
5236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
5336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
5436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
5536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Types...
5636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
5736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
5836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestypedef struct				/**** Page information ****/
5936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
6036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  char		*label;			/* Page label */
6136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		bounding_box[4];	/* PageBoundingBox */
6236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  off_t		offset;			/* Offset to start of page */
6336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ssize_t	length;			/* Number of bytes for page */
6436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		num_options;		/* Number of options for this page */
6536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cups_option_t	*options;		/* Options for this page */
6636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines} pstops_page_t;
6736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
6836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinestypedef struct				/**** Document information ****/
6936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
7036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		page;			/* Current page */
7136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		bounding_box[4];	/* BoundingBox from header */
7236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		new_bounding_box[4];	/* New composite bounding box */
7336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		num_options;		/* Number of document-wide options */
7436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cups_option_t	*options;		/* Document-wide options */
7536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		normal_landscape,	/* Normal rotation for landscape? */
7636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		saw_eof,		/* Saw the %%EOF comment? */
7736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		slow_collate,		/* Collate copies by hand? */
7836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		slow_duplex,		/* Duplex pages slowly? */
7936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		slow_order,		/* Reverse pages slowly? */
8036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		use_ESPshowpage;	/* Use ESPshowpage? */
8136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cups_array_t	*pages;			/* Pages in document */
8236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cups_file_t	*temp;			/* Temporary file, if any */
8336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  char		tempfile[1024];		/* Temporary filename */
8436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		job_id;			/* Job ID */
8536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const char	*user,			/* User name */
8636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*title;			/* Job name */
8736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		copies;			/* Number of copies */
8836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const char	*ap_input_slot,		/* AP_FIRSTPAGE_InputSlot value */
8936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*ap_manual_feed,	/* AP_FIRSTPAGE_ManualFeed value */
9036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*ap_media_color,	/* AP_FIRSTPAGE_MediaColor value */
9136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*ap_media_type,		/* AP_FIRSTPAGE_MediaType value */
9236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*ap_page_region,	/* AP_FIRSTPAGE_PageRegion value */
9336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*ap_page_size;		/* AP_FIRSTPAGE_PageSize value */
9436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		collate,		/* Collate copies? */
9536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		emit_jcl,		/* Emit JCL commands? */
9636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		fit_to_page;		/* Fit pages to media */
9736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const char	*input_slot,		/* InputSlot value */
9836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*manual_feed,		/* ManualFeed value */
9936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*media_color,		/* MediaColor value */
10036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*media_type,		/* MediaType value */
10136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*page_region,		/* PageRegion value */
10236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*page_size;		/* PageSize value */
10336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		mirror,			/* doc->mirror/mirror pages */
10436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		number_up,		/* Number of pages on each sheet */
10536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		number_up_layout,	/* doc->number_up_layout of N-up pages */
10636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		output_order,		/* Requested reverse output order? */
10736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		page_border;		/* doc->page_border around pages */
10836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const char	*page_label,		/* page-label option, if any */
10936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*page_ranges,		/* page-ranges option, if any */
11036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		*page_set;		/* page-set option, if any */
11136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines} pstops_doc_t;
11236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
11336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
11436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
11536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Convenience macros...
11636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
11736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
11836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define	is_first_page(p)	(doc->number_up == 1 || \
11936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				 ((p) % doc->number_up) == 1)
12036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define	is_last_page(p)		(doc->number_up == 1 || \
12136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				 ((p) % doc->number_up) == 0)
12236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define is_not_last_page(p)	(doc->number_up > 1 && \
12336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				 ((p) % doc->number_up) != 0)
12436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
12536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
12636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
12736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Local globals...
12836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
12936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
13036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic int		JobCanceled = 0;/* Set to 1 on SIGTERM */
13136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
13236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
13336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
13436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * Local functions...
13536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
13636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
13736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic pstops_page_t	*add_page(pstops_doc_t *doc, const char *label);
13836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		cancel_job(int sig);
13936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic int		check_range(pstops_doc_t *doc, int page);
14036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		copy_bytes(cups_file_t *fp, off_t offset,
14136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			           size_t length);
14236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic ssize_t		copy_comments(cups_file_t *fp, pstops_doc_t *doc,
14336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			              ppd_file_t *ppd, char *line,
14436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				      ssize_t linelen, size_t linesize);
14536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		copy_dsc(cups_file_t *fp, pstops_doc_t *doc,
14636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			         ppd_file_t *ppd, char *line, ssize_t linelen,
14736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				 size_t linesize);
14836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		copy_non_dsc(cups_file_t *fp, pstops_doc_t *doc,
14936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			             ppd_file_t *ppd, char *line,
15036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				     ssize_t linelen, size_t linesize);
15136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic ssize_t		copy_page(cups_file_t *fp, pstops_doc_t *doc,
15236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			          ppd_file_t *ppd, int number, char *line,
15336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				  ssize_t linelen, size_t linesize);
15436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic ssize_t		copy_prolog(cups_file_t *fp, pstops_doc_t *doc,
15536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			            ppd_file_t *ppd, char *line,
15636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				    ssize_t linelen, size_t linesize);
15736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic ssize_t		copy_setup(cups_file_t *fp, pstops_doc_t *doc,
15836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			           ppd_file_t *ppd, char *line,
15936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				   ssize_t linelen, size_t linesize);
16036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic ssize_t		copy_trailer(cups_file_t *fp, pstops_doc_t *doc,
16136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			             ppd_file_t *ppd, int number, char *line,
16236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				     ssize_t linelen, size_t linesize);
16336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		do_prolog(pstops_doc_t *doc, ppd_file_t *ppd);
16436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void 		do_setup(pstops_doc_t *doc, ppd_file_t *ppd);
16536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		doc_printf(pstops_doc_t *doc, const char *format, ...)
16636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			__attribute__ ((__format__ (__printf__, 2, 3)));
16736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		doc_puts(pstops_doc_t *doc, const char *s);
16836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		doc_write(pstops_doc_t *doc, const char *s, size_t len);
16936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		end_nup(pstops_doc_t *doc, int number);
17036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic int		include_feature(ppd_file_t *ppd, const char *line,
17136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			                int num_options,
17236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines					cups_option_t **options);
17336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic char		*parse_text(const char *start, char **end, char *buffer,
17436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			            size_t bufsize);
17536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		set_pstops_options(pstops_doc_t *doc, ppd_file_t *ppd,
17636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			                   char *argv[], int num_options,
17736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			                   cups_option_t *options);
17836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic ssize_t		skip_page(cups_file_t *fp, char *line, ssize_t linelen,
17936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				  size_t linesize);
18036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		start_nup(pstops_doc_t *doc, int number,
18136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines				  int show_border, const int *bounding_box);
18236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		write_label_prolog(pstops_doc_t *doc, const char *label,
18336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			                   float bottom, float top,
18436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines					   float width);
18536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		write_labels(pstops_doc_t *doc, int orient);
18636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void		write_options(pstops_doc_t  *doc, ppd_file_t *ppd,
18736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines			              int num_options, cups_option_t *options);
18836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
18936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
19036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
19136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * 'main()' - Main entry.
19236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
19336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
19436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesint					/* O - Exit status */
19536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesmain(int  argc,				/* I - Number of command-line args */
19636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines     char *argv[])			/* I - Command-line arguments */
19736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
19836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  pstops_doc_t	doc;			/* Document information */
19936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cups_file_t	*fp;			/* Print file */
20036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ppd_file_t	*ppd;			/* PPD file */
20136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		num_options;		/* Number of print options */
20236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cups_option_t	*options;		/* Print options */
20336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  char		line[8192];		/* Line buffer */
20436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ssize_t	len;			/* Length of line buffer */
20536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
20636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  struct sigaction action;		/* Actions for POSIX signals */
20736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
20836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
20936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
21036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
21136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Make sure status messages are not buffered...
21236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
21336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
21436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  setbuf(stderr, NULL);
21536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
21636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
21736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Ignore broken pipe signals...
21836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
21936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
22036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  signal(SIGPIPE, SIG_IGN);
22136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
22236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
22336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Check command-line...
22436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
22536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
22636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (argc < 6 || argc > 7)
22736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
22836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    _cupsLangPrintf(stderr,
22936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                    _("Usage: %s job-id user title copies options [file]"),
23036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                    argv[0]);
23136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return (1);
23236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
23336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
23436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
23536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Register a signal handler to cleanly cancel a job.
23636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
23736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
23836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
23936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  sigset(SIGTERM, cancel_job);
24036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#elif defined(HAVE_SIGACTION)
24136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  memset(&action, 0, sizeof(action));
24236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
24336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  sigemptyset(&action.sa_mask);
24436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  action.sa_handler = cancel_job;
24536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  sigaction(SIGTERM, &action, NULL);
24636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#else
24736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  signal(SIGTERM, cancel_job);
24836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#endif /* HAVE_SIGSET */
24936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
25036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
25136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * If we have 7 arguments, print the file named on the command-line.
25236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Otherwise, send stdin instead...
25336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
25436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
25536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (argc == 6)
25636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    fp = cupsFileStdin();
25736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  else
25836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
25936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
26036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Try to open the print file...
26136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
26236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
26336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
26436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
26536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (!JobCanceled)
26636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      {
26736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        fprintf(stderr, "DEBUG: Unable to open \"%s\".\n", argv[6]);
26836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        _cupsLangPrintError("ERROR", _("Unable to open print file"));
26936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
27036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
27136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return (1);
27236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
27336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
27436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
27536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
27636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Read the first line to see if we have DSC comments...
27736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
27836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
27936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if ((len = (ssize_t)cupsFileGetLine(fp, line, sizeof(line))) == 0)
28036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
28136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    fputs("DEBUG: The print file is empty.\n", stderr);
28236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return (1);
28336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
28436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
28536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
28636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Process command-line options...
28736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
28836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
28936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  options     = NULL;
29036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  num_options = cupsParseOptions(argv[5], 0, &options);
29136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ppd         = SetCommonOptions(num_options, options, 1);
29236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
29336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  set_pstops_options(&doc, ppd, argv, num_options, options);
29436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
29536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
29636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Write any "exit server" options that have been selected...
29736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
29836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
29936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
30036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
30136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
30236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Write any JCL commands that are needed to print PostScript code...
30336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
30436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
30536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (doc.emit_jcl)
30636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    ppdEmitJCL(ppd, stdout, doc.job_id, doc.user, doc.title);
30736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
30836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
30936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Start with a DSC header...
31036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
31136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
31236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  puts("%!PS-Adobe-3.0");
31336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
31436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
31536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Skip leading PJL in the document...
31636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
31736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
31836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
31936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
32036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
32136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Yup, we have leading PJL fun, so skip it until we hit the line
32236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * with "ENTER LANGUAGE"...
32336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
32436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
32536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    fputs("DEBUG: Skipping PJL header...\n", stderr);
32636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
32736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
32836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if ((len = (ssize_t)cupsFileGetLine(fp, line, sizeof(line))) == 0)
32936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        break;
33036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
33136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (!strncmp(line, "%!", 2))
33236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
33336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
33436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if ((len = (ssize_t)cupsFileGetLine(fp, line, sizeof(line))) == 0)
33536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
33636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
33736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
33836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
33936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Now see if the document conforms to the Adobe Document Structuring
34036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Conventions...
34136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
34236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
34336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!strncmp(line, "%!PS-Adobe-", 11))
34436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
34536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
34636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Yes, filter the document...
34736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
34836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
34936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    copy_dsc(fp, &doc, ppd, line, len, sizeof(line));
35036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
35136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  else
35236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
35336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
35436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * No, display an error message and treat the file as if it contains
35536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * a single page...
35636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
35736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
35836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    copy_non_dsc(fp, &doc, ppd, line, len, sizeof(line));
35936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
36036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
36136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
36236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Send %%EOF as needed...
36336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
36436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
36536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!doc.saw_eof)
36636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    puts("%%EOF");
36736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
36836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
36936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * End the job with the appropriate JCL command or CTRL-D...
37036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
37136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
37236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (doc.emit_jcl)
37336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
37436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (ppd && ppd->jcl_end)
37536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      ppdEmitJCLEnd(ppd, stdout);
37636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else
37736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      putchar(0x04);
37836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
37936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
38036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
38136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Close files and remove the temporary file if needed...
38236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
38336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
38436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (doc.temp)
38536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
38636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    cupsFileClose(doc.temp);
38736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    unlink(doc.tempfile);
38836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
38936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
39036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ppdClose(ppd);
39136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cupsFreeOptions(num_options, options);
39236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
39336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cupsFileClose(fp);
39436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
39536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  return (0);
39636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
39736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
39836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
39936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
40036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * 'add_page()' - Add a page to the pages array.
40136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
40236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
40336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic pstops_page_t *			/* O - New page info object */
40436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesadd_page(pstops_doc_t *doc,		/* I - Document information */
40536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines         const char   *label)		/* I - Page label */
40636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
40736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  pstops_page_t	*pageinfo;		/* New page info object */
40836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
40936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
41036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!doc->pages)
41136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc->pages = cupsArrayNew(NULL, NULL);
41236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
41336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!doc->pages)
41436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
41536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    _cupsLangPrintError("EMERG", _("Unable to allocate memory for pages array"));
41636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    exit(1);
41736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
41836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
41936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if ((pageinfo = calloc(1, sizeof(pstops_page_t))) == NULL)
42036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
42136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    _cupsLangPrintError("EMERG", _("Unable to allocate memory for page info"));
42236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    exit(1);
42336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
42436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
42536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  pageinfo->label  = strdup(label);
42636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  pageinfo->offset = cupsFileTell(doc->temp);
42736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
42836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  cupsArrayAdd(doc->pages, pageinfo);
42936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
43036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  doc->page ++;
43136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
43236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  return (pageinfo);
43336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
43436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
43536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
43636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
43736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * 'cancel_job()' - Flag the job as canceled.
43836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
43936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
44036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void
44136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinescancel_job(int sig)			/* I - Signal number (unused) */
44236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
44336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  (void)sig;
44436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
44536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  JobCanceled = 1;
44636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
44736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
44836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
44936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
45036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * 'check_range()' - Check to see if the current page is selected for
45136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines *                   printing.
45236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
45336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
45436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic int				/* O - 1 if selected, 0 otherwise */
45536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinescheck_range(pstops_doc_t *doc,		/* I - Document information */
45636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines            int          page)		/* I - Page number */
45736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
45836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  const char	*range;			/* Pointer into range string */
45936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		lower, upper;		/* Lower and upper page numbers */
46036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
46136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
46236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (doc->page_set)
46336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
46436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
46536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * See if we only print even or odd pages...
46636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
46736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
46836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (!_cups_strcasecmp(doc->page_set, "even") && (page & 1))
46936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return (0);
47036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
47136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (!_cups_strcasecmp(doc->page_set, "odd") && !(page & 1))
47236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return (0);
47336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
47436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
47536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!doc->page_ranges)
47636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return (1);				/* No range, print all pages... */
47736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
47836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  for (range = doc->page_ranges; *range != '\0';)
47936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
48036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (*range == '-')
48136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
48236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      lower = 1;
48336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      range ++;
48436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      upper = (int)strtol(range, (char **)&range, 10);
48536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
48636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else
48736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
48836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      lower = (int)strtol(range, (char **)&range, 10);
48936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
49036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (*range == '-')
49136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      {
49236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        range ++;
49336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	if (!isdigit(*range & 255))
49436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  upper = 65535;
49536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	else
49636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  upper = (int)strtol(range, (char **)&range, 10);
49736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
49836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      else
49936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        upper = lower;
50036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
50136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
50236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (page >= lower && page <= upper)
50336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return (1);
50436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
50536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (*range == ',')
50636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      range ++;
50736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else
50836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
50936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
51036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
51136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  return (0);
51236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
51336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
51436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
51536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
51636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * 'copy_bytes()' - Copy bytes from the input file to stdout.
51736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
51836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
51936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void
52036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinescopy_bytes(cups_file_t *fp,		/* I - File to read from */
52136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines           off_t       offset,		/* I - Offset to page data */
52236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines           size_t      length)		/* I - Length of page data */
52336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
52436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  char		buffer[8192];		/* Data buffer */
52536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  ssize_t	nbytes;			/* Number of bytes read */
52636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  size_t	nleft;			/* Number of bytes left/remaining */
52736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
52836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
52936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  nleft = length;
53036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
53136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (cupsFileSeek(fp, offset) < 0)
53236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
53336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    _cupsLangPrintError("ERROR", _("Unable to see in file"));
53436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return;
53536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
53636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
53736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  while (nleft > 0 || length == 0)
53836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
53936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (nleft > sizeof(buffer) || length == 0)
54036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      nbytes = sizeof(buffer);
54136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else
54236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      nbytes = (ssize_t)nleft;
54336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
54436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if ((nbytes = cupsFileRead(fp, buffer, (size_t)nbytes)) < 1)
54536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return;
54636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
54736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    nleft -= (size_t)nbytes;
54836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
54936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    fwrite(buffer, 1, (size_t)nbytes, stdout);
55036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
55136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
55236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
55336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
55436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
55536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * 'copy_comments()' - Copy all of the comments section.
55636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines *
55736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * This function expects "line" to be filled with a comment line.
55836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * On return, "line" will contain the next line in the file, if any.
55936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
56036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
56136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic ssize_t				/* O - Length of next line */
56236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinescopy_comments(cups_file_t  *fp,		/* I - File to read from */
56336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines              pstops_doc_t *doc,	/* I - Document info */
56436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	      ppd_file_t   *ppd,	/* I - PPD file */
56536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines              char         *line,	/* I - Line buffer */
56636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	      ssize_t      linelen,	/* I - Length of initial line */
56736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	      size_t       linesize)	/* I - Size of line buffer */
56836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
56936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int	saw_bounding_box,		/* Saw %%BoundingBox: comment? */
57036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	saw_for,			/* Saw %%For: comment? */
57136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	saw_pages,			/* Saw %%Pages: comment? */
57236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	saw_title;			/* Saw %%Title: comment? */
57336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
57436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
57536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
57636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Loop until we see %%EndComments or a non-comment line...
57736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
57836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
57936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  saw_bounding_box = 0;
58036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  saw_for          = 0;
58136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  saw_pages        = 0;
58236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  saw_title        = 0;
58336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
58436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  while (line[0] == '%')
58536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
58636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
58736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Strip trailing whitespace...
58836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
58936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
59036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    while (linelen > 0)
59136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
59236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      linelen --;
59336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
59436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (!isspace(line[linelen] & 255))
59536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        break;
59636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      else
59736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        line[linelen] = '\0';
59836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
59936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
60036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
60136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Log the header...
60236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
60336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
60436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    fprintf(stderr, "DEBUG: %s\n", line);
60536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
60636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
60736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Pull the headers out...
60836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
60936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
61036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (!strncmp(line, "%%Pages:", 8))
61136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
61236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      int	pages;			/* Number of pages */
61336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
61436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (saw_pages)
61536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	fputs("DEBUG: A duplicate %%Pages: comment was seen.\n", stderr);
61636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
61736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      saw_pages = 1;
61836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
61936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (Duplex && (pages = atoi(line + 8)) > 0 && pages <= doc->number_up)
62036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      {
62136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines       /*
62236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        * Since we will only be printing on a single page, disable duplexing.
62336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	*/
62436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
62536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	Duplex           = 0;
62636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	doc->slow_duplex = 0;
62736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
62836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	if (cupsGetOption("sides", doc->num_options, doc->options))
62936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  doc->num_options = cupsAddOption("sides", "one-sided",
63036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	                                   doc->num_options, &(doc->options));
63136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
63236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	if (cupsGetOption("Duplex", doc->num_options, doc->options))
63336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  doc->num_options = cupsAddOption("Duplex", "None",
63436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	                                   doc->num_options, &(doc->options));
63536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
63636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	if (cupsGetOption("EFDuplex", doc->num_options, doc->options))
63736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  doc->num_options = cupsAddOption("EFDuplex", "None",
63836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	                                   doc->num_options, &(doc->options));
63936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
64036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	if (cupsGetOption("EFDuplexing", doc->num_options, doc->options))
64136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  doc->num_options = cupsAddOption("EFDuplexing", "False",
64236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	                                   doc->num_options, &(doc->options));
64336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
64436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	if (cupsGetOption("KD03Duplex", doc->num_options, doc->options))
64536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  doc->num_options = cupsAddOption("KD03Duplex", "None",
64636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	                                   doc->num_options, &(doc->options));
64736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
64836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	if (cupsGetOption("JCLDuplex", doc->num_options, doc->options))
64936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	  doc->num_options = cupsAddOption("JCLDuplex", "None",
65036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	                                   doc->num_options, &(doc->options));
65136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
65236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	ppdMarkOption(ppd, "Duplex", "None");
65336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	ppdMarkOption(ppd, "EFDuplex", "None");
65436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	ppdMarkOption(ppd, "EFDuplexing", "False");
65536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	ppdMarkOption(ppd, "KD03Duplex", "None");
65636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	ppdMarkOption(ppd, "JCLDuplex", "None");
65736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
65836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
65936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else if (!strncmp(line, "%%BoundingBox:", 14))
66036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
66136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (saw_bounding_box)
66236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	fputs("DEBUG: A duplicate %%BoundingBox: comment was seen.\n", stderr);
66336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      else if (strstr(line + 14, "(atend)"))
66436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      {
66536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines       /*
66636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        * Do nothing for now but use the default imageable area...
66736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	*/
66836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
66936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      else if (sscanf(line + 14, "%d%d%d%d", doc->bounding_box + 0,
67036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	              doc->bounding_box + 1, doc->bounding_box + 2,
67136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines		      doc->bounding_box + 3) != 4)
67236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      {
67336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	fputs("DEBUG: A bad %%BoundingBox: comment was seen.\n", stderr);
67436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
67536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	doc->bounding_box[0] = (int)PageLeft;
67636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	doc->bounding_box[1] = (int)PageBottom;
67736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	doc->bounding_box[2] = (int)PageRight;
67836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	doc->bounding_box[3] = (int)PageTop;
67936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
68036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
68136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      saw_bounding_box = 1;
68236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
68336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else if (!strncmp(line, "%%For:", 6))
68436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
68536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      saw_for = 1;
68636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      doc_printf(doc, "%s\n", line);
68736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
68836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else if (!strncmp(line, "%%Title:", 8))
68936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
69036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      saw_title = 1;
69136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      doc_printf(doc, "%s\n", line);
69236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
69336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else if (!strncmp(line, "%cupsRotation:", 14))
69436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
69536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines     /*
69636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      * Reset orientation of document?
69736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      */
69836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
69936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      int orient = (atoi(line + 14) / 90) & 3;
70036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
70136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (orient != Orientation)
70236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      {
70336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines       /*
70436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        * Yes, update things so that the pages come out right...
70536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	*/
70636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
70736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	Orientation = (4 - Orientation + orient) & 3;
70836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	UpdatePageVars();
70936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	Orientation = orient;
71036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      }
71136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
71236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else if (!strcmp(line, "%%EndComments"))
71336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
71436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
71536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
71636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
71736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else if (strncmp(line, "%!", 2) && strncmp(line, "%cups", 5))
71836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      doc_printf(doc, "%s\n", line);
71936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
72036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
72136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
72236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
72336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
72436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!saw_bounding_box)
72536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    fputs("DEBUG: There wasn't a %%BoundingBox: comment in the header.\n",
72636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines          stderr);
72736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
72836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!saw_pages)
72936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    fputs("DEBUG: There wasn't a %%Pages: comment in the header.\n", stderr);
73036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
73136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!saw_for)
73236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    WriteTextComment("For", doc->user);
73336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
73436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (!saw_title)
73536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    WriteTextComment("Title", doc->title);
73636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
73736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
73836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
73936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
74036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Tell the document processor the copy and duplex options
74136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * that are required...
74236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
74336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
74436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc_printf(doc, "%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
74536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines               doc->collate ? " collate" : "",
74636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	       Duplex ? " duplex" : "");
74736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
74836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
74936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Apple uses RBI comments for various non-PPD options...
75036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
75136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
75236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc_printf(doc, "%%RBINumCopies: %d\n", doc->copies);
75336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
75436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  else
75536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
75636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
75736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Tell the document processor the duplex option that is required...
75836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
75936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
76036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (Duplex)
76136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      doc_puts(doc, "%%Requirements: duplex\n");
76236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
76336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
76436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Apple uses RBI comments for various non-PPD options...
76536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
76636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
76736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc_puts(doc, "%RBINumCopies: 1\n");
76836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
76936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
77036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  doc_puts(doc, "%%Pages: (atend)\n");
77136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  doc_puts(doc, "%%BoundingBox: (atend)\n");
77236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  doc_puts(doc, "%%EndComments\n");
77336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
77436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  return (linelen);
77536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}
77636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
77736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
77836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines/*
77936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * 'copy_dsc()' - Copy a DSC-conforming document.
78036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines *
78136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines * This function expects "line" to be filled with the %!PS-Adobe comment line.
78236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines */
78336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
78436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void
78536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinescopy_dsc(cups_file_t  *fp,		/* I - File to read from */
78636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines         pstops_doc_t *doc,		/* I - Document info */
78736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines         ppd_file_t   *ppd,		/* I - PPD file */
78836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	 char         *line,		/* I - Line buffer */
78936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	 ssize_t      linelen,		/* I - Length of initial line */
79036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	 size_t       linesize)		/* I - Size of line buffer */
79136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
79236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  int		number;			/* Page number */
79336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  pstops_page_t	*pageinfo;		/* Page information */
79436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
79536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
79636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
79736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Make sure we use ESPshowpage for EPS files...
79836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
79936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
80036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (strstr(line, "EPSF"))
80136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
80236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc->use_ESPshowpage = 1;
80336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc->number_up       = 1;
80436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
80536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
80636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
80736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Start sending the document with any commands needed...
80836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
80936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
81036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  fprintf(stderr, "DEBUG: Before copy_comments - %s", line);
81136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  linelen = copy_comments(fp, doc, ppd, line, linelen, linesize);
81236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
81336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
81436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Now find the prolog section, if any...
81536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
81636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
81736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  fprintf(stderr, "DEBUG: Before copy_prolog - %s", line);
81836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  linelen = copy_prolog(fp, doc, ppd, line, linelen, linesize);
81936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
82036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
82136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Then the document setup section...
82236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
82336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
82436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  fprintf(stderr, "DEBUG: Before copy_setup - %s", line);
82536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  linelen = copy_setup(fp, doc, ppd, line, linelen, linesize);
82636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
82736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
82836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Copy until we see %%Page:...
82936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
83036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
83136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  while (strncmp(line, "%%Page:", 7) && strncmp(line, "%%Trailer", 9))
83236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
83336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc_write(doc, line, (size_t)linelen);
83436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
83536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
83636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
83736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
83836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
83936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
84036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Then process pages until we have no more...
84136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
84236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
84336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  number = 0;
84436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
84536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  fprintf(stderr, "DEBUG: Before page loop - %s", line);
84636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  while (!strncmp(line, "%%Page:", 7))
84736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
84836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (JobCanceled)
84936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      break;
85036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
85136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    number ++;
85236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
85336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (check_range(doc, (number - 1) / doc->number_up + 1))
85436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
85536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      fprintf(stderr, "DEBUG: Copying page %d...\n", number);
85636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      linelen = copy_page(fp, doc, ppd, number, line, linelen, linesize);
85736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
85836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else
85936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
86036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      fprintf(stderr, "DEBUG: Skipping page %d...\n", number);
86136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      linelen = skip_page(fp, line, linelen, linesize);
86236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
86336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
86436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
86536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
86636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Finish up the last page(s)...
86736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
86836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
86936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (number && is_not_last_page(number) && cupsArrayLast(doc->pages) &&
87036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      check_range(doc, (number - 1) / doc->number_up + 1))
87136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
87236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
87336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
87436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    start_nup(doc, doc->number_up, 0, doc->bounding_box);
87536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc_puts(doc, "showpage\n");
87636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    end_nup(doc, doc->number_up);
87736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
87836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    pageinfo->length = (ssize_t)(cupsFileTell(doc->temp) - pageinfo->offset);
87936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
88036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
88136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (doc->slow_duplex && (doc->page & 1))
88236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
88336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
88436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Make sure we have an even number of pages...
88536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
88636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
88736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    pageinfo = add_page(doc, "(filler)");
88836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
88936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (!doc->slow_order)
89036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
89136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (!ppd || !ppd->num_filters)
89236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	fprintf(stderr, "PAGE: %d %d\n", doc->page,
89336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        	doc->slow_collate ? 1 : doc->copies);
89436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
89536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      printf("%%%%Page: (filler) %d\n", doc->page);
89636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
89736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
89836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    start_nup(doc, doc->number_up, 0, doc->bounding_box);
89936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc_puts(doc, "showpage\n");
90036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    end_nup(doc, doc->number_up);
90136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
90236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    pageinfo->length = (ssize_t)(cupsFileTell(doc->temp) - pageinfo->offset);
90336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
90436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
90536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines /*
90636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  * Make additional copies as necessary...
90736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  */
90836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
90936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  number = doc->slow_order ? 0 : doc->page;
91036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
91136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (doc->temp && !JobCanceled && cupsArrayCount(doc->pages) > 0)
91236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  {
91336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    int	copy;				/* Current copy */
91436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
91536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
91636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
91736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Reopen the temporary file for reading...
91836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
91936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
92036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    cupsFileClose(doc->temp);
92136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
92236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    doc->temp = cupsFileOpen(doc->tempfile, "r");
92336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
92436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines   /*
92536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    * Make the copies...
92636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    */
92736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
92836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (doc->slow_collate)
92936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      copy = !doc->slow_order;
93036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    else
93136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      copy = doc->copies - 1;
93236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
93336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    for (; copy < doc->copies; copy ++)
93436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    {
93536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (JobCanceled)
93636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	break;
93736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
93836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines     /*
93936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      * Send end-of-job stuff followed by any start-of-job stuff required
94036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      * for the JCL options...
94136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      */
94236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
94336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      if (number && doc->emit_jcl && ppd && ppd->jcl_end)
94436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      {
94536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines       /*
94636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        * Send the trailer...
94736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines	*/
94836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines
94936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        puts("%%Trailer");
950	printf("%%%%Pages: %d\n", cupsArrayCount(doc->pages));
951	if (doc->number_up > 1 || doc->fit_to_page)
952	  printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
953		 PageLeft, PageBottom, PageRight, PageTop);
954	else
955	  printf("%%%%BoundingBox: %d %d %d %d\n",
956		 doc->new_bounding_box[0], doc->new_bounding_box[1],
957		 doc->new_bounding_box[2], doc->new_bounding_box[3]);
958        puts("%%EOF");
959
960       /*
961        * Start a new document...
962	*/
963
964        ppdEmitJCLEnd(ppd, stdout);
965        ppdEmitJCL(ppd, stdout, doc->job_id, doc->user, doc->title);
966
967	puts("%!PS-Adobe-3.0");
968
969	number = 0;
970      }
971
972     /*
973      * Copy the prolog as needed...
974      */
975
976      if (!number)
977      {
978        pageinfo = (pstops_page_t *)cupsArrayFirst(doc->pages);
979	copy_bytes(doc->temp, 0, (size_t)pageinfo->offset);
980      }
981
982     /*
983      * Then copy all of the pages...
984      */
985
986      pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayLast(doc->pages) :
987                                   (pstops_page_t *)cupsArrayFirst(doc->pages);
988
989      while (pageinfo)
990      {
991        if (JobCanceled)
992	  break;
993
994        number ++;
995
996	if (!ppd || !ppd->num_filters)
997	  fprintf(stderr, "PAGE: %d %d\n", number,
998	          doc->slow_collate ? 1 : doc->copies);
999
1000	if (doc->number_up > 1)
1001	{
1002	  printf("%%%%Page: (%d) %d\n", number, number);
1003	  printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
1004		 PageLeft, PageBottom, PageRight, PageTop);
1005	}
1006	else
1007	{
1008          printf("%%%%Page: %s %d\n", pageinfo->label, number);
1009	  printf("%%%%PageBoundingBox: %d %d %d %d\n",
1010		 pageinfo->bounding_box[0], pageinfo->bounding_box[1],
1011		 pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
1012	}
1013
1014	copy_bytes(doc->temp, pageinfo->offset, (size_t)pageinfo->length);
1015
1016	pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayPrev(doc->pages) :
1017                                     (pstops_page_t *)cupsArrayNext(doc->pages);
1018      }
1019    }
1020  }
1021
1022 /*
1023  * Restore the old showpage operator as needed...
1024  */
1025
1026  if (doc->use_ESPshowpage)
1027    puts("userdict/showpage/ESPshowpage load put\n");
1028
1029 /*
1030  * Write/copy the trailer...
1031  */
1032
1033  if (!JobCanceled)
1034    copy_trailer(fp, doc, ppd, number, line, linelen, linesize);
1035}
1036
1037
1038/*
1039 * 'copy_non_dsc()' - Copy a document that does not conform to the DSC.
1040 *
1041 * This function expects "line" to be filled with the %! comment line.
1042 */
1043
1044static void
1045copy_non_dsc(cups_file_t  *fp,		/* I - File to read from */
1046             pstops_doc_t *doc,		/* I - Document info */
1047             ppd_file_t   *ppd,		/* I - PPD file */
1048	     char         *line,	/* I - Line buffer */
1049	     ssize_t      linelen,	/* I - Length of initial line */
1050	     size_t       linesize)	/* I - Size of line buffer */
1051{
1052  int		copy;			/* Current copy */
1053  char		buffer[8192];		/* Copy buffer */
1054  ssize_t	bytes;			/* Number of bytes copied */
1055
1056
1057  (void)linesize;
1058
1059 /*
1060  * First let the user know that they are attempting to print a file
1061  * that may not print correctly...
1062  */
1063
1064  fputs("DEBUG: This document does not conform to the Adobe Document "
1065        "Structuring Conventions and may not print correctly.\n", stderr);
1066
1067 /*
1068  * Then write a standard DSC comment section...
1069  */
1070
1071  printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
1072         PageRight, PageTop);
1073
1074  if (doc->slow_collate && doc->copies > 1)
1075    printf("%%%%Pages: %d\n", doc->copies);
1076  else
1077    puts("%%Pages: 1");
1078
1079  WriteTextComment("For", doc->user);
1080  WriteTextComment("Title", doc->title);
1081
1082  if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
1083  {
1084   /*
1085    * Tell the document processor the copy and duplex options
1086    * that are required...
1087    */
1088
1089    printf("%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
1090           doc->collate ? " collate" : "",
1091	   Duplex ? " duplex" : "");
1092
1093   /*
1094    * Apple uses RBI comments for various non-PPD options...
1095    */
1096
1097    printf("%%RBINumCopies: %d\n", doc->copies);
1098  }
1099  else
1100  {
1101   /*
1102    * Tell the document processor the duplex option that is required...
1103    */
1104
1105    if (Duplex)
1106      puts("%%Requirements: duplex");
1107
1108   /*
1109    * Apple uses RBI comments for various non-PPD options...
1110    */
1111
1112    puts("%RBINumCopies: 1");
1113  }
1114
1115  puts("%%EndComments");
1116
1117 /*
1118  * Then the prolog...
1119  */
1120
1121  puts("%%BeginProlog");
1122
1123  do_prolog(doc, ppd);
1124
1125  puts("%%EndProlog");
1126
1127 /*
1128  * Then the setup section...
1129  */
1130
1131  puts("%%BeginSetup");
1132
1133  do_setup(doc, ppd);
1134
1135  puts("%%EndSetup");
1136
1137 /*
1138  * Finally, embed a copy of the file inside a %%Page...
1139  */
1140
1141  if (!ppd || !ppd->num_filters)
1142    fprintf(stderr, "PAGE: 1 %d\n", doc->temp ? 1 : doc->copies);
1143
1144  puts("%%Page: 1 1");
1145  puts("%%BeginPageSetup");
1146  ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
1147  puts("%%EndPageSetup");
1148  puts("%%BeginDocument: nondsc");
1149
1150  fwrite(line, (size_t)linelen, 1, stdout);
1151
1152  if (doc->temp)
1153    cupsFileWrite(doc->temp, line, (size_t)linelen);
1154
1155  while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
1156  {
1157    fwrite(buffer, 1, (size_t)bytes, stdout);
1158
1159    if (doc->temp)
1160      cupsFileWrite(doc->temp, buffer, (size_t)bytes);
1161  }
1162
1163  puts("%%EndDocument");
1164
1165  if (doc->use_ESPshowpage)
1166  {
1167    WriteLabels(Orientation);
1168    puts("ESPshowpage");
1169  }
1170
1171  if (doc->temp && !JobCanceled)
1172  {
1173   /*
1174    * Reopen the temporary file for reading...
1175    */
1176
1177    cupsFileClose(doc->temp);
1178
1179    doc->temp = cupsFileOpen(doc->tempfile, "r");
1180
1181   /*
1182    * Make the additional copies as needed...
1183    */
1184
1185    for (copy = 1; copy < doc->copies; copy ++)
1186    {
1187      if (JobCanceled)
1188	break;
1189
1190      if (!ppd || !ppd->num_filters)
1191	fputs("PAGE: 1 1\n", stderr);
1192
1193      printf("%%%%Page: %d %d\n", copy + 1, copy + 1);
1194      puts("%%BeginPageSetup");
1195      ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
1196      puts("%%EndPageSetup");
1197      puts("%%BeginDocument: nondsc");
1198
1199      copy_bytes(doc->temp, 0, 0);
1200
1201      puts("%%EndDocument");
1202
1203      if (doc->use_ESPshowpage)
1204      {
1205	WriteLabels(Orientation);
1206        puts("ESPshowpage");
1207      }
1208    }
1209  }
1210
1211 /*
1212  * Restore the old showpage operator as needed...
1213  */
1214
1215  if (doc->use_ESPshowpage)
1216    puts("userdict/showpage/ESPshowpage load put\n");
1217}
1218
1219
1220/*
1221 * 'copy_page()' - Copy a page description.
1222 *
1223 * This function expects "line" to be filled with a %%Page comment line.
1224 * On return, "line" will contain the next line in the file, if any.
1225 */
1226
1227static ssize_t				/* O - Length of next line */
1228copy_page(cups_file_t  *fp,		/* I - File to read from */
1229          pstops_doc_t *doc,		/* I - Document info */
1230          ppd_file_t   *ppd,		/* I - PPD file */
1231	  int          number,		/* I - Current page number */
1232	  char         *line,		/* I - Line buffer */
1233	  ssize_t      linelen,		/* I - Length of initial line */
1234	  size_t       linesize)	/* I - Size of line buffer */
1235{
1236  char		label[256],		/* Page label string */
1237		*ptr;			/* Pointer into line */
1238  int		level;			/* Embedded document level */
1239  pstops_page_t	*pageinfo;		/* Page information */
1240  int		first_page;		/* First page on N-up output? */
1241  int		has_page_setup = 0;	/* Does the page have %%Begin/EndPageSetup? */
1242  int		bounding_box[4];	/* PageBoundingBox */
1243
1244
1245 /*
1246  * Get the page label for this page...
1247  */
1248
1249  first_page = is_first_page(number);
1250
1251  if (!parse_text(line + 7, &ptr, label, sizeof(label)))
1252  {
1253    fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr);
1254    label[0] = '\0';
1255    number   = doc->page;
1256  }
1257  else if (strtol(ptr, &ptr, 10) == LONG_MAX || !isspace(*ptr & 255))
1258  {
1259    fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr);
1260    number = doc->page;
1261  }
1262
1263 /*
1264  * Create or update the current output page...
1265  */
1266
1267  if (first_page)
1268    pageinfo = add_page(doc, label);
1269  else
1270    pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
1271
1272 /*
1273  * Handle first page override...
1274  */
1275
1276  if (doc->ap_input_slot || doc->ap_manual_feed)
1277  {
1278    if ((doc->page == 1 && (!doc->slow_order || !Duplex)) ||
1279        (doc->page == 2 && doc->slow_order && Duplex))
1280    {
1281     /*
1282      * First page/sheet gets AP_FIRSTPAGE_* options...
1283      */
1284
1285      pageinfo->num_options = cupsAddOption("InputSlot", doc->ap_input_slot,
1286                                            pageinfo->num_options,
1287					    &(pageinfo->options));
1288      pageinfo->num_options = cupsAddOption("ManualFeed",
1289                                            doc->ap_input_slot ? "False" :
1290					        doc->ap_manual_feed,
1291                                            pageinfo->num_options,
1292					    &(pageinfo->options));
1293      pageinfo->num_options = cupsAddOption("MediaColor", doc->ap_media_color,
1294                                            pageinfo->num_options,
1295					    &(pageinfo->options));
1296      pageinfo->num_options = cupsAddOption("MediaType", doc->ap_media_type,
1297                                            pageinfo->num_options,
1298					    &(pageinfo->options));
1299      pageinfo->num_options = cupsAddOption("PageRegion", doc->ap_page_region,
1300                                            pageinfo->num_options,
1301					    &(pageinfo->options));
1302      pageinfo->num_options = cupsAddOption("PageSize", doc->ap_page_size,
1303                                            pageinfo->num_options,
1304					    &(pageinfo->options));
1305    }
1306    else if (doc->page == (Duplex + 2))
1307    {
1308     /*
1309      * Second page/sheet gets default options...
1310      */
1311
1312      pageinfo->num_options = cupsAddOption("InputSlot", doc->input_slot,
1313                                            pageinfo->num_options,
1314					    &(pageinfo->options));
1315      pageinfo->num_options = cupsAddOption("ManualFeed",
1316                                            doc->input_slot ? "False" :
1317					        doc->manual_feed,
1318                                            pageinfo->num_options,
1319					    &(pageinfo->options));
1320      pageinfo->num_options = cupsAddOption("MediaColor", doc->media_color,
1321                                            pageinfo->num_options,
1322					    &(pageinfo->options));
1323      pageinfo->num_options = cupsAddOption("MediaType", doc->media_type,
1324                                            pageinfo->num_options,
1325					    &(pageinfo->options));
1326      pageinfo->num_options = cupsAddOption("PageRegion", doc->page_region,
1327                                            pageinfo->num_options,
1328					    &(pageinfo->options));
1329      pageinfo->num_options = cupsAddOption("PageSize", doc->page_size,
1330                                            pageinfo->num_options,
1331					    &(pageinfo->options));
1332    }
1333  }
1334
1335 /*
1336  * Scan comments until we see something other than %%Page*: or
1337  * %%Include*...
1338  */
1339
1340  memcpy(bounding_box, doc->bounding_box, sizeof(bounding_box));
1341
1342  while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
1343  {
1344    if (!strncmp(line, "%%PageBoundingBox:", 18))
1345    {
1346     /*
1347      * %%PageBoundingBox: llx lly urx ury
1348      */
1349
1350      if (sscanf(line + 18, "%d%d%d%d", bounding_box + 0,
1351                 bounding_box + 1, bounding_box + 2,
1352		 bounding_box + 3) != 4)
1353      {
1354	fputs("DEBUG: There was a bad %%PageBoundingBox: comment in the file.\n", stderr);
1355        memcpy(bounding_box, doc->bounding_box,
1356	       sizeof(bounding_box));
1357      }
1358      else if (doc->number_up == 1 && !doc->fit_to_page  && Orientation)
1359      {
1360        int	temp_bbox[4];		/* Temporary bounding box */
1361
1362
1363        memcpy(temp_bbox, bounding_box, sizeof(temp_bbox));
1364
1365        fprintf(stderr, "DEBUG: Orientation = %d\n", Orientation);
1366        fprintf(stderr, "DEBUG: original bounding_box = [ %d %d %d %d ]\n",
1367		bounding_box[0], bounding_box[1],
1368		bounding_box[2], bounding_box[3]);
1369        fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n",
1370	        PageWidth, PageLength);
1371
1372        switch (Orientation)
1373	{
1374	  case 1 : /* Landscape */
1375	      bounding_box[0] = (int)(PageLength - temp_bbox[3]);
1376	      bounding_box[1] = temp_bbox[0];
1377	      bounding_box[2] = (int)(PageLength - temp_bbox[1]);
1378	      bounding_box[3] = temp_bbox[2];
1379              break;
1380
1381	  case 2 : /* Reverse Portrait */
1382	      bounding_box[0] = (int)(PageWidth - temp_bbox[2]);
1383	      bounding_box[1] = (int)(PageLength - temp_bbox[3]);
1384	      bounding_box[2] = (int)(PageWidth - temp_bbox[0]);
1385	      bounding_box[3] = (int)(PageLength - temp_bbox[1]);
1386              break;
1387
1388	  case 3 : /* Reverse Landscape */
1389	      bounding_box[0] = temp_bbox[1];
1390	      bounding_box[1] = (int)(PageWidth - temp_bbox[2]);
1391	      bounding_box[2] = temp_bbox[3];
1392	      bounding_box[3] = (int)(PageWidth - temp_bbox[0]);
1393              break;
1394	}
1395
1396        fprintf(stderr, "DEBUG: updated bounding_box = [ %d %d %d %d ]\n",
1397		bounding_box[0], bounding_box[1],
1398		bounding_box[2], bounding_box[3]);
1399      }
1400    }
1401#if 0
1402    else if (!strncmp(line, "%%PageCustomColors:", 19) ||
1403             !strncmp(line, "%%PageMedia:", 12) ||
1404	     !strncmp(line, "%%PageOrientation:", 18) ||
1405	     !strncmp(line, "%%PageProcessColors:", 20) ||
1406	     !strncmp(line, "%%PageRequirements:", 18) ||
1407	     !strncmp(line, "%%PageResources:", 16))
1408    {
1409     /*
1410      * Copy literal...
1411      */
1412    }
1413#endif /* 0 */
1414    else if (!strncmp(line, "%%PageCustomColors:", 19))
1415    {
1416     /*
1417      * %%PageCustomColors: ...
1418      */
1419    }
1420    else if (!strncmp(line, "%%PageMedia:", 12))
1421    {
1422     /*
1423      * %%PageMedia: ...
1424      */
1425    }
1426    else if (!strncmp(line, "%%PageOrientation:", 18))
1427    {
1428     /*
1429      * %%PageOrientation: ...
1430      */
1431    }
1432    else if (!strncmp(line, "%%PageProcessColors:", 20))
1433    {
1434     /*
1435      * %%PageProcessColors: ...
1436      */
1437    }
1438    else if (!strncmp(line, "%%PageRequirements:", 18))
1439    {
1440     /*
1441      * %%PageRequirements: ...
1442      */
1443    }
1444    else if (!strncmp(line, "%%PageResources:", 16))
1445    {
1446     /*
1447      * %%PageResources: ...
1448      */
1449    }
1450    else if (!strncmp(line, "%%IncludeFeature:", 17))
1451    {
1452     /*
1453      * %%IncludeFeature: *MainKeyword OptionKeyword
1454      */
1455
1456      if (doc->number_up == 1 &&!doc->fit_to_page)
1457	pageinfo->num_options = include_feature(ppd, line,
1458	                                        pageinfo->num_options,
1459                                        	&(pageinfo->options));
1460    }
1461    else if (!strncmp(line, "%%BeginPageSetup", 16))
1462    {
1463      has_page_setup = 1;
1464      break;
1465    }
1466    else
1467      break;
1468  }
1469
1470  if (doc->number_up == 1)
1471  {
1472   /*
1473    * Update the document's composite and page bounding box...
1474    */
1475
1476    memcpy(pageinfo->bounding_box, bounding_box,
1477           sizeof(pageinfo->bounding_box));
1478
1479    if (bounding_box[0] < doc->new_bounding_box[0])
1480      doc->new_bounding_box[0] = bounding_box[0];
1481    if (bounding_box[1] < doc->new_bounding_box[1])
1482      doc->new_bounding_box[1] = bounding_box[1];
1483    if (bounding_box[2] > doc->new_bounding_box[2])
1484      doc->new_bounding_box[2] = bounding_box[2];
1485    if (bounding_box[3] > doc->new_bounding_box[3])
1486      doc->new_bounding_box[3] = bounding_box[3];
1487  }
1488
1489 /*
1490  * Output the page header as needed...
1491  */
1492
1493  if (!doc->slow_order && first_page)
1494  {
1495    if (!ppd || !ppd->num_filters)
1496      fprintf(stderr, "PAGE: %d %d\n", doc->page,
1497	      doc->slow_collate ? 1 : doc->copies);
1498
1499    if (doc->number_up > 1)
1500    {
1501      printf("%%%%Page: (%d) %d\n", doc->page, doc->page);
1502      printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
1503	     PageLeft, PageBottom, PageRight, PageTop);
1504    }
1505    else
1506    {
1507      printf("%%%%Page: %s %d\n", pageinfo->label, doc->page);
1508      printf("%%%%PageBoundingBox: %d %d %d %d\n",
1509	     pageinfo->bounding_box[0], pageinfo->bounding_box[1],
1510	     pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
1511    }
1512  }
1513
1514 /*
1515  * Copy any page setup commands...
1516  */
1517
1518  if (first_page)
1519    doc_puts(doc, "%%BeginPageSetup\n");
1520
1521  if (has_page_setup)
1522  {
1523    int	feature = 0;			/* In a Begin/EndFeature block? */
1524
1525    while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
1526    {
1527      if (!strncmp(line, "%%EndPageSetup", 14))
1528	break;
1529      else if (!strncmp(line, "%%BeginFeature:", 15))
1530      {
1531	feature = 1;
1532
1533	if (doc->number_up > 1 || doc->fit_to_page)
1534	  continue;
1535      }
1536      else if (!strncmp(line, "%%EndFeature", 12))
1537      {
1538	feature = 0;
1539
1540	if (doc->number_up > 1 || doc->fit_to_page)
1541	  continue;
1542      }
1543      else if (!strncmp(line, "%%IncludeFeature:", 17))
1544      {
1545	pageinfo->num_options = include_feature(ppd, line,
1546						pageinfo->num_options,
1547						&(pageinfo->options));
1548	continue;
1549      }
1550      else if (!strncmp(line, "%%Include", 9))
1551	continue;
1552
1553      if (line[0] != '%' && !feature)
1554        break;
1555
1556      if (!feature || (doc->number_up == 1 && !doc->fit_to_page))
1557	doc_write(doc, line, (size_t)linelen);
1558    }
1559
1560   /*
1561    * Skip %%EndPageSetup...
1562    */
1563
1564    if (linelen > 0 && !strncmp(line, "%%EndPageSetup", 14))
1565      linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
1566  }
1567
1568  if (first_page)
1569  {
1570    char	*page_setup;		/* PageSetup commands to send */
1571
1572
1573    if (pageinfo->num_options > 0)
1574      write_options(doc, ppd, pageinfo->num_options, pageinfo->options);
1575
1576   /*
1577    * Output commands for the current page...
1578    */
1579
1580    page_setup = ppdEmitString(ppd, PPD_ORDER_PAGE, 0);
1581
1582    if (page_setup)
1583    {
1584      doc_puts(doc, page_setup);
1585      free(page_setup);
1586    }
1587  }
1588
1589 /*
1590  * Prep for the start of the page description...
1591  */
1592
1593  start_nup(doc, number, 1, bounding_box);
1594
1595  if (first_page)
1596    doc_puts(doc, "%%EndPageSetup\n");
1597
1598 /*
1599  * Read the rest of the page description...
1600  */
1601
1602  level = 0;
1603
1604  do
1605  {
1606    if (level == 0 &&
1607        (!strncmp(line, "%%Page:", 7) ||
1608	 !strncmp(line, "%%Trailer", 9) ||
1609	 !strncmp(line, "%%EOF", 5)))
1610      break;
1611    else if (!strncmp(line, "%%BeginDocument", 15) ||
1612	     !strncmp(line, "%ADO_BeginApplication", 21))
1613    {
1614      doc_write(doc, line, (size_t)linelen);
1615
1616      level ++;
1617    }
1618    else if ((!strncmp(line, "%%EndDocument", 13) ||
1619	      !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
1620    {
1621      doc_write(doc, line, (size_t)linelen);
1622
1623      level --;
1624    }
1625    else if (!strncmp(line, "%%BeginBinary:", 14) ||
1626             (!strncmp(line, "%%BeginData:", 12) &&
1627	      !strstr(line, "ASCII") && !strstr(line, "Hex")))
1628    {
1629     /*
1630      * Copy binary data...
1631      */
1632
1633      int	bytes;			/* Bytes of data */
1634
1635
1636      doc_write(doc, line, (size_t)linelen);
1637
1638      bytes = atoi(strchr(line, ':') + 1);
1639
1640      while (bytes > 0)
1641      {
1642	if ((size_t)bytes > linesize)
1643	  linelen = cupsFileRead(fp, line, linesize);
1644	else
1645	  linelen = cupsFileRead(fp, line, (size_t)bytes);
1646
1647	if (linelen < 1)
1648	{
1649	  line[0] = '\0';
1650	  perror("ERROR: Early end-of-file while reading binary data");
1651	  return (0);
1652	}
1653
1654        doc_write(doc, line, (size_t)linelen);
1655
1656	bytes -= linelen;
1657      }
1658    }
1659    else
1660      doc_write(doc, line, (size_t)linelen);
1661  }
1662  while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0);
1663
1664 /*
1665  * Finish up this page and return...
1666  */
1667
1668  end_nup(doc, number);
1669
1670  pageinfo->length = (ssize_t)(cupsFileTell(doc->temp) - pageinfo->offset);
1671
1672  return (linelen);
1673}
1674
1675
1676/*
1677 * 'copy_prolog()' - Copy the document prolog section.
1678 *
1679 * This function expects "line" to be filled with a %%BeginProlog comment line.
1680 * On return, "line" will contain the next line in the file, if any.
1681 */
1682
1683static ssize_t				/* O - Length of next line */
1684copy_prolog(cups_file_t  *fp,		/* I - File to read from */
1685            pstops_doc_t *doc,		/* I - Document info */
1686            ppd_file_t   *ppd,		/* I - PPD file */
1687	    char         *line,		/* I - Line buffer */
1688	    ssize_t      linelen,	/* I - Length of initial line */
1689	    size_t       linesize)	/* I - Size of line buffer */
1690{
1691  while (strncmp(line, "%%BeginProlog", 13))
1692  {
1693    if (!strncmp(line, "%%BeginSetup", 12) || !strncmp(line, "%%Page:", 7))
1694      break;
1695
1696    doc_write(doc, line, (size_t)linelen);
1697
1698    if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
1699      break;
1700  }
1701
1702  doc_puts(doc, "%%BeginProlog\n");
1703
1704  do_prolog(doc, ppd);
1705
1706  if (!strncmp(line, "%%BeginProlog", 13))
1707  {
1708    while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
1709    {
1710      if (!strncmp(line, "%%EndProlog", 11) ||
1711          !strncmp(line, "%%BeginSetup", 12) ||
1712          !strncmp(line, "%%Page:", 7))
1713        break;
1714
1715      doc_write(doc, line, (size_t)linelen);
1716    }
1717
1718    if (!strncmp(line, "%%EndProlog", 11))
1719      linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
1720    else
1721      fputs("DEBUG: The %%EndProlog comment is missing.\n", stderr);
1722  }
1723
1724  doc_puts(doc, "%%EndProlog\n");
1725
1726  return (linelen);
1727}
1728
1729
1730/*
1731 * 'copy_setup()' - Copy the document setup section.
1732 *
1733 * This function expects "line" to be filled with a %%BeginSetup comment line.
1734 * On return, "line" will contain the next line in the file, if any.
1735 */
1736
1737static ssize_t				/* O - Length of next line */
1738copy_setup(cups_file_t  *fp,		/* I - File to read from */
1739           pstops_doc_t *doc,		/* I - Document info */
1740           ppd_file_t   *ppd,		/* I - PPD file */
1741	   char         *line,		/* I - Line buffer */
1742	   ssize_t      linelen,	/* I - Length of initial line */
1743	   size_t       linesize)	/* I - Size of line buffer */
1744{
1745  int		num_options;		/* Number of options */
1746  cups_option_t	*options;		/* Options */
1747
1748
1749  while (strncmp(line, "%%BeginSetup", 12))
1750  {
1751    if (!strncmp(line, "%%Page:", 7))
1752      break;
1753
1754    doc_write(doc, line, (size_t)linelen);
1755
1756    if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
1757      break;
1758  }
1759
1760  doc_puts(doc, "%%BeginSetup\n");
1761
1762  do_setup(doc, ppd);
1763
1764  num_options = 0;
1765  options     = NULL;
1766
1767  if (!strncmp(line, "%%BeginSetup", 12))
1768  {
1769    while (strncmp(line, "%%EndSetup", 10))
1770    {
1771      if (!strncmp(line, "%%Page:", 7))
1772        break;
1773      else if (!strncmp(line, "%%IncludeFeature:", 17))
1774      {
1775       /*
1776	* %%IncludeFeature: *MainKeyword OptionKeyword
1777	*/
1778
1779        if (doc->number_up == 1 && !doc->fit_to_page)
1780	  num_options = include_feature(ppd, line, num_options, &options);
1781      }
1782      else if (strncmp(line, "%%BeginSetup", 12))
1783        doc_write(doc, line, (size_t)linelen);
1784
1785      if ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) == 0)
1786	break;
1787    }
1788
1789    if (!strncmp(line, "%%EndSetup", 10))
1790      linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
1791    else
1792      fputs("DEBUG: The %%EndSetup comment is missing.\n", stderr);
1793  }
1794
1795  if (num_options > 0)
1796  {
1797    write_options(doc, ppd, num_options, options);
1798    cupsFreeOptions(num_options, options);
1799  }
1800
1801  doc_puts(doc, "%%EndSetup\n");
1802
1803  return (linelen);
1804}
1805
1806
1807/*
1808 * 'copy_trailer()' - Copy the document trailer.
1809 *
1810 * This function expects "line" to be filled with a %%Trailer comment line.
1811 * On return, "line" will contain the next line in the file, if any.
1812 */
1813
1814static ssize_t				/* O - Length of next line */
1815copy_trailer(cups_file_t  *fp,		/* I - File to read from */
1816             pstops_doc_t *doc,		/* I - Document info */
1817             ppd_file_t   *ppd,		/* I - PPD file */
1818	     int          number,	/* I - Number of pages */
1819	     char         *line,	/* I - Line buffer */
1820	     ssize_t      linelen,	/* I - Length of initial line */
1821	     size_t       linesize)	/* I - Size of line buffer */
1822{
1823 /*
1824  * Write the trailer comments...
1825  */
1826
1827  (void)ppd;
1828
1829  puts("%%Trailer");
1830
1831  while (linelen > 0)
1832  {
1833    if (!strncmp(line, "%%EOF", 5))
1834      break;
1835    else if (strncmp(line, "%%Trailer", 9) &&
1836             strncmp(line, "%%Pages:", 8) &&
1837             strncmp(line, "%%BoundingBox:", 14))
1838      fwrite(line, 1, (size_t)linelen, stdout);
1839
1840    linelen = (ssize_t)cupsFileGetLine(fp, line, linesize);
1841  }
1842
1843  fprintf(stderr, "DEBUG: Wrote %d pages...\n", number);
1844
1845  printf("%%%%Pages: %d\n", number);
1846  if (doc->number_up > 1 || doc->fit_to_page)
1847    printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
1848	   PageLeft, PageBottom, PageRight, PageTop);
1849  else
1850    printf("%%%%BoundingBox: %d %d %d %d\n",
1851	   doc->new_bounding_box[0], doc->new_bounding_box[1],
1852	   doc->new_bounding_box[2], doc->new_bounding_box[3]);
1853
1854  return (linelen);
1855}
1856
1857
1858/*
1859 * 'do_prolog()' - Send the necessary document prolog commands.
1860 */
1861
1862static void
1863do_prolog(pstops_doc_t *doc,		/* I - Document information */
1864          ppd_file_t   *ppd)		/* I - PPD file */
1865{
1866  char	*ps;				/* PS commands */
1867
1868
1869 /*
1870  * Send the document prolog commands...
1871  */
1872
1873  if (ppd && ppd->patches)
1874  {
1875    doc_puts(doc, "%%BeginFeature: *JobPatchFile 1\n");
1876    doc_puts(doc, ppd->patches);
1877    doc_puts(doc, "\n%%EndFeature\n");
1878  }
1879
1880  if ((ps = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL)
1881  {
1882    doc_puts(doc, ps);
1883    free(ps);
1884  }
1885
1886 /*
1887  * Define ESPshowpage here so that applications that define their
1888  * own procedure to do a showpage pick it up...
1889  */
1890
1891  if (doc->use_ESPshowpage)
1892    doc_puts(doc, "userdict/ESPshowpage/showpage load put\n"
1893	          "userdict/showpage{}put\n");
1894}
1895
1896
1897/*
1898 * 'do_setup()' - Send the necessary document setup commands.
1899 */
1900
1901static void
1902do_setup(pstops_doc_t *doc,		/* I - Document information */
1903         ppd_file_t   *ppd)		/* I - PPD file */
1904{
1905  char	*ps;				/* PS commands */
1906
1907
1908 /*
1909  * Disable CTRL-D so that embedded files don't cause printing
1910  * errors...
1911  */
1912
1913  doc_puts(doc, "% Disable CTRL-D as an end-of-file marker...\n");
1914  doc_puts(doc, "userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
1915
1916 /*
1917  * Mark job options...
1918  */
1919
1920  cupsMarkOptions(ppd, doc->num_options, doc->options);
1921
1922 /*
1923  * Send all the printer-specific setup commands...
1924  */
1925
1926  if ((ps = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL)
1927  {
1928    doc_puts(doc, ps);
1929    free(ps);
1930  }
1931
1932  if ((ps = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL)
1933  {
1934    doc_puts(doc, ps);
1935    free(ps);
1936  }
1937
1938 /*
1939  * Set the number of copies for the job...
1940  */
1941
1942  if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
1943  {
1944    doc_printf(doc, "%%RBIBeginNonPPDFeature: *NumCopies %d\n", doc->copies);
1945    doc_printf(doc,
1946               "%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n"
1947               "{1 dict begin/NumCopies exch def currentdict end "
1948	       "setpagedevice}\n"
1949	       "{userdict/#copies 3 -1 roll put}ifelse\n", doc->copies);
1950    doc_puts(doc, "%RBIEndNonPPDFeature\n");
1951  }
1952
1953 /*
1954  * If we are doing N-up printing, disable setpagedevice...
1955  */
1956
1957  if (doc->number_up > 1)
1958  {
1959    doc_puts(doc, "userdict/CUPSsetpagedevice/setpagedevice load put\n");
1960    doc_puts(doc, "userdict/setpagedevice{pop}bind put\n");
1961  }
1962
1963 /*
1964  * Make sure we have rectclip and rectstroke procedures of some sort...
1965  */
1966
1967  doc_puts(doc,
1968           "% x y w h ESPrc - Clip to a rectangle.\n"
1969	   "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
1970	   "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
1971	   "neg 0 rlineto closepath clip newpath}bind}ifelse put\n");
1972
1973  doc_puts(doc,
1974           "% x y w h ESPrf - Fill a rectangle.\n"
1975	   "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
1976	   "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
1977	   "neg 0 rlineto closepath fill grestore}bind}ifelse put\n");
1978
1979  doc_puts(doc,
1980           "% x y w h ESPrs - Stroke a rectangle.\n"
1981	   "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
1982	   "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
1983	   "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n");
1984
1985 /*
1986  * Write the page and label prologs...
1987  */
1988
1989  if (doc->number_up == 2 || doc->number_up == 6)
1990  {
1991   /*
1992    * For 2- and 6-up output, rotate the labels to match the orientation
1993    * of the pages...
1994    */
1995
1996    if (Orientation & 1)
1997      write_label_prolog(doc, doc->page_label, PageBottom,
1998                         PageWidth - PageLength + PageTop, PageLength);
1999    else
2000      write_label_prolog(doc, doc->page_label, PageLeft, PageRight,
2001                         PageLength);
2002  }
2003  else
2004    write_label_prolog(doc, doc->page_label, PageBottom, PageTop, PageWidth);
2005}
2006
2007
2008/*
2009 * 'doc_printf()' - Send a formatted string to stdout and/or the temp file.
2010 *
2011 * This function should be used for all page-level output that is affected
2012 * by ordering, collation, etc.
2013 */
2014
2015static void
2016doc_printf(pstops_doc_t *doc,		/* I - Document information */
2017           const char   *format,	/* I - Printf-style format string */
2018	   ...)				/* I - Additional arguments as needed */
2019{
2020  va_list	ap;			/* Pointer to arguments */
2021  char		buffer[1024];		/* Output buffer */
2022  ssize_t	bytes;			/* Number of bytes to write */
2023
2024
2025  va_start(ap, format);
2026  bytes = vsnprintf(buffer, sizeof(buffer), format, ap);
2027  va_end(ap);
2028
2029  if ((size_t)bytes > sizeof(buffer))
2030  {
2031    _cupsLangPrintFilter(stderr, "ERROR",
2032                         _("Buffer overflow detected, aborting."));
2033    exit(1);
2034  }
2035
2036  doc_write(doc, buffer, (size_t)bytes);
2037}
2038
2039
2040/*
2041 * 'doc_puts()' - Send a nul-terminated string to stdout and/or the temp file.
2042 *
2043 * This function should be used for all page-level output that is affected
2044 * by ordering, collation, etc.
2045 */
2046
2047static void
2048doc_puts(pstops_doc_t *doc,		/* I - Document information */
2049         const char   *s)		/* I - String to send */
2050{
2051  doc_write(doc, s, strlen(s));
2052}
2053
2054
2055/*
2056 * 'doc_write()' - Send data to stdout and/or the temp file.
2057 */
2058
2059static void
2060doc_write(pstops_doc_t *doc,		/* I - Document information */
2061          const char   *s,		/* I - Data to send */
2062	  size_t       len)		/* I - Number of bytes to send */
2063{
2064  if (!doc->slow_order)
2065    fwrite(s, 1, len, stdout);
2066
2067  if (doc->temp)
2068    cupsFileWrite(doc->temp, s, len);
2069}
2070
2071
2072/*
2073 * 'end_nup()' - End processing for N-up printing.
2074 */
2075
2076static void
2077end_nup(pstops_doc_t *doc,		/* I - Document information */
2078        int          number)		/* I - Page number */
2079{
2080  if (doc->number_up > 1)
2081    doc_puts(doc, "userdict/ESPsave get restore\n");
2082
2083  switch (doc->number_up)
2084  {
2085    case 1 :
2086	if (doc->use_ESPshowpage)
2087	{
2088	  write_labels(doc, Orientation);
2089          doc_puts(doc, "ESPshowpage\n");
2090	}
2091	break;
2092
2093    case 2 :
2094    case 6 :
2095	if (is_last_page(number) && doc->use_ESPshowpage)
2096	{
2097	  if (Orientation & 1)
2098	  {
2099	   /*
2100	    * Rotate the labels back to portrait...
2101	    */
2102
2103	    write_labels(doc, Orientation - 1);
2104	  }
2105	  else if (Orientation == 0)
2106	  {
2107	   /*
2108	    * Rotate the labels to landscape...
2109	    */
2110
2111	    write_labels(doc, doc->normal_landscape ? 1 : 3);
2112	  }
2113	  else
2114	  {
2115	   /*
2116	    * Rotate the labels to landscape...
2117	    */
2118
2119	    write_labels(doc, doc->normal_landscape ? 3 : 1);
2120	  }
2121
2122          doc_puts(doc, "ESPshowpage\n");
2123	}
2124        break;
2125
2126    default :
2127	if (is_last_page(number) && doc->use_ESPshowpage)
2128	{
2129	  write_labels(doc, Orientation);
2130          doc_puts(doc, "ESPshowpage\n");
2131	}
2132        break;
2133  }
2134
2135  fflush(stdout);
2136}
2137
2138
2139/*
2140 * 'include_feature()' - Include a printer option/feature command.
2141 */
2142
2143static int				/* O  - New number of options */
2144include_feature(
2145    ppd_file_t    *ppd,			/* I  - PPD file */
2146    const char    *line,		/* I  - DSC line */
2147    int           num_options,		/* I  - Number of options */
2148    cups_option_t **options)		/* IO - Options */
2149{
2150  char		name[255],		/* Option name */
2151		value[255];		/* Option value */
2152  ppd_option_t	*option;		/* Option in file */
2153
2154
2155 /*
2156  * Get the "%%IncludeFeature: *Keyword OptionKeyword" values...
2157  */
2158
2159  if (sscanf(line + 17, "%254s%254s", name, value) != 2)
2160  {
2161    fputs("DEBUG: The %%IncludeFeature: comment is not valid.\n", stderr);
2162    return (num_options);
2163  }
2164
2165 /*
2166  * Find the option and choice...
2167  */
2168
2169  if ((option = ppdFindOption(ppd, name + 1)) == NULL)
2170  {
2171    _cupsLangPrintFilter(stderr, "WARNING", _("Unknown option \"%s\"."),
2172                         name + 1);
2173    return (num_options);
2174  }
2175
2176  if (option->section == PPD_ORDER_EXIT ||
2177      option->section == PPD_ORDER_JCL)
2178  {
2179    _cupsLangPrintFilter(stderr, "WARNING",
2180                         _("Option \"%s\" cannot be included via "
2181			   "%%%%IncludeFeature."), name + 1);
2182    return (num_options);
2183  }
2184
2185  if (!ppdFindChoice(option, value))
2186  {
2187    _cupsLangPrintFilter(stderr, "WARNING",
2188			 _("Unknown choice \"%s\" for option \"%s\"."),
2189			 value, name + 1);
2190    return (num_options);
2191  }
2192
2193 /*
2194  * Add the option to the option array and return...
2195  */
2196
2197  return (cupsAddOption(name + 1, value, num_options, options));
2198}
2199
2200
2201/*
2202 * 'parse_text()' - Parse a text value in a comment.
2203 *
2204 * This function parses a DSC text value as defined on page 36 of the
2205 * DSC specification.  Text values are either surrounded by parenthesis
2206 * or whitespace-delimited.
2207 *
2208 * The value returned is the literal characters for the entire text
2209 * string, including any parenthesis and escape characters.
2210 */
2211
2212static char *				/* O - Value or NULL on error */
2213parse_text(const char *start,		/* I - Start of text value */
2214           char       **end,		/* O - End of text value */
2215	   char       *buffer,		/* I - Buffer */
2216           size_t     bufsize)		/* I - Size of buffer */
2217{
2218  char	*bufptr,			/* Pointer in buffer */
2219	*bufend;			/* End of buffer */
2220  int	level;				/* Parenthesis level */
2221
2222
2223 /*
2224  * Skip leading whitespace...
2225  */
2226
2227  while (isspace(*start & 255))
2228    start ++;
2229
2230 /*
2231  * Then copy the value...
2232  */
2233
2234  level  = 0;
2235  bufptr = buffer;
2236  bufend = buffer + bufsize - 1;
2237
2238  while (bufptr < bufend)
2239  {
2240    if (isspace(*start & 255) && !level)
2241      break;
2242
2243    *bufptr++ = *start;
2244
2245    if (*start == '(')
2246      level ++;
2247    else if (*start == ')')
2248    {
2249      if (!level)
2250      {
2251        start ++;
2252        break;
2253      }
2254      else
2255        level --;
2256    }
2257    else if (*start == '\\')
2258    {
2259     /*
2260      * Copy escaped character...
2261      */
2262
2263      int	i;			/* Looping var */
2264
2265
2266      for (i = 1;
2267           i <= 3 && isdigit(start[i] & 255) && bufptr < bufend;
2268	   *bufptr++ = start[i], i ++);
2269    }
2270
2271    start ++;
2272  }
2273
2274  *bufptr = '\0';
2275
2276 /*
2277  * Return the value and new pointer into the line...
2278  */
2279
2280  if (end)
2281    *end = (char *)start;
2282
2283  if (bufptr == bufend)
2284    return (NULL);
2285  else
2286    return (buffer);
2287}
2288
2289
2290/*
2291 * 'set_pstops_options()' - Set pstops options.
2292 */
2293
2294static void
2295set_pstops_options(
2296    pstops_doc_t  *doc,			/* I - Document information */
2297    ppd_file_t    *ppd,			/* I - PPD file */
2298    char          *argv[],		/* I - Command-line arguments */
2299    int           num_options,		/* I - Number of options */
2300    cups_option_t *options)		/* I - Options */
2301{
2302  const char	*val;			/* Option value */
2303  int		intval;			/* Integer option value */
2304  ppd_attr_t	*attr;			/* PPD attribute */
2305  ppd_option_t	*option;		/* PPD option */
2306  ppd_choice_t	*choice;		/* PPD choice */
2307  const char	*content_type;		/* Original content type */
2308  int		max_copies;		/* Maximum number of copies supported */
2309
2310
2311 /*
2312  * Initialize document information structure...
2313  */
2314
2315  memset(doc, 0, sizeof(pstops_doc_t));
2316
2317  doc->job_id = atoi(argv[1]);
2318  doc->user   = argv[2];
2319  doc->title  = argv[3];
2320  doc->copies = atoi(argv[4]);
2321
2322  if (ppd && ppd->landscape > 0)
2323    doc->normal_landscape = 1;
2324
2325  doc->bounding_box[0] = (int)PageLeft;
2326  doc->bounding_box[1] = (int)PageBottom;
2327  doc->bounding_box[2] = (int)PageRight;
2328  doc->bounding_box[3] = (int)PageTop;
2329
2330  doc->new_bounding_box[0] = INT_MAX;
2331  doc->new_bounding_box[1] = INT_MAX;
2332  doc->new_bounding_box[2] = INT_MIN;
2333  doc->new_bounding_box[3] = INT_MIN;
2334
2335 /*
2336  * AP_FIRSTPAGE_* and the corresponding non-first-page options.
2337  */
2338
2339  doc->ap_input_slot  = cupsGetOption("AP_FIRSTPAGE_InputSlot", num_options,
2340                                      options);
2341  doc->ap_manual_feed = cupsGetOption("AP_FIRSTPAGE_ManualFeed", num_options,
2342                                      options);
2343  doc->ap_media_color = cupsGetOption("AP_FIRSTPAGE_MediaColor", num_options,
2344                                      options);
2345  doc->ap_media_type  = cupsGetOption("AP_FIRSTPAGE_MediaType", num_options,
2346                                      options);
2347  doc->ap_page_region = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options,
2348                                      options);
2349  doc->ap_page_size   = cupsGetOption("AP_FIRSTPAGE_PageSize", num_options,
2350                                      options);
2351
2352  if ((choice = ppdFindMarkedChoice(ppd, "InputSlot")) != NULL)
2353    doc->input_slot = choice->choice;
2354  if ((choice = ppdFindMarkedChoice(ppd, "ManualFeed")) != NULL)
2355    doc->manual_feed = choice->choice;
2356  if ((choice = ppdFindMarkedChoice(ppd, "MediaColor")) != NULL)
2357    doc->media_color = choice->choice;
2358  if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
2359    doc->media_type = choice->choice;
2360  if ((choice = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL)
2361    doc->page_region = choice->choice;
2362  if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL)
2363    doc->page_size = choice->choice;
2364
2365 /*
2366  * collate, multiple-document-handling
2367  */
2368
2369  if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
2370  {
2371   /*
2372    * This IPP attribute is unnecessarily complicated...
2373    *
2374    *   single-document, separate-documents-collated-copies, and
2375    *   single-document-new-sheet all require collated copies.
2376    *
2377    *   separate-documents-uncollated-copies allows for uncollated copies.
2378    */
2379
2380    doc->collate = _cups_strcasecmp(val, "separate-documents-uncollated-copies") != 0;
2381  }
2382
2383  if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
2384      (!_cups_strcasecmp(val, "true") ||!_cups_strcasecmp(val, "on") ||
2385       !_cups_strcasecmp(val, "yes")))
2386    doc->collate = 1;
2387
2388 /*
2389  * emit-jcl
2390  */
2391
2392  if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
2393      (!_cups_strcasecmp(val, "false") || !_cups_strcasecmp(val, "off") ||
2394       !_cups_strcasecmp(val, "no") || !strcmp(val, "0")))
2395    doc->emit_jcl = 0;
2396  else
2397    doc->emit_jcl = 1;
2398
2399 /*
2400  * fit-to-page/ipp-attribute-fidelity
2401  *
2402  * (Only for original PostScript content)
2403  */
2404
2405  if ((content_type = getenv("CONTENT_TYPE")) == NULL)
2406    content_type = "application/postscript";
2407
2408  if (!_cups_strcasecmp(content_type, "application/postscript"))
2409  {
2410    if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL &&
2411	!_cups_strcasecmp(val, "true"))
2412      doc->fit_to_page = 1;
2413    else if ((val = cupsGetOption("ipp-attribute-fidelity", num_options,
2414                                  options)) != NULL &&
2415	     !_cups_strcasecmp(val, "true"))
2416      doc->fit_to_page = 1;
2417  }
2418
2419 /*
2420  * mirror/MirrorPrint
2421  */
2422
2423  if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
2424  {
2425    val = choice->choice;
2426    choice->marked = 0;
2427  }
2428  else
2429    val = cupsGetOption("mirror", num_options, options);
2430
2431  if (val && (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") ||
2432              !_cups_strcasecmp(val, "yes")))
2433    doc->mirror = 1;
2434
2435 /*
2436  * number-up
2437  */
2438
2439  if ((val = cupsGetOption("number-up", num_options, options)) != NULL)
2440  {
2441    switch (intval = atoi(val))
2442    {
2443      case 1 :
2444      case 2 :
2445      case 4 :
2446      case 6 :
2447      case 9 :
2448      case 16 :
2449          doc->number_up = intval;
2450	  break;
2451      default :
2452          _cupsLangPrintFilter(stderr, "ERROR",
2453	                       _("Unsupported number-up value %d, using "
2454				 "number-up=1."), intval);
2455          doc->number_up = 1;
2456	  break;
2457    }
2458  }
2459  else
2460    doc->number_up = 1;
2461
2462 /*
2463  * number-up-layout
2464  */
2465
2466  if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL)
2467  {
2468    if (!_cups_strcasecmp(val, "lrtb"))
2469      doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
2470    else if (!_cups_strcasecmp(val, "lrbt"))
2471      doc->number_up_layout = PSTOPS_LAYOUT_LRBT;
2472    else if (!_cups_strcasecmp(val, "rltb"))
2473      doc->number_up_layout = PSTOPS_LAYOUT_RLTB;
2474    else if (!_cups_strcasecmp(val, "rlbt"))
2475      doc->number_up_layout = PSTOPS_LAYOUT_RLBT;
2476    else if (!_cups_strcasecmp(val, "tblr"))
2477      doc->number_up_layout = PSTOPS_LAYOUT_TBLR;
2478    else if (!_cups_strcasecmp(val, "tbrl"))
2479      doc->number_up_layout = PSTOPS_LAYOUT_TBRL;
2480    else if (!_cups_strcasecmp(val, "btlr"))
2481      doc->number_up_layout = PSTOPS_LAYOUT_BTLR;
2482    else if (!_cups_strcasecmp(val, "btrl"))
2483      doc->number_up_layout = PSTOPS_LAYOUT_BTRL;
2484    else
2485    {
2486      _cupsLangPrintFilter(stderr, "ERROR",
2487                           _("Unsupported number-up-layout value %s, using "
2488			     "number-up-layout=lrtb."), val);
2489      doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
2490    }
2491  }
2492  else
2493    doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
2494
2495 /*
2496  * OutputOrder
2497  */
2498
2499  if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL)
2500  {
2501    if (!_cups_strcasecmp(val, "Reverse"))
2502      doc->output_order = 1;
2503  }
2504  else if (ppd)
2505  {
2506   /*
2507    * Figure out the right default output order from the PPD file...
2508    */
2509
2510    if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL &&
2511        (attr = ppdFindAttr(ppd, "PageStackOrder", choice->choice)) != NULL &&
2512	attr->value)
2513      doc->output_order = !_cups_strcasecmp(attr->value, "Reverse");
2514    else if ((attr = ppdFindAttr(ppd, "DefaultOutputOrder", NULL)) != NULL &&
2515             attr->value)
2516      doc->output_order = !_cups_strcasecmp(attr->value, "Reverse");
2517  }
2518
2519 /*
2520  * page-border
2521  */
2522
2523  if ((val = cupsGetOption("page-border", num_options, options)) != NULL)
2524  {
2525    if (!_cups_strcasecmp(val, "none"))
2526      doc->page_border = PSTOPS_BORDERNONE;
2527    else if (!_cups_strcasecmp(val, "single"))
2528      doc->page_border = PSTOPS_BORDERSINGLE;
2529    else if (!_cups_strcasecmp(val, "single-thick"))
2530      doc->page_border = PSTOPS_BORDERSINGLE2;
2531    else if (!_cups_strcasecmp(val, "double"))
2532      doc->page_border = PSTOPS_BORDERDOUBLE;
2533    else if (!_cups_strcasecmp(val, "double-thick"))
2534      doc->page_border = PSTOPS_BORDERDOUBLE2;
2535    else
2536    {
2537      _cupsLangPrintFilter(stderr, "ERROR",
2538                           _("Unsupported page-border value %s, using "
2539			     "page-border=none."), val);
2540      doc->page_border = PSTOPS_BORDERNONE;
2541    }
2542  }
2543  else
2544    doc->page_border = PSTOPS_BORDERNONE;
2545
2546 /*
2547  * page-label
2548  */
2549
2550  doc->page_label = cupsGetOption("page-label", num_options, options);
2551
2552 /*
2553  * page-ranges
2554  */
2555
2556  doc->page_ranges = cupsGetOption("page-ranges", num_options, options);
2557
2558 /*
2559  * page-set
2560  */
2561
2562  doc->page_set = cupsGetOption("page-set", num_options, options);
2563
2564 /*
2565  * Now figure out if we have to force collated copies, etc.
2566  */
2567
2568  if ((attr = ppdFindAttr(ppd, "cupsMaxCopies", NULL)) != NULL)
2569    max_copies = atoi(attr->value);
2570  else if (ppd && ppd->manual_copies)
2571    max_copies = 1;
2572  else
2573    max_copies = 9999;
2574
2575  if (doc->copies > max_copies)
2576    doc->collate = 1;
2577  else if (ppd && ppd->manual_copies && Duplex && doc->copies > 1)
2578  {
2579   /*
2580    * Force collated copies when printing a duplexed document to
2581    * a non-PS printer that doesn't do hardware copy generation.
2582    * Otherwise the copies will end up on the front/back side of
2583    * each page.
2584    */
2585
2586    doc->collate = 1;
2587  }
2588
2589 /*
2590  * See if we have to filter the fast or slow way...
2591  */
2592
2593  if (doc->collate && doc->copies > 1)
2594  {
2595   /*
2596    * See if we need to manually collate the pages...
2597    */
2598
2599    doc->slow_collate = 1;
2600
2601    if (doc->copies <= max_copies &&
2602        (choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
2603        !_cups_strcasecmp(choice->choice, "True"))
2604    {
2605     /*
2606      * Hardware collate option is selected, see if the option is
2607      * conflicting - if not, collate in hardware.  Otherwise,
2608      * turn the hardware collate option off...
2609      */
2610
2611      if ((option = ppdFindOption(ppd, "Collate")) != NULL &&
2612          !option->conflicted)
2613	doc->slow_collate = 0;
2614      else
2615        ppdMarkOption(ppd, "Collate", "False");
2616    }
2617  }
2618  else
2619    doc->slow_collate = 0;
2620
2621  if (!ppdFindOption(ppd, "OutputOrder") && doc->output_order)
2622    doc->slow_order = 1;
2623  else
2624    doc->slow_order = 0;
2625
2626  if (Duplex &&
2627       (doc->slow_collate || doc->slow_order ||
2628        ((attr = ppdFindAttr(ppd, "cupsEvenDuplex", NULL)) != NULL &&
2629	 attr->value && !_cups_strcasecmp(attr->value, "true"))))
2630    doc->slow_duplex = 1;
2631  else
2632    doc->slow_duplex = 0;
2633
2634 /*
2635  * Create a temporary file for page data if we need to filter slowly...
2636  */
2637
2638  if (doc->slow_order || doc->slow_collate)
2639  {
2640    if ((doc->temp = cupsTempFile2(doc->tempfile,
2641                                   sizeof(doc->tempfile))) == NULL)
2642    {
2643      perror("DEBUG: Unable to create temporary file");
2644      exit(1);
2645    }
2646  }
2647
2648 /*
2649  * Figure out if we should use ESPshowpage or not...
2650  */
2651
2652  if (doc->page_label || getenv("CLASSIFICATION") || doc->number_up > 1 ||
2653      doc->page_border)
2654  {
2655   /*
2656    * Yes, use ESPshowpage...
2657    */
2658
2659    doc->use_ESPshowpage = 1;
2660  }
2661
2662  fprintf(stderr, "DEBUG: slow_collate=%d, slow_duplex=%d, slow_order=%d\n",
2663          doc->slow_collate, doc->slow_duplex, doc->slow_order);
2664}
2665
2666
2667/*
2668 * 'skip_page()' - Skip past a page that won't be printed.
2669 */
2670
2671static ssize_t				/* O - Length of next line */
2672skip_page(cups_file_t *fp,		/* I - File to read from */
2673          char        *line,		/* I - Line buffer */
2674	  ssize_t     linelen,		/* I - Length of initial line */
2675          size_t      linesize)		/* I - Size of line buffer */
2676{
2677  int	level;				/* Embedded document level */
2678
2679
2680  level = 0;
2681
2682  while ((linelen = (ssize_t)cupsFileGetLine(fp, line, linesize)) > 0)
2683  {
2684    if (level == 0 &&
2685        (!strncmp(line, "%%Page:", 7) || !strncmp(line, "%%Trailer", 9)))
2686      break;
2687    else if (!strncmp(line, "%%BeginDocument", 15) ||
2688	     !strncmp(line, "%ADO_BeginApplication", 21))
2689      level ++;
2690    else if ((!strncmp(line, "%%EndDocument", 13) ||
2691	      !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
2692      level --;
2693    else if (!strncmp(line, "%%BeginBinary:", 14) ||
2694             (!strncmp(line, "%%BeginData:", 12) &&
2695	      !strstr(line, "ASCII") && !strstr(line, "Hex")))
2696    {
2697     /*
2698      * Skip binary data...
2699      */
2700
2701      ssize_t	bytes;			/* Bytes of data */
2702
2703      bytes = atoi(strchr(line, ':') + 1);
2704
2705      while (bytes > 0)
2706      {
2707	if ((size_t)bytes > linesize)
2708	  linelen = (ssize_t)cupsFileRead(fp, line, linesize);
2709	else
2710	  linelen = (ssize_t)cupsFileRead(fp, line, (size_t)bytes);
2711
2712	if (linelen < 1)
2713	{
2714	  line[0] = '\0';
2715	  perror("ERROR: Early end-of-file while reading binary data");
2716	  return (0);
2717	}
2718
2719	bytes -= linelen;
2720      }
2721    }
2722  }
2723
2724  return (linelen);
2725}
2726
2727
2728/*
2729 * 'start_nup()' - Start processing for N-up printing.
2730 */
2731
2732static void
2733start_nup(pstops_doc_t *doc,		/* I - Document information */
2734          int          number,		/* I - Page number */
2735	  int          show_border,	/* I - Show the border? */
2736	  const int    *bounding_box)	/* I - BoundingBox value */
2737{
2738  int		pos;			/* Position on page */
2739  int		x, y;			/* Relative position of subpage */
2740  double	w, l,			/* Width and length of subpage */
2741		tx, ty;			/* Translation values for subpage */
2742  double	pagew,			/* Printable width of page */
2743		pagel;			/* Printable height of page */
2744  int		bboxx,			/* BoundingBox X origin */
2745		bboxy,			/* BoundingBox Y origin */
2746		bboxw,			/* BoundingBox width */
2747		bboxl;			/* BoundingBox height */
2748  double	margin = 0;		/* Current margin for border */
2749
2750
2751  if (doc->number_up > 1)
2752    doc_puts(doc, "userdict/ESPsave save put\n");
2753
2754  pos   = (number - 1) % doc->number_up;
2755  pagew = PageRight - PageLeft;
2756  pagel = PageTop - PageBottom;
2757
2758  if (doc->fit_to_page)
2759  {
2760    bboxx = bounding_box[0];
2761    bboxy = bounding_box[1];
2762    bboxw = bounding_box[2] - bounding_box[0];
2763    bboxl = bounding_box[3] - bounding_box[1];
2764  }
2765  else
2766  {
2767    bboxx = 0;
2768    bboxy = 0;
2769    bboxw = (int)PageWidth;
2770    bboxl = (int)PageLength;
2771  }
2772
2773  fprintf(stderr, "DEBUG: pagew = %.1f, pagel = %.1f\n", pagew, pagel);
2774  fprintf(stderr, "DEBUG: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d\n",
2775          bboxx, bboxy, bboxw, bboxl);
2776  fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n",
2777          PageLeft, PageRight);
2778  fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n",
2779          PageTop, PageBottom);
2780  fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n",
2781          PageWidth, PageLength);
2782
2783  switch (Orientation)
2784  {
2785    case 1 : /* Landscape */
2786        doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", PageLength);
2787        break;
2788    case 2 : /* Reverse Portrait */
2789        doc_printf(doc, "%.1f %.1f translate 180 rotate\n", PageWidth,
2790	           PageLength);
2791        break;
2792    case 3 : /* Reverse Landscape */
2793        doc_printf(doc, "0.0 %.1f translate -90 rotate\n", PageWidth);
2794        break;
2795  }
2796
2797 /*
2798  * Mirror the page as needed...
2799  */
2800
2801  if (doc->mirror)
2802    doc_printf(doc, "%.1f 0.0 translate -1 1 scale\n", PageWidth);
2803
2804 /*
2805  * Offset and scale as necessary for fit_to_page/fit-to-page/number-up...
2806  */
2807
2808  if (Duplex && doc->number_up > 1 && ((number / doc->number_up) & 1))
2809    doc_printf(doc, "%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
2810  else if (doc->number_up > 1 || doc->fit_to_page)
2811    doc_printf(doc, "%.1f %.1f translate\n", PageLeft, PageBottom);
2812
2813  switch (doc->number_up)
2814  {
2815    default :
2816        if (doc->fit_to_page)
2817	{
2818          w = pagew;
2819          l = w * bboxl / bboxw;
2820
2821          if (l > pagel)
2822          {
2823            l = pagel;
2824            w = l * bboxw / bboxl;
2825          }
2826
2827          tx = 0.5 * (pagew - w);
2828          ty = 0.5 * (pagel - l);
2829
2830	  doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", tx, ty,
2831	             w / bboxw, l / bboxl);
2832	}
2833	else
2834          w = PageWidth;
2835	break;
2836
2837    case 2 :
2838        if (Orientation & 1)
2839	{
2840          x = pos & 1;
2841
2842          if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
2843	    x = 1 - x;
2844
2845          w = pagel;
2846          l = w * bboxl / bboxw;
2847
2848          if (l > (pagew * 0.5))
2849          {
2850            l = pagew * 0.5;
2851            w = l * bboxw / bboxl;
2852          }
2853
2854          tx = 0.5 * (pagew * 0.5 - l);
2855          ty = 0.5 * (pagel - w);
2856
2857          if (doc->normal_landscape)
2858            doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
2859	  else
2860	    doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
2861
2862          doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
2863                     ty, tx + pagew * 0.5 * x, w / bboxw, l / bboxl);
2864        }
2865	else
2866	{
2867          x = pos & 1;
2868
2869          if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
2870	    x = 1 - x;
2871
2872          l = pagew;
2873          w = l * bboxw / bboxl;
2874
2875          if (w > (pagel * 0.5))
2876          {
2877            w = pagel * 0.5;
2878            l = w * bboxl / bboxw;
2879          }
2880
2881          tx = 0.5 * (pagel * 0.5 - w);
2882          ty = 0.5 * (pagew - l);
2883
2884          if (doc->normal_landscape)
2885	    doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
2886	  else
2887            doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
2888
2889          doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
2890                     tx + pagel * 0.5 * x, ty, w / bboxw, l / bboxl);
2891        }
2892        break;
2893
2894    case 4 :
2895        if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
2896	{
2897	  x = (pos / 2) & 1;
2898          y = pos & 1;
2899        }
2900	else
2901	{
2902          x = pos & 1;
2903	  y = (pos / 2) & 1;
2904        }
2905
2906        if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
2907	  x = 1 - x;
2908
2909	if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
2910	  y = 1 - y;
2911
2912        w = pagew * 0.5;
2913	l = w * bboxl / bboxw;
2914
2915	if (l > (pagel * 0.5))
2916	{
2917	  l = pagel * 0.5;
2918	  w = l * bboxw / bboxl;
2919	}
2920
2921        tx = 0.5 * (pagew * 0.5 - w);
2922        ty = 0.5 * (pagel * 0.5 - l);
2923
2924	doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
2925	           tx + x * pagew * 0.5, ty + y * pagel * 0.5,
2926	           w / bboxw, l / bboxl);
2927        break;
2928
2929    case 6 :
2930        if (Orientation & 1)
2931	{
2932	  if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
2933	  {
2934	    x = pos / 3;
2935	    y = pos % 3;
2936
2937            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
2938	      x = 1 - x;
2939
2940            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
2941	      y = 2 - y;
2942	  }
2943	  else
2944	  {
2945	    x = pos & 1;
2946	    y = pos / 2;
2947
2948            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
2949	      x = 1 - x;
2950
2951            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
2952	      y = 2 - y;
2953	  }
2954
2955          w = pagel * 0.5;
2956          l = w * bboxl / bboxw;
2957
2958          if (l > (pagew * 0.333))
2959          {
2960            l = pagew * 0.333;
2961            w = l * bboxw / bboxl;
2962          }
2963
2964          tx = 0.5 * (pagel - 2 * w);
2965          ty = 0.5 * (pagew - 3 * l);
2966
2967          if (doc->normal_landscape)
2968            doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
2969	  else
2970	    doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
2971
2972          doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
2973                     tx + x * w, ty + y * l, l / bboxl, w / bboxw);
2974        }
2975	else
2976	{
2977	  if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
2978	  {
2979	    x = pos / 2;
2980	    y = pos & 1;
2981
2982            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
2983	      x = 2 - x;
2984
2985            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
2986	      y = 1 - y;
2987	  }
2988	  else
2989	  {
2990	    x = pos % 3;
2991	    y = pos / 3;
2992
2993            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
2994	      x = 2 - x;
2995
2996            if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
2997	      y = 1 - y;
2998	  }
2999
3000          l = pagew * 0.5;
3001          w = l * bboxw / bboxl;
3002
3003          if (w > (pagel * 0.333))
3004          {
3005            w = pagel * 0.333;
3006            l = w * bboxl / bboxw;
3007          }
3008
3009	  tx = 0.5 * (pagel - 3 * w);
3010	  ty = 0.5 * (pagew - 2 * l);
3011
3012          if (doc->normal_landscape)
3013	    doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
3014	  else
3015            doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
3016
3017          doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
3018                     tx + w * x, ty + l * y, w / bboxw, l / bboxl);
3019
3020        }
3021        break;
3022
3023    case 9 :
3024        if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
3025	{
3026	  x = (pos / 3) % 3;
3027          y = pos % 3;
3028        }
3029	else
3030	{
3031          x = pos % 3;
3032	  y = (pos / 3) % 3;
3033        }
3034
3035        if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
3036	  x = 2 - x;
3037
3038	if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
3039	  y = 2 - y;
3040
3041        w = pagew * 0.333;
3042	l = w * bboxl / bboxw;
3043
3044	if (l > (pagel * 0.333))
3045	{
3046	  l = pagel * 0.333;
3047	  w = l * bboxw / bboxl;
3048	}
3049
3050        tx = 0.5 * (pagew * 0.333 - w);
3051        ty = 0.5 * (pagel * 0.333 - l);
3052
3053	doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
3054	           tx + x * pagew * 0.333, ty + y * pagel * 0.333,
3055	           w / bboxw, l / bboxl);
3056        break;
3057
3058    case 16 :
3059        if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
3060	{
3061	  x = (pos / 4) & 3;
3062          y = pos & 3;
3063        }
3064	else
3065	{
3066          x = pos & 3;
3067	  y = (pos / 4) & 3;
3068        }
3069
3070        if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
3071	  x = 3 - x;
3072
3073	if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
3074	  y = 3 - y;
3075
3076        w = pagew * 0.25;
3077	l = w * bboxl / bboxw;
3078
3079	if (l > (pagel * 0.25))
3080	{
3081	  l = pagel * 0.25;
3082	  w = l * bboxw / bboxl;
3083	}
3084
3085        tx = 0.5 * (pagew * 0.25 - w);
3086        ty = 0.5 * (pagel * 0.25 - l);
3087
3088	doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
3089	           tx + x * pagew * 0.25, ty + y * pagel * 0.25,
3090	           w / bboxw, l / bboxl);
3091        break;
3092  }
3093
3094 /*
3095  * Draw borders as necessary...
3096  */
3097
3098  if (doc->page_border && show_border)
3099  {
3100    int		rects;			/* Number of border rectangles */
3101    double	fscale;			/* Scaling value for points */
3102
3103
3104    rects  = (doc->page_border & PSTOPS_BORDERDOUBLE) ? 2 : 1;
3105    fscale = PageWidth / w;
3106    margin = 2.25 * fscale;
3107
3108   /*
3109    * Set the line width and color...
3110    */
3111
3112    doc_puts(doc, "gsave\n");
3113    doc_printf(doc, "%.3f setlinewidth 0 setgray newpath\n",
3114               (doc->page_border & PSTOPS_BORDERTHICK) ? 0.5 * fscale :
3115	                                                 0.24 * fscale);
3116
3117   /*
3118    * Draw border boxes...
3119    */
3120
3121    for (; rects > 0; rects --, margin += 2 * fscale)
3122      if (doc->number_up > 1)
3123	doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
3124		   margin,
3125		   margin,
3126		   bboxw - 2 * margin,
3127		   bboxl - 2 * margin);
3128      else
3129	doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
3130        	   PageLeft + margin,
3131		   PageBottom + margin,
3132		   PageRight - PageLeft - 2 * margin,
3133		   PageTop - PageBottom - 2 * margin);
3134
3135   /*
3136    * Restore pen settings...
3137    */
3138
3139    doc_puts(doc, "grestore\n");
3140  }
3141
3142  if (doc->fit_to_page)
3143  {
3144   /*
3145    * Offset the page by its bounding box...
3146    */
3147
3148    doc_printf(doc, "%d %d translate\n", -bounding_box[0],
3149               -bounding_box[1]);
3150  }
3151
3152  if (doc->fit_to_page || doc->number_up > 1)
3153  {
3154   /*
3155    * Clip the page to the page's bounding box...
3156    */
3157
3158    doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrc\n",
3159               bboxx + margin, bboxy + margin,
3160               bboxw - 2 * margin, bboxl - 2 * margin);
3161  }
3162}
3163
3164
3165/*
3166 * 'write_label_prolog()' - Write the prolog with the classification
3167 *                          and page label.
3168 */
3169
3170static void
3171write_label_prolog(pstops_doc_t *doc,	/* I - Document info */
3172                   const char   *label,	/* I - Page label */
3173		   float        bottom,	/* I - Bottom position in points */
3174		   float        top,	/* I - Top position in points */
3175		   float        width)	/* I - Width in points */
3176{
3177  const char	*classification;	/* CLASSIFICATION environment variable */
3178  const char	*ptr;			/* Temporary string pointer */
3179
3180
3181 /*
3182  * First get the current classification...
3183  */
3184
3185  if ((classification = getenv("CLASSIFICATION")) == NULL)
3186    classification = "";
3187  if (strcmp(classification, "none") == 0)
3188    classification = "";
3189
3190 /*
3191  * If there is nothing to show, bind an empty 'write labels' procedure
3192  * and return...
3193  */
3194
3195  if (!classification[0] && (label == NULL || !label[0]))
3196  {
3197    doc_puts(doc, "userdict/ESPwl{}bind put\n");
3198    return;
3199  }
3200
3201 /*
3202  * Set the classification + page label string...
3203  */
3204
3205  doc_puts(doc, "userdict");
3206  if (!strcmp(classification, "confidential"))
3207    doc_puts(doc, "/ESPpl(CONFIDENTIAL");
3208  else if (!strcmp(classification, "classified"))
3209    doc_puts(doc, "/ESPpl(CLASSIFIED");
3210  else if (!strcmp(classification, "secret"))
3211    doc_puts(doc, "/ESPpl(SECRET");
3212  else if (!strcmp(classification, "topsecret"))
3213    doc_puts(doc, "/ESPpl(TOP SECRET");
3214  else if (!strcmp(classification, "unclassified"))
3215    doc_puts(doc, "/ESPpl(UNCLASSIFIED");
3216  else
3217  {
3218    doc_puts(doc, "/ESPpl(");
3219
3220    for (ptr = classification; *ptr; ptr ++)
3221    {
3222      if (*ptr < 32 || *ptr > 126)
3223        doc_printf(doc, "\\%03o", *ptr);
3224      else if (*ptr == '_')
3225        doc_puts(doc, " ");
3226      else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
3227	doc_printf(doc, "\\%c", *ptr);
3228      else
3229        doc_printf(doc, "%c", *ptr);
3230    }
3231  }
3232
3233  if (label)
3234  {
3235    if (classification[0])
3236      doc_puts(doc, " - ");
3237
3238   /*
3239    * Quote the label string as needed...
3240    */
3241
3242    for (ptr = label; *ptr; ptr ++)
3243    {
3244      if (*ptr < 32 || *ptr > 126)
3245        doc_printf(doc, "\\%03o", *ptr);
3246      else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
3247	doc_printf(doc, "\\%c", *ptr);
3248      else
3249        doc_printf(doc, "%c", *ptr);
3250    }
3251  }
3252
3253  doc_puts(doc, ")put\n");
3254
3255 /*
3256  * Then get a 14 point Helvetica-Bold font...
3257  */
3258
3259  doc_puts(doc, "userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put\n");
3260
3261 /*
3262  * Finally, the procedure to write the labels on the page...
3263  */
3264
3265  doc_puts(doc, "userdict/ESPwl{\n");
3266  doc_puts(doc, "  ESPpf setfont\n");
3267  doc_printf(doc, "  ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
3268             width * 0.5f);
3269  doc_puts(doc, "  1 setgray\n");
3270  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
3271  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
3272  doc_puts(doc, "  0 setgray\n");
3273  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
3274  doc_printf(doc, "  dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
3275  doc_printf(doc, "  dup %.0f moveto ESPpl show\n", bottom + 2.0);
3276  doc_printf(doc, "  %.0f moveto ESPpl show\n", top - 14.0);
3277  doc_puts(doc, "pop\n");
3278  doc_puts(doc, "}bind put\n");
3279}
3280
3281
3282/*
3283 * 'write_labels()' - Write the actual page labels.
3284 *
3285 * This function is a copy of the one in common.c since we need to
3286 * use doc_puts/doc_printf instead of puts/printf...
3287 */
3288
3289static void
3290write_labels(pstops_doc_t *doc,		/* I - Document information */
3291             int          orient)	/* I - Orientation of the page */
3292{
3293  float	width,				/* Width of page */
3294	length;				/* Length of page */
3295
3296
3297  doc_puts(doc, "gsave\n");
3298
3299  if ((orient ^ Orientation) & 1)
3300  {
3301    width  = PageLength;
3302    length = PageWidth;
3303  }
3304  else
3305  {
3306    width  = PageWidth;
3307    length = PageLength;
3308  }
3309
3310  switch (orient & 3)
3311  {
3312    case 1 : /* Landscape */
3313        doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", length);
3314        break;
3315    case 2 : /* Reverse Portrait */
3316        doc_printf(doc, "%.1f %.1f translate 180 rotate\n", width, length);
3317        break;
3318    case 3 : /* Reverse Landscape */
3319        doc_printf(doc, "0.0 %.1f translate -90 rotate\n", width);
3320        break;
3321  }
3322
3323  doc_puts(doc, "ESPwl\n");
3324  doc_puts(doc, "grestore\n");
3325}
3326
3327
3328/*
3329 * 'write_options()' - Write options provided via %%IncludeFeature.
3330 */
3331
3332static void
3333write_options(
3334    pstops_doc_t  *doc,		/* I - Document */
3335    ppd_file_t    *ppd,		/* I - PPD file */
3336    int           num_options,	/* I - Number of options */
3337    cups_option_t *options)	/* I - Options */
3338{
3339  int		i;		/* Looping var */
3340  ppd_option_t	*option;	/* PPD option */
3341  float		min_order;	/* Minimum OrderDependency value */
3342  char		*doc_setup,	/* DocumentSetup commands to send */
3343		*any_setup;	/* AnySetup commands to send */
3344
3345
3346 /*
3347  * Figure out the minimum OrderDependency value...
3348  */
3349
3350  if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
3351    min_order = option->order;
3352  else
3353    min_order = 999.0f;
3354
3355  for (i = 0; i < num_options; i ++)
3356    if ((option = ppdFindOption(ppd, options[i].name)) != NULL &&
3357	option->order < min_order)
3358      min_order = option->order;
3359
3360 /*
3361  * Mark and extract them...
3362  */
3363
3364  cupsMarkOptions(ppd, num_options, options);
3365
3366  doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
3367  any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
3368
3369 /*
3370  * Then send them out...
3371  */
3372
3373  if (doc->number_up > 1)
3374  {
3375   /*
3376    * Temporarily restore setpagedevice so we can set the options...
3377    */
3378
3379    doc_puts(doc, "userdict/setpagedevice/CUPSsetpagedevice load put\n");
3380  }
3381
3382  if (doc_setup)
3383  {
3384    doc_puts(doc, doc_setup);
3385    free(doc_setup);
3386  }
3387
3388  if (any_setup)
3389  {
3390    doc_puts(doc, any_setup);
3391    free(any_setup);
3392  }
3393
3394  if (doc->number_up > 1)
3395  {
3396   /*
3397    * Disable setpagedevice again...
3398    */
3399
3400    doc_puts(doc, "userdict/setpagedevice{pop}bind put\n");
3401  }
3402}
3403