Back to index

tetex-bin  3.0
output.c
Go to the documentation of this file.
00001 /*
00002  *   These routines do most of the communicating with the printer.
00003  *
00004  *   LINELENGTH tells the maximum line length to send out.  It's been
00005  *   reduced to 72 because sometimes PostScript files are included in
00006  *   mail messages and many mailers mutilate longer lines.
00007  */
00008 #define LINELENGTH (72)
00009 #include "dvips.h" /* The copyright notice in that file is included too! */
00010 #include <ctype.h>
00011 #include <stdlib.h>
00012 
00013 #ifdef OS2
00014 #ifdef _MSC_VER
00015 #define popen(pcmd, pmode)  _popen(pcmd, pmode)
00016 #define pclose(pstream) _pclose(pstream)
00017 #endif
00018 #endif
00019 
00020 #ifdef __DJGPP__
00021 #include <unistd.h>  /* for `isatty' */
00022 #endif
00023 
00024 /*
00025  *   The external routines called here:
00026  */
00027 #include "protos.h"
00028 
00029 /*
00030  *   These are the external variables used by these routines.
00031  */
00032 extern integer hh, vv ;
00033 extern fontdesctype *curfnt ;
00034 extern FILE *bitfile ;
00035 extern char *oname ;
00036 extern Boolean secure ;
00037 extern Boolean reverse ;
00038 extern Boolean removecomments ;
00039 extern Boolean sendcontrolD, disablecomments, multiplesects ;
00040 extern Boolean shiftlowchars ;
00041 extern Boolean usesPSfonts, headers_off ;
00042 extern Boolean safetyenclose ;
00043 extern Boolean cropmarks ;
00044 extern Boolean tryepsf ;
00045 extern Boolean compressed ;
00046 extern Boolean sepfiles ;
00047 extern int numcopies ;
00048 extern int collatedcopies ;
00049 extern integer pagecopies ;
00050 extern int totalpages ;
00051 extern integer pagenum ;
00052 extern Boolean manualfeed ;
00053 extern int landscape ;
00054 extern int quiet ;
00055 extern int prettycolumn ;
00056 extern int actualdpi, vactualdpi ;
00057 extern char *iname, *nextstring ;
00058 extern char *paperfmt ;
00059 #ifndef KPATHSEA
00060 extern char *headerpath ;
00061 extern char *figpath ;
00062 #endif
00063 extern char errbuf[] ;
00064 extern shalfword linepos ;
00065 extern struct header_list *ps_fonts_used ;
00066 extern char banner[], banner2[] ;
00067 extern int gargc ;
00068 extern char **gargv ;
00069 extern struct papsiz *papsizes ;
00070 extern integer hpapersize, vpapersize ;
00071 char preamblecomment[256] ; /* usually "TeX output ..." */
00072 #ifdef HPS
00073 extern Boolean noprocset, HPS_FLAG ;
00074 #endif
00075 /*
00076  *   We need a few statics to take care of things.
00077  */
00078 static integer rhh, rvv ;
00079 static int instring ;
00080 static Boolean lastspecial = 1 ;
00081 static shalfword d ;
00082 static Boolean popened = 0 ;
00083 int lastfont ; /* exported to dospecial to fix rotate.tex problem */
00084 static void chrcmd P1H(char c);        /* just a forward declaration */
00085 static char strbuffer[LINELENGTH + 20], *strbp = strbuffer ;
00086 static struct papsiz *finpapsiz ;
00087 static struct papsiz defpapsiz = {
00088    0, 40258437L, 52099154L, "letter", ""
00089 } ;
00090 #ifdef CREATIONDATE
00091 #if (!defined(VMS) && !defined(MSDOS) && !(defined(OS2) && defined(_MSC_VER)) && !defined(ATARIST))
00092  /* VAXC/MSDOS don't like/need this !! */
00093 #include <sys/types.h>
00094 #include <sys/time.h> /* time(), at least on BSD Unix */
00095 #endif
00096 #include <time.h> /* asctime() and localtime(), at least on BSD Unix */
00097 static time_t jobtime;
00098 #endif
00099 /*
00100  *   This routine copies a file down the pipe.  Search path uses the
00101  *   header path.
00102  *
00103  *   We add code to handle the case of MS-DOS font files.
00104  *
00105  *   Format:  80 {01,02} four byte length in littleendian order data
00106  *   repeated possibly multiple times.
00107  */
00108 static char *hxdata = "0123456789ABCDEF" ;
00109 static int infigure ;
00110 extern char *infont ;
00111 static char possibleDSCLine[81],
00112        *dscLinePointer = possibleDSCLine, *dscLineEnd = possibleDSCLine + 80 ;
00113 void
00114 copyfile P1C(char *, s)
00115 {
00116    FILE *f = NULL ;
00117    int c, prevc = '\n' ;
00118    long len ;
00119    /* begin DOS EPS code */
00120    int doseps = 0;
00121    unsigned long dosepsbegin, dosepsend = 0;
00122    int removingBytes = 0 ;
00123    char *scanForEnd = 0 ;
00124    /* end DOS EPS code */
00125 #ifdef VMCMS
00126    register char *lastdirsep ;
00127    register char *trunc_s ;
00128    trunc_s = s ;
00129 #endif
00130 #ifdef MVSXA
00131    register char *lastdirsep ;
00132    register char *trunc_s ;
00133    trunc_s = s ;
00134 #endif
00135    dscLinePointer = possibleDSCLine ;
00136 
00137    switch (infigure) {
00138    case 1:
00139 /*
00140  *   Look in headerpath too, just in case.  This allows common header
00141  *   or figure files to be installed in the .../ps directory.
00142  */
00143       f = search(figpath, s, READBIN) ;
00144       if (f == 0)
00145          f = search(headerpath, s, READBIN) ;
00146 #ifdef VMCMS
00147       lastdirsep = strrchr(s, '/') ;
00148       if ( NULL != lastdirsep ) trunc_s = lastdirsep + 1 ;
00149       (void)sprintf(errbuf,
00150    "Couldn't find figure file %s with CMS name %s; continuing", s, trunc_s) ;
00151 #else
00152 #ifdef MVSXA
00153       lastdirsep = strrchr(s, '/') ;
00154       if ( NULL != lastdirsep ) trunc_s = lastdirsep + 1 ;
00155       (void)sprintf(errbuf,
00156     "Couldn't find figure file %s with MVS name %s; continuing", s, trunc_s) ;
00157 #else
00158       (void)sprintf(errbuf, "Could not find figure file %s; continuing", s) ;
00159 #endif
00160 #endif
00161       break ;
00162 #ifndef VMCMS
00163 #ifndef MVSXA
00164 #ifndef VMS
00165 #if !defined(MSDOS) || defined(__DJGPP__)
00166 #ifndef ATARIST
00167 #ifndef __THINK__
00168    case 2:
00169 #ifdef SECURE
00170       (void)sprintf(errbuf, "<%s>: Tick filename execution disabled", s) ;
00171 #else
00172 #ifdef OS2
00173       if (_osmode == OS2_MODE) {
00174 #endif
00175       if (secure == 0) {
00176          (void)sprintf(errbuf, "Execution of  <%s> failed ", s) ;
00177          f = popen(s, "r") ;
00178          if (f != 0)
00179             SET_BINARY(fileno(f)) ;
00180        }
00181        else {
00182       (void)sprintf(errbuf,"Secure mode is %d so execute <%s> will not run", secure,s) ;
00183        }
00184 #ifdef OS2
00185       }
00186 #endif
00187 #endif
00188       break;
00189 #endif
00190 #endif
00191 #endif
00192 #endif
00193 #endif
00194 #endif
00195    default:
00196       f = search(headerpath, s, READBIN) ;
00197       (void)sprintf(errbuf, "! Could not find header file %s", s) ;
00198       break ;
00199    }
00200    if (f==NULL)
00201       error(errbuf) ;
00202    else {
00203       if (! quiet) {
00204          if (strlen(s) + prettycolumn > STDOUTSIZE) {
00205             fprintf(stderr, "\n") ;
00206             prettycolumn = 0 ;
00207          }
00208 #ifdef VMCMS
00209          (void)fprintf(stderr, "<%s>", trunc_s) ;
00210 #else
00211 #ifdef MVSXA
00212          (void)fprintf(stderr, "<%s>", trunc_s) ;
00213 #else
00214          (void)fprintf(stderr, "<%s>", s) ;
00215 #endif
00216 #endif
00217          (void)fflush(stderr) ;
00218          prettycolumn += 2 + strlen(s) ;
00219       }
00220       if (linepos != 0)
00221          (void)putc('\n', bitfile) ;
00222 /*
00223  *   Suggested by Andrew Trevorrow; don't ever BeginFont a file ending in .enc
00224  */
00225       if (infont && strstr(s,".enc"))
00226          infont = 0 ;
00227       if (! disablecomments) {
00228          if (infigure)
00229             (void)fprintf(bitfile, "%%%%BeginDocument: %s\n", s) ;
00230          else if (infont)
00231             (void)fprintf(bitfile, "%%%%BeginFont: %s\n", infont) ;
00232 #ifdef HPS
00233          else if (noprocset) {}
00234 #endif
00235          else
00236             (void)fprintf(bitfile, "%%%%BeginProcSet: %s 0 0\n", s) ;
00237       }
00238       c = getc(f) ;
00239       if (c == 0x80) {
00240          while (1) {
00241             c = getc(f) ;
00242             switch(c) {
00243 case 1:
00244 case 2:
00245                len = getc(f) ;
00246                len += getc(f) * 256L ;
00247                len += getc(f) * 65536L ;
00248                len += getc(f) * 256L * 65536 ;
00249                if (c == 1) {
00250                   while (len > 0) {
00251                      c = getc(f) ;
00252                      if (c == EOF) {
00253                         error("premature EOF in MS-DOS font file") ;
00254                         len = 0 ;
00255                      } else {
00256                       if (c == '\r') { /* Mac- or DOS-style text file */
00257                            (void)putc('\n', bitfile) ;
00258                         if ((c = getc(f)) == '\n') /* DOS-style text */
00259                            len--; /* consume, but don't generate NL */
00260                         else
00261                            ungetc(c, f);
00262                      }
00263                         else
00264                            (void)putc(c, bitfile) ;
00265                         len-- ;
00266                      }
00267                   }
00268                } else {
00269                   putc('\n', bitfile) ;
00270                   prevc = 0 ;
00271                   while (len > 0) {
00272                      c = getc(f) ;
00273                      if (c == EOF) {
00274                         error("premature EOF in MS-DOS font file") ;
00275                         len = 0 ;
00276                      } else {
00277                         (void)putc(hxdata[c >> 4], bitfile) ;
00278                         (void)putc(hxdata[c & 15], bitfile) ;
00279                         len-- ;
00280                         prevc += 2 ;
00281                         if (prevc >= 76) {
00282                            putc('\n', bitfile) ;
00283                            prevc = 0 ;
00284                         }
00285                      }
00286                   }
00287                }
00288                break ;
00289 case 3:
00290                goto msdosdone ;
00291 default:
00292                error("saw type other than 1, 2, or 3 in MS-DOS font file") ;
00293                break ;
00294             }
00295             c = getc(f) ;
00296             if (c == EOF)
00297                break ;
00298             if (c != 0x80) {
00299                error("saw non-MSDOS header in MSDOS font file") ;
00300                break ;
00301             }
00302          }
00303 msdosdone:
00304          prevc = 0 ;
00305       } else {
00306 /* begin DOS EPS code */
00307          if (c == 'E'+0x80) {
00308             if ((getc(f)=='P'+0x80) && (getc(f)=='S'+0x80)
00309                                    && (getc(f)=='F'+0x80)) {
00310                doseps = 1;
00311                dosepsbegin = getc(f) ;
00312                dosepsbegin += getc(f) * 256L ;
00313                dosepsbegin += getc(f) * 65536L ;
00314                dosepsbegin += getc(f) * 256L * 65536 ;
00315                dosepsend = getc(f) ;
00316                dosepsend += getc(f) * 256L ;
00317                dosepsend += getc(f) * 65536L ;
00318                dosepsend += getc(f) * 256L * 65536 ;
00319                fseek(f, dosepsbegin, 0);
00320                c = getc(f);
00321                dosepsend-- ;
00322             }
00323             else {
00324                rewind(f);
00325                c = getc(f);
00326             }
00327          }
00328 /* end DOS EPS code */
00329          if (c != EOF) {
00330             while (1) {
00331                if (c == '\n') { /* end or beginning of line; check DSC */
00332                   *dscLinePointer = 0 ; /* make sure we terminate!
00333                                          * might be a new empty line! */
00334                   if (strncmp(possibleDSCLine, "%%BeginBinary:", 14) == 0 ||
00335                       strncmp(possibleDSCLine, "%%BeginData:", 12) == 0) {
00336                      integer size = 0 ;
00337                      char *p = possibleDSCLine ;
00338                      *dscLinePointer = 0 ;
00339                      *dscLineEnd = 0 ;
00340                      if (scanForEnd == 0 && removecomments)
00341                         (void)fputs(possibleDSCLine, bitfile) ;
00342                      scanForEnd = 0 ;
00343                      while (*p != ':')
00344                         p++ ;
00345                      p++ ;
00346                      while (*p && *p <= ' ')
00347                         p++ ;
00348                      if ('0' > *p || *p > '9') {
00349                         /*
00350                          *   No byte count!  We need to scan for end binary
00351                          *   or end data, and hope we get it right.  Really
00352                          *   the file is malformed.
00353                          */
00354                         scanForEnd = "Yes" ;
00355                      }
00356                      while ('0' <= *p && *p <= '9') {
00357                         size = size * 10 + *p - '0' ;
00358                         p++ ;
00359                      }
00360                      while (*p && *p <= ' ')
00361                         p++ ;
00362                      if (*p == 'h' || *p == 'H')
00363                         /*
00364                          *   Illustrator 8 and 9 have bogus byte counts
00365                          *   for hex data.  But if it is hex, we assume
00366                          *   that it is safe to use ASCII scanning, so
00367                          *   we do so.
00368                          */
00369                         scanForEnd = "Yes" ;
00370                      while (*p > ' ') /* ignore Hex/Binary/ASCII */
00371                         p++ ;
00372                      while (*p && *p <= ' ')
00373                         p++ ;
00374                      (void)putc(c, bitfile) ;
00375                      if (c == '\r') { /* maybe we have a DOS-style text file */
00376                         c = getc(f);
00377                         if (c == '\n') {
00378                            (void)putc(c, bitfile);
00379                            dosepsend-- ;
00380                         } else
00381                            ungetc(c, f);
00382                      }
00383                      if (scanForEnd != 0) {
00384                         if (strncmp(possibleDSCLine, "%%BeginBinary", 13) == 0)
00385                            scanForEnd = "%%EndBinary" ;
00386                         else
00387                            scanForEnd = "%%EndData" ;
00388                      }
00389                      if (scanForEnd == 0) {
00390                         if (strncmp(p, "lines", 5) != 0 &&
00391                             strncmp(p, "Lines", 5) != 0) {
00392                            for (; size>0; size--) {
00393                               c = getc(f) ;
00394                               dosepsend-- ;
00395                               if (c == EOF)
00396                                  error(
00397                                  "! premature end of file in binary section") ;
00398                               (void)putc(c, bitfile) ;
00399                            }
00400                         } else {
00401                            /*
00402                             *  Count both newlines and returns, and when either
00403                             *  goes over the count, we are done.
00404                             */
00405                            int newlines=0, returns=0 ;
00406                            while (newlines < size && returns < size) {
00407                               c = getc(f) ;
00408                               dosepsend-- ;
00409                               if (c == EOF)
00410                                  error(
00411                                     "! premature end of file in binary section") ;
00412                               (void)putc(c, bitfile) ;
00413                               if (c == '\n')
00414                                  newlines++ ;
00415                               else if (c == '\r')
00416                                  returns++ ;
00417                            }
00418                            /*
00419                             *   If we've seen precisely one too few newlines,
00420                             *   and the next char is a newline, include it too.
00421                             */
00422                            if (returns == newlines + 1) {
00423                               if ((c = getc(f)) == '\n') {
00424                                  putc(c, bitfile) ;
00425                                  dosepsend-- ;
00426                               } else {
00427                                  ungetc(c, f);
00428                               }
00429                            }
00430                         }
00431                         c = getc(f) ;
00432                         dosepsend-- ;
00433                         if (c == '\n' || c == '\r') {
00434                            (void)putc(c, bitfile) ;
00435                         if (c == '\r') { /* DOS-style text file? */
00436                            c = getc(f);
00437                               dosepsend-- ;
00438                            if (c == '\n') {
00439                               putc(c, bitfile);
00440                               c = getc(f);
00441                                  dosepsend-- ;
00442                            }
00443                         } else {
00444                            c = getc(f) ;
00445                               dosepsend-- ;
00446                            }
00447                         }
00448                         if (c != '%') {
00449                            /*   try to find %%EndBinary or %%EndData anywhere
00450                                 in the rest of the file, and pretend it
00451                                 worked; this works around various Illustrator
00452                                 bugs.   -tgr, 14 June 2003                  */
00453                            char *m1 = "%%EndData" ;
00454                            char *m2 = "%%EndBinary" ;
00455                            char *p1 = m1 ;
00456                            char *p2 = m2 ;
00457                            error(
00458                " expected to see %%EndBinary at end of data; struggling on") ;
00459                            while (1) {
00460                               (void)putc(c, bitfile) ;
00461                               if (c == '\r' || c == '\n') {
00462                               if (c == '\r') { /* DOS-style text file? */
00463                                  c = getc(f);
00464                                  if (c != '\n')
00465                                    ungetc(c, f);
00466                                     else
00467                                        dosepsend-- ;
00468                               }
00469                                  break ;
00470                            }
00471                               c = getc(f) ;
00472                               dosepsend-- ;
00473                               if (c == EOF)
00474                                  error(
00475                                  "! premature end of file in binary section") ;
00476  /*
00477   *   By the way, this code can be fooled by things like %%%EndBinary
00478   *   or even %%EndBi%%EndBinary, but this isn't valid DSC anyway.
00479   *   This comment is mainly here to prevent anyone else from emulating
00480   *   this code when doing stream-based substring matching.
00481   */
00482                               if (c == *p1) {
00483                                  p1++ ;
00484                                  if (*p1 == 0)
00485                                     break ;
00486                               } else {
00487                                  p1 = m1 ;
00488                               }
00489                               if (c == *p2) {
00490                                  p2++ ;
00491                                  if (*p2 == 0)
00492                                     break ;
00493                               } else {
00494                                  p2 = m2 ;
00495                               }
00496                            }
00497                         }
00498                         while (1) {
00499                            (void)putc(c, bitfile) ;
00500                            if (c == '\r' || c == '\n') {
00501                            if (c == '\r') { /* DOS-style text file? */
00502                               c = getc(f);
00503                               if (c != '\n')
00504                                 ungetc(c, f);
00505                                  else
00506                                     dosepsend-- ;
00507                            }
00508                               break ;
00509                         }
00510                            c = getc(f) ;
00511                            dosepsend-- ;
00512                            if (c == EOF)
00513                               error(
00514                                  "! premature end of file in binary section") ;
00515                         }
00516                         c = getc(f) ;
00517                         dosepsend-- ;
00518                      }
00519                   } else if (scanForEnd && strncmp(possibleDSCLine, scanForEnd,
00520                                                    strlen(scanForEnd))==0) {
00521                      scanForEnd = 0 ;
00522                   }
00523                   dscLinePointer = possibleDSCLine ;
00524                } else if (dscLinePointer < dscLineEnd) {
00525                   *dscLinePointer++ = c ;
00526                   if (removecomments && scanForEnd == 0 &&
00527                       c == '%' && dscLinePointer == possibleDSCLine + 1) {
00528                      /* % is first char */
00529                      c = getc(f) ;
00530                      if (c == '%' || c == '!')
00531                         removingBytes = 1 ;
00532                      if (c != EOF)
00533                         ungetc(c, f) ;
00534                      c = '%' ;
00535                   }
00536                }
00537 #ifdef VMCMS
00538                if (c != 0x37 ) {
00539 #else
00540 #ifdef MVSXA
00541                if (c != 0x37 ) {
00542 #else
00543                if (c != 4) {
00544 #endif
00545 #endif
00546                   if (!removingBytes)
00547                      (void)putc(c, bitfile) ;
00548                }
00549                prevc = c ;
00550 /* begin DOS EPS code */
00551                if (doseps && (dosepsend <= 0))
00552                   break;      /* stop at end of DOS EPS PostScript section */
00553 /* end DOS EPS code */
00554                c = getc(f) ;
00555                dosepsend-- ;
00556                if (c == EOF)
00557                   break ;
00558                else if (c == '\r') {
00559                 c = getc(f);
00560                 if (c == '\n') { /* DOS-style text file? */
00561                    if (!removingBytes) (void)putc('\r', bitfile);
00562                      dosepsend-- ;
00563                 } else
00564                    ungetc(c, f);
00565                   c = '\n' ;
00566               }
00567                if (prevc == '\n')
00568                   removingBytes = 0 ;
00569             }
00570          }
00571       }
00572       if (prevc != '\n')
00573          (void)putc('\n', bitfile) ;
00574       linepos = 0 ;
00575 #ifndef VMCMS
00576 #ifndef MVSXA
00577 #ifndef VMS
00578 #if !defined(MSDOS) || defined(__DJGPP__)
00579 #ifndef ATARIST
00580 #ifndef __THINK__
00581       if (infigure == 2)
00582 #ifdef OS2
00583          {
00584             if (_osmode == OS2_MODE)
00585                (void)pclose(f) ;
00586          }
00587 #else
00588          (void)pclose(f) ;
00589 #endif
00590       else
00591 #endif
00592 #endif
00593 #endif
00594 #endif
00595 #endif
00596 #endif
00597          (void)fclose(f) ;
00598       if (!disablecomments) {
00599          if (infigure)
00600             (void)fprintf(bitfile, "\n%%%%EndDocument\n") ;
00601          else if (infont)
00602             (void)fprintf(bitfile, "\n%%%%EndFont\n") ;
00603 #ifdef HPS
00604          else if (noprocset) {}
00605 #endif
00606          else
00607             (void)fprintf(bitfile, "\n%%%%EndProcSet\n") ;
00608       }
00609    }
00610 }
00611 
00612 /*
00613  *   For included PostScript graphics, we use the above routine, but
00614  *   with no fatal error message.
00615  */
00616 void figcopyfile P2C(char *, s, int, systemtype)
00617 {
00618    infigure = systemtype ? 2 : 1 ;
00619    copyfile(s) ;
00620    infigure = 0 ;
00621 }
00622 /*
00623  *   This next routine writes out a `special' character.  In this case,
00624  *   we simply put it out, since any special character terminates the
00625  *   preceding token.
00626  */
00627 void
00628 specialout P1C(char, c)
00629 {
00630    if (linepos >= LINELENGTH) {
00631       (void)putc('\n', bitfile) ;
00632       linepos = 0 ;
00633    }
00634    (void)putc(c, bitfile) ;
00635    linepos++ ;
00636    lastspecial = 1 ;
00637 }
00638 
00639 void
00640 stringend P1H(void)
00641 {
00642    if (linepos + instring >= LINELENGTH - 2) {
00643       (void)putc('\n', bitfile) ;
00644       linepos = 0 ;
00645    }
00646    (void)putc('(', bitfile) ;
00647    *strbp = 0 ;
00648    (void)fputs(strbuffer, bitfile) ;
00649    (void)putc(')', bitfile) ;
00650    linepos += instring + 2 ;
00651    lastspecial = 1 ;
00652    instring = 0 ;
00653    strbp = strbuffer ;
00654 }
00655 
00656 #ifdef SHIFTLOWCHARS
00657 /* 
00658  *   moving chars 0-32 and 127 to higher positions
00659  *   is desirable when using some fonts
00660  */
00661 int T1Char P1C(int, c)
00662 {
00663   int tmpchr = c;
00664   if (shiftlowchars && curfnt->resfont) {
00665     if ((tmpchr <= 0x20)&&(tmpchr>=0)) {
00666       if (tmpchr < 0x0A) {
00667         tmpchr += 0xA1;
00668       }
00669       else {
00670         tmpchr += 0xA3;
00671       }
00672     }
00673     else if (tmpchr == 0x7F) {
00674       tmpchr = 0xC4;
00675     }
00676   }
00677   if (curfnt->chardesc[tmpchr].flags2 & EXISTS)
00678     tmpchr = c ;
00679   return tmpchr;
00680 }
00681 #endif
00682 
00683 void
00684 scout P1C(unsigned char, c)   /* string character out */
00685 {
00686 /*
00687  *   Is there room in the buffer?  LINELENGTH-6 is used because we
00688  *   need room for (, ), and a possible four-byte string \000, for
00689  *   instance.  If it is too long, we send out the string.
00690  */
00691    if (instring > LINELENGTH-6) {
00692       stringend() ;
00693       chrcmd('p') ;
00694    }
00695 #ifdef SHIFTLOWCHARS
00696    c=T1Char(c);
00697 #endif
00698 /*  changed next line to hex representation for VMCMS port
00699    if (c<' ' || c > 126 || c=='%' ) {
00700 */
00701    if ( c<0x20 || c>= 0x7F || c==0x25 ) {
00702       *strbp++ = '\\' ;
00703       *strbp++ = '0' + ((c >> 6) & 3) ;
00704       *strbp++ = '0' + ((c >> 3) & 7) ;
00705       *strbp++ = '0' + (c & 7) ;
00706       instring += 4 ;
00707    } else {
00708 #ifdef VMCMS
00709      c = ascii2ebcdic[c];
00710 #else
00711 #ifdef MVSXA
00712      c = ascii2ebcdic[c];
00713 #endif
00714 #endif
00715      if (c == '(' || c == ')' || c == '\\') {
00716        *strbp++ = '\\' ;
00717        *strbp++ = c ;
00718        instring += 2 ;
00719      } else {
00720        *strbp++ = c ;
00721        instring++ ;
00722      }
00723    }
00724 }
00725 
00726 void
00727 scout2 P1C(int, c)
00728 {
00729    char s[64] ;
00730 
00731    sprintf(s, "<%04x>p", c) ;
00732    cmdout(s) ;
00733 }
00734 
00735 void
00736 cmdout P1C(char *, s)
00737 {
00738    int l ;
00739 
00740    /* hack added by dorab */
00741    if (instring) {
00742         stringend();
00743         chrcmd('p');
00744    }
00745    l = strlen(s) ;
00746    if ((! lastspecial && linepos >= LINELENGTH - 20) ||
00747            linepos + l >= LINELENGTH) {
00748       (void)putc('\n', bitfile) ;
00749       linepos = 0 ;
00750       lastspecial = 1 ;
00751    } else if (! lastspecial) {
00752       (void)putc(' ', bitfile) ;
00753       linepos++ ;
00754    }
00755    (void)fputs(s, bitfile) ;
00756    linepos += l ;
00757    lastspecial = 0 ;
00758 }
00759 
00760 
00761 static void
00762 chrcmd P1C(char, c)
00763 {
00764    if ((! lastspecial && linepos >= LINELENGTH - 20) ||
00765        linepos + 2 > LINELENGTH) {
00766       (void)putc('\n', bitfile) ;
00767       linepos = 0 ;
00768       lastspecial = 1 ;
00769    } else if (! lastspecial) {
00770       (void)putc(' ', bitfile) ;
00771       linepos++ ;
00772    }
00773    (void)putc(c, bitfile) ;
00774    linepos++ ;
00775    lastspecial = 0 ;
00776 }
00777 
00778 void
00779 floatout P1C(float, n)
00780 {
00781    char buf[20] ;
00782 
00783    (void)sprintf(buf, "%.2f", n) ;
00784    cmdout(buf) ;
00785 }
00786 
00787 void doubleout P1C(double, n)
00788 {
00789    char buf[40] ;
00790 
00791    (void)sprintf(buf, "%g", n) ;
00792    cmdout(buf) ;
00793 }
00794 
00795 void
00796 numout P1C(integer, n)
00797 {
00798    char buf[10] ;
00799 
00800 #ifdef SHORTINT
00801    (void)sprintf(buf, "%ld", n) ;
00802 #else
00803    (void)sprintf(buf, "%d", n) ;
00804 #endif
00805    cmdout(buf) ;
00806 }
00807 
00808 void
00809 mhexout P2C(register unsigned char *, p,
00810            register long, len)
00811 {
00812    register char *hexchar = hxdata ;
00813    register int n, k ;
00814 
00815    while (len > 0) {
00816       if (linepos > LINELENGTH - 2) {
00817          (void)putc('\n', bitfile) ;
00818          linepos = 0 ;
00819       }
00820       k = (LINELENGTH - linepos) >> 1 ;
00821       if (k > len)
00822          k = len ;
00823       len -= k ;
00824       linepos += (k << 1) ;
00825       while (k--) {
00826          n = *p++ ;
00827          (void)putc(hexchar[n >> 4], bitfile) ;
00828          (void)putc(hexchar[n & 15], bitfile) ;
00829       }
00830    }
00831 }
00832 
00833 void
00834 fontout P1C(int, n)
00835 {
00836    char buf[6] ;
00837 
00838    if (instring) {
00839       stringend() ;
00840       chrcmd('p') ;
00841    }
00842    makepsname(buf, n) ;
00843    cmdout(buf) ;
00844 }
00845 
00846 void
00847 hvpos P1H(void)
00848 {
00849    if (rvv != vv) {
00850       if (instring) {
00851          stringend() ;
00852          numout(hh) ;
00853          numout(vv) ;
00854          chrcmd('y') ;
00855       } else if (rhh != hh) {
00856          numout(hh) ;
00857          numout(vv) ;
00858          chrcmd('a') ;
00859       } else { /* hard to get this case, but it's there when you need it! */
00860          numout(vv - rvv) ;
00861          chrcmd('x') ;
00862       }
00863       rvv = vv ;
00864    } else if (rhh != hh) {
00865       if (instring) {
00866          stringend() ;
00867          if (hh - rhh < 5 && rhh - hh < 5) {
00868 #ifdef VMCMS /*  should replace 'p' in non-VMCMS line as well */
00869             chrcmd(ascii2ebcdic[(char)(112 + hh - rhh)]) ;
00870 #else
00871 #ifdef MVSXA /*  should replace 'p' in non-MVSXA line as well */
00872             chrcmd(ascii2ebcdic[(char)(112 + hh - rhh)]) ;
00873 #else
00874             chrcmd((char)('p' + hh - rhh)) ;
00875 #endif
00876 #endif
00877          } else if (hh - rhh < d + 5 && rhh - hh < 5 - d) {
00878 #ifdef VMCMS /* should replace 'g' in non-VMCMS line as well  */
00879             chrcmd(ascii2ebcdic[(char)(103 + hh - rhh - d)]) ;
00880 #else
00881 #ifdef MVSXA /* should replace 'g' in non-MVSXA line as well  */
00882             chrcmd(ascii2ebcdic[(char)(103 + hh - rhh - d)]) ;
00883 #else
00884             chrcmd((char)('g' + hh - rhh - d)) ;
00885 #endif
00886 #endif
00887             d = hh - rhh ;
00888          } else {
00889             numout(hh - rhh) ;
00890             chrcmd('b') ;
00891             d = hh - rhh ;
00892          }
00893       } else {
00894          numout(hh - rhh) ;
00895          chrcmd('w') ;
00896       }
00897    }
00898    rhh = hh ;
00899 }
00900 
00901 /*
00902  *   initprinter opens the bitfile and writes the initialization sequence
00903  *   to it.
00904  */
00905 void newline P1H(void)
00906 {
00907    if (linepos != 0) {
00908       (void)fprintf(bitfile, "\n") ;
00909       linepos = 0 ;
00910    }
00911    lastspecial = 1 ;
00912 }
00913 
00914 void
00915 nlcmdout P1C(char *, s)
00916 {
00917    newline() ;
00918    cmdout(s) ;
00919    newline() ;
00920 }
00921 /*
00922  *   Is the dimension close enough for a match?  We use a quarter inch
00923  *   as a match; this is 65536*72.27/4 or 1,184,072 scaled points.
00924  */
00925 static int indelta P1C(integer, i)
00926 {
00927    if (i < 0)
00928       i = -i ;
00929    return (i <= 1184072) ;
00930 }
00931 /*
00932  *   A case-irrelevant string compare.
00933  */
00934 int mlower P1C(int, c)
00935 {
00936    if ('A' <= c && c <= 'Z')
00937       return c - 'A' + 'a' ;
00938    else
00939       return c ;
00940 }
00941 int ncstrcmp P2C(char *, a, char *, b)
00942 {
00943    while (*a && (*a == *b ||
00944                        mlower(*a) == mlower(*b)))
00945       a++, b++ ;
00946    if (*a == 0 && *b == 0)
00947       return 0 ;
00948    else
00949       return 1 ;
00950 }
00951 /*
00952  *   Find the paper size.
00953  */
00954 void findpapersize P1H(void) {
00955    if (finpapsiz == 0) {
00956       struct papsiz *ps ;
00957 
00958       if (tryepsf && !landscape) {
00959          finpapsiz = &defpapsiz ;
00960          hpapersize = defpapsiz.xsize ;
00961          vpapersize = defpapsiz.ysize ;
00962          return ;
00963       }
00964       if (cropmarks) {
00965 /*
00966  *   If user wanted crop marks, we increase the size of the page by
00967  *   a half inch all around.
00968  */
00969          if (hpapersize == 0 || vpapersize == 0) {
00970             error(
00971  "warning: -k crop marks wanted, but no paper size specified; using default") ;
00972             if (landscape) {
00973                hpapersize = defpapsiz.ysize ;
00974                vpapersize = defpapsiz.xsize ;
00975             } else {
00976                hpapersize = defpapsiz.xsize ;
00977                vpapersize = defpapsiz.ysize ;
00978             }
00979          }
00980          hpapersize += 2368143L ;
00981          vpapersize += 2368143L ;
00982          add_header(CROPHEADER) ;
00983       }
00984       if (paperfmt && *paperfmt) {
00985          for (ps = papsizes; ps; ps = ps->next)
00986             if (ncstrcmp(paperfmt, ps->name)==0)
00987                finpapsiz = ps ;
00988          if (finpapsiz == 0)
00989             error("no match for papersize") ;
00990       }
00991       if (finpapsiz == 0 && hpapersize > 0 && vpapersize > 0) {
00992          for (ps=papsizes; ps; ps = ps->next) {
00993             if (indelta(ps->xsize-hpapersize) &&
00994                 indelta(ps->ysize-vpapersize)) {
00995                landscape = 0 ;
00996                break ;
00997             }
00998          }
00999          if (ps == 0) {
01000             for (ps=papsizes; ps; ps = ps->next) {
01001                if (indelta(ps->ysize-hpapersize) &&
01002                    indelta(ps->xsize-vpapersize)) {
01003                   landscape = 1 ;
01004                   break ;
01005                }
01006             }
01007             if (ps == 0) {
01008                for (ps=papsizes; ps; ps = ps->next) {
01009                   if (ps->ysize == 0 && ps->xsize == 0)
01010                      break ;
01011                }
01012                if (ps == 0) {
01013                   landscape = (hpapersize > vpapersize) ;
01014                   error(
01015                     "no match for special paper size found; using default") ;
01016                }
01017             }
01018          }
01019          finpapsiz = ps ;
01020       }
01021       if (finpapsiz == 0) {
01022          if (papsizes)
01023             finpapsiz = papsizes ;
01024          else
01025             finpapsiz = &defpapsiz ;
01026 /*
01027  *   But change xsize/ysize to match so bounding box works.
01028  */
01029          if (hpapersize && vpapersize) {
01030             if (landscape) {
01031                finpapsiz->ysize = hpapersize ;
01032                finpapsiz->xsize = vpapersize ;
01033             } else {
01034                finpapsiz->xsize = hpapersize ;
01035                finpapsiz->ysize = vpapersize ;
01036             }
01037          }
01038       }
01039 /*
01040  *   Here, there was no papersize special.  We set the paper size from
01041  *   the selected paper format.  If the selected paper format has no
01042  *   sizes, we use the defaults.
01043  */
01044       if (hpapersize == 0 || vpapersize == 0) {
01045          if (finpapsiz->xsize == 0 || finpapsiz->ysize == 0) {
01046             finpapsiz->xsize = defpapsiz.xsize ;
01047             finpapsiz->ysize = defpapsiz.ysize ;
01048          }
01049          if (landscape) {
01050             vpapersize = finpapsiz->xsize ;
01051             hpapersize = finpapsiz->ysize ;
01052          } else {
01053             hpapersize = finpapsiz->xsize ;
01054             vpapersize = finpapsiz->ysize ;
01055          }
01056 /*
01057  *   Here, there was a papersize special, but the selected paper
01058  *   format has 0 0 for sizes.  We set the sizes here so that the
01059  *   bounding box works.
01060  */
01061       } else if (finpapsiz->xsize == 0 || finpapsiz->ysize == 0) {
01062          finpapsiz->xsize = hpapersize ;
01063          finpapsiz->ysize = vpapersize ;
01064 /*
01065  *   Here, the user specified a size with -t, and there was a
01066  *   papersize special, and its sizes were greater than zero.
01067  *   We make sure the sizes are okay.  Note that the user must have
01068  *   specified landscape if this is desired.
01069  */
01070       } else if (paperfmt && *paperfmt) {
01071          if (landscape) {
01072             if (!indelta(vpapersize - finpapsiz->xsize) ||
01073                 !indelta(hpapersize - finpapsiz->ysize)) {
01074                if (vpapersize > finpapsiz->xsize ||
01075                    hpapersize > finpapsiz->ysize)
01076                   error("warning: -t selected paper may be too small") ;
01077                else
01078                   error("note: -t selected paper may be too large") ;
01079             }
01080          } else {
01081             if (!indelta(hpapersize - finpapsiz->xsize) ||
01082                 !indelta(vpapersize - finpapsiz->ysize)) {
01083                if (hpapersize > finpapsiz->xsize ||
01084                    vpapersize > finpapsiz->ysize)
01085                   error("warning: -t selected paper may be too small") ;
01086                else
01087                   error("note: -t selected paper may be too large") ;
01088             }
01089          }
01090       }
01091    }
01092 }
01093 /*
01094  *   Convert scaled points to PostScript points.  This is the same
01095  *   as return (i * 72 / (65536 * 72.27)), which is the same as
01096  *   dividing by 65781.76, but we want to round up.
01097  */
01098 static int topoints P1C(integer, i)
01099 {
01100    i += 65780L ;
01101    return (i / 6578176L)*100 + (i % 6578176) * 100 / 6578176 ;
01102 }
01103 /*
01104  *   Send out the special paper stuff.  If `hed' is non-zero, only
01105  *   send out lines starting with `!' else send all other lines out.
01106  */
01107 void paperspec P2C(char *, s, int, hed)
01108 {
01109    int sendit ;
01110 
01111    while (*s) {
01112       s++ ;
01113       if (*s == '\0')
01114          return ;
01115       if (*s == '!') {
01116          s++ ;
01117          while (*s == ' ') s++ ;
01118          sendit = hed ;
01119       } else
01120          sendit = ! hed ;
01121       if (sendit) {
01122          while (*s && *s != '\n')
01123             (void)putc(*s++, bitfile) ;
01124          putc('\n', bitfile) ;
01125       } else {
01126          while (*s && *s != '\n')
01127             s++ ;
01128       }
01129    }
01130 }
01131 char *epsftest P1C(integer, bop)
01132 {
01133    if (tryepsf && paperfmt == 0 && *iname) {
01134       findbb(bop+44) ;
01135       return nextstring ;
01136    }
01137    return 0 ;
01138 }
01139 static char *isepsf = 0 ;
01140 static int endprologsent ;
01141 void open_output P1H(void) {
01142    FILE * pf = NULL;
01143    if (*oname != 0) {
01144 /*
01145  *   We check to see if the first character is a exclamation
01146  *   point, and popen if so.
01147  */
01148       if (*oname == '!' || *oname == '|') {
01149 #if defined (MSDOS) && !defined (__DJGPP__)
01150             error("! can't open output pipe") ;
01151 #else
01152 #ifdef VMS
01153             error("! can't open output pipe") ;
01154 #else
01155 #ifdef VMCMS
01156             error("! can't open output pipe") ;
01157 #else
01158 #ifdef MVSXA
01159             error("! can't open output pipe") ;
01160 #else
01161 #ifdef __THINK__
01162             error("! can't open output pipe") ;
01163 #else
01164 #ifdef ATARIST
01165             error("! can't open output pipe") ;
01166 #else
01167 #ifdef OS2
01168          if (_osmode != OS2_MODE) {
01169             error("! can't open output pipe") ;
01170          } else {
01171 #endif
01172 #ifdef __DJGPP__
01173         /* Feature: if they pipe to "lpr" and there's no executable by
01174            that name anywhere in sight, write to local printer instead.
01175 
01176            We do this up front, before even trying to popen, because on
01177            MS-DOS popen always succeeds for writing (it only opens a
01178            temporary file), and by the time we get to actually run the
01179            (possibly nonexistent) program in pclose, it's too late to
01180            fall back.
01181 
01182            We don't use kpathsea functions here because they don't
01183            know about DOS-specific executable extensions, while we
01184            want to be able to find "lpr.exe", "lpr.com", "lpr.bat" etc.  */
01185         extern char *__dosexec_find_on_path(const char *,
01186                                             char **, char *) ;
01187         extern char **environ ;
01188         char *p = oname + 1 ;
01189         char found[FILENAME_MAX] ;
01190 
01191         while (ISSPACE(*p))
01192           p++ ;
01193         if (strncmp(p, "lpr", 3) == 0 && (ISSPACE(p[3]) || p[3] == '\0')
01194             && !__dosexec_find_on_path(oname+1, (char **)0, found)
01195             && !__dosexec_find_on_path(oname+1, environ, found))
01196            pf = fopen("PRN", "w") ;
01197 #endif
01198         if (pf == NULL && (pf = popen(oname+1, "w")) != NULL)
01199            popened = 1;
01200          if (pf == NULL)
01201             error("! couldn't open output pipe") ;
01202         bitfile = pf;
01203 #ifdef OS2
01204          }
01205 #endif
01206 #endif
01207 #endif
01208 #endif
01209 #endif
01210 #endif
01211 #endif
01212       } else {
01213          if ((bitfile=fopen(oname,"w"))==NULL)
01214             error("! couldn't open PostScript file") ;
01215       }
01216    } else {
01217       bitfile = stdout ;
01218    }
01219 
01220    /* Even PostScript output may include binary characters, so switch
01221       bitfile to binary mode.  */
01222    if (O_BINARY && !isatty(fileno(bitfile)))
01223       SET_BINARY(fileno(bitfile)) ;
01224 }
01225 void
01226 initprinter P1C(sectiontype *, sect)
01227 {
01228    void tell_needed_fonts() ;
01229    int n = sect->numpages * pagecopies * collatedcopies ;
01230 #ifdef HPS
01231    if (!HPS_FLAG)
01232 #endif
01233       open_output() ;
01234 
01235    findpapersize() ;
01236    if (disablecomments) {
01237       (void)fprintf(bitfile,
01238              "%%!PS (but not EPSF; comments have been disabled)\n") ;
01239       (void)fprintf(stderr, "Warning:  no %%%%Page comments generated.\n") ;
01240    } else {
01241       if (multiplesects) {
01242          (void)fprintf(bitfile,
01243              "%%!PS (but not EPSF because of memory limits)\n") ;
01244          (void)fprintf(stderr, "Warning:  no %%%%Page comments generated.\n") ;
01245       } else {
01246          isepsf = epsftest(sect->bos) ;
01247          if (isepsf)
01248             (void)fprintf(bitfile, "%%!PS-Adobe-2.0 EPSF-2.0\n") ;
01249          else
01250             (void)fprintf(bitfile, "%%!PS-Adobe-2.0\n") ;
01251       }
01252       if (tryepsf && isepsf == 0)
01253          error("We tried, but couldn't make it EPSF.") ;
01254       (void)fprintf(bitfile, "%%%%Creator: %s\n", banner + 8) ;
01255       if (*iname)
01256          (void)fprintf(bitfile, "%%%%Title: %s\n", iname) ;
01257 #ifdef CREATIONDATE
01258       jobtime=time(0);
01259       (void)fprintf(bitfile, "%%%%CreationDate: %s",
01260                                  asctime(localtime(&jobtime))) ;
01261 #endif
01262       if (! isepsf) {
01263 /*
01264  *   Normally, we wouldn't want to add that second field
01265  *   indicating that the page order is reversed, as per page
01266  *   644 of the Red book.  But we have to, for many existing
01267  *   spoolers.
01268  */
01269         (void)fprintf(bitfile, "%%%%Pages: %d%s\n", (sepfiles ? n : totalpages),
01270                                                     (reverse?" -1":"")) ;
01271         (void)fprintf(bitfile, "%%%%PageOrder: %sscend\n", reverse?"De":"A");
01272       }
01273       if (landscape) {
01274          fprintf(bitfile, "%%%%Orientation: Landscape\n") ;
01275          fprintf(bitfile, "%%%%BoundingBox: 0 0 %d %d\n",
01276               topoints(finpapsiz->xsize), topoints(finpapsiz->ysize)) ;
01277       } else if (isepsf)
01278          fprintf(bitfile, "%%%%BoundingBox: %s\n", isepsf) ;
01279       else
01280          fprintf(bitfile, "%%%%BoundingBox: 0 0 %d %d\n",
01281               topoints(finpapsiz->xsize), topoints(finpapsiz->ysize)) ;
01282       tell_needed_fonts() ;
01283       paperspec(finpapsiz->specdat, 1) ;
01284       (void)fprintf(bitfile, "%%%%EndComments\n") ;
01285    }
01286    {
01287       int i, len ;
01288       char *p ;
01289 
01290 /*
01291  *   Here, too, we have to be careful not to exceed the line length
01292  *   limitation, if possible.
01293  */
01294       (void)fprintf(bitfile, "%%DVIPSWebPage: %s\n", banner2) ;
01295       (void)fprintf(bitfile, "%%DVIPSCommandLine:") ;
01296       len = 18 ;
01297       for (i=0; i<gargc; i++) {
01298          p = gargv[i] ;
01299          while (*p > ' ')
01300             p++ ;
01301          if (*p)
01302             len += 2 ;
01303          len += strlen(gargv[i]) + 1 ;
01304          if (len > LINELENGTH) {
01305             (void)fprintf(bitfile, "\n%%+") ;
01306             len = strlen(gargv[i]) + 3 ;
01307             if (*p)
01308                len += 2 ;
01309          }
01310          (void)fprintf(bitfile, (*p ? " \"%s\"" : " %s"), gargv[i]) ;
01311       }
01312       (void)fprintf(bitfile, "\n%%DVIPSParameters: dpi=%d", actualdpi) ;
01313       if (actualdpi != vactualdpi)
01314          (void)fprintf(bitfile, "x%d", vactualdpi) ;
01315       if (compressed)
01316          (void)fprintf(bitfile, ", compressed") ;
01317       if (removecomments)
01318          (void)fprintf(bitfile, ", comments removed") ;
01319       (void)fputc('\n', bitfile) ;
01320    }
01321 #ifdef VMCMS  /* convert preamblecomment to ebcdic so we can read it */
01322    {
01323       int i ;
01324       for ( i=0 ; preamblecomment[i] ; i++ )
01325           preamblecomment[i] = ascii2ebcdic[preamblecomment[i]] ;
01326    }
01327 #else
01328 #ifdef MVSXA   /* IBM: MVS/XA */
01329    {
01330       int i ;
01331       for ( i=0 ; preamblecomment[i] ; i++ )
01332           preamblecomment[i] = ascii2ebcdic[preamblecomment[i]] ;
01333    }
01334 #endif  /* VMCMS */
01335 #endif
01336    (void)fprintf(bitfile, "%%DVIPSSource: %s\n", preamblecomment) ;
01337    linepos = 0 ;
01338    endprologsent = 0 ;
01339    if (safetyenclose)
01340       (void)fprintf(bitfile, "/SafetyEnclosure save def\n") ;
01341    if (! headers_off)
01342       send_headers() ;
01343 }
01344 void setup P1H(void) {
01345    newline() ;
01346    if (endprologsent == 0 && !disablecomments) {
01347       (void)fprintf(bitfile, "%%%%EndProlog\n") ;
01348       (void)fprintf(bitfile, "%%%%BeginSetup\n") ;
01349       if (vactualdpi == actualdpi)
01350          (void)fprintf(bitfile, "%%%%Feature: *Resolution %ddpi\n",
01351                                            actualdpi) ;
01352       else
01353          (void)fprintf(bitfile, "%%%%Feature: *Resolution %dx%ddpi\n",
01354                                            actualdpi, vactualdpi) ;
01355       if (multiplesects && *(finpapsiz->specdat)) {
01356          (void)fprintf(bitfile, "TeXDict begin\n") ;
01357          paperspec(finpapsiz->specdat, 0) ;
01358          (void)fprintf(bitfile, "end\n") ;
01359       }
01360       if (manualfeed)
01361          (void)fprintf(bitfile, "%%%%Feature: *ManualFeed True\n") ;
01362 #ifdef HPS
01363       if (!HPS_FLAG)
01364 #endif
01365       if (multiplesects)
01366          (void)fprintf(bitfile, "%%%%EndSetup\n") ;
01367    }
01368    if (multiplesects && ! disablecomments)
01369       (void)fprintf(bitfile, "%%DVIPSBeginSection\n") ;
01370    cmdout("TeXDict") ;
01371    cmdout("begin") ;
01372    if (endprologsent || disablecomments || multiplesects == 0) {
01373       (void)fprintf(bitfile, "\n") ;
01374       paperspec(finpapsiz->specdat, 0) ;
01375    }
01376    if (manualfeed) cmdout("@manualfeed") ;
01377    if (landscape) cmdout("@landscape") ;
01378    if (numcopies != 1) {
01379       numout((integer)numcopies) ;
01380       cmdout("@copies") ;
01381    }
01382    cmdout("end") ;
01383    if (endprologsent == 0 && !disablecomments) {
01384       newline() ;
01385       endprologsent = 1 ;
01386 #ifdef HPS
01387       if (!HPS_FLAG)
01388 #endif
01389          if (! multiplesects)
01390             (void)fprintf(bitfile, "%%%%EndSetup\n") ;
01391    }
01392 #ifdef HPS
01393   if (HPS_FLAG) {
01394     fclose(bitfile) ;
01395     set_bitfile("body.tmp",0) ;
01396   }
01397 #endif
01398 }
01399 /*
01400  *   cleanprinter is the antithesis of the above routine.
01401  */
01402 void
01403 cleanprinter P1H(void)
01404 {
01405    (void)fprintf(bitfile, "\n") ;
01406    (void)fprintf(bitfile, "userdict /end-hook known{end-hook}if\n") ;
01407    if (safetyenclose)
01408       (void)fprintf(bitfile, "SafetyEnclosure restore\n") ;
01409    if (!disablecomments)
01410       (void)fprintf(bitfile, "%%%%EOF\n") ;
01411    if (sendcontrolD)
01412       (void)putc(4, bitfile) ;
01413    if (ferror(bitfile))
01414       error("Problems with file writing; probably disk full.") ;
01415 #if !defined(MSDOS) || defined(__DJGPP__)
01416 #ifndef VMS
01417 #ifndef MVSXA
01418 #ifndef VMCMS
01419 #ifndef __THINK__
01420 #ifndef ATARIST
01421 #ifdef OS2
01422    if (_osmode == OS2_MODE)
01423 #endif
01424       if (popened)
01425          (void)pclose(bitfile) ;
01426 #endif
01427 #endif
01428 #endif
01429 #endif
01430 #endif
01431 #endif
01432    if (popened == 0)
01433       (void)fclose(bitfile) ;
01434    bitfile = NULL ;
01435 }
01436 
01437 /* this tells dvips that it has no clue where it is. */
01438 static int thispage = 0 ;
01439 static integer rulex, ruley ;
01440 void psflush P1H(void) {
01441    rulex = ruley = rhh = rvv = -314159265 ;
01442    lastfont = -1 ;
01443 }
01444 /*
01445  *   pageinit initializes the output variables.
01446  */
01447 void
01448 pageinit P1H(void)
01449 {
01450    psflush() ;
01451    newline() ;
01452    thispage++ ;
01453    if (!disablecomments)
01454       if (multiplesects)
01455 #ifdef SHORTINT
01456          (void)fprintf(bitfile, "%%DVIPSSectionPage: %ld\n", pagenum) ;
01457       else if (! isepsf)
01458          (void)fprintf(bitfile, "%%%%Page: %ld %d\n", pagenum, thispage) ;
01459 #else
01460          (void)fprintf(bitfile, "%%DVIPSSectionPage: %d\n", pagenum) ;
01461       else if (! isepsf)
01462          (void)fprintf(bitfile, "%%%%Page: %d %d\n", pagenum, thispage) ;
01463 #endif
01464    linepos = 0 ;
01465    cmdout("TeXDict") ;
01466    cmdout("begin") ;
01467 #ifdef HPS
01468    if (HPS_FLAG) {
01469       cmdout("HPSdict") ;
01470       cmdout("begin") ;
01471    }
01472 #endif
01473    if (landscape) cmdout("@landscape") ;
01474    numout((integer)pagenum) ;
01475    numout((integer)thispage-1) ;
01476    cmdout("bop") ;
01477    d = 0 ;
01478 }
01479 
01480 
01481 
01482 /*
01483  *   This routine ends a page.
01484  */
01485 void
01486 pageend P1H(void)
01487 {
01488    if (instring) {
01489       stringend() ;
01490       chrcmd('p') ;
01491    }
01492    cmdout("eop") ;
01493    cmdout("end") ;
01494 #ifdef HPS
01495    if (HPS_FLAG)
01496       cmdout("end") ;
01497 #endif
01498 }
01499 
01500 /*
01501  *   drawrule draws a rule at the specified position.
01502  *   It does nothing to save/restore the current position,
01503  *   or even draw the current string.  (Rules are normally
01504  *   set below the baseline anyway, so this saves us on
01505  *   output size almost always.)
01506  */
01507 void
01508 drawrule P2C(integer, rw, integer, rh)
01509 {
01510    numout((integer)hh) ;
01511    numout((integer)vv) ;
01512    if (rw == rulex && rh == ruley)
01513       chrcmd('V') ;
01514    else {
01515       numout((integer)rw) ;
01516       numout((integer)rh) ;
01517       chrcmd('v') ;
01518       rulex = rw ;
01519       ruley = rh ;
01520    }
01521 }
01522 
01523 /*
01524  *   drawchar draws a character at the specified position.
01525  */
01526 void
01527 drawchar P2C(chardesctype *, c, int, cc)
01528 {
01529    hvpos() ;
01530    if (lastfont != curfnt->psname) {
01531       fontout((int)curfnt->psname) ;
01532       lastfont = curfnt->psname ;
01533    }
01534    if (curfnt->codewidth==1) scout((unsigned char)cc) ;
01535    else scout2(cc) ;
01536    rhh = hh + c->pixelwidth ; /* rvv = rv */
01537 }
01538 /*
01539  *   This routine sends out the document fonts comment.
01540  */
01541 void tell_needed_fonts P1H(void) {
01542    struct header_list *hl = ps_fonts_used ;
01543    char *q ;
01544    int roomleft = -1 ;
01545 
01546    if (hl == 0)
01547       return ;
01548    while (0 != (q=get_name(&hl))) {
01549       if ((int)strlen(q) >= roomleft) {
01550          if (roomleft != -1) {
01551             fprintf(bitfile, "\n%%%%+") ;
01552             roomleft = LINELENGTH - 3 ;
01553          } else {
01554             fprintf(bitfile, "%%%%DocumentFonts:") ;
01555             roomleft = LINELENGTH - 16 ;
01556          }
01557       }
01558       fprintf(bitfile, " %s", q) ;
01559       roomleft -= strlen(q) + 1 ;
01560    }
01561    fprintf(bitfile, "\n") ;
01562 }