#include "common.h"
#define MAX_PAGES 10000
#define BORDER_NONE 0
#define BORDER_THICK 1
#define BORDER_SINGLE 2
#define BORDER_SINGLE2 3
#define BORDER_DOUBLE 4
#define BORDER_DOUBLE2 5
#define LAYOUT_LRBT 0
#define LAYOUT_LRTB 1
#define LAYOUT_RLBT 2
#define LAYOUT_RLTB 3
#define LAYOUT_BTLR 4
#define LAYOUT_TBLR 5
#define LAYOUT_BTRL 6
#define LAYOUT_TBRL 7
#define LAYOUT_NEGATEY 1
#define LAYOUT_NEGATEX 2
#define LAYOUT_VERTICAL 4
#if defined(__APPLE__)
#define setFirstPageOptionsAndEmit(ppd, specialSlotSel, minOutputOrder) \
setPageOptionsAndEmit((ppd), (minOutputOrder), (specialSlotSel).firstPgInputSlot, \
(specialSlotSel).firstPgManualFeed, (specialSlotSel).otherPgManualFeed)
#define setOtherPageOptionsAndEmit(ppd, specialSlotSel, minOutputOrder) \
setPageOptionsAndEmit((ppd), (minOutputOrder), (specialSlotSel).otherPgInputSlot, \
(specialSlotSel).otherPgManualFeed, (specialSlotSel).firstPgManualFeed)
typedef struct SpecialSlotSel{
char *firstPgInputSlot,
*firstPgManualFeed,
*otherPgInputSlot,
*otherPgManualFeed;
}SpecialSlotSel;
#endif
#define PROT_STANDARD 0
#define PROT_BCP 1
#define PROT_TBCP 2
const char *TBCP_END_PROTOCOL_STRING="\033%-12345X";
int NumPages = 0;
long Pages[MAX_PAGES];
const char *PageRanges = NULL;
const char *PageSet = NULL;
int Order = 0,
Flip = 0,
NUp = 1,
Collate = 0,
Copies = 1,
UseESPsp = 0,
Border = BORDER_NONE,
Layout = LAYOUT_LRTB,
NormalLandscape = 0,
Protocol = PROT_STANDARD;
static int check_range(int page);
static void copy_bytes(FILE *fp, size_t length);
static void do_prolog(ppd_file_t *ppd);
static void do_setup(ppd_file_t *ppd, int copies, int collate,
int slowcollate, float g, float b);
static void end_nup(int number);
#define is_first_page(p) (NUp == 1 || (((p)+1) % NUp) == 1)
#define is_last_page(p) (NUp > 1 && (((p)+1) % NUp) == 0)
#define is_not_last_page(p) (NUp > 1 && ((p) % NUp) != 0)
static void psbcp(ppd_file_t *ppd);
static char *psgets(char *buf, size_t *bytes, FILE *fp);
static size_t pswrite(const char *buf, size_t bytes, FILE *fp);
static void start_nup(int number, int show_border);
static void setPageOptionsAndEmit(ppd_file_t *ppd, float minOrder, const char *inputSlotToSet,
const char *manualFeedToSet,
const char *manualFeedToUnset);
int
main(int argc,
char *argv[])
{
FILE *fp;
ppd_file_t *ppd;
ppd_attr_t *attr;
int num_options;
cups_option_t *options;
const char *val;
char tempfile[255];
FILE *temp;
int tempfd;
int number;
int slowcollate;
int sloworder;
int slowduplex;
char line[8192];
size_t len;
float g;
float b;
int level;
int nbytes,
tbytes;
int page;
int real_page;
int page_count;
int basepage;
int subpage;
int copy;
int saweof;
int sent_espsp,
sent_prolog,
sent_setup;
int emit_jcl = 1;
int disallow_binary_quoting = 0;
SpecialSlotSel specialSlotSelection;
char firstPgOption[255];
char otherPgOption[255];
float minOutputOrder = 999999;
setbuf(stderr, NULL);
if (argc < 6 || argc > 7)
{
fputs("ERROR: pstops job-id user title copies options [file]\n", stderr);
return (1);
}
if (argc == 6)
fp = stdin;
else
{
if ((fp = fopen(argv[6], "rb")) == NULL)
{
fprintf(stderr, "ERROR: unable to open print file \"%s\" - %s\n",
argv[6], strerror(errno));
return (1);
}
}
g = 1.0;
b = 1.0;
Copies = atoi(argv[4]);
options = NULL;
num_options = cupsParseOptions(argv[5], 0, &options);
ppd = SetCommonOptions(num_options, options, 1);
if (ppd && ppd->landscape > 0)
NormalLandscape = 1;
if ((val = cupsGetOption("page-ranges", num_options, options)) != NULL)
PageRanges = val;
if ((val = cupsGetOption("page-set", num_options, options)) != NULL)
PageSet = val;
if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
{
Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
}
if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
!strcasecmp(val, "True"))
Collate = 1;
if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL){
if(!strcasecmp(val, "Reverse"))
Order = 1;
}else{
if(ppd){
int foundOrder = 0;
ppd_choice_t *choice = ppdFindMarkedChoice(ppd, "OutputBin");
if(choice != NULL){
ppd_attr_t *attr = ppdFindAttr(ppd, "PageStackOrder", choice->choice);
if(attr != NULL && attr->value != NULL){
foundOrder = 1;
if(strcasecmp(attr->value, "Reverse") == 0)
Order = 1;
}
}
if(!foundOrder){
ppd_attr_t *attr = ppdFindAttr(ppd, "DefaultOutputOrder", NULL);
if(attr != NULL && attr->value != NULL){
if(strcasecmp(attr->value, "Reverse") == 0)
Order = 1;
}
}
}
}
if ((val = cupsGetOption("number-up", num_options, options)) != NULL)
NUp = atoi(val);
if ((val = cupsGetOption("page-border", num_options, options)) != NULL)
{
if (!strcasecmp(val, "none"))
Border = BORDER_NONE;
else if (!strcasecmp(val, "single"))
Border = BORDER_SINGLE;
else if (!strcasecmp(val, "single-thick"))
Border = BORDER_SINGLE2;
else if (!strcasecmp(val, "double"))
Border = BORDER_DOUBLE;
else if (!strcasecmp(val, "double-thick"))
Border = BORDER_DOUBLE2;
}
if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL)
{
if (!strcasecmp(val, "lrtb"))
Layout = LAYOUT_LRTB;
else if (!strcasecmp(val, "lrbt"))
Layout = LAYOUT_LRBT;
else if (!strcasecmp(val, "rltb"))
Layout = LAYOUT_RLTB;
else if (!strcasecmp(val, "rlbt"))
Layout = LAYOUT_RLBT;
else if (!strcasecmp(val, "tblr"))
Layout = LAYOUT_TBLR;
else if (!strcasecmp(val, "tbrl"))
Layout = LAYOUT_TBRL;
else if (!strcasecmp(val, "btlr"))
Layout = LAYOUT_BTLR;
else if (!strcasecmp(val, "btrl"))
Layout = LAYOUT_BTRL;
}
if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
g = atoi(val) * 0.001f;
if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
b = atoi(val) * 0.01f;
if ((val = cupsGetOption("mirror", num_options, options)) != NULL &&
!strcasecmp(val, "True"))
Flip = 1;
if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL)
emit_jcl = atoi(val);
if ((val = cupsGetOption("disallow-binary-quoting", num_options, options)) != NULL)
disallow_binary_quoting = atoi(val);
specialSlotSelection.firstPgInputSlot = specialSlotSelection.firstPgManualFeed =
specialSlotSelection.otherPgInputSlot = specialSlotSelection.otherPgManualFeed = NULL;
if ((val = cupsGetOption("AP_FIRSTPAGE_InputSlot", num_options, options)) != NULL){
strlcpy(firstPgOption, val, sizeof(firstPgOption));
specialSlotSelection.firstPgInputSlot = firstPgOption;
}else{
if ((val = cupsGetOption("AP_FIRSTPAGE_ManualFeed", num_options, options)) != NULL){
strlcpy(firstPgOption, val, sizeof(firstPgOption));
specialSlotSelection.firstPgManualFeed = firstPgOption;
}
}
if(specialSlotSelection.firstPgInputSlot || specialSlotSelection.firstPgManualFeed){
if ((val = cupsGetOption("InputSlot", num_options, options)) != NULL){
strlcpy(otherPgOption, val, sizeof(otherPgOption));
specialSlotSelection.otherPgInputSlot = otherPgOption;
}else{
if ((val = cupsGetOption("ManualFeed", num_options, options)) != NULL){
strlcpy(otherPgOption, val, sizeof(otherPgOption));
specialSlotSelection.otherPgManualFeed = otherPgOption;
}
}
if(!specialSlotSelection.otherPgInputSlot && !specialSlotSelection.otherPgManualFeed){
specialSlotSelection.firstPgInputSlot = NULL;
specialSlotSelection.firstPgManualFeed = NULL;
}
if( (specialSlotSelection.otherPgInputSlot && specialSlotSelection.firstPgInputSlot &&
strcasecmp(specialSlotSelection.otherPgInputSlot, specialSlotSelection.firstPgInputSlot) == 0)
|| (specialSlotSelection.otherPgManualFeed && specialSlotSelection.firstPgManualFeed &&
strcasecmp(specialSlotSelection.otherPgManualFeed, specialSlotSelection.firstPgManualFeed) == 0)
){
specialSlotSelection.firstPgInputSlot = specialSlotSelection.firstPgManualFeed =
specialSlotSelection.otherPgInputSlot = specialSlotSelection.otherPgManualFeed = NULL;
}
if(ppd){
int i;
const char * const FeatureList[] = {
"PageRegion",
"InputSlot",
"ManualFeed"};
ppd_option_t *theOption;
for(i=0; i < sizeof(FeatureList)/sizeof(char *) ; i++){
theOption = ppdFindOption(ppd, FeatureList[i]);
if(theOption && minOutputOrder > theOption->order)
minOutputOrder = theOption->order;
}
}
}
if (ppd && ppd->manual_copies && Duplex && Copies > 1)
{
Collate = 1;
slowduplex = 1;
}
else
slowduplex = 0;
if(Collate && Copies > 1)
{
slowcollate = 1;
ppd_choice_t *choice = ppdFindMarkedChoice(ppd, "Collate");
if(choice != NULL){
if(strcasecmp(choice->choice, "True") == 0){
int conflicts = ppdMarkOption(ppd, "Collate", "True");
if(conflicts == 0)
slowcollate = 0;
else
ppdMarkOption(ppd, "Collate", "False");
}
}
}else
slowcollate = 0;
if (ppdFindOption(ppd, "OutputOrder") == NULL && Order)
sloworder = 1;
else
sloworder = 0;
if (sloworder || slowcollate)
{
tempfd = cupsTempFd(tempfile, sizeof(tempfile));
if (tempfd < 0)
{
perror("ERROR: Unable to open temp file");
temp = NULL;
}
else
temp = fdopen(tempfd, "wb+");
if (temp == NULL)
slowcollate = sloworder = 0;
}
else
temp = NULL;
if (!disallow_binary_quoting && (attr = ppdFindAttr(ppd, "cupsProtocol", NULL)) != NULL &&
attr->value != NULL)
{
if (!strcasecmp(attr->value, "TBCP"))
Protocol = PROT_TBCP;
else if (!strcasecmp(attr->value, "BCP"))
{
Protocol = PROT_BCP;
psbcp(ppd);
}
}
ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
if(emit_jcl)
ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
len = sizeof(line);
if (psgets(line, &len, fp) == NULL)
{
fputs("ERROR: Empty print file!\n", stderr);
ppdClose(ppd);
return (1);
}
fwrite(line, 1, len, stdout);
while (!strncmp(line, "\033%-12345X", 9))
{
fputs("DEBUG: Skipping PJL header...\n", stderr);
while (strstr(line, "ENTER LANGUAGE") == NULL)
{
len = sizeof(line);
if (psgets(line, &len, fp) == NULL)
break;
fwrite(line, 1, len, stdout);
}
len = sizeof(line);
if (psgets(line, &len, fp) == NULL)
break;
}
if (Protocol == PROT_TBCP)
fputs("\001M", stdout);
saweof = 0;
sent_espsp = 0;
sent_prolog = 0;
sent_setup = 0;
if (Copies != 1 && (!Collate || !slowcollate))
{
printf("%%%%Requirements: numcopies(%d)%s%s\n", Copies,
Collate ? " collate" : "",
Duplex ? " duplex" : "");
printf("%%RBINumCopies: %d\n", Copies);
}
else
{
if (Duplex)
puts("%%Requirements: duplex\n");
puts("%RBINumCopies: 1");
}
val = cupsGetOption("page-label", num_options, options);
if (val != NULL || getenv("CLASSIFICATION") != NULL || NUp > 1 ||
Border || strstr(line, "EPS") != NULL)
{
UseESPsp = 1;
}
fprintf(stderr, "DEBUG: slowcollate=%d, slowduplex=%d, sloworder=%d\n",
slowcollate, slowduplex, sloworder);
if (!strncmp(line, "%!PS-Adobe-", 11) && !strstr(line, "EPSF"))
{
puts("%%Pages: (atend)");
level = 0;
while (!feof(fp))
{
len = sizeof(line);
if (psgets(line, &len, fp) == NULL)
break;
if (!strncmp(line, "%%", 2))
fprintf(stderr, "DEBUG: %d %s", level, line);
else if (line[0] != '%' && line[0] && !sent_espsp && UseESPsp)
{
sent_espsp = 1;
puts("userdict/ESPshowpage/showpage load put\n"
"userdict/showpage{}put");
}
if (!strncmp(line, "%%BeginDocument:", 16) ||
!strncmp(line, "%%BeginDocument ", 16))
{
fputs(line, stdout);
level ++;
}
else if (!strncmp(line, "%%EndDocument", 13) && level > 0)
{
fputs(line, stdout);
level --;
}
else if (!strncmp(line, "%cupsRotation:", 14) && level == 0)
{
int orient = (atoi(line + 14) / 90) & 3;
if (orient != Orientation)
{
Orientation = (4 - Orientation + orient) & 3;
UpdatePageVars();
Orientation = orient;
}
}
else if (!strncmp(line, "%%BeginProlog", 13) && level == 0)
{
fputs(line, stdout);
if (!sent_prolog)
{
sent_prolog = 1;
do_prolog(ppd);
}
}
else if (!strncmp(line, "%%BeginSetup", 12) && level == 0)
{
fputs(line, stdout);
if (!sent_setup)
{
sent_setup = 1;
do_setup(ppd, Copies, Collate, slowcollate, g, b);
}
}
else if (!strncmp(line, "%%Page:", 7) && level == 0)
break;
else if (!strncmp(line, "%%BeginBinary:", 14) ||
(!strncmp(line, "%%BeginData:", 12) &&
!strstr(line, "ASCII") && !strstr(line, "Hex")))
{
tbytes = atoi(strchr(line, ':') + 1);
fputs(line, stdout);
while (tbytes > 0)
{
if (tbytes > sizeof(line))
nbytes = fread(line, 1, sizeof(line), fp);
else
nbytes = fread(line, 1, tbytes, fp);
if (nbytes < 1)
{
perror("ERROR: Early end-of-file while reading binary data");
return (1);
}
pswrite(line, nbytes, stdout);
tbytes -= nbytes;
}
}
else if (strncmp(line, "%%Pages:", 8) != 0)
pswrite(line, len, stdout);
}
if (!sent_prolog)
{
puts("%%BeginProlog");
sent_prolog = 1;
do_prolog(ppd);
puts("%%EndProlog");
}
if (!sent_setup)
{
puts("%%BeginSetup");
sent_setup = 1;
do_setup(ppd, Copies, Collate, slowcollate, g, b);
puts("%%EndSetup");
}
if (!sent_espsp && UseESPsp)
{
sent_espsp = 1;
puts("userdict/ESPshowpage/showpage load put\n"
"userdict/showpage{}put");
}
if (NUp == 2 || NUp == 6)
{
if (Orientation & 1)
WriteLabelProlog(val, PageBottom, PageWidth - PageLength + PageTop,
PageLength);
else
WriteLabelProlog(val, PageLeft, PageRight, PageLength);
}
else
WriteLabelProlog(val, PageBottom, PageTop, PageWidth);
for (page = 1, real_page = 1;;)
{
if (!strncmp(line, "%%", 2))
fprintf(stderr, "DEBUG: %d %s", level, line);
if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
strncmp(line, "%%BeginDocument ", 16) == 0){
level ++;
if (!sloworder)
fputs(line, stdout);
if (slowcollate || sloworder)
fputs(line, temp);
}else if (strncmp(line, "%%EndDocument", 13) == 0 && level > 0){
level --;
if (!sloworder)
fputs(line, stdout);
if (slowcollate || sloworder)
fputs(line, temp);
}else if (strcmp(line, "\004") == 0 && len == 1)
break;
else if (!strncmp(line, "%%EOF", 5) && level == 0)
{
fputs("DEBUG: Saw EOF!\n", stderr);
saweof = 1;
break;
}
else if (!strncmp(line, "%%Page:", 7) && level == 0)
{
if (!check_range(real_page))
{
while (!feof(fp))
{
len = sizeof(line);
if (psgets(line, &len, fp) == NULL)
break;
if (!strncmp(line, "%%", 2))
fprintf(stderr, "DEBUG: %d %s", level, line);
if (!strncmp(line, "%%BeginDocument:", 16) ||
!strncmp(line, "%%BeginDocument ", 16))
level ++;
else if (!strncmp(line, "%%EndDocument", 13) && level > 0)
level --;
else if (!strncmp(line, "%%Page:", 7) && level == 0)
{
real_page ++;
break;
}
else if (!strncmp(line, "%%BeginBinary:", 14) ||
(!strncmp(line, "%%BeginData:", 12) &&
!strstr(line, "ASCII") && !strstr(line, "Hex")))
{
tbytes = atoi(strchr(line, ':') + 1);
while (tbytes > 0)
{
if (tbytes > sizeof(line))
nbytes = fread(line, 1, sizeof(line), fp);
else
nbytes = fread(line, 1, tbytes, fp);
if (nbytes < 1)
{
perror("ERROR: Early end-of-file while reading binary data");
return (1);
}
tbytes -= nbytes;
}
}
}
continue;
}
if (!sloworder && NumPages > 0)
end_nup(NumPages - 1);
if (slowcollate || sloworder)
Pages[NumPages] = ftell(temp);
if (!sloworder)
{
if (is_first_page(NumPages))
{
if (ppd == NULL || ppd->num_filters == 0)
fprintf(stderr, "PAGE: %d %d\n", page, slowcollate ? 1 : Copies);
if(page == 2){
setOtherPageOptionsAndEmit(ppd, specialSlotSelection, minOutputOrder);
}
printf("%%%%Page: %d %d\n", page, page);
if(page == 1){
setFirstPageOptionsAndEmit(ppd, specialSlotSelection, minOutputOrder);
}
page ++;
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
}
start_nup(NumPages, 1);
}
NumPages ++;
real_page ++;
}
else if (!strncmp(line, "%%BeginBinary:", 14) ||
(!strncmp(line, "%%BeginData:", 12) &&
!strstr(line, "ASCII") && !strstr(line, "Hex")))
{
tbytes = atoi(strchr(line, ':') + 1);
if (!sloworder)
fputs(line, stdout);
if (slowcollate || sloworder)
fputs(line, temp);
while (tbytes > 0)
{
if (tbytes > sizeof(line))
nbytes = fread(line, 1, sizeof(line), fp);
else
nbytes = fread(line, 1, tbytes, fp);
if (nbytes < 1)
{
perror("ERROR: Early end-of-file while reading binary data");
return (1);
}
if (!sloworder)
pswrite(line, nbytes, stdout);
if (slowcollate || sloworder)
fwrite(line, 1, nbytes, temp);
tbytes -= nbytes;
}
}
else if (!strncmp(line, "%%Trailer", 9) && level == 0)
{
fputs("DEBUG: Saw Trailer!\n", stderr);
break;
}
else
{
if (!sloworder)
pswrite(line, len, stdout);
if (slowcollate || sloworder)
fwrite(line, 1, len, temp);
}
len = sizeof(line);
if (psgets(line, &len, fp) == NULL)
break;
}
if (!sloworder)
{
end_nup(NumPages - 1);
if (is_not_last_page(NumPages))
{
start_nup(NUp - 1, 0);
end_nup(NUp - 1);
}
if (Duplex && !(page & 1))
{
if (ppd == NULL || ppd->num_filters == 0)
fprintf(stderr, "PAGE: %d %d\n", page, slowcollate ? 1 : Copies);
printf("%%%%Page: %d %d\n", page, page);
page ++;
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
start_nup(NUp - 1, 0);
puts("showpage");
end_nup(NUp - 1);
}
}
if (slowcollate || sloworder)
{
Pages[NumPages] = ftell(temp);
if (!sloworder)
{
while (Copies > 1)
{
rewind(temp);
for (number = 0; number < NumPages; number ++)
{
if (is_first_page(number))
{
if (ppd == NULL || ppd->num_filters == 0)
fprintf(stderr, "PAGE: %d 1\n", page);
if(number == 1){
setOtherPageOptionsAndEmit(ppd, specialSlotSelection, minOutputOrder);
}
printf("%%%%Page: %d %d\n", page, page);
if(number == 0){
setFirstPageOptionsAndEmit(ppd, specialSlotSelection, minOutputOrder);
}
page ++;
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
}
start_nup(number, 1);
copy_bytes(temp, Pages[number + 1] - Pages[number]);
end_nup(number);
}
if (is_not_last_page(NumPages))
{
start_nup(NUp - 1, 0);
end_nup(NUp - 1);
}
if (slowduplex && !(page & 1))
{
if (ppd == NULL || ppd->num_filters == 0)
fprintf(stderr, "PAGE: %d 1\n", page);
printf("%%%%Page: %d %d\n", page, page);
page ++;
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
start_nup(NUp - 1, 0);
puts("showpage");
end_nup(NUp - 1);
}
Copies --;
}
}
else
{
page_count = (NumPages + NUp - 1) / NUp;
copy = 0;
fprintf(stderr, "DEBUG: page_count=%d\n", page_count);
do
{
if (Duplex && (page_count & 1))
basepage = page_count;
else
basepage = page_count - 1;
for (; basepage >= 0; basepage --)
{
if (ppd == NULL || ppd->num_filters == 0)
fprintf(stderr, "PAGE: %d %d\n", page,
slowcollate ? 1 : Copies);
printf("%%%%Page: %d %d\n", page, page);
page ++;
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
if (basepage >= page_count)
{
start_nup(NUp - 1, 0);
puts("showpage");
end_nup(NUp - 1);
}
else
{
for (subpage = 0, number = basepage * NUp;
subpage < NUp && number < NumPages;
subpage ++, number ++)
{
start_nup(number, 1);
fseek(temp, Pages[number], SEEK_SET);
copy_bytes(temp, Pages[number + 1] - Pages[number]);
end_nup(number);
}
if (is_not_last_page(number))
{
start_nup(NUp - 1, 0);
end_nup(NUp - 1);
}
}
}
copy ++;
}
while (copy < Copies && slowcollate);
}
}
puts("%%Trailer");
printf("%%%%Pages: %d\n", page - 1);
if (UseESPsp)
puts("userdict/showpage/ESPshowpage load put\n");
while (!feof(fp))
{
len = sizeof(line);
if (psgets(line, &len, fp) == NULL)
break;
if ( !((strcmp(line, "\004") == 0) && len == 1) &&
strncmp(line, "%%Pages:", 8) != 0)
pswrite(line, len, stdout);
if (!strncmp(line, "%%EOF", 5))
{
fputs("DEBUG: Saw EOF!\n", stderr);
saweof = 1;
break;
}
}
}
else
{
if (slowcollate && Copies > 1)
printf("%%%%Pages: %d\n", Copies);
else
puts("%%Pages: 1");
if (UseESPsp)
puts("userdict/ESPshowpage/showpage load put\n"
"userdict/showpage{}put");
puts("%%BeginProlog");
WriteLabelProlog(val, PageBottom, PageTop, PageWidth);
do_prolog(ppd);
puts("%%EndProlog");
puts("%%BeginSetup");
do_setup(ppd, Copies, Collate, slowcollate, g, b);
puts("%%EndSetup");
if (ppd == NULL || ppd->num_filters == 0)
fprintf(stderr, "PAGE: 1 %d\n", slowcollate ? 1 : Copies);
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
saweof = 1;
while ((nbytes = fread(line, 1, sizeof(line), fp)) > 0)
{
pswrite(line, nbytes, stdout);
if (slowcollate)
fwrite(line, 1, nbytes, temp);
}
if (UseESPsp)
{
WriteLabels(Orientation);
puts("ESPshowpage");
}
if (slowcollate)
{
while (Copies > 1)
{
if (ppd == NULL || ppd->num_filters == 0)
fputs("PAGE: 1 1\n", stderr);
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
rewind(temp);
copy_bytes(temp, 0);
Copies --;
if (UseESPsp)
{
WriteLabels(Orientation);
puts("ESPshowpage");
}
}
}
}
if (!saweof)
puts("%%EOF");
if (ppd != NULL)
{
if (emit_jcl && ppd->jcl_end)
fputs(ppd->jcl_end, stdout);
else {
if (ppd->num_filters == 0)
putchar(0x04);
if(Protocol == PROT_TBCP)
fputs(TBCP_END_PROTOCOL_STRING, stdout);
}
}
if (slowcollate || sloworder)
{
fclose(temp);
unlink(tempfile);
}
ppdClose(ppd);
if (fp != stdin)
fclose(fp);
return (0);
}
static int
check_range(int page)
{
const char *range;
int lower, upper;
if (PageSet != NULL)
{
if (!strcasecmp(PageSet, "even") && ((page - 1) % (NUp << 1)) < NUp)
return (0);
if (!strcasecmp(PageSet, "odd") && ((page - 1) % (NUp << 1)) >= NUp)
return (0);
}
if (PageRanges == NULL)
return (1);
for (range = PageRanges; *range != '\0';)
{
if (*range == '-')
{
lower = 1;
range ++;
upper = strtol(range, (char **)&range, 10);
}
else
{
lower = strtol(range, (char **)&range, 10);
if (*range == '-')
{
range ++;
if (!isdigit(*range))
upper = 65535;
else
upper = strtol(range, (char **)&range, 10);
}
else
upper = lower;
}
if (page >= lower && page <= upper)
return (1);
if (*range == ',')
range ++;
else
break;
}
return (0);
}
static void
copy_bytes(FILE *fp,
size_t length)
{
char buffer[8192];
size_t nbytes,
nleft;
nleft = length;
while (nleft > 0 || length == 0)
{
if (nleft > sizeof(buffer) || length == 0)
nbytes = sizeof(buffer);
else
nbytes = nleft;
if ((nbytes = fread(buffer, 1, nbytes, fp)) < 1)
return;
nleft -= nbytes;
pswrite(buffer, nbytes, stdout);
}
}
static void
do_prolog(ppd_file_t *ppd)
{
if (ppd != NULL && ppd->patches != NULL)
{
puts("%%BeginFeature: *JobPatchFile 1");
puts(ppd->patches);
puts("%%EndFeature");
}
ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
}
static void
do_setup(ppd_file_t *ppd,
int copies,
int collate,
int slowcollate,
float g,
float b)
{
puts("userdict(\\004)cvn{}put");
ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
ppdEmit(ppd, stdout, PPD_ORDER_ANY);
if (copies != 1 && (!collate || !slowcollate))
{
printf("%%RBIBeginNonPPDFeature: *NumCopies %d\n", copies);
printf("%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse{1 dict begin"
"/NumCopies exch def currentdict end "
"setpagedevice}{userdict/#copies 3 -1 roll put}ifelse\n", copies);
printf("%%RBIEndNonPPDFeature\n");
}
if (g != 1.0 || b != 1.0)
printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
"ifelse %.3f mul } bind settransfer\n", g, b);
WriteCommon();
}
static void
end_nup(int number)
{
puts("");
if (Flip || Orientation || NUp > 1)
puts("userdict /ESPsave get restore");
switch (NUp)
{
case 1 :
if (UseESPsp)
{
WriteLabels(Orientation);
puts("ESPshowpage");
}
break;
case 2 :
case 6 :
if (is_last_page(number) && UseESPsp)
{
if (Orientation & 1)
{
WriteLabels(Orientation - 1);
}
else if (Orientation == 0)
{
WriteLabels(NormalLandscape ? 1 : 3);
}
else
{
WriteLabels(NormalLandscape ? 3 : 1);
}
puts("ESPshowpage");
}
break;
default :
if (is_last_page(number) && UseESPsp)
{
WriteLabels(Orientation);
puts("ESPshowpage");
}
break;
}
fflush(stdout);
}
static void
psbcp(ppd_file_t *ppd)
{
if (ppd->jcl_begin)
fputs(ppd->jcl_begin, stdout);
if (ppd->jcl_ps)
fputs(ppd->jcl_ps, stdout);
if (ppd->language_level == 1)
{
fputs("%!PS-Adobe-3.0 ExitServer\n", stdout);
fputs("%%Title: (BCP - Level 1)\n", stdout);
fputs("%%EndComments\n", stdout);
fputs("%%BeginExitServer: 0\n", stdout);
fputs("serverdict begin 0 exitserver\n", stdout);
fputs("%%EndExitServer\n", stdout);
fputs("statusdict begin\n", stdout);
fputs("/setsoftwareiomode known {100 setsoftwareiomode}\n", stdout);
fputs("end\n", stdout);
fputs("%EOF\n", stdout);
}
else
{
fputs("%!PS-Adobe-3.0\n", stdout);
fputs("%%Title: (BCP - Level 2)\n", stdout);
fputs("%%EndComments\n", stdout);
fputs("currentsysparams\n", stdout);
fputs("/CurInputDevice 2 copy known {\n", stdout);
fputs("get\n", stdout);
fputs("<</Protocol /Binary>> setdevparams\n", stdout);
fputs("}{\n", stdout);
fputs("pop pop\n", stdout);
fputs("} ifelse\n", stdout);
fputs("%EOF\n", stdout);
}
if (ppd->jcl_end)
fputs(ppd->jcl_end, stdout);
else if (ppd->num_filters == 0)
putchar(0x04);
}
static char *
psgets(char *buf,
size_t *bytes,
FILE *fp)
{
char *bufptr;
int ch;
size_t len;
len = *bytes - 1;
bufptr = buf;
ch = EOF;
while ((bufptr - buf) < len)
{
if ((ch = getc(fp)) == EOF)
break;
if (ch == '\r')
{
ch = getc(fp);
if (ch != EOF && ch != '\n')
{
ungetc(ch, fp);
ch = '\r';
}
else
*bufptr++ = '\r';
break;
}
else if (ch == '\n')
break;
else
*bufptr++ = ch;
}
if (ch == '\n' || ch == '\r')
{
if ((bufptr - buf) < len)
*bufptr++ = ch;
else
ungetc(ch, fp);
}
*bufptr = '\0';
*bytes = bufptr - buf;
if (ch == EOF && bufptr == buf)
return (NULL);
else
return (buf);
}
static size_t
pswrite(const char *buf,
size_t bytes,
FILE *fp)
{
size_t count;
switch (Protocol)
{
case PROT_STANDARD :
return (fwrite(buf, 1, bytes, fp));
case PROT_BCP :
for (count = bytes; count > 0; count --, buf ++)
switch (*buf)
{
case 0x01 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x11 :
case 0x13 :
case 0x14 :
case 0x1c :
putchar(0x01);
putchar(*buf ^ 0x40);
break;
default :
putchar(*buf);
break;
}
return (bytes);
case PROT_TBCP :
for (count = bytes; count > 0; count --, buf ++)
switch (*buf)
{
case 0x01 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x11 :
case 0x13 :
case 0x14 :
case 0x1b :
case 0x1c :
putchar(0x01);
putchar(*buf ^ 0x40);
break;
default :
putchar(*buf);
break;
}
return (bytes);
}
return (fwrite(buf, 1, bytes, fp));
}
static void
start_nup(int number,
int show_border)
{
int pos;
int x, y;
float w, l,
tx, ty;
float pw, pl;
if (Flip || Orientation || NUp > 1)
puts("userdict/ESPsave save put");
if (Flip)
printf("%.1f 0.0 translate -1 1 scale\n", PageWidth);
pos = number % NUp;
pw = PageRight - PageLeft;
pl = PageTop - PageBottom;
fprintf(stderr, "DEBUG: pw = %.1f, pl = %.1f\n", pw, pl);
fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n", PageLeft, PageRight);
fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n", PageTop, PageBottom);
fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", PageWidth, PageLength);
#if 0
if(Orientation & 1)
{
if(Orientation == 1)
printf("%.1f %.1f %.1f %.1f ESPrs\n",
PageBottom, PageLeft,
PageTop - PageBottom, PageRight - PageLeft);
else
printf("%.1f %.1f %.1f %.1f ESPrs\n",
PageLength - PageTop, PageWidth - PageRight,
PageTop - PageBottom, PageRight - PageLeft);
}else{
if(Orientation == 0)
printf("%.1f %.1f %.1f %.1f ESPrs\n",
PageLeft, PageBottom,
PageRight - PageLeft, PageTop - PageBottom);
else
printf("%.1f %.1f %.1f %.1f ESPrs\n",
PageWidth - PageRight, PageLength - PageTop,
PageRight - PageLeft, PageTop - PageBottom);
}
#endif
switch (Orientation)
{
case 1 :
printf("%.1f 0.0 translate 90 rotate\n", PageLength);
break;
case 2 :
printf("%.1f %.1f translate 180 rotate\n", PageWidth, PageLength);
break;
case 3 :
printf("0.0 %.1f translate -90 rotate\n", PageWidth);
break;
}
if (Duplex && NUp > 1 && ((number / NUp) & 1))
printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
else if (NUp > 1)
printf("%.1f %.1f translate\n", PageLeft, PageBottom);
switch (NUp)
{
default :
w = PageWidth;
l = PageLength;
break;
case 2 :
if (Orientation & 1)
{
x = pos & 1;
if (Layout & LAYOUT_NEGATEY)
x = 1 - x;
w = pl;
l = w * PageLength / PageWidth;
if (l > (pw * 0.5))
{
l = pw * 0.5;
w = l * PageWidth / PageLength;
}
tx = 0.5 * (pw * 0.5 - l);
ty = 0.5 * (pl - w);
if (NormalLandscape)
printf("0.0 %.1f translate -90 rotate\n", pl);
else
printf("%.1f 0.0 translate 90 rotate\n", pw);
printf("%.1f %.1f translate %.3f %.3f scale\n",
ty, tx + l * x, w / PageWidth, l / PageLength);
}
else
{
x = pos & 1;
if (Layout & LAYOUT_NEGATEX)
x = 1 - x;
l = pw;
w = l * PageWidth / PageLength;
if (w > (pl * 0.5))
{
w = pl * 0.5;
l = w * PageLength / PageWidth;
}
tx = 0.5 * (pl * 0.5 - w);
ty = 0.5 * (pw - l);
if (NormalLandscape)
printf("%.1f 0.0 translate 90 rotate\n", pw);
else
printf("0.0 %.1f translate -90 rotate\n", pl);
printf("%.1f %.1f translate %.3f %.3f scale\n",
tx + w * x, ty, w / PageWidth, l / PageLength);
}
break;
case 4 :
if (Layout & LAYOUT_VERTICAL)
{
x = (pos / 2) & 1;
y = pos & 1;
}
else
{
x = pos & 1;
y = (pos / 2) & 1;
}
if (Layout & LAYOUT_NEGATEX)
x = 1 - x;
if (Layout & LAYOUT_NEGATEY)
y = 1 - y;
w = pw * 0.5;
l = w * PageLength / PageWidth;
if (l > (pl * 0.5))
{
l = pl * 0.5;
w = l * PageWidth / PageLength;
}
tx = 0.5 * (pw * 0.5 - w);
ty = 0.5 * (pl * 0.5 - l);
printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
w / PageWidth, l / PageLength);
break;
case 6 :
if (Orientation & 1)
{
if (Layout & LAYOUT_VERTICAL)
{
x = pos / 3;
y = pos % 3;
if (Layout & LAYOUT_NEGATEX)
x = 1 - x;
if (Layout & LAYOUT_NEGATEY)
y = 2 - y;
}
else
{
x = pos & 1;
y = pos / 2;
if (Layout & LAYOUT_NEGATEX)
x = 1 - x;
if (Layout & LAYOUT_NEGATEY)
y = 2 - y;
}
w = pl * 0.5;
l = w * PageLength / PageWidth;
if (l > (pw * 0.333))
{
l = pw * 0.333;
w = l * PageWidth / PageLength;
}
tx = 0.5 * (pl - 2 * w);
ty = 0.5 * (pw - 3 * l);
if (NormalLandscape)
printf("0.0 %.1f translate -90 rotate\n", pl);
else
printf("%.1f 0.0 translate 90 rotate\n", pw);
printf("%.1f %.1f translate %.3f %.3f scale\n",
tx + x * w, ty + y * l, w / PageWidth, l / PageLength);
}
else
{
if (Layout & LAYOUT_VERTICAL)
{
x = pos / 2;
y = pos & 1;
if (Layout & LAYOUT_NEGATEX)
x = 2 - x;
if (Layout & LAYOUT_NEGATEY)
y = 1 - y;
}
else
{
x = pos % 3;
y = pos / 3;
if (Layout & LAYOUT_NEGATEX)
x = 2 - x;
if (Layout & LAYOUT_NEGATEY)
y = 1 - y;
}
l = pw * 0.5;
w = l * PageWidth / PageLength;
if (w > (pl * 0.333))
{
w = pl * 0.333;
l = w * PageLength / PageWidth;
}
tx = 0.5 * (pl - 3 * w);
ty = 0.5 * (pw - 2 * l);
if (NormalLandscape)
printf("%.1f 0.0 translate 90 rotate\n", pw);
else
printf("0.0 %.1f translate -90 rotate\n", pl);
printf("%.1f %.1f translate %.3f %.3f scale\n",
tx + w * x, ty + l * y, w / PageWidth, l / PageLength);
}
break;
case 9 :
if (Layout & LAYOUT_VERTICAL)
{
x = (pos / 3) % 3;
y = pos % 3;
}
else
{
x = pos % 3;
y = (pos / 3) % 3;
}
if (Layout & LAYOUT_NEGATEX)
x = 2 - x;
if (Layout & LAYOUT_NEGATEY)
y = 2 - y;
w = pw * 0.333;
l = w * PageLength / PageWidth;
if (l > (pl * 0.333))
{
l = pl * 0.333;
w = l * PageWidth / PageLength;
}
tx = 0.5 * (pw * 0.333 - w);
ty = 0.5 * (pl * 0.333 - l);
printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
w / PageWidth, l / PageLength);
break;
case 16 :
if (Layout & LAYOUT_VERTICAL)
{
x = (pos / 4) & 3;
y = pos & 3;
}
else
{
x = pos & 3;
y = (pos / 4) & 3;
}
if (Layout & LAYOUT_NEGATEX)
x = 3 - x;
if (Layout & LAYOUT_NEGATEY)
y = 3 - y;
w = pw * 0.25;
l = w * PageLength / PageWidth;
if (l > (pl * 0.25))
{
l = pl * 0.25;
w = l * PageWidth / PageLength;
}
tx = 0.5 * (pw * 0.25 - w);
ty = 0.5 * (pl * 0.25 - l);
printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l,
w / PageWidth, l / PageLength);
break;
}
if (Border && show_border)
{
int rects;
float fscale,
margin;
rects = (Border & BORDER_DOUBLE) ? 2 : 1;
fscale = PageWidth / w;
margin = 2.25 * fscale;
puts("gsave");
printf("%.3f setlinewidth 0 setgray newpath\n",
(Border & BORDER_THICK) ? 0.5 * fscale : 0.24 * fscale);
for (; rects > 0; rects --, margin += 2 * fscale)
if (NUp > 1)
printf("%.1f %.1f %.1f %.1f ESPrs\n",
margin,
margin,
PageWidth - 2 * margin,
PageLength - 2 * margin);
else
printf("%.1f %.1f %.1f %.1f ESPrs\n",
PageLeft + margin,
PageBottom + margin,
PageRight - PageLeft - 2 * margin,
PageTop - PageBottom - 2 * margin);
puts("grestore");
}
if (NUp > 1)
{
printf("0 0 %.1f %.1f ESPrc\n", PageWidth, PageLength);
}
}
static void setPageOptionsAndEmit(ppd_file_t *ppd, float minOrder, const char *inputSlotToSet, const char *manualFeedToSet, const char *manualFeedToUnset)
{
if(ppd && (inputSlotToSet || manualFeedToSet)){
int limitOrder = 1;
if(inputSlotToSet){
if(manualFeedToUnset && strcasecmp(manualFeedToUnset, "True") == 0){
ppdMarkOption(ppd, "ManualFeed", "False");
}
ppdMarkOption(ppd, "InputSlot", inputSlotToSet);
}else{
ppdMarkOption(ppd, "ManualFeed", manualFeedToSet);
}
ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_DOCUMENT, limitOrder, minOrder);
ppdEmitAfterOrder(ppd, stdout, PPD_ORDER_ANY, limitOrder, minOrder);
}
}