home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Tex / Dvi / dvi2ttys.lzh / DVISTUFF.C < prev    next >
C/C++ Source or Header  |  1991-02-01  |  38KB  |  1,144 lines

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