Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
 * troff5.c
 * 
 * misc processing requests
 */

#include "tdef.h"
#include "fns.h"
#include "ext.h"

int     iflist[NIF];
int     ifx;
int     ifnum = 0;      /* trying numeric expression for .if or .ie condition */

void casead(void)
{
        int i;

        ad = 1;
        /* leave admod alone */
        if (skip())
                return;
        switch (i = cbits(getch())) {
        case 'r':       /* right adj, left ragged */
                admod = 2;
                break;
        case 'l':       /* left adj, right ragged */
                admod = ad = 0; /* same as casena */
                break;
        case 'c':       /*centered adj*/
                admod = 1;
                break;
        case 'b': 
        case 'n':
                admod = 0;
                break;
        case '0': 
        case '2': 
        case '4':
                ad = 0;
        case '1': 
        case '3': 
        case '5':
                admod = (i - '0') / 2;
        }
}


void casena(void)
{
        ad = 0;
}


void casefi(void)
{
        tbreak();
        fi = 1;
        pendnf = 0;
}


void casenf(void)
{
        tbreak();
        fi = 0;
}


void casers(void)
{
        dip->nls = 0;
}


void casens(void)
{
        dip->nls++;
}


chget(int c)
{
        Tchar i;

        i = 0;
        if (skip() || ismot(i = getch()) || cbits(i) == ' ' || cbits(i) == '\n') {
                ch = i;
                return(c);
        } else 
                return cbits(i);        /* was (i & BYTEMASK) */
}


void casecc(void)
{
        cc = chget('.');
}


void casec2(void)
{
        c2 = chget('\'');
}


void casehc(void)
{
        ohc = chget(OHC);
}


void casetc(void)
{
        tabc = chget(0);
}


void caselc(void)
{
        dotc = chget(0);
}


void casehy(void)
{
        int i;

        hyf = 1;
        if (skip())
                return;
        noscale++;
        i = atoi0();
        noscale = 0;
        if (nonumb)
                return;
        hyf = max(i, 0);
}


void casenh(void)
{
        hyf = 0;
}


max(int aa, int bb)
{
        if (aa > bb)
                return(aa);
        else 
                return(bb);
}


void casece(void)
{
        int i;

        noscale++;
        skip();
        i = max(atoi0(), 0);
        if (nonumb)
                i = 1;
        tbreak();
        ce = i;
        noscale = 0;
}


void casein(void)
{
        int i;

        if (skip())
                i = in1;
        else {
                i = max(hnumb(&in), 0);
                if (nonumb)
                        i = in1;
        }
        tbreak();
        in1 = in;
        in = i;
        if (!nc) {
                un = in;
                setnel();
        }
}


void casell(void)
{
        int i;

        if (skip())
                i = ll1;
        else {
                i = max(hnumb(&ll), INCH / 10);
                if (nonumb)
                        i = ll1;
        }
        ll1 = ll;
        ll = i;
        setnel();
}


void caselt(void)
{
        int i;

        if (skip())
                i = lt1;
        else {
                i = max(hnumb(&lt), 0);
                if (nonumb)
                        i = lt1;
        }
        lt1 = lt;
        lt = i;
}


void caseti(void)
{
        int i;

        if (skip())
                return;
        i = max(hnumb(&in), 0);
        tbreak();
        un1 = i;
        setnel();
}


void casels(void)
{
        int i;

        noscale++;
        if (skip())
                i = ls1;
        else {
                i = max(inumb(&ls), 1);
                if (nonumb)
                        i = ls1;
        }
        ls1 = ls;
        ls = i;
        noscale = 0;
}


void casepo(void)
{
        int i;

        if (skip())
                i = po1;
        else {
                i = max(hnumb(&po), 0);
                if (nonumb)
                        i = po1;
        }
        po1 = po;
        po = i;
        if (TROFF & !ascii)
                esc += po - po1;
}


void casepl(void)
{
        int i;

        skip();
        if ((i = vnumb(&pl)) == 0)
                pl = 11 * INCH; /*11in*/
        else 
                pl = i;
        if (numtabp[NL].val > pl)
                numtabp[NL].val = pl;
}


void casewh(void)
{
        int i, j, k;

        lgf++;
        skip();
        i = vnumb((int *)0);
        if (nonumb)
                return;
        skip();
        j = getrq();
        if ((k = findn(i)) != NTRAP) {
                mlist[k] = j;
                return;
        }
        for (k = 0; k < NTRAP; k++)
                if (mlist[k] == 0)
                        break;
        if (k == NTRAP) {
                flusho();
                ERROR "cannot plant trap." WARN;
                return;
        }
        mlist[k] = j;
        nlist[k] = i;
}


void casech(void)
{
        int i, j, k;

        lgf++;
        skip();
        if (!(j = getrq()))
                return;
        else 
                for (k = 0; k < NTRAP; k++)
                        if (mlist[k] == j)
                                break;
        if (k == NTRAP)
                return;
        skip();
        i = vnumb((int *)0);
        if (nonumb)
                mlist[k] = 0;
        nlist[k] = i;
}


findn(int i)
{
        int k;

        for (k = 0; k < NTRAP; k++)
                if ((nlist[k] == i) && (mlist[k] != 0))
                        break;
        return(k);
}


void casepn(void)
{
        int i;

        skip();
        noscale++;
        i = max(inumb(&numtabp[PN].val), 0);
        noscale = 0;
        if (!nonumb) {
                npn = i;
                npnflg++;
        }
}


void casebp(void)
{
        int i;
        Stack *savframe;

        if (dip != d)
                return;
        savframe = frame;
        skip();
        if ((i = inumb(&numtabp[PN].val)) < 0)
                i = 0;
        tbreak();
        if (!nonumb) {
                npn = i;
                npnflg++;
        } else if (dip->nls)
                return;
        eject(savframe);
}

void casetm(void)
{
        casetm1(0, stderr);
}


void casefm(void)
{
        static struct fcache {
                char *name;
                FILE *fp;
        } fcache[15];
        int i;

        if ( skip() || !getname()) {
                ERROR "fm: missing filename" WARN;
                return;
        }
                
        for (i = 0; i < 15 && fcache[i].fp != NULL; i++) {
                if (strcmp(nextf, fcache[i].name) == 0)
                        break;
        }
        if (i >= 15) {
                ERROR "fm: too many streams" WARN;
                return;
        }
        if (fcache[i].fp == NULL) {
                if( (fcache[i].fp = fopen(nextf, "w")) == NULL) {
                        ERROR "fm: cannot open %s", nextf WARN;
                        return;
                }
                fcache[i].name = strdupl(nextf);
        }
        casetm1(0, fcache[i].fp);
}

void casetm1(int ab, FILE *out) 
{
        int i, j, c;
        char *p;
        char tmbuf[NTM];

        lgf++;
        copyf++;
        if (ab) {
                if (skip())
                        ERROR "User Abort" WARN;
                else {
                        extern int error;
                        int savtrac = trace;
                        trace = 0;
                        noscale++;
                        i = inumb(&trace);
                        noscale--;
                        if (i) {
                                error = i;
                                if (nlflg || skip())
                                        ERROR "User Abort, exit code %d", i WARN;
                        }
                        trace = savtrac;
                }
        } else
                skip(); 
        for (i = 0; i < NTM - 2; ) {
                if ((c = cbits(getch())) == '\n' || c == RIGHT)
                        break;
                else if (c == MINUS) {  /* special pleading for strange encodings */
                        tmbuf[i++] = '\\';
                        tmbuf[i++] = '-';
                } else if (c == PRESC) {
                        tmbuf[i++] = '\\';
                        tmbuf[i++] = 'e';
                } else if (c == FILLER) {
                        tmbuf[i++] = '\\';
                        tmbuf[i++] = '&';
                } else if (c == UNPAD) {
                        tmbuf[i++] = '\\';
                        tmbuf[i++] = ' ';
                } else if (c == OHC) {
                        tmbuf[i++] = '\\';
                        tmbuf[i++] = '%';
                } else if (c >= ALPHABET) {
                        p = chname(c);
                        switch (*p) {
                        case MBchar:
                                sprintf(&tmbuf[i], p+1);
                                break;
                        case Number:
                                sprintf(&tmbuf[i], "\\N'%s'", p+1);
                                break;
                        case Troffchar:
                                if (strlen(p+1) == 2)
                                        sprintf(&tmbuf[i], "\\(%s", p+1);
                                else
                                        sprintf(&tmbuf[i], "\\C'%s'", p+1);
                                break;
                        default:
                                sprintf(&tmbuf[i]," %s? ", p);
                                break;
                        }
                        j = strlen(&tmbuf[i]);
                        i += j;
                } else
                        tmbuf[i++] = c;
        }
        tmbuf[i] = 0;
        if (ab) /* truncate output */
                obufp = obuf;   /* should be a function in n2.c */
        flusho();
        if (i)
                fprintf(out, "%s\n", tmbuf);
        fflush(out);
        copyf--;
        lgf--;
}


void casesp(void)
{
        casesp1(0);
}

void casesp1(int a)
{
        int i, j, savlss;

        tbreak();
        if (dip->nls || trap)
                return;
        i = findt1();
        if (!a) {
                skip();
                j = vnumb((int *)0);
                if (nonumb)
                        j = lss;
        } else 
                j = a;
        if (j == 0)
                return;
        if (i < j)
                j = i;
        savlss = lss;
        if (dip != d)
                i = dip->dnl; 
        else 
                i = numtabp[NL].val;
        if ((i + j) < 0)
                j = -i;
        lss = j;
        newline(0);
        lss = savlss;
}


void casert(void)
{
        int a, *p;

        skip();
        if (dip != d)
                p = &dip->dnl; 
        else 
                p = &numtabp[NL].val;
        a = vnumb(p);
        if (nonumb)
                a = dip->mkline;
        if ((a < 0) || (a >= *p))
                return;
        nb++;
        casesp1(a - *p);
}


void caseem(void)
{
        lgf++;
        skip();
        em = getrq();
}


void casefl(void)
{
        tbreak();
        if (!ascii)
                ptflush();
        flusho();
}


void caseev(void)
{
        int nxev;

        if (skip()) {
e0:
                if (evi == 0)
                        return;
                nxev =  evlist[--evi];
                goto e1;
        }
        noscale++;
        nxev = atoi0();
        noscale = 0;
        if (nonumb)
                goto e0;
        flushi();
        if (nxev >= NEV || nxev < 0 || evi >= EVLSZ) {
                flusho();
                ERROR "cannot do .ev %d", nxev WARN;
                if (error)
                        done2(040);
                else 
                        edone(040);
                return;
        }
        evlist[evi++] = ev;
e1:
        if (ev == nxev)
                return;
        ev = nxev;
        envp = &env[ev];
}

void envcopy(Env *e1, Env *e2)  /* copy env e2 to e1 */
{
        *e1 = *e2;      /* rumor hath that this fails on some machines */
}


void caseel(void)
{
        if (--ifx < 0) {
                ifx = 0;
                iflist[0] = 0;
        }
        caseif1(2);
}


void caseie(void)
{
        if (ifx >= NIF) {
                ERROR "if-else overflow." WARN;
                ifx = 0;
                edone(040);
        }
        caseif1(1);
        ifx++;
}


void caseif(void)
{
        caseif1(0);
}

void caseif1(int x)
{
        extern int falsef;
        int notflag, true;
        Tchar i;

        if (x == 2) {
                notflag = 0;
                true = iflist[ifx];
                goto i1;
        }
        true = 0;
        skip();
        if ((cbits(i = getch())) == '!') {
                notflag = 1;
        } else {
                notflag = 0;
                ch = i;
        }
        ifnum++;
        i = atoi0();
        ifnum = 0;
        if (!nonumb) {
                if (i > 0)
                        true++;
                goto i1;
        }
        i = getch();
        switch (cbits(i)) {
        case 'e':
                if (!(numtabp[PN].val & 01))
                        true++;
                break;
        case 'o':
                if (numtabp[PN].val & 01)
                        true++;
                break;
        case 'n':
                if (NROFF)
                        true++;
                break;
        case 't':
                if (TROFF)
                        true++;
                break;
        case ' ':
                break;
        default:
                true = cmpstr(i);
        }
i1:
        true ^= notflag;
        if (x == 1)
                iflist[ifx] = !true;
        if (true) {
i2:
                while ((cbits(i = getch())) == ' ')
                        ;
                if (cbits(i) == LEFT)
                        goto i2;
                ch = i;
                nflush++;
        } else {
                if (!nlflg) {
                        copyf++;
                        falsef++;
                        eatblk(0);
                        copyf--;
                        falsef--;
                }
        }
}

void eatblk(int inblk)
{
        int cnt, i;

        cnt = 0;
        do {
                if (ch) {
                        i = cbits(ch);
                        ch = 0;
                } else
                        i = cbits(getch0());
                if (i == ESC)
                        cnt++;
                else {
                        if (cnt == 1)
                                switch (i) {
                                case '{':  i = LEFT; break;
                                case '}':  i = RIGHT; break;
                                case '\n': i = 'x'; break;
                                }
                        cnt = 0;
                }
                if (i == LEFT) eatblk(1);
        } while ((!inblk && (i != '\n')) || (inblk && (i != RIGHT)));
        if (i == '\n') {
                nlflg++;
                if (ip == 0)
                        numtabp[CD].val++;
        }
}


cmpstr(Tchar c)
{
        int j, delim;
        Tchar i;
        int val;
        int savapts, savapts1, savfont, savfont1, savpts, savpts1;
        Tchar string[1280];
        Tchar *sp;

        if (ismot(c))
                return(0);
        delim = cbits(c);
        savapts = apts;
        savapts1 = apts1;
        savfont = font;
        savfont1 = font1;
        savpts = pts;
        savpts1 = pts1;
        sp = string;
        while ((j = cbits(i = getch()))!=delim && j!='\n' && sp<&string[1280-1])
                *sp++ = i;
        if (sp >= string + 1280) {
                ERROR "too-long string compare." WARN;
                edone(0100);
        }
        if (nlflg) {
                val = sp==string;
                goto rtn;
        }
        *sp = 0;
        apts = savapts;
        apts1 = savapts1;
        font = savfont;
        font1 = savfont1;
        pts = savpts;
        pts1 = savpts1;
        mchbits();
        val = 1;
        sp = string;
        while ((j = cbits(i = getch())) != delim && j != '\n') {
                if (*sp != i) {
                        eat(delim);
                        val = 0;
                        goto rtn;
                }
                sp++;
        }
        if (*sp)
                val = 0;
rtn:
        apts = savapts;
        apts1 = savapts1;
        font = savfont;
        font1 = savfont1;
        pts = savpts;
        pts1 = savpts1;
        mchbits();
        return(val);
}


void caserd(void)
{

        lgf++;
        skip();
        getname();
        if (!iflg) {
                if (quiet) {
                        if (NROFF) {
                                echo_off();
                                flusho();
                        }
                        fprintf(stderr, "\007"); /*bell*/
                } else {
                        if (nextf[0]) {
                                fprintf(stderr, "%s:", nextf);
                        } else {
                                fprintf(stderr, "\007"); /*bell*/
                        }
                }
        }
        collect();
        tty++;
        pushi(RD_OFFSET, PAIR('r','d'));
}


rdtty(void)
{
        char    onechar;

        onechar = 0;
        if (read(0, &onechar, 1) == 1) {
                if (onechar == '\n')
                        tty++;
                else 
                        tty = 1;
                if (tty != 3)
                        return(onechar);
        }
        tty = 0;
        if (NROFF && quiet)
                echo_on();
        return(0);
}


void caseec(void)
{
        eschar = chget('\\');
}


void caseeo(void)
{
        eschar = 0;
}


void caseta(void)
{
        int i, j, k;

        tabtab[0] = nonumb = 0;
        for (i = 0; ((i < (NTAB - 1)) && !nonumb); i++) {
                if (skip())
                        break;
                k = tabtab[max(i-1, 0)] & TABMASK;
                if ((j = max(hnumb(&k), 0)) > TABMASK) {
                        ERROR "Tab too far away" WARN;
                        j = TABMASK;
                }
                tabtab[i] = j & TABMASK;
                if (!nonumb) 
                        switch (cbits(ch)) {
                        case 'C':
                                tabtab[i] |= CTAB;
                                break;
                        case 'R':
                                tabtab[i] |= RTAB;
                                break;
                        default: /*includes L*/
                                break;
                        }
                nonumb = ch = 0;
        }
        if (!skip())
                ERROR "Too many tab stops" WARN;
        tabtab[i] = 0;
}


void casene(void)
{
        int i, j;

        skip();
        i = vnumb((int *)0);
        if (nonumb)
                i = lss;
        if (dip == d && numtabp[NL].val == -1) {
                newline(1);
                return;
        }
        if (i > (j = findt1())) {
                i = lss;
                lss = j;
                dip->nls = 0;
                newline(0);
                lss = i;
        }
}


void casetr(void)
{
        int i, j;
        Tchar k;

        lgf++;
        skip();
        while ((i = cbits(k=getch())) != '\n') {
                if (ismot(k))
                        return;
                if (ismot(k = getch()))
                        return;
                if ((j = cbits(k)) == '\n')
                        j = ' ';
                trtab[i] = j;
        }
}


void casecu(void)
{
        cu++;
        caseul();
}


void caseul(void)
{
        int i;

        noscale++;
        skip();
        i = max(atoi0(), 0);
        if (nonumb)
                i = 1;
        if (ul && (i == 0)) {
                font = sfont;
                ul = cu = 0;
        }
        if (i) {
                if (!ul) {
                        sfont = font;
                        font = ulfont;
                }
                ul = i;
        }
        noscale = 0;
        mchbits();
}


void caseuf(void)
{
        int i, j;

        if (skip() || !(i = getrq()) || i == 'S' ||  (j = findft(i))  == -1)
                ulfont = ULFONT; /*default underline position*/
        else 
                ulfont = j;
        if (NROFF && ulfont == FT)
                ulfont = ULFONT;
}


void caseit(void)
{
        int i;

        lgf++;
        it = itmac = 0;
        noscale++;
        skip();
        i = atoi0();
        skip();
        if (!nonumb && (itmac = getrq()))
                it = i;
        noscale = 0;
}


void casemc(void)
{
        int i;

        if (icf > 1)
                ic = 0;
        icf = 0;
        if (skip())
                return;
        ic = getch();
        icf = 1;
        skip();
        i = max(hnumb((int *)0), 0);
        if (!nonumb)
                ics = i;
}


void casemk(void)
{
        int i, j;

        if (dip != d)
                j = dip->dnl; 
        else 
                j = numtabp[NL].val;
        if (skip()) {
                dip->mkline = j;
                return;
        }
        if ((i = getrq()) == 0)
                return;
        numtabp[findr(i)].val = j;
}


void casesv(void)
{
        int i;

        skip();
        if ((i = vnumb((int *)0)) < 0)
                return;
        if (nonumb)
                i = 1;
        sv += i;
        caseos();
}


void caseos(void)
{
        int savlss;

        if (sv <= findt1()) {
                savlss = lss;
                lss = sv;
                newline(0);
                lss = savlss;
                sv = 0;
        }
}


void casenm(void)
{
        int i;

        lnmod = nn = 0;
        if (skip())
                return;
        lnmod++;
        noscale++;
        i = inumb(&numtabp[LN].val);
        if (!nonumb)
                numtabp[LN].val = max(i, 0);
        getnm(&ndf, 1);
        getnm(&nms, 0);
        getnm(&ni, 0);
        getnm(&nmwid, 3);       /* really kludgy! */
        noscale = 0;
        nmbits = chbits;
}

/*
 * .nm relies on the fact that illegal args are skipped; don't warn
 * for illegality of these
 */
void getnm(int *p, int min)
{
        int i;
        int savtr = trace;

        eat(' ');
        if (skip())
                return;
        trace = 0;
        i = atoi0();
        if (nonumb)
                return;
        *p = max(i, min);
        trace = savtr;
}


void casenn(void)
{
        noscale++;
        skip();
        nn = max(atoi0(), 1);
        noscale = 0;
}


void caseab(void)
{
        casetm1(1, stderr);
        done3(0);
}


/* nroff terminal handling has been pretty well excised */
/* as part of the merge with troff.  these are ghostly remnants, */
/* called, but doing nothing. restore them at your peril. */


void save_tty(void)                     /*save any tty settings that may be changed*/
{
}


void restore_tty(void)                  /*restore tty settings from beginning*/
{
}


void set_tty(void)
{
}


void echo_off(void)                     /*turn off ECHO for .rd in "-q" mode*/
{
}


void echo_on(void)                      /*restore ECHO after .rd in "-q" mode*/
{
}