summaryrefslogtreecommitdiff
path: root/troff/n1.c
diff options
context:
space:
mode:
Diffstat (limited to 'troff/n1.c')
-rw-r--r--troff/n1.c2602
1 files changed, 2602 insertions, 0 deletions
diff --git a/troff/n1.c b/troff/n1.c
new file mode 100644
index 0000000000000..e56735fc94ff5
--- /dev/null
+++ b/troff/n1.c
@@ -0,0 +1,2602 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "n1.c 1.25 05/06/08 SMI" */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)n1.c 1.144 (gritter) 8/19/08
+ */
+
+/*
+ * Changes Copyright (c) 2014 Carsten Kunze <carsten.kunze at arcor.de>
+ */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+char *xxxvers = "@(#)roff:n1.c 2.13";
+/*
+ * n1.c
+ *
+ * consume options, initialization, main loop,
+ * input routines, escape function calling
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <setjmp.h>
+#include <time.h>
+#include <stdarg.h>
+#include <locale.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#ifdef EUC
+#include <stddef.h>
+#include <limits.h>
+#include <wchar.h>
+#include <wctype.h>
+#endif /* EUC */
+
+#include "tdef.h"
+#include "ext.h"
+
+#ifdef NROFF
+#include "tw.h"
+#include "draw.h"
+#endif
+#include "pt.h"
+
+#define MAX_RECURSION_DEPTH 512
+static int max_recursion_depth = MAX_RECURSION_DEPTH;
+static int max_tail_depth;
+
+jmp_buf sjbuf;
+filep ipl[NSO];
+long offl[NSO];
+long ioff;
+char *ttyp;
+char *cfname[NSO+1]; /*file name stack*/
+int cfline[NSO]; /*input line count stack*/
+static int cfpid[NSO+1]; /* .pso process IDs */
+char *progname; /* program name (troff) */
+#ifdef EUC
+char mbbuf1[MB_LEN_MAX + 1];
+char *mbbuf1p = mbbuf1;
+wchar_t twc = 0;
+#endif /* EUC */
+static unsigned char escoff[126-31];
+
+static void initg(void);
+static void printlong(long, int);
+static void printn(long, long);
+static char *sprintlong(char *s, long, int);
+static char *sprintn(char *s, long n, int b);
+#ifndef NROFF
+#define vfdprintf xxvfdprintf
+static void vfdprintf(int fd, const char *fmt, va_list ap);
+#endif
+static tchar setyon(void);
+static void _setenv(void);
+static tchar setZ(void);
+static int setgA(void);
+static int setB(void);
+static void _caseesc(int);
+
+#ifdef DEBUG
+int debug = 0; /*debug flag*/
+#endif /* DEBUG */
+
+static int _xflag;
+int bol;
+int noschr;
+int prdblesc;
+
+int
+main(int argc, char **argv)
+{
+ register char *p;
+ register int j;
+ char **oargv;
+ char *s;
+ size_t l;
+
+ setlocale(LC_CTYPE, "");
+ mb_cur_max = MB_CUR_MAX;
+ progname = argv[0];
+ nextf = calloc(1, NS = 1);
+ d = calloc(NDI = 5, sizeof *d);
+ growblist();
+ growcontab();
+ grownumtab();
+ growpbbuf();
+ morechars(1);
+ initg();
+ for (j = 0; j <= NSO; j++)
+ cfpid[j] = -1;
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, catch);
+ if (signal(SIGINT, catch) == SIG_IGN) {
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ }
+ signal(SIGPIPE, catch);
+ signal(SIGTERM, kcatch);
+ oargv = argv;
+ s = "<standard input>";
+ l = strlen(s) + 1;
+ cfname[0] = malloc(l);
+ n_strcpy(cfname[0], s, l);
+ init0();
+#ifdef EUC
+ localize();
+#endif /* EUC */
+ if ((p = getenv("TYPESETTER")) != 0)
+ n_strcpy(devname, p, sizeof(devname));
+ while (--argc > 0 && (++argv)[0][0] == '-')
+ switch (argv[0][1]) {
+
+ case 'F': /* switch font tables from default */
+ if (argv[0][2] != '\0') {
+ termtab = &argv[0][2];
+ fontfile = &argv[0][2];
+ } else {
+ argv++; argc--;
+ if (argv[0] != '\0') {
+ termtab = argv[0];
+ fontfile = argv[0];
+ } else
+ errprint("missing the font directory");
+ }
+ continue;
+ case 0:
+ goto start;
+ case 'i':
+ stdi++;
+ continue;
+ case 'q':
+#ifdef NROFF
+ quiet++;
+ save_tty();
+#else
+ errprint("-q option ignored in troff");
+#endif /* NROFF */
+ continue;
+ case 'n':
+ npn = ctoi(&argv[0][2]);
+ continue;
+ case 'u': /* set emboldening amount */
+ initbdtab[3] = ctoi(&argv[0][2]);
+ if (initbdtab[3] < 0 || initbdtab[3] > 50)
+ initbdtab[3] = 0;
+ continue;
+ case 's':
+ if (!(stop = ctoi(&argv[0][2])))
+ stop++;
+ continue;
+ case 't':
+ ptid = 1;
+ continue;
+ case 'r':
+ case 'd':
+ if (&argv[0][2] != '\0' && strlen(&argv[0][2]) >= 2 && &argv[0][3] != '\0') {
+ if ((p = strchr(&argv[0][3], '=')) != NULL) {
+ *p = 0;
+ l = strlen(ibuf);
+ eibuf = roff_sprintf(ibuf + l, sizeof(ibuf) - l,
+ ".do %s %s %s%s\n",
+ argv[0][1] == 'd' ? "ds" : "nr",
+ &argv[0][2],
+ argv[0][1] == 'd' ? "\"" : "",
+ &p[1]);
+ *p = '=';
+ } else {
+ l = strlen(ibuf);
+ eibuf = roff_sprintf(ibuf + l, sizeof(ibuf) - l,
+ ".%s %c %s%s\n",
+ argv[0][1] == 'd' ? "ds" : "nr",
+ argv[0][2],
+ argv[0][1] == 'd' ? "\"" : "",
+ &argv[0][3]);
+ }
+ } else
+ errprint("wrong options");
+ continue;
+ case 'c':
+ case 'm':
+ if (mflg++ >= NMF && (mfiles = realloc(mfiles,
+ ++NMF * sizeof *mfiles)) == 0) {
+ errprint("Too many macro packages: %s",
+ argv[0]);
+ continue;
+ }
+ if (argv[0][2] == '\0') {
+ errprint("No library provided with -m");
+ done(02);
+ }
+ if (getenv("TROFFMACS") != '\0') {
+ if (tryfile(getenv("TROFFMACS"), &argv[0][2], nmfi))
+ nmfi++;
+ } else
+ if (tryfile(MACDIR "/", &argv[0][2], nmfi)
+ || tryfile(MACDIR "/tmac.", &argv[0][2], nmfi))
+ nmfi++;
+ else {
+ errprint("Cannot find library %s\n", argv[0]);
+ done(02);
+ }
+ continue;
+ case 'o':
+ getpn(&argv[0][2]);
+ continue;
+ case 'T':
+ n_strcpy(devname, &argv[0][2], sizeof(devname));
+ dotT++;
+ continue;
+ case 'x':
+ if (argv[0][2])
+ xflag = strtol(&argv[0][2], NULL, 10);
+ else
+ xflag = 2;
+ continue;
+ case 'X':
+ xflag = 0;
+ continue;
+#ifdef NROFF
+ case 'h':
+ hflg++;
+ continue;
+ case 'z':
+ no_out++;
+ continue;
+ case 'e':
+ eqflg++;
+ continue;
+#endif
+#ifndef NROFF
+ case 'z':
+ no_out++;
+ case 'a':
+ ascii = 1;
+ nofeed++;
+ continue;
+ case 'f':
+ nofeed++;
+ continue;
+#endif
+ case '#':
+#ifdef DEBUG
+ debug = ctoi(&argv[0][2]);
+#else
+ errprint("DEBUG not enabled");
+#endif /* DEBUG */
+ continue;
+ case 'V':
+ fprintf(stdout, "Heirloom doctools %croff, " RELEASE
+ "\n",
+#ifdef NROFF
+ 'n'
+#else
+ 't'
+#endif
+ );
+ exit(0);
+ default:
+ errprint("unknown option %s", argv[0]);
+ done(02);
+ }
+
+start:
+ init1(oargv[0][0]);
+ argp = argv;
+ rargc = argc;
+ nmfi = 0;
+ init2();
+ mainloop();
+ /*NOTREACHED*/
+ return(0);
+}
+
+void
+mainloop(void)
+{
+ register int j;
+ register tchar i;
+ int eileenct; /*count to test for "Eileen's loop"*/
+#ifdef NROFF
+ int ndo = 0;
+#endif
+
+ _xflag = xflag;
+ setjmp(sjbuf);
+ eileenct = 0; /*reset count for "Eileen's loop"*/
+loop:
+#ifdef NROFF
+ if (ndo) {
+ ndo = 0;
+ npic(0);
+ }
+#endif
+ xflag = _xflag;
+ defcf = charf = clonef = copyf = lgf = nb = nflush = nlflg = 0;
+ if (ip && rbf0(ip) == 0 && dip == d && ejf &&
+ frame->pframe->tail_cnt <= ejl) {
+ nflush++;
+ trap = 0;
+ eject((struct s *)0);
+#ifdef DEBUG
+ if (debug & DB_LOOP)
+ fprintf(stderr, "loop: NL=%d, ejf=%d, lss=%d, "
+ "eileenct=%d\n", numtab[NL].val, ejf, lss,
+ eileenct);
+#endif /* DEBUG */
+ if (eileenct > 20) {
+ errprint("job looping; check abuse of macros");
+ ejf = 0; /*try to break Eileen's loop*/
+ eileenct = 0;
+ } else
+ eileenct++;
+ goto loop;
+ }
+ eileenct = 0; /*reset count for "Eileen's loop"*/
+ bol = 1;
+ i = getch();
+ bol = 0;
+ if (!i) /* CK: Bugfix: .bp followed by .. */
+ goto loop;
+ 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 || isxfunc(i, CC)) {
+ if (gflag && isdi(i))
+ goto Lt;
+ if (j == c2)
+ nb++;
+ copyf++;
+ while ((j = cbits(i = getch())) == ' ' || j == '\t')
+ ;
+ ch = i;
+ copyf--;
+ j = getrq(4);
+#ifdef NROFF
+ if (j == PAIR('P', 'S')) npic(1);
+ else if (ndraw && j == PAIR('d', 'o')) ndo = 1;
+ else
+#endif
+ if (xflag != 0 && j == PAIR('d', 'o')) {
+ xflag = 3;
+ skip(1);
+ j = getrq(4);
+ }
+ noschr = 1;
+ control(j, 1);
+ noschr = 0;
+ flushi();
+ goto loop;
+ }
+Lt:
+ ch = i;
+ text();
+ if (nlflg)
+ numtab[HP].val = 0;
+ goto loop;
+}
+
+
+int
+tryfile(register char *pat, register char *fn, int idx)
+{
+ size_t l = strlen(pat) + strlen(fn) + 1;
+ mfiles[idx] = malloc(l);
+ n_strcpy(mfiles[idx], pat, l);
+ n_strcat(mfiles[idx], fn, l);
+ if (access(mfiles[idx], 4) == -1)
+ return(0);
+ else return(1);
+}
+
+void catch(int unused)
+{
+ done3(01);
+}
+
+
+void kcatch(int unused)
+{
+ signal(SIGTERM, SIG_IGN);
+ done3(01);
+}
+
+
+void
+init0(void)
+{
+ eibuf = ibufp = ibuf;
+ ibuf[0] = 0;
+ numtab[NL].val = -1;
+}
+
+
+void
+init1(char a)
+{
+ register int i;
+
+ for (i = NTRTAB; --i; )
+ trnttab[i] = trtab[i] = i;
+ trnttab[UNPAD] = trtab[UNPAD] = ' ';
+ trnttab[STRETCH] = trtab[STRETCH] = ' ';
+}
+
+
+void
+init2(void)
+{
+ register int i, j;
+ size_t l;
+
+ ttyod = 2;
+ if ((ttyp=ttyname(j=0)) != 0 || (ttyp=ttyname(j=1)) != 0 || (ttyp=ttyname(j=2)) != 0)
+ ;
+ else
+ ttyp = "notty";
+ iflg = j;
+ if (ascii)
+ mesg(0);
+ obufp = obuf;
+ ptinit();
+ mchbits();
+ cvtime();
+ setnr(".g", gflag, 0);
+ numtab[PID].val = getpid();
+ spreadlimit = 3*EM;
+ olinesz = LNSIZE;
+ oline = malloc(olinesz * sizeof *oline);
+ olinep = oline;
+ ioff = 0;
+ numtab[HP].val = init = 0;
+ numtab[NL].val = -1;
+ nfo = 0;
+ ifile = 0;
+ copyf = raw = 0;
+ l = strlen(ibuf);
+ eibuf = roff_sprintf(ibuf + l, sizeof(ibuf) - l, ".ds .T %s\n",
+ devname);
+ numtab[CD].val = -1; /* compensation */
+ cpushback(ibuf);
+ ibufp = ibuf;
+ nx = mflg;
+ frame = stk = calloc(1, sizeof *stk);
+ stk->frame_cnt = 0;
+ dip = &d[0];
+ nxf = calloc(1, sizeof *nxf);
+ initenv = env;
+ for (i = 0; i < NEV; i++) {
+ extern tchar *corebuf;
+ ((struct env *)corebuf)[i] = env;
+ }
+}
+
+
+void
+cvtime(void)
+{
+ time_t tt;
+ register struct tm *tm;
+
+ tt = time((time_t *) 0);
+ tm = localtime(&tt);
+ numtab[DY].val = tm->tm_mday;
+ numtab[DW].val = tm->tm_wday + 1;
+ numtab[YR].val = tm->tm_year;
+ numtab[MO].val = tm->tm_mon + 1;
+ setnr("hours", tm->tm_hour, 0);
+ setnr("minutes", tm->tm_min, 0);
+ setnr("seconds", tm->tm_sec, 0);
+ setnr("year", tm->tm_year + 1900, 0);
+
+}
+
+
+int
+ctoi(register char *s)
+{
+ register int n;
+
+ while (*s == ' ')
+ s++;
+ n = 0;
+ while (isdigit((unsigned char)*s))
+ n = 10 * n + *s++ - '0';
+ return n;
+}
+
+
+void
+mesg(int f)
+{
+ static int mode;
+ struct stat stbuf;
+
+ if (!f) {
+ stat(ttyp, &stbuf);
+ mode = stbuf.st_mode;
+ chmod(ttyp, mode & ~0122); /* turn off writing for others */
+ } else {
+ if (ttyp && *ttyp && mode)
+ chmod(ttyp, mode);
+ }
+}
+
+void
+verrprint(const char *s, va_list ap)
+{
+ fprintf(stderr, "%s: ", progname);
+ vfprintf(stderr, s, ap);
+ if (numtab[CD].val > 0)
+ fprintf(stderr, "; line %d, file %s",
+ numtab[CD].val + (nlflg == 0 && frame == stk),
+ cfname[ifi] ? cfname[ifi] : "");
+ if (xflag && realpage)
+ fprintf(stderr, "; page %ld", realpage);
+ fprintf(stderr, "\n");
+ stackdump();
+#ifdef DEBUG
+ if (debug & DB_ABRT)
+ abort();
+#endif /* DEBUG */
+}
+
+void
+errprint(const char *s, ...) /* error message printer */
+{
+ va_list ap;
+
+ va_start(ap, s);
+ verrprint(s, ap);
+ va_end(ap);
+}
+
+
+#ifndef NROFF
+/*
+ * Scaled down version of C Library printf.
+ * Only %s %u %d (==%u) %o %c %x %D are recognized.
+ */
+#undef putchar
+#define putchar(n) (*pfbp++ = (n)) /* NO CHECKING! */
+
+static char pfbuf[NTM];
+static char *pfbp = pfbuf;
+
+void
+fdprintf(int fd, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfdprintf(fd, fmt, ap);
+ va_end(ap);
+}
+
+static void
+vfdprintf(int fd, const char *fmt, va_list ap)
+{
+ register int c;
+ char *s;
+ register int i;
+
+ pfbp = pfbuf;
+loop:
+ while ((c = *fmt++) != '%') {
+ if (c == '\0') {
+ if (fd == 2)
+ write(STDERR_FILENO, pfbuf, pfbp - pfbuf);
+ else {
+ *pfbp = 0;
+ pfbp = pfbuf;
+ while (*pfbp) {
+ *obufp++ = *pfbp++;
+ if (obufp >= &obuf[OBUFSZ])
+ flusho();
+ }
+ }
+ return;
+ }
+ putchar(c);
+ }
+ c = *fmt++;
+ if (c == 'd' || c == 'u' || c == 'o' || c == 'x') {
+ i = va_arg(ap, int);
+ printlong(i, c);
+ } else if (c == 'c') {
+ if (c > 0177 || c < 040)
+ putchar('\\');
+ putchar(va_arg(ap, int) & 0177);
+ } else if (c == 's') {
+ s = va_arg(ap, char *);
+ while ((c = *s++))
+ putchar(c);
+ } else if (c == 'D') {
+ printn(va_arg(ap, long), 10);
+ } else if (c == 'O') {
+ printn(va_arg(ap, long), 8);
+ } else if (c == 'e' || c == 'E' ||
+ c == 'f' || c == 'F' ||
+ c == 'g' || c == 'G') {
+ char tmp[40];
+ char fmt[] = "%%";
+ fmt[1] = c;
+ snprintf(s = tmp, sizeof(tmp), fmt, va_arg(ap, double));
+ while ((c = *s++))
+ putchar(c);
+ } else if (c == 'p') {
+ i = (intptr_t)va_arg(ap, void *);
+ putchar('0');
+ putchar('x');
+ printlong(i, 'x');
+ } else if (c == 'l') {
+ c = *fmt++;
+ if (c == 'd' || c == 'u' || c == 'o' || c == 'x') {
+ i = va_arg(ap, long);
+ printlong(i, c);
+ } else if (c == 'c') {
+ i = va_arg(ap, int);
+ if (c & ~0177) {
+#ifdef EUC
+ char mb[MB_LEN_MAX];
+ int j, n;
+ n = wctomb(mb, i);
+ for (j = 0; j < n; j++)
+ putchar(mb[j]&0377);
+#endif /* EUC */
+ } else
+ putchar(i);
+ }
+ } else if (c == 'C') {
+ extern int nchtab;
+ tchar t = va_arg(ap, tchar);
+ if ((i = cbits(t)) < 0177) {
+ putchar(i);
+ } else if (i < 128 + nchtab) {
+ putchar('\\');
+ putchar('(');
+ putchar(chname[chtab[i-128]]);
+ putchar(chname[chtab[i-128]+1]);
+ }
+ else if ((i = tr2un(i, fbits(t))) != -1)
+ goto U;
+ } else if (c == 'U') {
+ i = va_arg(ap, int);
+ U:
+ putchar('U');
+ putchar('+');
+ if (i < 0x1000)
+ putchar('0');
+ if (i < 0x100)
+ putchar('0');
+ if (i < 0x10)
+ putchar('0');
+ printn((long)i, 16);
+#ifdef EUC
+ if (iswprint(i)) {
+ char mb[MB_LEN_MAX];
+ int j, n;
+ n = wctomb(mb, i);
+ putchar(' ');
+ putchar('(');
+ for (j = 0; j < n; j++)
+ putchar(mb[j]&0377);
+ putchar(')');
+ }
+#endif /* EUC */
+ }
+ goto loop;
+}
+#endif /* !NROFF */
+
+
+static void
+printlong(long i, int fmt)
+{
+ switch (fmt) {
+ case 'd':
+ if (i < 0) {
+ putchar('-');
+ i = -i;
+ }
+ /*FALLTHRU*/
+ case 'u':
+ printn(i, 10);
+ break;
+ case 'o':
+ printn(i, 8);
+ break;
+ case 'x':
+ printn(i, 16);
+ break;
+ }
+}
+
+/*
+ * Print an unsigned integer in base b.
+ */
+static void printn(register long n, register long b)
+{
+ register long a;
+
+ if (n < 0) { /* shouldn't happen */
+ putchar('-');
+ n = -n;
+ }
+ if ((a = n / b))
+ printn(a, b);
+ putchar("0123456789ABCDEF"[(int)(n%b)]);
+}
+
+/* scaled down version of library roff_sprintf */
+/* same limits as fdprintf */
+/* returns pointer to \0 that ends the string */
+
+/* VARARGS2 */
+char *roff_sprintf(char *str, size_t size, char *fmt, ...)
+{
+ register int c;
+ char *s;
+ long i;
+ va_list ap;
+ char *buf = str;
+
+ va_start(ap, fmt);
+loop:
+ while ((c = *fmt++) != '%') {
+ if (c == '\0') {
+ *str = 0;
+ va_end(ap);
+ return str;
+ }
+ *str++ = c;
+ }
+ c = *fmt++;
+ if (c == 'd' || c == 'u' || c == 'o' || c == 'x') {
+ i = va_arg(ap, int);
+ str = sprintlong(str, i, c);
+ } else if (c == 'c') {
+ if (c > 0177 || c < 040)
+ *str++ = '\\';
+ *str++ = va_arg(ap, int) & 0177;
+ } else if (c == 's') {
+ s = va_arg(ap, char *);
+ while ((c = *s++))
+ *str++ = c;
+ } else if (c == 'D') {
+ str = sprintn(str, va_arg(ap, long), 10);
+ } else if (c == 'O') {
+ str = sprintn(str, va_arg(ap, unsigned) , 8);
+ } else if (c == 'e' || c == 'E' ||
+ c == 'f' || c == 'F' ||
+ c == 'g' || c == 'G') {
+ char fmt[] = "%%";
+ fmt[1] = c;
+ str += snprintf(str, size - (str - buf), fmt, va_arg(ap,
+ double));
+ } else if (c == 'p') {
+ i = (intptr_t)va_arg(ap, void *);
+ *str++ = '0';
+ *str++ = 'x';
+ str = sprintlong(str, i, 'x');
+ } else if (c == 'l') {
+ c = *fmt++;
+ if (c == 'd' || c == 'u' || c == 'o' || c == 'x') {
+ i = va_arg(ap, long);
+ printlong(i, c);
+ } else if (c == 'c') {
+ i = va_arg(ap, int);
+ if (i & ~0177) {
+#ifdef EUC
+ int n;
+ n = wctomb(str, i);
+ if (n > 0)
+ str += n;
+#endif /* EUC */
+ } else
+ *str++ = i;
+ }
+ }
+ goto loop;
+}
+
+static char *
+sprintlong(char *s, long i, int fmt)
+{
+ switch (fmt) {
+ case 'd':
+ if (i < 0) {
+ *s++ = '-';
+ i = -i;
+ }
+ /*FALLTHRU*/
+ case 'u':
+ s = sprintn(s, i, 10);
+ break;
+ case 'o':
+ s = sprintn(s, i, 8);
+ break;
+ case 'x':
+ s = sprintn(s, i, 16);
+ break;
+ }
+ return s;
+}
+
+/*
+ * Print an unsigned integer in base b.
+ */
+static char *sprintn(register char *s, register long n, int b)
+{
+ register long a;
+
+ if (n < 0) { /* shouldn't happen */
+ *s++ = '-';
+ n = -n;
+ }
+ if ((a = n / b))
+ s = sprintn(s, a, b);
+ *s++ = "0123456789ABCDEF"[(int)(n%b)];
+ return s;
+}
+
+
+int
+control(register int a, register int b)
+{
+ struct contab *contp;
+ int newip;
+ struct s *p;
+
+ if (a == 0 || (contp = findmx(a)) == NULL) {
+ nosuch(a);
+ return(0);
+ }
+
+ /*
+ * Attempt to find endless recursion at runtime. Arbitrary
+ * recursion limit of MAX_RECURSION_DEPTH was chosen as
+ * it is extremely unlikely that a correct nroff/troff
+ * invocation would exceed this value.
+ *
+ * The depth of tail-recursive macro calls is not limited
+ * by default.
+ */
+
+ if (max_recursion_depth > 0 && frame->frame_cnt > max_recursion_depth) {
+ errprint(
+ "Exceeded maximum stack size (%d) when "
+ "executing macro %s. Stack dump follows",
+ max_recursion_depth, macname(frame->mname));
+ edone(02);
+ }
+ if (max_tail_depth > 0 && frame->tail_cnt > max_tail_depth) {
+ errprint(
+ "Exceeded maximum recursion depth (%d) when "
+ "executing macro %s. Stack dump follows",
+ max_tail_depth, macname(frame->mname));
+ edone(02);
+ }
+
+ lastrq = a;
+
+#ifdef DEBUG
+ if (debug & DB_MAC)
+ fprintf(stderr, "control: macro %s, contab[%d]\n",
+ macname(a), contp - contab);
+#endif /* DEBUG */
+ if (contp->f == 0) {
+ nxf->nargs = 0;
+ tailflg = 0;
+ if (b)
+ collect();
+ flushi();
+ newip = pushi((filep)contp->mx, a, contp->flags);
+ p = frame->pframe;
+ if (tailflg && b && p != stk &&
+ p->ppendt == 0 &&
+ p->pch == 0 &&
+ p->pip == frame->pip &&
+ p->lastpbp == frame->lastpbp) {
+ frame->pframe = p->pframe;
+ frame->frame_cnt--;
+ sfree(p);
+ *p = *frame;
+ free(frame);
+ frame = p;
+ }
+ contp->flags |= FLAG_USED;
+ frame->contp = contp;
+ tailflg = 0;
+ return newip;
+ } else if (b) {
+ (*contp->f)(0);
+ return 0;
+ } else
+ return(0);
+}
+
+
+int
+rgetach(void)
+{
+ extern const char nmctab[];
+ int i;
+
+ if ((i = getach()) == 0 || (xflag && i < ' ' && nmctab[i]))
+ return(0);
+ return(i);
+}
+
+int
+getrq2(void)
+{
+ register int i, j;
+
+ if (((i = rgetach()) == 0) || ((j = rgetach()) == 0))
+ goto rtn;
+ i = PAIR(i, j);
+rtn:
+ return(i);
+}
+
+int
+getrq(int flags)
+{
+ int i;
+
+ if ((i = getrq2()) >= 256)
+ i = maybemore(i, flags);
+ return(i);
+}
+
+/*
+ * table encodes some special characters, to speed up tests
+ * in getchar, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
+ */
+
+static char
+_gchtab[] = {
+ 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,000,000,000,000,000, /* FLSS */
+ 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,
+};
+
+static void
+initg(void)
+{
+ memcpy(gchtab, _gchtab, sizeof _gchtab);
+}
+
+tchar
+getch(void)
+{
+ register int k;
+ register tchar i, j;
+ struct numtab *np;
+
+g0:
+ if ((i = ch)) {
+ if (cbits(i) == '\n') {
+ nlflg++;
+ tailflg = istail(i);
+ }
+ ch = 0;
+ return(i);
+ }
+
+ if (nlflg)
+ return('\n');
+ i = getch0();
+ if (ismot(i))
+ return(i);
+ k = cbits(i);
+ if (k != ESC) {
+ if (k >= NCHARS || gchtab[k]==0)
+ return(i);
+ if (k == '\n') {
+ nl:
+ if (cbits(i) == '\n') {
+ nlflg++;
+ tailflg = istail(i);
+ }
+ 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 (gchtab[k]&LGBIT && !isdi(i) && lg && !lgf) {
+ k = cbits(i = getlg(i));
+ goto chartest;
+ }
+ 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);
+ }
+chartest:
+ if (
+#ifndef NROFF
+ (!html || k < NCHARS) &&
+#endif
+ !lgf && !charf && chartab[trtab[k]] != NULL &&
+ !noschr && (!argdelim || k != argdelim) &&
+ !(bol && (k == cc || k == c2)))
+ i = setchar(i);
+ return(i);
+ }
+ return(i);
+ }
+ge:
+ k = cbits(j = getch0());
+ if (ismot(j))
+ return(j);
+ if (k >= 32 && k <= 126 && escoff[k-32]) {
+ if (clonef || copyf || tryglf) {
+ pbbuf[pbp++] = j;
+ return eschar;
+ }
+ return j;
+ }
+ switch (k) {
+
+ case '\n': /* concealed newline */
+ if (fmtchar)
+ goto nl;
+ goto g0;
+ case '{': /* LEFT */
+ i = LEFT;
+ goto gx;
+ case '}': /* RIGHT */
+ i = RIGHT;
+ goto gx;
+ case '#': /* comment including newline */
+ if (xflag == 0)
+ break;
+ /*FALLTHRU*/
+ case '"': /* comment */
+ while (cbits(i = getch0()) != '\n')
+ ;
+ if (k == '#')
+ goto g0;
+ nlflg++;
+ tailflg = istail(i);
+ return(i);
+ case 'e': /* printable version of current eschar */
+ i = PRESC;
+ goto gx;
+ case ' ': /* unpaddable space */
+ i = UNPAD;
+ goto gx;
+ case '~': /* stretchable but unbreakable space */
+ if (xflag == 0)
+ break;
+ i = STRETCH;
+ 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 ')': /* transparent filler */
+ if (xflag == 0)
+ break;
+ i = FILLER|TRANBIT;
+ 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) */
+ i = LEADER;
+ return(i);
+ case '%': /* ohc */
+ i = OHC;
+ return(i);
+ case ':': /* optional line break but no hyphenation */
+ if (xflag == 0)
+ break;
+ i = OHC | BLBIT;
+ return(i);
+ }
+ if (clonef) {
+ pbbuf[pbp++] = j;
+ return(eschar);
+ }
+ switch (k) {
+
+ case 'n': /* number register */
+ setn();
+ goto g0;
+ case '*': /* string indicator */
+ setstr();
+ goto g0;
+ case '$': /* argument indicator */
+ seta();
+ goto g0;
+ case ESC: /* double backslash */
+ if (prdblesc || dilev)
+ i = PRESC;
+ else
+ i = eschar;
+ goto gx;
+ case 'g': /* return format of a number register */
+ setaf();
+ goto g0;
+ case 'P': /* output line trap */
+ if (xflag == 0)
+ break;
+ i = setolt();
+ return(i);
+ case 'V': /* environment variable */
+ if (xflag == 0)
+ break;
+ _setenv();
+ goto g0;
+ case '.': /* . */
+ i = '.';
+gx:
+ setsfbits(i, sfbits(j));
+ return(i);
+ }
+ if (copyf) {
+copy:
+ pbbuf[pbp++] = j;
+ return(eschar);
+ }
+ switch (k) {
+
+ case '[':
+ if (defcf)
+ goto copy;
+ if (xflag == 0)
+ goto dfl;
+ /*FALLTHRU*/
+ case 'C':
+ case '(': /* special char name */
+ if (defcf)
+ goto copy;
+ if ((i = setch(k)) == 0 && !tryglf)
+ goto g0;
+ k = cbits(i);
+ goto chartest;
+ case 'U': /* Unicode character */
+ if (xflag == 0)
+ goto dfl;
+ if ((i = setuc()) == 0 && !tryglf)
+ goto g0;
+ return(i);
+ case 'N': /* absolute character number */
+ i = setabs();
+ goto gx;
+ case 'E': /* eschar out of copy mode */
+ if (xflag == 0)
+ goto dfl;
+ goto ge;
+ }
+ if (tryglf) {
+ pbbuf[pbp++] = j;
+ return(eschar);
+ }
+ switch (k) {
+
+ case 'X': /* \X'...' for copy through */
+ setxon();
+ goto g0;
+ case 'Y': /* \Y(xx for indirect copy through */
+ if (xflag == 0)
+ goto dfl;
+ i = setyon();
+ return(i);
+ case 'p': /* spread */
+ spread = 1;
+ goto g0;
+ case 's': /* size indicator */
+ setps();
+ goto g0;
+ case 'H': /* character height */
+ return(setht());
+ case 'S': /* slant */
+ return(setslant());
+ case 'f': /* font indicator */
+ setfont(0);
+ goto g0;
+ case 'w': /* width function */
+ setwd();
+ goto g0;
+ case 'v': /* vert mot */
+ if ((i = vmot()))
+ return(i);
+ goto g0;
+ case 'h': /* horiz mot */
+ if ((i = hmot()))
+ return(i);
+ goto g0;
+ case 'z': /* zero with char */
+ return(setz());
+ case 'l': /* hor line */
+ setline();
+ goto g0;
+ case 'L': /* vert line */
+ setvline();
+ goto g0;
+ case 'D': /* drawing function */
+ setdraw();
+ goto g0;
+ case 'b': /* bracket */
+ setbra();
+ goto g0;
+ case 'o': /* overstrike */
+ setov();
+ goto g0;
+ case 'k': /* mark hor place */
+ if ((np = findr(getsn(1))) != NULL) {
+ np->val = numtab[HP].val;
+ prwatchn(np);
+ }
+ goto g0;
+ case '0': /* number space */
+ return(makem(width('0' | chbits)));
+#ifdef NROFF
+ case '/':
+ case ',':
+ if (!(gflag || gemu))
+ goto dfl;
+ goto g0;
+ case '|':
+ case '^':
+ goto g0;
+#else
+ case '/':
+ if (gflag == 0)
+ goto dfl;
+ return(makem((int)(EM)/12)); /* italic correction */
+ case ',':
+ if (!(gflag || gemu))
+ goto dfl;
+ return(makem(0)); /* left italic correction */
+ case '|': /* narrow space */
+ return(makem((int)(EM)/6));
+ case '^': /* half narrow space */
+ return(makem((int)(EM)/12));
+#endif
+ case 'x': /* extra line space */
+ 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));
+ case 'I':
+ if (xflag) {
+ i = setgA() + '0';
+ goto gx;
+ }
+ goto dfl;
+ case 'A': /* set anchor */
+ if (gflag) { /* acceptable as name */
+ i = setgA() + '0';
+ goto gx;
+ }
+ if (xflag == 0)
+ goto dfl;
+ if ((j = setanchor()) == 0)
+ goto g0;
+ return(j);
+ case 'B': /* acceptable as expression */
+ if (xflag) {
+ i = setB() + '0';
+ goto gx;
+ }
+ goto dfl;
+ case 'F':
+ case 'm':
+ case 'M':
+ if (gflag || gemu) { /* font family, color */
+ if ((i = getsn(0)) > 0 && warn & WARN_ESCAPE)
+ errprint("\\%c[%s] unimplemented",
+ k, macname(i));
+ goto g0;
+ }
+ goto dfl;
+ case 'T':
+ if (xflag == 0)
+ goto dfl;
+ if ((j = setlink()) == 0)
+ goto g0;
+ return(j);
+ case 'R':
+ if (xflag) {
+ setr();
+ goto g0;
+ }
+ goto dfl;
+ case 'W': /* URI link */
+ if (xflag == 0)
+ goto dfl;
+ if ((j = setulink()) == 0)
+ goto g0;
+ return(j);
+ case 'Z':
+ if (xflag == 0)
+ goto dfl;
+ if ((j = setZ()) != 0)
+ return(j);
+ goto g0;
+ case 'j':
+ if (xflag == 0)
+ goto dfl;
+ if ((j = setpenalty()) != 0)
+ return(j);
+ goto g0;
+ case 'J':
+ if (xflag == 0)
+ goto dfl;
+ if ((j = setdpenal()) != 0)
+ return(j);
+ goto g0;
+ case '@':
+ if (xflag == 0)
+ goto dfl;
+ k = cbits(i = getch0());
+ switch (k) {
+ case '{':
+ pushinlev();
+ break;
+ case '}':
+ if ((i = popinlev()) != 0)
+ return(i);
+ break;
+ default:
+ if (warn & WARN_ESCAPE)
+ errprint("undefined inline environment "
+ "function \\@%c", k);
+ pbbuf[pbp++] = i;
+ goto dfl;
+ }
+ goto g0;
+ case ';': /* ligature suppressor (only) */
+ if (xflag)
+ goto g0;
+ /*FALLTHRU*/
+ default:
+ dfl: if (defcf)
+ goto copy;
+ if (warn & WARN_ESCAPE)
+ errprint("undefined escape sequence \\%c", k);
+ return(j);
+ }
+ /* NOTREACHED */
+}
+
+void
+setxon(void) /* \X'...' for copy through */
+{
+ tchar xbuf[NC];
+ register tchar *i;
+ tchar c, delim;
+ int k;
+
+ if (ismot(c = getch()))
+ return;
+ delim = c;
+ i = xbuf;
+ *i++ = XON;
+ charf++;
+ while (k = cbits(c = getch()), !issame(c, delim) && k != '\n' && i < xbuf+NC-1) {
+ if (k == ' ')
+ setcbits(c, UNPAD);
+ *i++ = c | ZBIT;
+ }
+ if (!issame(c, delim))
+ nodelim(delim);
+ charf--;
+ *i++ = XOFF;
+ *i = 0;
+ pushback(xbuf);
+}
+
+static tchar
+setyon(void) /* \Y(xx for indirect copy through */
+{
+ storerq(getsn(0));
+ return mkxfunc(YON, 0);
+}
+
+
+char ifilt[32] = {
+ 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012};
+
+tchar getch0(void)
+{
+ register int j;
+ register tchar i;
+#ifdef EUC
+ size_t n;
+#endif /* EUC */
+
+again:
+ if (pbp > lastpbp)
+ i = pbbuf[--pbp];
+ else if (ip) {
+ extern tchar *corebuf;
+ i = corebuf[ip];
+ if (i == 0)
+ {
+ /* CK: Bugfix: .bp followed by ..
+ * The "<" is questionable */
+ if (ejf && frame->pframe->tail_cnt < ejl && dip == d)
+ goto r;
+ i = rbf();
+ }
+ else {
+ if ((++ip & (BLK - 1)) == 0) {
+ --ip;
+ (void)rbf();
+ }
+ }
+ } else {
+ if (donef || ndone)
+ done(0);
+ if (nx || ibufp >= eibuf) {
+ if (nfo==0) {
+g0:
+ if (nextfile()) {
+ if (ip)
+ goto again;
+ if (ibufp < eibuf)
+ goto g2;
+ }
+ }
+ nx = 0;
+ if ((j = read(ifile, ibuf, IBUFSZ)) <= 0)
+ goto g0;
+ ibufp = ibuf;
+ eibuf = ibuf + j;
+ if (ip)
+ goto again;
+ }
+g2:
+#ifndef EUC
+ i = *ibufp++ & 0177;
+ ioff++;
+ if (i >= 040 && i < 0177)
+#else /* EUC */
+ i = *ibufp++ & 0377;
+ ioff++;
+ *mbbuf1p++ = i;
+ *mbbuf1p = 0;
+ if (multi_locale && (*mbbuf1&~(wchar_t)0177)) {
+ mbstate_t state;
+ memset(&state, 0, sizeof state);
+ if ((n = mbrtowc(&twc, mbbuf1, mbbuf1p-mbbuf1, &state))
+ == -1 ||
+ twc & ~(wchar_t)0x1FFFFF) {
+ illseq(-1, mbbuf1, mbbuf1p-mbbuf1);
+ mbbuf1p = mbbuf1;
+ *mbbuf1p = 0;
+ i &= 0177;
+ } else if (n == -2)
+ goto again;
+ else {
+ mbbuf1p = mbbuf1;
+ *mbbuf1p = 0;
+ i = twc | COPYBIT;
+ goto g4;
+ }
+ } else {
+ mbbuf1p = mbbuf1;
+ *mbbuf1p = 0;
+ if (!raw)
+ i &= 0177;
+ }
+ if (i >= 040 && i < 0177)
+#endif /* EUC */
+ goto g4;
+ if (i != 0177) {
+ if (i != ifilt[i])
+ illseq(i, NULL, 0);
+ i = ifilt[i];
+ } else
+ illseq(i, NULL, 0);
+ if (i == '\n')
+ numtab[CD].val++; /* line number */
+ }
+ if (cbits(i) == IMP && !raw)
+ goto again;
+ if ((i == 0 || i == 0177) && !init && !raw) {
+ goto again;
+ }
+g4:
+ if (!copyf && iscopy(i))
+ i = setuc0(cbits(i));
+ if (copyf == 0 && (i & ~BYTEMASK) == 0)
+ i |= chbits;
+ if (cbits(i) == eschar && !raw) {
+ if (gflag && isdi(i))
+ setcbits(i, PRESC);
+ else
+ setcbits(i, ESC);
+ }
+r:
+ return i;
+}
+
+void
+pushback(register tchar *b)
+{
+ register tchar *ob = b;
+
+ while (*b++)
+ ;
+ b--;
+ while (b > ob) {
+ if (pbp >= pbsize-3)
+ if (growpbbuf() == NULL) {
+ errprint("pushback overflow");
+ done(2);
+ }
+ pbbuf[pbp++] = *--b;
+ }
+}
+
+void
+cpushback(register char *b)
+{
+ register char *ob = b;
+
+ while (*b++)
+ ;
+ b--;
+ while (b > ob) {
+ if (pbp >= pbsize-3)
+ if (growpbbuf() == NULL) {
+ errprint("cpushback overflow");
+ done(2);
+ }
+ pbbuf[pbp++] = *--b;
+ }
+}
+
+tchar *
+growpbbuf(void)
+{
+ tchar *npb;
+ int inc = NC;
+
+ if ((npb = realloc(pbbuf, (pbsize + inc) * sizeof *pbbuf)) == NULL)
+ return NULL;
+ pbsize += inc;
+ return pbbuf = npb;
+}
+
+int
+nextfile(void)
+{
+ register char *p;
+ char *s;
+ size_t l;
+
+n0:
+ if (ifile)
+ close(ifile);
+ if (nx || nmfi < mflg) {
+ p = mfiles[nmfi++];
+ if (*p != 0)
+ goto n1;
+ }
+ if (ifi > 0) {
+ if (popf())
+ goto n0; /* popf error */
+ return(1); /* popf ok */
+ }
+ if (rargc-- <= 0) {
+ if ((nfo -= mflg) && !stdi)
+ done(0);
+ nfo++;
+ numtab[CD].val = ifile = stdi = mflg = 0;
+ free(cfname[ifi]);
+ s = "<standard input>";
+ l = strlen(s) + 1;
+ cfname[ifi] = malloc(l);
+ n_strcpy(cfname[ifi], s, l);
+ ioff = 0;
+ return(0);
+ }
+ p = (argp++)[0];
+n1:
+ numtab[CD].val = 0;
+ if (p[0] == '-' && p[1] == 0) {
+ ifile = 0;
+ free(cfname[ifi]);
+ s = "<standard input>";
+ l = strlen(s) + 1;
+ cfname[ifi] = malloc(l);
+ n_strcpy(cfname[ifi], s, l);
+ } else if ((ifile = open(p, O_RDONLY)) < 0) {
+ errprint("cannot open file %s", p);
+ nfo -= mflg;
+ done(02);
+ } else {
+ free(cfname[ifi]);
+ l = strlen(p) + 1;
+ cfname[ifi] = malloc(l);
+ n_strcpy(cfname[ifi], p, l);
+ }
+ nfo++;
+ ioff = 0;
+ return(0);
+}
+
+
+int
+popf(void)
+{
+ register int i;
+ register char *p, *q;
+
+ if (cfpid[ifi] != -1) {
+ while (waitpid(cfpid[ifi], NULL, 0) != cfpid[ifi]);
+ cfpid[ifi] = -1;
+ }
+ ioff = offl[--ifi];
+ numtab[CD].val = cfline[ifi]; /*restore line counter*/
+ ip = ipl[ifi];
+ if ((ifile = ifl[ifi]) == 0) {
+ p = xbuf;
+ q = ibuf;
+ ibufp = xbufp;
+ eibuf = xeibuf;
+ while (q < eibuf)
+ *q++ = *p++;
+ return(0);
+ }
+ if (lseek(ifile, ioff & ~(IBUFSZ-1), SEEK_SET) == -1
+ || (i = read(ifile, ibuf, IBUFSZ)) < 0)
+ return(1);
+ eibuf = ibuf + i;
+ ibufp = ibuf;
+ if (ttyname(ifile) == 0)
+ /* was >= ... */
+ if ((ibufp = ibuf + (ioff & (IBUFSZ - 1))) > eibuf)
+ return(1);
+ return(0);
+}
+
+
+void
+flushi(void)
+{
+ if (nflush)
+ return;
+ ch = 0;
+ copyf++;
+ while (!nlflg) {
+ if (donef && (frame == stk))
+ break;
+ getch();
+ }
+ copyf--;
+}
+
+
+int
+getach(void)
+{
+ register tchar i;
+ register int j;
+
+ lgf++;
+ i = getch();
+ while (isxfunc(i, CHAR))
+ i = charout[sbits(i)].ch;
+ j = cbits(i);
+ if (ismot(i) || (j == XFUNC && fbits(i)) || j == ' ' || j == '\n' ||
+ j & 0200) {
+ if (!ismot(i) && j >= 0200)
+ illseq(j, NULL, -3);
+ else if (WARN_INPUT) {
+ if (ismot(i) && !isadjmot(i))
+ errprint("motion terminates name");
+ else if (j == XFUNC && fbits(i))
+ errprint("illegal character terminates name");
+ }
+
+ ch = i;
+ j = 0;
+ }
+ lgf--;
+ return(j & 0177);
+}
+
+
+void
+casenx(void)
+{
+ struct s *pp;
+ lgf++;
+ skip(0);
+ getname();
+ nx++;
+ if (nmfi > 0)
+ nmfi--;
+ if (mfiles == NULL)
+ mfiles = calloc(1, sizeof *mfiles);
+ free(mfiles[nmfi]);
+ mfiles[nmfi] = malloc(NS);
+ n_strcpy(mfiles[nmfi], nextf, NS);
+ nextfile();
+ nlflg++;
+ tailflg = 0;
+ ip = 0;
+ pendt = 0;
+ while (frame != stk) {
+ pp = frame;
+ frame = frame->pframe;
+ sfree(pp);
+ free(pp);
+ }
+ nxf = calloc(1, sizeof *nxf);
+}
+
+
+int
+getname(void)
+{
+ register int j, k;
+ tchar i;
+ int delim = ' ';
+
+ lgf++;
+ k = 0;
+ while (1) {
+ if ((j = cbits(i = getch())) < 32 || j == delim || (!xflag
+ && j > 0176))
+ break;
+ if (xflag && !k && j == '"') {
+ delim = j;
+ continue;
+ }
+ if (k + 1 >= NS)
+ nextf = realloc(nextf, NS += 14);
+ nextf[k++] = j & BYTEMASK;
+ }
+ nextf[k] = 0;
+ ch = i;
+ lgf--;
+ return(nextf[0]);
+}
+
+tchar
+setuc(void)
+{
+ char c, d, b[NC], *bp;
+ int i = 0, n;
+ tchar r = 0;
+#ifndef NROFF
+ extern int nchtab;
+#endif
+
+ d = getach();
+ do {
+ c = getach();
+ if (i >= sizeof b)
+ goto rtn;
+ b[i++] = c;
+ } while (c && c != d);
+ b[--i] = 0;
+ if (i == 0 || c != d)
+ goto rtn;
+ n = strtol(b, &bp, 16);
+ if (n == 0 || *bp != '\0')
+ goto rtn;
+#ifndef NROFF
+ switch (n) {
+ case '\'':
+ bp = "aq";
+ break;
+ case '`':
+ bp = "ga";
+ break;
+ case '-':
+ r = MINUS;
+ goto rtn;
+ default:
+ goto uc;
+ }
+ for (i = 0; i < nchtab; i++)
+ if (strcmp(&chname[chtab[i]], bp) == 0) {
+ r = (i + 128) | chbits;
+ break;
+ }
+ goto rtn;
+uc:
+#endif
+ r = setuc0(n);
+rtn:
+ return r;
+}
+
+
+static void
+_setenv(void)
+{
+ int a = 0, i = 0, c, delim;
+ char *np = NULL, *vp;
+
+ if ((delim = getach()) == 0)
+ return;
+ switch (delim) {
+ case '[':
+ for (;;) {
+ if (i + 1 >= a)
+ np = realloc(np, a += 32);
+ if ((c = getach()) == 0) {
+ nodelim(']');
+ break;
+ }
+ if (c == ']')
+ break;
+ np[i++] = c;
+ }
+ np[i] = 0;
+ break;
+ case '(':
+ np = malloc(a = 3);
+ np[0] = delim;
+ np[1] = getach();
+ np[2] = 0;
+ break;
+ default:
+ np = malloc(a = 2);
+ np[0] = delim;
+ np[1] = 0;
+ }
+ if ((vp = getenv(np)) != NULL)
+ cpushback(vp);
+ free(np);
+}
+
+
+static void
+sopso(int i, pid_t pid)
+{
+ register char *p, *q;
+
+ free(cfname[ifi+1]);
+ cfname[ifi+1] = malloc(NS);
+ n_strcpy(cfname[ifi+1], nextf, NS);
+ cfline[ifi] = numtab[CD].val; /*hold line counter*/
+ numtab[CD].val = 0;
+ flushi();
+ cfpid[ifi+1] = pid;
+ ifl[ifi] = ifile;
+ ifile = i;
+ offl[ifi] = ioff;
+ ioff = 0;
+ ipl[ifi] = ip;
+ ip = 0;
+ nx++;
+ nflush++;
+ if (!ifl[ifi++]) {
+ p = ibuf;
+ q = xbuf;
+ xbufp = ibufp;
+ xeibuf = eibuf;
+ while (p < eibuf)
+ *q++ = *p++;
+ }
+}
+
+void
+caseso(void)
+{
+ register int i = 0;
+
+ lgf++;
+ nextf[0] = 0;
+ if (skip(1))
+ done(02);
+ if (!getname() || ((i = open(nextf, O_RDONLY)) < 0) ||
+ (ifi >= NSO)) {
+ errprint("can't open file %s", nextf);
+ if (gflag)
+ return;
+ done(02);
+ }
+ sopso(i, -1);
+}
+
+void
+casepso(void)
+{
+ int pd[2];
+ int c, i, k;
+ pid_t pid;
+
+ lgf++;
+ nextf[0] = 0;
+ if (skip(1))
+ done(02);
+ if (ifi >= NSO || pipe(pd) < 0) {
+ errprint("can't .pso");
+ done(02);
+ }
+ for (k = 0; ; k++) {
+ if ((c = cbits(i = getch())) == '\n' || c == 0)
+ break;
+ if (k + 1 >= NS)
+ nextf = realloc(nextf, NS += 14);
+ nextf[k] = c & BYTEMASK;
+ }
+ nextf[k] = 0;
+ switch (pid = fork()) {
+ case 0:
+ close(pd[0]);
+ close(1);
+ dup(pd[1]);
+ close(pd[1]);
+ execl(SHELL, "sh", "-c", nextf, NULL);
+ _exit(0177);
+ /*NOTREACHED*/
+ case -1:
+ errprint("can't fork");
+ done(02);
+ /*NOTREACHED*/
+ }
+ close(pd[1]);
+ sopso(pd[0], pid);
+}
+
+void
+caself(void) /* set line number and file */
+{
+ int n;
+
+ if (skip(1))
+ return;
+ n = hatoi();
+ cfline[ifi] = numtab[CD].val = n - 2;
+ if (skip(0))
+ return;
+ if (getname()) {
+ free(cfname[ifi]);
+ cfname[ifi] = malloc(NS);
+ n_strcpy(cfname[ifi], nextf, NS);
+ }
+}
+
+
+void
+casecf(void)
+{ /* copy file without change */
+#ifndef NROFF
+ int fd = -1, n;
+ char buf[512];
+ extern int hpos, esc, po;
+ nextf[0] = 0;
+ if (skip(1))
+ return;
+ if (!getname() || (fd = open(nextf, O_RDONLY)) < 0) {
+ errprint("can't open file %s", nextf);
+ done(02);
+ }
+ tbreak();
+ /* make it into a clean state, be sure that everything is out */
+ hpos = po;
+ esc = un;
+ ptesc();
+ ptlead();
+ ptps();
+ ptfont();
+ flusho();
+ while ((n = read(fd, buf, sizeof buf)) > 0)
+ write(ptid, buf, n);
+ close(fd);
+#endif
+}
+
+void
+casesy(void) /* call system */
+{
+ char sybuf[NTM];
+ int i;
+
+ lgf++;
+ copyf++;
+ skip(1);
+ for (i = 0; i < NTM - 2; i++)
+ if ((sybuf[i] = getch()) == '\n')
+ break;
+ sybuf[i] = 0;
+ system(sybuf);
+ copyf--;
+ lgf--;
+}
+
+
+void
+getpn(register char *a)
+{
+ register 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((unsigned char)*a)) {
+ do
+ n = 10 * n + *a++ - '0';
+ while (isdigit((unsigned char)*a));
+ a--;
+ } else
+ n = 9999;
+ *pnp++ = neg ? -n : n;
+ neg = 0;
+ if (pnp >= &pnlist[NPN-2]) {
+ errprint("too many page numbers");
+ done3(-3);
+ }
+ }
+ if (neg)
+ *pnp++ = -9999;
+ *pnp = -32767;
+ print = 0;
+ pnp = pnlist;
+ if (*pnp != -32767)
+ chkpn();
+}
+
+
+void
+setrpt(void)
+{
+ tchar i, j;
+
+ copyf++;
+ raw++;
+ i = getch0();
+ copyf--;
+ raw--;
+ if (i < 0 || cbits(j = getch0()) == RPT)
+ return;
+ i &= BYTEMASK;
+ while (i>0) {
+ if (pbp >= pbsize-3)
+ if (growpbbuf() == NULL)
+ break;
+ i--;
+ pbbuf[pbp++] = j;
+ }
+}
+
+
+void
+casedb(void)
+{
+#ifdef DEBUG
+ debug = 0;
+ if (skip(1))
+ return;
+ noscale++;
+ debug = max(hatoi(), 0);
+ noscale = 0;
+#endif /* DEBUG */
+}
+
+void
+casexflag(void)
+{
+ int i;
+
+#ifndef NROFF
+ if (gflag == 1)
+ zapwcache(1);
+#endif
+ gflag = 0;
+ setnr(".g", gflag, 0);
+ gemu = 0;
+ skip(1);
+ noscale++;
+ i = hatoi();
+ noscale--;
+ if (!nonumb)
+ _xflag = xflag = i & 3;
+}
+
+void
+casecp(void)
+{
+ if (xflag) {
+#ifndef NROFF
+ if (gflag == 0)
+ zapwcache(1);
+#endif
+ gflag = 1;
+ noscale++;
+ if (skip(1) || (hatoi() && !nonumb))
+ xflag = 1;
+ else
+ xflag = 3;
+ noscale--;
+ _xflag = xflag;
+ setnr(".g", gflag, 0);
+ setnr(".C", xflag == 1, 0);
+ setnr(".x", 1, 0);
+ setnr(".y", 18, 0);
+ }
+}
+
+void
+caserecursionlimit(void)
+{
+ skip(1);
+ noscale++;
+ max_recursion_depth = hatoi();
+ skip(0);
+ max_tail_depth = hatoi();
+ noscale--;
+}
+
+void
+casechar(int flag)
+{
+#ifndef NROFF
+ extern int ps2cc(const char *);
+ extern int nchtab;
+#endif
+ char name[NC];
+ int i, k, size = 0;
+ tchar c, *tp = NULL;
+
+ defcf++;
+ charf++;
+ lgf++;
+ if (skip(1))
+ return;
+ c = getch();
+ while (isxfunc(c, CHAR))
+ c = charout[sbits(c)].ch;
+ if ((k = cbits(c)) == eschar || k == WORDSP) {
+ switch (cbits(c = getch())) {
+ case '(':
+ name[0] = getch();
+ name[1] = getch();
+ name[2] = 0;
+ break;
+ case '[':
+ for (i = 0; cbits(c = getch()) != ']'; i++)
+ if (i < sizeof name - 1)
+ name[i] = c;
+ name[i] = 0;
+ break;
+ default:
+ errprint("mapping of escape sequences not permitted");
+ return;
+ }
+#ifndef NROFF
+ k = ps2cc(name) + nchtab + 128 + 32 + 128 - 32 + nchtab;
+#else
+ if (!(k = findch(name)))
+ k = addch(name);
+#endif
+ } else if (iscopy(c))
+ k = cbits(c = setuc0(k));
+ if (k <= ' ') {
+ errprint("mapping of special characters not permitted");
+ return;
+ }
+ defcf--;
+ charf--;
+ copyf++;
+ size = 10;
+ tp = malloc(size * sizeof *tp);
+ i = 0;
+ if (skip(0))
+ tp[i++] = FILLER;
+ else {
+ if (cbits(c = getch()) != '"')
+ ch = c;
+ while (c = getch(), !nlflg) {
+ if (i + 3 >= size) {
+ size += 10;
+ tp = realloc(tp, size * sizeof *tp);
+ }
+ tp[i++] = c;
+ }
+ }
+ tp[i++] = '\n';
+ tp[i] = 0;
+ i = k;
+ if (++i >= NCHARS)
+ morechars(i);
+ free(chartab[k]);
+ chartab[k] = tp;
+ gchtab[k] |= CHBIT;
+ copyf--;
+#ifndef NROFF
+ if (flag)
+ fchartab[k] = 1;
+ else
+ fchartab[k] = 0;
+#endif
+}
+
+void
+casefchar(void)
+{
+#ifndef NROFF
+ casechar(1);
+#endif
+}
+
+void
+caserchar(void)
+{
+ tchar c;
+ int k;
+
+ lgf++;
+ if (skip(1))
+ return;
+ do {
+ c = getch();
+ k = cbits(c);
+ free(chartab[k]);
+ chartab[k] = NULL;
+ gchtab[k] &= ~CHBIT;
+ } while (!skip(0));
+}
+
+struct fmtchar {
+ struct d newd, *savedip;
+ struct env saveev;
+ int savvflag;
+ int savvpt;
+ int savhp;
+ int savnflush;
+ tchar *csp;
+ int charcount;
+};
+
+static int
+prepchar(struct fmtchar *fp)
+{
+ static int charcount;
+ filep startb;
+ tchar t;
+
+ if ((startb = alloc()) == 0) {
+ errprint("out of space");
+ return -1;
+ }
+ t = 0;
+ setsbits(t, charcount);
+ charcount = sbits(t);
+ if (dip != d)
+ wbt(0);
+ if (charcount >= charoutsz) {
+ charoutsz += 32;
+ charout = realloc(charout, charoutsz * sizeof *charout);
+ }
+ memset(&charout[charcount], 0, sizeof *charout);
+ fp->savedip = dip;
+ memset(&fp->newd, 0, sizeof fp->newd);
+ dip = &fp->newd;
+ offset = dip->op = startb;
+ charout[charcount].op = startb;
+ fp->savnflush = nflush;
+ fp->savvflag = vflag;
+ vflag = 0;
+ fp->savvpt = vpt;
+ vpt = 0;
+ fp->savhp = numtab[HP].val;
+ fp->saveev = env;
+ evc(&env, &env);
+ in = in1 = 0;
+ fi = 0;
+ return charcount++;
+}
+
+static void
+restchar(struct fmtchar *fp, int keepf)
+{
+ wbt(0);
+ dip = fp->savedip;
+ offset = dip->op;
+ relsev(&env);
+ if (keepf) {
+ fp->saveev._apts = apts;
+ fp->saveev._apts1 = apts1;
+ fp->saveev._pts = pts;
+ fp->saveev._pts1 = pts1;
+ fp->saveev._font = font;
+ fp->saveev._font1 = font1;
+ fp->saveev._chbits = chbits;
+ fp->saveev._spbits = spbits;
+ }
+ env = fp->saveev;
+ nflush = fp->savnflush;
+ vflag = fp->savvflag;
+ vpt = fp->savvpt;
+ numtab[HP].val = fp->savhp;
+}
+
+tchar
+setchar(tchar c)
+{
+ struct fmtchar f;
+ int k = trtab[cbits(c)];
+ tchar *csp;
+ int charcount;
+ int savxflag;
+ int saveschar;
+
+#ifndef NROFF
+ if (fchartab[k] && onfont(c))
+ return c;
+#endif
+ if (iszbit(c))
+ return c;
+ if ((charcount = prepchar(&f)) < 0)
+ return ' ';
+ fmtchar++;
+ savxflag = xflag;
+ xflag = 3;
+ saveschar = eschar;
+ eschar = '\\';
+ csp = chartab[k];
+ chartab[k] = NULL;
+ pushback(csp);
+ text();
+ tbreak();
+ nlflg = 0;
+ charout[charcount].ch = c;
+ if (iszbit(c))
+ charout[charcount].width = 0;
+ else {
+ charout[charcount].width = dip->maxl - lasttrack;
+ width(' ' | sfmask(c));
+ charout[charcount].width += lasttrack;
+ }
+ charout[charcount].height = maxcht;
+ charout[charcount].depth = maxcdp;
+ restchar(&f, 0);
+ chartab[k] = csp;
+ eschar = saveschar;
+ xflag = savxflag;
+ fmtchar--;
+ return mkxfunc(CHAR, charcount);
+}
+
+static tchar
+setZ(void)
+{
+ struct fmtchar f;
+ int charcount;
+ tchar i;
+
+ if (ismot(i = getch()))
+ return 0;
+ if ((charcount = prepchar(&f)) < 0)
+ return 0;
+ stopch = i;
+ charout[charcount].ch = FILLER | sfmask(stopch);
+ text();
+ if (nlflg)
+ nodelim(stopch);
+ charout[charcount].ch = 0;
+ restchar(&f, 1);
+ return mkxfunc(CHAR, charcount);
+}
+
+tchar
+sfmask(tchar t)
+{
+ while (isxfunc(t, CHAR))
+ t = charout[sbits(t)].ch;
+ if (t == XFUNC || t == SLANT || (t & SFMASK) == 0)
+ return chbits;
+ return t & SFMASK;
+}
+
+int
+issame(tchar c, tchar d)
+{
+ if (ismot(c) || ismot(d))
+ return 0;
+ while (isxfunc(c, CHAR))
+ c = charout[sbits(c)].ch;
+ while (isxfunc(d, CHAR))
+ d = charout[sbits(d)].ch;
+ if (cbits(c) != cbits(d))
+ return 0;
+ if (cbits(c) == XFUNC && cbits(d) == XFUNC)
+ return fbits(c) == fbits(d);
+ return 1;
+}
+
+static int
+setgA(void)
+{
+ extern const char nmctab[];
+ tchar c, delim;
+ int k, y = 1;
+
+ lgf++;
+ delim = getch();
+ if (ismot(delim)) {
+ lgf--;
+ return 0;
+ }
+ while (k = cbits(c = getch()), !issame(c, delim) && !nlflg)
+ if (ismot(c) || (k < ' ' && nmctab[k]) || k == ' ' || k >= 0200)
+ y = 0;
+ if (nlflg)
+ y = 0;
+ lgf--;
+ return y;
+}
+
+static int
+setB(void)
+{
+ tchar c, delim;
+ int y = 1;
+
+ lgf++;
+ delim = getch();
+ if (ismot(delim)) {
+ lgf--;
+ return 0;
+ }
+ atoi0();
+ if (nonumb)
+ y = 0;
+ do {
+ c = getch();
+ if (!ismot(c) && issame(c, delim))
+ break;
+ y = 0;
+ } while (!nlflg);
+ lgf--;
+ return y;
+}
+
+void
+caseescoff(void) {
+ _caseesc(1);
+}
+
+void
+caseescon(void) {
+ _caseesc(0);
+}
+
+static void
+_caseesc(int off) {
+ int c;
+ if (skip(1)) return;
+ while (1) {
+ c = cbits(getch());
+ if (c < 32 || c > 126)
+ errprint("Invalid character '%c' for .esc%s\n",
+ c, off ? "off" : "on");
+ else
+ escoff[c-32] = (unsigned char)off;
+ if (skip(0))
+ return;
+ }
+}