shithub: riscv

Download patch

ref: 96c1137205df142dc79ac4d55e518a7d0a45d523
parent: cd5cab75449bcdb05b7ee47c5b603625c4753d2b
author: Jacob Moody <moody@posixcafe.org>
date: Sat May 3 03:11:15 EDT 2025

troff: native port

Imported from Geoff Collyer's tree with minor changes

--- a/sys/src/cmd/troff/dwbinit.c
+++ b/sys/src/cmd/troff/dwbinit.c
@@ -73,11 +73,7 @@
  *
  */
 
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-
+#include "tdef.h"
 #include "dwbinit.h"
 
 #ifndef DWBCONFIG
@@ -89,7 +85,7 @@
 #endif
 
 #ifndef DWBHOME
-#define DWBHOME		""
+#define DWBHOME		"/"
 #endif
 
 #ifndef DWBDEBUG
@@ -277,37 +273,3 @@
     DWBdebug(opaths, 1);
 
 }   /* End of DWBinit */
-
-/*****************************************************************************/
-
-void DWBprefix( char *prog, char *path, int length)
-{
-
-    char	*home;
-    char	buf[512];
-    int		len = strlen(DWBPREFIX);
-
-/*
- *
- * Replace a leading DWBPREFIX string in path by the current DWBhome().
- * Used by programs that pretend to handle .so requests. Assumes path
- * is an array with room for length characters. The implementation is
- * not great, but should be good enough for now. Also probably should
- * have DWBhome() only do the lookup once, and remember the value if
- * called again.
- * 
- */
-
-    if ( strncmp(path, DWBPREFIX, len) == 0 ) {
-	if ( (home = DWBhome()) != NULL ) {
-	    if ( strlen(home) + strlen(path+len) < length ) {
-		sprintf(buf, "%s%s", home, path+len);
-		strcpy(path, buf);		/* assuming there's room in path */
-	    } else fprintf(stderr, "%s: no room to grow path %s", prog, path);
-	}   /* End if */
-    }	/* End if */
-
-}   /* End of DWBprefix */
-
-/*****************************************************************************/
-
--- a/sys/src/cmd/troff/ext.h
+++ b/sys/src/cmd/troff/ext.h
@@ -97,7 +97,7 @@
 extern	int	po1;
 extern	int	po;
 extern	int	ppts;
-extern	int	print;
+extern	int	doprint;
 extern	FILE	*ptid;
 extern	int	pto;
 extern	int	quiet;
--- a/sys/src/cmd/troff/fns.h
+++ b/sys/src/cmd/troff/fns.h
@@ -3,10 +3,6 @@
  */
 int	pclose(FILE*);
 long	filesize(int fd);
-int	open(char *, int);
-int	read(int, char *, int);
-int	lseek(int, long, int);
-int	close(int);
 int	getpid(void);
 
 /*
@@ -230,7 +226,7 @@
 void	caselg(void);
 void	casefp(void);
 char	*strdupl(const char *);
-int	setfp(int pos, int f, char *truename, int print);
+int	setfp(int pos, int f, char *truename, int doprint);
 void	casecs(void);
 void	casebd(void);
 void	casevs(void);
@@ -318,7 +314,6 @@
 int	getfont(char *name, int pos);
 int	chadd(char *s, int, int);
 char*	chname(int n);
-int	getlig(FILE *fin);
 
 /*
  * n6.c
--- /dev/null
+++ b/sys/src/cmd/troff/mbwc.c
@@ -1,0 +1,22 @@
+/* ansi wide-character to multibyte-string conversions */
+#include <u.h>
+#include <libc.h>
+
+int
+mbtowc(Rune *rp, char *s, int len)
+{
+	int bytes, copy;
+	char utf[UTFmax+1];
+
+	if(s == nil)
+		return 0;
+	if(len < 1)
+		return -1;
+	copy = len > UTFmax? UTFmax: len;
+	strncpy(utf, s, copy);
+	utf[copy] = '\0';
+	bytes = chartorune(rp, utf);
+	if (bytes == 1 && *rp == Runeerror)
+		return -1;
+	return bytes;
+}
--- a/sys/src/cmd/troff/mkfile
+++ b/sys/src/cmd/troff/mkfile
@@ -18,6 +18,10 @@
 	hytab.$O\
 	suftab.$O\
 	dwbinit.$O\
+	mbwc.$O\
+	popen.$O\
+	system.$O\
+	space.$O\
 
 HFILES=tdef.h\
 	fns.h\
@@ -24,37 +28,19 @@
 	ext.h\
 	dwbinit.h\
 
-
 BIN=/$objtype/bin
 </sys/src/cmd/mkone
-CFLAGS=-c -DSTRICT -DUNICODE
-CC=pcc
+CFLAGS=-FTVw -DUNICODE
 
 TMACDIR='"sys/lib/tmac/tmac."'
 FONTDIR="sys/lib/troff/font"
 NTERMDIR='"sys/lib/troff/term/tab."'
-TEXHYPHENS='"sys/lib/texmf/tex/generic/hyphen/hyphen.tex"'
-DWBHOME='"/"'
-TDEVNAME='"utf"'
-NDEVNAME='"utf"'
 
-$O.out:	$OFILES
-	pcc -o $target $prereq
+$O.out:	$OFILES $LIB
+	$LD -o $target $prereq
 
 ni.$O:	ni.c $HFILES
 	$CC $CFLAGS -DTMACDIR'='$TMACDIR ni.c
 
-t10.$O:	t10.c $HFILES
-	$CC $CFLAGS -DTDEVNAME'='$TDEVNAME t10.c
-
 n1.$O:	n1.c $HFILES
-	$CC $CFLAGS -DFONTDIR'='$FONTDIR -DNTERMDIR'='$NTERMDIR -DTEXHYPHENS'='$TEXHYPHENS -DALTHYPHENS'='$TEXHYPHENS -DDWBHOME'='$DWBHOME n1.c
-
-n10.$O:	n10.c $HFILES
-	$CC $CFLAGS -DNDEVNAME'='$NDEVNAME n10.c
-
-n8.$O:	n8.c $HFILES
-	$CC $CFLAGS -DTEXHYPHENS'='$TEXHYPHENS n8.c
-
-dwbinit.$O:	dwbinit.c
-	$CC $CFLAGS -DDWBHOME'='$DWBHOME dwbinit.c
+	$CC $CFLAGS -DFONTDIR'='$FONTDIR -DNTERMDIR'='$NTERMDIR n1.c
--- a/sys/src/cmd/troff/n1.c
+++ b/sys/src/cmd/troff/n1.c
@@ -10,9 +10,6 @@
 #include "ext.h"
 #include "dwbinit.h"
 
-#include <setjmp.h>
-#include <time.h>
-
 char	*Version	= "March 11, 1994";
 
 #ifndef DWBVERSION
@@ -52,9 +49,8 @@
 	char *p;
 	int j;
 	Tchar i;
-	char buf[100];
+	char buf[200];
 
-	buf[0] = '\0';		/* make sure it's empty (silly 3b2) */
 	progname = argv[0];
 	if ((p = strrchr(progname, '/')) == NULL)
 		p = progname;
@@ -72,6 +68,7 @@
 	nrehash();
 	numtabp[NL].val = -1;
 
+	buf[0] = '\0';
 	while (--argc > 0 && (++argv)[0][0] == '-')
 		switch (argv[0][1]) {
 
@@ -193,7 +190,8 @@
 		while (cbits(i) != '\n')
 			pchar(i = getch());
 		tflg = 0;
-		copyf--;
+		copyf--;			/* pointless */
+		USED(copyf);
 		goto loop;
 	}
 	if (j == cc || j == c2) {
@@ -221,7 +219,7 @@
 void init2(void)
 {
 	int i;
-	char buf[100];
+	char buf[256];
 
 	for (i = NTRTAB; --i; )
 		trtab[i] = i;
@@ -239,9 +237,9 @@
 	numtabp[NL].val = -1;
 	nfo = 0;
 	copyf = raw = 0;
-	sprintf(buf, ".ds .T %s\n", devname);
+	snprintf(buf, sizeof buf, ".ds .T %s\n", devname);
 	cpushback(buf);
-	sprintf(buf, ".ds .P %s\n", DWBhomedir);
+	snprintf(buf, sizeof buf, ".ds .P %s\n", DWBhomedir);
 	cpushback(buf);
 	numtabp[CD].val = -1;	/* compensation */
 	nx = mflg;
@@ -273,16 +271,16 @@
 
 void cvtime(void)
 {
-	long tt;
-	struct tm *ltime;
+	Tm ltime;
+	Tzone *tz;
 
-	time(&tt);
-	ltime = localtime(&tt);
-	numtabp[YR].val = ltime->tm_year % 100;
+	tz = tzload("local");
+	tmnow(&ltime, tz);
+	numtabp[YR].val = ltime.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 */
+	numtabp[MO].val = ltime.mon + 1;	/* troff uses 1..12 */
+	numtabp[DY].val = ltime.mday;
+	numtabp[DW].val = ltime.wday + 1;	/* troff uses 1..7 */
 }
 
 
@@ -670,7 +668,6 @@
 
 Tchar getch0(void)
 {
-	int j;
 	Tchar i;
 
 again:
@@ -713,7 +710,6 @@
 			if (ip)
 				goto again;
 		}
-g2:
 		if (i >= 040)			/* zapped: && i < 0177 */
 			goto g4;
 		i = ifilt[i];
@@ -741,14 +737,16 @@
 	char buf[100], *p;
 	int i, n, c;
 
+	n = c = 0;
 	for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
 		if ((c = getc(fp)) == EOF)
 			return c;
 		*p++ = c;
+		*p = '\0';
 		if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
 			break;
 	}
-	if (n == 1)	/* real ascii, presumably */
+	if (n == 1)		/* real ascii, presumably */
 		return wc;
 	if (n == 0)
 		return p[-1];	/* illegal, but what else to do? */
@@ -911,7 +909,6 @@
 getname(void)
 {
 	int j, k;
-	Tchar i;
 
 	lgf++;
 	for (k = 0; k < NS - 1; k++) {
@@ -929,10 +926,10 @@
 void caseso(void)
 {
 	FILE *fp;
-	char *p, *q;
 
 	lgf++;
 	nextf[0] = 0;
+	fp = NULL;
 	if (skip() || !getname() || (fp = fopen(nextf, "r")) == NULL || ifi >= NSO) {
 		ERROR "can't open file %s", nextf WARN;
 		done(02);
@@ -1105,7 +1102,7 @@
 	if (neg)
 		*pnp++ = -9999;
 	*pnp = -INT_MAX;
-	print = 0;
+	doprint = 0;
 	pnp = pnlist;
 	if (*pnp != -INT_MAX)
 		chkpn();
--- a/sys/src/cmd/troff/n10.c
+++ b/sys/src/cmd/troff/n10.c
@@ -7,7 +7,6 @@
 #include "tdef.h"
 #include "ext.h"
 #include "fns.h"
-#include <ctype.h>
 
 Term	t;	/* terminal characteristics */
 
@@ -39,7 +38,8 @@
 	}
 	for (;;) {
 		if (quote && *s == '"') {
-			s++;
+			s++;			/* pointless */
+			USED(s);
 			break;
 		}
 		if (!quote && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\0'))
@@ -74,35 +74,50 @@
 
 static int getnrfont(FILE *fp)	/* read the nroff description file */
 {
-	FILE *fin;
 	Chwid chtemp[NCHARS];
 	static Chwid chinit;
 	int i, nw, n, wid, code, type;
-	char buf[100], ch[100], s1[100], s2[100], cmd[300];
+	char *ch, *s1, *s2;
+	char buf[128], dummy[32];
 	wchar_t wc;
 
-
+	code = wid = 0;			/* no idea what this should be */
 	chinit.wid = 1;
 	chinit.str = "";
 	for (i = 0; i < ALPHABET; i++) {
 		chtemp[i] = chinit;	/* zero out to begin with */
-		chtemp[i].num = chtemp[i].code = i;	/* every alphabetic character is itself */
+		/* every alphabetic character is itself */
+		chtemp[i].num = chtemp[i].code = i;
 		chtemp[i].wid = 1;	/* default ascii widths */
 	}
 	skipline(fp);
 	nw = ALPHABET;
 	while (fgets(buf, sizeof buf, fp) != NULL) {
-		sscanf(buf, "%s %s %[^\n]", ch, s1, s2);
-		if (!eq(s1, "\"")) {	/* genuine new character */
-			sscanf(s1, "%d", &wid);
-		} /* else it's a synonym for prev character, */
-			/* so leave previous values intact */
+		int ntok;
+		char *toks[4];		/* last field for trailing junk */
 
+		ch = s1 = s2 = "";
+		memset(toks, 0, sizeof toks);
+		ntok = getfields(buf, toks, nelem(toks), 1, "\r\n\t ");
+		if (ntok == 0)
+			continue;
+		if (ntok >= 2) {
+			ch = toks[0];
+			s1 = toks[1];
+			if (ntok >= 3)
+				s2 = toks[2];
+		}
+
+		if (!eq(s1, "\""))	/* genuine new character */
+			wid = atoi(s1);
+		/* else it's a synonym for prev character, */
+		/* so leave previous values intact */
+
 		/* decide what kind of alphabet it might come from */
 
-		if (strlen(ch) == 1) {	/* it's ascii */
-			n = ch[0];	/* origin includes non-graphics */
-			chtemp[n].num = ch[0];
+		if (ch[0] && ch[1] == '\0') {	/* it's ascii */
+			n = ch[0] & 0xff;  /* origin includes non-graphics */
+			chtemp[n].num = n;
 		} else if (ch[0] == '\\' && ch[1] == '0') {
 			n = strtol(ch+1, 0, 0);	/* \0octal or \0xhex */
 			chtemp[n].num = n;
@@ -114,7 +129,9 @@
 #endif	/*UNICODE*/
 		} else {
 			if (strcmp(ch, "---") == 0) { /* no name */
-				sprintf(ch, "%d", code);
+				/* code used to be uninitialised here */
+				snprintf(dummy, sizeof dummy, "%d", code);
+				ch = dummy;
 				type = Number;
 			} else
 				type = Troffchar;
@@ -139,8 +156,8 @@
 void n_ptinit(void)
 {
 	int i;
-	char *p, *cp;
-	char opt[50], cmd[100];
+	char *p, *opt;
+	char cmd[128];
 	FILE *fp;
 
 	hmot = n_hmot;
@@ -163,13 +180,11 @@
 	setwd = n_setwd;
 
 	if ((p = getenv("NROFFTERM")) != 0)
-		strcpy(devname, p);
+		strncpy(devname, p, sizeof devname);
 	if (termtab[0] == 0)
-		strcpy(termtab,DWBntermdir);
-	if (fontdir[0] == 0)
-		strcpy(fontdir, "");
+		strcpy(termtab, DWBntermdir);
 	if (devname[0] == 0)
-		strcpy(devname, NDEVNAME);
+		strncpy(devname, NDEVNAME, sizeof devname);
 	pl = 11*INCH;
 	po = PO;
 	hyf = 0;
@@ -196,14 +211,22 @@
 /* it assumes  name, name-value pairs..., charset */
 /* god help us if we get out of sync. */
 
-	fscanf(fp, "%s", cmd);	/* should be device name... */
+	cmd[0] = '\0';
+	if (fgets(cmd, sizeof cmd, fp) != NULL)	/* should be device name... */
+		cmd[strlen(cmd) - 1] = '\0';	/* step on newline */
 	if (!is(devname) && trace)
 		ERROR "wrong terminal name: saw %s, wanted %s", cmd, devname WARN;
-	for (;;) {
-		fscanf(fp, "%s", cmd);
+	while (fgets(cmd, sizeof cmd, fp) != NULL) {
+		cmd[strlen(cmd) - 1] = '\0';	/* step on newline */
+		if (*cmd == '\0')
+			continue;
 		if (is("charset"))
 			break;
-		fscanf(fp, " %[^\n]", opt);
+		opt = skipword(cmd);
+		if (*opt != '\0') {
+			*opt++ = '\0';
+			opt = skipspace(opt);
+		}
 		if (is("bset")) t.bset = atoi(opt);
 		else if (is("breset")) t.breset = atoi(opt);
 		else if (is("Hor")) t.Hor = atoi(opt);
@@ -368,7 +391,8 @@
 			for (j = w / t.Char; j > 0; j--)
 				oput('\b');
 		}
-		if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) || xfont == BDFONT || xfont == BIFONT))
+		if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) ||
+		    xfont == BDFONT || xfont == BIFONT))
 			j++;
 		else
 			j = 1;	/* number of overstrikes for bold */
@@ -378,19 +402,19 @@
 				oput('\b');
 				oput(k);
 			}
-		} else if (k >= t.tfont.nchars) {	/* BUG -- not really understood */
+		} else if (k >= t.tfont.nchars) { /* BUG -- not really understood */
 /* fprintf(stderr, "big char %d, name %s\n", k, chname(k)); /* */
-			oputs(chname(k)+1);	/* BUG: should separate Troffchar and MBchar... */
+			oputs(chname(k)+1); /* BUG: should separate Troffchar and MBchar... */
 		} else if (t.tfont.wp[k].str == 0) {
 /* fprintf(stderr, "nostr char %d, name %s\n", k, chname(k)); /* */
-			oputs(chname(k)+1);	/* BUG: should separate Troffchar and MBchar... */
-		} else if (t.tfont.wp[k].str[0] == MBchar) {	/* parse() puts this on */
+			oputs(chname(k)+1); /* BUG: should separate Troffchar and MBchar... */
+		} else if (t.tfont.wp[k].str[0] == MBchar) { /* parse() puts this on */
 /* fprintf(stderr, "MBstr char %d, name %s\n", k, chname(k)); /* */
 			oputs(t.tfont.wp[k].str+1);
 		} else {
 			int oj = j;
 /* fprintf(stderr, "str char %d, name %s\n", k, chname(k)); /* */
-			codep = t.tfont.wp[k].str+1;	/* Troffchar by default */
+			codep = t.tfont.wp[k].str+1; /* Troffchar by default */
 			while (*codep != 0) {
 				if (*codep & 0200) {
 					codep = plot(codep);
--- a/sys/src/cmd/troff/n2.c
+++ b/sys/src/cmd/troff/n2.c
@@ -7,14 +7,9 @@
 #include "tdef.h"
 #include "fns.h"
 #include "ext.h"
-#include <setjmp.h>
 
-#ifdef STRICT
-	/* not in ANSI or POSIX */
-FILE*	popen(char*, char*);
-#endif
+FILE*	popen(char*, char*);	/* not in ANSI or POSIX */
 
-
 extern	jmp_buf	sjbuf;
 int	toolate;
 int	error;
@@ -92,7 +87,7 @@
 		dip->op = offset;
 		return;
 	}
-	if (!tflg && !print) {
+	if (!tflg && !doprint) {
 		if (j == '\n')
 			dip->alss = dip->blss = 0;
 		return;
@@ -100,7 +95,7 @@
 	if (j == FILLER && !xon)
 		return;
 	if (tflg) {	/* transparent mode, undiverted */
-		if (print)			/* assumes that it's ok to print */
+		if (doprint)		/* assumes that it's ok to print */
 			/* OUT "%c", j PUT;	/* i.e., is ascii */
 			outascii(i);
 		return;
@@ -137,7 +132,6 @@
 
 void outascii(Tchar i)	/* print i in best-guess ascii */
 {
-	char *p;
 	int j = cbits(i);
 
 /* is this ever called with NROFF set? probably doesn't work at all. */
--- a/sys/src/cmd/troff/n3.c
+++ b/sys/src/cmd/troff/n3.c
@@ -64,7 +64,7 @@
 
 char *grow(char *ptr, int num, int size)	/* make array bigger */
 {
-	char *p, new;
+	char *p;
 
 	if (ptr == NULL)
 		p = (char *) calloc(num, size);
@@ -176,8 +176,7 @@
 
 void caserm(void)
 {
-	int j;
-	int k = 0;
+	int j, k;
 
 	lgf++;
 g0:
@@ -249,7 +248,8 @@
 		savoff = offset;
 		offset = apptr;
 		wbf((Tchar) IMP);
-		offset = savoff;
+		offset = savoff;	/* pointless */
+		USED(offset);
 	}
 	offset = dip->op;
 	if (req != '.')
@@ -307,7 +307,6 @@
 Offset finds(int mn)
 {
 	int i;
-	Tchar j = IMP;
 	Offset savip;
 
 	oldmn = findmn(mn);
@@ -383,6 +382,7 @@
 	flushi();
 	nlflg = 0;
 	state = 1;
+	savoff = 0;
 
 /* state 0	eat up
  * state 1	look for .
@@ -506,7 +506,7 @@
 	if (i == 0)
 		contabp[savslot].emx = offset;
 	off = boffset(offset);
-	blist[j].bp[off++] = i;
+	blist[j].bp[off] = i;
 	offset++;
 	if (pastend(offset)) {	/* off the end of this block */
 		if (blist[j].nextoff == -1) {
@@ -826,7 +826,6 @@
 	dip->dimac = getrq();
 }
 
-#define LNSIZE 4000
 void casetl(void)
 {
 	int j;
--- a/sys/src/cmd/troff/n4.c
+++ b/sys/src/cmd/troff/n4.c
@@ -8,7 +8,6 @@
 #include "fns.h"
 #include "ext.h"
 
-
 int	regcnt = NNAMES;
 int	falsef	= 0;	/* on if inside false branch of if */
 
@@ -117,7 +116,7 @@
 			i = ne;
 			break;
 		case 'P':
-			i = print;
+			i = doprint;
 			break;
 		case 'L':
 			i = ls;
@@ -373,7 +372,7 @@
 			i = *(onesp + 1);
 		else
 			i = *fivesp;
-		return(k += (*f)(i | nrbits));
+		return(k + (*f)(i | nrbits));
 	}
 	if (q)
 		k += (*f)(*fivesp | nrbits);
@@ -531,14 +530,11 @@
 long ckph(void)
 {
 	Tchar i;
-	long j;
 
 	if (cbits(i = getch()) == '(')
-		j = atoi0();
-	else {
-		j = atoi1(i);
-	}
-	return(j);
+		return atoi0();
+	else
+		return atoi1(i);
 }
 
 
@@ -547,15 +543,16 @@
  */
 void prnumerr(void)
 {
-	char err_buf[40];
+	char err_buf[128];
 	static char warn[] = "Numeric argument expected";
 	int savcd = numtabp[CD].val;
 
 	if (numerr.type == RQERR)
-		sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
-						unpair(numerr.req), warn);
+		snprintf(err_buf, sizeof err_buf, "%c%s: %s",
+			nb ? cbits(c2) : cbits(cc), unpair(numerr.req), warn);
 	else
-		sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
+		snprintf(err_buf, sizeof err_buf, "\\%c'%s': %s",
+			numerr.esc, &numerr.escarg,
 									warn);
 	if (frame != stk)	/* uncertainty correction */
 		numtabp[CD].val--;
@@ -571,7 +568,6 @@
 	int neg, abs, field, decpnt;
 	extern int ifnum;
 
-
 	neg = abs = field = decpnt = digits = 0;
 	acc = 0;
 	for (;;) {
@@ -657,7 +653,7 @@
 	if (neg)
 		acc = -acc;
 	if (!noscale) {
-		acc = (acc * j) / i;
+		acc = (acc * j) / (i? i: 1);
 	}
 	if (field != digits && digits > 0)
 		while (digits--)
@@ -713,11 +709,11 @@
 	lgf++;
 	skip();
 	if ((i = findr(getrq())) == -1)
-		goto rtn;
+		return;
 	skip();
 	j = inumb(&numtabp[i].val);
 	if (nonumb)
-		goto rtn;
+		return;
 	numtabp[i].val = j;
 	skip();
 	trace = 0;
@@ -724,10 +720,8 @@
 	j = atoi0();		/* BUG??? */
 	trace = savtr;
 	if (nonumb)
-		goto rtn;
+		return;
 	numtabp[i].inc = j;
-rtn:
-	return;
 }
 
 void caseaf(void)
@@ -818,7 +812,10 @@
 		n = -n;
 	}
 	/* better as i = ((n + m/2)/m)*m */
-	i = n / m;
+	if (m != 0)
+		i = n / m;
+	else
+		i = n;
 	if (n - m * i > m / 2)
 		i += 1;
 	i *= m;
--- a/sys/src/cmd/troff/n5.c
+++ b/sys/src/cmd/troff/n5.c
@@ -83,6 +83,7 @@
 {
 	Tchar i;
 
+	i = 0;
 	if (skip() || ismot(i = getch()) || cbits(i) == ' ' || cbits(i) == '\n') {
 		ch = i;
 		return(c);
@@ -431,7 +432,7 @@
 		else {
 			extern int error;
 			int savtrac = trace;
-			i = trace = 0;
+			trace = 0;
 			noscale++;
 			i = inumb(&trace);
 			noscale--;
@@ -472,7 +473,7 @@
 				sprintf(&tmbuf[i], "\\N'%s'", p+1);
 				break;
 			case Troffchar:
-				if ((j = strlen(p+1)) == 2)
+				if (strlen(p+1) == 2)
 					sprintf(&tmbuf[i], "\\(%s", p+1);
 				else
 					sprintf(&tmbuf[i], "\\C'%s'", p+1);
--- a/sys/src/cmd/troff/n6.c
+++ b/sys/src/cmd/troff/n6.c
@@ -1,7 +1,6 @@
 #include "tdef.h"
 #include "ext.h"
 #include "fns.h"
-#include <ctype.h>
 
 /*
  * n6.c -- width functions, sizes and fonts
@@ -83,9 +82,9 @@
 	i = cbits(getch());
 	if (isdigit(i)) {		/* \sd or \sdd */
 		i -= '0';
-		if (i == 0)		/* \s0 */
+		if (i == 0) {		/* \s0 */
 			;
-		else if (i <= 3 && (ch=getch()) && isdigit(cbits(ch))) {	/* \sdd */
+		} else if (i <= 3 && (ch=getch()) && isdigit(cbits(ch))) {	/* \sdd */
 			ch = 0;
 		}
 	} else if (i == '(') {		/* \s(dd */
@@ -294,7 +293,7 @@
 {
 	int i, j, k;
 
-	k = 0;
+	j = k = 0;
 bd0:
 	if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
 		if (k)
--- a/sys/src/cmd/troff/n7.c
+++ b/sys/src/cmd/troff/n7.c
@@ -2,15 +2,12 @@
 #include "fns.h"
 #include "ext.h"
 
-#ifdef STRICT
-	/* not in ANSI or POSIX */
-#define	isascii(a) ((a) >= 0 && (a) <= 127)
-#endif
+#undef  isascii
+#define	isascii(a) ((a) >= 0 && (a) <= 127)	/* not in ANSI or POSIX */
 
 #define GETCH gettch
 Tchar	gettch(void);
 
-
 /*
  * troff7.c
  * 
@@ -354,6 +351,7 @@
 	int i, j, nlss;
 	int opn;
 
+	nlss = 0;
 	if (a)
 		goto nl1;
 	if (dip != d) {
@@ -413,17 +411,17 @@
 	}
 nlpn:
 	if (numtabp[PN].val == pfrom) {
-		print++;
+		doprint++;
 		pfrom = -1;
 	} else if (opn == pto) {
-		print = 0;
+		doprint = 0;
 		opn = -1;
 		chkpn();
 		goto nlpn;
 	}
-	if (print)
+	if (doprint)
 		ptpage(numtabp[PN].val);	/* supposedly in a clean state so can pause */
-	if (stop && print) {
+	if (stop && doprint) {
 		dpn++;
 		if (dpn >= stop) {
 			dpn = 0;
@@ -472,7 +470,7 @@
 	}
 	if (pto < 0) {
 		pto = -pto;
-		print++;
+		doprint++;
 		pfrom = 0;
 	}
 }
@@ -656,7 +654,7 @@
 	int noword;
 	int obits;
 
-	noword = 0;
+	j = noword = 0;
 	if (x)
 		if (pendw) {
 			*pendw = 0;
--- a/sys/src/cmd/troff/n8.c
+++ b/sys/src/cmd/troff/n8.c
@@ -1,7 +1,6 @@
 #include "tdef.h"
 #include "fns.h"
 #include "ext.h"
-#include <assert.h>
 
 #define	HY_BIT	0200	/* stuff in here only works for 7-bit ascii */
 			/* this value is used (as a literal) in suftab.c */
@@ -306,12 +305,11 @@
 
 void digram(void)
 {
-	Tchar *w;
-	int val;
-	Tchar *nhyend, *maxw;
-	int maxval;
+	int maxval, val;
+	Tchar *nhyend, *maxw, *w;
 	extern char bxh[26][13], bxxh[26][13], xxh[26][13], xhx[26][13], hxx[26][13];
 
+	maxw = 0;
 again:
 	if (!(w = chkvow(hyend + 1)))
 		return;
@@ -465,7 +463,8 @@
 static int readpats(void)
 {
 	FILE *fp;
-	char buf[200], buf1[200];
+	char *p, *wd;
+	char buf[200];
 
 	if ((fp = fopen(TEXHYPHENS, "r")) == NULL
 	 && (fp = fopen(DWBalthyphens, "r")) == NULL) {
@@ -474,8 +473,14 @@
 	}
 
 	while (fgets(buf, sizeof buf, fp) != NULL) {
-		sscanf(buf, "%s", buf1);
-		if (strcmp(buf1, "\\patterns{") == 0)
+		p = buf;
+		if (isspace(*p))
+			p++;
+		wd = p;
+		if (*p != '\0' && !isspace(*p))
+			p++;
+		*p = '\0';
+		if (strcmp(wd, "\\patterns{") == 0)
 			break;
 	}
 	while (fgets(buf, sizeof buf, fp) != NULL) {
--- a/sys/src/cmd/troff/n9.c
+++ b/sys/src/cmd/troff/n9.c
@@ -331,20 +331,18 @@
 
 Tchar setfield(int x)
 {
-	Tchar ii, jj, *fp;
-	int i, j;
-	int length, ws, npad, temp, type;
+	Tchar rchar, ii, jj, *fp;
 	Tchar **pp, *padptr[NPP];
 	Tchar fbuf[FBUFSZ];
-	int savfc, savtc, savlc;
-	Tchar rchar;
-	int savepos;
+	int i, j, length, ws, npad, temp, type, savepos, savfc, savtc, savlc;
 	static Tchar wbuf[] = { WORDSP, 0};
 
 	if (x == tabch) 
 		rchar = tabc | chbits;
-	else if (x ==  ldrch) 
+	else if (x == ldrch) 
 		rchar = dotc | chbits;
+	else
+		rchar = 0;
 	temp = npad = ws = 0;
 	savfc = fc;
 	savtc = tabch;
--- a/sys/src/cmd/troff/ni.c
+++ b/sys/src/cmd/troff/ni.c
@@ -1,4 +1,3 @@
-#include <stdio.h>
 #include "tdef.h"
 #include "fns.h"
 #include "ext.h"
@@ -29,7 +28,7 @@
 int	alphabet	= 256;	/* latin-1 */
 int	pto	= 10000;
 int	pfrom	= 1;
-int	print	= 1;
+int	doprint	= 1;
 char	nextf[NS]	= TMACDIR;
 char	mfiles[NMF][NS];
 int	nmfi	= 0;
--- /dev/null
+++ b/sys/src/cmd/troff/popen.c
@@ -1,0 +1,153 @@
+/*
+ * popen, pclose - open and close pipes (Plan 9 version)
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+enum { Stdin, Stdout, };
+enum {
+	Rd,
+	Wr,
+	Maxfd = 200,
+};
+
+typedef struct {
+	long	pid;
+	char	*sts;		/* malloced; valid if non-nil */
+} Pipe;
+
+static Pipe pipes[Maxfd];
+
+static int
+_pipefd(int rfd, int wfd)
+{
+	close(wfd);
+	return rfd;
+}
+
+FILE *
+popen(char *file, char *mode)
+{
+	int pipedes[2];
+	long pid;
+
+	if (pipe(pipedes) < 0)		/* cat's got the last pipe */
+		return 0;
+	if ((pid = fork()) < 0) {	/* can't fork */
+		close(pipedes[Rd]);
+		close(pipedes[Wr]);
+		return 0;
+	}
+	/*
+	 * The pipe was created and the fork succeeded.
+	 * Now fiddle the file descriptors in both processes.
+	 */
+	if (pid == 0) {			/* child process */
+		int sts;
+
+		/*
+		 * If the mode is 'r', the child writes on stdout so the
+		 * parent can read on its stdin from the child.
+		 * If the mode is not 'r', the child reads on stdin so the
+		 * parent can write on its stdout to the child.
+		 */
+		if (mode[0] == 'r')		/* read from child */
+			sts = dup(pipedes[Wr], Stdout);
+		else				/* write to child */
+			sts = dup(pipedes[Rd], Stdin);
+		if (sts < 0)			/* couldn't fiddle fd's */
+			_exits("no pipe");
+		close(pipedes[Rd]);
+		close(pipedes[Wr]);
+		execl("/bin/rc", "rc", "-c", file, (char *)nil);
+		_exits("no /bin/rc");		/* no shell */
+	} else {			/* parent process */
+		int fd;
+
+		/*
+		 * If the mode is 'r', the parent reads on its stdin the child;
+		 * otherwise the parent writes on its stdout to the child.
+		 */
+		if (mode[0] == 'r')	/* read from child */
+			fd = _pipefd(pipedes[Rd], pipedes[Wr]);
+		else
+			fd = _pipefd(pipedes[Wr], pipedes[Rd]);
+		if (fd >= 0 && fd < Maxfd) {
+			Pipe *pp = pipes + fd;
+
+			pp->pid = pid;		/* save fd's child's pid */
+			free(pp->sts);
+			pp->sts = nil;
+		}
+		return fdopen(fd, mode[0] == 'r'? "w": "r");
+	}
+}
+
+static volatile int waiting;
+
+static int
+gotnote(void *, char *note)
+{
+	if (strcmp(note, "interrupt") == 0)
+		if (waiting)
+			return 1;	/* NCONT */
+	return 0;			/* not a known note: NDFLT */
+}
+
+int
+pclose(FILE *fp)
+{
+	int fd;
+	int pid;		/* pid, wait status for some child */
+	Pipe *fpp, *app = nil, *spp;
+	Waitmsg *wm;
+	static int registered;
+
+	fd = fileno(fp);
+	if (fd < 0 || fd >= Maxfd)
+		return -1;	// "fd out of range";
+	fpp = pipes + fd;
+	if (fpp->pid <= 0)
+		return -1;	// "no child process for fd";
+	close(fd);
+	/*
+	 * Ignore notes in case this process was catching them.
+	 * Otherwise both this process and its child(ren) would
+	 * catch these notes.
+	 * Ideally I suppose popen should ignore the notes.
+	 */
+	if (!registered) {
+		atnotify(gotnote, 1);
+		registered = 1;
+	}
+	waiting = 1;
+	/*
+	 * Wait for fd's child to die.
+	 * ``Bring out your dead!''
+	 */
+	while (fpp->sts == nil && (wm = wait()) != nil) {
+		pid = wm->pid;
+		/*
+		 * See if any fd is attached to this corpse;
+		 * if so, give that fd its wait status.
+		 */
+		if (pid == fpp->pid)	/* quick check */
+			app = fpp;
+		else
+			for (spp = pipes; spp < pipes + Maxfd; spp++)
+				if (pid == spp->pid) {
+					app = spp;
+					break;
+				}
+		if (app != nil) {
+			/* record pid's status, possibly for later use */
+			free(app->sts);
+			app->sts = strdup(wm->msg);
+		}
+		free(wm);
+	}
+	waiting = 0;
+	return fpp->sts != nil && fpp->sts[0] != '\0'? 1: 0;
+}
--- /dev/null
+++ b/sys/src/cmd/troff/space.c
@@ -1,0 +1,74 @@
+/*
+ * functions to skip spaces or non-spaces
+ */
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+
+char *
+skipspace(char *s)
+{
+	while (isspace(*s))
+		s++;
+	return s;
+}
+
+char *
+skipword(char *s)
+{
+	s = skipspace(s);
+	while (*s != '\0' && !isspace(*s))
+		s++;
+	return s;
+}
+
+/* returns -1 or first non-space char read */
+int
+rdspace(int fd)
+{
+	int n;
+	char c;
+
+	while ((n = read(fd, &c, 1)) == 1 && isspace(c))
+		;
+	if (n <= 0)
+		return -1;
+	return (uchar)c;
+}
+
+/*
+ * fill buf with a non-empty word of max bytes from fd.
+ * result will be NUL-terminated.  the terminating character,
+ * usually whitespace is returned; if it is not -1 and not whitespace,
+ * the word was truncated and there is more to read.
+ */
+int
+rdword(int fd, char *buf, int max)
+{
+	int n, i;
+	char c;
+
+	i = n = 0;
+	buf[i] = '\0';
+
+	c = rdspace(fd);
+	if (c == -1)
+		return -1;		/* eof */
+
+	/* else rdspace read a byte too far past spaces */
+	if (--max <= 0)
+		return 0;		/* terminated by count */
+	if (c > 0)
+		buf[i++] = c;
+
+	while (--max > 0 && (n = read(fd, &c, 1)) == 1 && !isspace(c)) {
+		buf[i++] = c;
+		c = '\0';
+	}
+	if (i == 0 && n <= 0)		/* eof and empty word? */
+		return -1;
+	if (max <= 0)
+		c = 0;			/* terminated by count */
+	buf[i] = '\0';
+	return c;
+}
--- /dev/null
+++ b/sys/src/cmd/troff/system.c
@@ -1,0 +1,23 @@
+/*
+ * system - run a shell command (Plan 9 version)
+ */
+
+#include <u.h>
+#include <libc.h>
+
+int
+system(char *s)
+{
+	long pid = fork();
+	Waitmsg *wm;
+
+	if (pid == 0) {
+		execl("/bin/rc", "rc", "-c", s, nil);
+		_exits("no /bin/rc");
+	}
+	if (pid < 0)
+		return -1;	// "can't fork";
+	while ((wm = wait()) != nil && wm->pid != pid)
+		continue;
+	return wm == nil? -1: wm->msg != 0 && wm->msg[0]? 1: 0;
+}
--- a/sys/src/cmd/troff/t10.c
+++ b/sys/src/cmd/troff/t10.c
@@ -156,11 +156,11 @@
 
 int ptout0(Tchar *pi)
 {
-	int j, k, w;
-	int z, dx, dy, dx2, dy2, n;
-	Tchar i;
+	int j, k, w, z, dx, dy, dx2, dy2, n;
 	int outsize;	/* size of object being printed */
+	Tchar i;
 
+	w = 0;
 	outsize = 1;	/* default */
 	i = *pi;
 	k = cbits(i);
--- a/sys/src/cmd/troff/t11.c
+++ b/sys/src/cmd/troff/t11.c
@@ -12,46 +12,54 @@
 
 Font	fonts[MAXFONTS+1];	/* font info + ptr to width info */
 
+static int	getlig(char **);
 
-#define	skipline(f)	while (getc(f) != '\n')
-
-#define	eq(s1, s2)	(strcmp(s1, s2) == 0)
-
 getdesc(char *name)
 {
 	FILE *fin;
-	char cmd[100], s[100];
-	int i, v;
+	char *cmd, *s;
+	char ln[128];
+	char *toks[50];
+	int i, v, ntok;
 
 	if ((fin = fopen(name, "r")) == NULL)
 		return -1;
-	while (fscanf(fin, "%s", cmd) != EOF) {
-		if (strcmp(cmd, "res") == 0) {
-			fscanf(fin, "%d", &Inch);
-		} else if (strcmp(cmd, "hor") == 0) {
-			fscanf(fin, "%d", &Hor);
-		} else if (strcmp(cmd, "vert") == 0) {
-			fscanf(fin, "%d", &Vert);
-		} else if (strcmp(cmd, "unitwidth") == 0) {
-			fscanf(fin, "%d", &Unitwidth);
-		} else if (strcmp(cmd, "sizes") == 0) {
+	while (fgets(ln, sizeof ln, fin) != NULL) {
+		memset(toks, 0, sizeof toks);
+		ntok = getfields(ln, toks, nelem(toks), 1, "\r\n\t ");
+		if (ntok == 0)
+			continue;
+		cmd = toks[0];
+		if (strcmp(cmd, "res") == 0)
+			Inch = atoi(toks[1]);
+		else if (strcmp(cmd, "hor") == 0)
+			Hor = atoi(toks[1]);
+		else if (strcmp(cmd, "vert") == 0)
+			Vert = atoi(toks[1]);
+		else if (strcmp(cmd, "unitwidth") == 0)
+			Unitwidth = atoi(toks[1]);
+		else if (strcmp(cmd, "sizes") == 0) {
 			nsizes = 0;
-			while (fscanf(fin, "%d", &v) != EOF && v != 0 && nsizes < MAXPS)
+			while (toks[nsizes+1] && (v = atoi(toks[nsizes+1])) != 0 &&
+			    nsizes < MAXPS)
 				pstab[nsizes++] = v;
 		} else if (strcmp(cmd, "fonts") == 0) {
-			fscanf(fin, "%d", &nfonts);
+			nfonts = atoi(toks[1]);
 			for (i = 1; i <= nfonts; i++) {
-				fscanf(fin, "%s", s);
+				s = toks[i+1];
 				fontlab[i] = PAIR(s[0], s[1]);
 			}
-		} else if (strcmp(cmd, "charset") == 0) {	/* add any names */
-			while (fscanf(fin, "%s", s) != EOF)
-				chadd(s, Troffchar, Install);
+		} else if (strcmp(cmd, "charset") == 0) {  /* add any names */
+			/* chew up any remaining lines */
+			while (fgets(ln, sizeof ln, fin) != NULL) {
+				ntok = getfields(ln, toks, nelem(toks), 1, "\r\n\t ");
+				for (i = 0; i < ntok; i++)
+					chadd(toks[i], Troffchar, Install);
+			}
 			break;
 		}
 		/* else 
 			just skip anything else */
-		skipline(fin);
 	}
 	fclose(fin);
 	return 1;
@@ -61,7 +69,8 @@
 {		/* in case it's not really a font description file */
 		/* really paranoid, but consider \f. */
 	FILE *fp;
-	char buf[300], buf2[300];
+	char *buf2, *p;
+	char buf[300];
 	int i, status = -1;
 
 	if ((fp = fopen(name, "r")) == NULL)
@@ -69,11 +78,13 @@
 	for (i = 1; i <= 10; i++) {
 		if (fgets(buf, sizeof buf, fp) == NULL)
 			break;
-		sscanf(buf, "%s", buf2);
+		buf2 = skipspace(buf);
 		if (buf2[0] == '#') {
 			i--;
 			continue;
 		}
+		p = skipword(buf2);
+		*p = '\0';
 		if (eq(buf2, "name") || eq(buf2, "fontname") ||
 		    eq(buf2, "special") || eq(buf2, "charset")) {
 			status = 1;
@@ -82,7 +93,6 @@
 	}
 	fclose(fp);
 	return status;
-	
 }
 
 getfont(char *name, int pos)	/* create width tab for font */
@@ -91,9 +101,14 @@
 	Font *ftemp = &fonts[pos];
 	Chwid chtemp[MAXCH];
 	static Chwid chinit;
-	int i, nw, n, wid, kern, code, type;
-	char buf[100], ch[100], s1[100], s2[100], s3[100], cmd[300];
+	int i, nw, n, wid, kern, code, ntok;
+	wchar_t wc;
+	char buf[128], ln[300], dummy[32];
+	char *toks[30];
+	char *ch, *cmd;
 
+	dummy[0] = '\0';
+	ch = dummy;
 	/* fprintf(stderr, "read font %s onto %d\n", name, pos); */
 	if (checkfont(name) == -1)
 		return -1;
@@ -102,55 +117,66 @@
 	for (i = 0; i < ALPHABET; i++)
 		chtemp[i] = chinit;	/* zero out to begin with */
 	ftemp->specfont = ftemp->ligfont = 0;
-	ftemp->defaultwidth = ftemp->spacewidth = Inch * Unitwidth / 72 / 3; /* should be rounded */
-	while (fscanf(fin, "%s", cmd) != EOF) {
+	ftemp->defaultwidth = ftemp->spacewidth = Inch * Unitwidth / 72 / 3;
+					/* should be rounded */
+	nw = code = kern = wid = 0;
+	while (fgets(ln, sizeof ln, fin) != NULL) {
+		memset(toks, 0, sizeof toks);
+		ntok = getfields(ln, toks, nelem(toks), 1, "\r\n\t ");
+		if (ntok == 0)
+			continue;
+		cmd = toks[0];
 		if (strcmp(cmd, "name") == 0)
-			fscanf(fin, "%s", ftemp->longname);
+			strcpy(ftemp->longname, toks[1]);
 		else if (strcmp(cmd, "special") == 0)
 			ftemp->specfont = 1;
-		else if (strcmp(cmd, "ligatures") == 0) {
-			ftemp->ligfont = getlig(fin);
-		} else if (strcmp(cmd, "spacewidth") == 0) {
-			fscanf(fin, "%d", &ftemp->spacewidth);
-		} else if (strcmp(cmd, "defaultwidth") == 0) {
-			fscanf(fin, "%d", &ftemp->defaultwidth);
-		} else if (strcmp(cmd, "charset") == 0) {
-			wchar_t wc;
-			skipline(fin);
+		else if (strcmp(cmd, "ligatures") == 0)
+			ftemp->ligfont = getlig(&toks[1]);
+		else if (strcmp(cmd, "spacewidth") == 0)
+			ftemp->spacewidth = atoi(toks[1]);
+		else if (strcmp(cmd, "defaultwidth") == 0)
+			ftemp->defaultwidth = atoi(toks[1]);
+		else if (strcmp(cmd, "charset") == 0) {
 			nw = ALPHABET;
 			while (fgets(buf, sizeof buf, fin) != NULL) {
-				sscanf(buf, "%s %s %s %s", ch, s1, s2, s3);
-				if (s1[0] != '"') {	/* genuine new character */
-					sscanf(s1, "%d", &wid);
-					sscanf(s2, "%d", &kern);
-					code = strtol(s3, 0, 0);	/* dec/oct/hex */
+				memset(toks, 0, sizeof toks);
+				ntok = getfields(buf, toks, 5, 1, "\r\n\t ");
+				if (ntok >= 4 &&
+				    toks[1][0] != '"') { /* genuine new character */
+					ch = toks[0];
+					wid = atoi(toks[1]);
+					kern = atoi(toks[2]);
+					code = atoi(toks[3]);  /* dec/oct/hex */
+					/* toks[4] is char name */
 				}
-				/* otherwise it's a synonym for prev character, */
-				/* so leave previous values intact */
+				/*
+				 * otherwise it's a synonym for prev character,
+				 * so leave previous values intact.
+				 */
 
-
 				/* decide what kind of alphabet it might come from here */
 
-
-				if (strlen(ch) == 1) {	/* it's ascii */
-					n = ch[0];	/* origin includes non-graphics */
-					chtemp[n].num = ch[0];
+				if (ch[0] && ch[1] == '\0') {	/* it's ascii */
+					n = ch[0] & 0xff; /* origin includes non-graphics */
+					chtemp[n].num = n;
 				} else if (ch[0] == '\\' && ch[1] == '0') {
 					n = strtol(ch+1, 0, 0);	/* \0octal or \0xhex */
 					chtemp[n].num = n;
 #ifdef UNICODE
 				} else if (mbtowc(&wc, ch, strlen(ch)) > 1) {
-					chtemp[nw].num = chadd(ch,  MBchar, Install);
+					chtemp[nw].num = chadd(ch, MBchar, Install);
 					n = nw;
 					nw++;
 #endif	/*UNICODE*/
 				} else {
 					if (strcmp(ch, "---") == 0) { /* no name */
-						sprintf(ch, "%d", code);
-						type = Number;
+						snprintf(dummy, sizeof dummy,
+							"%d", code);
+						ch = dummy;
+						n = chadd(ch, Number, Install);
 					} else
-						type = Troffchar;
-					chtemp[nw].num = chadd(ch, type, Install);
+						n = chadd(ch, Troffchar, Install);
+					chtemp[nw].num = n;
 					n = nw;
 					nw++;
 				}
@@ -163,13 +189,12 @@
 			}
 			break;
 		}
-		skipline(fin);
 	}
 	fclose(fin);
-	chtemp[' '].wid = ftemp->spacewidth;	/* width of space on this font */
+	chtemp[' '].wid = ftemp->spacewidth;  /* width of space on this font */
 	ftemp->nchars = nw;
 	if (ftemp->wp)
-		free(ftemp->wp);	/* god help us if this wasn't allocated */
+		free(ftemp->wp);  /* god help us if this wasn't allocated */
 	ftemp->wp = (Chwid *) malloc(nw * sizeof(Chwid));
 	if (ftemp->wp == NULL)
 		return -1;
@@ -200,12 +225,13 @@
 
 /* fprintf(stderr, "into chadd %s %c %c\n", s, type, install); /* */
 	for (i = 0; i < nchnames; i++)
-		if (type == chnames[i][0] && eq(s, chnames[i]+1)) /* +1 since type at front */
+		/* +1 since type at front */
+		if (type == chnames[i][0] && eq(s, chnames[i]+1))
 			break;
 /* fprintf(stderr, "i %d, nchnames %d\n", i, nchnames); /* */
-	if (i < nchnames)		/* found same type and bytes at position i */
+	if (i < nchnames)	/* found same type and bytes at position i */
 		return ALPHABET + i;
-	else if (install == Lookup)	/* not found, and we were just looking */
+	else if (install == Lookup)  /* not found, and we were just looking */
 		return -1;
 
 	chnames[nchnames] = p = (char *) malloc(strlen(s)+1+1);	/* type + \0 */
@@ -231,13 +257,15 @@
 		return "";
 }
 
-getlig(FILE *fin)	/* pick up ligature list */
+static int
+getlig(char **toks)	/* pick up ligature list. e.g., "ligatures ff fi 0" */
 {
-	int lig;
-	char temp[200];
+	int lig, i;
+	char *temp;
 
 	lig = 0;
-	while (fscanf(fin, "%s", temp) != EOF && strcmp(temp, "0") != 0) {
+	for (i = 0; toks[i] && strcmp(toks[i], "0") != 0; i++) {
+		temp = toks[i];
 		if (strcmp(temp, "fi") == 0)
 			lig |= LFI;
 		else if (strcmp(temp, "fl") == 0)
--- a/sys/src/cmd/troff/t6.c
+++ b/sys/src/cmd/troff/t6.c
@@ -96,7 +96,7 @@
 	/* maybe it was a \N... */
 	np = chname(n);
 	if (*np == Number) {
-		i = atoi(np+1);		/* sscanf(np+1, "%d", &i); */
+		i = atoi(np+1);
 		cp = &fp->wp[0];
 		ep = &fp->wp[fp->nchars];
 		for ( ; cp < ep; cp++) {	/* search others */
@@ -214,7 +214,6 @@
 
 Tchar t_setch(int c)
 {
-	int j;
 	char temp[50];
 	char *s;
 
@@ -228,19 +227,18 @@
 			s++;
 	}
 	*s = '\0';
-#ifdef UNICODE
-	return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
-#else
+#ifndef UNICODE
 	if (NROFF) {
+		int j;
+
 		j = chadd(temp, Troffchar, Lookup);
-		if ( j == -1)
+		if (j == -1)
 			return 0;
 		else
 			return j | chbits;
-	} else
-		return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
-		
+	}
 #endif /*UNICODE*/
+	return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
 }
 
 Tchar t_setabs(void)		/* set absolute char from \N'...' */
@@ -254,7 +252,7 @@
 	getch();	/* delim */
 	if (nonumb)
 		return 0;
-	sprintf(temp, "%d", n);	/* convert into "#n" */
+	snprintf(temp, sizeof temp, "%d", n);	/* convert into "#n" */
 	n = chadd(temp, Number, Install);
 	return n | chbits;
 }
@@ -397,6 +395,7 @@
 	int i, j;
 
 	i = cbits(getch());
+	j = i;				/* make compiler happy */
 	if (isdigit(i)) {		/* \sd or \sdd */
 		i -= '0';
 		if (i == 0)		/* \s0 */
@@ -703,9 +702,9 @@
 	return t;
 }
 
-setfp(int pos, int f, char *truename, int print)	/* mount font f at position pos[0...nfonts] */
+setfp(int pos, int f, char *truename, int doprint)	/* mount font f at position pos[0...nfonts] */
 {
-	char pathname[NS], shortname[NS], *sl;
+	char pathname[NS], shortname[NS];
 
 	zapwcache(0);
 	if (truename)
@@ -730,7 +729,7 @@
 		ERROR "Can't open font file %s", pathname WARN;
 		return -1;
 	}
-	if (print && !ascii) {
+	if (doprint && !ascii) {
 		ptfpcmd(pos, fonts[pos].longname, truename);
 		ptfont();
 	}
@@ -785,7 +784,7 @@
 		return;
 	}
 	zapwcache(0);
-	k = 0;
+	j = k = 0;
 bd0:
 	if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
 		if (k)
--- a/sys/src/cmd/troff/tdef.h
+++ b/sys/src/cmd/troff/tdef.h
@@ -1,8 +1,7 @@
+#include <u.h>
+#include <libc.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
 #include <ctype.h>
-#include <string.h>
 
 #define	NROFF	(!TROFF)
 
@@ -19,16 +18,18 @@
 #define NTERMDIR	"lib/term/tab."
 #endif
 #ifndef TDEVNAME
-#define TDEVNAME	"post"
+#define TDEVNAME	"utf"		/* was "post" */
 #endif
 #ifndef NDEVNAME
-#define NDEVNAME	"37"
+#define NDEVNAME	"utf"		/* was "37" */
 #endif
 #ifndef TEXHYPHENS
-#define	TEXHYPHENS	"/usr/lib/tex/macros/hyphen.tex"
+#define	TEXHYPHENS	"sys/lib/texmf/tex/generic/hyphen/hyphen.tex"
+			/* was "/usr/lib/tex/macros/hyphen.tex" */
 #endif
 #ifndef ALTHYPHENS
-#define	ALTHYPHENS	"lib/tmac/hyphen.tex"	/* another place to look */
+#define	ALTHYPHENS	TEXHYPHENS
+			/* was "lib/tmac/hyphen.tex"  /* another place to look */
 #endif
 
 typedef	unsigned char	Uchar;
@@ -52,18 +53,14 @@
 typedef	struct	Tbuf	Tbuf;
 
 /* this simulates printf into a buffer that gets flushed sporadically */
-/* the BSD goo is because SunOS sprintf doesn't return anything useful */
 
-#ifdef BSD4_2
-#define	OUT		(obufp += strlen(sprintf(obufp,
-#define	PUT		))) > obuf+BUFSIZ ? flusho() : 1
-#else
-#define	OUT		(obufp += sprintf(obufp,
+#define	OUT		junk = (obufp += sprintf(obufp,
 #define	PUT		)) > obuf+BUFSIZ ? flusho() : 1
-#endif
 
+int junk;
+
 #define	oputs(a)	OUT "%s", a PUT
-#define	oput(c)		( *obufp++ = (c), obufp > obuf+BUFSIZ ? flusho() : 1 )
+#define	oput(c)		junk = (*obufp++ = (c), obufp > obuf+BUFSIZ? flusho(): 1)
 
 extern	char	errbuf[];
 #define	ERROR	sprintf(errbuf,
@@ -270,6 +267,7 @@
 #define	SHORTMASK 0XFFFF
 #define	SHORT	 16
 
+#define INT_MAX	(~0u >> 1)
 #define	TABMASK	 ((unsigned) INT_MAX >> 1)
 #define	RTAB	((TABMASK << 1) & ~TABMASK)
 #define	CTAB	(RTAB << 1)
@@ -668,3 +666,15 @@
 	char	escarg;	/* argument of esc's like \D'l' */
 	unsigned int	req;	/* was request or macro named req */
 };
+
+/* import from unix */
+#define MB_CUR_MAX UTFmax
+#define wchar_t	Rune
+
+#define exit(n)		exits((n) == 0? nil: "error")
+#define wctomb(s, wc)	runetochar(s, &(wc))
+
+int	mbtowc(Rune *, char *, int);
+int	system(char *);
+char	*skipspace(char *);
+char	*skipword(char *);
--