1 /*
2  * dvi2tty
3  * Copyright (C) 2003 Marcel J.E. Mol <marcel@mesa.nl>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  */
20 
21 /*
22  * Include files
23  */
24 
25 #include "dvi2tty.h"
26 
27 #if defined(VMS)
28 # include types.h
29 # include stat
30 #else
31 # if defined(THINK_C)
32 #  include <unix.h>
33 # else
34 #  include <sys/types.h>
35 #  include <sys/stat.h>
36 # endif
37 #endif
38 
39 #if defined(MSDOS) || defined(THINK_C)
40 # include <math.h>
41 #endif
42 
43 #include "commands.h"
44 
45 
46 
47 /*
48  * Constant definitions
49  */
50 
51 #if defined(VMS)
52 #define mseek vmsseek
53 #define ROUND(a)        (a>=0.0 ?  (int) (a + 0.5) : (int) (a - 0.5) )
54 #else
55 #define mseek fseek
56 #endif
57 
58 #define VERSIONID            2 /* dvi version number that pgm handles      */
59 #define VERTICALEPSILON 450000L /* crlf when increasing v more than this   */
60 
61 #define rightmargin     MAXTERMWIDTH+20
62                                /* nr of columns allowed to the right of h=0*/
63 #define leftmargin      -50    /* give some room for negative h-coordinate */
64 #define LINELEN         rightmargin - leftmargin + 1
65 
66 #define MOVE            TRUE   /* if advancing h when outputing a rule     */
67 #define STAY            FALSE  /* if not advancing h when outputing a rule */
68 
69 #define absolute        0      /* for seeking in files                     */
70 #define relative        1
71 
72 #define FORM             12    /* formfeed                                 */
73 #define SPACE            32    /* space                                    */
74 #define DEL             127    /* delete                                   */
75 
76 #define LASTCHAR        127    /* max dvi character, above are commands    */
77 
78 #define IMIN(a, b)      (a<b ? a : b)
79 #define IMAX(a, b)      (a>b ? a : b)
80 
81 #define get1()          num(1)
82 #define get2()          num(2)
83 #define get3()          num(3)
84 #define get4()          num(4)
85 #define sget1()         snum(1)
86 #define sget2()         snum(2)
87 #define sget3()         snum(3)
88 #define sget4()         snum(4)
89 
90 
91 /*
92  * Structure and variable definitions
93  */
94 
95 const char *dvistuff = "@(#) dvistuff.c  " VERSION " 20101027 M.J.E. Mol (c) 1989-2010";
96 
97 typedef struct {
98     long hh;
99     long vv;
100     long ww;
101     long xx;
102     long yy;
103     long zz;
104 } stackitem;
105 
106 typedef struct lineptr {        /* the lines of text to be output to outfile */
107     long            vv;                 /* vertical position of the line     */
108     int             charactercount;     /* pos of last char on line          */
109     struct lineptr *prev;               /* preceding line                    */
110     struct lineptr *next;               /* succeeding line                   */
111     unsigned char   text[LINELEN+1];    /* leftmargin...rightmargin          */
112 } linetype;
113 
114 typedef struct _font {
115     long    num;
116     struct _font * next;
117     char  * name;
118     char    flags; /* to store font types, to get rid of nttj/asciip/uptex/ttfont/symbolfon/mifont vars */
119     int     fontnum; /* helper for japanese fonts */
120 } font;
121 
122 #define SYMFONT   0x01
123 #define TTFONT    0x02
124 #define MIFONT    0x04
125 #define JAPFONT   0x08
126 #define JASCFONT  0x10
127 
128 
129 bool        pageswitchon;       /* true if user-set pages to print           */
130 bool        sequenceon;         /* false if pagesw-nrs refers to TeX-nrs     */
131 bool        scascii;            /* if true make Scand. nat. chars right      */
132 bool        latin1;             /* if true make latin1 chars right           */
133 bool        accent;             /* if true output accents etc: \'{e} etc.    */
134 bool        ttfont = FALSE;     /* if true we assumed ttfonts, not cmr       */
135 bool        symbolfont = FALSE; /* true if font is a symbol font             */
136 bool        nttj = FALSE;       /* switch to NTT japanese fonts ...          */
137 bool        asciip = FALSE;      /* switch to ASCII japanese fonts ...       */
138 bool        uptex = FALSE;      /* switch to upTeX CJK fonts ...             */
139 bool        japan = FALSE;      /* switch to NTT/ASCII/.. japanese fonts ... */
140 bool        jautodetect = FALSE; /* switch if do auto detection of Japanese TeX */
141 bool        jdetect = FALSE;     /* switch if Japanese TeX detection is done */
142 bool        mifont = FALSE;      /* ASCII japanese font ??? */
143 bool        noffd;              /* if true output ^L instead of formfeed     */
144 const char *delim;              /* -bdelim for font switch printing          */
145 bool        printfont;          /* true if user wants font switches printed  */
146 bool        allchar;            /* true if user sets all characters          */
147                                 /* overrides sscasci, accent                 */
148 
149 int         opcode;             /* dvi-opcodes                               */
150 
151 long        h, v;               /* coordinates, horizontal and vertical      */
152 long        w, x, y, z;         /* horizontal and vertical amounts           */
153 
154 long        pagecounter;        /* sequence page number counter              */
155 long        backpointer;        /* pointer for offset to previous page       */
156 long        pagenr;             /* TeX page number                           */
157 int         stackmax;           /* stacksize required                        */
158 
159 long        maxpagewidth;       /* width of widest page in file              */
160 long        charwidth;          /* aprox width of character                  */
161 long        lineheight = VERTICALEPSILON;
162                                 /* aprox height of a line                    */
163 
164 linetype *  currentline;        /* pointer to current line on current page   */
165 linetype *  firstline;          /* pointer to first line on current page     */
166 linetype *  lastline;           /* pointer to last line on current page      */
167 int         firstcolumn;        /* 1st column with something to print        */
168 
169 stackitem * stack;              /* stack for dvi-pushes                      */
170 int         sptr;               /* stack pointer                             */
171 
172 font * fonts = NULL;            /* List of fontnames defined                 */
173 font * fnt = NULL;              /* Current font                              */
174 
175 int    kanji1 = 0;     /* number of rest of trailer bytes in kanji character */
176 
177 
178 
179 /*
180  * Function definitions
181  */
182 
183 #if defined(MSDOS)
184 void            postamble       (void);
185 void            preamble        (void);
186 void            walkpages       (void);
187 void            initpage        (void);
188 void            dopage          (void);
189 void            skippage        (void);
190 void            printpage       (void);
191 bool            inlist          (long);
192 void            rule            (bool, long, long);
193 void            ruleaux         (long, long, char);
194 long            horizontalmove  (long);
195 int             skipnops        (void);
196 linetype    *   my_getline      (void);
197 linetype    *   findline        (void);
198 unsigned long   num             (int);
199 long            snum            (int);
200 void            dochar          (unsigned char);
201 void            symchar         (unsigned char);
202 void            normchar        (unsigned char);
203 void            outchar         (unsigned char);
204 void            putcharacter    (long);
205 void            setchar         (long);
206 void            fontdef         (int);
207 void            setfont         (long);
208 void            jischar         (unsigned long);
209 int             compute_jis     (int, unsigned int, unsigned int *, unsigned int *);
210 void            dokanji         (long);
211 int             getjsubfont     (char *);
212 
213 #else
214 void            postamble       (void);
215 void            preamble        (void);
216 void            walkpages       (void);
217 void            initpage        (void);
218 void            dopage          (void);
219 void            skippage        (void);
220 void            printpage       (void);
221 bool            inlist          (long pagenr);
222 void            rule            (bool moving, long rulewt, long ruleht);
223 void            ruleaux         (long rulewt, long ruleht, char ch);
224 long            horizontalmove  (long amount);
225 int             skipnops        (void);
226 linetype    *   my_getline      (void);
227 linetype    *   findline        (void);
228 unsigned long   num             (int size);
229 long            snum            (int size);
230 void            dochar          (unsigned char ch);
231 void            symchar         (unsigned char ch);
232 void            normchar        (unsigned char ch);
233 void            outchar         (unsigned char ch);
234 void            putcharacter    (long charnr);
235 void            setchar         (long charnr);
236 void            fontdef         (int x);
237 void            setfont         (long fntnum);
238 void            jischar         (unsigned long ch);
239 void            compute_jis     (int f, unsigned int c, unsigned int * ku, unsigned int * ten);
240 void            dokanji         (long ch);
241 int             getjsubfont     (char * s);
242 #if defined(VMS)
243 long		vmsseek		();
244 long		vms_ftell	();
245 long		vms_ungetc	();
246 #endif
247 #endif
248 
249 
250 
251 /*
252  * DVIMAIN -- The main function for processing the dvi file.
253  *            Here we assume there are to file pointers: DVIfile and output.
254  *            Also we have a list of pages pointed to by 'currentpage',
255  *            which is only used (in 'inlist()') when a page list is given.
256  */
257 
dvimain(void)258 void dvimain(void)
259 {
260 
261     postamble();                            /* seek and process the postamble */
262     preamble();                             /* process preamble               */
263     /* note that walkpages *must* immediately follow preamble */
264     walkpages();                            /* time to do the actual work!    */
265 
266     return;
267 
268 } /* dvimain */
269 
270 
271  /*
272   * POSTAMBLE -- Find and process postamble, use random access
273   */
274 
postamble(void)275 void postamble(void)
276 {
277     register long size;
278     register int  count;
279 #if !defined (THINK_C) && defined(VMS)
280     struct stat st;
281 #endif
282 
283 #if defined (THINK_C)
284     size = DVIfile->len;
285 #elif defined(VMS)
286     fstat (fileno(DVIfile), &st);
287     size = (long) st.st_size;                   /* get size of file          */
288 #else
289     fseek (DVIfile, 0L, SEEK_END);
290     size = ftell (DVIfile);                     /* get size of file          */
291 #endif
292 
293     count = -1;
294     do {              /* back file up past signature bytes (223), to id-byte */
295         if (size-- == 0)
296             errorexit(nopst);
297         mseek(DVIfile, size, absolute);
298         opcode = (int) get1();
299         count++;
300     } while (opcode == TRAILER);
301     if (count < 4) {                            /* must have 4 trailer bytes */
302          foo = count;
303          errorexit(fwsgn);
304     }
305     if (opcode != VERSIONID)
306         errorexit(badid);
307     mseek(DVIfile, size-4, absolute);       /* back up to back-pointer       */
308     mseek(DVIfile, sget4(), absolute);      /* and to start of postamble     */
309     if (get1() != POST)
310         errorexit(nopst);
311     mseek(DVIfile, 20L, relative); /* lastpageoffset, numerator, denominator */
312                                    /* magnification, maxpageheight           */
313     maxpagewidth = sget4();
314     charwidth = maxpagewidth / (ttywidth + espace);
315     stackmax = (int) get2();
316     if ((stack = (stackitem *) malloc(stackmax * sizeof(stackitem))) == NULL)
317        errorexit(stkrq);
318 
319     /* get2() -- totalpages */
320     /* fontdefs  do fontdefs in flight ... */
321 
322     return;
323 
324 } /* postamble */
325 
326 
327 
328 /*
329  * PREAMBLE --process preamble, use random access
330  */
331 
preamble(void)332 void preamble(void)
333 {
334 
335     mseek(DVIfile, 0L, absolute);       /* read the dvifile from the start   */
336     if ((opcode = skipnops()) != PRE)
337         errorexit(nopre);
338     opcode = (int) get1();        /* check id in preamble, ignore rest of it */
339     if (opcode != VERSIONID)
340         errorexit(badid);
341     mseek(DVIfile, 12L, relative);  /* numerator, denominator, magnification */
342     mseek(DVIfile, get1(), relative);         /* skip job identification     */
343 
344     return;
345 
346 } /* preamble */
347 
348 
349 
350 /*
351  * WALKPAGES -- process the pages in the DVI-file
352  */
353 
walkpages(void)354 void walkpages(void)
355 {
356     register bool wantpage;
357 
358     pagecounter = 0L;
359     while ((opcode = skipnops()) != POST) {
360 
361         if (opcode != BOP)              /* should be at start of page now    */
362             errorexit(nobop);
363 
364         pagecounter++;
365         pagenr = sget4();               /* get TeX page number               */
366         mseek(DVIfile, 36L, relative);  /* skip page header */
367         backpointer = sget4();          /* get previous page offset          */
368         if (pageswitchon)
369             wantpage = inlist(sequenceon ? pagecounter : pagenr);
370         else
371             wantpage = TRUE;
372 
373         if (wantpage) {
374             initpage();
375             dopage();
376             printpage();
377         }
378         else
379                 skippage();
380     }
381 
382     return;
383 
384 } /* walkpages */
385 
386 
387 
388 /*
389  * INITPAGE -- Setup a new, empty page.
390  */
391 
initpage(void)392 void initpage(void)
393 {
394 
395     h = 0L;  v = 0L;                        /* initialize coordinates   */
396     x = 0L;  w = 0L;  y = 0L;  z = 0L;      /* initialize amounts       */
397     sptr = 0;                               /* initialize stack         */
398     currentline = my_getline();                /* initialize list of lines */
399     currentline->vv = 0L;
400     firstline   = currentline;
401     lastline    = currentline;
402     firstcolumn = rightmargin;
403     if (pageswitchon) {
404         if ((sequenceon ? pagecounter : pagenr) != firstpage->pag) {
405             if (noffd)
406                 fprintf(output, "^L\n");
407             else
408                 putc(FORM, output);
409         }
410     }
411     else
412         if (backpointer != -1) {             /* not FORM at first page   */
413             if (noffd)
414                 fprintf(output, "^L\n");
415             else
416                 putc(FORM, output);
417         }
418 
419     return;
420 
421 } /* initpage */
422 
423 
424 
425 /*
426  * DOPAGE -- Process the dvi file until an end-off-page.
427  *           Build up a page image.
428  */
429 
dopage(void)430 void dopage(void)
431 {
432 
433     while ((opcode = (int) get1()) != EOP) {    /* process page until eop */
434         if (opcode <= LASTCHAR)
435             dochar((unsigned char) opcode);
436         else if ((opcode >= FONT_00) && (opcode <= FONT_63))
437             setfont((long) opcode - FONT_00);
438         else if (opcode > POST_POST)
439             errorexit(illop);
440         else
441             switch (opcode) {
442                 case SET1     : nttj ? jischar(get1()) : setchar(get1());break;
443                 case SET2     : (asciip || uptex) ? dokanji(get2()) : setchar(get2()); break;
444                 case SET3     : uptex ? dokanji(get3()) : setchar(get3()); break;
445                 case SET4     : setchar(get4()); break;
446                 case SET_RULE : { long height = sget4();
447                                   rule(MOVE, sget4(), height); break;
448                                 }
449                 case PUT1     : putcharacter(get1()); break;
450                 case PUT2     : putcharacter(get2()); break;
451                 case PUT3     : putcharacter(get3()); break;
452                 case PUT4     : putcharacter(get4()); break;
453                 case PUT_RULE : { long height = sget4();
454                                   rule(STAY, sget4(), height); break;
455                                 }
456                 case NOP      : break;  /* no-op */
457                 case BOP      : errorexit(bdbop); break;
458 /*              case EOP      : break;  strange place to have EOP */
459                 case PUSH     : if (sptr >= stackmax)            /* push */
460                                      errorexit(stkof);
461                                 stack[sptr].hh = h;
462                                 stack[sptr].vv = v;
463                                 stack[sptr].ww = w;
464                                 stack[sptr].xx = x;
465                                 stack[sptr].yy = y;
466                                 stack[sptr].zz = z;
467                                 sptr++;
468                                 break;
469                 case POP      : if (sptr-- == 0)                 /* pop */
470                                     errorexit(stkuf);
471                                 h = stack[sptr].hh;
472                                 v = stack[sptr].vv;
473                                 w = stack[sptr].ww;
474                                 x = stack[sptr].xx;
475                                 y = stack[sptr].yy;
476                                 z = stack[sptr].zz;
477                                 break;
478                 case RIGHT1   : (void) horizontalmove(sget1()); break;
479                 case RIGHT2   : (void) horizontalmove(sget2()); break;
480                 case RIGHT3   : (void) horizontalmove(sget3()); break;
481                 case RIGHT4   : (void) horizontalmove(sget4()); break;
482                 case W0       : h += w; break;
483                 case W1       : w = horizontalmove(sget1()); break;
484                 case W2       : w = horizontalmove(sget2()); break;
485                 case W3       : w = horizontalmove(sget3()); break;
486                 case W4       : w = horizontalmove(sget4()); break;
487                 case X0       : h += x; break;
488                 case X1       : x = horizontalmove(sget1()); break;
489                 case X2       : x = horizontalmove(sget2()); break;
490                 case X3       : x = horizontalmove(sget3()); break;
491                 case X4       : x = horizontalmove(sget4()); break;
492                 case DOWN1    : v += sget1(); break;
493                 case DOWN2    : v += sget2(); break;
494                 case DOWN3    : v += sget3(); break;
495                 case DOWN4    : v += sget4(); break;
496                 case Y0       : v += y; break;
497                 case Y1       : y = sget1(); v += y; break;
498                 case Y2       : y = sget2(); v += y; break;
499                 case Y3       : y = sget3(); v += y; break;
500                 case Y4       : y = sget4(); v += y; break;
501                 case Z0       : v += z; break;
502                 case Z1       : z = sget1(); v += z; break;
503                 case Z2       : z = sget2(); v += z; break;
504                 case Z3       : z = sget3(); v += z; break;
505                 case Z4       : z = sget4(); v += z; break;
506                 case FNT1     :
507                 case FNT2     :
508                 case FNT3     :
509                 case FNT4     : setfont(num(opcode - FNT1 + 1));
510                                 break;
511                 case XXX1     : mseek(DVIfile, get1(), relative); break;
512                 case XXX2     : mseek(DVIfile, get2(), relative); break;
513                 case XXX3     : mseek(DVIfile, get3(), relative); break;
514                 case XXX4     : mseek(DVIfile, get4(), relative); break;
515                 case FNT_DEF1 :
516                 case FNT_DEF2 :
517                 case FNT_DEF3 :
518                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1);
519                                 break;
520                 case PRE      : errorexit(bdpre); break;
521                 case POST     : errorexit(bdpst); break;
522                 case POST_POST: errorexit(bdpp); break;
523             }
524     }
525 
526     return;
527 
528 } /* dopage */
529 
530 
531 
532 /*
533  * SKIPPAGE -- Scan the dvi file until an end-off-page.
534  *             Skip this page.
535  */
536 
skippage(void)537 void skippage(void)
538 {
539     register int opcode;
540 
541     while ((opcode = (int) get1()) != EOP) {
542         if (opcode > POST_POST)
543             errorexit(illop);
544         else
545             switch (opcode) {
546                 case SET1     :
547                 case PUT1     :
548                 case RIGHT1   :
549                 case W1       :
550                 case X1       :
551                 case DOWN1    :
552                 case Y1       :
553                 case Z1       : /* assume FNT change can also be skipped */
554                 case FNT1     : mseek(DVIfile, 1L, relative); break;
555                 case SET2     :
556                 case PUT2     :
557                 case RIGHT2   :
558                 case W2       :
559                 case X2       :
560                 case DOWN2    :
561                 case Y2       :
562                 case Z2       :
563                 case FNT2     : mseek(DVIfile, 2L, relative); break;
564                 case SET3     :
565                 case PUT3     :
566                 case RIGHT3   :
567                 case W3       :
568                 case X3       :
569                 case DOWN3    :
570                 case Y3       :
571                 case Z3       :
572                 case FNT3     : mseek(DVIfile, 3L, relative); break;
573                 case SET4     :
574                 case PUT4     :
575                 case RIGHT4   :
576                 case W4       :
577                 case X4       :
578                 case DOWN4    :
579                 case Y4       :
580                 case Z4       :
581                 case FNT4     : mseek(DVIfile, 4L, relative); break;
582                 case SET_RULE :
583                 case PUT_RULE : mseek(DVIfile, 8L, relative); break;
584                 case BOP      : errorexit(bdbop); break;
585                 case XXX1     : mseek(DVIfile, get1(), relative); break;
586                 case XXX2     : mseek(DVIfile, get2(), relative); break;
587                 case XXX3     : mseek(DVIfile, get3(), relative); break;
588                 case XXX4     : mseek(DVIfile, get4(), relative); break;
589                 case FNT_DEF1 :
590                 case FNT_DEF2 :
591                 case FNT_DEF3 :
592                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1); break;
593                 case PRE      : errorexit(bdpre); break;
594                 case POST     : errorexit(bdpst); break;
595                 case POST_POST: errorexit(bdpp); break;
596         }
597     }
598 
599     return;
600 
601 } /* skippage */
602 
603 
604 
605 /*
606  * PRINTPAGE -- 'end of page', writes lines of page to output file
607  */
608 
printpage(void)609 void printpage(void)
610 {
611     register int  i, j, k;
612     register unsigned char ch;
613     unsigned char buff[4];
614 
615     if (sptr != 0)
616         fprintf(stderr, "dvi2tty: warning - stack not empty at eop.\n");
617     for (currentline = firstline; currentline != nil;
618           currentline = currentline->next) {
619         if (currentline != firstline) {
620             foo = ((currentline->vv - currentline->prev->vv)/lineheight)-1;
621             if (foo > 3)
622                 foo = 3;            /* linespacings not too large */
623             for (i = 1; i <= (int) foo; i++)
624                 putc('\n', output);
625         }
626         if (currentline->charactercount >= leftmargin) {
627             foo = ttywidth - 2;
628             for (i = firstcolumn, j = 1; i <= currentline->charactercount;
629                    i++, j++) {
630                 ch = currentline->text[i - leftmargin];
631 
632 		if (japan) {
633 		  if (ch > 127) {
634 		    for (k = 0; k < 4; k++) {
635 		      if (i - leftmargin + k < LINELEN+1)
636 			buff[k] = currentline->text[i - leftmargin + k];
637 		      else buff[k] = '\0';
638 		    }
639 		    kanji1 = multistrlen(buff, 4, 0) - 1;
640 		  }
641 		  else kanji1 = 0;
642 		  if (kanji1 && (j + kanji1 > (int) foo) &&
643 		      (currentline->charactercount > i+1)) {
644 		    putc2('*', output);
645 		    putc2('\n', output);    /* if line to large */
646 		    putc2(' ', output);
647 		    putc2('*', output);     /* mark output      */
648 		    j = 2;
649 		  }
650 		}
651 
652                 if (ch >= SPACE || allchar) {
653 		  if (japan) {
654 		    for (k = 0; k < kanji1; k++) {
655 		      putc2(ch, output);
656 		      i++; j++;
657 		      ch = currentline->text[i - leftmargin];
658 		    }
659 		    putc2(ch, output);
660 		  }
661 		  else
662 		    putc(ch, output);
663 		}
664                 if ((j > (int) foo) && (currentline->charactercount > i+1)) {
665 		  if (japan) {
666 		    putc2('*', output);
667 		    putc2('\n', output);    /* if line to large */
668 		    putc2(' ', output);
669 		    putc2('*', output);     /* mark output      */
670 		  }
671 		  else {
672 		    fprintf(output, "*\n");         /* if line to large */
673 		    fprintf(output, " *");          /* mark output      */
674 		  }
675 		  j = 2;
676                 }
677             }
678         }
679         if (japan)
680           putc2('\n', output);
681         else
682           putc('\n', output);
683     }
684 
685     currentline = firstline;
686     while (currentline->next != nil) {
687         currentline = currentline->next;
688         free(currentline->prev);
689     }
690     free(currentline);              /* free last line */
691     currentline = nil;
692 
693     return;
694 
695 } /* printpage */
696 
697 
698 
699 /*
700  * INLIST -- return true if pagenr is in the list of pages to be printed.
701  */
702 
inlist(long pagenr)703 bool inlist(long pagenr)
704 {
705 
706     while ((currentpage->pag < 0) && (currentpage->pag != pagenr) &&
707            !currentpage->all && (currentpage->nxt != nil))
708         currentpage = currentpage->nxt;
709     if ((currentpage->all && (pagenr < currentpage->pag)) ||
710          (currentpage->pag == pagenr))
711             return TRUE;
712     else if (pagenr > 0) {
713         while ((currentpage->pag < pagenr) && (currentpage->nxt != nil))
714             currentpage = currentpage->nxt;
715         if (currentpage->pag == pagenr)
716             return TRUE;
717     }
718 
719     return FALSE;
720 
721 } /* inlist */
722 
723 
724 
725 /*
726  * RULE -- Output a rule (vertical or horizontal).
727  *         Increment h if moving is true.
728  */
729 
rule(bool moving,long rulewt,long ruleht)730 void rule(bool moving, long rulewt, long ruleht)
731 {
732 
733     register char ch;               /* character to set rule with            */
734     register long saveh = 0, savev;
735                               /* rule   --   starts up the recursive routine */
736     if (!moving)
737         saveh = h;
738     if ((ruleht <= 0) || (rulewt <= 0))
739         h += rulewt;
740     else {
741         savev = v;
742         if ((ruleht / rulewt) > 0)         /* value < 1 truncates to 0 */
743             ch = '|';
744         else if (ruleht > (lineheight / 2))
745             ch = '=';
746         else
747             ch = '_';
748         ruleaux(rulewt, ruleht, ch);
749         v = savev;
750     }
751     if (!moving)
752         h = saveh;
753 
754     return;
755 
756 } /* rule */
757 
758 
759 
760 /*
761  * RULEAUX -- do the actual output for the rule recursively.
762  */
763 
ruleaux(long rulewt,long ruleht,char ch)764 void ruleaux(long rulewt, long ruleht, char ch)
765 {
766     register long wt, lmh, rmh;
767 
768     wt = rulewt;
769     lmh = h;                        /* save left margin                      */
770     if (h < 0) {                    /* let rules that start at negative h    */
771         wt -= h;                    /* start at coordinate 0, but let it     */
772         h = 0;                      /*   have the right length               */
773     }
774     while (wt > 0) {                /* output the part of the rule that      */
775         rmh = h;                    /*   goes on this line                   */
776         outchar(ch);
777         wt -= (h-rmh);              /* decrease the width left on line       */
778     }
779     ruleht -= lineheight;      /* decrease the height                   */
780     if (ruleht > lineheight) { /* still more vertical?                  */
781         rmh = h;                    /* save current h (right margin)         */
782         h = lmh;                    /* restore left margin                   */
783         v -= (lineheight + lineheight / 10);
784         ruleaux(rulewt, ruleht, ch);
785         h = rmh;                    /* restore right margin                  */
786     }
787 
788     return;
789 
790 } /* ruleaux */
791 
792 
793 
794 /*
795  * HORIZONTALMOVE -- Move the h pointer by amount.
796  */
797 
horizontalmove(long amount)798 long horizontalmove(long amount)
799 {
800 
801 #if defined(MSDOS) || defined(THINK_C)
802     if (labs(amount) > charwidth / 4L) {    /* } to make vi happy */
803 #else
804     if (abs(amount) > charwidth / 4L) {
805 #endif
806         foo = 3*charwidth / 4;
807         if (amount > 0)
808             amount = ((amount+foo) / charwidth) * charwidth;
809         else
810 #if defined(VMS)
811             amount = (ROUND( (float) (amount-foo) / charwidth) + 1)* charwidth;
812 #else
813             amount = ((amount-foo) / charwidth) * charwidth;
814 #endif
815         h += amount;
816         return amount;
817     }
818     else
819         return 0;
820 
821 }   /* horizontalmove */
822 
823 
824 
825 /*
826  * SKIPNOPS -- Return first non NOP opcode.
827  */
828 
829 int skipnops(void)
830 {
831     register int opcode;
832 
833     while ((opcode = (int) num(1)) == NOP);
834 
835     return opcode;
836 
837 } /* skipnops */
838 
839 
840 
841 /*
842  * GETLINE -- Returns an initialized line-object
843  */
844 
845 linetype *my_getline(void)
846 {
847     register int  i;
848     register linetype *temp;
849 
850     if ((temp = (linetype *) malloc(sizeof(linetype))) == NULL)
851         errorexit(lnerq);
852     temp->charactercount = leftmargin - 1;
853     temp->prev = nil;
854     temp->next = nil;
855     for (i = 0; i < LINELEN; i++)
856         temp->text[i] = ' ';
857     temp->text[i] = '\0';
858 
859     return temp;
860 
861 } /* my_getline */
862 
863 
864 
865 /*
866  * FINDLINE -- Find best fit line were text should go
867  *             and generate new line if needed.
868  */
869 
870 linetype *findline(void)
871 {
872     register linetype *temp;
873     register long topd, botd;
874 
875     if (v <= firstline->vv) {                      /* above first line */
876         if (firstline->vv - v > lineheight) {
877             temp = my_getline();
878             temp->next = firstline;
879             firstline->prev = temp;
880             temp->vv = v;
881             firstline = temp;
882         }
883         return firstline;
884     }
885 
886     if (v >= lastline->vv) {                       /* below last line */
887         if (v - lastline->vv > lineheight) {
888             temp = my_getline();
889             temp->prev = lastline;
890             lastline->next = temp;
891             temp->vv = v;
892             lastline = temp;
893         }
894         return lastline;
895     }
896 
897     temp = lastline;                               /* in between two lines */
898     while ((temp->vv > v) && (temp != firstline))
899         temp = temp->prev;
900 
901     /* temp->vv < v < temp->next->vv --- temp is above, temp->next is below */
902     topd = v - temp->vv;
903     botd = temp->next->vv - v;
904     if ((topd < lineheight) || (botd < lineheight)) {
905         if (topd < botd)                           /* take best fit */
906             return temp;
907         else
908             return temp->next;
909     }
910 
911     /* no line fits suitable, generate a new one */
912     currentline = my_getline();
913     currentline->next = temp->next;
914     currentline->prev = temp;
915     temp->next->prev = currentline;
916     temp->next = currentline;
917     currentline->vv = v;
918 
919     return currentline;
920 
921 } /* findline */
922 
923 
924 
925 /*
926  * NUM --
927  */
928 
929 unsigned long num(int size)
930 {
931     register int i;
932     register unsigned long x = 0;
933 
934     for (i = size; i > 0; i--)
935         x = (x << 8) + (unsigned) getc(DVIfile);
936 
937     return x;
938 
939 } /* num */
940 
941 
942 /*
943  * SNUM --
944  */
945 
946 long snum(int size)
947 {
948     register int i;
949     register long x;
950 
951     x = getc(DVIfile);
952     if (x & 0x80)
953         x -= 0x100;
954     for (i = size - 1; i > 0; i--)
955         x = (x << 8) + (unsigned) getc(DVIfile);
956 
957     return x;
958 
959 } /* snum */
960 
961 
962 
963 /*
964  * DOKANJI -- Process a kanji character opcode.
965  */
966 
967 void dokanji(long ch)
968 {
969     long i;
970 
971     i = toBUFF(fromDVI(ch));
972     kanji1 = 3;
973     if (BYTE1(i) != 0) outchar((unsigned char)BYTE1(i));
974     kanji1 = 2;
975     if (BYTE2(i) != 0) outchar((unsigned char)BYTE2(i));
976     kanji1 = 1;
977     /* always */       outchar((unsigned char)BYTE3(i));
978     kanji1 = 0;
979     /* always */       outchar((unsigned char)BYTE4(i));
980 
981     return;
982 
983 } /* dokanji */
984 
985 
986 
987 /*
988  * DOCHAR -- Process a character opcode.
989  */
990 
991 void dochar(unsigned char ch)
992 {
993 
994     if (nttj && fnt->fontnum)
995         jischar((long) ch);
996     else if (symbolfont == TRUE)
997         symchar(ch);
998     else
999         normchar(ch);
1000 
1001     return;
1002 
1003 } /* dochar */
1004 
1005 
1006 
1007 /*
1008  * SYMCHAR -- Process a character opcode for a symbol font.
1009  */
1010 
1011 void symchar(unsigned char ch)
1012 {
1013 
1014     switch (ch) {       /* can do a lot more on MSDOS/latin1/unicode machines ... */
1015        case   0: ch = '-'; break;
1016        case   1: ch = '.'; break;
1017        case   2: ch = 'x'; break;
1018        case   3: ch = '*'; break;
1019        case  13: ch = 'O'; break;
1020        case  14: ch = 'O'; break;
1021        case  15: ch = 'o'; break;
1022        case  24: ch = '~'; break;
1023        case  32: ch = nttj ? '<' : 32; break; /* really only for japan? */
1024        case  33: ch = nttj ? '>' : 33; break; /* really only for japan? */
1025        case 102: ch = '{'; break;
1026        case 103: ch = '}'; break;
1027        case 104: ch = '<'; break;
1028        case 105: ch = '>'; break;
1029        case 106: ch = '|'; break;
1030        case 110: ch = '\\'; break;
1031     }
1032 
1033     outchar(ch);
1034 
1035     return;
1036 
1037 } /* symchar */
1038 
1039 
1040 
1041 /*
1042  * NORMCHAR -- Process a character opcode for a normal font.
1043  */
1044 
1045 void normchar(unsigned char ch)
1046 {
1047 
1048     switch (ch) {
1049         case 11  :  if (ttfont)
1050                         ch = '^';                   /* up symbol       */
1051                     else if (!allchar) {
1052                         outchar('f'); ch = 'f';     /* ligature        */
1053                     }
1054                     break;
1055         case 12  :  if (ttfont)
1056                         ch = 'v';                   /* low symbol       */
1057                     else if (!allchar) {
1058                         outchar('f'); ch = 'i';     /* ligature        */
1059                     }
1060                     break;
1061         case 13  :  if (ttfont)
1062                         ch = '`';
1063                     else if (!allchar) {
1064                         outchar('f'); ch = 'l';     /* ligature        */
1065                     }
1066                     break;
1067         case 14  :  if (ttfont)
1068                         ch = 'i';                   /* spanish !        */
1069                     else if (!allchar) {
1070                         outchar('f'); outchar('f');
1071                                   ch = 'i';         /* ligature        */
1072                     }
1073                     break;
1074         case 15  :  if (ttfont)
1075                         ch = '.';                   /* spanish ?        */
1076                     else if (!allchar) {
1077                         outchar('f'); outchar('f');
1078                                   ch = 'l';         /* ligature        */
1079                     }
1080                     break;
1081         case 16  :  if (!allchar) ch = 'i'; break;
1082         case 17  :  if (!allchar) ch = 'j'; break;
1083         case 25  :  if (!allchar) {
1084                         if (latin1) {
1085                             ch = 0xdf;
1086                         }
1087                         else {
1088                             outchar('s');
1089                             ch = 's';
1090                         }
1091                     }
1092                     break;  /* German double s */
1093         case 26  :  if (!allchar) {
1094                         if (latin1) {
1095                             ch = 0xe6;
1096                         }
1097                         else {
1098                             outchar('a');
1099                             ch = 'e';
1100                         }
1101                     }
1102                     break;  /* Dane/Norw ae    */
1103         case 27  :  if (!allchar) {
1104                         outchar('o');
1105                         ch = 'e';
1106                     }
1107                     break;  /* Dane/Norw oe    */
1108         case 28  :  if (!allchar) {
1109                         if (scascii)
1110                             ch = '|';
1111                         else if (latin1)
1112                             ch = 0xf8;
1113                         else
1114                             ch = 'o';
1115                     }
1116                     break; /* Dane/Norw /o    */
1117         case 29  :  if (!allchar) {
1118                         if (latin1) {
1119                             ch = 0xc6;
1120                         }
1121                         else {
1122                             outchar('A');
1123                             ch = 'E';
1124                         }
1125                     }
1126                     break;  /* Dane/Norw AE    */
1127         case 30  :  if (!allchar) {
1128                         outchar('O');
1129                         ch = 'E';
1130                     }
1131                     break;  /* Dane/Norw OE    */
1132         case 31  :  if (!allchar) {
1133                         if (scascii)
1134                             ch = '\\';
1135                         else if (latin1)
1136                             ch = 0xd8;
1137                         else
1138                             ch = 'O';
1139                     }
1140                     break; /* Dane/Norw /O    */
1141         case 32  :  ch = allchar || ttfont ? ch : '_'; break;
1142                                                         /* underlined blank */
1143         case 58  :  ch = allchar || !mifont ? ch : '.'; break; /* if japan */
1144         case 59  :  ch = allchar || !mifont ? ch : ','; break; /* if japan */
1145         case 92  :  ch = allchar || ttfont ? ch : '"'; break;  /* \ from `` */
1146         case 123 :  ch = allchar || ttfont ? ch : '-'; break;  /* { from -- */
1147         case 124 :  ch = allchar || ttfont ? ch : '_'; break;  /* | from --- */
1148         case 125 :  ch = allchar || ttfont ? ch : '"'; break;  /* } from \H */
1149         case 126 :  ch = allchar || ttfont ? ch : '"'; break;  /* ~ from \~ */
1150         case 127 :  if (!allchar) ch = '"'; break;             /* DEL from \" */
1151 
1152         /*
1153          * Should SPACE be useed for non-accents ???
1154          * This seems to work ...
1155          */
1156         case 18  :  ch = !allchar && accent ? '`' : ch; break;  /* from \` */
1157         case 19  :  ch = !allchar && accent ? 0x27 : ch; break; /* from \' */
1158         case 20  :  ch = !allchar && accent ? '~' : ch; break;  /* from \v */
1159         case 21  :  ch = !allchar && accent ? '~' : ch; break;  /* from \u */
1160         case 22  :  ch = !allchar && accent ? '~' : ch; break;  /* from \= */
1161         case 24  :  ch = !allchar && accent ? ',' : ch; break;  /* from \c */
1162         case 94  :  ch = (!allchar && accent && !ttfont) ? '^' : ch; break;
1163                                                                 /* ^ from \^ */
1164         case 95  :  ch = (!allchar && accent && !ttfont) ? '`' : ch; break;
1165                                                                 /* _ from \. */
1166     }
1167     outchar(ch);
1168 
1169     return;
1170 
1171 } /* normchar */
1172 
1173 
1174 
1175 /*
1176  * OUTCHAR -- Here we put the character into the current page.
1177  *
1178  *            This function includes some code to handle Latin1/Scandinavian
1179  *            characters. I think that code doesn't belong here. IT
1180  *            SHOULD BE MOVED OUT.
1181  */
1182 
1183 void outchar(unsigned char ch)
1184 {
1185     register int i, j;
1186 
1187 /*     fprintf(stderr, "hor: %ld, ver: %ld\n", h, v); */
1188 
1189 #if defined(MSDOS) || defined(THINK_C)
1190     if (labs(v - currentline->vv) > lineheight / 2L)
1191 #else
1192     if (abs(v - currentline->vv) > lineheight / 2L)
1193 #endif
1194         currentline = findline();
1195 
1196 #if 0
1197     j = (int) (((double) h / (double) maxpagewidth) * (ttywidth-1)) + 1;
1198 #else
1199     j = (int) (h / charwidth);
1200 #endif
1201     if (j > rightmargin)     /* leftmargin <= j <= rightmargin */
1202         j = rightmargin;
1203     else if (j < leftmargin)
1204         j = leftmargin;
1205     foo = leftmargin - 1;
1206 
1207     /*
1208      * This code does not really belong here ...
1209      *
1210      * The following is very specialized code, it handles national *
1211      * Swe/Fin characters. They are respectively: a and o with two *
1212      * dots ("a & "o) and a with a circle (Oa). In Swe/Fin "ASCII" *
1213      * these characters replace {}|[] and \.  TeX outputs these by *
1214      * first issuing the dots or circle and then backspace and set *
1215      * the a or o. When dvi2tty finds an a or o it searches in the *
1216      * near vicinity for the character codes that represent circle *
1217      * or dots and if one is found the corresponding national char *
1218      * replaces the special character codes.                       *
1219      */
1220     if (!allchar && (scascii || latin1)) {
1221         if ((ch == 'a') || (ch == 'A') || (ch == 'o') || (ch == 'O') || (ch == 'u') || (ch == 'U')) {
1222             for (i = IMAX(leftmargin, j-2);
1223                  i <= IMIN(rightmargin, j+2);
1224                  i++)
1225                 if ((currentline->text[i - leftmargin] == 127) || /* DEL */
1226                     (currentline->text[i - leftmargin] == 34)  || /* "   */
1227                     (currentline->text[i - leftmargin] == 23))
1228                     foo = i;
1229             if (foo >= leftmargin) {
1230                 j = (int) foo;
1231                 switch (currentline->text[j - leftmargin]) {
1232                     case 127 :
1233                     case 34  :                         /* DEL or " */
1234                                if (ch == 'a')
1235                                    ch = latin1 ? 0xe4 : '{';            /* } vi */
1236                                else if (ch == 'A')      /* dots ... */
1237                                    ch = latin1 ? 0xc4 : '[';
1238                                else if (ch == 'o')
1239                                    ch = latin1 ? 0xf6 : '|';
1240                                else if (ch == 'O')
1241                                    ch = latin1 ? 0xd6 : '\\';
1242                                else if (ch == 'u')
1243                                    ch = latin1 ? 0xfc : 'u';
1244                                else if (ch == 'U')
1245                                    ch = latin1 ? 0xdc : 'U';
1246                                break;
1247                     case 23  : if (ch == 'a')
1248                                    ch = latin1 ? 0xe5 : '}';  /* { vi */
1249                                else if (ch == 'A')      /* circle */
1250                                    ch = latin1 ? 0xc5 : ']';
1251                                break;
1252                 }
1253             }
1254         }
1255     }
1256     /*----------------- end of 'latin1 / Scandinavian code' ----------------*/
1257 
1258     if (foo == leftmargin-1) {
1259       if (japan) {
1260         while (((currentline->text[j - leftmargin] != SPACE) ||
1261 	        (kanji1 && (currentline->text[j+kanji1 - leftmargin] != SPACE)))
1262                 && (j < rightmargin)) {
1263 	  j++;
1264 	  h += charwidth;
1265         }
1266       } else {
1267         while (j < rightmargin &&
1268                ( (currentline->text[j - leftmargin] != SPACE) ||
1269                  (kanji1 && (currentline->text[j+1 - leftmargin] != SPACE))
1270                ) ) {
1271             j++;
1272             h += charwidth;
1273         }
1274       }
1275     }
1276     if ( allchar || ((ch >= SPACE) && (ch != DEL)) ||
1277          ((latin1 || scascii) && (ch == 23)) ) {
1278           /*  ((latin1 || scascii) && (ch == DEL)) )     if VMS ??? */
1279         if (j < rightmargin)
1280             currentline->text[j - leftmargin] = ch;
1281         else
1282             currentline->text[rightmargin - leftmargin] = '@';
1283         if (j > currentline->charactercount)
1284             currentline->charactercount = j;
1285         if (j < firstcolumn)
1286             firstcolumn = j;
1287     }
1288     h += charwidth;
1289 
1290     return;
1291 
1292 } /* outchar */
1293 
1294 
1295 
1296 /*
1297  * PUTCHARACTER -- Output character, don't change h
1298  */
1299 
1300 void putcharacter(long charnr)
1301 {
1302     register long saveh;
1303 
1304     saveh = h;
1305     if (nttj)
1306         dochar((unsigned char) charnr);
1307     else if (allchar || ((charnr >= 0) && (charnr <= LASTCHAR)))
1308         outchar((unsigned char) charnr);
1309     else
1310         setchar(charnr);
1311     h = saveh;
1312 
1313     return;
1314 
1315 } /* putcharacter */
1316 
1317 
1318 
1319 /*
1320  * SETCHAR -- Should print characters with character code>127 from
1321  *            current font. Note that the parameter is a dummy, since
1322  *            ascii-chars are<=127.
1323  */
1324 
1325 void setchar(long charnr)
1326 {
1327 
1328     outchar((unsigned char)(allchar ? charnr : '#'));
1329 
1330     return;
1331 
1332 } /* setchar */
1333 
1334 
1335 static const char *ptex_fontchk[] = {
1336     "min", "goth", "jis",
1337     "hmin", "hgoth", "hmgoth",               /* japanese-otf package */
1338     "nmlmin", "nmlgoth", "nmlmgoth",
1339     "hiramin", "hirakaku", "hiramaru",
1340     NULL /* end */
1341 };
1342 
1343 static const char *uptex_fontchk[] = {
1344     "umin", "ugoth", "ujis",
1345     "upjis", "upjpn", "upsch", "uptch", "upkor",
1346     "uphmin", "uphgoth", "uphmgoth",         /* japanese-otf package */
1347     "upnmlmin", "upnmlgoth", "upnmlmgoth",
1348     "uphiramin", "uphirakaku", "uphiramaru",
1349     NULL /* end */
1350 };
1351 
1352 static const char *jtex_fontchk[] = {
1353     "dmj", "dgj",
1354     NULL /* end */
1355 };
1356 
1357 static int checkjfont(const char **jfontlist, const char *name)
1358 {
1359     int i, len;
1360     const char *tmpfont;
1361 
1362     i=0;
1363     while ( (tmpfont=jfontlist[i]) != NULL ) {
1364         len=strlen(tmpfont);
1365         if ( !strncmp(tmpfont, name, len) ) return 1;
1366         i++;
1367     }
1368     return 0;
1369 } /* checkjfont */
1370 
1371 
1372 
1373 /*
1374  * FONTDEF -- Process a font definition.
1375  */
1376 
1377 void fontdef(int x)
1378 {
1379     register int i;
1380     char * name;
1381     font * fnt;
1382     int namelen;
1383     long fntnum;
1384     int new = 0;
1385 
1386     fntnum = num(x);
1387     (void) get4();                      /* checksum */
1388     (void) get4();                      /* scale */
1389     (void) get4();                      /* design */
1390     namelen = (int) get1() + (int) get1();
1391     fnt = fonts;
1392     while (fnt != NULL && fnt->num != fntnum)       /* does fontnum exist */
1393         fnt = fnt->next;
1394     if (fnt == NULL) {
1395         if ((fnt = (font *) malloc(sizeof(font))) == NULL) {
1396             perror("fontdef");
1397             exit(1);
1398         }
1399         fnt->num = fntnum;
1400         new = 1;
1401     }
1402     else
1403         free(fnt->name);    /* free old name */
1404     if ((name = (char *) malloc((namelen+1) * sizeof(char))) == NULL) {
1405         perror("fontdef");
1406         exit(1);
1407     }
1408 
1409     for (i = 0; i < namelen; i++)
1410         name[i] = get1();
1411     name[i] = '\0';	/* properly end string */
1412     fnt->name = name;
1413     if (new) {
1414         fnt->next = fonts;
1415         fonts = fnt;
1416     }
1417 
1418     /*
1419      * some magic to learn about font types...
1420      */
1421     fonts->flags = 0;
1422 
1423     if ((asciip == FALSE && nttj == FALSE && uptex == FALSE)
1424         && (!jdetect) && jautodetect) {
1425         if ( checkjfont(ptex_fontchk, name) ) {
1426             /* Detect as ASCII TeX */
1427             asciip = TRUE;
1428             nttj = uptex = FALSE;
1429             japan = jdetect = TRUE;
1430             fonts->flags |= MIFONT;
1431             set_enc_string (NULL, PTEX_INTERNAL_ENC);
1432         } else if ( checkjfont(uptex_fontchk, name) ) {
1433             /* Detect as upTeX */
1434             uptex = TRUE;
1435             nttj = asciip = FALSE;
1436             japan = jdetect = TRUE;
1437             fonts->flags |= MIFONT;
1438             enable_UPTEX(true);
1439             set_enc_string (NULL, UPTEX_INTERNAL_ENC);
1440         } else if ( checkjfont(jtex_fontchk, name) ) {
1441             /* Detect as NTT JTeX */
1442             nttj = TRUE;
1443             asciip = uptex = FALSE;
1444             japan = jdetect = TRUE;
1445             fonts->flags |= JAPFONT;
1446             set_enc_string (NULL, JTEX_INTERNAL_ENC);
1447         }
1448     }
1449     if (nttj)
1450         fonts->fontnum = getjsubfont(name);
1451     else
1452         fonts->fontnum = 0;
1453 
1454     if ((strstr(name, "sy")) != NULL)
1455             fonts->flags |= SYMFONT;
1456     if ((strstr(name, "tt")) != NULL)
1457             fonts->flags |= TTFONT;
1458     if ((strstr(name, "mi")) != NULL)
1459             fonts->flags |= MIFONT;
1460 
1461     return;
1462 
1463 } /* fontdef */
1464 
1465 
1466 
1467 #define    NJSUBS        33
1468 const char *jsf_names[]={
1469     "sy", "roma", "hira", "kata", "greek", "russian", "keisen",
1470     "ka", "kb", "kc", "kd", "ke", "kf", "kg", "kh", "ki", "kj",
1471     "kk", "kl", "km", "kn", "ko", "kp", "kq", "kr", "ks", "kt",
1472     "ku", "kv", "kw", "kx", "ky", "kz"
1473 };
1474 
1475 
1476 int getjsubfont(char *s)
1477 {
1478     int jf;
1479 
1480     if (strlen(s) > 3 && s[0] == 'd' && (s[1] == 'm' || s[1] == 'g') && s[2] == 'j') {
1481         for (jf = 0; jf < NJSUBS; jf++) {
1482             if (strncmp(&s[3], jsf_names[jf], strlen(jsf_names[jf])) == 0)
1483                 return jf+1;
1484         }
1485     }
1486 
1487     return 0;
1488 
1489 } /* getjsubfont */
1490 
1491 
1492 
1493 /*
1494  * SETFONT -- Switch to specific font. Try to find out if it is a symbol
1495  *            font.
1496  *            Option -c allchar does not pertain to this portion, so symbols
1497  *            are still translated.
1498  */
1499 
1500 void setfont(long fntnum)
1501 {
1502     char * s;
1503     const char * d;
1504 
1505     symbolfont = FALSE;
1506     ttfont = FALSE;
1507     mifont = FALSE;
1508     fnt = fonts;
1509 
1510     while (fnt != NULL && fnt->num != fntnum)
1511         fnt = fnt->next;
1512 
1513     if (fnt == NULL) {
1514         /* error : font not found */
1515         return;
1516     }
1517 
1518     if (fnt->fontnum == 0) {
1519         symbolfont = fnt->flags & SYMFONT;
1520         ttfont = fnt->flags & TTFONT;
1521         mifont = fnt->flags & MIFONT;
1522     }
1523 
1524     s = fnt->name;
1525     if (printfont) {
1526          d = delim;      /* print delim and font name if -b was chosen */
1527          while (*d) {putcharacter(*d); d++;}
1528          while (*s) {putcharacter(*s); s++;}
1529          while (d-- > delim) {putcharacter(*d);}
1530     }
1531 
1532     return;
1533 
1534 } /* setfont */
1535 
1536 
1537 
1538 void jischar(unsigned long ch)
1539 {
1540     unsigned int Ku, Ten;
1541 
1542     compute_jis(fnt->fontnum, (unsigned int) ch, &Ku, &Ten);
1543     kanji1 = 1;
1544     outchar((unsigned char)(Ku+128));
1545     kanji1 = 0;
1546     outchar((unsigned char)(Ten+128));
1547 
1548     return;
1549 
1550 } /* jischar */
1551 
1552 #define	kushift(c)	c+0x20
1553 #define	tenshift(c)	c+0x20
1554 
1555 void compute_jis(int f, unsigned int c, unsigned int *ku, unsigned int *ten)
1556 {
1557     int n;
1558 
1559     if (f <= 7) {
1560         if (f == 1) {
1561             if (c >= 100) {
1562                 *ku = kushift(2);
1563                 *ten = tenshift(c-100);
1564             }
1565             else {
1566                 *ku = kushift(1);
1567                 *ten = tenshift(c);
1568             }
1569         }
1570         else if (f == 2) {
1571             *ku = kushift(3);
1572             *ten = tenshift(c-32);
1573         }
1574         else {
1575             *ku = kushift(f+1);
1576             *ten = tenshift(c);
1577         }
1578     }
1579     else if (f <= 19) {    /* Daiichi Suijun */
1580         n = (f-8)*256+c;
1581         *ku = kushift((n/94)+16);
1582         *ten = tenshift((n%94)+1);
1583     }
1584     else {            /* Daini Suijun */
1585         n = (f-20)*256+c;
1586         *ku = kushift((n/94)+48);
1587         *ten = tenshift((n%94)+1);
1588     }
1589 
1590     return;
1591 
1592 } /* compute_jis */
1593 
1594 
1595 
1596 /*
1597  * VMS CODE
1598  */
1599 
1600 #if defined(VMS)
1601 long vmsseek(fp,n,dir)
1602 FILE *fp;
1603 long n;
1604 long dir;
1605 {
1606     long k,m,pos,val,oldpos;
1607     struct stat buffer;
1608 
1609     for (;;) {                     /* loops only once or twice */
1610         switch (dir) {
1611             case 0:            /* from BOF */
1612                     oldpos = vms_ftell(fp);
1613                     k = n & 511;
1614                     m = n >> 9;
1615                     if (((*fp)->_cnt) && ((oldpos >> 9) == m)) {
1616                         val = 0; /* still in */
1617                         (*fp)->_ptr = ((*fp)->_base) + k;
1618                         (*fp)->_cnt = 512 - k;
1619                     }
1620                     else {
1621                         val = fseek(fp, m << 9, 0);
1622                         if (val == 0) {
1623                             (*fp)->_cnt = 0;
1624                             (void) fgetc(fp);
1625                             (*fp)->_ptr = ((*fp)->_base) + k;
1626                             (*fp)->_cnt = 512 - k;
1627                         }
1628                     }
1629                     return(val);
1630 
1631             case 1: pos = vms_ftell(fp);
1632                     if (pos == EOF)
1633                         return (EOF);
1634                     n += pos;
1635                     dir = 0;
1636                     break;
1637 
1638             case 2: val = fstat(fileno(fp), &buffer);
1639                     if (val == EOF)
1640                         return (EOF);
1641                     n += buffer.st_size - 1;
1642 
1643                     dir = 0;
1644                     break;
1645 
1646             default : return (EOF);
1647         }
1648     }
1649 
1650     /* NOTREACHED */
1651 
1652 } /* vmsseek */
1653 
1654 
1655 
1656 long vms_ftell(fp)
1657 FILE *fp;
1658 {
1659     char c;
1660     long pos;
1661     long val;
1662 
1663     if ((*fp)->_cnt == 0) {
1664         c = fgetc(fp);
1665         val = vms_ungetc(c, fp);
1666         if (val != c)
1667             return (EOF);
1668     }
1669     pos = ftell(fp);
1670     if (pos >= 0)
1671         pos += ((*fp)->_ptr) - ((*fp)->_base);
1672 
1673     return (pos);
1674 
1675 } /* vms_ftell */
1676 
1677 
1678 
1679 long vms_ungetc(c,fp)
1680 char c;
1681 FILE *fp;
1682 {
1683 
1684     if ((c == EOF) && feof(fp))
1685         return (EOF);
1686 
1687     if ((*fp)->_cnt >= 512)
1688         return (EOF);
1689 
1690     (*fp)->_cnt++;
1691     (*fp)->_ptr--;
1692     *((*fp)->_ptr) = c;
1693 
1694     return (c);
1695 
1696 } /*vms_ungetc */
1697 #endif
1698