ref: 37e0d4ab29c8483aab727b76effaec009b650153
dir: /sys/src/cmd/troff/t6.c/
/* * t6.c * * width functions, sizes and fonts */ #include "tdef.h" #include "fns.h" #include "ext.h" int fontlab[MAXFONTS+1]; int cstab[MAXFONTS+1]; int ccstab[MAXFONTS+1]; int bdtab[MAXFONTS+1]; int sbold = 0; t_width(Tchar j) { int i, k; if (iszbit(j)) return 0; if (ismot(j)) { if (isvmot(j)) return(0); k = absmot(j); if (isnmot(j)) k = -k; return(k); } i = cbits(j); if (i < ' ') { if (i == '\b') return(-widthp); if (i == PRESC) i = eschar; else if (i == HX) return(0); } if (i == ohc) return(0); i = trtab[i]; if (i < ' ') return(0); if (sfbits(j) == oldbits) { xfont = pfont; xpts = ppts; } else xbits(j, 0); if (i < nchnames + ALPHABET && widcache[i].fontpts == (xfont<<8) + xpts && !setwdf) k = widcache[i].width; else { k = getcw(i); if (bd) k += (bd - 1) * HOR; if (cs) k = cs; } widthp = k; return(k); } /* * clear width cache-- s means just space */ void zapwcache(int s) { int i; if (s) { widcache[' '].fontpts = 0; return; } for (i=0; i<NWIDCACHE; i++) widcache[i].fontpts = 0; } onfont(int n, int f) /* is char n on font f? */ { int i; Font *fp = &fonts[f]; Chwid *cp, *ep; char *np; if (n < ALPHABET) { if (fp->wp[n].num == n) /* ascii at front */ return n; else return -1; } cp = &fp->wp[ALPHABET]; ep = &fp->wp[fp->nchars]; for ( ; cp < ep; cp++) /* search others */ if (cp->num == n) return cp - &fp->wp[0]; /* maybe it was a \N... */ np = chname(n); if (*np == Number) { i = atoi(np+1); /* sscanf(np+1, "%d", &i); */ cp = &fp->wp[0]; ep = &fp->wp[fp->nchars]; for ( ; cp < ep; cp++) { /* search others */ if (cp->code == i) return cp - &fp->wp[0]; } return -2; /* a \N that doesn't have an entry */ } return -1; /* vanilla not found */ } getcw(int i) { int k, n, x; Font *fp; int nocache = 0; if (i < ' ') return 0; bd = 0; fp = &fonts[xfont]; if (i == ' ') { /* a blank */ k = (fp->spacewidth * spacesz + 6) / 12; /* this nonsense because .ss cmd uses 1/36 em as its units */ /* and default is 12 */ } else if ((n = onfont(i, xfont)) >= 0) { /* on this font at n */ k = fp->wp[n].wid; if (setwdf) numtabp[CT].val |= fp->wp[n].kern; } else if (n == -2) { /* \N with default width */ k = fp->defaultwidth; } else { /* not on current font */ nocache = 1; k = fp->defaultwidth; /* default-size space */ if (smnt) { int ii, jj; for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) { if ((n = onfont(i, ii)) >= 0) { k = fonts[ii].wp[n].wid; if (xfont == sbold) bd = bdtab[ii]; if (setwdf) numtabp[CT].val |= fonts[ii].wp[n].kern; break; } } } } if (!bd) bd = bdtab[xfont]; if (cs = cstab[xfont]) { nocache = 1; if (ccs = ccstab[xfont]) x = ccs; else x = xpts; cs = (cs * EMPTS(x)) / 36; } /* was (k & BYTEMASK); since .wid is unsigned, should never happen */ if (k < 0) ERROR "can't happen: negative width %d in getcw %d\n", k, i WARN; k = (k * xpts + (Unitwidth / 2)) / Unitwidth; if (nocache|bd) widcache[i].fontpts = 0; else { widcache[i].fontpts = (xfont<<8) + xpts; widcache[i].width = k; } return(k); /* Unitwidth is Units/Point, where /* Units is the fundamental digitization /* of the character set widths, and /* Point is the number of goobies in a point /* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6 /* In effect, it's the size at which the widths /* translate directly into units. */ } void xbits(Tchar i, int bitf) { int k; if(TROFF) { xfont = fbits(i); k = sbits(i); if(k) { xpts = pstab[k-1]; oldbits = sfbits(i); pfont = xfont; ppts = xpts; return; } switch(bitf) { case 0: xfont = font; xpts = pts; break; case 1: xfont = pfont; xpts = ppts; break; case 2: xfont = mfont; xpts = mpts; } } } /* these next two functions ought to be the same in troff and nroff, */ /* but the data structures they search are different. */ /* silly historical problem. */ Tchar t_setch(int c) { int j; char temp[50]; char *s; s = temp; if (c == '(') { /* \(xx */ if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0) return(0); } else { /* \C'...' */ c = getach(); while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1) s++; } *s = '\0'; #ifdef UNICODE return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */ #else if (NROFF) { j = chadd(temp, Troffchar, Lookup); if ( j == -1) return 0; else return j | chbits; } else return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */ #endif /*UNICODE*/ } Tchar t_setabs(void) /* set absolute char from \N'...' */ { int n; char temp[10]; getch(); /* delim */ n = 0; n = inumb(&n); getch(); /* delim */ if (nonumb) return 0; sprintf(temp, "%d", n); /* convert into "#n" */ n = chadd(temp, Number, Install); return n | chbits; } /* * fontlab[] is a cache that contains font information * for each font. * fontlab[] contains the 1- or 2-character name of the * font current associated with that font. * fonts 1..nfonts correspond to the mounted fonts; * the last of these are the special fonts. * If we don't use the (named) font in one of the * standard positions, we install the name in the next * free slot of fontlab[] and font[]. * Whenever we need info about the font, we * read in the data into the next free slot with getfont. * The ptfont() (t10.c) routine will tell * the device filter to put the font always at position * zero if xfont > nfonts, so no need to change these filters. * Yes, this is a bit kludgy. * * This gives the new specs of findft: * find the font name i, where i also can be a number. * Installs the font(name) i when not present * returns -1 on error */ t_findft(int i) { int k; Uchar *p; p = unpair(i); if (isdigit(p[0])) { /* first look for numbers */ k = p[0] - '0'; if (p[1] > 0 && isdigit(p[1])) k = 10 * k + p[1] - '0'; if (k > 0 && k <= nfonts && k < smnt) return(k); /* mounted font: .ft 3 */ if (fontlab[k] && k <= MAXFONTS) { /* translate */ return(k); /*number to a name */ } else { fprintf(stderr, "troff: no font at position %d\n", k); return(-1); /* wild number */ } } /* * Now we look for font names */ for (k = 1; fontlab[k] != i; k++) { if (k > MAXFONTS) return(-1); /* running out of fontlab space */ if (fontlab[k] == 0) { /* passed all existing names */ if (setfp(k, i, (char *) 0, 1) == -1) return(-1); else { fontlab[k] = i; /* install the name */ return(k); } } } return(k); /* was one of the existing names */ } void caseps(void) { int i; if (TROFF) { if(skip()) i = apts1; else { noscale++; i = inumb(&apts); /* this is a disaster for fractional point sizes */ noscale = 0; if(nonumb) i = apts1; } casps1(i); } } void casps1(int i) { /* * in olden times, it used to ignore changes to 0 or negative. * this is meant to allow the requested size to be anything, * in particular so eqn can generate lots of \s-3's and still * get back by matching \s+3's. if (i <= 0) return; */ apts1 = apts; apts = i; pts1 = pts; pts = findps(i); mchbits(); } findps(int i) { int j, k; for (j=k=0 ; pstab[j] != 0 ; j++) if (abs(pstab[j]-i) < abs(pstab[k]-i)) k = j; return(pstab[k]); } void t_mchbits(void) { int i, j, k; i = pts; for (j = 0; i > (k = pstab[j]); j++) if (!k) { j--; break; } chbits = 0; setsbits(chbits, ++j); setfbits(chbits, font); sps = width(' ' | chbits); zapwcache(1); } void t_setps(void) { int i, j; i = cbits(getch()); if (isdigit(i)) { /* \sd or \sdd */ i -= '0'; if (i == 0) /* \s0 */ j = apts1; else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) { /* \sdd */ j = 10 * i + j - '0'; ch = 0; } else /* \sd */ j = i; } else if (i == '(') { /* \s(dd */ j = cbits(getch()) - '0'; j = 10 * j + cbits(getch()) - '0'; if (j == 0) /* \s(00 */ j = apts1; } else if (i == '+' || i == '-') { /* \s+, \s- */ j = cbits(getch()); if (isdigit(j)) { /* \s+d, \s-d */ j -= '0'; } else if (j == '(') { /* \s+(dd, \s-(dd */ j = cbits(getch()) - '0'; j = 10 * j + cbits(getch()) - '0'; } if (i == '-') j = -j; j += apts; } casps1(j); } Tchar t_setht(void) /* set character height from \H'...' */ { int n; Tchar c; getch(); n = inumb(&apts); getch(); if (n == 0 || nonumb) n = apts; /* does this work? */ c = CHARHT; c |= ZBIT; setsbits(c, n); setfbits(c, pts); /* sneaky, CHARHT font bits are size bits */ return(c); } Tchar t_setslant(void) /* set slant from \S'...' */ { int n; Tchar c; getch(); n = 0; n = inumb(&n); getch(); if (nonumb) n = 0; c = SLANT; c |= ZBIT; setsfbits(c, n+180); return(c); } void caseft(void) { if (!TROFF) { n_caseft(); return; } skip(); setfont(1); } void t_setfont(int a) { int i, j; if (a) i = getrq(); else i = getsn(); if (!i || i == 'P') { j = font1; goto s0; } if (/* i == 'S' || */ i == '0') /* an experiment -- why can't we change to it? */ return; if ((j = findft(i)) == -1) if ((j = setfp(0, i, (char*) 0, 1)) == -1) /* try to put it in position 0 */ return; s0: font1 = font; font = j; mchbits(); } void t_setwd(void) { int base, wid; Tchar i; int delim, emsz, k; int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1; base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0; if (ismot(i = getch())) return; delim = cbits(i); savhp = numtabp[HP].val; numtabp[HP].val = 0; savapts = apts; savapts1 = apts1; savfont = font; savfont1 = font1; savpts = pts; savpts1 = pts1; setwdf++; while (cbits(i = getch()) != delim && !nlflg) { k = width(i); wid += k; numtabp[HP].val += k; if (!ismot(i)) { emsz = (INCH/72) * xpts; } else if (isvmot(i)) { k = absmot(i); if (isnmot(i)) k = -k; base -= k; emsz = 0; } else continue; if (base < numtabp[SB].val) numtabp[SB].val = base; if ((k = base + emsz) > numtabp[ST].val) numtabp[ST].val = k; } setn1(wid, 0, (Tchar) 0); numtabp[HP].val = savhp; apts = savapts; apts1 = savapts1; font = savfont; font1 = savfont1; pts = savpts; pts1 = savpts1; mchbits(); setwdf = 0; } Tchar t_vmot(void) { dfact = lss; vflag++; return t_mot(); } Tchar t_hmot(void) { dfact = EM; return t_mot(); } Tchar t_mot(void) { int j, n; Tchar i; j = HOR; getch(); /*eat delim*/ if (n = atoi0()) { if (vflag) j = VERT; i = makem(quant(n, j)); } else i = 0; getch(); vflag = 0; dfact = 1; return(i); } Tchar t_sethl(int k) { int j; Tchar i; j = EM / 2; if (k == 'u') j = -j; else if (k == 'r') j = -2 * j; vflag++; i = makem(j); vflag = 0; return(i); } Tchar t_makem(int i) { Tchar j; if (i >= 0) j = i; else j = -i; if (Hor > 1 && !vflag) j = (j + Hor/2)/Hor * Hor; j |= MOT; if (i < 0) j |= NMOT; if (vflag) j |= VMOT; return(j); } Tchar getlg(Tchar i) { Tchar j, k; int lf; if (!TROFF) return i; if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */ return(i); j = getch0(); if (cbits(j) == 'i' && (lf & LFI)) j = LIG_FI; else if (cbits(j) == 'l' && (lf & LFL)) j = LIG_FL; else if (cbits(j) == 'f' && (lf & LFF)) { if ((lf & (LFFI|LFFL)) && lg != 2) { k = getch0(); if (cbits(k)=='i' && (lf&LFFI)) j = LIG_FFI; else if (cbits(k)=='l' && (lf&LFFL)) j = LIG_FFL; else { *pbp++ = k; j = LIG_FF; } } else j = LIG_FF; } else { *pbp++ = j; j = i; } return(i & SFMASK | j); } void caselg(void) { if(TROFF) { skip(); lg = atoi0(); if (nonumb) lg = 1; } } void casefp(void) { int i, j; if (!TROFF) { n_casefp(); return; } skip(); i = cbits(getch()); if (isdigit(i)) { i -= '0'; j = cbits(getch()); if (isdigit(j)) i = 10 * i + j - '0'; } if (i <= 0 || i > nfonts) ERROR "fp: bad font position %d", i WARN; else if (skip() || !(j = getrq())) ERROR "fp: no font name" WARN; else if (skip() || !getname()) setfp(i, j, (char*) 0, 1); else /* 3rd argument = filename */ setfp(i, j, nextf, 1); } char *strdupl(const char *s) /* make a copy of s */ { char *t; t = (char *) malloc(strlen(s) + 1); if (t == NULL) ERROR "out of space in strdupl(%s)", s FATAL; strcpy(t, s); return t; } setfp(int pos, int f, char *truename, int print) /* mount font f at position pos[0...nfonts] */ { char pathname[NS], shortname[NS], *sl; zapwcache(0); if (truename) strcpy(shortname, truename); else strcpy(shortname, (char *) unpair(f)); if (truename && strrchr(truename, '/')) { /* .fp 1 R dir/file: use verbatim */ sprintf(pathname, "%s", truename); if (fonts[pos].truename) free(fonts[pos].truename); fonts[pos].truename = strdupl(truename); } else if (truename) { /* synonym: .fp 1 R Avant */ sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename); truename = 0; /* so doesn't get repeated by ptfpcmd */ } else /* vanilla: .fp 5 XX */ sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname); if (truename == 0 && fonts[pos].truename != 0) { free(fonts[pos].truename); fonts[pos].truename = 0; } if (getfont(pathname, pos) < 0) { ERROR "Can't open font file %s", pathname WARN; return -1; } if (print && !ascii) { ptfpcmd(pos, fonts[pos].longname, truename); ptfont(); } if (pos == smnt) { smnt = 0; sbold = 0; } fontlab[pos] = f; if (smnt == 0 && fonts[pos].specfont) smnt = pos; bdtab[pos] = cstab[pos] = ccstab[pos] = 0; return pos; } /* * .cs request; don't check legality of optional arguments */ void casecs(void) { int i, j; if (TROFF) { int savtr = trace; trace = 0; noscale++; skip(); if (!(i = getrq()) || (i = findft(i)) < 0) goto rtn; skip(); cstab[i] = atoi0(); skip(); j = atoi0(); if(nonumb) ccstab[i] = 0; else ccstab[i] = findps(j); rtn: zapwcache(0); noscale = 0; trace = savtr; } } void casebd(void) { int i, j, k; if (!TROFF) { n_casebd(); return; } zapwcache(0); k = 0; bd0: if (skip() || !(i = getrq()) || (j = findft(i)) == -1) { if (k) goto bd1; else return; } if (j == smnt) { k = smnt; goto bd0; } if (k) { sbold = j; j = k; } bd1: skip(); noscale++; bdtab[j] = atoi0(); noscale = 0; } void casevs(void) { int i; if (!TROFF) { n_casevs(); return; } skip(); vflag++; dfact = INCH; /* default scaling is points! */ dfactd = 72; res = VERT; i = inumb(&lss); if (nonumb) i = lss1; if (i < VERT) i = VERT; lss1 = lss; lss = i; } void casess(void) { int i; if(TROFF) { noscale++; skip(); if(i = atoi0()) { spacesz = i & 0177; zapwcache(0); sps = width(' ' | chbits); } noscale = 0; } } Tchar t_xlss(void) { /* stores \x'...' into two successive Tchars. /* the first contains HX, the second the value, /* encoded as a vertical motion. /* decoding is done in n2.c by pchar(). */ int i; getch(); dfact = lss; i = quant(atoi0(), VERT); dfact = 1; getch(); if (i >= 0) *pbp++ = MOT | VMOT | i; else *pbp++ = MOT | VMOT | NMOT | -i; return(HX); } Uchar *unpair(int i) { static Uchar name[3]; name[0] = i & SHORTMASK; name[1] = (i >> SHORT) & SHORTMASK; name[2] = 0; return name; }