Subversion Repositories planix.SVN

Rev

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

/*
 * n1.c
 *
 *      consume options, initialization, main loop,
 *      input routines, escape function calling
 */

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

#include <setjmp.h>
#include <time.h>

char    *Version        = "March 11, 1994";

#ifndef DWBVERSION
#define DWBVERSION      "???"
#endif

char    *DWBfontdir = FONTDIR;
char    *DWBntermdir = NTERMDIR;
char    *DWBalthyphens = ALTHYPHENS;
char    *DWBhomedir = "";

dwbinit dwbpaths[] = {
        &DWBfontdir, NULL, 0,
        &DWBntermdir, NULL, 0,
        &DWBalthyphens, NULL, 0,
        &DWBhomedir, NULL, 0,
        NULL, nextf, NS,
        NULL, NULL, 0
};

int     TROFF   = 1;    /* assume we started in troff... */

jmp_buf sjbuf;
Offset  ipl[NSO];

static  FILE    *ifile  = stdin;
static  FILE    *ifl[NSO];      /* open input file pointers */
char    cfname[NSO+1][NS] = {  "stdin" };       /* file name stack */
int     cfline[NSO];            /* input line count stack */
char    *progname;              /* program name (troff or nroff) */

int     trace = 0;      /* tracing mode: default off */
int     trace1 = 0;

main(int argc, char *argv[])
{
        char *p;
        int j;
        Tchar i;
        char buf[100];

        buf[0] = '\0';          /* make sure it's empty (silly 3b2) */
        progname = argv[0];
        if ((p = strrchr(progname, '/')) == NULL)
                p = progname;
        else
                p++;
        DWBinit(progname, dwbpaths);
        if (strcmp(p, "nroff") == 0)
                TROFF = 0;
#ifdef UNICODE
        alphabet = 128; /* unicode for plan 9 */
#endif  /*UNICODE*/
        mnspace();
        nnspace();
        mrehash();
        nrehash();
        numtabp[NL].val = -1;

        while (--argc > 0 && (++argv)[0][0] == '-')
                switch (argv[0][1]) {

                case 'N':       /* ought to be used first... */
                        TROFF = 0;
                        break;
                case 'd':
                        fprintf(stderr, "troff/nroff version %s\n", Version);
                        break;
                case 'F':       /* switch font tables from default */
                        if (argv[0][2] != '\0') {
                                strcpy(termtab, &argv[0][2]);
                                strcpy(fontdir, &argv[0][2]);
                        } else {
                                argv++; argc--;
                                strcpy(termtab, argv[0]);
                                strcpy(fontdir, argv[0]);
                        }
                        break;
                case 0:
                        goto start;
                case 'i':
                        stdi++;
                        break;
                case 'n':
                        npn = atoi(&argv[0][2]);
                        break;
                case 'u':       /* set emboldening amount */
                        bdtab[3] = atoi(&argv[0][2]);
                        if (bdtab[3] < 0 || bdtab[3] > 50)
                                bdtab[3] = 0;
                        break;
                case 's':
                        if (!(stop = atoi(&argv[0][2])))
                                stop++;
                        break;
                case 'r':
                        sprintf(buf + strlen(buf), ".nr %c %s\n",
                                argv[0][2], &argv[0][3]);
                        /* not yet cpushback(buf);*/
                        /* dotnr(&argv[0][2], &argv[0][3]); */
                        break;
                case 'm':
                        if (mflg++ >= NMF) {
                                ERROR "Too many macro packages: %s", argv[0] WARN;
                                break;
                        }
                        strcpy(mfiles[nmfi], nextf);
                        strcat(mfiles[nmfi++], &argv[0][2]);
                        break;
                case 'o':
                        getpn(&argv[0][2]);
                        break;
                case 'T':
                        strcpy(devname, &argv[0][2]);
                        dotT++;
                        break;
                case 'a':
                        ascii = 1;
                        break;
                case 'h':
                        hflg++;
                        break;
                case 'e':
                        eqflg++;
                        break;
                case 'q':
                        quiet++;
                        save_tty();
                        break;
                case 'V':
                        fprintf(stdout, "%croff: DWB %s\n", 
                                        TROFF ? 't' : 'n', DWBVERSION);
                        exit(0);
                case 't':
                        if (argv[0][2] != '\0')
                                trace = trace1 = argv[0][2];
                        break;          /* for the sake of compatibility */
                default:
                        ERROR "unknown option %s", argv[0] WARN;
                        done(02);
                }

start:
        /*
         * cpushback maintains a LIFO, so push pack the -r arguments
         * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
         */
        if (buf[0]) {
                char *p = buf;
                while(*p++)
                        ;
                while(p > buf) {
                        while(strncmp(p, ".nr", 3) != 0)
                                p--;
                        cpushback(p);
                        *p-- = '\0';
                }
        }
        argp = argv;
        rargc = argc;
        nmfi = 0;
        init2();
        setjmp(sjbuf);
loop:
        copyf = lgf = nb = nflush = nlflg = 0;
        if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
                nflush++;
                trap = 0;
                eject((Stack *)0);
                goto loop;
        }
        i = getch();
        if (pendt)
                goto Lt;
        if ((j = cbits(i)) == XPAR) {
                copyf++;
                tflg++;
                while (cbits(i) != '\n')
                        pchar(i = getch());
                tflg = 0;
                copyf--;                        /* pointless */
                goto loop;
        }
        if (j == cc || j == c2) {
                if (j == c2)
                        nb++;
                copyf++;
                while ((j = cbits(i = getch())) == ' ' || j == '\t')
                        ;
                ch = i;
                copyf--;
                control(getrq(), 1);
                flushi();
                goto loop;
        }
Lt:
        ch = i;
        text();
        if (nlflg)
                numtabp[HP].val = 0;
        goto loop;
}



void init2(void)
{
        int i;
        char buf[100];

        for (i = NTRTAB; --i; )
                trtab[i] = i;
        trtab[UNPAD] = ' ';
        iflg = 0;
        obufp = obuf;
        if (TROFF)
                t_ptinit();
        else
                n_ptinit();
        mchbits();
        cvtime();
        numtabp[PID].val = getpid();
        numtabp[HP].val = init = 0;
        numtabp[NL].val = -1;
        nfo = 0;
        copyf = raw = 0;
        sprintf(buf, ".ds .T %s\n", devname);
        cpushback(buf);
        sprintf(buf, ".ds .P %s\n", DWBhomedir);
        cpushback(buf);
        numtabp[CD].val = -1;   /* compensation */
        nx = mflg;
        frame = stk = (Stack *)setbrk(STACKSIZE);
        dip = &d[0];
        nxf = frame + 1;
        for (i = 1; i < NEV; i++)       /* propagate the environment */
                envcopy(&env[i], &env[0]);
        for (i = 0; i < NEV; i++) {
                if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
                        ERROR "not enough room for word buffers" WARN;
                        done2(1);
                }
                env[i]._word._size = WDSIZE;
                if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
                        ERROR "not enough room for line buffers" WARN;
                        done2(1);
                }
                env[i]._line._size = LNSIZE;
        }
        if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
                ERROR "not enough room for line buffers" WARN;
                done2(1);
        }
        olinep = oline;
        olnsize = OLNSIZE;
        blockinit();
}

void cvtime(void)
{
        long tt;
        struct tm *ltime;

        time(&tt);
        ltime = localtime(&tt);
        numtabp[YR].val = ltime->tm_year % 100;
        numtabp[YR].fmt = 2;
        numtabp[MO].val = ltime->tm_mon + 1;    /* troff uses 1..12 */
        numtabp[DY].val = ltime->tm_mday;
        numtabp[DW].val = ltime->tm_wday + 1;   /* troff uses 1..7 */
}



char    errbuf[200];

void errprint(void)     /* error message printer */
{
        int savecd = numtabp[CD].val;

        if (!nlflg)
                numtabp[CD].val++;

        fprintf(stderr, "%s: ", progname);
        fputs(errbuf, stderr);
        if (cfname[ifi][0])
                fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
        fputs("\n", stderr);
        if (cfname[ifi][0])
                stackdump();
        numtabp[CD].val = savecd;
}


int control(int a, int b)
{
        int j, k;
        extern Contab *contabp;

        numerr.type = RQERR;
        numerr.req = a;
        if (a == 0 || (j = findmn(a)) == -1)
                return(0);
        if (contabp[j].f == 0) {
                if (trace & TRMAC)
                        fprintf(stderr, "invoke macro %s\n", unpair(a));
                if (dip != d)
                        for (k = dilev; k; k--)
                                if (d[k].curd == a) {
                                        ERROR "diversion %s invokes itself during diversion",
                                                                unpair(a) WARN;
                                        edone(0100);
                                }
                nxf->nargs = 0;
                if (b)
                        collect();
                flushi();
                return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */
        }
        if (b) {
                if (trace & TRREQ)
                        fprintf(stderr, "invoke request %s\n", unpair(a));
                 (*contabp[j].f)();
        }
        return(0);
}

void casept(void)
{
        int i;

        noscale++;
        if (skip())
                i = trace1;
        else {
                i = max(inumb(&trace), 0);
                if (nonumb)
                        i = trace1;
        }
        trace1 = trace;
        trace = i;
        noscale = 0;
}


int getrq(void)
{
        int i, j;

        if ((i = getach()) == 0 || (j = getach()) == 0)
                goto rtn;
        i = PAIR(i, j);
rtn:
        return(i);
}

/*
 * table encodes some special characters, to speed up tests
 * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
 */

char gchtab[NCHARS] = {
        000,004,000,000,010,000,000,000, /* fc, ldr */
        001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
        000,000,000,000,000,000,000,000,
        000,001,000,001,000,000,000,000, /* FLSS, ESC */
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,001,000, /* f */
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
        000,000,000,000,000,000,000,000,
};

int realcbits(Tchar c)  /* return character bits, or MOTCH if motion */
{
        if (ismot(c))
                return MOTCH;
        else
                return c & 0xFFFF;
}

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

g0:
        if (ch) {
                i = ch;
                if (cbits(i) == '\n')
                        nlflg++;
                ch = 0;
                return(i);
        }

        if (nlflg)
                return('\n');
        i = getch0();
        if (ismot(i))
                return(i);
        k = cbits(i);
        if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0)    /* nothing special */
                return(i);
        if (k != ESC) {
                if (k == '\n') {
                        nlflg++;
                        if (ip == 0)
                                numtabp[CD].val++; /* line number */
                        return(k);
                }
                if (k == FLSS) {
                        copyf++; 
                        raw++;
                        i = getch0();
                        if (!fi)
                                flss = i;
                        copyf--; 
                        raw--;
                        goto g0;
                }
                if (k == RPT) {
                        setrpt();
                        goto g0;
                }
                if (!copyf) {
                        if (k == 'f' && lg && !lgf) {
                                i = getlg(i);
                                return(i);
                        }
                        if (k == fc || k == tabch || k == ldrch) {
                                if ((i = setfield(k)) == 0)
                                        goto g0; 
                                else 
                                        return(i);
                        }
                        if (k == '\b') {
                                i = makem(-width(' ' | chbits));
                                return(i);
                        }
                }
                return(i);
        }

        k = cbits(j = getch0());
        if (ismot(j))
                return(j);

        switch (k) {
        case 'n':       /* number register */
                setn();
                goto g0;
        case '$':       /* argument indicator */
                seta();
                goto g0;
        case '*':       /* string indicator */
                setstr();
                goto g0;
        case '{':       /* LEFT */
                i = LEFT;
                goto gx;
        case '}':       /* RIGHT */
                i = RIGHT;
                goto gx;
        case '"':       /* comment */
                while (cbits(i = getch0()) != '\n')
                        ;
                if (ip == 0)
                        numtabp[CD].val++; /* line number */
                nlflg++;
                return(i);

/* experiment: put it here instead of copy mode */
        case '(':       /* special char name \(xx */
        case 'C':       /*              \C'...' */
                if ((i = setch(k)) == 0)
                        goto g0;
                goto gx;

        case ESC:       /* double backslash */
                i = eschar;
                goto gx;
        case 'e':       /* printable version of current eschar */
                i = PRESC;
                goto gx;
        case '\n':      /* concealed newline */
                numtabp[CD].val++;
                goto g0;
        case ' ':       /* unpaddable space */
                i = UNPAD;
                goto gx;
        case '\'':      /* \(aa */
                i = ACUTE;
                goto gx;
        case '`':       /* \(ga */
                i = GRAVE;
                goto gx;
        case '_':       /* \(ul */
                i = UNDERLINE;
                goto gx;
        case '-':       /* current font minus */
                i = MINUS;
                goto gx;
        case '&':       /* filler */
                i = FILLER;
                goto gx;
        case 'c':       /* to be continued */
                i = CONT;
                goto gx;
        case '!':       /* transparent indicator */
                i = XPAR;
                goto gx;
        case 't':       /* tab */
                i = '\t';
                return(i);
        case 'a':       /* leader (SOH) */
/* old:         *pbp++ = LEADER; goto g0; */
                i = LEADER;
                return i;
        case '%':       /* ohc */
                i = OHC;
                return(i);
        case 'g':       /* return format of a number register */
                setaf();        /* should this really be in copy mode??? */
                goto g0;
        case '.':       /* . */
                i = '.';
gx:
                setsfbits(i, sfbits(j));
                return(i);
        }
        if (copyf) {
                *pbp++ = j;
                return(eschar);
        }
        switch (k) {

        case 'f':       /* font indicator */
                setfont(0);
                goto g0;
        case 's':       /* size indicator */
                setps();
                goto g0;
        case 'v':       /* vert mot */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                if (i = vmot()) {
                        return(i);
                }
                goto g0;
        case 'h':       /* horiz mot */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                if (i = hmot())
                        return(i);
                goto g0;
        case '|':       /* narrow space */
                if (NROFF)
                        goto g0;
                return(makem((int)(EM)/6));
        case '^':       /* half narrow space */
                if (NROFF)
                        goto g0;
                return(makem((int)(EM)/12));
        case 'w':       /* width function */
                setwd();
                goto g0;
        case 'p':       /* spread */
                spread++;
                goto g0;
        case 'N':       /* absolute character number */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                if ((i = setabs()) == 0)
                        goto g0;
                return i;
        case 'H':       /* character height */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                return(setht());
        case 'S':       /* slant */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                return(setslant());
        case 'z':       /* zero with char */
                return(setz());
        case 'l':       /* hor line */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                setline();
                goto g0;
        case 'L':       /* vert line */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                setvline();
                goto g0;
        case 'D':       /* drawing function */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                setdraw();
                goto g0;
        case 'X':       /* \X'...' for copy through */
                setxon();
                goto g0;
        case 'b':       /* bracket */
                setbra();
                goto g0;
        case 'o':       /* overstrike */
                setov();
                goto g0;
        case 'k':       /* mark hor place */
                if ((k = findr(getsn())) != -1) {
                        numtabp[k].val = numtabp[HP].val;
                }
                goto g0;
        case '0':       /* number space */
                return(makem(width('0' | chbits)));
        case 'x':       /* extra line space */
                numerr.type = numerr.escarg = 0; numerr.esc = k;
                if (i = xlss())
                        return(i);
                goto g0;
        case 'u':       /* half em up */
        case 'r':       /* full em up */
        case 'd':       /* half em down */
                return(sethl(k));
        default:
                return(j);
        }
        /* NOTREACHED */
}

void setxon(void)       /* \X'...' for copy through */
{
        Tchar xbuf[NC];
        Tchar *i;
        Tchar c;
        int delim, k;

        if (ismot(c = getch()))
                return;
        delim = cbits(c);
        i = xbuf;
        *i++ = XON | chbits;
        while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
                if (k == ' ')
                        setcbits(c, WORDSP);
                *i++ = c | ZBIT;
        }
        *i++ = XOFF | chbits;
        *i = 0;
        pushback(xbuf);
}


char    ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };

Tchar getch0(void)
{
        Tchar i;

again:
        if (pbp > lastpbp)
                i = *--pbp;
        else if (ip) {
                /* i = rbf(); */
                i = rbf0(ip);
                if (i == 0)
                        i = rbf();
                else {
                        ++ip;
                        if (pastend(ip)) {
                                --ip;
                                rbf();
                        }
                }
        } else {
                if (donef || ndone)
                        done(0);
                if (nx || 1) {  /* BUG: was ibufp >= eibuf, so EOF test is wrong */
                        if (nfo < 0)
                                ERROR "in getch0, nfo = %d", nfo WARN;
                        if (nfo == 0) {
g0:
                                if (nextfile()) {
                                        if (ip)
                                                goto again;
                                }
                        }
                        nx = 0;
#ifdef UNICODE
                        if (MB_CUR_MAX > 1)
                                i = get1ch(ifile);
                        else
#endif  /*UNICODE*/
                                i = getc(ifile);
                        if (i == EOF)
                                goto g0;
                        if (ip)
                                goto again;
                }
                if (i >= 040)                   /* zapped: && i < 0177 */
                        goto g4;
                i = ifilt[i];
        }
        if (cbits(i) == IMP && !raw)
                goto again;
        if (i == 0 && !init && !raw) {          /* zapped:  || i == 0177 */
                goto again;
        }
g4:
        if (ismot(i))
                return i;
        if (copyf == 0 && sfbits(i) == 0)
                i |= chbits;
        if (cbits(i) == eschar && !raw)
                setcbits(i, ESC);
        return(i);
}


#ifdef UNICODE
Tchar get1ch(FILE *fp)  /* get one "character" from input, figure out what alphabet */
{
        wchar_t wc;
        char buf[100], *p;
        int i, n, c;

        n = c = 0;
        for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
                if ((c = getc(fp)) == EOF)
                        return c;
                *p++ = c;
                if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
                        break;
        }
        if (n == 1)     /* real ascii, presumably */
                return wc;
        if (n == 0)
                return p[-1];   /* illegal, but what else to do? */
        if (c == EOF)
                return EOF;
        *p = 0;
        return chadd(buf, MBchar, Install);     /* add name even if haven't seen it */
}
#endif  /*UNICODE*/

void pushback(Tchar *b)
{
        Tchar *ob = b;

        while (*b++)
                ;
        b--;
        while (b > ob && pbp < &pbbuf[NC-3])
                *pbp++ = *--b;
        if (pbp >= &pbbuf[NC-3]) {
                ERROR "pushback overflow" WARN;
                done(2);
        }
}

void cpushback(char *b)
{
        char *ob = b;

        while (*b++)
                ;
        b--;
        while (b > ob && pbp < &pbbuf[NC-3])
                *pbp++ = *--b;
        if (pbp >= &pbbuf[NC-3]) {
                ERROR "cpushback overflow" WARN;
                done(2);
        }
}

int nextfile(void)
{
        char *p;

n0:
        if (ifile != stdin)
                fclose(ifile);
        if (ifi > 0 && !nx) {
                if (popf())
                        goto n0; /* popf error */
                return(1);       /* popf ok */
        }
        if (nx || nmfi < mflg) {
                p = mfiles[nmfi++];
                if (*p != 0)
                        goto n1;
        }
        if (rargc-- <= 0) {
                if ((nfo -= mflg) && !stdi) {
                        done(0);
}
                nfo++;
                numtabp[CD].val = stdi = mflg = 0;
                ifile = stdin;
                strcpy(cfname[ifi], "stdin");
                return(0);
        }
        p = (argp++)[0];
        if (rargc >= 0)
                cfname[ifi][0] = 0;
n1:
        numtabp[CD].val = 0;
        if (p[0] == '-' && p[1] == 0) {
                ifile = stdin;
                strcpy(cfname[ifi], "stdin");
        } else if ((ifile = fopen(p, "r")) == NULL) {
                ERROR "cannot open file %s", p WARN;
                nfo -= mflg;
                done(02);
        } else
                strcpy(cfname[ifi],p);
        nfo++;
        return(0);
}


popf(void)
{
        --ifi;
        if (ifi < 0) {
                ERROR "popf went negative" WARN;
                return 1;
        }
        numtabp[CD].val = cfline[ifi];  /* restore line counter */
        ip = ipl[ifi];                  /* input pointer */
        ifile = ifl[ifi];               /* input FILE * */
        return(0);
}


void flushi(void)
{
        if (nflush)
                return;
        ch = 0;
        copyf++;
        while (!nlflg) {
                if (donef && frame == stk)
                        break;
                getch();
        }
        copyf--;
}

/*
 * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
 * (internal names), spaces and special cookies (below 040).
 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
 */
getach(void)
{
        Tchar i;
        int j;

        lgf++;
        j = cbits(i = getch());
        if (ismot(i)
            || j > SHORTMASK
            || (j <= 040 && j != 002    /*STX*/
                        && j != 003     /*ETX*/
                        && j != 005     /*ENQ*/
                        && j != 006     /*ACK*/
                        && j != 007)) { /*BELL*/
                ch = i;
                j = 0;
        }
        lgf--;
        return j;
}


void casenx(void)
{
        lgf++;
        skip();
        getname();
        nx++;
        if (nmfi > 0)
                nmfi--;
        strcpy(mfiles[nmfi], nextf);
        nextfile();
        nlflg++;
        ip = 0;
        pendt = 0;
        frame = stk;
        nxf = frame + 1;
}


getname(void)
{
        int j, k;

        lgf++;
        for (k = 0; k < NS - 1; k++) {
                j = getach();
                if (!j)
                        break;
                nextf[k] = j;
        }
        nextf[k] = 0;
        lgf--;
        return(nextf[0]);
}


void caseso(void)
{
        FILE *fp;

        lgf++;
        nextf[0] = 0;
        fp = NULL;
        if (skip() || !getname() || (fp = fopen(nextf, "r")) == NULL || ifi >= NSO) {
                ERROR "can't open file %s", nextf WARN;
                done(02);
        }
        strcpy(cfname[ifi+1], nextf);
        cfline[ifi] = numtabp[CD].val;          /*hold line counter*/
        numtabp[CD].val = 0;
        flushi();
        ifl[ifi] = ifile;
        ifile = fp;
        ipl[ifi] = ip;
        ip = 0;
        nx++;
        nflush++;
        ifi++;
}

void caself(void)       /* set line number and file */
{
        int n;

        if (skip())
                return;
        n = atoi0();
        if (!nonumb)
                cfline[ifi] = numtabp[CD].val = n - 1;
        if (!skip())
                if (getname()) {        /* eats '\n' ? */
                        strcpy(cfname[ifi], nextf);
                        if (!nonumb)
                                numtabp[CD].val--;
                }
}

void cpout(FILE *fin, char *token)
{
        int n;
        char buf[1024];

        if (token) {    /* BUG: There should be no NULL bytes in input */
                char *newl = buf;
                while ((fgets(buf, sizeof buf, fin)) != NULL) {
                        if (newl) {
                                numtabp[CD].val++; /* line number */
                                if (strcmp(token, buf) == 0)
                                        return;
                        }
                        newl = strchr(buf, '\n');
                        fputs(buf, ptid);
                }
        } else {
                while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
                        fwrite(buf, n, 1, ptid);
                fclose(fin);
        }
}

void casecf(void)
{       /* copy file without change */
        FILE *fd;
        char *eof, *p;
        extern int hpos, esc, po;

        /* this may not make much sense in nroff... */

        lgf++;
        nextf[0] = 0;
        if (!skip() && getname()) {
                if (strncmp("<<", nextf, 2) != 0) {
                        if ((fd = fopen(nextf, "r")) == NULL) {
                                ERROR "can't open file %s", nextf WARN;
                                done(02);
                        }
                        eof = (char *) NULL;
                } else {        /* current file */
                        if (pbp > lastpbp || ip) {
                                ERROR "casecf: not reading from file" WARN;
                                done(02);
                        }
                        eof = &nextf[2];
                        if (!*eof)  {
                                ERROR "casecf: missing end of input token" WARN;
                                done(02);
                        }
                        p = eof;
                        while(*++p)
                                ;
                        *p++ = '\n';
                        *p = 0;
                        fd = ifile;
                }
        } else {
                ERROR "casecf: no argument" WARN;
                lgf--;
                return;
        }
        lgf--;

        /* make it into a clean state, be sure that everything is out */
        tbreak();
        hpos = po;
        esc = 0;
        ptesc();        /* to left margin */
        esc = un;
        ptesc();
        ptlead();
        ptps();
        ptfont();
        flusho();
        cpout(fd, eof);
        ptps();
        ptfont();
}

void getline(char *s, int n)    /* get rest of input line into s */
{
        int i;

        lgf++;
        copyf++;
        skip();
        for (i = 0; i < n-1; i++)
                if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
                        break;
        s[i] = 0;
        copyf--;
        lgf--;
}

void casesy(void)       /* call system */
{
        char sybuf[NTM];

        getline(sybuf, NTM);
        system(sybuf);
}


void getpn(char *a)
{
        int n, neg;

        if (*a == 0)
                return;
        neg = 0;
        for ( ; *a; a++)
                switch (*a) {
                case '+':
                case ',':
                        continue;
                case '-':
                        neg = 1;
                        continue;
                default:
                        n = 0;
                        if (isdigit(*a)) {
                                do
                                        n = 10 * n + *a++ - '0';
                                while (isdigit(*a));
                                a--;
                        } else
                                n = 9999;
                        *pnp++ = neg ? -n : n;
                        neg = 0;
                        if (pnp >= &pnlist[NPN-2]) {
                                ERROR "too many page numbers" WARN;
                                done3(-3);
                        }
                }
        if (neg)
                *pnp++ = -9999;
        *pnp = -INT_MAX;
        print = 0;
        pnp = pnlist;
        if (*pnp != -INT_MAX)
                chkpn();
}


void setrpt(void)
{
        Tchar i, j;

        copyf++;
        raw++;
        i = getch0();
        copyf--;
        raw--;
        if ((long) i < 0 || cbits(j = getch0()) == RPT)
                return;
        while (i > 0 && pbp < &pbbuf[NC-3]) {
                i--;
                *pbp++ = j;
        }
}