1131 lines
20 KiB
C
1131 lines
20 KiB
C
/*
|
|
* 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--;
|
|
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)
|
|
{
|
|
int j;
|
|
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;
|
|
}
|
|
g2:
|
|
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;
|
|
|
|
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;
|
|
Tchar i;
|
|
|
|
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;
|
|
char *p, *q;
|
|
|
|
lgf++;
|
|
nextf[0] = 0;
|
|
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;
|
|
}
|
|
}
|