// @(#)print.cc 1.4 93/08/01 // // Copyright (c) Steve Holden and Rich Burridge. // All rights reserved. // // Permission is given to distribute these sources, as long as the // copyright messages are not removed, and no monies are exchanged. // // No responsibility is taken for any errors inherent either // to the comments or the code of this program, but if reported // to me then an attempt will be made to fix them. #include using namespace std; #include #include #include #include #include #include #include #include "header.hh" #include "input.hh" #include "print.hh" extern Header hdr ; extern Input input ; extern Print prt ; void Print::do_date(void) // Output Postscript definition for the date and time. { char *ptr ; // Pointer to current time or date string. int len ; time_t clock ; // Used by the localtime function call. struct stat status ; // Stat(2) information from current file (-modtime). struct tm *tm ; // Used by the localtime and asctime calls. char *timenow ; // Used to set TimeNow field with users name. if (input.modtime && input.numnames) // -modtime given on command line? if (!stat(prt.curfname, &status)) { tm = localtime(&status.st_mtime) ; hdr.date = asctime(tm) ; hdr.date[24] = '\0' ; } if (hdr.date == NULL) { clock = time((time_t *) 0) ; tm = localtime(&clock) ; ptr = asctime(tm) ; ptr[24] = '\0' ; } else ptr = hdr.date ; if (!input.article) psdef("TimeNow", ptr) ; else { len = strlen(ptr) ; timenow = (char *) malloc((unsigned) (len + 6 + strlen(input.whoami) + 1)) ; (void) sprintf(timenow, "%s - (%s)", ptr, input.whoami) ; psdef("TimeNow", timenow) ; } } void Print::end(action_type op) { int pval ; switch (op) { case IS_COL : FPUTS("sf ") ; linect = 1 ; ++colct ; if (input.landscape) pval = (2 * pageno) + colct - 2 ; else pval = pageno ; FPRINTF(ofp, "(%1d) %1d endcol\n", pval, colct) ; // Needed for correct heading in multiple columns. if (input.numcols > 1) set_defs() ; if (input.landscape && colct != input.numcols) return ; pageno++ ; break ; case IS_FILE : linect = 0 ; break ; case IS_LINE : FPUTS(") showline\n") ; break ; case IS_PAGE : linect = 0 ; FPRINTF(ofp, "(%1d) endpage\n", tpn) ; } } // Display a string with PostScript-sensitive characters escaped. void Print::expand(unsigned char *s) { for (; s && *s; s++) { switch (*s) { case '\\' : FPUTS("\\\\") ; break ; case '(' : FPUTS("\\(") ; break ; case ')' : FPUTS("\\)") ; break ; default : if ((*s < 0x20) || (*s > 0x7e)) FPRINTF(ofp, "\\%03o", *s) ; else if (isprint(*s)) (void) putc(*s, ofp) ; } } } FILE * Print::makecmd(char *fname) { FILE *fp ; // Output stream pointer from popen(). char cmd[MAXLINE] ; // The print command to execute. int isbsd = 1 ; // Default to a BSD print system. if (ofp && input.toprinter) (void) pclose(ofp) ; if (access(PRINTPROG, X_OK) == 0) isbsd = 0 ; // System V system? (void) strcpy(cmd, (isbsd ? "lpr -J " : "lp -t ")) ; (void) strcat(cmd, fname) ; (void) strcat(cmd, " ") ; if (!input.banner) (void) strcat(cmd, "-h ") ; // If no printer name given, try to get the default from the environment. if (!printer_name) { if (isbsd) printer_name = getenv("PRINTER") ; else printer_name = getenv("LPDEST") ; } if (printer_name) { (void) strcat(cmd, (isbsd ? "-P " : "-d ")) ; (void) strcat(cmd, printer_name) ; } if ((fp = popen(cmd, "w")) == NULL) { cerr << "Invalid print command: " << cmd << "\n" ; cerr << "Defaulting to standard output.\n" ; fp = stdout ; } return(fp) ; } Print::Print() { colct = 0 ; // Column count on current page. linect = 0 ; // Line count on current page. pageno = 1 ; // Page number within message. tpn = 0 ; // Total number of pages printed. ofp = NULL ; // No output stream open initially. paper_size = US ; // Paper size - default US. printer_name = NULL ; // Default printer. } void Print::print_extra(void) { int i ; for (i = 0; i < input.addhdr_num; i++) if (input.hdrs[i]) prt.show_text(T_MIXED, input.addhdrs[i], input.hdrs[i]) ; } void Print::psdef(char *name, char *def) // Do a PostScript define. { FPRINTF(ofp, "/%s (", name) ; expand((unsigned char *) def) ; FPUTS(") def\n") ; } void Print::set_defs(void) // Setup PostScript definitions. { int i ; if (input.article) message_for = "Article from" ; else if (input.print_orig && hdr.from) message_for = "From" ; psdef("MailFor", message_for) ; if (input.article && hdr.newsgroups) // User. { for (i = 0; i < strlen(hdr.newsgroups); i++) if (hdr.newsgroups[i] == ',' || hdr.newsgroups[i] == '\0') break ; input.owner = (char *) realloc(input.owner, (unsigned int) i+1) ; (void) strncpy(input.owner, hdr.newsgroups, i) ; input.owner[i] = '\0' ; } else if (input.print_orig && hdr.from) { i = strlen(hdr.from) ; input.owner = (char *) realloc(input.owner, (unsigned int) i+1) ; (void) strncpy(input.owner, hdr.from, i) ; input.owner[i] = '\0' ; } psdef("User", input.owner) ; do_date() ; // TimeNow. if (input.text_doc && input.numnames) hdr.subject = curfname ; psdef("Subject", (hdr.gsubject != NULL) ? hdr.gsubject : hdr.subject) ; // Subject. } // Display the PostScript prologue file for mp. void Print::show_prologue(char *pro) { FILE *cf, *pf ; char buf[MAXLINE], tmpstr[MAXLINE] ; char cpro[MAXPATHLEN] ; // Full pathname of the common prologue file. int t2 ; // Possible extract page or line length. if ((pf = fopen(pro, "r")) == NULL) { (void) sprintf(tmpstr, "%s/%s", input.prologue, pro) ; if ((pf = fopen(tmpstr, "r")) == NULL) { cerr << input.progname << ": Prologue file " << pro << " not found.\n" ; exit(1) ; } } while (fgets(buf, MAXLINE, pf) != NULL) { // Check if the line just read starts with /fullheight // If this is the case, then replace it with the appropriate page height // (A4 or US). if (EQUALN(buf, "/fullwidth")) { if (paper_size == US) FPUTS("/fullwidth 8.5 inch def\n") ; else if (paper_size == A4) FPUTS("/fullwidth 595 def\n") ; } else if (EQUALN(buf, "/fullheight")) { if (paper_size == US) FPUTS("/fullheight 11 inch def\n") ; else if (paper_size == A4) FPUTS("/fullheight 842 def\n") ; } // If "-columns #", "-linelength #" or "-pagelength #" was given on the // command line, then use that value, otherwise get the appropriate value // from the prologue file. else { if (input.plen_given && EQUALN(buf, "%%PageLength")) (void) sprintf(buf, "%%%%PageLength %1d\n", input.plen) ; else if (input.llen_given && EQUALN(buf, "%%LineLength")) (void) sprintf(buf, "%%%%LineLength %1d\n", input.llen) ; else if (input.cols_given && EQUALN(buf, "%%NumCols")) (void) sprintf(buf, "%%%%NumCols %1d\n", input.numcols) ; FPUTS(buf) ; } // If appropriate, extract out the pagelength, linelength or the number of // columns. Note that they might have just been set above. It was simpler to // do it this way. tmpstr[0] = '\0' ; (void) sscanf(buf, "%s %d", tmpstr, &t2) ; if (!strcmp(tmpstr, "%%PageLength")) input.plen = t2 ; // Change the page length. */ else if (!strcmp(tmpstr, "%%LineLength")) input.llen = t2 ; // Change the line length. */ else if (!strcmp(tmpstr, "%%NumCols")) input.numcols = t2 ; // Change the number of columns. */ else if (!strcmp(tmpstr, "%%EndComments")) { // If this is the %%EndComments line from the prologue file, then we // need to read (and output to stdout), the contents of the common // prologue file, mp.common.ps (void) sprintf(cpro, "%s/mp.common.ps", input.prologue) ; if ((cf = fopen(cpro, "r")) == NULL) { cerr << input.progname << ": Common prologue file " << cpro << " not found.\n" ; exit(1) ; } while (fgets(buf, MAXLINE, cf) != NULL) FPUTS(buf) ; (void) fclose(cf) ; } } (void) fclose(pf) ; FPUTS("%%EndProlog\n") ; } void Print::show_text(text_type op, char *hdr, char *str) { static char *fontstr[MAXTTYPES] = { "BoldFont ", // T_BOLD. "BoldFont ", // T_MIXED. NULL, // T_PLAIN. "pf " // T_ROMAN. } ; useline() ; if (fontstr[(int) op]) FPUTS(fontstr[(int) op]) ; start(IS_LINE) ; switch (op) { case T_BOLD : expand((unsigned char *) hdr) ; expand((unsigned char *) str) ; break ; case T_MIXED : expand((unsigned char *) hdr) ; FPUTS(") show pf (") ; expand((unsigned char *) str) ; break ; case T_PLAIN : expand((unsigned char *) str) ; break ; case T_ROMAN : expand((unsigned char *) str) ; } end(IS_LINE) ; } void Print::show_trailer(void) { FPUTS("%%Trailer\n") ; FPRINTF(ofp, "%%%%Pages: %1d\n", prt.tpn) ; } void Print::start(action_type op) { switch (op) { case IS_COL : break ; case IS_FILE : break ; case IS_LINE : (void) putc('(', ofp) ; break ; case IS_PAGE : FPRINTF(ofp, "%%%%Page: ? %1d\n", ++tpn) ; FPRINTF(ofp, "%1d newpage\n", tpn) ; set_defs() ; FPUTS("sf ") ; break ; } } void Print::useline(void) // Called in order to ready a line for printing. { if (++linect > input.plen || input.end_of_page) { end(IS_COL) ; if (colct < input.numcols) return ; colct = 0 ; end(IS_PAGE) ; linect = 1 ; start(IS_PAGE) ; } }