/* * 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(<), 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*/ { }