/* * These routines do most of the communicating with the printer. * * LINELENGTH tells the maximum line length to send out. It's been * reduced to 72 because sometimes PostScript files are included in * mail messages and many mailers mutilate longer lines. */ #define LINELENGTH (72) #include "dvips.h" /* The copyright notice in that file is included too! */ #include #include #ifdef OS2 #ifdef _MSC_VER #define popen(pcmd, pmode) _popen(pcmd, pmode) #define pclose(pstream) _pclose(pstream) #endif #endif #ifdef __DJGPP__ #include /* for `isatty' */ #endif /* * The external routines called here: */ #include "protos.h" /* * These are the external variables used by these routines. */ extern integer hh, vv ; extern fontdesctype *curfnt ; extern FILE *bitfile ; extern char *oname ; extern int secure ; extern Boolean reverse ; extern Boolean removecomments ; extern Boolean sendcontrolD, disablecomments, multiplesects ; extern Boolean shiftlowchars ; extern Boolean usesPSfonts, headers_off ; extern Boolean safetyenclose ; extern Boolean cropmarks ; extern Boolean tryepsf ; extern Boolean compressed ; extern Boolean sepfiles ; extern int numcopies ; extern int collatedcopies ; extern integer pagecopies ; extern int totalpages ; extern integer pagenum ; extern Boolean manualfeed ; extern int landscape ; extern int quiet ; extern int prettycolumn ; extern int actualdpi, vactualdpi ; extern char *iname, *nextstring ; extern char *paperfmt ; #ifndef KPATHSEA extern char *headerpath ; extern char *figpath ; #endif extern char errbuf[] ; extern shalfword linepos ; extern struct header_list *ps_fonts_used ; extern char banner[], banner2[] ; extern int gargc ; extern char **gargv ; extern struct papsiz *papsizes ; extern integer hpapersize, vpapersize ; char preamblecomment[256] ; /* usually "TeX output ..." */ #ifdef HPS extern Boolean noprocset, HPS_FLAG ; #endif /* * We need a few statics to take care of things. */ static integer rhh, rvv ; static int instring ; static Boolean lastspecial = 1 ; static shalfword d ; static Boolean popened = 0 ; int lastfont ; /* exported to dospecial to fix rotate.tex problem */ static void chrcmd(char c); /* just a forward declaration */ static char strbuffer[LINELENGTH + 20], *strbp = strbuffer ; static struct papsiz *finpapsiz ; static struct papsiz defpapsiz = { 0, 40258437L, 52099154L, "letter", "" } ; #ifdef CREATIONDATE #if (!defined(VMS) && !defined(MSDOS) && !(defined(OS2) && defined(_MSC_VER)) && !defined(ATARIST)) /* VAXC/MSDOS don't like/need this !! */ #include #include /* time(), at least on BSD Unix */ #endif #include /* asctime() and localtime(), at least on BSD Unix */ static time_t jobtime; #endif /* * This routine copies a file down the pipe. Search path uses the * header path. * * We add code to handle the case of MS-DOS font files. * * Format: 80 {01,02} four byte length in littleendian order data * repeated possibly multiple times. */ static char *hxdata = "0123456789ABCDEF" ; static int infigure ; extern char *infont ; static char possibleDSCLine[81], *dscLinePointer = possibleDSCLine, *dscLineEnd = possibleDSCLine + 80 ; void copyfile_general(char *s, struct header_list *cur_header) { extern char *realnameoffile ; FILE *f = NULL ; int c, prevc = '\n' ; long len ; /* begin DOS EPS code */ int doseps = 0; unsigned long dosepsbegin, dosepsend = 0; int removingBytes = 0 ; char *scanForEnd = 0 ; int scanningFont = 0; /* end DOS EPS code */ #ifdef VMCMS register char *lastdirsep ; register char *trunc_s ; trunc_s = s ; #endif #ifdef MVSXA register char *lastdirsep ; register char *trunc_s ; trunc_s = s ; #endif dscLinePointer = possibleDSCLine ; switch (infigure) { case 1: /* * Look in headerpath too, just in case. This allows common header * or figure files to be installed in the .../ps directory. */ f = search(figpath, s, READBIN) ; if (f == 0) f = search(headerpath, s, READBIN) ; #ifdef VMCMS lastdirsep = strrchr(s, '/') ; if ( NULL != lastdirsep ) trunc_s = lastdirsep + 1 ; (void)sprintf(errbuf, "Couldn't find figure file %s with CMS name %s; continuing.\nNote that an absolute path or a relative path with .. are denied in -R2 mode.", s, trunc_s) ; #else #ifdef MVSXA lastdirsep = strrchr(s, '/') ; if ( NULL != lastdirsep ) trunc_s = lastdirsep + 1 ; (void)sprintf(errbuf, "Couldn't find figure file %s with MVS name %s; continuing.\nNote that an absolute path or a relative path with .. are denied in -R2 mode.", s, trunc_s) ; #else (void)sprintf(errbuf, "Could not find figure file %s; continuing.\nNote that an absolute path or a relative path with .. are denied in -R2 mode.", s) ; #endif #endif break ; #ifndef VMCMS #ifndef MVSXA #ifndef VMS #if !defined(MSDOS) || defined(__DJGPP__) #ifndef ATARIST #ifndef __THINK__ case 2: #ifdef SECURE (void)sprintf(errbuf, "<%s>: Tick filename execution disabled", s) ; #else #ifdef OS2 if (_osmode == OS2_MODE) { #endif if (secure == 0) { (void)sprintf(errbuf, "Execution of <%s> failed ", s) ; f = popen(s, "r") ; if (f != 0) (void)SET_BINARY(fileno(f)) ; } else { (void)sprintf(errbuf,"Secure mode is %d so execute <%s> will not run", secure,s) ; } #ifdef OS2 } #endif #endif break; #endif #endif #endif #endif #endif #endif default: f = search(headerpath, s, READBIN) ; if(cur_header && (cur_header->precode || cur_header->postcode)) { if(f==NULL) f = search(figpath, s, READBIN) ; } (void)sprintf(errbuf, "! Could not find header file %s.\nNote that an absolute path or a relative path with .. are denied in -R2 mode.", s) ; break ; } if (f==NULL) error(errbuf) ; else { if (! quiet) { #if defined(VMCMS) || defined (MVSXA) if (strlen(s) + prettycolumn > STDOUTSIZE) { #else if (strlen(realnameoffile) + prettycolumn > STDOUTSIZE) { #endif fprintf(stderr, "\n") ; prettycolumn = 0 ; } #ifdef VMCMS (void)fprintf(stderr, "<%s>", trunc_s) ; #else #ifdef MVSXA (void)fprintf(stderr, "<%s>", trunc_s) ; #else (void)fprintf(stderr, "<%s>", realnameoffile) ; #endif #endif (void)fflush(stderr) ; #if defined(VMCMS) || defined (MVSXA) prettycolumn += 2 + strlen(s) ; #else prettycolumn += 2 + strlen(realnameoffile) ; #endif } if (linepos != 0) (void)putc('\n', bitfile) ; /* * Suggested by Andrew Trevorrow; don't ever BeginFont a file ending in .enc */ if (infont && strstr(s,".enc")) infont = 0 ; if (! disablecomments) { if (infigure) (void)fprintf(bitfile, "%%%%BeginDocument: %s\n", s) ; else if (infont) (void)fprintf(bitfile, "%%%%BeginFont: %s\n", infont) ; #ifdef HPS else if (noprocset) {} #endif else (void)fprintf(bitfile, "%%%%BeginProcSet: %s 0 0\n", s) ; } if (cur_header && cur_header->precode) { (void)fprintf(bitfile, "%s\n", cur_header->precode) ; free(cur_header->precode) ; } c = getc(f) ; if (c == 0x80) { while (1) { c = getc(f) ; switch(c) { case 1: case 2: len = getc(f) ; len += getc(f) * 256L ; len += getc(f) * 65536L ; len += getc(f) * 256L * 65536 ; if (c == 1) { while (len > 0) { c = getc(f) ; if (c == EOF) { error("premature EOF in MS-DOS font file") ; len = 0 ; } else { if (c == '\r') { /* Mac- or DOS-style text file */ (void)putc('\n', bitfile) ; if ((c = getc(f)) == '\n') /* DOS-style text */ len--; /* consume, but don't generate NL */ else ungetc(c, f); } else (void)putc(c, bitfile) ; len-- ; } } } else { putc('\n', bitfile) ; prevc = 0 ; while (len > 0) { c = getc(f) ; if (c == EOF) { error("premature EOF in MS-DOS font file") ; len = 0 ; } else { (void)putc(hxdata[c >> 4], bitfile) ; (void)putc(hxdata[c & 15], bitfile) ; len-- ; prevc += 2 ; if (prevc >= 76) { putc('\n', bitfile) ; prevc = 0 ; } } } } break ; case 3: goto msdosdone ; default: error("saw type other than 1, 2, or 3 in MS-DOS font file") ; break ; } c = getc(f) ; if (c == EOF) break ; if (c != 0x80) { error("saw non-MSDOS header in MSDOS font file") ; break ; } } msdosdone: prevc = 0 ; } else { /* begin DOS EPS code */ if (c == 'E'+0x80) { if ((getc(f)=='P'+0x80) && (getc(f)=='S'+0x80) && (getc(f)=='F'+0x80)) { doseps = 1; dosepsbegin = getc(f) ; dosepsbegin += getc(f) * 256L ; dosepsbegin += getc(f) * 65536L ; dosepsbegin += getc(f) * 256L * 65536 ; dosepsend = getc(f) ; dosepsend += getc(f) * 256L ; dosepsend += getc(f) * 65536L ; dosepsend += getc(f) * 256L * 65536 ; fseek(f, dosepsbegin, 0); c = getc(f); dosepsend-- ; } else { rewind(f); c = getc(f); } } /* end DOS EPS code */ if (c != EOF) { while (1) { if (c == '\n') { /* end or beginning of line; check DSC */ *dscLinePointer = 0 ; /* make sure we terminate! * might be a new empty line! */ if (strncmp(possibleDSCLine, "%%BeginBinary:", 14) == 0 || strncmp(possibleDSCLine, "%%BeginData:", 12) == 0 || strncmp(possibleDSCLine, "%%BeginFont:", 12) == 0) { integer size = 0 ; char *p = possibleDSCLine ; *dscLinePointer = 0 ; *dscLineEnd = 0 ; if (scanForEnd == 0 && removecomments) (void)fputs(possibleDSCLine, bitfile) ; if (strncmp(possibleDSCLine, "%%BeginFont:", 12) == 0) { /* Theoretically, we could wait until we see the "currentfile eexec" and possibly even check that the following data really looks like binary before we begin verbatim copying, but that would complicate the code beyond our present needs. If we were going to do that much work, this entire chunk of code should probably be rewritten. [dmj@ams.org, 2007/08/20] */ scanForEnd = "%%EndFont"; scanningFont = 1; } else { scanningFont = 0; scanForEnd = 0 ; while (*p != ':') p++ ; p++ ; while (*p && *p <= ' ') p++ ; if ('0' > *p || *p > '9') { /* * No byte count! We need to scan for end binary * or end data, and hope we get it right. Really * the file is malformed. */ scanForEnd = "Yes" ; } while ('0' <= *p && *p <= '9') { size = size * 10 + *p - '0' ; p++ ; } while (*p && *p <= ' ') p++ ; if (*p == 'h' || *p == 'H') /* * Illustrator 8 and 9 have bogus byte counts * for hex data. But if it is hex, we assume * that it is safe to use ASCII scanning, so * we do so. */ scanForEnd = "Yes" ; while (*p > ' ') /* ignore Hex/Binary/ASCII */ p++ ; while (*p && *p <= ' ') p++ ; (void)putc(c, bitfile) ; if (c == '\r') { /* maybe we have a DOS-style text file */ c = getc(f); if (c == '\n') { (void)putc(c, bitfile); dosepsend-- ; } else ungetc(c, f); } if (scanForEnd != 0) { if (strncmp(possibleDSCLine, "%%BeginBinary", 13) == 0) scanForEnd = "%%EndBinary" ; else scanForEnd = "%%EndData" ; } } if (scanForEnd == 0) { if (strncmp(p, "lines", 5) != 0 && strncmp(p, "Lines", 5) != 0) { for (; size>0; size--) { c = getc(f) ; dosepsend-- ; if (c == EOF) error( "! premature end of file in binary section") ; (void)putc(c, bitfile) ; } } else { /* * Count both newlines and returns, and when either * goes over the count, we are done. */ int newlines=0, returns=0 ; while (newlines < size && returns < size) { c = getc(f) ; dosepsend-- ; if (c == EOF) error( "! premature end of file in binary section") ; (void)putc(c, bitfile) ; if (c == '\n') newlines++ ; else if (c == '\r') returns++ ; } /* * If we've seen precisely one too few newlines, * and the next char is a newline, include it too. */ if (returns == newlines + 1) { if ((c = getc(f)) == '\n') { putc(c, bitfile) ; dosepsend-- ; } else { ungetc(c, f); } } } c = getc(f) ; dosepsend-- ; if (c == '\n' || c == '\r') { (void)putc(c, bitfile) ; if (c == '\r') { /* DOS-style text file? */ c = getc(f); dosepsend-- ; if (c == '\n') { putc(c, bitfile); c = getc(f); dosepsend-- ; } } else { c = getc(f) ; dosepsend-- ; } } if (c != '%') { /* try to find %%EndBinary or %%EndData anywhere in the rest of the file, and pretend it worked; this works around various Illustrator bugs. -tgr, 14 June 2003 */ char *m1 = "%%EndData" ; char *m2 = "%%EndBinary" ; char *p1 = m1 ; char *p2 = m2 ; error( " expected to see %%EndBinary at end of data; struggling on") ; while (1) { (void)putc(c, bitfile) ; if (c == '\r' || c == '\n') { if (c == '\r') { /* DOS-style text file? */ c = getc(f); if (c != '\n') ungetc(c, f); else dosepsend-- ; } break ; } c = getc(f) ; dosepsend-- ; if (c == EOF) error( "! premature end of file in binary section") ; /* * By the way, this code can be fooled by things like %%%EndBinary * or even %%EndBi%%EndBinary, but this isn't valid DSC anyway. * This comment is mainly here to prevent anyone else from emulating * this code when doing stream-based substring matching. */ if (c == *p1) { p1++ ; if (*p1 == 0) break ; } else { p1 = m1 ; } if (c == *p2) { p2++ ; if (*p2 == 0) break ; } else { p2 = m2 ; } } } while (1) { (void)putc(c, bitfile) ; if (c == '\r' || c == '\n') { if (c == '\r') { /* DOS-style text file? */ c = getc(f); if (c != '\n') ungetc(c, f); else { (void)putc(c, bitfile) ; dosepsend-- ; } } break ; } c = getc(f) ; removingBytes = 0; dosepsend-- ; if (c == EOF) error( "! premature end of file in binary section") ; } c = getc(f) ; dosepsend-- ; } } else if (scanForEnd && strncmp(possibleDSCLine, scanForEnd, strlen(scanForEnd))==0) { scanForEnd = 0 ; scanningFont = 0; } dscLinePointer = possibleDSCLine ; } else if (dscLinePointer < dscLineEnd) { *dscLinePointer++ = c ; if (removecomments && scanForEnd == 0 && c == '%' && dscLinePointer == possibleDSCLine + 1) { /* % is first char */ c = getc(f) ; if (c == '%' || c == '!') removingBytes = 1 ; if (c != EOF) ungetc(c, f) ; c = '%' ; } } #ifdef VMCMS if (c != 0x37 || scanningFont) { #else #ifdef MVSXA if (c != 0x37 || scanningFont) { #else if (c != 4 || scanningFont) { #endif #endif if (!removingBytes) (void)putc(c, bitfile) ; } prevc = c ; /* begin DOS EPS code */ if (doseps && (dosepsend <= 0)) break; /* stop at end of DOS EPS PostScript section */ /* end DOS EPS code */ c = getc(f) ; dosepsend-- ; if (c == EOF) break ; else if (c == '\r' && ! scanningFont) { c = getc(f); if (c == '\n') { /* DOS-style text file? */ if (!removingBytes) (void)putc('\r', bitfile); dosepsend-- ; } else ungetc(c, f); c = '\n' ; } if (prevc == '\n') removingBytes = 0 ; } } } if (prevc != '\n') (void)putc('\n', bitfile) ; linepos = 0 ; #ifndef VMCMS #ifndef MVSXA #ifndef VMS #if !defined(MSDOS) || defined(__DJGPP__) #ifndef ATARIST #ifndef __THINK__ if (infigure == 2) #ifdef OS2 { if (_osmode == OS2_MODE) (void)pclose(f) ; } #else (void)pclose(f) ; #endif else #endif #endif #endif #endif #endif #endif (void)fclose(f) ; if (cur_header && cur_header->postcode) { (void)fprintf(bitfile, "\n%s", cur_header->postcode) ; free(cur_header->postcode) ; } if (!disablecomments) { if (infigure) (void)fprintf(bitfile, "\n%%%%EndDocument\n") ; else if (infont) (void)fprintf(bitfile, "\n%%%%EndFont\n") ; #ifdef HPS else if (noprocset) {} #endif else (void)fprintf(bitfile, "\n%%%%EndProcSet\n") ; } } } void copyfile(char *s) { copyfile_general(s, NULL) ; } /* * For included PostScript graphics, we use the above routine, but * with no fatal error message. */ void figcopyfile(char *s, int systemtype) { infigure = systemtype ? 2 : 1 ; copyfile(s) ; infigure = 0 ; } /* * This next routine writes out a `special' character. In this case, * we simply put it out, since any special character terminates the * preceding token. */ void specialout(char c) { if (linepos >= LINELENGTH) { (void)putc('\n', bitfile) ; linepos = 0 ; } (void)putc(c, bitfile) ; linepos++ ; lastspecial = 1 ; } void stringend(void) { if (linepos + instring >= LINELENGTH - 2) { (void)putc('\n', bitfile) ; linepos = 0 ; } (void)putc('(', bitfile) ; *strbp = 0 ; (void)fputs(strbuffer, bitfile) ; (void)putc(')', bitfile) ; linepos += instring + 2 ; lastspecial = 1 ; instring = 0 ; strbp = strbuffer ; } #ifdef SHIFTLOWCHARS /* * moving chars 0-32 and 127 to higher positions * is desirable when using some fonts */ int T1Char(int c) { int tmpchr = c; if (shiftlowchars && curfnt->resfont) { if ((tmpchr <= 0x20)&&(tmpchr>=0)) { if (tmpchr < 0x0A) { tmpchr += 0xA1; } else { tmpchr += 0xA3; } } else if (tmpchr == 0x7F) { tmpchr = 0xC4; } } if (curfnt->chardesc[tmpchr].flags2 & EXISTS) tmpchr = c ; return tmpchr; } #endif void scout(unsigned char c) /* string character out */ { /* * Is there room in the buffer? LINELENGTH-6 is used because we * need room for (, ), and a possible four-byte string \000, for * instance. If it is too long, we send out the string. */ if (instring > LINELENGTH-6) { stringend() ; chrcmd('p') ; } #ifdef SHIFTLOWCHARS c=T1Char(c); #endif /* changed next line to hex representation for VMCMS port if (c<' ' || c > 126 || c=='%' ) { */ if ( c<0x20 || c>= 0x7F || c==0x25 ) { *strbp++ = '\\' ; *strbp++ = '0' + ((c >> 6) & 3) ; *strbp++ = '0' + ((c >> 3) & 7) ; *strbp++ = '0' + (c & 7) ; instring += 4 ; } else { #ifdef VMCMS c = ascii2ebcdic[c]; #else #ifdef MVSXA c = ascii2ebcdic[c]; #endif #endif if (c == '(' || c == ')' || c == '\\') { *strbp++ = '\\' ; *strbp++ = c ; instring += 2 ; } else { *strbp++ = c ; instring++ ; } } } static void scout2(int c) { char s[64] ; sprintf(s, "<%04x>p", c) ; cmdout(s) ; } void cmdout(char *s) { int l ; /* hack added by dorab */ if (instring) { stringend(); chrcmd('p'); } l = strlen(s) ; if ((! lastspecial && linepos >= LINELENGTH - 20) || linepos + l >= LINELENGTH) { (void)putc('\n', bitfile) ; linepos = 0 ; lastspecial = 1 ; } else if (! lastspecial) { (void)putc(' ', bitfile) ; linepos++ ; } (void)fputs(s, bitfile) ; linepos += l ; lastspecial = 0 ; } static void chrcmd(char c) { if ((! lastspecial && linepos >= LINELENGTH - 20) || linepos + 2 > LINELENGTH) { (void)putc('\n', bitfile) ; linepos = 0 ; lastspecial = 1 ; } else if (! lastspecial) { (void)putc(' ', bitfile) ; linepos++ ; } (void)putc(c, bitfile) ; linepos++ ; lastspecial = 0 ; } void floatout(float n) { char buf[20] ; (void)sprintf(buf, "%.2f", n) ; cmdout(buf) ; } void doubleout(double n) { char buf[40] ; (void)sprintf(buf, "%g", n) ; cmdout(buf) ; } void numout(integer n) { char buf[10] ; #ifdef SHORTINT (void)sprintf(buf, "%ld", n) ; #else (void)sprintf(buf, "%d", n) ; #endif cmdout(buf) ; } void mhexout(register unsigned char *p, register long len) { register char *hexchar = hxdata ; register int n, k ; while (len > 0) { if (linepos > LINELENGTH - 2) { (void)putc('\n', bitfile) ; linepos = 0 ; } k = (LINELENGTH - linepos) >> 1 ; if (k > len) k = len ; len -= k ; linepos += (k << 1) ; while (k--) { n = *p++ ; (void)putc(hexchar[n >> 4], bitfile) ; (void)putc(hexchar[n & 15], bitfile) ; } } } void fontout(int n) { char buf[6] ; if (instring) { stringend() ; chrcmd('p') ; } makepsname(buf, n) ; cmdout(buf) ; } void hvpos(void) { if (rvv != vv) { if (instring) { stringend() ; numout(hh) ; numout(vv) ; chrcmd('y') ; } else if (rhh != hh) { numout(hh) ; numout(vv) ; chrcmd('a') ; } else { /* hard to get this case, but it's there when you need it! */ numout(vv - rvv) ; chrcmd('x') ; } rvv = vv ; } else if (rhh != hh) { if (instring) { stringend() ; if (hh - rhh < 5 && rhh - hh < 5) { #ifdef VMCMS /* should replace 'p' in non-VMCMS line as well */ chrcmd(ascii2ebcdic[(char)(112 + hh - rhh)]) ; #else #ifdef MVSXA /* should replace 'p' in non-MVSXA line as well */ chrcmd(ascii2ebcdic[(char)(112 + hh - rhh)]) ; #else chrcmd((char)('p' + hh - rhh)) ; #endif #endif } else if (hh - rhh < d + 5 && rhh - hh < 5 - d) { #ifdef VMCMS /* should replace 'g' in non-VMCMS line as well */ chrcmd(ascii2ebcdic[(char)(103 + hh - rhh - d)]) ; #else #ifdef MVSXA /* should replace 'g' in non-MVSXA line as well */ chrcmd(ascii2ebcdic[(char)(103 + hh - rhh - d)]) ; #else chrcmd((char)('g' + hh - rhh - d)) ; #endif #endif d = hh - rhh ; } else { numout(hh - rhh) ; chrcmd('b') ; d = hh - rhh ; } } else { numout(hh - rhh) ; chrcmd('w') ; } } rhh = hh ; } /* * initprinter opens the bitfile and writes the initialization sequence * to it. */ void newline(void) { if (linepos != 0) { (void)fprintf(bitfile, "\n") ; linepos = 0 ; } lastspecial = 1 ; } void nlcmdout(char *s) { newline() ; cmdout(s) ; newline() ; } /* * Is the dimension close enough for a match? We use 5bp * as a match; this is 65536*72.27*5/72 or 328909 scaled points. */ static int indelta(integer i) { if (i < 0) i = -i ; return (i <= 328909) ; } /* * A case-irrelevant string compare. */ int mlower(int c) { if ('A' <= c && c <= 'Z') return c - 'A' + 'a' ; else return c ; } int ncstrcmp(char *a, char *b) { while (*a && (*a == *b || mlower(*a) == mlower(*b))) a++, b++ ; if (*a == 0 && *b == 0) return 0 ; else return 1 ; } /* * Find the paper size. */ void findpapersize(void) { if (finpapsiz == 0) { struct papsiz *ps ; struct papsiz *fps = 0 ; int ih, iv, it ; int mindiff = 0x7fffffff ; if (tryepsf && !landscape) { finpapsiz = &defpapsiz ; hpapersize = defpapsiz.xsize ; vpapersize = defpapsiz.ysize ; return ; } if (cropmarks) { /* * If user wanted crop marks, we increase the size of the page by * a half inch all around. */ if (hpapersize == 0 || vpapersize == 0) { error( "warning: -k crop marks wanted, but no paper size specified; using default") ; if (landscape) { hpapersize = defpapsiz.ysize ; vpapersize = defpapsiz.xsize ; } else { hpapersize = defpapsiz.xsize ; vpapersize = defpapsiz.ysize ; } } hpapersize += 2368143L ; vpapersize += 2368143L ; add_header(CROPHEADER) ; } if (paperfmt && *paperfmt) { for (ps = papsizes; ps; ps = ps->next) if (ncstrcmp(paperfmt, ps->name)==0) finpapsiz = ps ; if (finpapsiz == 0) error("no match for papersize") ; } if (finpapsiz == 0 && hpapersize > 0 && vpapersize > 0) { for (ps=papsizes; ps; ps = ps->next) { ih = ps->xsize-hpapersize ; iv = ps->ysize-vpapersize ; if (ih < 0) ih = -ih ; if (iv < 0) iv = -iv ; it = ih ; if (it < iv) it = iv ; if (it < mindiff) { mindiff = it ; fps = ps ; } } if (indelta(mindiff)) landscape = 0 ; else fps = 0 ; mindiff = 0x7fffffff ; if (fps == 0) { for (ps=papsizes; ps; ps = ps->next) { iv = ps->ysize-hpapersize ; ih = ps->xsize-vpapersize ; if (ih < 0) ih = -ih ; if (iv < 0) iv = -iv ; it = ih ; if (it < iv) it = iv ; if (it < mindiff) { mindiff = it ; fps = ps ; } } if (indelta(mindiff)) landscape = 1 ; else fps = 0 ; if (fps == 0) { for (ps=papsizes; ps; ps = ps->next) { if (ps->ysize == 0 && ps->xsize == 0) { fps = ps ; break ; } } if (fps == 0) { landscape = (hpapersize > vpapersize) ; error( "no match for special paper size found; using default") ; } } } finpapsiz = fps ; } if (finpapsiz == 0) { if (papsizes) finpapsiz = papsizes ; else finpapsiz = &defpapsiz ; /* * But change xsize/ysize to match so bounding box works. */ if (hpapersize && vpapersize) { if (landscape) { finpapsiz->ysize = hpapersize ; finpapsiz->xsize = vpapersize ; } else { finpapsiz->xsize = hpapersize ; finpapsiz->ysize = vpapersize ; } } } /* * Here, there was no papersize special. We set the paper size from * the selected paper format. If the selected paper format has no * sizes, we use the defaults. */ if (hpapersize == 0 || vpapersize == 0) { if (finpapsiz->xsize == 0 || finpapsiz->ysize == 0) { finpapsiz->xsize = defpapsiz.xsize ; finpapsiz->ysize = defpapsiz.ysize ; } if (landscape) { vpapersize = finpapsiz->xsize ; hpapersize = finpapsiz->ysize ; } else { hpapersize = finpapsiz->xsize ; vpapersize = finpapsiz->ysize ; } /* * Here, there was a papersize special, but the selected paper * format has 0 0 for sizes. We set the sizes here so that the * bounding box works. */ } else if (finpapsiz->xsize == 0 || finpapsiz->ysize == 0) { finpapsiz->xsize = hpapersize ; finpapsiz->ysize = vpapersize ; /* * Here, the user specified a size with -t, and there was a * papersize special, and its sizes were greater than zero. * We make sure the sizes are okay. Note that the user must have * specified landscape if this is desired. */ } else if (paperfmt && *paperfmt) { if (landscape) { if (!indelta(vpapersize - finpapsiz->xsize) || !indelta(hpapersize - finpapsiz->ysize)) { if (vpapersize > finpapsiz->xsize || hpapersize > finpapsiz->ysize) error("warning: -t selected paper may be too small") ; else error("note: -t selected paper may be too large") ; } } else { if (!indelta(hpapersize - finpapsiz->xsize) || !indelta(vpapersize - finpapsiz->ysize)) { if (hpapersize > finpapsiz->xsize || vpapersize > finpapsiz->ysize) error("warning: -t selected paper may be too small") ; else error("note: -t selected paper may be too large") ; } } } } } /* * Convert scaled points to PostScript points. This is the same * as return (i * 72 / (65536 * 72.27)), which is the same as * dividing by 65781.76, but we want to round up. */ static int topoints(integer i) { i += 65780L ; return (i / 6578176L)*100 + (i % 6578176) * 100 / 6578176 ; } /* * Send out the special paper stuff. If `hed' is non-zero, only * send out lines starting with `!' else send all other lines out. */ void paperspec(char *s, int hed) { int sendit ; while (*s) { s++ ; if (*s == '\0') return ; if (*s == '!') { s++ ; while (*s == ' ') s++ ; sendit = hed ; } else sendit = ! hed ; if (sendit) { while (*s && *s != '\n') (void)putc(*s++, bitfile) ; putc('\n', bitfile) ; } else { while (*s && *s != '\n') s++ ; } } } char * epsftest(integer bop) { if (tryepsf && paperfmt == 0 && *iname) { findbb(bop+44) ; return nextstring ; } return 0 ; } static char *isepsf = 0 ; static int endprologsent ; void open_output(void) { FILE * pf = NULL; if (*oname != 0) { /* * We check to see if the first character is a exclamation * point, and popen if so. */ if (*oname == '!' || *oname == '|') { #if defined (MSDOS) && !defined (__DJGPP__) error("! can't open output pipe") ; #else #ifdef VMS error("! can't open output pipe") ; #else #ifdef VMCMS error("! can't open output pipe") ; #else #ifdef MVSXA error("! can't open output pipe") ; #else #ifdef __THINK__ error("! can't open output pipe") ; #else #ifdef ATARIST error("! can't open output pipe") ; #else #ifdef OS2 if (_osmode != OS2_MODE) { error("! can't open output pipe") ; } else { #endif #ifdef __DJGPP__ /* Feature: if they pipe to "lpr" and there's no executable by that name anywhere in sight, write to local printer instead. We do this up front, before even trying to popen, because on MS-DOS popen always succeeds for writing (it only opens a temporary file), and by the time we get to actually run the (possibly nonexistent) program in pclose, it's too late to fall back. We don't use kpathsea functions here because they don't know about DOS-specific executable extensions, while we want to be able to find "lpr.exe", "lpr.com", "lpr.bat" etc. */ extern char *__dosexec_find_on_path(const char *, char **, char *) ; extern char **environ ; char *p = oname + 1 ; char found[FILENAME_MAX] ; while (ISSPACE(*p)) p++ ; if (strncmp(p, "lpr", 3) == 0 && (ISSPACE(p[3]) || p[3] == '\0') && !__dosexec_find_on_path(oname+1, (char **)0, found) && !__dosexec_find_on_path(oname+1, environ, found)) pf = fopen("PRN", "w") ; #endif if (pf == NULL && (pf = popen(oname+1, "w")) != NULL) popened = 1; if (pf == NULL) error("! couldn't open output pipe") ; bitfile = pf; #ifdef OS2 } #endif #endif #endif #endif #endif #endif #endif } else { if ((bitfile=fopen(oname,"w"))==NULL) error("! couldn't open PostScript file") ; } } else { bitfile = stdout ; } /* Even PostScript output may include binary characters, so switch bitfile to binary mode. */ if (O_BINARY && !isatty(fileno(bitfile))) SET_BINARY(fileno(bitfile)) ; } void initprinter(sectiontype *sect) { void tell_needed_fonts() ; int n = sect->numpages * pagecopies * collatedcopies ; #ifdef HPS if (!HPS_FLAG) #endif open_output() ; findpapersize() ; if (disablecomments) { (void)fprintf(bitfile, "%%!PS (but not EPSF; comments have been disabled)\n") ; (void)fprintf(stderr, "Warning: no %%%%Page comments generated.\n") ; } else { if (multiplesects) { (void)fprintf(bitfile, "%%!PS (but not EPSF because of memory limits)\n") ; (void)fprintf(stderr, "Warning: no %%%%Page comments generated.\n") ; } else { isepsf = epsftest(sect->bos) ; if (isepsf) (void)fprintf(bitfile, "%%!PS-Adobe-2.0 EPSF-2.0\n") ; else (void)fprintf(bitfile, "%%!PS-Adobe-2.0\n") ; } if (tryepsf && isepsf == 0) error("We tried, but couldn't make it EPSF.") ; (void)fprintf(bitfile, "%%%%Creator: %s\n", banner + 8) ; if (*iname) (void)fprintf(bitfile, "%%%%Title: %s\n", iname) ; #ifdef CREATIONDATE jobtime=time(0); (void)fprintf(bitfile, "%%%%CreationDate: %s", asctime(localtime(&jobtime))) ; #endif if (! isepsf) { /* * Normally, we wouldn't want to add that second field * indicating that the page order is reversed, as per page * 644 of the Red book. But we have to, for many existing * spoolers. */ (void)fprintf(bitfile, "%%%%Pages: %d%s\n", (sepfiles ? n : totalpages), (reverse?" -1":"")) ; (void)fprintf(bitfile, "%%%%PageOrder: %sscend\n", reverse?"De":"A"); } if (landscape) { fprintf(bitfile, "%%%%Orientation: Landscape\n") ; fprintf(bitfile, "%%%%BoundingBox: 0 0 %d %d\n", topoints(finpapsiz->xsize), topoints(finpapsiz->ysize)) ; } else if (isepsf) fprintf(bitfile, "%%%%BoundingBox: %s\n", isepsf) ; else fprintf(bitfile, "%%%%BoundingBox: 0 0 %d %d\n", topoints(finpapsiz->xsize), topoints(finpapsiz->ysize)) ; tell_needed_fonts() ; paperspec(finpapsiz->specdat, 1) ; (void)fprintf(bitfile, "%%%%EndComments\n") ; } { int i, len ; char *p ; /* * Here, too, we have to be careful not to exceed the line length * limitation, if possible. */ (void)fprintf(bitfile, "%%DVIPSWebPage: %s\n", banner2) ; (void)fprintf(bitfile, "%%DVIPSCommandLine:") ; len = 18 ; for (i=0; i ' ') p++ ; if (*p) len += 2 ; len += strlen(gargv[i]) + 1 ; if (len > LINELENGTH) { (void)fprintf(bitfile, "\n%%+") ; len = strlen(gargv[i]) + 3 ; if (*p) len += 2 ; } (void)fprintf(bitfile, (*p ? " \"%s\"" : " %s"), gargv[i]) ; } (void)fprintf(bitfile, "\n%%DVIPSParameters: dpi=%d", actualdpi) ; if (actualdpi != vactualdpi) (void)fprintf(bitfile, "x%d", vactualdpi) ; if (compressed) (void)fprintf(bitfile, ", compressed") ; if (removecomments) (void)fprintf(bitfile, ", comments removed") ; (void)fputc('\n', bitfile) ; } #ifdef VMCMS /* convert preamblecomment to ebcdic so we can read it */ { int i ; for ( i=0 ; preamblecomment[i] ; i++ ) preamblecomment[i] = ascii2ebcdic[preamblecomment[i]] ; } #else #ifdef MVSXA /* IBM: MVS/XA */ { int i ; for ( i=0 ; preamblecomment[i] ; i++ ) preamblecomment[i] = ascii2ebcdic[preamblecomment[i]] ; } #endif /* VMCMS */ #endif (void)fprintf(bitfile, "%%DVIPSSource: %s\n", preamblecomment) ; linepos = 0 ; endprologsent = 0 ; if (safetyenclose) (void)fprintf(bitfile, "/SafetyEnclosure save def\n") ; if (! headers_off) send_headers() ; } void setup(void) { newline() ; if (endprologsent == 0 && !disablecomments) { (void)fprintf(bitfile, "%%%%EndProlog\n") ; (void)fprintf(bitfile, "%%%%BeginSetup\n") ; if (vactualdpi == actualdpi) (void)fprintf(bitfile, "%%%%Feature: *Resolution %ddpi\n", actualdpi) ; else (void)fprintf(bitfile, "%%%%Feature: *Resolution %dx%ddpi\n", actualdpi, vactualdpi) ; if (multiplesects && *(finpapsiz->specdat)) { (void)fprintf(bitfile, "TeXDict begin\n") ; paperspec(finpapsiz->specdat, 0) ; (void)fprintf(bitfile, "end\n") ; } if (manualfeed) (void)fprintf(bitfile, "%%%%Feature: *ManualFeed True\n") ; #ifdef HPS if (!HPS_FLAG) #endif if (multiplesects) (void)fprintf(bitfile, "%%%%EndSetup\n") ; } if (multiplesects && ! disablecomments) (void)fprintf(bitfile, "%%DVIPSBeginSection\n") ; cmdout("TeXDict") ; cmdout("begin") ; if (endprologsent || disablecomments || multiplesects == 0) { (void)fprintf(bitfile, "\n") ; paperspec(finpapsiz->specdat, 0) ; } if (manualfeed) cmdout("@manualfeed") ; if (landscape) cmdout("@landscape") ; if (numcopies != 1) { numout((integer)numcopies) ; cmdout("@copies") ; } cmdout("end") ; if (endprologsent == 0 && !disablecomments) { newline() ; endprologsent = 1 ; #ifdef HPS if (!HPS_FLAG) #endif if (! multiplesects) (void)fprintf(bitfile, "%%%%EndSetup\n") ; } #ifdef HPS if (HPS_FLAG) { fclose(bitfile) ; set_bitfile("body.tmp",0) ; } #endif } /* * cleanprinter is the antithesis of the above routine. */ void cleanprinter(void) { (void)fprintf(bitfile, "\n") ; (void)fprintf(bitfile, "userdict /end-hook known{end-hook}if\n") ; if (safetyenclose) (void)fprintf(bitfile, "SafetyEnclosure restore\n") ; if (!disablecomments) (void)fprintf(bitfile, "%%%%EOF\n") ; if (sendcontrolD) (void)putc(4, bitfile) ; if (ferror(bitfile)) error("Problems with file writing; probably disk full.") ; #if !defined(MSDOS) || defined(__DJGPP__) #ifndef VMS #ifndef MVSXA #ifndef VMCMS #ifndef __THINK__ #ifndef ATARIST #ifdef OS2 if (_osmode == OS2_MODE) #endif if (popened) (void)pclose(bitfile) ; #endif #endif #endif #endif #endif #endif if (popened == 0) (void)fclose(bitfile) ; bitfile = NULL ; } /* this tells dvips that it has no clue where it is. */ static int thispage = 0 ; static integer rulex, ruley ; void psflush(void) { rulex = ruley = rhh = rvv = -314159265 ; lastfont = -1 ; } /* * pageinit initializes the output variables. */ void pageinit(void) { psflush() ; newline() ; thispage++ ; if (!disablecomments) { if (multiplesects) #ifdef SHORTINT (void)fprintf(bitfile, "%%DVIPSSectionPage: %ld\n", pagenum) ; else if (! isepsf) (void)fprintf(bitfile, "%%%%Page: %ld %d\n", pagenum, thispage) ; #else (void)fprintf(bitfile, "%%DVIPSSectionPage: %d\n", pagenum) ; else if (! isepsf) (void)fprintf(bitfile, "%%%%Page: %d %d\n", pagenum, thispage) ; #endif } linepos = 0 ; cmdout("TeXDict") ; cmdout("begin") ; #ifdef HPS if (HPS_FLAG) { cmdout("HPSdict") ; cmdout("begin") ; } #endif if (landscape) cmdout("@landscape") ; numout((integer)pagenum) ; numout((integer)thispage-1) ; cmdout("bop") ; d = 0 ; } /* * This routine ends a page. */ void pageend(void) { if (instring) { stringend() ; chrcmd('p') ; } cmdout("eop") ; cmdout("end") ; #ifdef HPS if (HPS_FLAG) cmdout("end") ; #endif } /* * drawrule draws a rule at the specified position. * It does nothing to save/restore the current position, * or even draw the current string. (Rules are normally * set below the baseline anyway, so this saves us on * output size almost always.) */ void drawrule(integer rw, integer rh) { numout((integer)hh) ; numout((integer)vv) ; if (rw == rulex && rh == ruley) chrcmd('V') ; else { numout((integer)rw) ; numout((integer)rh) ; chrcmd('v') ; rulex = rw ; ruley = rh ; } } /* * drawchar draws a character at the specified position. */ void drawchar(chardesctype *c, int cc) { hvpos() ; if (lastfont != curfnt->psname) { fontout((int)curfnt->psname) ; lastfont = curfnt->psname ; } if (curfnt->codewidth==1) scout((unsigned char)cc) ; else scout2(cc) ; rhh = hh + c->pixelwidth ; /* rvv = rv */ } /* * This routine sends out the document fonts comment. */ void tell_needed_fonts(void) { struct header_list *hl = ps_fonts_used ; char *q ; int roomleft = -1 ; if (hl == 0) return ; while (0 != (q=get_name(&hl))) { if ((int)strlen(q) >= roomleft) { if (roomleft != -1) { fprintf(bitfile, "\n%%%%+") ; roomleft = LINELENGTH - 3 ; } else { fprintf(bitfile, "%%%%DocumentFonts:") ; roomleft = LINELENGTH - 16 ; } } fprintf(bitfile, " %s", q) ; roomleft -= strlen(q) + 1 ; } fprintf(bitfile, "\n") ; }