home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / dvi2tty-2 / dvistuff.c < prev    next >
C/C++ Source or Header  |  1989-02-03  |  32KB  |  856 lines

  1.  
  2.  
  3. #include "dvi2tty.h"
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #if defined(MSDOS)
  7. #include <math.h>
  8. #endif
  9. #include "commands.h"
  10.  
  11. #define VERSIONID            2 /* dvi version number that pgm handles      */
  12. #define VERTICALEPSILON 450000L /* crlf when increasing v more than this   */
  13.  
  14. #define rightmargin     152    /* nr of columns allowed to the right of h=0*/
  15. #define leftmargin      -50    /* give some room for negative h-coordinate */
  16. #define LINELEN         203    /* rightmargin - leftmargin + 1 */
  17.  
  18. #define MOVE            TRUE   /* if advancing h when outputing a rule     */
  19. #define STAY            FALSE  /* if not advancing h when outputing a rule */
  20.  
  21. #define absolute        0      /* for seeking in files                     */
  22. #define relative        1
  23.  
  24. #define FORM             12    /* formfeed                                 */
  25. #define SPACE            32    /* space                                    */
  26. #define DEL             127    /* delete                                   */
  27.  
  28. #define LASTCHAR        127    /* max dvi character, above are commands    */
  29.  
  30. #define IMIN(a, b)      (a<b ? a : b)
  31. #define IMAX(a, b)      (a>b ? a : b)
  32.  
  33. #define get1()          num(1)
  34. #define get2()          num(2)
  35. #define get3()          num(3)
  36. #define get4()          num(4)
  37. #define sget1()         snum(1)
  38. #define sget2()         snum(2)
  39. #define sget3()         snum(3)
  40. #define sget4()         snum(4)
  41.  
  42. char *dvistuff = "(#)@  dvistuff.c  3.1 23/01/89 M.J.E. Mol (c) 1989"
  43.  
  44. /*---------------------------------------------------------------------------*/
  45.  
  46. typedef struct {
  47.     long hh;
  48.     long vv;
  49.     long ww;
  50.     long xx;
  51.     long yy;
  52.     long zz;
  53. } stackitem;
  54.  
  55. typedef struct lineptr {        /* the lines of text to be output to outfile */
  56.     long            vv;                 /* vertical position of the line     */
  57.     int             charactercount;     /* pos of last char on line          */
  58.     struct lineptr *prev;               /* preceding line                    */
  59.     struct lineptr *next;               /* succeeding line                   */
  60.     char            text[LINELEN+1];    /* leftmargin...rightmargin          */
  61. } linetype;
  62.  
  63. /*---------------------------------------------------------------------------*/
  64.  
  65. bool        pageswitchon;       /* true if user-set pages to print           */
  66. bool        sequenceon;         /* false if pagesw-nrs refers to TeX-nrs     */
  67. bool        scascii;            /* if true make Scand. nat. chars right      */
  68. bool        noffd;              /* if true output ^L instead of formfeed     */
  69.  
  70. int         opcode;             /* dvi-opcodes                               */
  71.  
  72. long        h, v;               /* coordinates, horizontal and vertical      */
  73. long        w, x, y, z;         /* horizontal and vertical amounts           */
  74.  
  75. long        pagecounter;        /* sequence page number counter              */
  76. long        backpointer;        /* pointer for offset to previous page       */
  77. long        pagenr;             /* TeX page number                           */
  78. int         stackmax;           /* stacksize required                        */
  79.  
  80. long        maxpagewidth;       /* width of widest page in file              */
  81. long        charwidth;          /* aprox width of character                  */
  82.  
  83. linetype *  currentline;        /* pointer to current line on current page   */
  84. linetype *  firstline;          /* pointer to first line on current page     */
  85. linetype *  lastline;           /* pointer to last line on current page      */
  86. int         firstcolumn;        /* 1st column with something to print        */
  87.  
  88. stackitem * stack;              /* stack for dvi-pushes                      */
  89. int         sptr;               /* stack pointer                             */
  90.  
  91. /*---------------------------------------------------------------------------*/
  92.  
  93. #if defined(MSDOS)
  94. void            postamble       (void);
  95. void            preamble        (void);
  96. void            walkpages       (void);
  97. void            initpage        (void);
  98. void            dopage          (void);
  99. void            skippage        (void);
  100. void            printpage       (void);
  101. bool            inlist          (long);
  102. void            rule            (bool, long, long);
  103. void            ruleaux         (long, long, char);
  104. long            horizontalmove  (long);
  105. int             skipnops        (void);
  106. linetype    *   getline         (void);
  107. linetype    *   findline        (void);
  108. unsigned long   num             (int);
  109. long            snum            (int);
  110. void            outchar         (char);
  111. void            putcharacter    (long);
  112. void            setchar         (long);
  113. #else
  114. void            postamble       ();
  115. void            preamble        ();
  116. void            walkpages       ();
  117. void            initpage        ();
  118. void            dopage          ();
  119. void            skippage        ();
  120. void            printpage       ();
  121. bool            inlist          ();
  122. void            rule            ();
  123. void            ruleaux         ();
  124. long            horizontalmove  ();
  125. int             skipnops        ();
  126. linetype    *   getline         ();
  127. linetype    *   findline        ();
  128. unsigned long   num             ();
  129. long            snum            ();
  130. void            outchar         ();
  131. void            putcharacter    ();
  132. void            setchar         ();
  133. #endif
  134.  
  135.  
  136. /*---------------------------------------------------------------------------*/
  137. /*---------------------------------------------------------------------------*/
  138.  
  139. /*
  140.  * The main function for processing the dvi file.
  141.  * Here we assume there are to file pointers: DVIfile and output.
  142.  * Also we have a list of pages pointed to by 'currentpage',
  143.  * which is only used (in 'inlist()') when a page list is given.
  144.  */
  145.  
  146. void dvimain()
  147. {
  148.  
  149.     postamble();                            /* seek and process the postamble */
  150.     /* note that walkpages *must* immediately follow preamble */
  151.     preamble();                             /* process preamble               */
  152.     walkpages();                            /* time to do the actual work!    */
  153.  
  154. } /* dvimain */
  155.  
  156. /*---------------------------------------------------------------------------*/
  157.  
  158. void postamble()            /* find and process postamble, use random access */
  159. {
  160.     register long size;
  161.     register int  count;
  162.     struct stat st;
  163.  
  164.     fstat (fileno(DVIfile), &st);
  165.     size = (long) st.st_size;                   /* get size of file          */
  166.     count = -1;
  167.     do {              /* back file up past signature bytes (223), to id-byte */
  168.         if (size == 0)
  169.             errorexit(nopst);
  170.         size--;
  171.         fseek(DVIfile, size, absolute);
  172.         opcode = (int) get1();
  173.         count++;
  174.     } while (opcode == TRAILER);
  175.     if (count < 4) {                            /* must have 4 trailer bytes */
  176.          foo = count;
  177.          errorexit(fwsgn);
  178.     }
  179.     if (opcode != VERSIONID)
  180.         errorexit(badid);
  181.     fseek(DVIfile, size-4, absolute);       /* back up to back-pointer       */
  182.     fseek(DVIfile, sget4(), absolute);      /* and to start of postamble   */
  183.     if (get1() != POST)
  184.         errorexit(nopst);
  185.     fseek(DVIfile, 20L, relative); /* lastpageoffset, numerator, denominator */
  186.                                    /* magnification, maxpageheight           */
  187.     maxpagewidth = sget4();
  188.     charwidth = maxpagewidth / (ttywidth + espace); 
  189.     stackmax = (int) get2();
  190.     if ((stack = (stackitem *) malloc(stackmax * sizeof(stackitem))) == NULL)
  191.        errorexit(stkrq);
  192.  
  193.     /* get2() -- totalpages */
  194.     /* fontdefs */
  195.  
  196. } /* postamble */
  197.  
  198. /*---------------------------------------------------------------------------*/
  199.  
  200. void preamble()                 /* process preamble, use random access       */
  201. {
  202.  
  203.     fseek(DVIfile, 0L, absolute);       /* read the dvifile from the start   */
  204.     if ((opcode = skipnops()) != PRE)
  205.         errorexit(nopre);
  206.     opcode = (int) get1();        /* check id in preamble, ignore rest of it */
  207.     if (opcode != VERSIONID)
  208.         errorexit(badid);
  209.     fseek(DVIfile, 12L, relative);  /* numerator, denominator, magnification */
  210.     fseek(DVIfile, get1(), relative);         /* skip job identification     */
  211.  
  212. } /* preamble */
  213.  
  214. /*----------------------------------------------------------------------------*/
  215.  
  216. void walkpages()                  /* process the pages in the DVI-file */
  217. {
  218.     register bool wantpage;
  219.  
  220.     pagecounter = 0L;
  221.     while ((opcode = skipnops()) != POST) {
  222.         if (opcode != BOP)              /* should be at start of page now    */
  223.             errorexit(nobop);
  224.         else {
  225.             pagecounter++;
  226.             pagenr = sget4();           /* get TeX page number               */
  227.             fseek(DVIfile, 36L, relative); /* skip page header */
  228.             backpointer = sget4();      /* get previous page offset          */
  229.             if (pageswitchon)
  230.                 if (sequenceon)
  231.                     wantpage = inlist(pagecounter);
  232.                 else
  233.                     wantpage = inlist(pagenr);
  234.             else
  235.                 wantpage = TRUE;
  236.  
  237.             if (wantpage) {
  238.                 initpage();
  239.                 dopage();
  240.                 printpage();
  241.             }
  242.             else {
  243.                 skippage();
  244.             }
  245.         }
  246.     }
  247.  
  248. } /* walkpages */
  249.  
  250. /*---------------------------------------------------------------------------*/
  251.  
  252. void initpage()
  253. {
  254.  
  255.     h = 0L;  v = 0L;                        /* initialize coordinates   */
  256.     x = 0L;  w = 0L;  y = 0L;  z = 0L;      /* initialize amounts       */
  257.     sptr = 0;                               /* initialize stack         */
  258.     currentline = getline();                /* initialize list of lines */
  259.     currentline->vv = 0L;
  260.     firstline   = currentline;
  261.     lastline    = currentline;
  262.     firstcolumn = rightmargin;
  263.     if (pageswitchon) {
  264.         if ((sequenceon && (pagecounter != firstpage->pag)) ||
  265.             (!sequenceon && (pagenr != firstpage->pag)))
  266.             if (noffd)
  267.                 fprintf(output, "^L\n");
  268.             else
  269.                 putc(FORM, output);
  270.     }
  271.     else
  272.         if (backpointer != -1)              /* not FORM at first page   */
  273.             if (noffd)
  274.                 fprintf(output, "^L\n");
  275.             else
  276.                 putc(FORM, output);
  277.  
  278. } /* initpage */
  279.  
  280. /*----------------------------------------------------------------------------*/
  281.  
  282. void dopage()
  283. {
  284.  
  285.     while ((opcode = (int) get1()) != EOP) {    /* process page until eop */
  286.         if (opcode > POST_POST)
  287.             errorexit(illop);
  288.         else if (opcode <= LASTCHAR)
  289.             outchar((char) opcode);
  290.         else
  291.             switch (opcode) {
  292.                 case SET1     : setchar(get1()); break;
  293.                 case SET2     : setchar(get2()); break;
  294.                 case SET3     : setchar(get3()); break;
  295.                 case SET4     : setchar(get4()); break;
  296.                 case SET_RULE : rule(MOVE, sget4(), sget4()); break;
  297.                 case PUT1     : putcharacter(get1()); break;
  298.                 case PUT2     : putcharacter(get2()); break;
  299.                 case PUT3     : putcharacter(get3()); break;
  300.                 case PUT4     : putcharacter(get4()); break;
  301.                 case PUT_RULE : rule(STAY, sget4(), sget4()); break;
  302.                 case NOP      : break;  /* no-op */
  303.                 case BOP      : errorexit(bdbop); break;
  304. /*              case EOP      : break;  strange place to have EOP */
  305.                 case PUSH     : if (sptr >= stackmax)            /* push */
  306.                                      errorexit(stkof);
  307.                                 stack[sptr].hh = h;
  308.                                 stack[sptr].vv = v;
  309.                                 stack[sptr].ww = w;
  310.                                 stack[sptr].xx = x;
  311.                                 stack[sptr].yy = y;
  312.                                 stack[sptr].zz = z;
  313.                                 sptr++;
  314.                                 break;
  315.                 case POP      : if (sptr == 0)                   /* pop */
  316.                                     errorexit(stkuf);
  317.                                 sptr--;
  318.                                 h = stack[sptr].hh;
  319.                                 v = stack[sptr].vv;
  320.                                 w = stack[sptr].ww;
  321.                                 x = stack[sptr].xx;
  322.                                 y = stack[sptr].yy;
  323.                                 z = stack[sptr].zz;
  324.                                 break;
  325.                 case RIGHT1   : (void) horizontalmove(sget1()); break;
  326.                 case RIGHT2   : (void) horizontalmove(sget2()); break;
  327.                 case RIGHT3   : (void) horizontalmove(sget3()); break;
  328.                 case RIGHT4   : (void) horizontalmove(sget4()); break;
  329.                 case W0       : h += w; break;
  330.                 case W1       : w = horizontalmove(sget1()); break;
  331.                 case W2       : w = horizontalmove(sget2()); break;
  332.                 case W3       : w = horizontalmove(sget3()); break;
  333.                 case W4       : w = horizontalmove(sget4()); break;
  334.                 case X0       : h += x; break;
  335.                 case X1       : x = horizontalmove(sget1()); break;
  336.                 case X2       : x = horizontalmove(sget2()); break;
  337.                 case X3       : x = horizontalmove(sget3()); break;
  338.                 case X4       : x = horizontalmove(sget4()); break;
  339.                 case DOWN1    : v += sget1(); break;
  340.                 case DOWN2    : v += sget2(); break;
  341.                 case DOWN3    : v += sget3(); break;
  342.                 case DOWN4    : v += sget4(); break;
  343.                 case Y0       : v += y; break;
  344.                 case Y1       : y = sget1(); v += y; break;
  345.                 case Y2       : y = sget2(); v += y; break;
  346.                 case Y3       : y = sget3(); v += y; break;
  347.                 case Y4       : y = sget4(); v += y; break;
  348.                 case Z0       : v += z; break;
  349.                 case Z1       : z = sget1(); v += z; break;
  350.                 case Z2       : z = sget2(); v += z; break;
  351.                 case Z3       : z = sget3(); v += z; break;
  352.                 case Z4       : z = sget4(); v += z; break;
  353.                 case FNT1     :
  354.                 case FNT2     :
  355.                 case FNT3     :                       /* ignore font changes */
  356.                 case FNT4     : fseek(DVIfile, (long) opcode-FNT1+1, relative);
  357.                                 break;
  358.                 case XXX1     : fseek(DVIfile, get1(), relative); break;
  359.                 case XXX2     : fseek(DVIfile, get2(), relative); break;
  360.                 case XXX3     : fseek(DVIfile, get3(), relative); break;
  361.                 case XXX4     : fseek(DVIfile, get4(), relative); break;
  362.                 case FNT_DEF1 :
  363.                 case FNT_DEF2 :
  364.                 case FNT_DEF3 :                   /* ignore font definitions */
  365.                 case FNT_DEF4 : fseek(DVIfile, (long) opcode-FNT_DEF1+1+12,
  366.                                                relative);
  367.                                 fseek(DVIfile, get1() + get1(), relative);
  368.                                 break;
  369.                 case PRE      : errorexit(bdpre); break;
  370.                 case POST     : errorexit(bdpst); break;
  371.                 case POST_POST: errorexit(bdpp); break;
  372.             }
  373.     }
  374.  
  375. } /* dopage */
  376.  
  377. /*----------------------------------------------------------------------------*/
  378.  
  379. void skippage()                /* skip past one page */
  380. {
  381.     register int opcode;
  382.  
  383.     while ((opcode = (int) get1()) != EOP) {
  384.         if (opcode > POST_POST)
  385.             errorexit(illop);
  386.         else
  387.             switch (opcode) {
  388.                 case SET1     :
  389.                 case PUT1     :
  390.                 case RIGHT1   :
  391.                 case W1       :
  392.                 case X1       :
  393.                 case DOWN1    :
  394.                 case Y1       :
  395.                 case Z1       :
  396.                 case FNT1     : fseek(DVIfile, 1L, relative); break;
  397.                 case SET2     :
  398.                 case PUT2     :
  399.                 case RIGHT2   :
  400.                 case W2       :
  401.                 case X2       :
  402.                 case DOWN2    :
  403.                 case Y2       :
  404.                 case Z2       :
  405.                 case FNT2     : fseek(DVIfile, 2L, relative); break;
  406.                 case SET3     :
  407.                 case PUT3     :
  408.                 case RIGHT3   :
  409.                 case W3       :
  410.                 case X3       :
  411.                 case DOWN3    :
  412.                 case Y3       :
  413.                 case Z3       :
  414.                 case FNT3     : fseek(DVIfile, 3L, relative); break;
  415.                 case SET4     :
  416.                 case PUT4     :
  417.                 case RIGHT4   :
  418.                 case W4       :
  419.                 case X4       :
  420.                 case DOWN4    :
  421.                 case Y4       :
  422.                 case Z4       :
  423.                 case FNT4     : fseek(DVIfile, 4L, relative); break;
  424.                 case SET_RULE :
  425.                 case PUT_RULE : fseek(DVIfile, 8L, relative); break;
  426.                 case BOP      : errorexit(bdbop); break;
  427.                 case XXX1     : fseek(DVIfile, get1(), relative); break;
  428.                 case XXX2     : fseek(DVIfile, get2(), relative); break;
  429.                 case XXX3     : fseek(DVIfile, get3(), relative); break;
  430.                 case XXX4     : fseek(DVIfile, get4(), relative); break;
  431.                 case FNT_DEF1 :
  432.                 case FNT_DEF2 :
  433.                 case FNT_DEF3 :
  434.                 case FNT_DEF4 : fseek(DVIfile, (long) opcode-FNT_DEF1+1+12,
  435.                                       relative);
  436.                                 fseek(DVIfile, get1()+get1(), relative);
  437.                                 break;
  438.                 case PRE      : errorexit(bdpre); break;
  439.                 case POST     : errorexit(bdpst); break;
  440.                 case POST_POST: errorexit(bdpp); break;
  441.         }
  442.     }
  443.  
  444. } /* skippage */
  445.  
  446. /*---------------------------------------------------------------------------*/
  447.  
  448. void printpage()       /* 'end of page', writes lines of page to output file */
  449. {
  450.     register int  i, j;
  451.     register char ch;
  452.  
  453.     if (sptr != 0)
  454.         fprintf(stderr, "dvi2tty: warning - stack not empty at eop.\n");
  455.     for (currentline = firstline; currentline != nil;
  456.           currentline = currentline->next) {
  457.         if (currentline != firstline) {
  458.             foo = ((currentline->vv - currentline->prev->vv)/VERTICALEPSILON)-1;
  459.             if (foo > 3)
  460.                 foo = 3;        /* linespacings not too large */
  461.             for (i = 1; i <= (int) foo; i++)
  462.                 putc('\n', output);
  463.         }
  464.         if (currentline->charactercount >= leftmargin) {
  465.             foo = ttywidth - 2;
  466.             for (i = firstcolumn, j = 1; i <= currentline->charactercount;
  467.                    i++, j++) {
  468.                 ch = currentline->text[i - leftmargin];
  469.                 if (ch >= SPACE)
  470.                     putc(ch, output);
  471.                 if ((j > (int) foo) && (currentline->charactercount > i+1)) {
  472.                         fprintf(output, "*\n");         /* if line to large */
  473.                         fprintf(output, " *");          /* mark output      */
  474.                         j = 2;
  475.                 }
  476.             } 
  477.         }
  478.         putc('\n', output);
  479.     } 
  480.  
  481.     currentline = firstline;
  482.     while (currentline->next != nil) {
  483.         currentline = currentline->next;
  484.         free(currentline->prev);
  485.     }
  486.     free(currentline);              /* free last line */
  487.     currentline = nil;
  488.  
  489. } /* printpage */
  490.  
  491. /*----------------------------------------------------------------------------*/
  492.  
  493. bool inlist(pagenr)                         /* ret true if in list of pages */
  494. register long pagenr;
  495. {
  496.  
  497.     while ((currentpage->pag < 0) && (currentpage->pag != pagenr) &&
  498.            !currentpage->all && (currentpage->nxt != nil))
  499.         currentpage = currentpage->nxt;
  500.     if ((currentpage->all && (pagenr < currentpage->pag)) ||
  501.          (currentpage->pag == pagenr))
  502.             return TRUE;
  503.     else if (pagenr > 0) {
  504.         while ((currentpage->pag < pagenr) && (currentpage->nxt != nil))
  505.             currentpage = currentpage->nxt;
  506.         if (currentpage->pag == pagenr)
  507.             return TRUE;
  508.     }
  509.     return FALSE;
  510.  
  511. } /* inlist */
  512.  
  513. /*----------------------------------------------------------------------------*/
  514.  
  515. void rule(moving, rulewt, ruleht)
  516. register bool moving;
  517. register long rulewt, ruleht;
  518. {   /* output a rule (vertical or horizontal), increment h if moving is true */
  519.  
  520.     register char ch;               /* character to set rule with            */
  521.     register long saveh, savev;
  522.                               /* rule   --   starts up the recursive routine */
  523.     if (!moving)
  524.         saveh = h;
  525.     if ((ruleht <= 0) || (rulewt <= 0))
  526.         h += rulewt;
  527.     else {
  528.         savev = v;
  529.         if ((ruleht / rulewt) > 0)
  530.             ch = '|';
  531.         else if (ruleht > (VERTICALEPSILON / 2))
  532.             ch = '=';
  533.         else
  534.             ch = '_';
  535.         ruleaux(rulewt, ruleht, ch);
  536.         v = savev;
  537.     }
  538.     if (!moving)
  539.         h = saveh;
  540.  
  541. } /* rule */
  542.  
  543.  
  544.  
  545. void ruleaux(rulewt, ruleht, ch)     /* recursive  that does the job */
  546. register long rulewt, ruleht;
  547. register char ch;
  548. {
  549.     register long wt, lmh, rmh;
  550.  
  551.     wt = rulewt;
  552.     lmh = h;                        /* save left margin                      */
  553.     if (h < 0) {                    /* let rules that start at negative h    */
  554.         wt -= h;                    /* start at coordinate 0, but let it     */
  555.         h = 0;                      /*   have the right length               */
  556.     }
  557.     while (wt > 0) {                /* output the part of the rule that      */
  558.         rmh = h;                    /*   goes on this line                   */
  559.         outchar(ch);
  560.         wt -= (h-rmh);              /* decrease the width left on line       */
  561.     }
  562.     ruleht -= VERTICALEPSILON;      /* decrease the height                   */
  563.     if (ruleht > VERTICALEPSILON) { /* still more vertical?                  */
  564.         rmh = h;                    /* save current h (right margin)         */
  565.         h = lmh;                    /* restore left margin                   */
  566.         v -= (VERTICALEPSILON + VERTICALEPSILON / 10);
  567.         ruleaux(rulewt, ruleht, ch);
  568.         h = rmh;                    /* restore right margin                  */
  569.     }
  570.  
  571. } /* ruleaux */
  572.  
  573. /*----------------------------------------------------------------------------*/
  574.  
  575. long horizontalmove(amount)
  576. register long amount;
  577. {
  578.  
  579. #if defined(MSDOS)
  580.     if (labs(amount) > charwidth / 4L) {
  581. #else
  582.     if (abs(amount) > charwidth / 4L) {
  583. #endif
  584.         foo = 3*charwidth / 4;
  585.         if (amount > 0)
  586.             amount = ((amount+foo) / charwidth) * charwidth;
  587.         else
  588.             amount = ((amount-foo) / charwidth) * charwidth;
  589.         h += amount;
  590.         return amount;
  591.     }
  592.     else
  593.         return 0;
  594.  
  595. }   /* horizontalmove */
  596.  
  597. /*----------------------------------------------------------------------------*/
  598.  
  599. int skipnops()                      /* skips by no-op commands  */
  600. {
  601.     register int opcode;
  602.  
  603.     while ((opcode = (int) num(1)) == NOP);
  604.     return opcode;
  605.  
  606. } /* skipnops */
  607.  
  608. /*----------------------------------------------------------------------------*/
  609.  
  610. linetype *getline()             /* returns an initialized line-object */
  611. {
  612.     register int  i;
  613.     register linetype *temp;
  614.  
  615.     if ((temp = (linetype *) malloc(sizeof(linetype))) == NULL) 
  616.         errorexit(lnerq);
  617.     temp->charactercount = leftmargin - 1;
  618.     temp->prev = nil;
  619.     temp->next = nil;
  620.     for (i = 0; i < LINELEN; i++)
  621.         temp->text[i] = ' ';
  622.     temp->text[i] = '\0';
  623.     return temp;
  624.  
  625. } /* getline */
  626.  
  627. /*----------------------------------------------------------------------------*/
  628.  
  629. linetype *findline()            /* find best fit line were text should go */
  630. {                               /* and generate new line if needed        */
  631.     register linetype *temp;
  632.     register long topd, botd;
  633.  
  634.     if (v <= firstline->vv) {                      /* above first line */
  635.         if (firstline->vv - v > VERTICALEPSILON) {
  636.             temp = getline();
  637.             temp->next = firstline;
  638.             firstline->prev = temp;
  639.             temp->vv = v;
  640.             firstline = temp;
  641.         }
  642.         return firstline;
  643.     }
  644.  
  645.     if (v >= lastline->vv) {                       /* below last line */
  646.         if (v - lastline->vv > VERTICALEPSILON) {
  647.             temp = getline();
  648.             temp->prev = lastline;
  649.             lastline->next = temp;
  650.             temp->vv = v;
  651.             lastline = temp;
  652.         }
  653.         return lastline;
  654.     }
  655.  
  656.     temp = lastline;                               /* in between two lines */
  657.     while ((temp->vv > v) && (temp != firstline))
  658.         temp = temp->prev;
  659.  
  660.     /* temp->vv < v < temp->next->vv --- temp is above, temp->next is below */
  661.     topd = v - temp->vv;
  662.     botd = temp->next->vv - v;
  663.     if ((topd < VERTICALEPSILON) || (botd < VERTICALEPSILON))
  664.         if (topd < botd)                           /* take best fit */
  665.             return temp;
  666.         else
  667.             return temp->next;
  668.  
  669.     /* no line fits suitable, generate a new one */
  670.     currentline = getline();
  671.     currentline->next = temp->next;
  672.     currentline->prev = temp;
  673.     temp->next->prev = currentline;
  674.     temp->next = currentline;
  675.     currentline->vv = v;
  676.     return currentline;
  677.  
  678. } /* findline */
  679.  
  680. /*----------------------------------------------------------------------------*/
  681.  
  682. unsigned long num(size)
  683. register int size;
  684. {
  685.     register int i;
  686.     register long x = 0;
  687.  
  688.     for (i = 0; i < size; i++)
  689.         x = (x << 8) + (unsigned) getc(DVIfile);
  690.     return x;
  691.  
  692. } /* num */
  693.  
  694.  
  695. long snum(size)
  696. register int size;
  697. {
  698.     register int i;
  699.     register long x = 0;
  700.  
  701.     x = getc(DVIfile);
  702.     if (x & 0x80)
  703.         x -= 0x100;
  704.     for (i = 1; i < size; i++)
  705.         x = (x << 8) + (unsigned) getc(DVIfile);
  706.     return x;
  707.  
  708. } /* snum */
  709.  
  710. /*----------------------------------------------------------------------------*/
  711.  
  712. void outchar(ch)                     /* output ch to appropriate line */
  713. register char ch;
  714. {
  715.     register int i, j;
  716.  
  717. /*     fprintf(stderr, "hor: %ld, ver: %ld\n", h, v); */
  718. #if defined(MSDOS)
  719.     if (labs(v - currentline->vv) > VERTICALEPSILON / 2L)
  720. #else
  721.     if (abs(v - currentline->vv) > VERTICALEPSILON / 2L)
  722. #endif
  723.         currentline = findline();
  724.     switch (ch) {
  725.         case 11  :  outchar('f'); ch = 'f'; break;  /* ligature        */
  726.         case 12  :  outchar('f'); ch = 'i'; break;  /* ligature        */
  727.         case 13  :  outchar('f'); ch = 'l'; break;  /* ligature        */
  728.         case 14  :  outchar('f'); outchar('f');
  729.                                   ch = 'i'; break;  /* ligature        */
  730.         case 15  :  outchar('f'); outchar('f');
  731.                                   ch = 'l'; break;  /* ligature        */
  732.         case 16  :  ch = 'i'; break;
  733.         case 17  :  ch = 'j'; break;
  734.         case 25  :  outchar('s'); ch = 's'; break;  /* German double s */
  735.         case 26  :  outchar('a'); ch = 'e'; break;  /* Dane/Norw ae    */
  736.         case 27  :  outchar('o'); ch = 'e'; break;  /* Dane/Norw oe    */
  737.         case 28  :  if (scascii)
  738.                         ch = '|';                   /* Dane/Norw /o    */
  739.                     else
  740.                         ch = 'o';
  741.                     break;
  742.         case 29  :  outchar('A'); ch = 'E'; break;  /* Dane/Norw AE    */
  743.         case 30  :  outchar('O'); ch = 'E'; break;  /* Dane/Norw OE    */
  744.         case 31  :  if (scascii)
  745.                         ch = '\\';                  /* Dane/Norw /O    */
  746.                     else
  747.                         ch = 'O';
  748.                     break;
  749. #if 0
  750.         case 92  :  ch = '"'; break;                /* beginning qoute  */
  751.         case 123 :  ch = '-'; break;
  752.         case 124 :  ch = '_'; break;
  753.         case 125 :  ch = '"'; break;
  754.         case 126 :  ch = '"'; break;
  755. #endif
  756.     }
  757. #if 0
  758.     j = (int) (((double) h / (double) maxpagewidth) * (ttywidth-1)) + 1;
  759. #else
  760.     j = (int) (h / charwidth);
  761. #endif
  762.     if (j > rightmargin)
  763.         j = rightmargin;
  764.     else if (j < leftmargin)
  765.         j = leftmargin;
  766.     foo = leftmargin - 1;
  767.     /*-------------------------------------------------------------*/
  768.     /* The following is very specialized code, it handles national */
  769.     /* Swedish characters. They are respectively: a and o with two */
  770.     /* dots ("a & "o) and a with a circle (Oa). In Swedish "ASCII" */
  771.     /* these characters replace }{|][ and \.  TeX outputs these by */
  772.     /* first issuing the dots or circle and then backspace and set */
  773.     /* the a or o.  When dvitty finds an a or o it searches in the */
  774.     /* near vicinity for the character codes that represent circle */
  775.     /* or dots and if one is found the corresponding national char */
  776.     /* replaces the special character codes.                       */
  777.     /*-------------------------------------------------------------*/
  778.     if (scascii) {
  779.         if ((ch == 'a') || (ch == 'A') || (ch == 'o') || (ch == 'O')) {
  780.             for (i = IMAX(leftmargin, j-2);
  781.                  i <= IMIN(rightmargin, j+2);
  782.                  i++)
  783.                 if ((currentline->text[i - leftmargin] == 127) ||
  784.                     (currentline->text[i - leftmargin] == 23))
  785.                     foo = i;
  786.             if (foo >= leftmargin) {
  787.                 j = (int) foo;
  788.                 switch (currentline->text[j - leftmargin]) {
  789.                     case 127 : if (ch == 'a')
  790.                                    ch = '{';
  791.                                else if (ch == 'A')      /* dots ... */
  792.                                    ch = '[';
  793.                                else if (ch == 'o')
  794.                                    ch = '|';
  795.                                else if (ch == 'O')
  796.                                    ch = '\\';
  797.                                break;
  798.                     case 23  : if (ch == 'a')
  799.                                    ch = '}';
  800.                                else if (ch == 'A')      /* circle */
  801.                                    ch = ']';
  802.                                break;
  803.                 }
  804.             }
  805.         }
  806.     }
  807.     /*----------------- end of 'Scandinavian code' ----------------*/
  808.     if (foo == leftmargin-1)
  809.         while ((currentline->text[j - leftmargin] != SPACE)
  810.                && (j < rightmargin)) {
  811.             j++;
  812.             h += charwidth;
  813.         }
  814.     if ( ((ch >= SPACE) && (ch != DEL)) ||
  815.          (scascii && (ch == 23)) ) {
  816.         if (j < rightmargin)
  817.             currentline->text[j - leftmargin] = ch;
  818.         else
  819.             currentline->text[rightmargin - leftmargin] = '@';
  820.         if (j > currentline->charactercount)
  821.             currentline->charactercount = j;
  822.         if (j < firstcolumn)
  823.             firstcolumn = j;
  824.         h += charwidth;
  825.     }
  826.  
  827. } /* outchar */
  828.  
  829. /*----------------------------------------------------------------------------*/
  830.  
  831. void putcharacter(charnr)            /* output character, don't change h */
  832. register long charnr;
  833. {
  834.     register long saveh;
  835.  
  836.     saveh = h;
  837.     if ((charnr >= 0) && (charnr <= LASTCHAR))
  838.         outchar((char) charnr);
  839.     else
  840.         setchar(charnr);
  841.     h = saveh;
  842.  
  843. } /* putcharacter */
  844.  
  845. /*----------------------------------------------------------------------------*/
  846.  
  847. void setchar(charnr)
  848. long charnr;
  849. {    /* should print characters with character code>127 from current font */
  850.      /* note that the parameter is a dummy, since ascii-chars are<=127    */
  851.  
  852.     outchar('#');
  853.  
  854. } /* setchar */
  855.  
  856.