| /* |
| * 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++; |
| } |
| |
| int |
| 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; |
| } |
| |
| int |
| 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(<), 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; |
| } |
| |
| int |
| 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(unsharp(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; |
| i = 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: |
| strcpy(&tmbuf[i], p+1); |
| break; |
| case Number: |
| sprintf(&tmbuf[i], "\\N'%s'", p+1); |
| break; |
| case Troffchar: |
| if ((j = 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++; |
| } |
| } |
| |
| int |
| 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')); |
| } |
| |
| int |
| 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*/ |
| { |
| } |