home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / PasTeX / dvi2tty.lha / dvistuff.c < prev    next >
C/C++ Source or Header  |  1990-12-18  |  39KB  |  1,334 lines

  1. /*
  2.  * Include files
  3.  */
  4.  
  5. #include "dvi2tty.h"
  6.  
  7. #if defined(VMS) 
  8. #include types.h
  9. #include stat
  10. #else
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #endif
  14.  
  15. #if defined(MSDOS)
  16. #include <math.h>
  17. #endif
  18.  
  19. #include "commands.h"
  20.  
  21.  
  22.  
  23. /*
  24.  * Constant definitions
  25.  */
  26.  
  27. #if defined(VMS) 
  28. #define mseek vmsseek
  29. #define ROUND(a)        (a>=0.0 ?  (int) (a + 0.5) : (int) (a - 0.5) )
  30. #else
  31. #define mseek fseek
  32. #endif
  33.  
  34. #define VERSIONID            2 /* dvi version number that pgm handles      */
  35. #define VERTICALEPSILON 450000L /* crlf when increasing v more than this   */
  36.  
  37. #define rightmargin     152    /* nr of columns allowed to the right of h=0*/
  38. #define leftmargin      -50    /* give some room for negative h-coordinate */
  39. #define LINELEN         203    /* rightmargin - leftmargin + 1 */
  40.  
  41. #define MOVE            TRUE   /* if advancing h when outputing a rule     */
  42. #define STAY            FALSE  /* if not advancing h when outputing a rule */
  43.  
  44. #define absolute        0      /* for seeking in files                     */
  45. #define relative        1
  46.  
  47. #define FORM             12    /* formfeed                                 */
  48. #define SPACE            32    /* space                                    */
  49. #define DEL             127    /* delete                                   */
  50.  
  51. #define LASTCHAR        127    /* max dvi character, above are commands    */
  52.  
  53. #define IMIN(a, b)      (a<b ? a : b)
  54. #define IMAX(a, b)      (a>b ? a : b)
  55.  
  56. #define get1()          num(1)
  57. #define get2()          num(2)
  58. #define get3()          num(3)
  59. #define get4()          num(4)
  60. #define sget1()         snum(1)
  61. #define sget2()         snum(2)
  62. #define sget3()         snum(3)
  63. #define sget4()         snum(4)
  64.  
  65.  
  66.  
  67. /*
  68.  * Structure and variable definitions
  69.  */
  70.  
  71. char *dvistuff = "@(#) dvistuff.c  5.0 29/11/90 M.J.E. Mol (c) 1989, 1990";
  72.  
  73. typedef struct {
  74.     long hh;
  75.     long vv;
  76.     long ww;
  77.     long xx;
  78.     long yy;
  79.     long zz;
  80. } stackitem;
  81.  
  82. typedef struct lineptr {        /* the lines of text to be output to outfile */
  83.     long            vv;                 /* vertical position of the line     */
  84.     int             charactercount;     /* pos of last char on line          */
  85.     struct lineptr *prev;               /* preceding line                    */
  86.     struct lineptr *next;               /* succeeding line                   */
  87.     char            text[LINELEN+1];    /* leftmargin...rightmargin          */
  88. } linetype;
  89.  
  90. typedef struct _font {
  91.     long    num;
  92.     struct _font * next;
  93.     char  * name;
  94. } font;
  95.  
  96.  
  97.  
  98. bool        pageswitchon;       /* true if user-set pages to print           */
  99. bool        sequenceon;         /* false if pagesw-nrs refers to TeX-nrs     */
  100. bool        scascii;            /* if true make Scand. nat. chars right      */
  101. bool        accent;             /* if true output accents etc: \'{e} etc.    */
  102. bool        ttfont;             /* if true we assumed ttfonts, not cmr       */
  103. bool        noffd;              /* if true output ^L instead of formfeed     */
  104.  
  105. int         opcode;             /* dvi-opcodes                               */
  106.  
  107. long        h, v;               /* coordinates, horizontal and vertical      */
  108. long        w, x, y, z;         /* horizontal and vertical amounts           */
  109.  
  110. long        pagecounter;        /* sequence page number counter              */
  111. long        backpointer;        /* pointer for offset to previous page       */
  112. long        pagenr;             /* TeX page number                           */
  113. int         stackmax;           /* stacksize required                        */
  114.  
  115. long        maxpagewidth;       /* width of widest page in file              */
  116. long        charwidth;          /* aprox width of character                  */
  117. long        lineheight = VERTICALEPSILON;
  118.                                 /* aprox height of a line                    */
  119.  
  120. linetype *  currentline;        /* pointer to current line on current page   */
  121. linetype *  firstline;          /* pointer to first line on current page     */
  122. linetype *  lastline;           /* pointer to last line on current page      */
  123. int         firstcolumn;        /* 1st column with something to print        */
  124.  
  125. stackitem * stack;              /* stack for dvi-pushes                      */
  126. int         sptr;               /* stack pointer                             */
  127.  
  128. font * fonts = NULL;            /* List of fontnames defined                 */
  129. int  symbolfont = FALSE;        /* true if font is a symbol font             */
  130.  
  131.  
  132.  
  133. /*
  134.  * Function definitions
  135.  */
  136.  
  137. #if defined(MSDOS)
  138. void            postamble       (void);
  139. void            preamble        (void);
  140. void            walkpages       (void);
  141. void            initpage        (void);
  142. void            dopage          (void);
  143. void            skippage        (void);
  144. void            printpage       (void);
  145. bool            inlist          (long);
  146. void            rule            (bool, long, long);
  147. void            ruleaux         (long, long, char);
  148. long            horizontalmove  (long);
  149. int             skipnops        (void);
  150. linetype    *   getline         (void);
  151. linetype    *   findline        (void);
  152. unsigned long   num             (int);
  153. long            snum            (int);
  154. void            dochar          (char);
  155. void            symchar         (char);
  156. void            normchar        (char);
  157. void            outchar         (char);
  158. void            putcharacter    (long);
  159. void            setchar         (long);
  160. void            fontdef         (int);
  161. void            setfont         (long);
  162. #else
  163. void            postamble       ();
  164. void            preamble        ();
  165. void            walkpages       ();
  166. void            initpage        ();
  167. void            dopage          ();
  168. void            skippage        ();
  169. void            printpage       ();
  170. bool            inlist          ();
  171. void            rule            ();
  172. void            ruleaux         ();
  173. long            horizontalmove  ();
  174. int             skipnops        ();
  175. linetype    *   getline         ();
  176. linetype    *   findline        ();
  177. unsigned long   num             ();
  178. long            snum            ();
  179. void            dochar          ();
  180. void            symchar         ();
  181. void            normchar        ();
  182. void            outchar         ();
  183. void            putcharacter    ();
  184. void            setchar         ();
  185. void            fontdef         ();
  186. void            setfont         ();
  187. #if defined(VMS)
  188. long        vmsseek        ();
  189. long        vms_ftell    ();
  190. long        vms_ungetc    ();
  191. #endif
  192. #endif
  193.  
  194.  
  195.  
  196. /*
  197.  * DVIMAIN -- The main function for processing the dvi file.
  198.  *            Here we assume there are to file pointers: DVIfile and output.
  199.  *            Also we have a list of pages pointed to by 'currentpage',
  200.  *            which is only used (in 'inlist()') when a page list is given.
  201.  */
  202.  
  203. void dvimain()
  204. {
  205.  
  206.     postamble();                            /* seek and process the postamble */
  207.     preamble();                             /* process preamble               */
  208.     /* note that walkpages *must* immediately follow preamble */
  209.     walkpages();                            /* time to do the actual work!    */
  210.  
  211.     return;
  212.  
  213. } /* dvimain */
  214.  
  215.  
  216.  /*
  217.   * POSTAMBLE -- Find and process postamble, use random access 
  218.   */
  219.  
  220. void postamble()
  221. {
  222.     register long size;
  223.     register int  count;
  224.     struct stat st;
  225.  
  226.     fstat (fileno(DVIfile), &st);
  227.     size = (long) st.st_size;                   /* get size of file          */
  228.     count = -1;
  229.     do {              /* back file up past signature bytes (223), to id-byte */
  230.         if (size-- == 0)
  231.             errorexit(nopst);
  232.         mseek(DVIfile, size, absolute);
  233.         opcode = (int) get1();
  234.         count++;
  235.     } while (opcode == TRAILER);
  236.     if (count < 4) {                            /* must have 4 trailer bytes */
  237.          foo = count;
  238.          errorexit(fwsgn);
  239.     }
  240.     if (opcode != VERSIONID)
  241.         errorexit(badid);
  242.     mseek(DVIfile, size-4, absolute);       /* back up to back-pointer       */
  243.     mseek(DVIfile, sget4(), absolute);      /* and to start of postamble     */
  244.     if (get1() != POST)
  245.         errorexit(nopst);
  246.     mseek(DVIfile, 20L, relative); /* lastpageoffset, numerator, denominator */
  247.                                    /* magnification, maxpageheight           */
  248.     maxpagewidth = sget4();
  249.     charwidth = maxpagewidth / (ttywidth + espace); 
  250.     stackmax = (int) get2();
  251.     if ((stack = (stackitem *) malloc(stackmax * sizeof(stackitem))) == NULL)
  252.        errorexit(stkrq);
  253.  
  254.     /* get2() -- totalpages */
  255.     /* fontdefs  do fontdefs in flight ... */
  256.  
  257.     return;
  258.  
  259. } /* postamble */
  260.  
  261.  
  262.  
  263. /*
  264.  * PREAMBLE --process preamble, use random access
  265.  */
  266.  
  267. void preamble()
  268. {
  269.  
  270.     mseek(DVIfile, 0L, absolute);       /* read the dvifile from the start   */
  271.     if ((opcode = skipnops()) != PRE)
  272.         errorexit(nopre);
  273.     opcode = (int) get1();        /* check id in preamble, ignore rest of it */
  274.     if (opcode != VERSIONID)
  275.         errorexit(badid);
  276.     mseek(DVIfile, 12L, relative);  /* numerator, denominator, magnification */
  277.     mseek(DVIfile, get1(), relative);         /* skip job identification     */
  278.  
  279.     return;
  280.  
  281. } /* preamble */
  282.  
  283.  
  284.  
  285. /*
  286.  * WALKPAGES -- process the pages in the DVI-file
  287.  */
  288.  
  289. void walkpages()
  290. {
  291.     register bool wantpage;
  292.  
  293.     pagecounter = 0L;
  294.     while ((opcode = skipnops()) != POST) {
  295.  
  296.         if (opcode != BOP)              /* should be at start of page now    */
  297.             errorexit(nobop);
  298.  
  299.         pagecounter++;
  300.         pagenr = sget4();               /* get TeX page number               */
  301.         mseek(DVIfile, 36L, relative);  /* skip page header */
  302.         backpointer = sget4();          /* get previous page offset          */
  303.         if (pageswitchon)
  304.             wantpage = inlist(sequenceon ? pagecounter : pagenr);
  305.         else
  306.             wantpage = TRUE;
  307.  
  308.         if (wantpage) {
  309.             initpage();
  310.             dopage();
  311.             printpage();
  312.         }
  313.         else
  314.                 skippage();
  315.     }
  316.  
  317.     return;
  318.  
  319. } /* walkpages */
  320.  
  321.  
  322.  
  323. /*
  324.  * INITPAGE -- Setup a new, empty page.
  325.  */
  326.  
  327. void initpage()
  328. {
  329.  
  330.     h = 0L;  v = 0L;                        /* initialize coordinates   */
  331.     x = 0L;  w = 0L;  y = 0L;  z = 0L;      /* initialize amounts       */
  332.     sptr = 0;                               /* initialize stack         */
  333.     currentline = getline();                /* initialize list of lines */
  334.     currentline->vv = 0L;
  335.     firstline   = currentline;
  336.     lastline    = currentline;
  337.     firstcolumn = rightmargin;
  338.     if (pageswitchon) {
  339.         if ((sequenceon ? pagecounter : pagenr) != firstpage->pag) 
  340.             if (noffd)
  341.                 fprintf(output, "^L\n");
  342.             else
  343.                 putc(FORM, output);
  344.     }
  345.     else
  346.         if (backpointer != -1)              /* not FORM at first page   */
  347.             if (noffd)
  348.                 fprintf(output, "^L\n");
  349.             else
  350.                 putc(FORM, output);
  351.  
  352.     return;
  353.  
  354. } /* initpage */
  355.  
  356.  
  357.  
  358. /*
  359.  * DOPAGE -- Process the dvi file until an end-off-page.
  360.  *           Build up a page image.
  361.  */
  362.  
  363. void dopage()
  364. {
  365.  
  366.     while ((opcode = (int) get1()) != EOP) {    /* process page until eop */
  367.         if (opcode <= LASTCHAR)
  368.             dochar((char) opcode);
  369.         else if ((opcode >= FONT_00) && (opcode <= FONT_63)) 
  370.             setfont(opcode - FONT_00);
  371.         else if (opcode > POST_POST)
  372.             errorexit(illop);
  373.         else
  374.             switch (opcode) {
  375.                 case SET1     : setchar(get1()); break;
  376.                 case SET2     : setchar(get2()); break;
  377.                 case SET3     : setchar(get3()); break;
  378.                 case SET4     : setchar(get4()); break;
  379.                 case SET_RULE : { long height = sget4();
  380.                                   rule(MOVE, sget4(), height); break;
  381.                                 }
  382.                 case PUT1     : putcharacter(get1()); break;
  383.                 case PUT2     : putcharacter(get2()); break;
  384.                 case PUT3     : putcharacter(get3()); break;
  385.                 case PUT4     : putcharacter(get4()); break;
  386.                 case PUT_RULE : { long height = sget4();
  387.                                   rule(STAY, sget4(), height); break;
  388.                                 }
  389.                 case NOP      : break;  /* no-op */
  390.                 case BOP      : errorexit(bdbop); break;
  391. /*              case EOP      : break;  strange place to have EOP */
  392.                 case PUSH     : if (sptr >= stackmax)            /* push */
  393.                                      errorexit(stkof);
  394.                                 stack[sptr].hh = h;
  395.                                 stack[sptr].vv = v;
  396.                                 stack[sptr].ww = w;
  397.                                 stack[sptr].xx = x;
  398.                                 stack[sptr].yy = y;
  399.                                 stack[sptr].zz = z;
  400.                                 sptr++;
  401.                                 break;
  402.                 case POP      : if (sptr-- == 0)                 /* pop */
  403.                                     errorexit(stkuf);
  404.                                 h = stack[sptr].hh;
  405.                                 v = stack[sptr].vv;
  406.                                 w = stack[sptr].ww;
  407.                                 x = stack[sptr].xx;
  408.                                 y = stack[sptr].yy;
  409.                                 z = stack[sptr].zz;
  410.                                 break;
  411.                 case RIGHT1   : (void) horizontalmove(sget1()); break;
  412.                 case RIGHT2   : (void) horizontalmove(sget2()); break;
  413.                 case RIGHT3   : (void) horizontalmove(sget3()); break;
  414.                 case RIGHT4   : (void) horizontalmove(sget4()); break;
  415.                 case W0       : h += w; break;
  416.                 case W1       : w = horizontalmove(sget1()); break;
  417.                 case W2       : w = horizontalmove(sget2()); break;
  418.                 case W3       : w = horizontalmove(sget3()); break;
  419.                 case W4       : w = horizontalmove(sget4()); break;
  420.                 case X0       : h += x; break;
  421.                 case X1       : x = horizontalmove(sget1()); break;
  422.                 case X2       : x = horizontalmove(sget2()); break;
  423.                 case X3       : x = horizontalmove(sget3()); break;
  424.                 case X4       : x = horizontalmove(sget4()); break;
  425.                 case DOWN1    : v += sget1(); break;
  426.                 case DOWN2    : v += sget2(); break;
  427.                 case DOWN3    : v += sget3(); break;
  428.                 case DOWN4    : v += sget4(); break;
  429.                 case Y0       : v += y; break;
  430.                 case Y1       : y = sget1(); v += y; break;
  431.                 case Y2       : y = sget2(); v += y; break;
  432.                 case Y3       : y = sget3(); v += y; break;
  433.                 case Y4       : y = sget4(); v += y; break;
  434.                 case Z0       : v += z; break;
  435.                 case Z1       : z = sget1(); v += z; break;
  436.                 case Z2       : z = sget2(); v += z; break;
  437.                 case Z3       : z = sget3(); v += z; break;
  438.                 case Z4       : z = sget4(); v += z; break;
  439.                 case FNT1     :
  440.                 case FNT2     :
  441.                 case FNT3     :
  442.                 case FNT4     : setfont(num(opcode - FNT1 + 1));
  443.                                 break;
  444.                 case XXX1     : mseek(DVIfile, get1(), relative); break;
  445.                 case XXX2     : mseek(DVIfile, get2(), relative); break;
  446.                 case XXX3     : mseek(DVIfile, get3(), relative); break;
  447.                 case XXX4     : mseek(DVIfile, get4(), relative); break;
  448.                 case FNT_DEF1 :
  449.                 case FNT_DEF2 :
  450.                 case FNT_DEF3 :
  451.                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1);
  452.                                 break;
  453.                 case PRE      : errorexit(bdpre); break;
  454.                 case POST     : errorexit(bdpst); break;
  455.                 case POST_POST: errorexit(bdpp); break;
  456.             }
  457.     }
  458.  
  459.     return;
  460.  
  461. } /* dopage */
  462.  
  463.  
  464.  
  465. /*
  466.  * SKIPPAGE -- Scan the dvi file until an end-off-page.
  467.  *             Skip this page.
  468.  */
  469.  
  470. void skippage()
  471. {
  472.     register int opcode;
  473.  
  474.     while ((opcode = (int) get1()) != EOP) {
  475.         if (opcode > POST_POST)
  476.             errorexit(illop);
  477.         else
  478.             switch (opcode) {
  479.                 case SET1     :
  480.                 case PUT1     :
  481.                 case RIGHT1   :
  482.                 case W1       :
  483.                 case X1       :
  484.                 case DOWN1    :
  485.                 case Y1       :
  486.                 case Z1       : /* assume FNT change can also be skipped */
  487.                 case FNT1     : mseek(DVIfile, 1L, relative); break;
  488.                 case SET2     :
  489.                 case PUT2     :
  490.                 case RIGHT2   :
  491.                 case W2       :
  492.                 case X2       :
  493.                 case DOWN2    :
  494.                 case Y2       :
  495.                 case Z2       :
  496.                 case FNT2     : mseek(DVIfile, 2L, relative); break;
  497.                 case SET3     :
  498.                 case PUT3     :
  499.                 case RIGHT3   :
  500.                 case W3       :
  501.                 case X3       :
  502.                 case DOWN3    :
  503.                 case Y3       :
  504.                 case Z3       :
  505.                 case FNT3     : mseek(DVIfile, 3L, relative); break;
  506.                 case SET4     :
  507.                 case PUT4     :
  508.                 case RIGHT4   :
  509.                 case W4       :
  510.                 case X4       :
  511.                 case DOWN4    :
  512.                 case Y4       :
  513.                 case Z4       :
  514.                 case FNT4     : mseek(DVIfile, 4L, relative); break;
  515.                 case SET_RULE :
  516.                 case PUT_RULE : mseek(DVIfile, 8L, relative); break;
  517.                 case BOP      : errorexit(bdbop); break;
  518.                 case XXX1     : mseek(DVIfile, get1(), relative); break;
  519.                 case XXX2     : mseek(DVIfile, get2(), relative); break;
  520.                 case XXX3     : mseek(DVIfile, get3(), relative); break;
  521.                 case XXX4     : mseek(DVIfile, get4(), relative); break;
  522.                 case FNT_DEF1 :
  523.                 case FNT_DEF2 :
  524.                 case FNT_DEF3 :
  525.                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1); break;
  526.                 case PRE      : errorexit(bdpre); break;
  527.                 case POST     : errorexit(bdpst); break;
  528.                 case POST_POST: errorexit(bdpp); break;
  529.         }
  530.     }
  531.  
  532.     return;
  533.  
  534. } /* skippage */
  535.  
  536.  
  537.  
  538. /*
  539.  * PRINTPAGE -- 'end of page', writes lines of page to output file 
  540.  */
  541.  
  542. void printpage()
  543. {
  544.     register int  i, j;
  545.     register char ch;
  546.  
  547.     if (sptr != 0)
  548.         fprintf(stderr, "dvi2tty: warning - stack not empty at eop.\n");
  549.     for (currentline = firstline; currentline != nil;
  550.           currentline = currentline->next) {
  551.         if (currentline != firstline) {
  552.             foo = ((currentline->vv - currentline->prev->vv)/lineheight)-1;
  553.             foo &= 3;            /* linespacings not too large */
  554.             for (i = 1; i <= (int) foo; i++)
  555.                 putc('\n', output);
  556.         }
  557.         if (currentline->charactercount >= leftmargin) {
  558.             foo = ttywidth - 2;
  559.             for (i = firstcolumn, j = 1; i <= currentline->charactercount;
  560.                    i++, j++) {
  561.                 ch = currentline->text[i - leftmargin];
  562.                 if (ch >= SPACE)
  563.                     putc(ch, output);
  564.                 if ((j > (int) foo) && (currentline->charactercount > i+1)) {
  565.                         fprintf(output, "*\n");         /* if line to large */
  566.                         fprintf(output, " *");          /* mark output      */
  567.                         j = 2;
  568.                 }
  569.             } 
  570.         }
  571.         putc('\n', output);
  572.     } 
  573.  
  574.     currentline = firstline;
  575.     while (currentline->next != nil) {
  576.         currentline = currentline->next;
  577.         free(currentline->prev);
  578.     }
  579.     free(currentline);              /* free last line */
  580.     currentline = nil;
  581.  
  582.     return;
  583.  
  584. } /* printpage */
  585.  
  586.  
  587.  
  588. /*
  589.  * INLIST -- return true if pagenr is in the list of pages to be printed.
  590.  */
  591.  
  592. bool inlist(pagenr)
  593. register long pagenr;
  594. {
  595.  
  596.     while ((currentpage->pag < 0) && (currentpage->pag != pagenr) &&
  597.            !currentpage->all && (currentpage->nxt != nil))
  598.         currentpage = currentpage->nxt;
  599.     if ((currentpage->all && (pagenr < currentpage->pag)) ||
  600.          (currentpage->pag == pagenr))
  601.             return TRUE;
  602.     else if (pagenr > 0) {
  603.         while ((currentpage->pag < pagenr) && (currentpage->nxt != nil))
  604.             currentpage = currentpage->nxt;
  605.         if (currentpage->pag == pagenr)
  606.             return TRUE;
  607.     }
  608.  
  609.     return FALSE;
  610.  
  611. } /* inlist */
  612.  
  613.  
  614.  
  615. /*
  616.  * RULE -- Output a rule (vertical or horizontal).
  617.  *         Increment h if moving is true.
  618.  */
  619.  
  620. void rule(moving, rulewt, ruleht)
  621. register bool moving;
  622. register long rulewt, ruleht;
  623. {
  624.  
  625.     register char ch;               /* character to set rule with            */
  626.     register long saveh, savev;
  627.                               /* rule   --   starts up the recursive routine */
  628.     if (!moving)
  629.         saveh = h;
  630.     if ((ruleht <= 0) || (rulewt <= 0))
  631.         h += rulewt;
  632.     else {
  633.         savev = v;
  634.         if ((ruleht / rulewt) > 0)         /* value < 1 truncates to 0 */
  635.             ch = '|';
  636.         else if (ruleht > (lineheight / 2))
  637.             ch = '=';
  638.         else
  639.             ch = '_';
  640.         ruleaux(rulewt, ruleht, ch);
  641.         v = savev;
  642.     }
  643.     if (!moving)
  644.         h = saveh;
  645.  
  646.     return;
  647.  
  648. } /* rule */
  649.  
  650.  
  651.  
  652. /*
  653.  * RULEAUX -- do the actual outtput for the rule recursively.
  654.  */
  655.  
  656. void ruleaux(rulewt, ruleht, ch)
  657. register long rulewt, ruleht;
  658. register char ch;
  659. {
  660.     register long wt, lmh, rmh;
  661.  
  662.     wt = rulewt;
  663.     lmh = h;                        /* save left margin                      */
  664.     if (h < 0) {                    /* let rules that start at negative h    */
  665.         wt -= h;                    /* start at coordinate 0, but let it     */
  666.         h = 0;                      /*   have the right length               */
  667.     }
  668.     while (wt > 0) {                /* output the part of the rule that      */
  669.         rmh = h;                    /*   goes on this line                   */
  670.         outchar(ch);
  671.         wt -= (h-rmh);              /* decrease the width left on line       */
  672.     }
  673.     ruleht -= lineheight;      /* decrease the height                   */
  674.     if (ruleht > lineheight) { /* still more vertical?                  */
  675.         rmh = h;                    /* save current h (right margin)         */
  676.         h = lmh;                    /* restore left margin                   */
  677.         v -= (lineheight + lineheight / 10);
  678.         ruleaux(rulewt, ruleht, ch);
  679.         h = rmh;                    /* restore right margin                  */
  680.     }
  681.  
  682.     return;
  683.  
  684. } /* ruleaux */
  685.  
  686.  
  687.  
  688. /*
  689.  * HORIZONTALMOVE -- Move the h pointer by amount.
  690.  */
  691.  
  692. long horizontalmove(amount)
  693. register long amount;
  694. {
  695.  
  696. #if defined(MSDOS)
  697.     if (labs(amount) > charwidth / 4L) {    /* } to make vi happy */
  698. #else
  699.     if (abs(amount) > charwidth / 4L) {
  700. #endif
  701.         foo = 3*charwidth / 4;
  702.         if (amount > 0)
  703.             amount = ((amount+foo) / charwidth) * charwidth;
  704.         else
  705. #if defined(VMS)
  706.             amount = (ROUND( (float) (amount-foo) / charwidth) + 1)* charwidth;
  707. #else
  708.             amount = ((amount-foo) / charwidth) * charwidth;
  709. #endif
  710.         h += amount;
  711.         return amount;
  712.     }
  713.     else
  714.         return 0;
  715.  
  716. }   /* horizontalmove */
  717.  
  718.  
  719.  
  720. /*
  721.  * SKIPNOPS -- Return first non NOP opcode.
  722.  */
  723.  
  724. int skipnops()
  725. {
  726.     register int opcode;
  727.  
  728.     while ((opcode = (int) num(1)) == NOP);
  729.  
  730.     return opcode;
  731.  
  732. } /* skipnops */
  733.  
  734.  
  735.  
  736. /*
  737.  * GETLINE -- Returns an initialized line-object 
  738.  */
  739.  
  740. linetype *getline()
  741. {
  742.     register int  i;
  743.     register linetype *temp;
  744.  
  745.     if ((temp = (linetype *) malloc(sizeof(linetype))) == NULL) 
  746.         errorexit(lnerq);
  747.     temp->charactercount = leftmargin - 1;
  748.     temp->prev = nil;
  749.     temp->next = nil;
  750.     for (i = 0; i < LINELEN; i++)
  751.         temp->text[i] = ' ';
  752.     temp->text[i] = '\0';
  753.  
  754.     return temp;
  755.  
  756. } /* getline */
  757.  
  758.  
  759.  
  760. /*
  761.  * FINDLINE -- Find best fit line were text should go
  762.  *             and generate new line if needed.
  763.  */
  764.  
  765. linetype *findline()
  766. {
  767.     register linetype *temp;
  768.     register long topd, botd;
  769.  
  770.     if (v <= firstline->vv) {                      /* above first line */
  771.         if (firstline->vv - v > lineheight) {
  772.             temp = getline();
  773.             temp->next = firstline;
  774.             firstline->prev = temp;
  775.             temp->vv = v;
  776.             firstline = temp;
  777.         }
  778.         return firstline;
  779.     }
  780.  
  781.     if (v >= lastline->vv) {                       /* below last line */
  782.         if (v - lastline->vv > lineheight) {
  783.             temp = getline();
  784.             temp->prev = lastline;
  785.             lastline->next = temp;
  786.             temp->vv = v;
  787.             lastline = temp;
  788.         }
  789.         return lastline;
  790.     }
  791.  
  792.     temp = lastline;                               /* in between two lines */
  793.     while ((temp->vv > v) && (temp != firstline))
  794.         temp = temp->prev;
  795.  
  796.     /* temp->vv < v < temp->next->vv --- temp is above, temp->next is below */
  797.     topd = v - temp->vv;
  798.     botd = temp->next->vv - v;
  799.     if ((topd < lineheight) || (botd < lineheight))
  800.         if (topd < botd)                           /* take best fit */
  801.             return temp;
  802.         else
  803.             return temp->next;
  804.  
  805.     /* no line fits suitable, generate a new one */
  806.     currentline = getline();
  807.     currentline->next = temp->next;
  808.     currentline->prev = temp;
  809.     temp->next->prev = currentline;
  810.     temp->next = currentline;
  811.     currentline->vv = v;
  812.  
  813.     return currentline;
  814.  
  815. } /* findline */
  816.  
  817.  
  818.  
  819. /*
  820.  * NUM --
  821.  */
  822.  
  823. unsigned long num(size)
  824. register int size;
  825. {
  826.     register int i;
  827.     register long x = 0;
  828.  
  829.     for (i = size; i > 0; i--)
  830.         x = (x << 8) + (unsigned) getc(DVIfile);
  831.  
  832.     return x;
  833.  
  834. } /* num */
  835.  
  836.  
  837. /*
  838.  * SNUM --
  839.  */
  840.  
  841. long snum(size)
  842. register int size;
  843. {
  844.     register int i;
  845.     register long x = 0;
  846.  
  847.     x = getc(DVIfile);
  848.     if (x & 0x80)
  849.         x -= 0x100;
  850.     for (i = size - 1; i > 0; i--)
  851.         x = (x << 8) + (unsigned) getc(DVIfile);
  852.  
  853.     return x;
  854.  
  855. } /* snum */
  856.  
  857.  
  858.  
  859. /*
  860.  * DOCHAR -- Process a character opcode.
  861.  */
  862.  
  863. void dochar(ch)
  864. register char ch;
  865. {
  866.  
  867.     if (symbolfont == TRUE)
  868.         symchar(ch);
  869.     else
  870.         normchar(ch);
  871.  
  872.     return;
  873.  
  874. } /* dochar */
  875.  
  876.  
  877.  
  878. /*
  879.  * SYMCHAR -- Process a character opcode for a symbol font.
  880.  */
  881.  
  882. void symchar(ch)
  883. register char ch;
  884. {
  885.  
  886.     switch (ch) {       /* can do a lot more on MSDOS machines ... */
  887.        case   0: ch = '-'; break;
  888.        case   1: ch = '.'; break;
  889.        case   2: ch = 'x'; break;
  890.        case   3: ch = '*'; break;
  891.        case  13: ch = 'O'; break;
  892.        case  14: ch = 'O'; break;
  893.        case  15: ch = 'o'; break;
  894.        case  24: ch = '~'; break;
  895.        case 102: ch = '{'; break;
  896.        case 103: ch = '}'; break;
  897.        case 104: ch = '<'; break;
  898.        case 105: ch = '>'; break;
  899.        case 106: ch = '|'; break;
  900.        case 110: ch = '\\'; break;
  901.     }
  902.  
  903.     outchar(ch);
  904.  
  905.     return;
  906.  
  907. } /* symchar */
  908.  
  909.  
  910.  
  911. /*
  912.  * NORMCHAR -- Process a character opcode for a normal font.
  913.  */
  914.  
  915. void normchar(ch)
  916. register char ch;
  917. {
  918.  
  919.     switch (ch) {
  920.         case 11  :  if (ttfont) 
  921.                         ch = '^';                   /* up symbol       */
  922.                     else {
  923.                         outchar('f'); ch = 'f';     /* ligature        */
  924.                     }
  925.                     break;
  926.         case 12  :  if (ttfont) 
  927.                         ch = 'v';                   /* low symbol       */
  928.                     else {
  929.                         outchar('f'); ch = 'i';     /* ligature        */
  930.                     }
  931.                     break;
  932.         case 13  :  if (ttfont) 
  933.                         ch = '`';
  934.                     else {
  935.                         outchar('f'); ch = 'l';     /* ligature        */
  936.                     }
  937.                     break;
  938.         case 14  :  if (ttfont) 
  939.                         ch = 'i';                   /* spanish !        */
  940.                     else {
  941.                         outchar('f'); outchar('f');
  942.                                   ch = 'i';         /* ligature        */
  943.                     }
  944.                     break;
  945.         case 15  :  if (ttfont) 
  946.                         ch = '.';                   /* spanish ?        */
  947.                     else {
  948.                         outchar('f'); outchar('f');
  949.                                   ch = 'l';         /* ligature        */
  950.                     }
  951.                     break;
  952.         case 16  :  ch = 'i'; break;
  953.         case 17  :  ch = 'j'; break;
  954.         case 25  :  outchar('s'); ch = 's'; break;  /* German double s */
  955.         case 26  :  outchar('a'); ch = 'e'; break;  /* Dane/Norw ae    */
  956.         case 27  :  outchar('o'); ch = 'e'; break;  /* Dane/Norw oe    */
  957.         case 28  :  if (scascii)
  958.                         ch = '|';                   /* Dane/Norw /o    */
  959.                     else
  960.                         ch = 'o';
  961.                     break;
  962.         case 29  :  outchar('A'); ch = 'E'; break;  /* Dane/Norw AE    */
  963.         case 30  :  outchar('O'); ch = 'E'; break;  /* Dane/Norw OE    */
  964.         case 31  :  if (scascii)
  965.                         ch = '\\';                  /* Dane/Norw /O    */
  966.                     else
  967.                         ch = 'O';
  968.                     break;
  969.         case 32  :  ch = '_'; break;  /* underlined blank */
  970.         case 92  :  ch = '"'; break;  /* \ from `` */
  971.         case 123 :  ch = '-'; break;  /* { from -- */
  972.         case 124 :  ch = '_'; break;  /* | from --- */
  973.         case 125 :  ch = '"'; break;  /* } from \H */
  974.         case 126 :  ch = '"'; break;  /* ~ from \~ */
  975.         case 127 :  ch = '"'; break;  /* DEL from \" */
  976.        
  977.         /*
  978.          * Or should I use SPACE for non-accents ???
  979.          * This seems to work ...
  980.          */
  981.         case 18  :  ch = accent ? '`' : ch; break;  /* from \` */
  982.         case 19  :  ch = accent ? 0x27 : ch; break; /* from \' */
  983.         case 20  :  ch = accent ? '~' : ch; break;  /* from \v */
  984.         case 21  :  ch = accent ? '~' : ch; break;  /* from \u */
  985.         case 22  :  ch = accent ? '~' : ch; break;  /* from \= */
  986.         case 24  :  ch = accent ? ',' : ch; break;  /* from \c */
  987.         case 94  :  ch = accent ? '^' : ch; break;  /* ^ from \^ */
  988.         case 95  :  ch = accent ? '`' : ch; break;  /* _ from \. */
  989.     }
  990.     outchar(ch); 
  991.  
  992.     return;
  993.  
  994. } /*normchar */
  995.  
  996.  
  997.  
  998. /*
  999.  * OUTCHAR -- Here we put the character into the current page.
  1000.  *            This function includes some code to handle Scandinavian
  1001.  *            characters. I think that code doesn'y belong here. IT
  1002.  *            SHOULD BE MOVED OUT.
  1003.  */
  1004.  
  1005. void outchar(ch)
  1006. register char ch;
  1007. {
  1008.     register int i, j;
  1009.  
  1010. /*     fprintf(stderr, "hor: %ld, ver: %ld\n", h, v); */
  1011.  
  1012. #if defined(MSDOS)
  1013.     if (labs(v - currentline->vv) > lineheight / 2L)
  1014. #else
  1015.     if (abs(v - currentline->vv) > lineheight / 2L)
  1016. #endif
  1017.         currentline = findline();
  1018.  
  1019. #if 0
  1020.     j = (int) (((double) h / (double) maxpagewidth) * (ttywidth-1)) + 1;
  1021. #else
  1022.     j = (int) (h / charwidth);
  1023. #endif
  1024.     if (j > rightmargin)     /* leftmargin <= j <= rightmargin */
  1025.         j = rightmargin;
  1026.     else if (j < leftmargin)
  1027.         j = leftmargin;
  1028.     foo = leftmargin - 1;
  1029.  
  1030.     /*
  1031.     /* This code does not really belong here ...
  1032.     /*
  1033.     /*-------------------------------------------------------------*/
  1034.     /* The following is very specialized code, it handles national */
  1035.     /* Swe/Fin characters. They are respectively: a and o with two */
  1036.     /* dots ("a & "o) and a with a circle (Oa). In Swe/Fin "ASCII" */
  1037.     /* these characters replace {}|[] and \.  TeX outputs these by */
  1038.     /* first issuing the dots or circle and then backspace and set */
  1039.     /* the a or o. When dvi2tty finds an a or o it searches in the */
  1040.     /* near vicinity for the character codes that represent circle */
  1041.     /* or dots and if one is found the corresponding national char */
  1042.     /* replaces the special character codes.                       */
  1043.     /*-------------------------------------------------------------*/
  1044.     if (scascii) {
  1045.         if ((ch == 'a') || (ch == 'A') || (ch == 'o') || (ch == 'O')) {
  1046.             for (i = IMAX(leftmargin, j-2);
  1047.                  i <= IMIN(rightmargin, j+2);
  1048.                  i++)
  1049.                 if ((currentline->text[i - leftmargin] == 127) || /* DEL */
  1050.                     (currentline->text[i - leftmargin] == 34)  || /* "   */
  1051.                     (currentline->text[i - leftmargin] == 23))
  1052.                     foo = i;
  1053.             if (foo >= leftmargin) {
  1054.                 j = (int) foo;
  1055.                 switch (currentline->text[j - leftmargin]) {
  1056.                     case 127 : case 34:                 /* DEL or " */
  1057.                                if (ch == 'a')
  1058.                                    ch = '{';            /* } vi */
  1059.                                else if (ch == 'A')      /* dots ... */
  1060.                                    ch = '[';
  1061.                                else if (ch == 'o')
  1062.                                    ch = '|';
  1063.                                else if (ch == 'O')
  1064.                                    ch = '\\';
  1065.                                break;
  1066.                     case 23  : if (ch == 'a')
  1067.                                    ch = /* { vi */ '}';
  1068.                                else if (ch == 'A')      /* circle */
  1069.                                    ch = ']';
  1070.                                break;
  1071.                 }
  1072.             }
  1073.         }
  1074.     }
  1075.     /*----------------- end of 'Scandinavian code' ----------------*/
  1076.  
  1077.     if (foo == leftmargin-1)
  1078.         while ((currentline->text[j - leftmargin] != SPACE)
  1079.                && (j < rightmargin)) {
  1080.             j++;
  1081.             h += charwidth;
  1082.         }
  1083.     if ( ((ch >= SPACE) && (ch != DEL)) ||
  1084.          (scascii && (ch == 23)) ) {
  1085.           /*  (scascii && (ch == DEL)) )     if VMS ??? */
  1086.         if (j < rightmargin)
  1087.             currentline->text[j - leftmargin] = ch;
  1088.         else
  1089.             currentline->text[rightmargin - leftmargin] = '@';
  1090.         if (j > currentline->charactercount)
  1091.             currentline->charactercount = j;
  1092.         if (j < firstcolumn)
  1093.             firstcolumn = j;
  1094.     }
  1095.     h += charwidth;
  1096.  
  1097.     return;
  1098.  
  1099. } /* outchar */
  1100.  
  1101.  
  1102.  
  1103. /*
  1104.  * PUTCHARACTER -- Output character, don't change h 
  1105.  */
  1106.  
  1107. void putcharacter(charnr)
  1108. register long charnr;
  1109. {
  1110.     register long saveh;
  1111.  
  1112.     saveh = h;
  1113.     if ((charnr >= 0) && (charnr <= LASTCHAR))
  1114.         outchar((char) charnr);
  1115.     else
  1116.         setchar(charnr);
  1117.     h = saveh;
  1118.  
  1119.     return;
  1120.  
  1121. } /* putcharacter */
  1122.  
  1123.  
  1124.  
  1125. /*
  1126.  * SETCHAR -- Should print characters with character code>127 from
  1127.  *            current font. Note that the parameter is a dummy, since
  1128.  *            ascii-chars are<=127.
  1129.  */
  1130.  
  1131. void setchar(charnr)
  1132. long charnr;
  1133. {
  1134.  
  1135.     outchar('#');
  1136.  
  1137.     return;
  1138.  
  1139. } /* setchar */
  1140.  
  1141.  
  1142.  
  1143. /*
  1144.  * FONTDEF -- Process a font definition.
  1145.  */
  1146.  
  1147. void fontdef(x)
  1148. register int x;
  1149. {
  1150.     register int i;
  1151.     char * name;
  1152.     font * fnt;
  1153.     int namelen;
  1154.     long fntnum;
  1155.     int new = 0;
  1156.  
  1157.     fntnum = num(x);
  1158.     (void) get4();                      /* checksum */
  1159.     (void) get4();                      /* scale */
  1160.     (void) get4();                      /* design */
  1161.     namelen = (int) get1() + (int) get1();
  1162.     fnt = fonts;
  1163.     while (fnt != NULL && fnt->num != fntnum)       /* does fontnum exist */
  1164.         fnt = fnt->next;
  1165.     if (fnt == NULL) {
  1166.         if ((fnt = (font *) malloc(sizeof(font))) == NULL) {
  1167.             perror("fontdef");
  1168.             exit(1);
  1169.         }
  1170.         fnt->num = fntnum;
  1171.         new = 1;
  1172.     }
  1173.     else
  1174.         free(fnt->name);    /* free old name */
  1175.     if ((name = (char *) malloc(namelen * sizeof(char))) == NULL) {
  1176.         perror("fontdef");
  1177.         exit(1);
  1178.     }
  1179.     
  1180.     for (i = 0; i < namelen; i++)
  1181.         name[i] = get1();
  1182.     fnt->name = name;
  1183.     if (new) {
  1184.         fnt->next = fonts;
  1185.         fonts = fnt;
  1186.     }
  1187.  
  1188.     return;
  1189.  
  1190. } /* fontdef */
  1191.  
  1192.  
  1193.  
  1194. /*
  1195.  * SETFONT -- Switch to specific font. Try to find out if it is a symbol
  1196.  *            font.
  1197.  */
  1198.  
  1199. void setfont(fntnum)
  1200. long fntnum;
  1201. {
  1202.     font * fnt;
  1203.     char * s;
  1204.  
  1205.     fnt = fonts;
  1206.     while (fnt != NULL && fnt->num != fntnum)
  1207.         fnt = fnt->next;
  1208.     if (fnt == NULL) {
  1209.         /* error : font not found */
  1210.         symbolfont = FALSE;
  1211.         return;
  1212.     }
  1213.  
  1214.     s = fnt->name;
  1215.     while ((s = strchr(s, 's')) != NULL) {
  1216.         if (strncmp("sy", s, 2) == 0) {
  1217.             symbolfont = TRUE;
  1218.             return;
  1219.         }
  1220.     s++;    /* New line to fix bug; font names with 's' would hang */
  1221.     }
  1222.    
  1223.     symbolfont = FALSE;
  1224.  
  1225.     return;
  1226.  
  1227. } /* setfont */
  1228.    
  1229.  
  1230.  
  1231. /* 
  1232.  * VMS CODE 
  1233.  */
  1234.  
  1235. #if defined(VMS)
  1236. long vmsseek(fp,n,dir)
  1237. FILE *fp;
  1238. long n;
  1239. long dir;
  1240. {
  1241.     long k,m,pos,val,oldpos;
  1242.     struct stat buffer;
  1243.  
  1244.     for (;;) {                     /* loops only once or twice */
  1245.         switch (dir) {
  1246.             case 0:            /* from BOF */
  1247.                     oldpos = vms_ftell(fp);
  1248.                     k = n & 511;
  1249.                     m = n >> 9;
  1250.                     if (((*fp)->_cnt) && ((oldpos >> 9) == m)) {
  1251.                         val = 0; /* still in */
  1252.                         (*fp)->_ptr = ((*fp)->_base) + k;
  1253.                         (*fp)->_cnt = 512 - k;
  1254.                     }
  1255.                     else {
  1256.                         val = fseek(fp, m << 9, 0);
  1257.                         if (val == 0) {
  1258.                             (*fp)->_cnt = 0;
  1259.                             (void) fgetc(fp);
  1260.                             (*fp)->_ptr = ((*fp)->_base) + k;
  1261.                             (*fp)->_cnt = 512 - k;
  1262.                         }
  1263.                     }
  1264.                     return(val);
  1265.  
  1266.             case 1: pos = vms_ftell(fp);
  1267.                     if (pos == EOF)
  1268.                         return (EOF);
  1269.                     n += pos;
  1270.                     dir = 0;
  1271.                     break;
  1272.  
  1273.             case 2: val = fstat(fileno(fp), &buffer);
  1274.                     if (val == EOF)
  1275.                         return (EOF);
  1276.                     n += buffer.st_size - 1;
  1277.  
  1278.                     dir = 0;
  1279.                     break;
  1280.  
  1281.             default : return (EOF);
  1282.         }
  1283.     }
  1284.  
  1285.     /* NOTREACHED */
  1286.  
  1287. } /* vmsseek */
  1288.         
  1289.  
  1290.  
  1291. long vms_ftell(fp)
  1292. FILE *fp;
  1293. {
  1294.     char c;
  1295.     long pos;
  1296.     long val;
  1297.  
  1298.     if ((*fp)->_cnt == 0) {
  1299.         c = fgetc(fp);
  1300.         val = vms_ungetc(c, fp);
  1301.         if (val != c)
  1302.             return (EOF);
  1303.     }
  1304.     pos = ftell(fp);
  1305.     if (pos >= 0)
  1306.         pos += ((*fp)->_ptr) - ((*fp)->_base);
  1307.  
  1308.     return (pos);
  1309.  
  1310. } /* vms_ftell */
  1311.  
  1312.  
  1313.  
  1314. long vms_ungetc(c,fp)
  1315. char c;
  1316. FILE *fp;
  1317. {
  1318.  
  1319.     if ((c == EOF) && feof(fp))
  1320.         return (EOF);
  1321.  
  1322.     if ((*fp)->_cnt >= 512)
  1323.         return (EOF);
  1324.     
  1325.     (*fp)->_cnt++;
  1326.     (*fp)->_ptr--;
  1327.     *((*fp)->_ptr) = c;
  1328.  
  1329.     return (c);
  1330.  
  1331. } /*vms_ungetc */
  1332. #endif
  1333.  
  1334.