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