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