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 if ((j = setfp(0, i, 0)) == -1) /* try to put it in position 0 */ 531 return; 532 s0: 533 font1 = font; 534 font = j; 535 mchbits(); 536 } 537 538 539 setwd() 540 { 541 register base, wid; 542 register tchar i; 543 int delim, emsz, k; 544 int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1; 545 546 base = numtab[ST].val = numtab[ST].val = wid = numtab[CT].val = 0; 547 if (ismot(i = getch())) 548 return; 549 delim = cbits(i); 550 savhp = numtab[HP].val; 551 numtab[HP].val = 0; 552 savapts = apts; 553 savapts1 = apts1; 554 savfont = font; 555 savfont1 = font1; 556 savpts = pts; 557 savpts1 = pts1; 558 setwdf++; 559 while (cbits(i = getch()) != delim && !nlflg) { 560 k = width(i); 561 wid += k; 562 numtab[HP].val += k; 563 if (!ismot(i)) { 564 emsz = POINT * xpts; 565 } else if (isvmot(i)) { 566 k = absmot(i); 567 if (isnmot(i)) 568 k = -k; 569 base -= k; 570 emsz = 0; 571 } else 572 continue; 573 if (base < numtab[SB].val) 574 numtab[SB].val = base; 575 if ((k = base + emsz) > numtab[ST].val) 576 numtab[ST].val = k; 577 } 578 setn1(wid, 0, (tchar) 0); 579 numtab[HP].val = savhp; 580 apts = savapts; 581 apts1 = savapts1; 582 font = savfont; 583 font1 = savfont1; 584 pts = savpts; 585 pts1 = savpts1; 586 mchbits(); 587 setwdf = 0; 588 } 589 590 591 tchar vmot() 592 { 593 dfact = lss; 594 vflag++; 595 return(mot()); 596 } 597 598 599 tchar hmot() 600 { 601 dfact = EM; 602 return(mot()); 603 } 604 605 606 tchar mot() 607 { 608 register int j, n; 609 register tchar i; 610 611 j = HOR; 612 getch(); /*eat delim*/ 613 if (n = atoi()) { 614 if (vflag) 615 j = VERT; 616 i = makem(quant(n, j)); 617 } else 618 i = 0; 619 getch(); 620 vflag = 0; 621 dfact = 1; 622 return(i); 623 } 624 625 626 tchar sethl(k) 627 int k; 628 { 629 register j; 630 tchar i; 631 632 j = EM / 2; 633 if (k == 'u') 634 j = -j; 635 else if (k == 'r') 636 j = -2 * j; 637 vflag++; 638 i = makem(j); 639 vflag = 0; 640 return(i); 641 } 642 643 644 tchar makem(i) 645 register int i; 646 { 647 register tchar j; 648 649 if ((j = i) < 0) 650 j = -j; 651 j |= MOT; 652 if (i < 0) 653 j |= NMOT; 654 if (vflag) 655 j |= VMOT; 656 return(j); 657 } 658 659 660 tchar getlg(i) 661 tchar i; 662 { 663 tchar j, k; 664 register int lf; 665 666 /* remember to map the font */ 667 if ((lf = fontbase[fbits(i) > nfonts ? 0 : fbits(i)]->ligfont) == 0) { 668 /* font lacks ligatures */ 669 return(i); 670 } 671 j = getch0(); 672 if (cbits(j) == 'i' && (lf & LFI)) 673 j = LIG_FI; 674 else if (cbits(j) == 'l' && (lf & LFL)) 675 j = LIG_FL; 676 else if (cbits(j) == 'f' && (lf & LFF)) { 677 if ((lf & (LFFI|LFFL)) && lg != 2) { 678 k = getch0(); 679 if (cbits(k)=='i' && (lf&LFFI)) 680 j = LIG_FFI; 681 else if (cbits(k)=='l' && (lf&LFFL)) 682 j = LIG_FFL; 683 else { 684 *pbp++ = k; 685 j = LIG_FF; 686 } 687 } else 688 j = LIG_FF; 689 } else { 690 *pbp++ = j; 691 j = i; 692 } 693 return(i & SFMASK | j); 694 } 695 696 697 caselg() 698 { 699 700 lg = 1; 701 if (skip()) 702 return; 703 lg = atoi(); 704 } 705 706 707 casefp() 708 { 709 register int i, j; 710 register char *s; 711 712 skip(); 713 /* allow .fp for fonts >nfonts, <NFONTS? */ 714 if ((i = cbits(getch()) - '0') <= 0 || i > nfonts) 715 errprint("fp: bad font position %d", i); 716 else if (skip() || !(j = getrq())) 717 errprint("fp: no font name"); 718 else if (skip() || !getname()) 719 setfp(i, j, 0); 720 else /* 3rd argument = filename */ 721 setfp(i, j, nextf); 722 } 723 724 setfp(pos, f, truename) /* mount font f at position pos[0...NFONTS] */ 725 register pos; 726 int f; 727 char *truename; 728 { 729 register k; 730 register struct Font *ft; 731 int n; 732 char longname[NS], shortname[20]; 733 extern int nchtab; 734 extern struct dev dev; 735 736 if (fontlab[pos] == f) /* if f already mounted at pos, */ 737 return(pos); /* don't remount it */ 738 zapwcache(0); 739 if (truename) 740 strcpy(shortname, truename); 741 else { 742 shortname[0] = f & BYTEMASK; 743 shortname[1] = f >> BYTE; 744 shortname[2] = '\0'; 745 } 746 sprintf(longname, "%s/dev%s/%s.out", fontfile, devname, shortname); 747 if ((k = open(longname, 0)) < 0) { 748 errprint("Can't open %s", longname); 749 return(-1); 750 } 751 if ((ft = fontbase[pos]) == 0) { 752 ft = fontbase[pos] = (struct Font *) malloc(EXTRAFONT); 753 ft->nwfont = MAXCHARS; 754 fontab[pos] = (char *)(ft + 1); 755 } 756 n = ft->nwfont; 757 read(k, (char *) ft, 3*n + nchtab + 128 - 32 + sizeof(struct Font)); 758 close(k); 759 760 k = ft->nwfont; 761 kerntab[pos] = (char *) fontab[pos] + k; 762 codetab[pos] = (char *) fontab[pos] + 2 * k; 763 /* have to reset the fitab pointer because the width may be different */ 764 fitab[pos] = (char *) fontab[pos] + 3 * k; 765 ft->nwfont = n; /* so can load a larger one again later */ 766 if (k > n) { 767 errprint("Font %s too big for position %d", shortname, pos); 768 return(-1); 769 } 770 if (pos == smnt) { 771 smnt = 0; 772 sbold = 0; 773 } 774 if ((fontlab[pos] = f) == 'S') 775 smnt = pos; 776 bdtab[pos] = cstab[pos] = ccstab[pos] = 0; 777 /* if there is a directory, no place to store its name. */ 778 /* if position isn't zero, no place to store its value. */ 779 /* only time a FONTPOS is pushed back is if it's a */ 780 /* standard font on position 0 (i.e., mounted implicitly. */ 781 /* there's a bug here: if there are several input lines */ 782 /* that look like .ft XX in short successtion, the output */ 783 /* will all be in the last one because the "x font ..." */ 784 /* comes out too soon. pushing back FONTPOS doesn't work */ 785 /* with .ft commands because input is flushed after .xx cmds */ 786 787 /* 788 * Trying to fix this FONTPOS problem: See findft() 789 */ 790 if ( pos > 0 && pos <= physfonts) 791 ptfpcmd(pos, shortname); 792 return(pos); 793 } 794 795 796 casecs() 797 { 798 register i, j; 799 800 noscale++; 801 skip(); 802 if (!(i = getrq()) || (i = findft(i)) < 0) 803 goto rtn; 804 skip(); 805 cstab[i] = atoi(); 806 skip(); 807 j = atoi(); 808 if (nonumb) 809 ccstab[i] = 0; 810 else 811 ccstab[i] = findps(j); 812 rtn: 813 zapwcache(0); 814 noscale = 0; 815 } 816 817 818 casebd() 819 { 820 register i, j, k; 821 822 zapwcache(0); 823 k = 0; 824 bd0: 825 if (skip() || !(i = getrq()) || (j = findft(i)) == -1) { 826 if (k) 827 goto bd1; 828 else 829 return; 830 } 831 if (j == smnt) { 832 k = smnt; 833 goto bd0; 834 } 835 if (k) { 836 sbold = j; 837 j = k; 838 } 839 bd1: 840 skip(); 841 noscale++; 842 bdtab[j] = atoi(); 843 noscale = 0; 844 } 845 846 847 casevs() 848 { 849 register i; 850 851 skip(); 852 vflag++; 853 dfact = INCH; /* default scaling is points! */ 854 dfactd = 72; 855 res = VERT; 856 i = inumb(&lss); 857 if (nonumb) 858 i = lss1; 859 /* if(i < VERT)i = VERT; */ 860 if (i < VERT) 861 i = 0; 862 lss1 = lss; 863 lss = i; 864 } 865 866 867 casess() 868 { 869 register i; 870 871 noscale++; 872 skip(); 873 if (i = atoi()) { 874 spacesz = i & 0177; 875 zapwcache(0); 876 sps = width(' ' | chbits); 877 } 878 noscale = 0; 879 } 880 881 882 tchar xlss() 883 { 884 /* stores \x'...' into 885 /* two successive tchars. 886 /* the first contains HX, the second the value, 887 /* encoded as a vertical motion. 888 /* decoding is done in n2.c by pchar(). 889 */ 890 int i; 891 892 getch(); 893 dfact = lss; 894 i = quant(atoi(), VERT); 895 dfact = 1; 896 getch(); 897 if (i >= 0) 898 *pbp++ = MOT | VMOT | i; 899 else 900 *pbp++ = MOT | VMOT | NMOT | -i; 901 return(HX); 902 } 903 904 char * 905 unpair(i) 906 register int i; 907 { static char name[3]; 908 909 name[0] = i & BYTEMASK; 910 name[1] = i >> BYTE; 911 name[2] = 0; 912 return (name); 913 } 914