1 #ifndef lint 2 static char sccsid[] = "@(#)t6.c 2.2 (CWI) 87/07/10"; 3 #endif lint 4 /* 5 * t6.c 6 * 7 * width functions, sizes and fonts 8 */ 9 10 #include "tdef.h" 11 #include "dev.h" 12 #include <sgtty.h> 13 #include <ctype.h> 14 #include "ext.h" 15 16 /* fitab[f][c] is 0 if c is not on font f 17 /* if it's non-zero, c is in fontab[f] at position 18 /* fitab[f][c]. 19 */ 20 extern struct Font *fontbase[NFONT+1]; 21 extern char *codetab[NFONT+1]; 22 extern int nchtab; 23 24 int fontlab[MAXFONTS+1]; 25 short *pstab; 26 int cstab[MAXFONTS+1]; 27 int ccstab[MAXFONTS+1]; 28 int bdtab[MAXFONTS+1]; 29 int sbold = 0; 30 31 width(j) 32 register tchar j; 33 { 34 register i, k; 35 36 if (j & (ZBIT|MOT)) { 37 if (iszbit(j)) 38 return(0); 39 if (isvmot(j)) 40 return(0); 41 k = absmot(j); 42 if (isnmot(j)) 43 k = -k; 44 return(k); 45 } 46 i = cbits(j); 47 if (i < ' ') { 48 if (i == '\b') 49 return(-widthp); 50 if (i == PRESC) 51 i = eschar; 52 else if (iscontrol(i)) 53 return(0); 54 } 55 if (i==ohc) 56 return(0); 57 i = trtab[i]; 58 if (i < 32) 59 return(0); 60 if (sfbits(j) == oldbits) { 61 xfont = pfont; 62 xpts = ppts; 63 } else 64 xbits(j, 0); 65 if (widcache[i-32].fontpts == (xfont<<8) + xpts && !setwdf) 66 k = widcache[i-32].width; 67 else { 68 k = getcw(i-32); 69 if (bd) 70 k += (bd - 1) * HOR; 71 if (cs) 72 k = cs; 73 } 74 widthp = k; 75 return(k); 76 } 77 78 /* 79 * clear width cache-- s means just space 80 */ 81 zapwcache(s) 82 { 83 register i; 84 85 if (s) { 86 widcache[0].fontpts = 0; 87 return; 88 } 89 for (i=0; i<NWIDCACHE; i++) 90 widcache[i].fontpts = 0; 91 } 92 93 getcw(i) 94 register int i; 95 { 96 register int k; 97 register char *p; 98 register int x, j; 99 int nocache = 0; 100 int savxfont = 0, savsbold = 0, savulfont = 0; 101 102 /* 103 * Here comes first part of bug fix 104 */ 105 106 if( xfont > nfonts) { /* font is not mounted */ 107 savxfont = xfont; 108 if( xfont == sbold) { 109 savsbold = sbold; 110 sbold = 0; 111 } 112 if( xfont == ulfont) { 113 savulfont = ulfont; 114 ulfont = 0; 115 } 116 xfont = 0; 117 setfp(0, fontlab[savxfont], 0); 118 bdtab[0] = bdtab[savxfont]; /* Save */ 119 cstab[0] = cstab[savxfont]; /* as */ 120 ccstab[0] = ccstab[savxfont]; /* well */ 121 } 122 /* End */ 123 124 125 bd = 0; 126 if (i >= nchtab + 128-32) { 127 j = abscw(i + 32 - (nchtab+128)); 128 goto g0; 129 } 130 if (i == 0) { /* a blank */ 131 k = (fontab[xfont][0] * spacesz + 6) / 12; 132 /* this nonsense because .ss cmd uses 1/36 em as its units */ 133 /* and default is 12 */ 134 goto g1; 135 } 136 if ((j = fitab[xfont][i] & BYTEMASK) == 0) { /* it's not on current font */ 137 /* search through search list of xfont 138 /* to see what font it ought to be on. 139 /* searches S, then remaining fonts in wraparound order. 140 */ 141 nocache = 1; 142 if (smnt) { 143 int ii, jj; 144 for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) { 145 j = fitab[ii][i] & BYTEMASK; 146 if (j != 0) { 147 p = fontab[ii]; 148 k = *(p + j); 149 if (xfont == sbold) 150 bd = bdtab[ii]; 151 if (setwdf) 152 numtab[CT].val |= kerntab[ii][j]; 153 goto g1; 154 } 155 } 156 } 157 k = fontab[xfont][0]; /* leave a space-size space */ 158 goto g1; 159 } 160 g0: 161 p = fontab[xfont]; 162 if (setwdf) 163 numtab[CT].val |= kerntab[xfont][j]; 164 k = *(p + j); 165 g1: 166 if (!bd) 167 bd = bdtab[xfont]; 168 if (cs = cstab[xfont]) { 169 nocache = 1; 170 if (ccs = ccstab[xfont]) 171 x = ccs; 172 else 173 x = xpts; 174 cs = (cs * EMPTS(x)) / 36; 175 } 176 k = ((k&BYTEMASK) * xpts + (Unitwidth / 2)) / Unitwidth; 177 /* 178 * undo the fontswap 179 */ 180 if(savxfont) { 181 xfont = savxfont; 182 if(savsbold) 183 sbold = savsbold; 184 if(savulfont) 185 ulfont = savulfont; 186 /* 187 * H'm, I guess we should not put 188 * this width in the cache 189 */ 190 nocache = 1; 191 } 192 if (nocache|bd) 193 widcache[i].fontpts = 0; 194 else { 195 widcache[i].fontpts = (xfont<<8) + xpts; 196 widcache[i].width = k; 197 } 198 return(k); 199 /* Unitwidth is Units/Point, where 200 /* Units is the fundamental digitization 201 /* of the character set widths, and 202 /* Point is the number of goobies in a point 203 /* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6 204 /* In effect, it's the size at which the widths 205 /* translate directly into units. 206 */ 207 } 208 209 abscw(n) /* return index of abs char n in fontab[], etc. */ 210 { register int i, ncf; 211 212 ncf = fontbase[xfont]->nwfont & BYTEMASK; 213 for (i = 0; i < ncf; i++) 214 if (codetab[xfont][i] == n) 215 return i; 216 return 0; 217 } 218 219 xbits(i, bitf) 220 register tchar i; 221 { 222 register k; 223 224 xfont = fbits(i); 225 k = sbits(i); 226 if (k) { 227 xpts = pstab[--k]; 228 oldbits = sfbits(i); 229 pfont = xfont; 230 ppts = xpts; 231 return; 232 } 233 switch (bitf) { 234 case 0: 235 xfont = font; 236 xpts = pts; 237 break; 238 case 1: 239 xfont = pfont; 240 xpts = ppts; 241 break; 242 case 2: 243 xfont = mfont; 244 xpts = mpts; 245 } 246 } 247 248 249 tchar setch() 250 { 251 register j; 252 char temp[10]; 253 register char *s; 254 extern char *chname; 255 extern short *chtab; 256 extern int nchtab; 257 258 s = temp; 259 if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0) 260 return(0); 261 *s = '\0'; 262 for (j = 0; j < nchtab; j++) 263 if (strcmp(&chname[chtab[j]], temp) == 0) 264 return(j + 128 | chbits); 265 return(0); 266 } 267 268 tchar setabs() /* set absolute char from \C'...' */ 269 { 270 int i, n, nf; 271 extern int nchtab; 272 273 getch(); 274 n = 0; 275 n = inumb(&n); 276 getch(); 277 if (nonumb) 278 return 0; 279 return n + nchtab + 128; 280 } 281 /* 282 * I (jaap) expand fontlab to the maximum of fonts troff can 283 * handle. The maximum number i, due to the two chars 284 * fontname limit, is 99. 285 * If we don't use the (named) font in one of the 286 * standard position, we install the name in the next 287 * free slot. Whenever we need info about the font, we 288 * read in the data at position zero, and secretly use 289 * the data (actually only necessary for the width 290 * and ligature info). The ptfont() (t10.c) routine will tell 291 * the device filter to put the font always at position 292 * zero if xfont > physfonts, so no need to change these filters. 293 * Yes, this is a bit kludgy. 294 * 295 * This gives the new specs of findft: 296 * 297 * find the font name i, where i also can be a number. 298 * 299 * Installs the font(name) i when not present 300 * 301 * returns -1 on error 302 */ 303 304 findft(i) 305 register int i; 306 { 307 register k; 308 register char *p; 309 extern char * unpair(); 310 311 p = unpair(i); 312 313 /* first look for numbers */ 314 if( isdigit(p[0]) && (p[1] == 0 || isdigit(p[1]))) { 315 k = p[0] - '0'; 316 if( p[1] > 0 && isdigit(p[1])) 317 k = 10 * k + ( p[1] - '0'); 318 319 /* 320 fprintf(ptid, "x xxx it's a number: %d\n", k); 321 */ 322 if( k > 0 && k <= nfonts && fontbase[k]->specfont == 0 ) { 323 /* 324 fprintf(ptid, "x xxx it's a mounted font\n"); 325 */ 326 return(k); /* mounted font */ 327 } 328 if( fontlab[k] && k <= MAXFONTS) { /* translate */ 329 /* 330 fprintf(ptid, "x xxx font exists\n"); 331 */ 332 return(k); /*number to a name */ 333 } 334 else { 335 fprintf(stderr, "troff: no font at position %d\n", k); 336 return(-1); /* wild number */ 337 } 338 } 339 340 /* 341 * Now we look for font names 342 */ 343 for (k = 1; fontlab[k] != i; k++) { 344 if (k > MAXFONTS +1) /* the +1 is for the ``font cache'' */ 345 return(-1); /* running out of fontlab space */ 346 if ( !fontlab[k] ) { /* passed all existing names */ 347 if (k <= NFONT) { 348 if(setfp(k, i, 0) < 0) 349 return(-1); 350 nfonts = k; 351 } else 352 if(setfp(0, i, 0) < 0) 353 return(-1); 354 /* 355 fprintf(ptid, "x xxx installed %s on %d\n", name ,k); 356 */ 357 /* now install the name */ 358 fontlab[k] = i; 359 /* 360 * and remember accociated with 361 * this font, ligature info etc. 362 */ 363 return(k); 364 } 365 } 366 return(k); /* was one of the existing names */ 367 } 368 369 370 caseps() 371 { 372 register i; 373 374 if (skip()) 375 i = apts1; 376 else { 377 noscale++; 378 i = inumb(&apts); /* this is a disaster for fractional point sizes */ 379 noscale = 0; 380 if (nonumb) 381 return; 382 } 383 casps1(i); 384 } 385 386 387 casps1(i) 388 register int i; 389 { 390 391 /* 392 * in olden times, it used to ignore changes to 0 or negative. 393 * this is meant to allow the requested size to be anything, 394 * in particular so eqn can generate lots of \s-3's and still 395 * get back by matching \s+3's. 396 397 if (i <= 0) 398 return; 399 */ 400 apts1 = apts; 401 apts = i; 402 pts1 = pts; 403 pts = findps(i); 404 mchbits(); 405 } 406 407 408 findps(i) 409 register int i; 410 { 411 register j, k; 412 413 for (j=k=0 ; pstab[j] != 0 ; j++) 414 if (abs(pstab[j]-i) < abs(pstab[k]-i)) 415 k = j; 416 417 return(pstab[k]); 418 } 419 420 421 mchbits() 422 { 423 register i, j, k; 424 425 i = pts; 426 for (j = 0; i > (k = pstab[j]); j++) 427 if (!k) { 428 k = pstab[--j]; 429 break; 430 } 431 chbits = 0; 432 setsbits(chbits, ++j); 433 setfbits(chbits, font); 434 sps = width(' ' | chbits); 435 zapwcache(1); 436 } 437 438 setps() 439 { 440 register int i, j; 441 442 i = cbits(getch()); 443 if (isdigit(i)) { /* \sd or \sdd */ 444 i -= '0'; 445 if (i == 0) /* \s0 */ 446 j = apts1; 447 else if (i <= 3 && isdigit(j = cbits(ch=getch()))) { /* \sdd */ 448 j = 10 * i + j - '0'; 449 ch = 0; 450 } else /* \sd */ 451 j = i; 452 } else if (i == '(') { /* \s(dd */ 453 j = cbits(getch()) - '0'; 454 j = 10 * j + cbits(getch()) - '0'; 455 if (j == 0) /* \s(00 */ 456 j = apts1; 457 } else if (i == '+' || i == '-') { /* \s+, \s- */ 458 j = cbits(getch()); 459 if (isdigit(j)) { /* \s+d, \s-d */ 460 j -= '0'; 461 } else if (j == '(') { /* \s+(dd, \s-(dd */ 462 j = cbits(getch()) - '0'; 463 j = 10 * j + cbits(getch()) - '0'; 464 } 465 if (i == '-') 466 j = -j; 467 j += apts; 468 } 469 casps1(j); 470 } 471 472 473 tchar setht() /* set character height from \H'...' */ 474 { 475 int n; 476 tchar c; 477 478 getch(); 479 n = inumb(&apts); 480 getch(); 481 if (n == 0 || nonumb) 482 n = apts; /* does this work? */ 483 c = CHARHT; 484 c |= ZBIT; 485 setsbits(c, n); 486 return(c); 487 } 488 489 tchar setslant() /* set slant from \S'...' */ 490 { 491 int n; 492 tchar c; 493 494 getch(); 495 n = 0; 496 n = inumb(&n); 497 getch(); 498 if (nonumb) 499 n = 0; 500 c = SLANT; 501 c |= ZBIT; 502 setsfbits(c, n+180); 503 return(c); 504 } 505 506 507 caseft() 508 { 509 skip(); 510 setfont(1); 511 } 512 513 514 setfont(a) 515 int a; 516 { 517 register i, j; 518 519 if (a) 520 i = getrq(); 521 else 522 i = getsn(); 523 if (!i || i == 'P') { 524 j = font1; 525 goto s0; 526 } 527 if (i == 'S' || i == '0') 528 return; 529 if ((j = findft(i)) == -1) 530 #ifdef notdef 531 /* findft does the setfp if possible */ 532 if ((j = setfp(0, i, 0)) == -1) /* try to put it in position 0 */ 533 #endif 534 return; 535 s0: 536 font1 = font; 537 font = j; 538 mchbits(); 539 } 540 541 542 setwd() 543 { 544 register base, wid; 545 register tchar i; 546 int delim, emsz, k; 547 int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1; 548 549 base = numtab[ST].val = numtab[ST].val = wid = numtab[CT].val = 0; 550 if (ismot(i = getch())) 551 return; 552 delim = cbits(i); 553 savhp = numtab[HP].val; 554 numtab[HP].val = 0; 555 savapts = apts; 556 savapts1 = apts1; 557 savfont = font; 558 savfont1 = font1; 559 savpts = pts; 560 savpts1 = pts1; 561 setwdf++; 562 while (cbits(i = getch()) != delim && !nlflg) { 563 k = width(i); 564 wid += k; 565 numtab[HP].val += k; 566 if (!ismot(i)) { 567 emsz = POINT * xpts; 568 } else if (isvmot(i)) { 569 k = absmot(i); 570 if (isnmot(i)) 571 k = -k; 572 base -= k; 573 emsz = 0; 574 } else 575 continue; 576 if (base < numtab[SB].val) 577 numtab[SB].val = base; 578 if ((k = base + emsz) > numtab[ST].val) 579 numtab[ST].val = k; 580 } 581 setn1(wid, 0, (tchar) 0); 582 numtab[HP].val = savhp; 583 apts = savapts; 584 apts1 = savapts1; 585 font = savfont; 586 font1 = savfont1; 587 pts = savpts; 588 pts1 = savpts1; 589 mchbits(); 590 setwdf = 0; 591 } 592 593 594 tchar vmot() 595 { 596 dfact = lss; 597 vflag++; 598 return(mot()); 599 } 600 601 602 tchar hmot() 603 { 604 dfact = EM; 605 return(mot()); 606 } 607 608 609 tchar mot() 610 { 611 register int j, n; 612 register tchar i; 613 614 j = HOR; 615 getch(); /*eat delim*/ 616 if (n = atoi()) { 617 if (vflag) 618 j = VERT; 619 i = makem(quant(n, j)); 620 } else 621 i = 0; 622 getch(); 623 vflag = 0; 624 dfact = 1; 625 return(i); 626 } 627 628 629 tchar sethl(k) 630 int k; 631 { 632 register j; 633 tchar i; 634 635 j = EM / 2; 636 if (k == 'u') 637 j = -j; 638 else if (k == 'r') 639 j = -2 * j; 640 vflag++; 641 i = makem(j); 642 vflag = 0; 643 return(i); 644 } 645 646 647 tchar makem(i) 648 register int i; 649 { 650 register tchar j; 651 652 if ((j = i) < 0) 653 j = -j; 654 j |= MOT; 655 if (i < 0) 656 j |= NMOT; 657 if (vflag) 658 j |= VMOT; 659 return(j); 660 } 661 662 663 tchar getlg(i) 664 tchar i; 665 { 666 tchar j, k; 667 register int lf; 668 669 /* remember to map the font */ 670 if ((lf = fontbase[fbits(i) > nfonts ? 0 : fbits(i)]->ligfont) == 0) { 671 /* font lacks ligatures */ 672 return(i); 673 } 674 j = getch0(); 675 if (cbits(j) == 'i' && (lf & LFI)) 676 j = LIG_FI; 677 else if (cbits(j) == 'l' && (lf & LFL)) 678 j = LIG_FL; 679 else if (cbits(j) == 'f' && (lf & LFF)) { 680 if ((lf & (LFFI|LFFL)) && lg != 2) { 681 k = getch0(); 682 if (cbits(k)=='i' && (lf&LFFI)) 683 j = LIG_FFI; 684 else if (cbits(k)=='l' && (lf&LFFL)) 685 j = LIG_FFL; 686 else { 687 *pbp++ = k; 688 j = LIG_FF; 689 } 690 } else 691 j = LIG_FF; 692 } else { 693 *pbp++ = j; 694 j = i; 695 } 696 return(i & SFMASK | j); 697 } 698 699 700 caselg() 701 { 702 703 lg = 1; 704 if (skip()) 705 return; 706 lg = atoi(); 707 } 708 709 710 casefp() 711 { 712 register int i, j; 713 register char *s; 714 715 skip(); 716 /* allow .fp for fonts >nfonts, <NFONTS? */ 717 if ((i = cbits(getch()) - '0') <= 0 || i > nfonts) 718 errprint("fp: bad font position %d", i); 719 else if (skip() || !(j = getrq())) 720 errprint("fp: no font name"); 721 else if (skip() || !getname()) 722 setfp(i, j, 0); 723 else /* 3rd argument = filename */ 724 setfp(i, j, nextf); 725 } 726 727 setfp(pos, f, truename) /* mount font f at position pos[0...NFONTS] */ 728 register pos; 729 int f; 730 char *truename; 731 { 732 register k; 733 register struct Font *ft; 734 int n; 735 char longname[NS], shortname[20]; 736 extern int nchtab; 737 extern struct dev dev; 738 739 if (fontlab[pos] == f) /* if f already mounted at pos, */ 740 return(pos); /* don't remount it */ 741 zapwcache(0); 742 if (truename) 743 strcpy(shortname, truename); 744 else { 745 shortname[0] = f & BYTEMASK; 746 shortname[1] = f >> BYTE; 747 shortname[2] = '\0'; 748 } 749 sprintf(longname, "%s/dev%s/%s.out", fontfile, devname, shortname); 750 if ((k = open(longname, 0)) < 0) { 751 errprint("Can't open %s", longname); 752 return(-1); 753 } 754 if ((ft = fontbase[pos]) == 0) { 755 ft = fontbase[pos] = (struct Font *) malloc(EXTRAFONT); 756 ft->nwfont = MAXCHARS; 757 fontab[pos] = (char *)(ft + 1); 758 } 759 n = ft->nwfont; 760 read(k, (char *) ft, 3*n + nchtab + 128 - 32 + sizeof(struct Font)); 761 close(k); 762 763 k = ft->nwfont; 764 kerntab[pos] = (char *) fontab[pos] + k; 765 codetab[pos] = (char *) fontab[pos] + 2 * k; 766 /* have to reset the fitab pointer because the width may be different */ 767 fitab[pos] = (char *) fontab[pos] + 3 * k; 768 ft->nwfont = n; /* so can load a larger one again later */ 769 if (k > n) { 770 errprint("Font %s too big for position %d", shortname, pos); 771 return(-1); 772 } 773 if (pos == smnt) { 774 smnt = 0; 775 sbold = 0; 776 } 777 if ((fontlab[pos] = f) == 'S') 778 smnt = pos; 779 bdtab[pos] = cstab[pos] = ccstab[pos] = 0; 780 /* if there is a directory, no place to store its name. */ 781 /* if position isn't zero, no place to store its value. */ 782 /* only time a FONTPOS is pushed back is if it's a */ 783 /* standard font on position 0 (i.e., mounted implicitly. */ 784 /* there's a bug here: if there are several input lines */ 785 /* that look like .ft XX in short successtion, the output */ 786 /* will all be in the last one because the "x font ..." */ 787 /* comes out too soon. pushing back FONTPOS doesn't work */ 788 /* with .ft commands because input is flushed after .xx cmds */ 789 790 /* 791 * Trying to fix this FONTPOS problem: See findft() 792 */ 793 if ( pos > 0 && pos <= physfonts) 794 ptfpcmd(pos, shortname); 795 return(pos); 796 } 797 798 799 casecs() 800 { 801 register i, j; 802 803 noscale++; 804 skip(); 805 if (!(i = getrq()) || (i = findft(i)) < 0) 806 goto rtn; 807 skip(); 808 cstab[i] = atoi(); 809 skip(); 810 j = atoi(); 811 if (nonumb) 812 ccstab[i] = 0; 813 else 814 ccstab[i] = findps(j); 815 rtn: 816 zapwcache(0); 817 noscale = 0; 818 } 819 820 821 casebd() 822 { 823 register i, j, k; 824 825 zapwcache(0); 826 k = 0; 827 bd0: 828 if (skip() || !(i = getrq()) || (j = findft(i)) == -1) { 829 if (k) 830 goto bd1; 831 else 832 return; 833 } 834 if (j == smnt) { 835 k = smnt; 836 goto bd0; 837 } 838 if (k) { 839 sbold = j; 840 j = k; 841 } 842 bd1: 843 skip(); 844 noscale++; 845 bdtab[j] = atoi(); 846 noscale = 0; 847 } 848 849 850 casevs() 851 { 852 register i; 853 854 skip(); 855 vflag++; 856 dfact = INCH; /* default scaling is points! */ 857 dfactd = 72; 858 res = VERT; 859 i = inumb(&lss); 860 if (nonumb) 861 i = lss1; 862 /* if(i < VERT)i = VERT; */ 863 if (i < VERT) 864 i = 0; 865 lss1 = lss; 866 lss = i; 867 } 868 869 870 casess() 871 { 872 register i; 873 874 noscale++; 875 skip(); 876 if (i = atoi()) { 877 spacesz = i & 0177; 878 zapwcache(0); 879 sps = width(' ' | chbits); 880 } 881 noscale = 0; 882 } 883 884 885 tchar xlss() 886 { 887 /* stores \x'...' into 888 /* two successive tchars. 889 /* the first contains HX, the second the value, 890 /* encoded as a vertical motion. 891 /* decoding is done in n2.c by pchar(). 892 */ 893 int i; 894 895 getch(); 896 dfact = lss; 897 i = quant(atoi(), VERT); 898 dfact = 1; 899 getch(); 900 if (i >= 0) 901 *pbp++ = MOT | VMOT | i; 902 else 903 *pbp++ = MOT | VMOT | NMOT | -i; 904 return(HX); 905 } 906 907 char * 908 unpair(i) 909 register int i; 910 { static char name[3]; 911 912 name[0] = i & BYTEMASK; 913 name[1] = i >> BYTE; 914 name[2] = 0; 915 return (name); 916 } 917