aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/troff/t6.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/troff/t6.c')
-rw-r--r--src/cmd/troff/t6.c881
1 files changed, 881 insertions, 0 deletions
diff --git a/src/cmd/troff/t6.c b/src/cmd/troff/t6.c
new file mode 100644
index 00000000..b778916c
--- /dev/null
+++ b/src/cmd/troff/t6.c
@@ -0,0 +1,881 @@
+/*
+ * 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;
+}