Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * 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)
{
        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) {
                int j;

                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());
        j = i;                          /* make compiler happy */
        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];

        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);
        j = 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;
}