1 #ifndef lint 2 static char sccsid[] = "@(#)t6.c 2.1 (CWI) 85/07/18"; 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 > nfonts, 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 if( isdigit(p[0])) { /* first look for numbers */ 314 k = p[0] - '0'; 315 if( p[1] > 0 && isdigit(p[1])) 316 k = 10 * k + ( p[1] - '0'); 317 318 /* 319 fprintf(ptid, "x xxx it's a number: %d\n", k); 320 */ 321 if( k > 0 && k <= nfonts && k < smnt ) { 322 /* 323 fprintf(ptid, "x xxx it's a mounted font\n"); 324 */ 325 return(k); /* mounted font */ 326 } 327 if( fontlab[k] && k <= MAXFONTS) { /* translate */ 328 /* 329 fprintf(ptid, "x xxx font exists\n"); 330 */ 331 return(k); /*number to a name */ 332 } 333 else { 334 fprintf(stderr, "troff: no font at position %d\n", k); 335 return(-1); /* wild number */ 336 } 337 } 338 339 /* 340 * Now we look for font names 341 */ 342 for (k = 1; fontlab[k] != i; k++) { 343 if (k > MAXFONTS +1) /* the +1 is for the ``font cache'' */ 344 return(-1); /* running out of fontlab space */ 345 if ( !fontlab[k] ) { /* passed all existing names */ 346 if(setfp(0, i, 0) < 0) 347 return(-1); 348 else { 349 /* 350 fprintf(ptid, "x xxx installed %s on %d\n", name ,k); 351 */ 352 fontlab[k] = i; /* install the name */ 353 return(k); 354 } 355 } 356 } 357 return(k); /* was one of the existing names */ 358 } 359 360 361 caseps() 362 { 363 register i; 364 365 if (skip()) 366 i = apts1; 367 else { 368 noscale++; 369 i = inumb(&apts); /* this is a disaster for fractional point sizes */ 370 noscale = 0; 371 if (nonumb) 372 return; 373 } 374 casps1(i); 375 } 376 377 378 casps1(i) 379 register int i; 380 { 381 382 /* 383 * in olden times, it used to ignore changes to 0 or negative. 384 * this is meant to allow the requested size to be anything, 385 * in particular so eqn can generate lots of \s-3's and still 386 * get back by matching \s+3's. 387 388 if (i <= 0) 389 return; 390 */ 391 apts1 = apts; 392 apts = i; 393 pts1 = pts; 394 pts = findps(i); 395 mchbits(); 396 } 397 398 399 findps(i) 400 register int i; 401 { 402 register j, k; 403 404 for (j=k=0 ; pstab[j] != 0 ; j++) 405 if (abs(pstab[j]-i) < abs(pstab[k]-i)) 406 k = j; 407 408 return(pstab[k]); 409 } 410 411 412 mchbits() 413 { 414 register i, j, k; 415 416 i = pts; 417 for (j = 0; i > (k = pstab[j]); j++) 418 if (!k) { 419 k = pstab[--j]; 420 break; 421 } 422 chbits = 0; 423 setsbits(chbits, ++j); 424 setfbits(chbits, font); 425 sps = width(' ' | chbits); 426 zapwcache(1); 427 } 428 429 setps() 430 { 431 register int i, j; 432 433 i = cbits(getch()); 434 if (isdigit(i)) { /* \sd or \sdd */ 435 i -= '0'; 436 if (i == 0) /* \s0 */ 437 j = apts1; 438 else if (i <= 3 && isdigit(j = cbits(ch=getch()))) { /* \sdd */ 439 j = 10 * i + j - '0'; 440 ch = 0; 441 } else /* \sd */ 442 j = i; 443 } else if (i == '(') { /* \s(dd */ 444 j = cbits(getch()) - '0'; 445 j = 10 * j + cbits(getch()) - '0'; 446 if (j == 0) /* \s(00 */ 447 j = apts1; 448 } else if (i == '+' || i == '-') { /* \s+, \s- */ 449 j = cbits(getch()); 450 if (isdigit(j)) { /* \s+d, \s-d */ 451 j -= '0'; 452 } else if (j == '(') { /* \s+(dd, \s-(dd */ 453 j = cbits(getch()) - '0'; 454 j = 10 * j + cbits(getch()) - '0'; 455 } 456 if (i == '-') 457 j = -j; 458 j += apts; 459 } 460 casps1(j); 461 } 462 463 464 tchar setht() /* set character height from \H'...' */ 465 { 466 int n; 467 tchar c; 468 469 getch(); 470 n = inumb(&apts); 471 getch(); 472 if (n == 0 || nonumb) 473 n = apts; /* does this work? */ 474 c = CHARHT; 475 c |= ZBIT; 476 setsbits(c, n); 477 return(c); 478 } 479 480 tchar setslant() /* set slant from \S'...' */ 481 { 482 int n; 483 tchar c; 484 485 getch(); 486 n = 0; 487 n = inumb(&n); 488 getch(); 489 if (nonumb) 490 n = 0; 491 c = SLANT; 492 c |= ZBIT; 493 setsfbits(c, n+180); 494 return(c); 495 } 496 497 498 caseft() 499 { 500 skip(); 501 setfont(1); 502 } 503 504 505 setfont(a) 506 int a; 507 { 508 register i, j; 509 510 if (a) 511 i = getrq(); 512 else 513 i = getsn(); 514 if (!i || i == 'P') { 515 j = font1; 516 goto s0; 517 } 518 if (i == 'S' || i == '0') 519 return; 520 if ((j = findft(i)) == -1) 521 if ((j = setfp(0, i, 0)) == -1) /* try to put it in position 0 */ 522 return; 523 s0: 524 font1 = font; 525 font = j; 526 mchbits(); 527 } 528 529 530 setwd() 531 { 532 register base, wid; 533 register tchar i; 534 int delim, emsz, k; 535 int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1; 536 537 base = numtab[ST].val = numtab[ST].val = wid = numtab[CT].val = 0; 538 if (ismot(i = getch())) 539 return; 540 delim = cbits(i); 541 savhp = numtab[HP].val; 542 numtab[HP].val = 0; 543 savapts = apts; 544 savapts1 = apts1; 545 savfont = font; 546 savfont1 = font1; 547 savpts = pts; 548 savpts1 = pts1; 549 setwdf++; 550 while (cbits(i = getch()) != delim && !nlflg) { 551 k = width(i); 552 wid += k; 553 numtab[HP].val += k; 554 if (!ismot(i)) { 555 emsz = POINT * xpts; 556 } else if (isvmot(i)) { 557 k = absmot(i); 558 if (isnmot(i)) 559 k = -k; 560 base -= k; 561 emsz = 0; 562 } else 563 continue; 564 if (base < numtab[SB].val) 565 numtab[SB].val = base; 566 if ((k = base + emsz) > numtab[ST].val) 567 numtab[ST].val = k; 568 } 569 setn1(wid, 0, (tchar) 0); 570 numtab[HP].val = savhp; 571 apts = savapts; 572 apts1 = savapts1; 573 font = savfont; 574 font1 = savfont1; 575 pts = savpts; 576 pts1 = savpts1; 577 mchbits(); 578 setwdf = 0; 579 } 580 581 582 tchar vmot() 583 { 584 dfact = lss; 585 vflag++; 586 return(mot()); 587 } 588 589 590 tchar hmot() 591 { 592 dfact = EM; 593 return(mot()); 594 } 595 596 597 tchar mot() 598 { 599 register int j, n; 600 register tchar i; 601 602 j = HOR; 603 getch(); /*eat delim*/ 604 if (n = atoi()) { 605 if (vflag) 606 j = VERT; 607 i = makem(quant(n, j)); 608 } else 609 i = 0; 610 getch(); 611 vflag = 0; 612 dfact = 1; 613 return(i); 614 } 615 616 617 tchar sethl(k) 618 int k; 619 { 620 register j; 621 tchar i; 622 623 j = EM / 2; 624 if (k == 'u') 625 j = -j; 626 else if (k == 'r') 627 j = -2 * j; 628 vflag++; 629 i = makem(j); 630 vflag = 0; 631 return(i); 632 } 633 634 635 tchar makem(i) 636 register int i; 637 { 638 register tchar j; 639 640 if ((j = i) < 0) 641 j = -j; 642 j |= MOT; 643 if (i < 0) 644 j |= NMOT; 645 if (vflag) 646 j |= VMOT; 647 return(j); 648 } 649 650 651 tchar getlg(i) 652 tchar i; 653 { 654 tchar j, k; 655 register int lf; 656 657 if ((lf = fontbase[fbits(i)]->ligfont) == 0) /* font lacks ligatures */ 658 return(i); 659 j = getch0(); 660 if (cbits(j) == 'i' && (lf & LFI)) 661 j = LIG_FI; 662 else if (cbits(j) == 'l' && (lf & LFL)) 663 j = LIG_FL; 664 else if (cbits(j) == 'f' && (lf & LFF)) { 665 if ((lf & (LFFI|LFFL)) && lg != 2) { 666 k = getch0(); 667 if (cbits(k)=='i' && (lf&LFFI)) 668 j = LIG_FFI; 669 else if (cbits(k)=='l' && (lf&LFFL)) 670 j = LIG_FFL; 671 else { 672 *pbp++ = k; 673 j = LIG_FF; 674 } 675 } else 676 j = LIG_FF; 677 } else { 678 *pbp++ = j; 679 j = i; 680 } 681 return(i & SFMASK | j); 682 } 683 684 685 caselg() 686 { 687 688 lg = 1; 689 if (skip()) 690 return; 691 lg = atoi(); 692 } 693 694 695 casefp() 696 { 697 register int i, j; 698 register char *s; 699 700 skip(); 701 if ((i = cbits(getch()) - '0') <= 0 || i > nfonts) 702 errprint("fp: bad font position %d", i); 703 else if (skip() || !(j = getrq())) 704 errprint("fp: no font name"); 705 else if (skip() || !getname()) 706 setfp(i, j, 0); 707 else /* 3rd argument = filename */ 708 setfp(i, j, nextf); 709 } 710 711 setfp(pos, f, truename) /* mount font f at position pos[0...nfonts] */ 712 int pos, f; 713 char *truename; 714 { 715 register k; 716 int n; 717 char longname[NS], shortname[20]; 718 extern int nchtab; 719 720 if (fontlab[pos] == f) /* if f already mounted at pos, */ 721 return(pos); /* don't remount it */ 722 zapwcache(0); 723 if (truename) 724 strcpy(shortname, truename); 725 else { 726 shortname[0] = f & BYTEMASK; 727 shortname[1] = f >> BYTE; 728 shortname[2] = '\0'; 729 } 730 sprintf(longname, "%s/dev%s/%s.out", fontfile, devname, shortname); 731 if ((k = open(longname, 0)) < 0) { 732 errprint("Can't open %s", longname); 733 return(-1); 734 } 735 n = fontbase[pos]->nwfont & BYTEMASK; 736 read(k, (char *) fontbase[pos], 3*n + nchtab + 128 - 32 + sizeof(struct Font)); 737 kerntab[pos] = (char *) fontab[pos] + (fontbase[pos]->nwfont & BYTEMASK); 738 /* have to reset the fitab pointer because the width may be different */ 739 fitab[pos] = (char *) fontab[pos] + 3 * (fontbase[pos]->nwfont & BYTEMASK); 740 if ((fontbase[pos]->nwfont & BYTEMASK) > n) { 741 errprint("Font %s too big for position %d", shortname, pos); 742 return(-1); 743 } 744 fontbase[pos]->nwfont = n; /* so can load a larger one again later */ 745 close(k); 746 if (pos == smnt) { 747 smnt = 0; 748 sbold = 0; 749 } 750 if ((fontlab[pos] = f) == 'S') 751 smnt = pos; 752 bdtab[pos] = cstab[pos] = ccstab[pos] = 0; 753 /* if there is a directory, no place to store its name. */ 754 /* if position isn't zero, no place to store its value. */ 755 /* only time a FONTPOS is pushed back is if it's a */ 756 /* standard font on position 0 (i.e., mounted implicitly. */ 757 /* there's a bug here: if there are several input lines */ 758 /* that look like .ft XX in short successtion, the output */ 759 /* will all be in the last one because the "x font ..." */ 760 /* comes out too soon. pushing back FONTPOS doesn't work */ 761 /* with .ft commands because input is flushed after .xx cmds */ 762 763 /* 764 * Trying to fix this FONTPOS problem: See findft() 765 */ 766 if ( pos > 0 && pos <= nfonts) 767 ptfpcmd(pos, shortname); 768 return(pos); 769 } 770 771 772 casecs() 773 { 774 register i, j; 775 776 noscale++; 777 skip(); 778 if (!(i = getrq()) || (i = findft(i)) < 0) 779 goto rtn; 780 skip(); 781 cstab[i] = atoi(); 782 skip(); 783 j = atoi(); 784 if (nonumb) 785 ccstab[i] = 0; 786 else 787 ccstab[i] = findps(j); 788 rtn: 789 zapwcache(0); 790 noscale = 0; 791 } 792 793 794 casebd() 795 { 796 register i, j, k; 797 798 zapwcache(0); 799 k = 0; 800 bd0: 801 if (skip() || !(i = getrq()) || (j = findft(i)) == -1) { 802 if (k) 803 goto bd1; 804 else 805 return; 806 } 807 if (j == smnt) { 808 k = smnt; 809 goto bd0; 810 } 811 if (k) { 812 sbold = j; 813 j = k; 814 } 815 bd1: 816 skip(); 817 noscale++; 818 bdtab[j] = atoi(); 819 noscale = 0; 820 } 821 822 823 casevs() 824 { 825 register i; 826 827 skip(); 828 vflag++; 829 dfact = INCH; /* default scaling is points! */ 830 dfactd = 72; 831 res = VERT; 832 i = inumb(&lss); 833 if (nonumb) 834 i = lss1; 835 /* if(i < VERT)i = VERT; */ 836 if (i < VERT) 837 i = 0; 838 lss1 = lss; 839 lss = i; 840 } 841 842 843 casess() 844 { 845 register i; 846 847 noscale++; 848 skip(); 849 if (i = atoi()) { 850 spacesz = i & 0177; 851 zapwcache(0); 852 sps = width(' ' | chbits); 853 } 854 noscale = 0; 855 } 856 857 858 tchar xlss() 859 { 860 /* stores \x'...' into 861 /* two successive tchars. 862 /* the first contains HX, the second the value, 863 /* encoded as a vertical motion. 864 /* decoding is done in n2.c by pchar(). 865 */ 866 int i; 867 868 getch(); 869 dfact = lss; 870 i = quant(atoi(), VERT); 871 dfact = 1; 872 getch(); 873 if (i >= 0) 874 *pbp++ = MOT | VMOT | i; 875 else 876 *pbp++ = MOT | VMOT | NMOT | -i; 877 return(HX); 878 } 879 880 char * 881 unpair(i) 882 register int i; 883 { static char name[3]; 884 885 name[0] = i & BYTEMASK; 886 name[1] = i >> BYTE; 887 name[2] = 0; 888 return (name); 889 } 890