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