/* * ppdfilt.c: Postscript filter for libppd * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * * See the AUTHORS file for a list of people who have hacked on * this code. * See the ChangeLog file for a list of changes. * * Contents: * * main() - Main entry... * check_range() - Check to see if the current page is selected for * copy_bytes() - Copy bytes from the input file to stdout... * end_nup() - End processing for N-up printing... * psgets() - Get a line from a file. * start_nup() - Start processing for N-up printing... * * Changes: * * 4/27/2000 - fixed "slow" collating bug. When the PPD file * doesn't include a Collate option, the program * collates internally by writing the postscript * data to a temp file, then outputting it to * produce n copies. Program was erroneously * also outputting a postscript "/#copies" tag * into the output, causing the printer to produce * n uncollated copies. Another bug was causing * n+1 copies to be printed, instead of just n. * All changes in source are marked with a comment * starting with my initials (MLP = "Mark Pruett") * to identify the damage I've done. */ #include "config.h" #include #include #include #include #include #include "ppd.h" #include "ppdfilt.h" #define MAX_PAGES 10000 enum orientation_t { PORTRAIT, LANDSCAPE, REVERSE_PORTRAIT, REVERSE_LANDSCAPE }; int check_range(int page, const char *PageRanges, const char *pageSet); void copy_bytes(FILE * fp, size_t length); void end_nup(int number, int Flip, int NUp, enum orientation_t Orientation); char *psgets(char *buf, size_t len, FILE * fp); void start_nup(int number, int Flip, enum orientation_t Orientation, int NUp, int Duplex, float PageWidth, float PageRight, float PageLeft, float PageTop, float PageBottom, float PageLength); PpdFile *SetCommonOptions(int num_options, cups_option_t * options, int change_size, float *PageWidth, float *PageLength, float *PageTop, float *PageBottom, float *PageLeft, float *PageRight, int *LanguageLevel, unsigned int *flags, const char *ppdfilename); int cupsTempFile(char *filename, int len); inline unsigned int get_slowcollate(unsigned int flags); inline void set_slowcollate(unsigned int *flags); inline void clear_slowcollate(unsigned int *flags); inline void setto_slowcollate(unsigned int *flags, unsigned int state); inline unsigned int get_sloworder(unsigned int flags); inline void set_sloworder(unsigned int *flags); inline void clear_sloworder(unsigned int *flags); inline void setto_sloworder(unsigned int *flags, unsigned int state); inline unsigned int get_pageorder(unsigned int flags); inline void set_pageorder(unsigned int *flags); inline void clear_pageorder(unsigned int *flags); inline unsigned int get_flip(unsigned int flags); inline void set_flip(unsigned int *flags); inline void clear_flip(unsigned int *flags); inline unsigned int get_collate(unsigned int flags); inline void set_collate(unsigned int *flags); inline void clear_collate(unsigned int *flags); inline void setto_collate(unsigned int *flags, unsigned int state); inline unsigned int get_duplex(unsigned int flags); inline void set_duplex(unsigned int *flags); inline void clear_duplex(unsigned int *flags); inline unsigned int get_colordevice(unsigned int flags); inline void set_colordevice(unsigned int *flags); inline void clear_colordevice(unsigned int *flags); enum orientation_t get_orientation(unsigned int flags); void set_orientation(unsigned int *flags, enum orientation_t orient); inline unsigned int get_slowcollate(unsigned int flags) { return flags & 1; } inline void set_slowcollate(unsigned int *flags) { *flags |= 1; } inline void clear_slowcollate(unsigned int *flags) { *flags &= ~1; } inline void setto_slowcollate(unsigned int *flags, unsigned int state) { if (state) set_slowcollate(flags); else clear_slowcollate(flags); } // we need to order manually inline unsigned int get_sloworder(unsigned int flags) { return flags & 2; } inline void set_sloworder(unsigned int *flags) { *flags |= 2; } inline void clear_sloworder(unsigned int *flags) { *flags &= ~2; } inline void setto_sloworder(unsigned int *flags, unsigned int state) { if (state) set_sloworder(flags); else clear_sloworder(flags); } // 0=normal, 1=reverse pages inline unsigned int get_pageorder(unsigned int flags) { return flags & 4; } inline void set_pageorder(unsigned int *flags) { *flags |= 4; } inline void clear_pageorder(unsigned int *flags) { *flags &= ~4; } // Flip/mirror pages inline unsigned int get_flip(unsigned int flags) { return flags & 8; } inline void set_flip(unsigned int *flags) { *flags |= 8; } inline void clear_flip(unsigned int *flags) { *flags &= ~8; } // Collate copies? inline unsigned int get_collate(unsigned int flags) { return flags & 16; } inline void set_collate(unsigned int *flags) { *flags |= 16; } inline void clear_collate(unsigned int *flags) { *flags &= ~16; } inline void setto_collate(unsigned int *flags, unsigned int state) { if (state) set_collate(flags); else clear_collate(flags); } // duplexed? inline unsigned int get_duplex(unsigned int flags) { return flags & 32; } inline void set_duplex(unsigned int *flags) { *flags |= 32; } inline void clear_duplex(unsigned int *flags) { *flags &= ~32; } // color_device inline unsigned int get_colordevice(unsigned int flags) { return flags & 64; } inline void set_colordevice(unsigned int *flags) { *flags |= 64; } inline void clear_colordevice(unsigned int *flags) { *flags &= ~64; } // Orientation enum orientation_t get_orientation(unsigned int flags) { switch (flags & 384) { case 0: return PORTRAIT; case 128: return LANDSCAPE; case 256: return REVERSE_PORTRAIT; case 384: return REVERSE_LANDSCAPE; default: return (enum orientation_t)-1; } /* This was added by mfasheh, because we need to have a default I honestly have no idea whether this is a proper default though... */ return (PORTRAIT); } void set_orientation(unsigned int *flags, enum orientation_t orient) { switch (orient) { case PORTRAIT: *flags = (*flags & ~384) | 0; break; case LANDSCAPE: *flags = (*flags & ~384) | 128; break; case REVERSE_PORTRAIT: *flags = (*flags & ~384) | 256; break; case REVERSE_LANDSCAPE: *flags = *flags | 384; } } //** 'main()' - Main entry... ** int main(int argc, char *argv[]) { FILE *fp; // Print file PpdFile *ppd; // PPD file int num_options; // Number of print options cups_option_t *options; // Print options const char *val; // Option value char tempfile[255]; // Temporary file name FILE *temp; // Temporary file int number; // Page number char line[8192]; // Line buffer float gamma; // Gamma correction value float brightness; // Brightness factor int level; // Nesting level for embedded files int nbytes; // Number of bytes read int tbytes; // Tot bytes to read for bin data int page; // Current page sequence number int page_count; // Page count for NUp int subpage; // Sub-page number int copy; // Current copy int NumPages = 0; // Number of pages in file long Pages[MAX_PAGES]; // Offsets to each page // char PageLabels[MAX_PAGES][64]; // Page labels const char *PageRanges = NULL; // Range of pages selected const char *PageSet = NULL; // All, Even, Odd pages int NUp = 1; // Number of pages on each sheet int copies = 1; // Number of copies int LanguageLevel = 1; // Language level of printer float PageLeft = 18.0f; // Left margin float PageRight = 594.0f; // Right margin float PageBottom = 36.0f; // Bottom margin float PageTop = 756.0f; // Top margin float PageWidth = 612.0f; // Total page width float PageLength = 792.0f; // Total page length const char *ppdfilename = getenv("PPD"); GSList *list; // List enumeration variable. unsigned int flags; clear_pageorder(&flags); clear_flip(&flags); clear_collate(&flags); clear_duplex(&flags); set_colordevice(&flags); if (!strcmp((char *)g_basename(argv[0]), "pstops")) { // if(strcmp((char*)basename(argv[0]),"pstops")){ // cups compatability if (argc < 6 || argc > 7) { fputs("ERROR: pstops job-id user title copies options [file]\n", stderr); return (1); } /* If we have 7 arguments,print the file named on the * command-line. Otherwise, send stdin instead... */ if (argc == 6) fp = stdin; else { /* Try to open the print file... */ if ((fp = fopen(argv[6], "rb")) == NULL) { perror("ERROR: unable to open print file - "); return (1); } } options = NULL; num_options = cupsParseOptions(argv[5], 0, &options); copies = atoi(argv[4]); } else { int curarg; static struct option long_options[] = { {"ppd", required_argument, NULL, 'p'}, {"option", required_argument, NULL, 'o'}, {"copies", required_argument, NULL, 'c'}, {"4up", no_argument, NULL, '4'}, {"2up", no_argument, NULL, '2'}, {"nup", required_argument, NULL, 'n'}, {"duplex-tumble", no_argument, NULL, 'D'}, {"duplex", optional_argument, NULL, 'd'}, {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, '?'}, {0, 0, 0, 0} }; char *cur; copies = 1; num_options = 0; options = NULL; /* MLP: added colon following c option in getopt_long parm */ while ( (curarg = getopt_long(argc, argv, "+?24c:d::D:n:o:p:VZ:", long_options, NULL)) != EOF) { switch (curarg) { case 'c': copies = atoi(optarg); break; case 'o': case 'Z': if ((cur = strchr(optarg, ':')) == NULL) { fprintf(stderr, "Bad option format: %s\n", optarg); exit(2); } *cur = 0; // break the string cur++; // point cur to the value /* MLP: skip past leading spaces. */ while (cur && (cur[0] == ' ')) cur++; num_options = cupsAddOption(optarg, cur, num_options, &options); break; case 'p': ppdfilename = optarg; break; case '4': NUp = 4; break; case '2': NUp = 2; break; case 'n': NUp = atoi(optarg); break; case 'D': num_options = cupsAddOption("Duplex", "DuplexTumble", num_options, &options); break; case 'V': printf("%s Version: %s\n", g_basename(argv[0]), VERSION); exit(0); case 'd': if (optarg == 0 || !strcasecmp("NoTumble", optarg)) { num_options = cupsAddOption("Duplex", "DuplexNoTumble", num_options, &options); break; } else if (!strcasecmp("Tumble", optarg)) { num_options = cupsAddOption("Duplex", "DuplexTumble", num_options, &options); break; } /* intentionally falls through because they are trying to set tumble to something totally unknown. */ case '?': // this need to be filled in more fully // per the gnu coding standards default: fputs("usage: ppdfilt [--ppd ppdfile] [--option options] [filename]\n", stderr); exit(1); } } if (optind == argc) fp = stdin; else { /* Try to open the print file... */ if ((fp = fopen(argv[optind], "rb")) == NULL) { perror("ERROR: unable to open print file - "); return (1); } } } gamma = 1.0; brightness = 1.0; // make sure that nup is within bounds. if (NUp != 2 && NUp != 4 && NUp != 1) { fprintf(stderr, "%s invalid nup,%d, must equal 1,2, or 4.\n", g_basename(argv[0]), NUp); exit(2); } if (ppdfilename==NULL) ppdfilename=PPD_PATH"generic-printer.ppd"; if ((ppd =SetCommonOptions(num_options, options, 1, &PageWidth, &PageLength, &PageTop, &PageBottom, &PageLeft, &PageRight, &LanguageLevel, &flags, ppdfilename)) == NULL) { fprintf(stderr, "Cannot read the PPD file.\n"); exit(4); } 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) { /* * This IPP attribute is unnecessarily complicated... * * single-document, separate-documents-collated-copies, and * single-document-new-sheet all require collated copies. * * separate-documents-collated-copies allows for uncollated * copies. */ setto_collate(&flags, strcasecmp(val, "separate-documents-collated-copies") != 0); } if ((val = cupsGetOption("Collate", num_options, options)) != NULL && strcasecmp(val, "True") == 0) set_collate(&flags); if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL && strcasecmp(val, "Reverse") == 0) set_pageorder(&flags); if ((val = cupsGetOption("number-up", num_options, options)) != NULL) NUp = atoi(val); if ((val = cupsGetOption("copies", num_options, options)) != NULL) copies = atoi(val); if ((val = cupsGetOption("gamma", num_options, options)) != NULL) gamma = atoi(val) * 0.001f; if ((val = cupsGetOption("brightness", num_options, options)) != NULL) brightness = atoi(val) * 0.01f; /* * See if we have to filter the fast or slow way... */ setto_slowcollate(&flags, ppd_find_option_by_keyword(ppd, "Collate") == NULL && get_collate(flags) && copies > 1); setto_sloworder(&flags, ppd_find_option_by_keyword(ppd, "OutputOrder") == NULL && get_pageorder(flags)); /* * If we need to filter slowly,then create a temporary file for * page data... * * If the temp file can't be created,then we'll ignore the * collating/output order options... */ if (get_sloworder(flags) || get_slowcollate(flags)) { if ((temp = fdopen(cupsTempFile(tempfile, sizeof(tempfile)), "wb+")) == NULL) { clear_slowcollate(&flags); clear_sloworder(&flags); } } // Write any "exit server" options that have been selected... ppd_emit_to_file(ppd, stdout, PPD_ORDER_EXIT); /* Write any JCL commands that are needed to print PostScript code... */ if (ppd != NULL && ppd->jcl_begin && ppd->jcl_ps) { fputs(ppd->jcl_begin->str, stdout); ppd_emit_to_file(ppd, stdout, PPD_ORDER_JCL); fputs(ppd->jcl_ps->str, stdout); } // Read the first line to see if we have DSC comments... if (psgets(line, sizeof(line), fp) == NULL) { fputs("ERROR: Empty print file!\n", stderr); ppd_file_free(ppd); return (1); } // Start sending the document with any commands needed... puts(line); if (ppd != NULL && ppd->patches != NULL) { list = ppd->patches; while (list) { puts((char *)list->data); list = g_slist_next(list); } } ppd_emit_to_file(ppd, stdout, PPD_ORDER_DOCUMENT); ppd_emit_to_file(ppd, stdout, PPD_ORDER_ANY); ppd_emit_to_file(ppd, stdout, PPD_ORDER_PROLOG); if (NUp > 1) puts("userdict begin\n" "/ESPshowpage /showpage load def\n" "/showpage { } def\n" "end"); if (gamma != 1.0 || brightness != 1.0) printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } " "ifelse %.3f mul } bind settransfer\n", gamma, brightness); /* MLP: changed from "if((copies>1)&&(get_collate(flags) || !get_slowcollate(flags))" */ /* MLP: If you're printing more than 1 copy, then you want to embed "/#copies..." into the postscript, unless you're also doing "slow" collating (which means that the program handles collating itself by sending the pages multiple times to the printer). */ if (copies > 1) if ((get_collate(flags) && !get_slowcollate(flags)) || !get_collate(flags)) printf("/#copies %d def\n", copies); if (strncmp(line, "%!PS-Adobe-", 11) == 0) { /* OK,we have DSC comments; read until we find a %%Page comment... */ level = 0; while (psgets(line, sizeof(line), fp) != NULL) if (strncmp(line, "%%BeginDocument:", 16) == 0 || strncmp(line, "%%BeginDocument ", 16) == 0) // Adobe // Acrobat BUG level++; else if (strcmp(line, "%%EndDocument") == 0 && level > 0) level--; else if (strncmp(line, "%%Page:", 7) == 0 && level == 0) break; else if (strncmp(line, "%%BeginBinary:", 14) == 0 || (strncmp(line, "%%BeginData:", 12) == 0 && strstr(line, "Binary") != NULL)) { // Copy binary data... tbytes = atoi(strchr(line, ':') + 1); while (tbytes > 0) { nbytes = fread(line, 1, sizeof(line), fp); fwrite(line, 1, nbytes, stdout); tbytes -= nbytes; } } else puts(line); // Then read all of the pages,filtering as needed... for (page = 1;;) { if (strncmp(line, "%%BeginDocument:", 16) == 0 || strncmp(line, "%%BeginDocument ", 16) == 0) // Adobe // Acrobat BUG level++; else if (strcmp(line, "%%EndDocument") == 0 && level > 0) level--; else if (strncmp(line, "%%Page:", 7) == 0 && level == 0) { if (sscanf(line, "%*s%*s%d", &number) == 1) { if (!check_range(number, PageRanges, PageSet)) { while (psgets(line, sizeof(line), fp) != NULL) if (strncmp(line, "%%BeginDocument:", 16) == 0 || strncmp(line, "%%BeginDocument ", 16) == 0) // Adobe // // // // // // // Acrobat // BUG level++; else if (strcmp(line, "%%EndDocument") == 0 && level > 0) level--; else if (strncmp(line, "%%Page:", 7) == 0 && level == 0) break; continue; } if (!get_sloworder(flags) && NumPages > 0) end_nup(NumPages - 1, get_flip(flags), NUp, get_orientation(flags)); if (get_slowcollate(flags) || get_sloworder(flags)) Pages[NumPages] = ftell(temp); if (!get_sloworder(flags)) { if ((NumPages & (NUp - 1)) == 0) { /* if (ppd == NULL || ppd->filters == NULL) */ /* fprintf(stderr, "PAGE: %d %d\n", page, copies); */ printf("%%%%Page: %d %d\n", page, page); page++; ppd_emit_to_file(ppd, stdout, PPD_ORDER_PAGE); } start_nup(NumPages, get_flip(flags), get_orientation(flags), NUp, get_duplex(flags), PageWidth, PageRight, PageLeft, PageTop, PageBottom, PageLength); } NumPages++; } } else if (strncmp(line, "%%BeginBinary:", 14) == 0 || (strncmp(line, "%%BeginData:", 12) == 0 && strstr(line, "Binary") != NULL)) { // Copy binary data... tbytes = atoi(strchr(line, ':') + 1); while (tbytes > 0) { nbytes = fread(line, 1, sizeof(line), fp); if (!get_sloworder(flags)) fwrite(line, 1, nbytes, stdout); if (get_slowcollate(flags) || get_sloworder(flags)) fwrite(line, 1, nbytes, stdout); tbytes -= nbytes; } } else if (strcmp(line, "%%Trailer") == 0 && level == 0) break; else { if (!get_sloworder(flags)) puts(line); if (get_slowcollate(flags) || get_sloworder(flags)) { fputs(line, temp); putc('\n', temp); } } if (psgets(line, sizeof(line), fp) == NULL) break; } if (!get_sloworder(flags)) { end_nup(NumPages - 1, get_flip(flags), NUp, get_orientation(flags)); if (NumPages & (NUp - 1)) { start_nup(NUp - 1, get_flip(flags), get_orientation(flags), NUp, get_duplex(flags), PageWidth, PageRight, PageLeft, PageTop, PageBottom, PageLength); end_nup(NUp - 1, get_flip(flags), NUp, get_orientation(flags)); } } if (get_slowcollate(flags) || get_sloworder(flags)) { Pages[NumPages] = ftell(temp); page = 1; if (!get_sloworder(flags)) { /* We've already done one copy, so reduce copies by one. */ copies--; while (copies > 0) { rewind(temp); for (number = 0; number < NumPages; number++) { if ((number & (NUp - 1)) == 0) { if (ppd == NULL || ppd->filters == NULL) fprintf(stderr, "PAGE: %d 1\n", page); printf("%%%%Page: %d %d\n", page, page); page++; ppd_emit_to_file(ppd, stdout, PPD_ORDER_PAGE); } start_nup(number, get_flip(flags), get_orientation(flags), NUp, get_duplex(flags), PageWidth, PageRight, PageLeft, PageTop, PageBottom, PageLength); copy_bytes(temp, Pages[number + 1] - Pages[number]); end_nup(number, get_flip(flags), NUp, get_orientation(flags)); } if (NumPages & (NUp - 1)) { start_nup(NUp - 1, get_flip(flags), get_orientation(flags), NUp, get_duplex(flags), PageWidth, PageRight, PageLeft, PageTop, PageBottom, PageLength); end_nup(NUp - 1, get_flip(flags), NUp, get_orientation(flags)); } copies--; } } else { page_count = (NumPages + NUp - 1) / NUp; copy = 0; do { for (page = page_count - 1; page >= 0; page--) { if (ppd == NULL || ppd->filters == NULL) fprintf(stderr, "PAGE: %d %d\n", page + 1, get_slowcollate(flags) ? 1 : copies); if (get_slowcollate(flags)) printf("%%%%Page: %d %d\n", page + 1, page_count - page + copy * page_count); else printf("%%%%Page: %d %d\n", page + 1, page_count - page); ppd_emit_to_file(ppd, stdout, PPD_ORDER_PAGE); for (subpage = 0, number = page * NUp; subpage < NUp && number < NumPages; subpage++, number++) { start_nup(number, get_flip(flags), get_orientation(flags), NUp, get_duplex(flags), PageWidth, PageRight, PageLeft, PageTop, PageBottom, PageLength); fseek(temp, Pages[number], SEEK_SET); copy_bytes(temp, Pages[number + 1] - Pages[number]); end_nup(number, get_flip(flags), NUp, get_orientation(flags)); } if (number & (NUp - 1)) { start_nup(NUp - 1, get_flip(flags), get_orientation(flags), NUp, get_duplex(flags), PageWidth, PageRight, PageLeft, PageTop, PageBottom, PageLength); end_nup(NUp - 1, get_flip(flags), NUp, get_orientation(flags)); } } copy++; } while (copy < copies && get_slowcollate(flags)); } } /* * Copy the trailer,if any... */ while ((nbytes = fread(line, 1, sizeof(line), fp)) > 0) fwrite(line, 1, nbytes, stdout); } else { /* * No DSC comments - write any page commands and then the rest * of the file... */ if (ppd == NULL || ppd->filters == NULL) fprintf(stderr, "PAGE: 1 %d\n", get_slowcollate(flags) ? 1 : copies); ppd_emit_to_file(ppd, stdout, PPD_ORDER_PAGE); while (psgets(line, sizeof(line), fp) != NULL) { puts(line); if (get_slowcollate(flags)) { fputs(line, temp); putc('\n', temp); } } if (get_slowcollate(flags)) { while (copies > 1) { if (ppd == NULL || ppd->filters == NULL) fputs("PAGE: 1 1\n", stderr); ppd_emit_to_file(ppd, stdout, PPD_ORDER_PAGE); rewind(temp); copy_bytes(temp, 0); } } } /* * End the job with the appropriate JCL command or CTRL-D otherwise. */ if (ppd != NULL && ppd->jcl_end) fputs(ppd->jcl_end->str, stdout); else putchar(0x04); /* * Close files and remove the temporary file if needed... */ if (get_slowcollate(flags) || get_sloworder(flags)) { fclose(temp); unlink(tempfile); } ppd_file_free(ppd); if (fp != stdin) fclose(fp); return (0); } /* * 'check_range()' - Check to see if the current page is * selected for printing. * * Returns: 1 if selected, 0 otherwise */ int check_range(int page, const char *PageRanges, const char *PageSet) { const char *range; // Pointer into range string int lower, upper; // Lower and upper page numbers if (PageSet != NULL) { // See if we only print even or odd pages... if (strcasecmp(PageSet, "even") == 0 && (page & 1)) return (0); if (strcasecmp(PageSet, "odd") == 0 && !(page & 1)) return (0); } if (PageRanges == NULL) return (1); // No range,print all pages... 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); } /* * 'copy_bytes()' - Copy bytes from the input file to stdout... */ void copy_bytes(FILE * fp, size_t length) { char buffer[8192]; // Data buffer size_t nbytes, // Number of bytes read nleft; // Number of bytes left/remaining nleft = length; while (nleft > 0 || length == 0) { if (nleft > sizeof(buffer)) nbytes = sizeof(buffer); else nbytes = nleft; if ((nbytes = fread(buffer, 1, nbytes, fp)) < 1) return; nleft -= nbytes; fwrite(buffer, 1, nbytes, stdout); } } /* * 'end_nup()' - End processing for N-up printing... */ void end_nup(int number, int Flip, int NUp, enum orientation_t Orientation) { if (Flip || Orientation != PORTRAIT || NUp > 1) puts("ESPsave restore"); switch (NUp) { case 2: if ((number & 1) == 1) puts("ESPshowpage"); break; case 4: if ((number & 3) == 3) puts("ESPshowpage"); break; } } /* * 'psgets()' - Get a line from a file. * * Note: * * This function differs from the gets() function in that it * handles any combination of CR,LF,or CR LF to end input * lines. */ char *psgets(char *buf, size_t len, FILE * fp) { char *bufptr; // Pointer into buffer int ch; // Character from file len--; bufptr = buf; while ((unsigned)(bufptr - buf) < len) { if ((ch = getc(fp)) == EOF) break; if (ch == 0x0d) { /* * Got a CR; see if there is a LF as well... */ ch = getc(fp); if (ch != EOF && ch != 0x0a) ungetc(ch, fp); // Nope,save it for later... break; } else if (ch == 0x0a) break; else *bufptr++ = ch; } /* * Nul-terminate the string and return it (or NULL for EOF). */ *bufptr = '\0'; if (ch == EOF && bufptr == buf) return (NULL); else return (buf); } /* * 'start_nup()' - Start processing for N-up printing... */ void start_nup(int number, int Flip, enum orientation_t Orientation, int NUp, int Duplex, float PageWidth, float PageRight, float PageLeft, float PageTop, float PageBottom, float PageLength) { int x, y; // Relative position of subpage float w, l; // Width and length of subpage float tx, ty; // Translation values for subpage float pw, pl; // Printable width and length of full page if (Flip || Orientation || NUp > 1) puts("/ESPsave save def"); if (Flip) printf("%.0f 0 translate -1 1 scale\n", PageWidth); pw = PageRight - PageLeft; pl = PageTop - PageBottom; switch (Orientation) { case LANDSCAPE: // Landscape printf("%.0f 0 translate 90 rotate\n", PageLength); break; case REVERSE_PORTRAIT: // Reverse Portrait printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); break; case REVERSE_LANDSCAPE: // Reverse Landscape printf("0 %.0f translate -90 rotate\n", PageWidth); break; default: // Portrait, plus anything else defined in // future revisions break; } switch (NUp) { case 2: x = number & 1; if (Orientation == LANDSCAPE || Orientation == REVERSE_LANDSCAPE) { x = 1 - x; w = pl; l = w * PageLength / PageWidth; if (l > (pw * 0.5)) { l = pw * 0.5; w = l * PageWidth / PageLength; } tx = pw * 0.5 - l; ty = (pl - w) * 0.5; } else { l = pw; w = l * PageWidth / PageLength; if (w > (pl * 0.5)) { w = pl * 0.5; l = w * PageLength / PageWidth; } tx = pl * 0.5 - w; ty = (pw - l) * 0.5; } if (Duplex && (number & 2)) printf("%.0f %.0f translate\n", PageWidth - PageRight, PageBottom); else printf("%.0f %.0f translate\n", PageLeft, PageBottom); if (Orientation == LANDSCAPE || Orientation == REVERSE_LANDSCAPE) { printf("0 %.0f translate -90 rotate\n", pl); printf("%.0f %.0f translate %.3f %.3f scale\n", ty, tx + l * x, w / pw, l / pl); } else { printf("%.0f 0 translate 90 rotate\n", pw); printf("%.0f %.0f translate %.3f %.3f scale\n", tx + w * x, ty, w / pw, l / pl); } printf("newpath\n" "0 0 moveto\n" "%.0f 0 lineto\n" "%.0f %.0f lineto\n" "0 %.0f lineto\n" "closepath clip newpath\n", PageWidth, PageWidth, PageLength, PageLength); break; case 4: x = number & 1; y = 1 - ((number & 2) != 0); w = pw * 0.5; l = w * PageLength / PageWidth; if (l > (pl * 0.5)) { l = pl * 0.5; w = l * PageWidth / PageLength; } if (Duplex && (number & 4)) printf("%.0f %.0f translate\n", PageWidth - PageRight, PageBottom); else printf("%.0f %.0f translate\n", PageLeft, PageBottom); printf("%.0f %.0f translate %.3f %.3f scale\n", x * w, y * l, w / PageWidth, l / PageLength); printf("newpath\n" "0 0 moveto\n" "%.0f 0 lineto\n" "%.0f %.0f lineto\n" "0 %.0f lineto\n" "closepath clip newpath\n", PageWidth, PageWidth, PageLength, PageLength); break; } } PpdFile *SetCommonOptions(int num_options, cups_option_t * options, int change_size, float *PageWidth, float *PageLength, float *PageTop, float *PageBottom, float *PageLeft, float *PageRight, int *LanguageLevel, unsigned int *flags, const char *ppdfilename) { float temp; // Swapping variable PpdFile *ppd; // PPD file PpdSize *pagesize; // Current page size const char *val; // Option value if ((ppd = ppd_file_new(ppdfilename)) == NULL) return NULL; ppd_mark_defaults(ppd); cupsMarkOptions(ppd, num_options, options); if ((pagesize = ppd_get_page_size(ppd, NULL)) != NULL) { *PageWidth = pagesize->width; *PageLength = pagesize->length; *PageTop = pagesize->top; *PageBottom = pagesize->bottom; *PageLeft = pagesize->left; *PageRight = pagesize->right; /* fprintf(stderr, "DEBUG: Page=%.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n", */ /* *PageWidth, *PageLength, *PageLeft, *PageBottom, *PageRight, */ /* *PageTop); */ } if (ppd != NULL) { set_colordevice(flags); *LanguageLevel = ppd->language_level; } if ((val = cupsGetOption("landscape", num_options, options)) != NULL) set_orientation(flags, LANDSCAPE); if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL) { int or = atoi(val); switch (or) { case 3: set_orientation(flags, PORTRAIT); break; case 4: set_orientation(flags, LANDSCAPE); break; case 5: set_orientation(flags, REVERSE_PORTRAIT); break; case 6: set_orientation(flags, REVERSE_LANDSCAPE); } } if ((val = cupsGetOption("page-left", num_options, options)) != NULL) { switch (get_orientation(*flags)) { case PORTRAIT: *PageLeft = (float)atof(val); break; case LANDSCAPE: *PageBottom = (float)atof(val); break; case REVERSE_PORTRAIT: *PageRight = *PageWidth - (float)atof(val); break; case REVERSE_LANDSCAPE: *PageTop = *PageLength - (float)atof(val); break; } } if ((val = cupsGetOption("page-right", num_options, options)) != NULL) { switch (get_orientation(*flags)) { case PORTRAIT: *PageRight = *PageWidth - (float)atof(val); break; case LANDSCAPE: *PageTop = *PageLength - (float)atof(val); break; case REVERSE_PORTRAIT: *PageLeft = (float)atof(val); break; case REVERSE_LANDSCAPE: *PageBottom = (float)atof(val); break; } } if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL) { switch (get_orientation(*flags)) { case PORTRAIT: *PageBottom = (float)atof(val); break; case LANDSCAPE: *PageRight = *PageWidth - (float)atof(val); break; case REVERSE_PORTRAIT: *PageTop = *PageLength - (float)atof(val); break; case REVERSE_LANDSCAPE: *PageLeft = (float)atof(val); break; } } if ((val = cupsGetOption("page-top", num_options, options)) != NULL) { switch (get_orientation(*flags)) { case PORTRAIT: *PageTop = *PageLength - (float)atof(val); break; case LANDSCAPE: *PageLeft = (float)atof(val); break; case REVERSE_PORTRAIT: *PageBottom = (float)atof(val); break; case REVERSE_LANDSCAPE: *PageRight = *PageWidth - (float)atof(val); break; } } if (change_size) switch (get_orientation(*flags)) { case PORTRAIT: break; case LANDSCAPE: temp = *PageLeft; *PageLeft = *PageBottom; *PageBottom = temp; temp = *PageRight; *PageRight = *PageTop; *PageTop = temp; temp = *PageWidth; *PageWidth = *PageLength; *PageLength = temp; break; case REVERSE_PORTRAIT: // Reverse Portrait temp = *PageWidth - *PageLeft; *PageLeft = *PageWidth - *PageRight; *PageRight = temp; temp = *PageLength - *PageBottom; *PageBottom = *PageLength - *PageTop; *PageTop = temp; break; case REVERSE_LANDSCAPE: // Reverse Landscape !! temp = *PageWidth - *PageLeft; *PageLeft = *PageWidth - *PageRight; *PageRight = temp; temp = *PageLength - *PageBottom; *PageBottom = *PageLength - *PageTop; *PageTop = temp; temp = *PageLeft; *PageLeft = *PageBottom; *PageBottom = temp; temp = *PageRight; *PageRight = *PageTop; *PageTop = temp; temp = *PageWidth; *PageWidth = *PageLength; *PageLength = temp; break; } if ((val = cupsGetOption("sides", num_options, options)) != NULL && strncasecmp(val, "two-", 4) == 0) set_duplex(flags); else if ((val = cupsGetOption("Duplex", num_options, options)) != NULL && strncasecmp(val, "Duplex", 6) == 0) set_duplex(flags); else if (ppd_check_option_is_marked(ppd, "Duplex", "DuplexNoTumble") || ppd_check_option_is_marked(ppd, "Duplex", "DuplexTumble")) set_duplex(flags); return (ppd); } int /* O - File Descriptor */ cupsTempFile(char *filename, /* I - Pointer to buffer */ int len) { /* I - Size of buffer */ static const char *tmpdir; /* TMPDIR environment var */ static char buf[1024] = ""; /* Buffer if you pass in NULL and 0 */ /* * See if a filename was specified... */ if (filename == NULL) { filename = buf; len = sizeof(buf); } /* See if TMPDIR is defined... */ if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/var/tmp"; if ((int)(strlen(tmpdir) + 8) > len) { /* The specified directory exceeds the size of the buffer; default it... */ strcpy(buf, "/var/tmp/XXXXXX"); return (mkstemp(buf)); } else { /* Make the temporary name using the specified directory... */ sprintf(filename, "%s/XXXXXX", tmpdir); return (mkstemp(filename)); } }