Commit Diff


commit - 76e6aca867e3e48ea04fbcf7284c45369a69829e
commit + 5cedca1b69d020c32466f70843a11767773d7e3b
blob - /dev/null
blob + 10dc8c75c0d6ab96a6106fba5dd4ce2aaf902ad7 (mode 644)
--- /dev/null
+++ src/cmd/eqn/diacrit.c
@@ -0,0 +1,75 @@
+#include "e.h"
+#include "y.tab.h"
+
+extern double Dvshift, Dhshift, Dh2shift, Dheight, Barv, Barh, Ubarv, Ubarh;
+
+void diacrit(int p1, int type)
+{
+	int c, t;
+
+	c = salloc();
+	t = salloc();
+	nrwid(p1, ps, p1);
+	printf(".nr 10 %gm\n", max(REL(eht[p1]-ebase[p1]-1,ps), 0));	/* vert shift if high */
+	if (type == HIGHBAR)
+		printf(".nr 10 \\n(10+%gm\n", Dvshift);
+	else if (type == LOWBAR)
+		printf(".nr 10 0\n");
+	else
+		printf(".if \\n(ct>1 .nr 10 \\n(10+%gm\n", Dvshift);
+	printf(".nr %d %gm\n", t, Dhshift);	/* horiz shift if high */
+	printf(".if \\n(ct>1 .nr %d %gm\n", t, Dh2shift);	/* was .1 and .15 */
+	switch (type) {
+	case VEC:
+		printf(".ds %d %s\n", c, lookup(deftbl, "vec_def")->cval);
+		break;
+	case DYAD:
+		printf(".ds %d %s\n", c, lookup(deftbl, "dyad_def")->cval);
+		break;
+	case HAT:
+		printf(".ds %d %s\n", c, lookup(deftbl, "hat_def")->cval);
+		break;
+	case TILDE:
+		printf(".ds %d %s\n", c, lookup(deftbl, "tilde_def")->cval);
+		break;
+	case DOT:
+		printf(".ds %d %s\n", c, lookup(deftbl, "dot_def")->cval);
+		break;
+	case DOTDOT:
+		printf(".ds %d %s\n", c, lookup(deftbl, "dotdot_def")->cval);
+		break;
+	case BAR:
+	case LOWBAR:
+	case HIGHBAR:
+		printf(".ds %d \\v'%gm'\\h'%gm'\\l'\\n(%du-%gm'\\h'%gm'\\v'%gm'\n",
+			c, -Barv, Barh, p1, 2*Barh, Barh, Barv);
+		break;
+	case UNDER:
+		printf(".ds %d \\v'%gm'\\l'\\n(%du-%gm\\(ul'\\h'%gm'\\v'%gm'\n",
+			c, -Ubarv, p1, Ubarh, Ubarh, Ubarv);
+		/* printf(".ds %d \\v'-%gm'\\l'\\n(%du\\(ul'\\v'%gm'\n",
+			c, Ubarv, p1, Ubarv);
+		*/
+		printf(".nr %d 0\n", t);
+		printf(".nr 10 0-.1m-%gm\n", REL(ebase[p1],ps));
+		printf(".if \\n(ct%%2=1 .nr 10 0\\n(10-.1m\n");
+		break;
+	case UTILDE:
+		printf(".ds %d %s\n", c, lookup(deftbl, "utilde_def")->cval);
+		printf(".nr %d 0\n", t);
+		printf(".nr 10 0-%gm\n", REL(ebase[p1],ps));
+		printf(".if \\n(ct%%2=1 .nr 10 0\\n(10-%gm\n", 0.1);
+		break;
+	}
+	nrwid(c, ps, c);
+	if (lfont[p1] != ITAL)
+		printf(".nr %d 0\n", t);
+	printf(".as %d \\h'-\\n(%du-\\n(%du/2u+\\n(%du'\\v'0-\\n(10u'\\*(%d", 
+		p1, p1, c, t, c);
+	printf("\\v'\\n(10u'\\h'-\\n(%du+\\n(%du/2u-\\n(%du'\n", c, p1, t);
+	if (type != UNDER && type != UTILDE)
+		eht[p1] += EM(Dheight, ps);	/* was .15 */
+	dprintf(".\tdiacrit: %c over S%d, lf=%c, rf=%c, h=%g, b=%g\n",
+		type, p1, lfont[p1], rfont[p1], eht[p1], ebase[p1]);
+	sfree(c); sfree(t);
+}
blob - /dev/null
blob + 70c47023b16c0470779bca25f15f37314f8cceb8 (mode 644)
--- /dev/null
+++ src/cmd/eqn/e.h
@@ -0,0 +1,166 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum charclass {
+	OTHER, OLET, ILET, DIG, LPAR, RPAR, SLASH, PLUS, ILETF, ILETJ, VBAR,
+	NONE, LAST
+};
+extern int class[LAST][LAST];
+
+#define	dprintf		if (dbg) printf
+#define	max(x,y)	(((x) >= (y)) ? (x) : (y))	/* beware of side effects */
+#define	min(x,y)	(((x) <= (y)) ? (x) : (y))
+
+extern	char	errbuf[200];
+extern	char	*cmdname;
+#define	ERROR	sprintf(errbuf,
+#define	FATAL	), error(1, errbuf)
+#define	WARNING	), error(0, errbuf)
+#define	SYNTAX	), yyerror(errbuf)
+
+#define	ROM	'1'
+#define	ITAL	'2'
+#define	BLD	'3'
+#define	BDIT	'4'
+
+#define	DEFGAP	-999	/* default gap in piles */
+
+extern int	dbg;
+extern int	ct;
+extern int	lp[];
+extern int	used[];		/* available registers */
+extern int	ps;		/* dflt init pt size */
+extern int	deltaps;	/* default change in ps */
+extern int	dps_set;	/* 1 => -p option used */
+extern int	gsize;		/* global size */
+extern int	ft;		/* default font */
+extern int	display;	/* 1 => inline, 0 => .EQ/.EN */
+extern int	synerr;		/* 1 if syntax error in this eqn */
+
+extern char	*typesetter;	/* typesetter name for -T... */
+extern int	minsize;	/* min size it can print */
+extern int	ttype;		/* actual type of typesetter: */
+
+#define	DEVCAT	1
+#define	DEV202	2
+#define	DEVAPS	3
+#define	DEVPOST	4
+
+extern double	eht[];
+extern double	ebase[];
+extern int	lfont[];
+extern int	rfont[];
+extern int	lclass[];
+extern int	rclass[];
+extern int	yyval;
+extern int	yylval;
+extern int	eqnreg;
+extern double	eqnht;
+extern int	lefteq, righteq;
+extern int	markline;	/* 1 if this EQ/EN contains mark or lineup */
+
+#define	TBLSIZE	100
+
+typedef struct s_tbl {
+	char	*name;		/* e.g., "max" or "sum" */
+	char	*cval;		/* e.g., "\\f1max\\fP" */
+	int	ival;		/*    or SUM */
+	struct s_tbl *next;
+} tbl;
+
+extern	char	*spaceval;	/* use in place of normal \x (for pic) */
+
+#define	String	01
+#define	Macro	02
+#define	File	04
+#define	Char	010
+#define	Free	040
+
+typedef struct infile {
+	FILE	*fin;
+	char	*fname;
+	int	lineno;
+} Infile;
+
+typedef struct {	/* input source */
+	int	type;	/* Macro, String, File */
+	char	*sp;	/* if String or Macro */
+} Src;
+
+extern	Src	src[], *srcp;	/* input source stack */
+
+#define	MAXARGS	20
+typedef struct {	/* argument stack */
+	char	*argstk[MAXARGS];	/* pointers to args */
+	char	*argval;	/* points to space containing args */
+} Arg;
+
+typedef struct {	/* font number and name */
+	int	ft;
+	char	name[10];
+} Font;
+
+extern	Font	ftstack[];
+extern	Font	*ftp;
+
+extern	int	szstack[];
+extern	int	nszstack;
+
+extern	Infile	infile[10];
+extern	Infile	*curfile;
+
+extern	tbl	*lookup(tbl **tblp, char *name);
+extern	void	install(tbl **tblp, char *name, char *cval, int ival);
+extern	tbl	*keytbl[], *deftbl[], *restbl[], *ftunetbl[];
+
+extern	int	salloc(void);
+extern	void	sfree(int);
+extern	void	nrwid(int, int, int);
+extern	char	*ABSPS(int);
+extern	char	*DPS(int, int);
+extern	int	EFFPS(int);
+extern	double	EM(double, int);
+extern	double	REL(double, int);
+extern	char	*pad(int);
+extern	void	getstr(char *, int);
+extern	char	*strsave(char *);
+
+extern	int	input(void);
+extern	int	unput(int);
+extern	void	pbstr(char *);
+extern	void	error(int, char *);
+extern	void	yyerror(char *);
+
+extern	void	diacrit(int, int);
+extern	void	eqnbox(int, int, int);
+extern	void	setfont(char *);
+extern	void	font(int, int);
+extern	void	globfont(void);
+extern	void	fatbox(int);
+extern	void	fromto(int, int, int);
+extern	void	funny(int);
+extern	void	integral(int, int, int);
+extern	void	setintegral(void);
+extern	void	pushsrc(int, char *);
+extern	void	popsrc(void);
+extern	void	putout(int);
+extern	void	text(int, char *);
+extern void subsup(int, int, int);
+extern void bshiftb(int, int, int);
+extern void shift2(int, int, int);
+extern void setsize(char *);
+extern void size(int, int);
+extern void globsize(void);
+#define sqrt esqrt
+extern void sqrt(int);
+extern void text(int, char *);
+extern void boverb(int, int);
+extern void lineup(int);
+extern void mark(int);
+extern void paren(int, int, int);
+extern void move(int, int, int);
+extern void pile(int);
+extern int startcol(int);
+extern void column(int, int);
+extern void matrix(int);
blob - /dev/null
blob + 527e5e084d4fb8e08b685be74388fe76943d3b8b (mode 644)
--- /dev/null
+++ src/cmd/eqn/eqn.c
@@ -0,0 +1,741 @@
+#define	CONTIG	57346
+#define	QTEXT	57347
+#define	SPACE	57348
+#define	THIN	57349
+#define	TAB	57350
+#define	MATRIX	57351
+#define	LCOL	57352
+#define	CCOL	57353
+#define	RCOL	57354
+#define	COL	57355
+#define	ABOVE	57356
+#define	MARK	57357
+#define	LINEUP	57358
+#define	SUM	57359
+#define	INT	57360
+#define	PROD	57361
+#define	UNION	57362
+#define	INTER	57363
+#define	DEFINE	57364
+#define	TDEFINE	57365
+#define	NDEFINE	57366
+#define	DELIM	57367
+#define	GSIZE	57368
+#define	GFONT	57369
+#define	INCLUDE	57370
+#define	IFDEF	57371
+#define	DOTEQ	57372
+#define	DOTEN	57373
+#define	FROM	57374
+#define	TO	57375
+#define	OVER	57376
+#define	SQRT	57377
+#define	SUP	57378
+#define	SUB	57379
+#define	SIZE	57380
+#define	FONT	57381
+#define	ROMAN	57382
+#define	ITALIC	57383
+#define	BOLD	57384
+#define	FAT	57385
+#define	UP	57386
+#define	DOWN	57387
+#define	BACK	57388
+#define	FWD	57389
+#define	LEFT	57390
+#define	RIGHT	57391
+#define	DOT	57392
+#define	DOTDOT	57393
+#define	HAT	57394
+#define	TILDE	57395
+#define	BAR	57396
+#define	LOWBAR	57397
+#define	HIGHBAR	57398
+#define	UNDER	57399
+#define	VEC	57400
+#define	DYAD	57401
+#define	UTILDE	57402
+
+#line	17	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+#include "e.h"
+
+int	yylex(void);
+extern	int	yyerrflag;
+#ifndef	YYMAXDEPTH
+#define	YYMAXDEPTH	150
+#endif
+#ifndef	YYSTYPE
+#define	YYSTYPE	int
+#endif
+YYSTYPE	yylval;
+YYSTYPE	yyval;
+#define YYEOFCODE 1
+#define YYERRCODE 2
+
+#line	140	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+
+short	yyexca[] =
+{-1, 0,
+	1, 3,
+	-2, 0,
+-1, 1,
+	1, -1,
+	-2, 0,
+};
+#define	YYNPROD	90
+#define	YYPRIVATE 57344
+#define	YYLAST	469
+short	yyact[] =
+{
+   4, 103, 119,  45,  27, 118, 104,   2, 102,  41,
+  42,  43,  44,  65,  80,  81,  79,  66,  67,  68,
+  69,  70,  50,  49,  74,  75,  76,  77, 105,  73,
+  40,  80,  81,  80,  81, 114,  61,  64,  54,  62,
+  57,  58,  59,  60,  55,  56,  63,  78,  91,  92,
+  82,  26,  83,  85,  86,  87,  88,  90,  51,  52,
+  48, 124,  50,  49, 117,  25,  45, 117,  72,  71,
+  80,  81, 113,  24,  45,  23,  61,  64,  54,  62,
+  57,  58,  59,  60,  55,  56,  63,  53,  89, 100,
+  84,  22,  96,  95, 106, 107, 108, 109,  99, 110,
+ 111,  41,  42,  43,  44,  45,  98, 115,  21,  94,
+  93,  18, 130, 123,  17, 116, 121,  46, 112, 125,
+ 127, 128,   1, 129, 126,   0,   0,  45,   8,   7,
+   9,  10,  11,  28,  41,  42,  43,  44,   0,  16,
+  47,  12,  34,  13,  14,  15,  61,  64,  54,  62,
+  57,  58,  59,  60,  55,  56,  63,   0,   0,  20,
+   0,   0,  29,  33,  30,  31,  32,  19,  37,  39,
+  38,  36,  35,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   6,  97,   8,   7,   9,
+  10,  11,  28,  41,  42,  43,  44,   0,  16,  47,
+  12,  34,  13,  14,  15,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,  20,   0,
+   0,  29,  33,  30,  31,  32,  19,  37,  39,  38,
+  36,  35, 101,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   3,   6,   8,   7,   9,  10,  11,
+  28,  41,  42,  43,  44,   0,  16,   5,  12,  34,
+  13,  14,  15,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,  20,   0,   0,  29,
+  33,  30,  31,  32,  19,  37,  39,  38,  36,  35,
+   0,   0,   8,   7,   9,  10,  11,  28,  41,  42,
+  43,  44,   6,  16,  47,  12,  34,  13,  14,  15,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,  20,   0,   0,  29,  33,  30,  31,
+  32,  19,  37,  39,  38,  36,  35,   0,   0,   8,
+   7,   9,  10,  11,  28,  41,  42,  43,  44,   6,
+  16,   5,  12,  34,  13,  14,  15,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  20,   0,   0,  29,  33,  30,  31,  32,  19,  37,
+  39,  38,  36,  35,   8,   7,   9,  10,  11,  28,
+  41,  42,  43,  44,   0,  16,   6,  12,  34,  13,
+  14,  15,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,  20,   0,   0,  29,  33,
+  30,  31,  32,  19,  37,  39,  38,  36,  35,  51,
+ 122,  48,   0,  50,  49,   0,   0,   0,   0,   0,
+   0,   6,   0,   0, 120,  49,   0,  61,  64,  54,
+  62,  57,  58,  59,  60,  55,  56,  63,  61,  64,
+  54,  62,  57,  58,  59,  60,  55,  56,  63
+};
+short	yypact[] =
+{
+ 241,-1000, 288,-1000,  26,-1000, 335,-1000,-1000,-1000,
+-1000,-1000,-1000,-1000,-1000,-1000, 380, 380, 380, 380,
+ 380,  32, 335, 380, 380, 380, 380,-1000,-1000,  66,
+-1000,-1000,-1000,  66,-1000,  29,  66,  66,  66,  66,
+  27,-1000,-1000,-1000,-1000,  26,-1000, 380, 380,-1000,
+-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
+-1000,-1000,-1000,-1000,-1000, 124,  26,  96,  96,  96,
+ -14,-1000,-1000, 183,  96,  96,  96,  96, -53,-1000,
+-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, 335,
+-1000,  26, -14, 380, 380, 380, 380,-1000, 380, 380,
+-1000,  10,  91,  53, 288, -56, 408, -14, 397,  26,
+ 408, -14,-1000,-1000,  -1,-1000,-1000, 335, 335,-1000,
+ 380,-1000, 380,-1000,-1000,-1000, 288,  50, -14,  26,
+-1000
+};
+short	yypgo[] =
+{
+   0, 122,   6,   0, 117,   2, 116, 114, 111, 110,
+ 109, 108, 106,  98,  93,  92,  91,  89,  87,  75,
+  73,  65,  51,   4,  47,  35,  16,  30,   1,  28
+};
+short	yyr1[] =
+{
+   0,   1,   1,   1,   2,   2,   2,   2,   4,   5,
+   5,   6,   6,   3,   3,   3,   3,   3,   3,   3,
+   3,   3,   3,   3,   3,   3,   3,   3,   3,   9,
+   3,  10,   3,  12,   3,  13,   3,   3,  14,   3,
+  15,   3,   3,   3,   3,   3,   3,   3,   3,   3,
+  24,   3,  11,  19,  20,  21,  22,  18,  18,  18,
+  18,  18,  18,  18,  18,  18,  18,  18,  16,  16,
+  17,  17,  25,  25,  23,  29,  23,  27,  27,  27,
+  27,  28,  28,   7,   8,   8,   8,   8,  26,  26
+};
+short	yyr2[] =
+{
+   0,   1,   1,   0,   1,   2,   2,   1,   2,   2,
+   0,   2,   0,   3,   1,   1,   1,   1,   1,   1,
+   1,   1,   1,   3,   2,   2,   2,   2,   2,   0,
+   5,   0,   4,   0,   5,   0,   4,   1,   0,   5,
+   0,   4,   3,   2,   2,   2,   2,   2,   2,   1,
+   0,   5,   1,   2,   2,   2,   2,   1,   1,   1,
+   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,
+   2,   2,   1,   2,   4,   0,   6,   1,   1,   1,
+   1,   1,   3,   2,   1,   1,   1,   2,   1,   1
+};
+short	yychk[] =
+{
+-1000,  -1,  -2,   2,  -3,  16,  61,   5,   4,   6,
+   7,   8,  17,  19,  20,  21,  15,  -7,  -8,  43,
+  35, -11, -16, -19, -20, -21, -22, -23,   9,  38,
+  40,  41,  42,  39,  18,  48,  47,  44,  46,  45,
+ -27,  10,  11,  12,  13,  -3,  -4,  16,  34,  37,
+  36,  32,  33, -18,  52,  58,  59,  54,  55,  56,
+  57,  50,  53,  60,  51,  -2,  -3,  -3,  -3,  -3,
+  -3,  37,  36,  -2,  -3,  -3,  -3,  -3, -24, -26,
+   4,   5, -26, -26,  61, -26, -26, -26, -26,  61,
+ -26,  -3,  -3,  -9, -10, -14, -15,  62, -12, -13,
+ -17,  49,  61, -28,  -2, -29,  -3,  -3,  -3,  -3,
+  -3,  -3, -26,  62, -25, -23,  62,  14,  61,  -5,
+  36,  -6,  33,  -5,  62, -23,  -2, -28,  -3,  -3,
+  62
+};
+short	yydef[] =
+{
+  -2,  -2,   1,   2,   4,   7,   0,  14,  15,  16,
+  17,  18,  19,  20,  21,  22,   0,   0,   0,   0,
+   0,  37,   0,   0,   0,   0,   0,  49,  50,   0,
+  84,  85,  86,   0,  52,   0,   0,   0,   0,   0,
+   0,  77,  78,  79,  80,   5,   6,   0,   0,  29,
+  31,  38,  40,  44,  57,  58,  59,  60,  61,  62,
+  63,  64,  65,  66,  67,   0,  24,  25,  26,  27,
+  28,  33,  35,  43,  45,  46,  47,  48,   0,  83,
+  88,  89,  87,  68,  69,  53,  54,  55,  56,   0,
+  75,   8,  23,   0,   0,   0,   0,  13,   0,   0,
+  42,   0,   0,   0,  81,   0,  10,  32,  12,  41,
+  10,  36,  70,  71,   0,  72,  74,   0,   0,  30,
+   0,  39,   0,  34,  51,  73,  82,   0,   9,  11,
+  76
+};
+short	yytok1[] =
+{
+   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,  61,   0,  62
+};
+short	yytok2[] =
+{
+   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,
+  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,
+  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
+  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
+  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,
+  52,  53,  54,  55,  56,  57,  58,  59,  60
+};
+long	yytok3[] =
+{
+   0
+};
+#define YYFLAG 		-1000
+#define YYERROR		goto yyerrlab
+#define YYACCEPT	return(0)
+#define YYABORT		return(1)
+#define	yyclearin	yychar = -1
+#define	yyerrok		yyerrflag = 0
+
+#ifdef	yydebug
+#include	"y.debug"
+#else
+#define	yydebug		0
+char*	yytoknames[1];		/* for debugging */
+char*	yystates[1];		/* for debugging */
+#endif
+
+/*	parser for yacc output	*/
+
+int	yynerrs = 0;		/* number of errors */
+int	yyerrflag = 0;		/* error recovery flag */
+
+char*
+yytokname(int yyc)
+{
+	static char x[10];
+
+	if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
+	if(yytoknames[yyc-1])
+		return yytoknames[yyc-1];
+	sprintf(x, "<%d>", yyc);
+	return x;
+}
+
+char*
+yystatname(int yys)
+{
+	static char x[10];
+
+	if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
+	if(yystates[yys])
+		return yystates[yys];
+	sprintf(x, "<%d>\n", yys);
+	return x;
+}
+
+long
+yylex1(void)
+{
+	long yychar;
+	long *t3p;
+	int c;
+
+	yychar = yylex();
+	if(yychar <= 0) {
+		c = yytok1[0];
+		goto out;
+	}
+	if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
+		c = yytok1[yychar];
+		goto out;
+	}
+	if(yychar >= YYPRIVATE)
+		if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
+			c = yytok2[yychar-YYPRIVATE];
+			goto out;
+		}
+	for(t3p=yytok3;; t3p+=2) {
+		c = t3p[0];
+		if(c == yychar) {
+			c = t3p[1];
+			goto out;
+		}
+		if(c == 0)
+			break;
+	}
+	c = 0;
+
+out:
+	if(c == 0)
+		c = yytok2[1];	/* unknown char */
+	if(yydebug >= 3)
+		printf("lex %.4lX %s\n", yychar, yytokname(c));
+	return c;
+}
+
+int
+yyparse(void)
+{
+	struct
+	{
+		YYSTYPE	yyv;
+		int	yys;
+	} yys[YYMAXDEPTH], *yyp, *yypt;
+	short *yyxi;
+	int yyj, yym, yystate, yyn, yyg;
+	YYSTYPE save1, save2;
+	int save3, save4;
+	long yychar;
+
+	save1 = yylval;
+	save2 = yyval;
+	save3 = yynerrs;
+	save4 = yyerrflag;
+
+	yystate = 0;
+	yychar = -1;
+	yynerrs = 0;
+	yyerrflag = 0;
+	yyp = &yys[-1];
+	goto yystack;
+
+ret0:
+	yyn = 0;
+	goto ret;
+
+ret1:
+	yyn = 1;
+	goto ret;
+
+ret:
+	yylval = save1;
+	yyval = save2;
+	yynerrs = save3;
+	yyerrflag = save4;
+	return yyn;
+
+yystack:
+	/* put a state and value onto the stack */
+	if(yydebug >= 4)
+		printf("char %s in %s", yytokname(yychar), yystatname(yystate));
+
+	yyp++;
+	if(yyp >= &yys[YYMAXDEPTH]) {
+		yyerror("yacc stack overflow");
+		goto ret1;
+	}
+	yyp->yys = yystate;
+	yyp->yyv = yyval;
+
+yynewstate:
+	yyn = yypact[yystate];
+	if(yyn <= YYFLAG)
+		goto yydefault; /* simple state */
+	if(yychar < 0)
+		yychar = yylex1();
+	yyn += yychar;
+	if(yyn < 0 || yyn >= YYLAST)
+		goto yydefault;
+	yyn = yyact[yyn];
+	if(yychk[yyn] == yychar) { /* valid shift */
+		yychar = -1;
+		yyval = yylval;
+		yystate = yyn;
+		if(yyerrflag > 0)
+			yyerrflag--;
+		goto yystack;
+	}
+
+yydefault:
+	/* default state action */
+	yyn = yydef[yystate];
+	if(yyn == -2) {
+		if(yychar < 0)
+			yychar = yylex1();
+
+		/* look through exception table */
+		for(yyxi=yyexca;; yyxi+=2)
+			if(yyxi[0] == -1 && yyxi[1] == yystate)
+				break;
+		for(yyxi += 2;; yyxi += 2) {
+			yyn = yyxi[0];
+			if(yyn < 0 || yyn == yychar)
+				break;
+		}
+		yyn = yyxi[1];
+		if(yyn < 0)
+			goto ret0;
+	}
+	if(yyn == 0) {
+		/* error ... attempt to resume parsing */
+		switch(yyerrflag) {
+		case 0:   /* brand new error */
+			yyerror("syntax error");
+			if(yydebug >= 1) {
+				printf("%s", yystatname(yystate));
+				printf("saw %s\n", yytokname(yychar));
+			}
+yyerrlab:
+			yynerrs++;
+
+		case 1:
+		case 2: /* incompletely recovered error ... try again */
+			yyerrflag = 3;
+
+			/* find a state where "error" is a legal shift action */
+			while(yyp >= yys) {
+				yyn = yypact[yyp->yys] + YYERRCODE;
+				if(yyn >= 0 && yyn < YYLAST) {
+					yystate = yyact[yyn];  /* simulate a shift of "error" */
+					if(yychk[yystate] == YYERRCODE)
+						goto yystack;
+				}
+
+				/* the current yyp has no shift onn "error", pop stack */
+				if(yydebug >= 2)
+					printf("error recovery pops state %d, uncovers %d\n",
+						yyp->yys, (yyp-1)->yys );
+				yyp--;
+			}
+			/* there is no state on the stack with an error shift ... abort */
+			goto ret1;
+
+		case 3:  /* no shift yet; clobber input char */
+			if(yydebug >= YYEOFCODE)
+				printf("error recovery discards %s\n", yytokname(yychar));
+			if(yychar == YYEOFCODE)
+				goto ret1;
+			yychar = -1;
+			goto yynewstate;   /* try again in the same state */
+		}
+	}
+
+	/* reduction by production yyn */
+	if(yydebug >= 2)
+		printf("reduce %d in:\n\t%s", yyn, yystatname(yystate));
+
+	yypt = yyp;
+	yyp -= yyr2[yyn];
+	yyval = (yyp+1)->yyv;
+	yym = yyn;
+
+	/* consult goto table to find next state */
+	yyn = yyr1[yyn];
+	yyg = yypgo[yyn];
+	yyj = yyg + yyp->yys + 1;
+
+	if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+		yystate = yyact[yyg];
+	switch(yym) {
+		
+case 1:
+#line	24	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ putout(yypt[-0].yyv); } break;
+case 2:
+#line	25	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ ERROR "syntax error" WARNING; } break;
+case 3:
+#line	26	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ eqnreg = 0; } break;
+case 5:
+#line	30	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ eqnbox(yypt[-1].yyv, yypt[-0].yyv, 0); } break;
+case 6:
+#line	31	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ eqnbox(yypt[-1].yyv, yypt[-0].yyv, 1); } break;
+case 7:
+#line	32	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ lineup(0); } break;
+case 8:
+#line	35	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-0].yyv; lineup(1); } break;
+case 9:
+#line	38	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-0].yyv; } break;
+case 10:
+#line	39	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = 0; } break;
+case 11:
+#line	42	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-0].yyv; } break;
+case 12:
+#line	43	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = 0; } break;
+case 13:
+#line	46	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-1].yyv; } break;
+case 14:
+#line	47	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(QTEXT, (char *) yypt[-0].yyv); } break;
+case 15:
+#line	48	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(CONTIG, (char *) yypt[-0].yyv); } break;
+case 16:
+#line	49	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(SPACE, (char *) 0); } break;
+case 17:
+#line	50	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(THIN, (char *) 0); } break;
+case 18:
+#line	51	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(TAB, (char *) 0); } break;
+case 19:
+#line	52	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(SUM); } break;
+case 20:
+#line	53	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(PROD); } break;
+case 21:
+#line	54	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(UNION); } break;
+case 22:
+#line	55	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(INTER); } break;
+case 23:
+#line	56	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ boverb(yypt[-2].yyv, yypt[-0].yyv); } break;
+case 24:
+#line	57	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ mark(yypt[-0].yyv); } break;
+case 25:
+#line	58	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ size(yypt[-1].yyv, yypt[-0].yyv); } break;
+case 26:
+#line	59	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ font(yypt[-1].yyv, yypt[-0].yyv); } break;
+case 27:
+#line	60	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ fatbox(yypt[-0].yyv); } break;
+case 28:
+#line	61	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ sqrt(yypt[-0].yyv); } break;
+case 29:
+#line	62	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 30:
+#line	62	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ subsup(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 31:
+#line	63	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 32:
+#line	63	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ subsup(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
+case 33:
+#line	64	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 34:
+#line	64	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ integral(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 35:
+#line	65	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 36:
+#line	65	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ integral(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
+case 37:
+#line	66	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ integral(yypt[-0].yyv, 0, 0); } break;
+case 38:
+#line	67	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 39:
+#line	67	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ fromto(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 40:
+#line	68	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 41:
+#line	68	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ fromto(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
+case 42:
+#line	69	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ paren(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 43:
+#line	70	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ paren(yypt[-1].yyv, yypt[-0].yyv, 0); } break;
+case 44:
+#line	71	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ diacrit(yypt[-1].yyv, yypt[-0].yyv); } break;
+case 45:
+#line	72	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(FWD, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 46:
+#line	73	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(UP, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 47:
+#line	74	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(BACK, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 48:
+#line	75	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(DOWN, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 49:
+#line	76	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ pile(yypt[-0].yyv); ct = yypt[-0].yyv; } break;
+case 50:
+#line	77	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{yyval=ct;} break;
+case 51:
+#line	77	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ matrix(yypt[-3].yyv); ct = yypt[-3].yyv; } break;
+case 52:
+#line	80	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ setintegral(); } break;
+case 53:
+#line	83	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 54:
+#line	84	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 55:
+#line	85	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 56:
+#line	86	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 57:
+#line	88	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = HAT; } break;
+case 58:
+#line	89	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = VEC; } break;
+case 59:
+#line	90	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = DYAD; } break;
+case 60:
+#line	91	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = BAR; } break;
+case 61:
+#line	92	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = LOWBAR; } break;
+case 62:
+#line	93	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = HIGHBAR; } break;
+case 63:
+#line	94	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = UNDER; } break;
+case 64:
+#line	95	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = DOT; } break;
+case 65:
+#line	96	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = TILDE; } break;
+case 66:
+#line	97	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = UTILDE; } break;
+case 67:
+#line	98	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = DOTDOT; } break;
+case 68:
+#line	101	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = ((char *)yypt[-0].yyv)[0]; } break;
+case 69:
+#line	102	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = '{'; } break;
+case 70:
+#line	105	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = ((char *)yypt[-0].yyv)[0]; } break;
+case 71:
+#line	106	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = '}'; } break;
+case 74:
+#line	113	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ column(yypt[-3].yyv, DEFGAP); } break;
+case 75:
+#line	114	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{yyval=atoi((char*)yypt[-0].yyv);} break;
+case 76:
+#line	114	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ column(yypt[-5].yyv, yypt[-3].yyv); } break;
+case 77:
+#line	117	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(LCOL); } break;
+case 78:
+#line	118	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(CCOL); } break;
+case 79:
+#line	119	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(RCOL); } break;
+case 80:
+#line	120	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(COL); } break;
+case 81:
+#line	123	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ lp[ct++] = yypt[-0].yyv; } break;
+case 82:
+#line	124	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ lp[ct++] = yypt[-0].yyv; } break;
+case 83:
+#line	127	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = ps; setsize((char *) yypt[-0].yyv); } break;
+case 84:
+#line	130	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ static char R[]="R"; setfont(R); } break;
+case 85:
+#line	131	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ static char I[]="I"; setfont(I); } break;
+case 86:
+#line	132	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ static char B[]="B"; setfont(B); } break;
+case 87:
+#line	133	"/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ setfont((char *)yypt[-0].yyv); } break;
+	}
+	goto yystack;  /* stack new state and value */
+}
blob - /dev/null
blob + 74796d7fa5b5e80b3d762d2d9dd3dd0b8b4922b6 (mode 644)
--- /dev/null
+++ src/cmd/eqn/eqn.y
@@ -0,0 +1,140 @@
+%term	CONTIG QTEXT SPACE THIN TAB
+%term	MATRIX LCOL CCOL RCOL COL ABOVE
+%term	MARK LINEUP
+%term	SUM INT PROD UNION INTER
+%term	DEFINE TDEFINE NDEFINE DELIM GSIZE GFONT INCLUDE SPACE IFDEF
+%term	DOTEQ DOTEN
+
+%right	FROM TO
+%left	OVER SQRT
+%right	SUP SUB
+%right	SIZE FONT ROMAN ITALIC BOLD FAT
+%right	UP DOWN BACK FWD
+%left	LEFT RIGHT
+%right	DOT DOTDOT HAT TILDE BAR LOWBAR HIGHBAR UNDER VEC DYAD UTILDE
+
+%{
+#include "e.h"
+
+int	yylex(void);
+%}
+
+%%
+
+stuff	: eqn 		{ putout($1); }
+	| error		{ ERROR "syntax error" WARNING; }	/* should be SYNTAX */
+	|		{ eqnreg = 0; }
+	;
+
+eqn	: box
+	| eqn box	{ eqnbox($1, $2, 0); }
+	| eqn lineupbox	{ eqnbox($1, $2, 1); }
+	| LINEUP	{ lineup(0); }
+	;
+
+lineupbox: LINEUP box	{ $$ = $2; lineup(1); }
+	;
+
+sbox	: SUP box	%prec SUP	{ $$ = $2; }
+	|		%prec SUP	{ $$ = 0; }
+	;
+
+tbox	: TO box	%prec TO	{ $$ = $2; }
+	|		%prec FROM	{ $$ = 0; }
+	;
+
+box	: '{' eqn '}'	{ $$ = $2; }
+	| QTEXT		{ text(QTEXT, (char *) $1); }
+	| CONTIG	{ text(CONTIG, (char *) $1); }
+	| SPACE		{ text(SPACE, (char *) 0); }
+	| THIN		{ text(THIN, (char *) 0); }
+	| TAB		{ text(TAB, (char *) 0); }
+	| SUM		{ funny(SUM); }
+	| PROD		{ funny(PROD); }
+	| UNION		{ funny(UNION); }
+	| INTER		{ funny(INTER); }
+ 	| box OVER box			{ boverb($1, $3); }
+	| MARK box			{ mark($2); }
+	| size box	%prec SIZE	{ size($1, $2); }
+	| font box	%prec FONT	{ font($1, $2); }
+	| FAT box			{ fatbox($2); }
+	| SQRT box			{ sqrt($2); }
+	| box SUB {ps -= deltaps;} box sbox	%prec SUB	{ subsup($1, $4, $5); }
+	| box SUP {ps -= deltaps;} box		%prec SUP	{ subsup($1, 0, $4); }
+	| int SUB {ps -= deltaps;} box sbox	%prec SUB	{ integral($1, $4, $5); }
+	| int SUP {ps -= deltaps;} box		%prec SUP	{ integral($1, 0, $4); }
+	| int					{ integral($1, 0, 0); }
+	| box FROM {ps -= deltaps;} box tbox	%prec FROM	{ fromto($1, $4, $5); }
+	| box TO {ps -= deltaps;} box		%prec TO	{ fromto($1, 0, $4); }
+	| left eqn right			{ paren($1, $2, $3); }
+	| left eqn 				{ paren($1, $2, 0); }
+	| box diacrit			{ diacrit($1, $2); }
+	| fwd box	%prec UP	{ move(FWD, $1, $2); }
+	| up box	%prec UP	{ move(UP, $1, $2); }
+	| back box	%prec UP	{ move(BACK, $1, $2); }
+	| down box	%prec UP	{ move(DOWN, $1, $2); }
+	| column			{ pile($1); ct = $1; }
+	| MATRIX {$$=ct;} '{' collist '}'	{ matrix($2); ct = $2; }
+	;
+
+int	: INT		{ setintegral(); }
+	;
+
+fwd	: FWD text	{ $$ = atoi((char *) $1); } ;
+up	: UP text	{ $$ = atoi((char *) $1); } ;
+back	: BACK text	{ $$ = atoi((char *) $1); } ;
+down	: DOWN text	{ $$ = atoi((char *) $1); } ;
+
+diacrit	: HAT		{ $$ = HAT; }
+	| VEC		{ $$ = VEC; }
+	| DYAD		{ $$ = DYAD; }
+	| BAR		{ $$ = BAR; }
+	| LOWBAR	{ $$ = LOWBAR; }
+	| HIGHBAR	{ $$ = HIGHBAR; }
+	| UNDER		{ $$ = UNDER; }	/* underbar */
+	| DOT		{ $$ = DOT; }
+	| TILDE		{ $$ = TILDE; }
+	| UTILDE	{ $$ = UTILDE; }
+	| DOTDOT	{ $$ = DOTDOT; } /* umlaut = double dot */
+	;
+
+left	: LEFT text	{ $$ = ((char *)$2)[0]; }
+	| LEFT '{'	{ $$ = '{'; }
+	;
+
+right	: RIGHT text	{ $$ = ((char *)$2)[0]; }
+	| RIGHT '}'	{ $$ = '}'; }
+	;
+
+collist	: column
+	| collist column
+	;
+
+column	: col '{' list '}'				{ column($1, DEFGAP); }
+	| col text {$$=atoi((char*)$2);} '{' list '}'	{ column($1, $3); }
+	;
+
+col	: LCOL		{ $$ = startcol(LCOL); }
+	| CCOL		{ $$ = startcol(CCOL); }
+	| RCOL		{ $$ = startcol(RCOL); }
+	| COL		{ $$ = startcol(COL); }
+	;
+
+list	: eqn			{ lp[ct++] = $1; }
+	| list ABOVE eqn	{ lp[ct++] = $3; }
+	;
+
+size	: SIZE text	{ $$ = ps; setsize((char *) $2); }
+	;
+
+font    : ROMAN         { static char R[]="R"; setfont(R); }
+        | ITALIC        { static char I[]="I"; setfont(I); }
+        | BOLD          { static char B[]="B"; setfont(B); }
+        | FONT text     { setfont((char *)$2); }
+        ;
+
+text	: CONTIG
+	| QTEXT
+	;
+
+%%
blob - /dev/null
blob + 7dd0b867c8182839e68a38b17be9ac64be49db5b (mode 644)
--- /dev/null
+++ src/cmd/eqn/eqnbox.c
@@ -0,0 +1,24 @@
+#include "e.h"
+
+void eqnbox(int p1, int p2, int lu)
+{
+	double b, h;
+	char *sh;
+	extern char *IRspace;
+
+	yyval = p1;
+	b = max(ebase[p1], ebase[p2]);
+	eht[yyval] = h = b + max(eht[p1]-ebase[p1], 
+		eht[p2]-ebase[p2]);
+	ebase[yyval] = b;
+	dprintf(".\tS%d <- %d %d; b=%g, h=%g\n", yyval, p1, p2, b, h);
+	sh = pad(class[rclass[p1]][lclass[p2]]);
+	if (lu) {
+		printf(".nr %d \\w'\\*(%d%s'\n", p1, p1, sh);
+		printf(".ds %d \\h'|\\n(09u-\\n(%du'\\*(%d\n", p1, p1, p1);
+	}
+	printf(".as %d \"%s\\*(%d\n", yyval, sh, p2);
+	rfont[p1] = rfont[p2];
+	rclass[p1] = rclass[p2];
+	sfree(p2);
+}
blob - /dev/null
blob + 3fb01119cc69e9a78b43df030fee71ec2a24fa2b (mode 644)
--- /dev/null
+++ src/cmd/eqn/font.c
@@ -0,0 +1,70 @@
+# include "e.h"
+
+void setfont(char *ch1)
+{
+	yyval = ft;
+	if (strcmp(ch1, "I") == 0) {	/* I and italic mean merely position 2 */
+		*ch1 = '2';
+		ft = ITAL;
+	} else if (strcmp(ch1, "B") == 0) {	/* and similarly for B & bold */
+		*ch1 = '3';
+		ft = BLD;
+	} else if (strcmp(ch1, "R") == 0) {	/* and R and roman */
+		*ch1 = '1';
+		ft = ROM;
+	} else {
+		ft = ROM;	/* assume it's a roman style */
+	}
+	ftp++;
+	if (ftp >= &ftstack[10])
+		ERROR "font stack overflow (10)" FATAL;
+	ftp->ft = ft;
+	if (ch1[1] == 0) {	/* 1-char name */
+		ftp->name[0] = *ch1;
+		ftp->name[1] = '\0';
+	} else
+		sprintf(ftp->name, "(%s", ch1);
+	dprintf(".\tsetfont %s %c\n", ch1, ft);
+}
+
+void font(int p1, int p2)
+{
+		/* old font in p1, new in ft */
+	yyval = p2;
+	lfont[yyval] = rfont[yyval] = ft==ITAL ? ITAL : ROM;
+	ftp--;
+	ft = p1;
+}
+
+void globfont(void)
+{
+	char temp[20];
+
+	getstr(temp, sizeof(temp));
+	yyval = eqnreg = 0;
+	if (strcmp(temp, "I") == 0 || strncmp(temp, "it", 2) == 0) {
+		ft = ITAL;
+		strcpy(temp, "2");
+	} else if (strcmp(temp, "B") == 0 || strncmp(temp, "bo", 2) == 0) {
+		ft = BLD;
+		strcpy(temp, "3");
+	} else if (strcmp(temp, "R") == 0 || strncmp(temp, "ro", 2) == 0) {
+		ft = ROM;
+		strcpy(temp, "1");
+	} else { 
+		ft = ROM;	/* assume it's a roman style */
+	}
+	ftstack[0].ft = ft;
+	if (temp[1] == 0)	/* 1-char name */
+		strcpy(ftstack[0].name, temp);
+	else
+		sprintf(ftstack[0].name, "(%.2s", temp);
+}
+
+void fatbox(int p)
+{
+	extern double Fatshift;
+
+	yyval = p;
+	printf(".ds %d \\*(%d\\h'-\\w'\\*(%d'u+%gm'\\*(%d\n", p, p, p, Fatshift, p);
+}
blob - /dev/null
blob + 2d4d7f7445799fbf67533e62185ec673861937ea (mode 644)
--- /dev/null
+++ src/cmd/eqn/fromto.c
@@ -0,0 +1,52 @@
+# include "e.h"
+
+void fromto(int p1, int p2, int p3)
+{
+	double b, h1, b1, t;
+	int subps;
+
+	yyval = salloc();
+	lfont[yyval] = rfont[yyval] = 0;
+	h1 = eht[yyval] = eht[p1];
+	b1 = ebase[p1];
+	b = 0;
+	subps = ps;
+	ps += deltaps;
+	nrwid(p1, ps, p1);
+	printf(".nr %d \\n(%d\n", yyval, p1);
+	if (p2 > 0) {
+		nrwid(p2, subps, p2);
+		printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, yyval, yyval, p2);
+		eht[yyval] += eht[p2];
+		b = eht[p2];
+	}
+	if (p3 > 0) {
+		nrwid(p3, subps, p3);
+		printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p3, yyval, yyval, p3);
+		eht[yyval] += eht[p3];
+	}
+	printf(".ds %d ", yyval);	/* bottom of middle box */
+	if (p2 > 0) {
+		t = eht[p2]-ebase[p2]+b1;
+		printf("\\v'%gm'\\h'\\n(%du-\\n(%du/2u'%s\\*(%d%s", 
+			REL(t,ps), yyval, p2, DPS(ps,subps), p2, DPS(subps,ps));
+		printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\\n", 
+			yyval, p2, REL(-t,ps));
+	}
+	printf("\\h'\\n(%du-\\n(%du/2u'\\*(%d\\h'\\n(%du-\\n(%du/2u'\\\n", 
+		yyval, p1, p1, yyval, p1);
+	if (p3  >0) {
+		t = h1-b1+ebase[p3];
+		printf("\\v'%gm'\\h'-\\n(%du-\\n(%du/2u'%s\\*(%d%s\\h'\\n(%du-\\n(%du/2u'\\v'%gm'\\\n", 
+			REL(-t,ps), yyval, p3, DPS(ps,subps), p3, DPS(subps,ps), yyval, p3, REL(t,ps));
+	}
+	printf("\n");
+	ebase[yyval] = b + b1;
+	dprintf(".\tS%d <- %d from %d to %d; h=%g b=%g\n", 
+		yyval, p1, p2, p3, eht[yyval], ebase[yyval]);
+	sfree(p1);
+	if (p2 > 0)
+		sfree(p2);
+	if (p3 > 0)
+		sfree(p3);
+}
blob - /dev/null
blob + 85955fceb4cfb617b3978f123204bd82248ff8fb (mode 644)
--- /dev/null
+++ src/cmd/eqn/funny.c
@@ -0,0 +1,30 @@
+#include "e.h"
+#include "y.tab.h"
+
+extern int Funnyps;
+extern double Funnyht, Funnybase;
+
+void funny(int n)
+{
+	char *f = 0;
+
+	yyval = salloc();
+	switch (n) {
+	case SUM:
+		f = lookup(deftbl, "sum_def")->cval; break;
+	case UNION:
+		f = lookup(deftbl, "union_def")->cval; break;
+	case INTER:	/* intersection */
+		f = lookup(deftbl, "inter_def")->cval; break;
+	case PROD:
+		f = lookup(deftbl, "prod_def")->cval; break;
+	default:
+		ERROR "funny type %d in funny", n FATAL;
+	}
+	printf(".ds %d %s\n", yyval, f);
+	eht[yyval] = EM(1.0, ps+Funnyps) - EM(Funnyht, ps);
+	ebase[yyval] = EM(Funnybase, ps);
+	dprintf(".\tS%d <- %s; h=%g b=%g\n", 
+		yyval, f, eht[yyval], ebase[yyval]);
+	lfont[yyval] = rfont[yyval] = ROM;
+}
blob - /dev/null
blob + 6ca1a1da6838041e6ec59f16fe525e992cbaa7de (mode 644)
--- /dev/null
+++ src/cmd/eqn/glob.c
@@ -0,0 +1,35 @@
+#include "e.h"
+
+	/* YOU MAY WANT TO CHANGE THIS */
+char	*typesetter = "post";	/* type of typesetter today */
+int	ttype	= DEVPOST;
+int	minsize	= 4;		/* min size it can handle */
+
+
+int	dbg;		/* debugging print if non-zero */
+int	lp[200];	/* stack for things like piles and matrices */
+int	ct;		/* pointer to lp */
+int	used[100];	/* available registers */
+int	ps;		/* default init point size */
+int	deltaps	= 3;	/* default change in ps */
+int	dps_set = 0;	/* 1 => -p option used */
+int	gsize	= 10;	/* default initial point size */
+int	ft	= '2';
+Font	ftstack[10] = { '2', "2" };	/* bottom is global font */
+Font	*ftp	= ftstack;
+int	szstack[10];	/* non-zero if absolute size set at this level */
+int	nszstack = 0;
+int	display	= 0;	/* 1=>display, 0=>.EQ/.EN */
+
+int	synerr;		/* 1 if syntax err in this eqn */
+double	eht[100];	/* height in ems at gsize */
+double	ebase[100];	/* base: where one enters above bottom */
+int	lfont[100];	/* leftmost and rightmost font associated with this thing */
+int	rfont[100];
+int	lclass[100];	/* leftmost and rightmost class associated with this thing */
+int	rclass[100];
+int	eqnreg;		/* register where final string appears */
+double	eqnht;		/* final height of equation */
+int	lefteq	= '\0';	/* left in-line delimiter */
+int	righteq	= '\0';	/* right in-line delimiter */
+int	markline = 0;	/* 1 if this EQ/EN contains mark; 2 if lineup */
blob - /dev/null
blob + 3b8656714a381fea23ca2dc8397c3cdb6d624c4d (mode 644)
--- /dev/null
+++ src/cmd/eqn/input.c
@@ -0,0 +1,289 @@
+#include "e.h"
+#include "y.tab.h"
+#include <ctype.h>
+#include <errno.h>
+
+Infile	infile[10];
+Infile	*curfile = infile;
+
+#define	MAXSRC	50
+Src	src[MAXSRC];	/* input source stack */
+Src	*srcp	= src;
+
+extern int getarg(char *);
+extern	void eprint(void);
+
+void pushsrc(int type, char *ptr)	/* new input source */
+{
+	if (++srcp >= src + MAXSRC)
+		ERROR "inputs nested too deep" FATAL;
+	srcp->type = type;
+	srcp->sp = ptr;
+	if (dbg > 1) {
+		printf("\n%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("push file %s\n", ((Infile *)ptr)->fname);
+			break;
+		case Macro:
+			printf("push macro <%s>\n", ptr);
+			break;
+		case Char:
+			printf("push char <%c>\n", *ptr);
+			break;
+		case String:
+			printf("push string <%s>\n", ptr);
+			break;
+		case Free:
+			printf("push free <%s>\n", ptr);
+			break;
+		default:
+			ERROR "pushed bad type %d\n", srcp->type FATAL;
+		}
+	}
+}
+
+void popsrc(void)	/* restore an old one */
+{
+	if (srcp <= src)
+		ERROR "too many inputs popped" FATAL;
+	if (dbg > 1) {
+		printf("%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("pop file\n");
+			break;
+		case Macro:
+			printf("pop macro\n");
+			break;
+		case Char:
+			printf("pop char <%c>\n", *srcp->sp);
+			break;
+		case String:
+			printf("pop string\n");
+			break;
+		case Free:
+			printf("pop free\n");
+			break;
+		default:
+			ERROR "pop weird input %d\n", srcp->type FATAL;
+		}
+	}
+	srcp--;
+}
+
+Arg	args[10];	/* argument frames */
+Arg	*argfp = args;	/* frame pointer */
+int	argcnt;		/* number of arguments seen so far */
+
+void dodef(tbl *stp)	/* collect args and switch input to defn */
+{
+	int i, len;
+	char *p;
+	Arg *ap;
+
+	ap = argfp+1;
+	if (ap >= args+10)
+		ERROR "more than arguments\n" FATAL;
+	argcnt = 0;
+	if (input() != '(')
+		ERROR "disaster in dodef\n"FATAL;
+	if (ap->argval == 0)
+		ap->argval = malloc(1000);
+	for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
+		ap->argstk[argcnt++] = p;
+		if (input() == ')')
+			break;
+	}
+	for (i = argcnt; i < MAXARGS; i++)
+		ap->argstk[i] = "";
+	if (dbg)
+		for (i = 0; i < argcnt; i++)
+			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
+	argfp = ap;
+	pushsrc(Macro, stp->cval);
+}
+
+getarg(char *p)	/* pick up single argument, store in p, return length */
+{
+	int n, c, npar;
+
+	n = npar = 0;
+	for ( ;; ) {
+		c = input();
+		if (c == EOF)
+			ERROR "end of file in getarg!\n" FATAL;
+		if (npar == 0 && (c == ',' || c == ')'))
+			break;
+		if (c == '"')	/* copy quoted stuff intact */
+			do {
+				*p++ = c;
+				n++;
+			} while ((c = input()) != '"' && c != EOF);
+		else if (c == '(')
+			npar++;
+		else if (c == ')')
+			npar--;
+		n++;
+		*p++ = c;
+	}
+	*p = 0;
+	unput(c);
+	return(n + 1);
+}
+
+#define	PBSIZE	2000
+char	pbuf[PBSIZE];		/* pushback buffer */
+char	*pb	= pbuf-1;	/* next pushed back character */
+
+char	ebuf[200];		/* collect input here for error reporting */
+char	*ep	= ebuf;
+
+input(void)
+{
+	register int c = 0;
+
+  loop:
+	switch (srcp->type) {
+	case File:
+		c = getc(curfile->fin);
+		if (c == EOF) {
+			if (curfile == infile)
+				break;
+			if (curfile->fin != stdin) {
+				fclose(curfile->fin);
+				free(curfile->fname);	/* assumes allocated */
+			}
+			curfile--;
+			printf(".lf %d %s\n", curfile->lineno, curfile->fname);
+			popsrc();
+			goto loop;
+		}
+		if (c == '\n')
+			curfile->lineno++;
+		break;
+	case Char:
+		if (pb >= pbuf) {
+			c = *pb--;
+			popsrc();
+			break;
+		} else {	/* can't happen? */
+			popsrc();
+			goto loop;
+		}
+	case String:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			popsrc();
+			goto loop;
+		} else {
+			if (*srcp->sp == '\0')	/* empty, so pop */
+				popsrc();
+			break;
+		}
+	case Macro:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			if (--argfp < args)
+				ERROR "argfp underflow" FATAL;
+			popsrc();
+			goto loop;
+		} else if (c == '$' && isdigit(*srcp->sp)) {
+			int n = 0;
+			while (isdigit(*srcp->sp))
+				n = 10 * n + *srcp->sp++ - '0';
+			if (n > 0 && n <= MAXARGS)
+				pushsrc(String, argfp->argstk[n-1]);
+			goto loop;
+		}
+		break;
+	case Free:	/* free string */
+		free(srcp->sp);
+		popsrc();
+		goto loop;
+	}
+	if (ep >= ebuf + sizeof ebuf)
+		ep = ebuf;
+	*ep++ = c;
+	return c;
+}
+
+
+unput(int c)
+{
+	if (++pb >= pbuf + sizeof pbuf)
+		ERROR "pushback overflow\n"FATAL;
+	if (--ep < ebuf)
+		ep = ebuf + sizeof(ebuf) - 1;
+	*pb = c;
+	pushsrc(Char, pb);
+	return c;
+}
+
+void pbstr(char *s)
+{
+	pushsrc(String, s);
+}
+
+void error(int die, char *s)
+{
+	extern char *cmdname;
+
+	if (synerr)
+		return;
+	fprintf(stderr, "%s: ", cmdname);
+	fprintf(stderr, s);
+	if (errno > 0)
+		perror("???");
+	if (curfile->fin)
+		fprintf(stderr, " near %s:%d",
+			curfile->fname, curfile->lineno+1);
+	fprintf(stderr, "\n");
+	eprint();
+	synerr = 1;
+	errno = 0;
+	if (die) {
+		if (dbg)
+			abort();
+		else
+			exit(1);
+	}
+}
+
+void yyerror(char *s)
+{
+	error(0, s);	/* temporary */
+}
+
+char errbuf[200];
+
+void eprint(void)	/* try to print context around error */
+{
+	char *p, *q;
+
+	if (ep == ebuf)
+		return;				/* no context */
+	p = ep - 1;
+	if (p > ebuf && *p == '\n')
+		p--;
+	for ( ; p >= ebuf && *p != '\n'; p--)
+		;
+	while (*p == '\n')
+		p++;
+	fprintf(stderr, " context is\n\t");
+	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
+		;
+	while (p < q)
+		putc(*p++, stderr);
+	fprintf(stderr, " >>> ");
+	while (p < ep)
+		putc(*p++, stderr);
+	fprintf(stderr, " <<< ");
+	while (pb >= pbuf)
+		putc(*pb--, stderr);
+	if (curfile->fin)
+		fgets(ebuf, sizeof ebuf, curfile->fin);
+	fprintf(stderr, "%s", ebuf);
+	pbstr("\n.EN\n");	/* safety first */
+	ep = ebuf;
+}
blob - /dev/null
blob + 2b1c9e3f306fa82f402d9b932e389d97e9f69e85 (mode 644)
--- /dev/null
+++ src/cmd/eqn/integral.c
@@ -0,0 +1,30 @@
+#include "e.h"
+#include "y.tab.h"
+
+extern int Intps;
+extern double Intht, Intbase, Int1h, Int1v, Int2h, Int2v;
+
+void integral(int p, int p1, int p2)
+{
+	if (p1 != 0)
+		printf(".ds %d \\h'%gm'\\v'%gm'\\*(%d\\v'%gm'\n", p1, -Int1h, Int1v, p1, -Int1v);
+	if (p2 != 0)
+		printf(".ds %d \\v'%gm'\\h'%gm'\\*(%d\\v'%gm'\n", p2, -Int2v, Int2h, p2, Int2v);
+	if (p1 != 0 && p2 != 0)
+		shift2(p, p1, p2);
+	else if (p1 != 0)
+		bshiftb(p, SUB, p1);
+	else if (p2 != 0)
+		bshiftb(p, SUP, p2);
+	dprintf(".\tintegral: S%d; h=%g b=%g\n", p, eht[p], ebase[p]);
+	lfont[p] = ROM;
+}
+
+void setintegral(void)
+{
+	yyval = salloc();
+	printf(".ds %d %s\n", yyval, lookup(deftbl, "int_def")->cval);
+	eht[yyval] = EM(Intht, ps+Intps);
+	ebase[yyval] = EM(Intbase, ps);
+	lfont[yyval] = rfont[yyval] = ROM;
+}
blob - /dev/null
blob + e535b8699b5551b117ec024618ac53046aae1d5e (mode 644)
--- /dev/null
+++ src/cmd/eqn/lex.c
@@ -0,0 +1,265 @@
+#include "e.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+#define	SSIZE	1000
+char	token[SSIZE];
+int	sp;
+
+void	space(void);
+void	dodef(tbl *);
+void	define(int);
+void	ifdef(void);
+void	include(void);
+void	delim(void);
+
+yylex(void)
+{
+	register int c;
+	tbl *tp;
+
+  begin:
+	while ((c = input()) == ' ' || c == '\n' || c == '\t')
+		;
+	yylval = c;
+	switch (c) {
+	case EOF:
+		ERROR "unexpected end of input inside equation" WARNING;
+		return(EOF);
+	case '~':
+		return(SPACE);
+	case '^':
+		return(THIN);
+	/* case '\t':
+		return(TAB);
+	*/
+	case '{':
+		return('{');
+	case '}':
+		return('}');
+	case '"':
+		for (sp = 0; (c=input())!='"' && c != '\n'; ) {
+			if (c == '\\')
+				if ((c = input()) != '"')
+					token[sp++] = '\\';
+			token[sp++] = c;
+			if (sp >= SSIZE)
+				ERROR "quoted string %.20s... too long", token FATAL;
+		}
+		token[sp] = '\0';
+		yylval = (int) &token[0];
+		if (c == '\n')
+			ERROR "missing \" in %.20s", token WARNING;
+		return(QTEXT);
+	}
+	if (!display && c == righteq)
+		return(EOF);
+
+	unput(c);
+	getstr(token, SSIZE);
+	dprintf(".\tlex token = |%s|\n", token);
+	if ((tp = lookup(deftbl, token)) != NULL) {	/* defined term */
+		c = input();
+		unput(c);
+		if (c == '(')	/* macro with args */
+			dodef(tp);
+		else {		/* no args */
+			unput(' ');
+			pbstr(tp->cval);
+			dprintf(".\tfound %s|=%s|\n", token, tp->cval);
+		}
+		goto begin;
+	}
+
+	if ((tp = lookup(keytbl, token)) == NULL)	/* not a keyword */
+		return CONTIG;
+
+	switch (tp->ival) {		/* some kind of keyword */
+	case DEFINE: case TDEFINE: case NDEFINE:
+		define(tp->ival);
+		break;
+	case IFDEF:
+		ifdef();
+		break;
+	case DELIM:
+		delim();
+		break;
+	case GSIZE:
+		globsize();
+		break;
+	case GFONT:
+		globfont();
+		break;
+	case INCLUDE:
+		include();
+		break;
+	case SPACE:
+		space();
+		break;
+	case DOTEQ:
+			/* .EQ inside equation -- should warn if at bottom level */
+		break;
+	case DOTEN:
+		if (curfile == infile)
+			return EOF;
+		/* else ignore nested .EN */
+		break;
+	default:
+		return tp->ival;
+	}
+	goto begin;
+}
+
+void getstr(char *s, int n)
+{
+	register int c;
+	register char *p;
+
+	p = s;
+	while ((c = input()) == ' ' || c == '\n')
+		;
+	if (c == EOF) {
+		*s = 0;
+		return;
+	}
+	while (c != ' ' && c != '\t' && c != '\n' && c != '{' && c != '}'
+	    && c != '"' && c != '~' && c != '^') {
+		if (!display && c == righteq)
+			break;
+		if (c == '(' && p > s) {	/* might be defined(...) */
+			*p = '\0';
+			if (lookup(deftbl, s) != NULL)
+				break;
+		}
+		if (c == '\\')
+			if ((c = input()) != '"')
+				*p++ = '\\';
+		*p++ = c;
+		if (--n <= 0)
+			ERROR "token %.20s... too long", s FATAL;
+		c = input();
+	}
+	unput(c);
+	*p = '\0';
+	yylval = (int) s;
+}
+
+cstr(char *s, int quote, int maxs)
+{
+	int del, c, i;
+
+	s[0] = 0;
+	while ((del=input()) == ' ' || del == '\t')
+		;
+	if (quote)
+		for (i=0; (c=input()) != del && c != EOF;) {
+			s[i++] = c;
+			if (i >= maxs)
+				return(1);	/* disaster */
+		}
+	else {
+		if (del == '\n')
+			return(1);
+		s[0] = del;
+		for (i=1; (c=input())!=' ' && c!= '\t' && c!='\n' && c!=EOF;) {
+			s[i++] = c;
+			if (i >= maxs)
+				return(1);	/* disaster */
+		}
+	}
+	s[i] = '\0';
+	if (c == EOF)
+		ERROR "Unexpected end of input at %.20s", s FATAL;
+	return(0);
+}
+
+void define(int type)
+{
+	char *p1, *p2;
+	extern int ftune(char *, char *);
+
+	getstr(token, SSIZE);	/* get name */
+	if (type != DEFINE) {
+		cstr(token, 1, SSIZE);	/* skip the definition too */
+		return;
+	}
+	p1 = strsave(token);
+	if (cstr(token, 1, SSIZE))
+		ERROR "Unterminated definition at %.20s", token FATAL;
+	if (lookup(ftunetbl, p1) != NULL) {	/* double tuning param */
+		dprintf(".\ttune %s %s\n", p1, token);
+		ftune(p1, token);
+	} else {
+		p2 = strsave(token);
+		install(deftbl, p1, p2, 0);
+		dprintf(".\tname %s defined as %s\n", p1, p2);
+	}
+}
+
+void ifdef(void)		/* do body if name is defined */
+{
+	char name[100], *p;
+
+	getstr(name, sizeof(name));	/* get name */
+	cstr(token, 1, SSIZE);		/* and body */
+	if (lookup(deftbl, name) != NULL) {	/* found it */
+		p = strsave(token);
+		pushsrc(Free, p);
+		pushsrc(String, p);
+	}
+}
+
+char	*spaceval	= NULL;
+
+void space(void)	/* collect line of form "space amt" to replace \x in output */
+{
+	getstr(token, SSIZE);
+	spaceval = strsave(token);
+	dprintf(".\tsetting spaceval to %s\n", token);
+}
+
+char *strsave(char *s)
+{
+	register char *q;
+
+	q = malloc(strlen(s)+1);
+	if (q == NULL)
+		ERROR "out of space in strsave on %s", s FATAL;
+	strcpy(q, s);
+	return(q);
+}
+
+void include(void)
+{
+	char name[100];
+	FILE *fin;
+	int c;
+	extern int errno;
+
+	while ((c = input()) == ' ')
+		;
+	unput(c);
+	cstr(name, c == '"', sizeof(name));	/* gets it quoted or not */
+	if ((fin = fopen(name, "r")) == NULL)
+		ERROR "can't open file %s", name FATAL;
+	errno = 0;
+	curfile++;
+	curfile->fin = fin;
+	curfile->fname = strsave(name);
+	curfile->lineno = 0;
+	printf(".lf 1 %s\n", curfile->fname);
+	pushsrc(File, curfile->fname);
+}
+
+void delim(void)
+{
+	yyval = eqnreg = 0;
+	if (cstr(token, 0, SSIZE))
+		ERROR "Bizarre delimiters" FATAL;
+	lefteq = token[0];
+	righteq = token[1];
+        if (!isprint(lefteq) || !isprint(righteq))
+		ERROR "Bizarre delimiters" FATAL;
+	if (lefteq == 'o' && righteq == 'f')
+		lefteq = righteq = '\0';
+}
blob - /dev/null
blob + 4eb94373641f98f847a283e7e0656120afe87e7d (mode 644)
--- /dev/null
+++ src/cmd/eqn/lookup.c
@@ -0,0 +1,219 @@
+#include "e.h"
+#include "y.tab.h"
+
+tbl	*keytbl[TBLSIZE];	/* key words */
+tbl	*restbl[TBLSIZE];	/* reserved words */
+tbl	*deftbl[TBLSIZE];	/* user-defined names */
+
+struct keyword {
+	char	*key;
+	int	keyval;
+} keyword[]	={
+	"sub", 		SUB, 
+	"sup", 		SUP, 
+	".EN", 		DOTEN,
+	".EQ",		DOTEQ, 
+	"from", 	FROM, 
+	"to", 		TO, 
+	"sum", 		SUM, 
+	"hat", 		HAT, 
+	"vec", 		VEC, 
+	"dyad", 	DYAD, 
+	"dot", 		DOT, 
+	"dotdot", 	DOTDOT, 
+	"bar", 		BAR,
+	"lowbar",	LOWBAR,
+	"highbar",	HIGHBAR, 
+	"tilde", 	TILDE, 
+	"utilde", 	UTILDE, 
+	"under", 	UNDER, 
+	"prod", 	PROD, 
+	"int", 		INT, 
+	"integral", 	INT, 
+	"union", 	UNION, 
+	"inter", 	INTER, 
+	"matrix", 	MATRIX, 
+	"col", 		COL, 
+	"lcol", 	LCOL, 
+	"ccol", 	CCOL, 
+	"rcol", 	RCOL, 
+	"pile", 	COL,	/* synonyms ... */ 
+	"lpile", 	LCOL, 
+	"cpile", 	CCOL, 
+	"rpile", 	RCOL, 
+	"over", 	OVER, 
+	"sqrt", 	SQRT, 
+	"above", 	ABOVE, 
+	"size", 	SIZE, 
+	"font", 	FONT, 
+	"fat", 		FAT, 
+	"roman", 	ROMAN, 
+	"italic", 	ITALIC, 
+	"bold", 	BOLD, 
+	"left", 	LEFT, 
+	"right", 	RIGHT, 
+	"delim", 	DELIM, 
+	"define", 	DEFINE, 
+	"tdefine", 	DEFINE, 
+	"ndefine", 	NDEFINE, 
+	"ifdef",	IFDEF,
+	"gsize", 	GSIZE, 
+	".gsize", 	GSIZE, 
+	"gfont", 	GFONT, 
+	"include", 	INCLUDE, 
+	"copy", 	INCLUDE, 
+	"space",	SPACE,
+	"up", 		UP, 
+	"down", 	DOWN, 
+	"fwd", 		FWD, 
+	"back", 	BACK, 
+	"mark", 	MARK, 
+	"lineup", 	LINEUP, 
+	0, 	0
+};
+
+struct resword {
+	char	*res;
+	char	*resval;
+} resword[]	={
+	">=",		"\\(>=",
+	"<=",		"\\(<=",
+	"==",		"\\(==",
+	"!=",		"\\(!=",
+	"+-",		"\\(+-",
+	"->",		"\\(->",
+	"<-",		"\\(<-",
+	"inf",		"\\(if",
+	"infinity",	"\\(if",
+	"partial",	"\\(pd",
+	"half",		"\\f1\\(12\\fP",
+	"prime",	"\\f1\\v'.5m'\\s+3\\(fm\\s-3\\v'-.5m'\\fP",
+	"dollar",	"\\f1$\\fP",
+	"nothing",	"",
+	"times",	"\\(mu",
+	"del",		"\\(gr",
+	"grad",		"\\(gr",
+	"approx",	"\\v'-.2m'\\z\\(ap\\v'.25m'\\(ap\\v'-.05m'",
+	"cdot",		"\\v'-.3m'.\\v'.3m'",
+	"...",		"\\v'-.25m'\\ .\\ .\\ .\\ \\v'.25m'",
+	",...,",	"\\f1,\\fP\\ .\\ .\\ .\\ \\f1,\\fP\\|",
+	"alpha",	"α",
+	"ALPHA",	"Α",
+	"beta",		"β",
+	"BETA",		"Β",
+	"gamma",	"γ",
+	"GAMMA",	"Γ",
+	"delta",	"δ",
+	"DELTA",	"Δ",
+	"epsilon",	"ε",
+	"EPSILON",	"Ε",
+	"omega",	"ω",
+	"OMEGA",	"Ω",
+	"lambda",	"λ",
+	"LAMBDA",	"Λ",
+	"mu",		"μ",
+	"MU",		"Μ",
+	"nu",		"ν",
+	"NU",		"Ν",
+	"theta",	"θ",
+	"THETA",	"Θ",
+	"phi",		"φ",
+	"PHI",		"Φ",
+	"pi",		"π",
+	"PI",		"Π",
+	"sigma",	"σ",
+	"SIGMA",	"Σ",
+	"xi",		"ξ",
+	"XI",		"Ξ",
+	"zeta",		"ζ",
+	"ZETA",		"Ζ",
+	"iota",		"ι",
+	"IOTA",		"Ι",
+	"eta",		"η",
+	"ETA",		"Η",
+	"kappa",	"κ",
+	"KAPPA",	"Κ",
+	"rho",		"ρ",
+	"RHO",		"Ρ",
+	"tau",		"τ",
+	"TAU",		"Τ",
+	"omicron",	"ο",
+	"OMICRON",	"Ο",
+	"upsilon",	"υ",
+	"UPSILON",	"Υ",
+	"psi",		"ψ",
+	"PSI",		"Ψ",
+	"chi",		"χ",
+	"CHI",		"Χ",
+	"and",		"\\f1and\\fP",
+	"for",		"\\f1for\\fP",
+	"if",		"\\f1if\\fP",
+	"Re",		"\\f1Re\\fP",
+	"Im",		"\\f1Im\\fP",
+	"sin",		"\\f1sin\\fP",
+	"cos",		"\\f1cos\\fP",
+	"tan",		"\\f1tan\\fP",
+	"arc",		"\\f1arc\\fP",
+	"sinh",		"\\f1sinh\\fP",
+	"coth",		"\\f1coth\\fP",
+	"tanh",		"\\f1tanh\\fP",
+	"cosh",		"\\f1cosh\\fP",
+	"lim",		"\\f1lim\\fP",
+	"log",		"\\f1log\\fP",
+	"ln",		"\\f1ln\\fP",
+	"max",		"\\f1max\\fP",
+	"min",		"\\f1min\\fP",
+	"exp",		"\\f1exp\\fP",
+	"det",		"\\f1det\\fP",
+	0,	0
+};
+
+int hash(char *s)
+{
+	register unsigned int h;
+
+	for (h = 0; *s != '\0'; )
+		h += *s++;
+	h %= TBLSIZE;
+	return h;
+}
+
+tbl *lookup(tbl **tblp, char *name)	/* find name in tbl */
+{
+	register tbl *p;
+
+	for (p = tblp[hash(name)]; p != NULL; p = p->next)
+		if (strcmp(name, p->name) == 0)
+			return(p);
+	return(NULL);
+}
+
+void install(tbl **tblp, char *name, char *cval, int ival)	/* install name, vals in tblp */
+{
+	register tbl *p;
+	int h;
+
+	if ((p = lookup(tblp, name)) == NULL) {
+		p = (tbl *) malloc(sizeof(tbl));
+		if (p == NULL)
+			ERROR "out of space in install" FATAL;
+		h = hash(name);	/* bad visibility here */
+		p->name = name;
+		p->next = tblp[h];
+		tblp[h] = p;
+	}
+	p->cval = cval;
+	p->ival = ival;
+}
+
+void init_tbl(void)	/* initialize tables */
+{
+	int i;
+	extern int init_tune(void);
+
+	for (i = 0; keyword[i].key != NULL; i++)
+		install(keytbl, keyword[i].key, (char *) 0, keyword[i].keyval);
+	for (i = 0; resword[i].res != NULL; i++)
+		install(restbl, resword[i].res, resword[i].resval, 0);
+	init_tune();	/* tuning table done in tuning.c */
+}
blob - /dev/null
blob + a06fd165acd404abf8339c3ecf3a5b35b83341a7 (mode 644)
--- /dev/null
+++ src/cmd/eqn/main.c
@@ -0,0 +1,333 @@
+#include "e.h"
+
+#define	MAXLINE	3600	/* maximum input line */
+
+char *version = "version Oct 24, 1991";
+
+char	in[MAXLINE];	/* input buffer */
+int	noeqn;
+char	*cmdname;
+
+int	yyparse(void);
+void	settype(char *);
+int	getdata(void);
+int	getline(char *);
+#define inline einline
+void	inline(void);
+void	init(void);
+void	init_tbl(void);
+
+void
+main(int argc, char *argv[])
+{
+	char *p, buf[20];
+
+	cmdname = argv[0];
+	if (p = getenv("TYPESETTER"))
+		typesetter = p;
+	while (argc > 1 && argv[1][0] == '-') {
+		switch (argv[1][1]) {
+
+		case 'd':
+			if (argv[1][2] == '\0') {
+				dbg++;
+				printf("...\teqn %s\n", version);
+			} else {
+				lefteq = argv[1][2];
+				righteq = argv[1][3];
+			}
+			break;
+		case 's': szstack[0] = gsize = atoi(&argv[1][2]); break;
+		case 'p': deltaps = atoi(&argv[1][2]); dps_set = 1; break;
+		case 'm': minsize = atoi(&argv[1][2]); break;
+		case 'f': strcpy(ftstack[0].name,&argv[1][2]); break;
+		case 'e': noeqn++; break;
+		case 'T': typesetter = &argv[1][2]; break;
+		default:
+			fprintf(stderr, "%s: unknown option %s\n", cmdname, argv[1]);
+			break;
+		}
+		argc--;
+		argv++;
+	}
+	settype(typesetter);
+	sprintf(buf, "\"%s\"", typesetter);
+	install(deftbl, strsave(typesetter), strsave(buf), 0);
+	init_tbl();	/* install other keywords in tables */
+	curfile = infile;
+	pushsrc(File, curfile->fname);
+	if (argc <= 1) {
+		curfile->fin = stdin;
+		curfile->fname = strsave("-");
+		getdata();
+	} else
+		while (argc-- > 1) {
+			if (strcmp(*++argv, "-") == 0)
+				curfile->fin = stdin;
+			else if ((curfile->fin = fopen(*argv, "r")) == NULL)
+				ERROR "can't open file %s", *argv FATAL;
+			curfile->fname = strsave(*argv);
+			getdata();
+			if (curfile->fin != stdin)
+				fclose(curfile->fin);
+		}
+	exit(0);
+}
+
+void settype(char *s)	/* initialize data for particular typesetter */
+			/* the minsize could profitably come from the */
+{			/* troff description file /usr/lib/font/dev.../DESC.out */
+	if (strcmp(s, "202") == 0)
+		{ minsize = 5; ttype = DEV202; }
+	else if (strcmp(s, "aps") == 0)
+		{ minsize = 5; ttype = DEVAPS; }
+	else if (strcmp(s, "cat") == 0)
+		{ minsize = 6; ttype = DEVCAT; }
+	else if (strcmp(s, "post") == 0)
+		{ minsize = 4; ttype = DEVPOST; }
+	else
+		{ minsize = 5; ttype = DEV202; }
+}
+
+getdata(void)
+{
+	int i, type, ln;
+	char fname[100];
+	extern int errno;
+
+	errno = 0;
+	curfile->lineno = 0;
+	printf(".lf 1 %s\n", curfile->fname);
+	while ((type = getline(in)) != EOF) {
+		if (in[0] == '.' && in[1] == 'E' && in[2] == 'Q') {
+			for (i = 11; i < 100; i++)
+				used[i] = 0;
+			printf("%s", in);
+			if (markline) {	/* turn off from last time */
+				printf(".nr MK 0\n");
+				markline = 0;
+			}
+			display = 1;
+			init();
+			yyparse();
+			if (eqnreg > 0) {
+				if (markline)
+					printf(".nr MK %d\n", markline); /* for -ms macros */
+				printf(".if %gm>\\n(.v .ne %gm\n", eqnht, eqnht);
+				printf(".rn %d 10\n", eqnreg);
+				if (!noeqn)
+					printf("\\&\\*(10\n");
+			}
+			printf(".EN");
+			while (putchar(input()) != '\n')
+				;
+			printf(".lf %d\n", curfile->lineno+1);
+		}
+		else if (type == lefteq)
+			inline();
+		else if (in[0] == '.' && in[1] == 'l' && in[2] == 'f') {
+			if (sscanf(in+3, "%d %s", &ln, fname) == 2) {
+				free(curfile->fname);
+				printf(".lf %d %s\n", curfile->lineno = ln, curfile->fname = strsave(fname));
+			} else
+				printf(".lf %d\n", curfile->lineno = ln);
+		} else
+			printf("%s", in);
+	}
+	return(0);
+}
+
+getline(char *s)
+{
+	register c;
+
+	while ((c=input()) != '\n' && c != EOF && c != lefteq) {
+		if (s >= in+MAXLINE) {
+			ERROR "input line too long: %.20s\n", in WARNING;
+			in[MAXLINE] = '\0';
+			break;
+		}
+		*s++ = c;
+	}
+	if (c != lefteq)
+		*s++ = c;
+	*s = '\0';
+	return(c);
+}
+
+void inline(void)
+{
+	int ds, n, sz1 = 0;
+
+	n = curfile->lineno;
+	if (szstack[0] != 0)
+		printf(".nr %d \\n(.s\n", sz1 = salloc());
+	ds = salloc();
+	printf(".rm %d \n", ds);
+	display = 0;
+	do {
+		if (*in)
+			printf(".as %d \"%s\n", ds, in);
+		init();
+		yyparse();
+		if (eqnreg > 0) {
+			printf(".as %d \\*(%d\n", ds, eqnreg);
+			sfree(eqnreg);
+			printf(".lf %d\n", curfile->lineno+1);
+		}
+	} while (getline(in) == lefteq);
+	if (*in)
+		printf(".as %d \"%s", ds, in);
+	if (sz1)
+		printf("\\s\\n(%d", sz1);
+	printf("\\*(%d\n", ds);
+	printf(".lf %d\n", curfile->lineno+1);
+	if (curfile->lineno > n+3)
+		fprintf(stderr, "eqn warning: multi-line %c...%c, file %s:%d,%d\n",
+			lefteq, righteq, curfile->fname, n, curfile->lineno); 
+	sfree(ds);
+	if (sz1) sfree(sz1);
+}
+
+void putout(int p1)
+{
+	double before, after;
+	extern double BeforeSub, AfterSub;
+
+	dprintf(".\tanswer <- S%d, h=%g,b=%g\n",p1, eht[p1], ebase[p1]);
+	eqnht = eht[p1];
+	before = eht[p1] - ebase[p1] - BeforeSub;	/* leave room for sub or superscript */
+	after = ebase[p1] - AfterSub;
+	if (spaceval || before > 0.01 || after > 0.01) {
+		printf(".ds %d ", p1);	/* used to be \\x'0' here:  why? */
+		if (spaceval != NULL)
+			printf("\\x'0-%s'", spaceval);
+		else if (before > 0.01)
+			printf("\\x'0-%gm'", before);
+		printf("\\*(%d", p1);
+		if (spaceval == NULL && after > 0.01)
+			printf("\\x'%gm'", after);
+		putchar('\n');
+	}
+	if (szstack[0] != 0)
+		printf(".ds %d %s\\*(%d\\s\\n(99\n", p1, DPS(gsize,gsize), p1);
+	eqnreg = p1;
+	if (spaceval != NULL) {
+		free(spaceval);
+		spaceval = NULL;
+	}
+}
+
+void init(void)
+{
+	synerr = 0;
+	ct = 0;
+	ps = gsize;
+	ftp = ftstack;
+	ft = ftp->ft;
+	nszstack = 0;
+	if (szstack[0] != 0)	/* absolute gsize in effect */
+		printf(".nr 99 \\n(.s\n");
+}
+
+salloc(void)
+{
+	int i;
+
+	for (i = 11; i < 100; i++)
+		if (used[i] == 0) {
+			used[i]++;
+			return(i);
+		}
+	ERROR "no eqn strings left (%d)", i FATAL;
+	return(0);
+}
+
+void sfree(int n)
+{
+	used[n] = 0;
+}
+
+void nrwid(int n1, int p, int n2)
+{
+	printf(".nr %d 0\\w'%s\\*(%d'\n", n1, DPS(gsize,p), n2);	/* 0 defends against - width */
+}
+
+char *ABSPS(int dn)	/* absolute size dn in printable form \sd or \s(dd (dd >= 40) */
+{
+	static char buf[100], *lb = buf;
+	char *p;
+
+	if (lb > buf + sizeof(buf) - 10)
+		lb = buf;
+	p = lb;
+	*lb++ = '\\';
+	*lb++ = 's';
+	if (dn >= 10) {		/* \s(dd only works in new troff */
+		if (dn >= 40)
+			*lb++ = '(';
+		*lb++ = dn/10 + '0';
+		*lb++ = dn%10 + '0';
+	} else {
+		*lb++ = dn + '0';
+	}
+	*lb++ = '\0';	
+	return p;
+}
+
+char *DPS(int f, int t)	/* delta ps (t-f) in printable form \s+d or \s-d or \s+-(dd */
+{
+	static char buf[100], *lb = buf;
+	char *p;
+	int dn;
+
+	if (lb > buf + sizeof(buf) - 10)
+		lb = buf;
+	p = lb;
+	*lb++ = '\\';
+	*lb++ = 's';
+	dn = EFFPS(t) - EFFPS(f);
+	if (szstack[nszstack] != 0)	/* absolute */
+		dn = EFFPS(t);		/* should do proper \s(dd */
+	else if (dn >= 0)
+		*lb++ = '+';
+	else {
+		*lb++ = '-';
+		dn = -dn;
+	}
+	if (dn >= 10) {		/* \s+(dd only works in new troff */
+		*lb++ = '(';
+		*lb++ = dn/10 + '0';
+		*lb++ = dn%10 + '0';
+	} else {
+		*lb++ = dn + '0';
+	}
+	*lb++ = '\0';	
+	return p;
+}
+
+EFFPS(int n)	/* effective value of n */
+{
+	if (n >= minsize)
+		return n;
+	else
+		return minsize;
+}
+
+double EM(double m, int ps)	/* convert m to ems in gsize */
+{
+	m *= (double) EFFPS(ps) / gsize;
+	if (m <= 0.001 && m >= -0.001)
+		return 0;
+	else
+		return m;
+}
+
+double REL(double m, int ps)	/* convert m to ems in ps */
+{
+	m *= (double) gsize / EFFPS(ps);
+	if (m <= 0.001 && m >= -0.001)
+		return 0;
+	else
+		return m;
+}
blob - /dev/null
blob + f02e677942141c732151dfb09d222f145196c7f3 (mode 644)
--- /dev/null
+++ src/cmd/eqn/mark.c
@@ -0,0 +1,19 @@
+#include "e.h"
+
+void mark(int p1)
+{
+	markline = 1;
+	printf(".ds %d \\k(09\\*(%d\n", p1, p1);
+	yyval = p1;
+	dprintf(".\tmark %d\n", p1);
+}
+
+void lineup(int p1)
+{
+	markline = 2;
+	if (p1 == 0) {
+		yyval = salloc();
+		printf(".ds %d \\h'|\\n(09u'\n", yyval);
+	}
+	dprintf(".\tlineup %d\n", p1);
+}
blob - /dev/null
blob + 9df6cff2f99d4dc688db9bd63ca6964597d612e4 (mode 644)
--- /dev/null
+++ src/cmd/eqn/matrix.c
@@ -0,0 +1,78 @@
+#include "e.h"
+
+startcol(int type)	/* mark start of column in lp[] array */
+{
+	int oct = ct;
+
+	lp[ct++] = type;
+	lp[ct++] = 0;	/* count, to come */
+	lp[ct++] = 0;	/* separation, to come */
+	return oct;
+}
+
+void column(int oct, int sep)	/* remember end of column that started at lp[oct] */
+{
+	int i, type;
+
+	lp[oct+1] = ct - oct - 3;
+	lp[oct+2] = sep;
+	type = lp[oct];
+	if (dbg) {
+		printf(".\t%d column of", type);
+		for (i = oct+3; i < ct; i++ )
+			printf(" S%d", lp[i]);
+		printf(", rows=%d, sep=%d\n", lp[oct+1], lp[oct+2]);
+	}
+}
+
+void matrix(int oct)	/* matrix is list of columns */
+{
+	int nrow, ncol, i, j, k, val[100];
+	double b, hb;
+	char *space;
+	extern char *Matspace;
+
+	space = Matspace;	/* between columns of matrix */
+	nrow = lp[oct+1];	/* disaster if rows inconsistent */
+				/* also assumes just columns */
+				/* fix when add other things */
+	ncol = 0;
+	for (i = oct+1; i < ct; i += lp[i]+3 ) {
+		ncol++;
+		dprintf(".\tcolct=%d\n", lp[i]);
+	}
+	for (k=1; k <= nrow; k++) {
+		hb = b = 0;
+		j = oct + k + 2;
+		for (i=0; i < ncol; i++) {
+			hb = max(hb, eht[lp[j]]-ebase[lp[j]]);
+			b = max(b, ebase[lp[j]]);
+			j += nrow + 3;
+		}
+		dprintf(".\trow %d: b=%g, hb=%g\n", k, b, hb);
+		j = oct + k + 2;
+		for (i=0; i<ncol; i++) {
+			ebase[lp[j]] = b;
+			eht[lp[j]] = b + hb;
+			j += nrow + 3;
+		}
+	}
+	j = oct;
+	for (i=0; i<ncol; i++) {
+		pile(j);
+		val[i] = yyval;
+		j += nrow + 3;
+	}
+	yyval = salloc();
+	eht[yyval] = eht[val[0]];
+	ebase[yyval] = ebase[val[0]];
+	lfont[yyval] = rfont[yyval] = 0;
+	dprintf(".\tmatrix S%d: r=%d, c=%d, h=%g, b=%g\n",
+		yyval,nrow,ncol,eht[yyval],ebase[yyval]);
+	printf(".ds %d \"", yyval);
+	for( i=0; i<ncol; i++ )  {
+		printf("\\*(%d%s", val[i], i==ncol-1 ? "" : space);
+		sfree(val[i]);
+	}
+	printf("\n");
+}
blob - /dev/null
blob + 5f8e559c5d8dadcaaf47986778ea2896a300b3e1 (mode 644)
--- /dev/null
+++ src/cmd/eqn/mkfile
@@ -0,0 +1,42 @@
+<$PLAN9/src/mkhdr
+
+TARG=eqn
+OFILES=main.$O\
+	tuning.$O\
+	diacrit.$O\
+	eqnbox.$O\
+	font.$O\
+	fromto.$O\
+	funny.$O\
+	glob.$O\
+	integral.$O\
+	input.$O\
+	lex.$O\
+	lookup.$O\
+	mark.$O\
+	matrix.$O\
+	move.$O\
+	over.$O\
+	paren.$O\
+	pile.$O\
+	shift.$O\
+	size.$O\
+	sqrt.$O\
+	text.$O\
+	eqn.$O\
+
+YFILES=eqn.y\
+
+HFILES=e.h\
+	y.tab.h\
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
+
+YFLAGS=-d -S
+
+eqn.c:	y.tab.c prevy.tab.h
+	mv y.tab.c $target
+
+prevy.tab.h:	y.tab.h
+	sh -c 'cmp -s y.tab.h prevy.tab.h || cp y.tab.h prevy.tab.h'
blob - /dev/null
blob + a622487c19337b6548ddd8620ea8e8af31d7f5ff (mode 644)
--- /dev/null
+++ src/cmd/eqn/move.c
@@ -0,0 +1,19 @@
+# include "e.h"
+# include "y.tab.h"
+
+void move(int dir, int amt, int p)
+{
+	double a;
+
+	yyval = p;
+	a = EM(amt/100.0, ps);
+	printf(".ds %d ", yyval);
+	if (dir == FWD || dir == BACK)
+		printf("\\h'%s%gm'\\*(%d\n", (dir==BACK) ? "-" : "", a, p);
+	else if (dir == UP)
+		printf("\\v'-%gm'\\*(%d\\v'%gm'\n", a, p, a);
+	else if (dir == DOWN)
+		printf("\\v'%gm'\\*(%d\\v'-%gm'\n", a, p, a);
+	dprintf(".\tmove %d dir %d amt %g; h=%g b=%g\n", 
+		p, dir, a, eht[yyval], ebase[yyval]);
+}
blob - /dev/null
blob + 61f93ddf336e76a759b1a413dba798d7166f5902 (mode 755)
Binary files /dev/null and src/cmd/eqn/o.eqn differ
blob - /dev/null
blob + 2794a73973ebb5055dde021a1deac95e11754e71 (mode 644)
--- /dev/null
+++ src/cmd/eqn/over.c
@@ -0,0 +1,35 @@
+#include "e.h"
+
+void boverb(int p1, int p2)
+{
+	int treg;
+	double h, b, d, d1, d2;
+	extern double Overgap, Overwid, Overline;
+
+	treg = salloc();
+	yyval = p1;
+	d = EM(Overgap, ps);
+	h = eht[p1] + eht[p2] + d;
+	b = eht[p2] - d;
+	dprintf(".\tS%d <- %d over %d; b=%g, h=%g\n", 
+		yyval, p1, p2, b, h);
+	nrwid(p1, ps, p1);
+	nrwid(p2, ps, p2);
+	printf(".nr %d \\n(%d\n", treg, p1);
+	printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, treg, treg, p2);
+	printf(".nr %d \\n(%d+%gm\n", treg, treg, Overwid);
+	d2 = eht[p2]-ebase[p2]-d;	/* denom */
+	printf(".ds %d \\v'%gm'\\h'\\n(%du-\\n(%du/2u'\\*(%d\\v'%gm'\\\n", 
+		yyval, REL(d2,ps), treg, p2, p2, REL(-d2,ps));
+	d1 = 2 * d + ebase[p1];		/* num */
+	printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\*(%d\\v'%gm'\\\n", 
+		p2, p1, REL(-d1,ps), p1, REL(d1,ps));
+	printf("\\h'-\\n(%du-\\n(%du/2u+%gm'\\v'%gm'\\l'\\n(%du-%gm'\\h'%gm'\\v'%gm'\n", 
+		treg, p1, Overline, REL(-d,ps),
+		treg, 2*Overline, Overline, REL(d,ps));
+	ebase[yyval] = b;
+	eht[yyval] = h;
+	lfont[yyval] = rfont[yyval] = 0;
+	sfree(p2);
+	sfree(treg);
+}
blob - /dev/null
blob + bb019bf750c4e0e105efd635c2e6c554dedcd95f (mode 644)
--- /dev/null
+++ src/cmd/eqn/paren.c
@@ -0,0 +1,135 @@
+#include "e.h"
+
+#define abs(x) ((x) > 0 ? (x) : (-(x)))
+
+extern void brack(int, char *, char *, char *);
+
+void paren(int leftc, int p1, int rightc)
+{
+	int n, m, j;
+	double h1, b1;
+	double v, bv;	/* v = shift of inside, bv = shift of brackets */
+	extern double Parenbase, Parenshift, Parenheight;
+
+	bv = ttype == DEVPOST ? Parenshift : 0;	/* move brackets down this much */
+	h1 = eht[p1];
+	b1 = ebase[p1];
+	yyval = p1;
+	lfont[yyval] = rfont[yyval] = 0;
+	n = REL(h1,ps) + 0.99;	/* ceiling */
+	if (n < 2)
+		n = 1;
+	m = n - 2;
+	if (leftc == '{' || rightc == '}') {
+		n = n%2 ? n : ++n;
+		if (n < 3)
+			n = 3;
+		m = n-3;
+	}
+	eht[yyval] = EM((double) n + Parenheight, ps);
+	ebase[yyval] = eht[yyval]/2 - EM(Parenbase, ps);
+
+	/* try to cope with things that are badly centered */
+	/* (top heavy or bottom heavy) */
+	if (abs(h1/2 - b1) >= EM(0.5, ps))
+		v = REL(-ebase[yyval] + (eht[yyval]-h1)/2 + b1, ps);
+	else
+		v = 0;	/* don't shift it at all */
+
+	printf(".ds %d \\^", yyval);	/* was \| */
+	if (bv)
+		printf("\\v'%gm'", bv);
+	switch (leftc) {
+	case 'n':	/* nothing */
+	case '\0':
+		break;
+	case 'f':	/* floor */
+		if (n <= 1)
+			printf("\\(lf");
+		else
+			brack(m, "\\(bv", "\\(bv", "\\(lf");
+		break;
+	case 'c':	/* ceiling */
+		if (n <= 1)
+			printf("\\(lc");
+		else
+			brack(m, "\\(lc", "\\(bv", "\\(bv");
+		break;
+	case '{':
+		printf("\\b'\\(lt");
+		for(j = 0; j < m; j += 2) printf("\\(bv");
+		printf("\\(lk");
+		for(j = 0; j < m; j += 2) printf("\\(bv");
+		printf("\\(lb'");
+		break;
+	case '(':
+		brack(m, "\\(lt", "\\(bv", "\\(lb");
+		break;
+	case '[':
+		brack(m, "\\(lc", "\\(bv", "\\(lf");
+		break;
+	case '|':
+		brack(m, "|", "|", "|");
+		break;
+	default:
+		brack(m, (char *) &leftc, (char *) &leftc, (char *) &leftc);
+		break;
+	}
+	if (bv)
+		printf("\\v'%gm'", -bv);
+	if (v)
+		printf("\\v'%gm'\\*(%d\\v'%gm'", -v, p1, v);
+	else
+		printf("\\*(%d", p1);
+	if (rightc) {
+		if (bv)
+			printf("\\v'%gm'", bv);
+		switch (rightc) {
+		case 'f':	/* floor */
+			if (n <= 1)
+				printf("\\(rf");
+			else
+				brack(m, "\\(bv", "\\(bv", "\\(rf");
+			break;
+		case 'c':	/* ceiling */
+			if (n <= 1)
+				printf("\\(rc");
+			else
+				brack(m, "\\(rc", "\\(bv", "\\(bv");
+			break;
+		case '}':
+			printf("\\b'\\(rt");
+			for(j = 0; j < m; j += 2) printf("\\(bv");
+			printf("\\(rk");
+			for(j = 0; j < m; j += 2) printf("\\(bv");
+			printf("\\(rb'");
+			break;
+		case ']':
+			brack(m, "\\(rc", "\\(bv", "\\(rf");
+			break;
+		case ')':
+			brack(m, "\\(rt", "\\(bv", "\\(rb");
+			break;
+		case '|':
+			brack(m, "|", "|", "|");
+			break;
+		default:
+			brack(m, (char *) &rightc, (char *) &rightc, (char *) &rightc);
+			break;
+		}
+		if (bv)
+			printf("\\v'%gm'", -bv);
+	}
+	printf("\n");
+	dprintf(".\tcurly: h=%g b=%g n=%d v=%g l=%c, r=%c\n", 
+		eht[yyval], ebase[yyval], n, v, leftc, rightc);
+}
+
+void brack(int m, char *t, char *c, char *b)
+{
+	int j;
+	printf("\\b'%s", t);
+	for( j=0; j < m; j++)
+		printf("%s", c);
+	printf("%s'", b);
+}
blob - /dev/null
blob + a2d16239c877569f17bfaa41675cd4451b6287c5 (mode 644)
--- /dev/null
+++ src/cmd/eqn/pile.c
@@ -0,0 +1,76 @@
+#include "e.h"
+#include "y.tab.h"
+
+void pile(int oct)
+{
+	int i, nlist, nlist2, mid;
+	double bi, h, b, gap, sb;
+	extern double Pilegap, Pilebase;
+	int type, p1, p2;
+
+	yyval = salloc();
+	type = lp[oct];
+	p1 = oct + 3;		/* first entry */
+	p2 = p1 + lp[oct+1];	/* 1 after last */
+	gap = lp[oct+2];
+	if (gap != DEFGAP)
+		gap = EM(gap/100.0, ps);
+	else if (type == COL)
+		gap = 0;
+	else
+		gap = EM(Pilegap, ps);	/* 0.4 m between LCOL, etc. */
+	nlist = p2 - p1;
+	nlist2 = (nlist+1)/2;
+	mid = p1 + nlist2 - 1;
+	h = 0;
+	for (i = p1; i < p2; i++)
+		h += eht[lp[i]];
+	eht[yyval] = h + (nlist-1)*gap;
+	b = 0;
+	for (i = p2-1; i > mid; i--)
+		b += eht[lp[i]] + gap;
+	ebase[yyval] = (nlist%2) ? b + ebase[lp[mid]]
+			: b - EM(Pilebase, ps) - gap;
+	if (dbg) {
+		printf(".\tS%d <- %d pile of:", yyval, type);
+		for (i = p1; i < p2; i++)
+			printf(" S%d", lp[i]);
+		printf("; h=%g b=%g\n", eht[yyval], ebase[yyval]);
+	}
+	nrwid(lp[p1], ps, lp[p1]);
+	printf(".nr %d \\n(%d\n", yyval, lp[p1]);
+	for (i = p1+1; i < p2; i++) {
+		nrwid(lp[i], ps, lp[i]);
+		printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", 
+			lp[i], yyval, yyval, lp[i]);
+	}
+	printf(".ds %d \\v'%gm'\\h'%du*\\n(%du'\\\n", yyval, REL(ebase[yyval],ps), 
+		type==RCOL ? 1 : 0, yyval);
+	sb = 0;		/* sum of box hts */
+	for (i = p2-1; i >= p1; i--) {
+		bi = sb + ebase[lp[i]];
+		switch (type) {
+		case LCOL:
+			printf("\\v'%gm'\\*(%d\\h'-\\n(%du'\\v'%gm'\\\n", 
+				REL(-bi,ps), lp[i], lp[i], REL(bi,ps));
+			break;
+		case RCOL:
+			printf("\\v'%gm'\\h'-\\n(%du'\\*(%d\\v'%gm'\\\n", 
+				REL(-bi,ps), lp[i], lp[i], REL(bi,ps));
+			break;
+		case CCOL:
+		case COL:
+			printf("\\v'%gm'\\h'\\n(%du-\\n(%du/2u'\\*(%d", 
+				REL(-bi,ps), yyval, lp[i], lp[i]);
+			printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\\n", 
+				yyval, lp[i], REL(bi,ps));
+			break;
+		}
+		sb += eht[lp[i]] + gap;
+	}
+	printf("\\v'%gm'\\h'%du*\\n(%du'\n", REL(-ebase[yyval],ps), 
+		type!=RCOL ? 1 : 0, yyval);
+	for (i = p1; i < p2; i++)
+		sfree(lp[i]);
+	lfont[yyval] = rfont[yyval] = 0;
+}
blob - /dev/null
blob + 1f6d3c718dc69a167a48bdaa376132ca3e8be589 (mode 644)
--- /dev/null
+++ src/cmd/eqn/prevy.tab.h
@@ -0,0 +1,57 @@
+#define	CONTIG	57346
+#define	QTEXT	57347
+#define	SPACE	57348
+#define	THIN	57349
+#define	TAB	57350
+#define	MATRIX	57351
+#define	LCOL	57352
+#define	CCOL	57353
+#define	RCOL	57354
+#define	COL	57355
+#define	ABOVE	57356
+#define	MARK	57357
+#define	LINEUP	57358
+#define	SUM	57359
+#define	INT	57360
+#define	PROD	57361
+#define	UNION	57362
+#define	INTER	57363
+#define	DEFINE	57364
+#define	TDEFINE	57365
+#define	NDEFINE	57366
+#define	DELIM	57367
+#define	GSIZE	57368
+#define	GFONT	57369
+#define	INCLUDE	57370
+#define	IFDEF	57371
+#define	DOTEQ	57372
+#define	DOTEN	57373
+#define	FROM	57374
+#define	TO	57375
+#define	OVER	57376
+#define	SQRT	57377
+#define	SUP	57378
+#define	SUB	57379
+#define	SIZE	57380
+#define	FONT	57381
+#define	ROMAN	57382
+#define	ITALIC	57383
+#define	BOLD	57384
+#define	FAT	57385
+#define	UP	57386
+#define	DOWN	57387
+#define	BACK	57388
+#define	FWD	57389
+#define	LEFT	57390
+#define	RIGHT	57391
+#define	DOT	57392
+#define	DOTDOT	57393
+#define	HAT	57394
+#define	TILDE	57395
+#define	BAR	57396
+#define	LOWBAR	57397
+#define	HIGHBAR	57398
+#define	UNDER	57399
+#define	VEC	57400
+#define	DYAD	57401
+#define	UTILDE	57402
blob - /dev/null
blob + dbac530b40b1493fd6a57dff497767d547670f1f (mode 644)
--- /dev/null
+++ src/cmd/eqn/shift.c
@@ -0,0 +1,116 @@
+#include "e.h"
+#include "y.tab.h"
+
+void subsup(int p1, int p2, int p3)
+{
+	if (p2 != 0 && p3 != 0)
+		shift2(p1, p2, p3);
+	else if (p2 != 0)
+		bshiftb(p1, SUB, p2);
+	else if (p3 != 0)
+		bshiftb(p1, SUP, p3);
+}
+
+extern double Subbase, Supshift;
+extern char *Sub1space, *Sup1space, *Sub2space;
+extern char *SS1space, *SS2space;
+
+void bshiftb(int p1, int dir, int p2)
+{
+	int subps, n;
+	double shval, d1, h1, b1, h2, b2;
+	char *sh1, *sh2;
+
+	yyval = p1;
+	h1 = eht[p1];
+	b1 = ebase[p1];
+	h2 = eht[p2];
+	b2 = ebase[p2];
+	subps = ps;
+	ps += deltaps;
+	if (dir == SUB) {
+		/* base .2m below bottom of main box */
+		shval = b1 + EM(Subbase, ps);
+		ebase[yyval] = shval + b2;
+		eht[yyval] = max(h1-b1+shval+b2, h2);
+		if (rfont[p1] == ITAL && lfont[p2] == ROM)
+			n = 2;		/* Sub1space */
+		else
+			n = max(2, class[rclass[p1]][lclass[p2]]);
+		sh1 = pad(n);
+		rclass[p1] = OTHER;	/* OTHER leaves too much after sup */
+	} else {	/* superscript */
+		/* 4/10 up main box */
+		d1 = EM(Subbase, subps);
+		ebase[yyval] = b1;
+		shval = -(Supshift * (h1-b1)) - b2;
+		if (Supshift*(h1-b1) + h2 < h1-b1)	/* raise little super */
+			shval = -(h1-b1) + h2-b2 - d1;
+		eht[yyval] = h1 + max(0, h2 - (1-Supshift)*(h1-b1));
+		if (rclass[p1] == ILETF)
+			n = 4;
+		else if (rfont[p1] == ITAL)
+			n = 2;		/* Sup1space */
+		else
+			n = max(1, class[rclass[p1]][lclass[p2]]);
+		sh1 = pad(n);
+		rclass[p1] = rclass[p2];	/* OTHER leaves too much after sup */
+	}
+	dprintf(".\tS%d <- %d shift %g %d; b=%g, h=%g, ps=%d, subps=%d\n", 
+		yyval, p1, shval, p2, ebase[yyval], eht[yyval], ps, subps);
+	sh2 = Sub2space;	/* was Sub2space; */
+	printf(".as %d \\v'%gm'%s%s\\*(%d%s%s\\v'%gm'\n", 
+		yyval, REL(shval,ps), DPS(ps,subps), sh1, p2,
+		DPS(subps,ps), sh2, REL(-shval,ps));
+	rfont[p1] = 0;
+	sfree(p2);
+}
+
+void shift2(int p1, int p2, int p3)
+{
+	int subps;
+	double h1, h2, h3, b1, b2, b3, subsh, d2, supsh;
+	int treg;
+	char *sh2;
+
+	treg = salloc();
+	yyval = p1;
+	subps = ps;	/* sub and sup at this size */
+	ps += deltaps;	/* outer size */
+	h1 = eht[p1]; b1 = ebase[p1];
+	h2 = eht[p2]; b2 = ebase[p2];
+	h3 = eht[p3]; b3 = ebase[p3];
+	subsh = EM(Subbase, ps);
+	if (b1 > b2 + subsh) /* move little sub down */
+		subsh += b1;
+	eht[yyval] = max(subsh+b2-b1+h1, h2);
+	supsh = -Supshift*(h1-b1) - b3;
+	d2 = EM(Subbase, subps);
+	if (h3 < (1-Supshift)*(h1-b1))
+		supsh = -(h1-b1) + (h3-b3) - d2;
+	ebase[yyval] = subsh + b2 - b1;
+	eht[yyval] = h1 + subsh+b2-b1 + max(0, h3-(1-Supshift)*(h1-b1));
+	dprintf(".\tS%d <- %d sub %d sup %d, ps=%d, subps=%d, h=%g, b=%g\n",
+		yyval, p1, p2, p3, ps, subps, eht[yyval], ebase[yyval]);
+	if (rclass[p1] == ILETF)
+		sh2 = "\\|\\|";
+	else
+		sh2 = SS2space;
+	/*n = max(class[rclass[p1]][lclass[p2]], class[rclass[p1]][lclass[p3]]);
+	/*sh2 = pad(max(2, n));
+	*/
+	printf(".ds %d %s\\*(%d\n", p2, SS1space, p2);
+	nrwid(p2, subps, p2);
+	printf(".ds %d %s\\*(%d\n", p3, sh2, p3);
+	nrwid(p3, subps, p3);
+	printf(".nr %d \\n(%d\n", treg, p3);
+	printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, treg, treg, p2);
+	printf(".as %d %s\\v'%gm'\\*(%d\\v'%gm'\\h'-\\n(%du'\\\n", 
+		p1, DPS(ps,subps), REL(subsh,subps), p2, REL(-subsh,subps), p2);
+	printf("\\v'%gm'\\*(%d\\v'%gm'\\h'-\\n(%du+\\n(%du'%s%s\n", 
+		REL(supsh,subps), p3, REL(-supsh,subps), p3, treg, DPS(subps,ps), Sub2space);
+	if (rfont[p2] == ITAL)
+		rfont[yyval] = 0;	/* lie */
+	rclass[yyval] = rclass[p3];	/* was OTHER */
+	sfree(p2); sfree(p3); sfree(treg);
+}
blob - /dev/null
blob + 59bf3f20b4322d30a07a82a09b3a3747d3106e7e (mode 644)
--- /dev/null
+++ src/cmd/eqn/size.c
@@ -0,0 +1,70 @@
+#include "e.h"
+#include <ctype.h>
+
+void setsize(char *p)	/* set size as found in p */
+{
+	nszstack++;
+	szstack[nszstack] = 0;		/* assume relative */
+	if (*p == '+') {
+		ps += atoi(p+1);
+		if (szstack[nszstack-1] != 0)	/* propagate absolute size */
+			szstack[nszstack] = ps;
+	} else if (*p == '-') {
+		ps -= atoi(p+1);
+		if (szstack[nszstack-1] != 0)
+			szstack[nszstack] = ps;
+	} else if (isdigit(*p)) {
+		if (szstack[nszstack-1] == 0)
+			printf(".nr %d \\n(.s\n", 99-nszstack);
+		else
+			printf(".nr %d %d\n", 99-nszstack, ps);
+		szstack[nszstack] = ps = atoi(p);
+	} else {
+		ERROR "illegal size %s ignored", p WARNING;
+	}
+	dprintf(".\tsetsize %s; ps = %d\n", p, ps);
+}
+
+void size(int p1, int p2)
+{
+		/* old size in p1, new in ps */
+	yyval = p2;
+	dprintf(".\tS%d <- \\s%d %d \\s%d; b=%g, h=%g\n", 
+		yyval, ps, p2, p1, ebase[yyval], eht[yyval]);
+	if (szstack[nszstack] != 0) {
+		printf(".ds %d %s\\*(%d\\s\\n(%d\n", yyval, ABSPS(ps), p2, 99-nszstack);
+	} else
+		printf(".ds %d %s\\*(%d%s\n", yyval, DPS(p1,ps), p2, DPS(ps,p1));
+	nszstack--;
+	ps = p1;
+}
+
+void globsize(void)
+{
+	char temp[20];
+
+	getstr(temp, sizeof(temp));
+	if (temp[0] == '+') {
+		gsize += atoi(temp+1);
+		if (szstack[0] != 0)
+			szstack[0] = gsize;
+	} else if (temp[0] == '-') {
+		gsize -= atoi(temp+1);
+		if (szstack[0] != 0)
+			szstack[0] = gsize;
+	} else  if (isdigit(temp[0])) {
+		gsize = atoi(temp);
+		szstack[0] = gsize;
+		printf(".nr 99 \\n(.s\n");
+	} else {
+		ERROR "illegal gsize %s ignored", temp WARNING;
+	}
+	yyval = eqnreg = 0;
+	ps = gsize;
+	if (gsize < 12 && !dps_set)		/* sub and sup size change */
+		deltaps = gsize / 3;
+	else if (gsize < 20)
+		deltaps = gsize / 4;
+	else
+		deltaps = gsize / 5;
+}
blob - /dev/null
blob + 391d924e2d0f6d73b0dc53510041b59737d1b12c (mode 644)
--- /dev/null
+++ src/cmd/eqn/sqrt.c
@@ -0,0 +1,35 @@
+#include "e.h"
+
+void sqrt(int p2)
+{
+	static int af = 0;
+	int nps;	/* point size for radical */
+	double radscale = 0.95;
+
+	if (ttype == DEVPOST)
+		radscale = 1.05;
+	nps = ps * radscale * eht[p2] / EM(1.0,ps) + 0.99;	/* kludgy */
+	nps = max(EFFPS(nps), ps);
+	yyval = p2;
+	if (ttype == DEVCAT || ttype == DEVAPS)
+		eht[yyval] = EM(1.2, nps);
+	else if (ttype == DEVPOST)
+		eht[yyval] = EM(1.15, nps);
+	else		/* DEV202, DEVPOST */
+		eht[yyval] = EM(1.15, nps);
+	dprintf(".\tS%d <- sqrt S%d;b=%g, h=%g, nps=%d\n", 
+		yyval, p2, ebase[yyval], eht[yyval], nps);
+	printf(".as %d \\|\n", yyval);
+	nrwid(p2, ps, p2);
+	if (af++ == 0)
+		printf(".af 10 01\n");	/* make it two digits when it prints */
+	printf(".nr 10 %.3fu*\\n(.su/10\n", 9.2*eht[p2]);	/* this nonsense */
+			/* guesses point size corresponding to height of stuff */
+	printf(".ds %d \\v'%gm'\\s(\\n(10", yyval, REL(ebase[p2],ps));
+	if (ttype == DEVCAT || ttype == DEVAPS)
+		printf("\\v'-.2m'\\(sr\\l'\\n(%du\\(rn'\\v'.2m'", p2);
+	else		/* DEV202, DEVPOST so far */
+		printf("\\(sr\\l'\\n(%du\\(rn'", p2);
+	printf("\\s0\\v'%gm'\\h'-\\n(%du'\\^\\*(%d\n", REL(-ebase[p2],ps), p2, p2);
+	lfont[yyval] = rfont[yyval] = ROM;
+}
blob - /dev/null
blob + 261c7fbfc33180f6a68b4abcb05fee01bcbe3fa0 (mode 644)
--- /dev/null
+++ src/cmd/eqn/text.c
@@ -0,0 +1,318 @@
+#include "e.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+#define	CSSIZE	1000
+char	cs[CSSIZE+20];	/* text string converted into this */
+char	*csp;		/* next spot in cs[] */
+char	*psp;		/* next character in input token */
+
+int	lf, rf;		/* temporary spots for left and right fonts */
+int	lastft;		/* last \f added */
+int	nextft;		/* next \f to be added */
+
+int	pclass;		/* class of previous character */
+int	nclass;		/* class of next character */
+
+int class[LAST][LAST] ={	/* guesswork, tuned to times roman postscript */
+
+	/*OT OL IL DG LP RP SL PL IF IJ VB */
+/*OT*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 },		/* OTHER */
+/*OL*/	{ 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 },		/* OLET */
+/*IL*/	{ 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 },		/* ILET */
+/*DG*/	{ 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 },		/* DIG */
+/*LP*/	{ 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 },		/* LPAR */
+/*RP*/	{ 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 },		/* RPAR */
+/*SL*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 },		/* SLASH */
+/*PL*/	{ 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 },		/* PLUS */
+/*IF*/	{ 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 },		/* ILETF */
+/*IJ*/	{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 },		/* ILETJ */
+/*VB*/	{ 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 },		/* VBAR */
+
+};
+
+extern void shim(int, int);
+extern void roman(int);
+extern void sadd(char *);
+extern void cadd(int);
+extern int trans(int, char *);
+
+int textc(void)	/* read next UTF rune from psp */
+{
+	wchar_t r;
+	int w;
+
+	w = mbtowc(&r, psp, 3);
+	if(w == 0){
+		psp++;
+		return 0;
+	}
+	if(w < 0){
+		psp += 1;
+		return 0x80;	/* Plan 9-ism */
+	}
+	psp += w;
+	return r;
+}
+
+void text(int t, char *p1)	/* convert text string p1 of type t */
+{
+	int c;
+	char *p;
+	tbl *tp;
+
+	yyval = salloc();
+	ebase[yyval] = 0;
+	eht[yyval] = EM(1.0, ps);	/* ht in ems of orig size */
+	lfont[yyval] = rfont[yyval] = ROM;
+	lclass[yyval] = rclass[yyval] = OTHER;
+	if (t == QTEXT) {
+		for (p = p1; *p; p++)	/* scan for embedded \f's */
+			if (*p == '\\' && *(p+1) == 'f')
+				break;
+		if (*p)		/* if found \f, leave it alone and hope */
+			p = p1;
+		else {
+			sprintf(cs, "\\f%s%s\\fP", ftp->name, p1);
+			p = cs;
+		}
+	} else if (t == SPACE)
+		p = "\\ ";
+	else if (t == THIN)
+		p = "\\|";
+	else if (t == TAB)
+		p = "\\t";
+	else if ((tp = lookup(restbl, p1)) != NULL) {
+		p = tp->cval;
+	} else {
+		lf = rf = 0;
+		lastft = 0;
+		nclass = NONE;	/* get started with no class == no pad */
+		csp = cs;
+		for (psp = p1; (c = textc()) != '\0'; ) {
+			nextft = ft;
+			pclass = nclass;
+			rf = trans(c, p1);
+			if (lf == 0) {
+				lf = rf;	/* left stuff is first found */
+				lclass[yyval] = nclass;
+			}
+			if (csp-cs > CSSIZE)
+				ERROR "converted token %.25s... too long", p1 FATAL ;
+		}
+		sadd("\\fP");
+		*csp = '\0';
+		p = cs;
+		lfont[yyval] = lf;
+		rfont[yyval] = rf;
+		rclass[yyval] = nclass;
+	}
+	dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n",
+		t, yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps);
+	printf(".ds %d \"%s\n", yyval, p);
+}
+
+int isalpharune(int c)
+{
+	return ('a'<=c && c<='z') || ('A'<=c && c<='Z');
+}
+
+int isdigitrune(int c)
+{
+	return ('0'<=c && c<='9');
+}
+
+trans(int c, char *p1)
+{
+	int f;
+
+	if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') {	/* italic letter */
+		shim(pclass, nclass = ILET);
+		cadd(c);
+		return ITAL;
+	}
+	if (isalpharune(c) && ft != ITAL) {		/* other letter */
+		shim(pclass, nclass = OLET);
+		cadd(c);
+		return ROM;
+	}
+	if (isdigitrune(c)) {
+		shim(pclass, nclass = DIG);
+		roman(c);
+		return ROM;	/* this is the right side font of this object */
+	}
+	f = ROM;
+	nclass = OTHER;
+	switch (c) {
+	case ':': case ';': case '!': case '%': case '?':
+		shim(pclass, nclass);
+		roman(c);
+		return f;
+	case '(': case '[':
+		shim(pclass, nclass = LPAR);
+		roman(c);
+		return f;
+	case ')': case ']':
+		shim(pclass, nclass = RPAR);
+		roman(c);
+		return f;
+	case ',':
+		shim(pclass, nclass = OTHER);
+		roman(c);
+		return f;
+	case '.':
+		if (rf == ROM)
+			roman(c);
+		else
+			cadd(c);
+		return f;
+	case '|':		/* postscript needs help with default width! */
+		shim(pclass, nclass = VBAR);
+		sadd("\\v'.17m'\\z|\\v'-.17m'\\|");	/* and height */
+		return f;
+	case '=':
+		shim(pclass, nclass = PLUS);
+		sadd("\\(eq");
+		return f;
+	case '+':
+		shim(pclass, nclass = PLUS);
+		sadd("\\(pl");
+		return f;
+	case '>':
+	case '<':		/* >, >=, >>, <, <-, <=, << */
+		shim(pclass, nclass = PLUS);
+		if (*psp == '=') {
+			sadd(c == '<' ? "\\(<=" : "\\(>=");
+			psp++;
+		} else if (c == '<' && *psp == '-') {	/* <- only */
+			sadd("\\(<-");
+			psp++;
+		} else if (*psp == c) {		/* << or >> */
+			cadd(c);
+			cadd(c);
+			psp++;
+		} else {
+			cadd(c);  
+		}
+		return f;
+	case '-':
+		shim(pclass, nclass = PLUS);	/* probably too big for ->'s */
+		if (*psp == '>') {
+			sadd("\\(->");
+			psp++;
+		} else {
+			sadd("\\(mi");
+		}
+		return f;
+	case '/':
+		shim(pclass, nclass = SLASH);
+		cadd('/');
+		return f;
+	case '~':
+	case ' ':
+		sadd("\\|\\|");
+		return f;
+	case '^':
+		sadd("\\|");
+		return f;
+	case '\\':	/* troff - pass only \(xx without comment */
+		shim(pclass, nclass);
+		cadd('\\');
+		cadd(c = *psp++);
+		if (c == '(' && *psp && *(psp+1)) {
+			cadd(*psp++);
+			cadd(*psp++);
+		} else
+			fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n",
+				c, curfile->fname, curfile->lineno);
+		return f;
+	case '\'':
+		shim(pclass, nclass);
+		sadd("\\(fm");
+		return f;
+
+	case 'f':
+		if (ft == ITAL) {
+			shim(pclass, nclass = ILETF);
+			cadd('f');
+			f = ITAL;
+		} else
+			cadd('f');
+		return f;
+	case 'j':
+		if (ft == ITAL) {
+			shim(pclass, nclass = ILETJ);
+			cadd('j');
+			f = ITAL;
+		} else
+			cadd('j');
+		return f;
+	default:
+		shim(pclass, nclass);
+		cadd(c);
+		return ft==ITAL ? ITAL : ROM;
+	}
+}
+
+char *pad(int n)	/* return the padding as a string */
+{
+	static char buf[20];
+
+	buf[0] = 0;
+	if (n < 0) {
+		sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n);
+		return buf;
+	}	
+	for ( ; n > 1; n -= 2)
+		strcat(buf, "\\|");
+	if (n > 0)
+		strcat(buf, "\\^");
+	return buf;
+}
+
+void shim(int lc, int rc)	/* add padding space suitable to left and right classes */
+{
+	sadd(pad(class[lc][rc]));
+}
+
+void roman(int c)	/* add char c in "roman" font */
+{
+	nextft = ROM;
+	cadd(c);
+}
+
+void sadd(char *s)		/* add string s to cs */
+{
+	while (*s)
+		cadd(*s++);
+}
+
+void cadd(int c)		/* add character c to end of cs */
+{
+	char *p;
+	int w;
+
+	if (lastft != nextft) {
+		if (lastft != 0) {
+			*csp++ = '\\';
+			*csp++ = 'f';
+			*csp++ = 'P';
+		}
+		*csp++ = '\\';
+		*csp++ = 'f';
+		if (ftp == ftstack) {	/* bottom level */
+			if (ftp->ft == ITAL)	/* usual case */
+				*csp++ = nextft;
+			else		/* gfont set, use it */
+				for (p = ftp->name; *csp = *p++; )
+					csp++;
+		} else {	/* inside some kind of font ... */
+			for (p = ftp->name; *csp = *p++; )
+				csp++;
+		}
+		lastft = nextft;
+	}
+	w = wctomb(csp, c);
+	if(w > 0)	/* ignore bad characters */
+		csp += w;
+}
blob - /dev/null
blob + 99718db3e8d335012211007157a808e1756dd579 (mode 644)
--- /dev/null
+++ src/cmd/eqn/tuning.c
@@ -0,0 +1,153 @@
+#include "e.h"
+
+/*
+
+This file contains parameter values for many of the
+tuning parameters in eqn.  Names are defined words.
+
+Strings are plugged in verbatim.
+Floats are usually in ems.
+
+*/
+
+/* In main.c: */
+
+double	BeforeSub = 1.2;	/* line space before a subscript */
+double	AfterSub  = 0.2;	/* line space after a subscript */
+
+/* diacrit.c: */
+
+double	Dvshift	= 0.25;		/* vertical shift for diacriticals on tall letters */
+double	Dhshift = 0.025;	/* horizontal shift for tall letters */
+double	Dh2shift = 0.05;	/* horizontal shift for small letters */
+double	Dheight	= 0.25;		/* increment to height for diacriticals */
+double	Barv	= 0.68;		/* vertical shift for bar */
+double	Barh	= 0.05;		/* 1/2 horizontal shrink for bar */
+double	Ubarv	= 0.1;		/* shift underbar up this much ems */
+double	Ubarh	= 0.05;		/* 1/2 horizontal shrink for underbar */
+
+/* Also:
+	Vec, Dyad, Hat, Tilde, Dot, Dotdot, Utilde */
+
+/* eqnbox.c: */
+
+char	*IRspace = "\\^";	/* space between italic & roman boxes */
+
+/* fat.c: */
+
+double	Fatshift = 0.05;	/* fattening shifts by Fatshift ems */
+
+/* funny.c: */
+
+int	Funnyps	= 5;		/* point size change (== 5 above) */
+double	Funnyht = 0.2;		/* height correction */
+double	Funnybase = 0.3;	/* base correction */
+
+/* integral.c: */
+
+int	Intps	= 4;		/* point size change for integral (== 4 above) */
+double	Intht	= 1.15;		/* ht of integral in ems */
+double	Intbase	= 0.3;		/* base in ems */
+double	Int1h	= 0.4;		/* lower limit left */
+double	Int1v	= 0.2;		/* lower limit down */
+double	Int2h	= 0.05;		/* upper limit right was 8 */
+double	Int2v	= 0.1;		/* upper limit up */
+
+/* matrix.c: */
+
+char	*Matspace = "\\ \\ ";	/* space between matrix columns */
+
+/* over.c: */
+
+double	Overgap	= 0.3;		/* gap between num and denom */
+double	Overwid	= 0.5;		/* extra width of box */
+double	Overline = 0.1;		/* extra length of fraction bar */
+
+/* paren.c* */
+
+double	Parenbase = 0.4;	/* shift of base for even count */
+double	Parenshift = 0.13;	/* how much to shift parens down in left ... */
+				/* ignored unless postscript */
+double	Parenheight = 0.3;	/* extra height above builtups */
+
+/* pile.c: */
+
+double	Pilegap	= 0.4;		/* gap between pile elems */
+double	Pilebase = 0.5;		/* shift base of even # of piled elems */
+
+/* shift.c: */
+
+double	Subbase	= 0.2;		/* subscript base belowe main base */
+double	Supshift = 0.4;		/* superscript .4 up main box */
+char	*Sub1space = "\\|";	/* italic sub roman space */
+char	*Sup1space = "\\|";	/* italic sup roman space */
+char	*Sub2space = "\\^";	/* space after subscripted thing */
+char	*SS1space = "\\^";	/* space before sub in x sub i sup j */
+char	*SS2space = "\\^";	/* space before sup */
+
+/* sqrt.c: */
+	/* sqrt is hard!  punt for now. */
+	/* part of the problem is that every typesetter does it differently */
+	/* and we have several typesetters to run. */
+
+/* text.c: */
+	/* ought to be done by a table */
+
+struct tune {
+	char	*name;
+	char	*cval;
+} tune[]	={
+  /* diacrit.c */
+	"vec_def",	"\\f1\\v'-.5m'\\s-3\\(->\\s0\\v'.5m'\\fP",	/* was \s-2 & .45m */
+	"dyad_def",	"\\f1\\v'-.5m'\\s-3\\z\\(<-\\|\\(->\\s0\\v'.5m'\\fP",
+	"hat_def",	"\\f1\\v'-.05m'\\s+1^\\s0\\v'.05m'\\fP",	/* was .1 */
+	"tilde_def",	"\\f1\\v'-.05m'\\s+1~\\s0\\v'.05m'\\fP",
+	"dot_def",	"\\f1\\v'-.67m'.\\v'.67m'\\fP",
+	"dotdot_def",	"\\f1\\v'-.67m'..\\v'.67m'\\fP",
+	"utilde_def",	"\\f1\\v'1.0m'\\s+2~\\s-2\\v'-1.0m'\\fP",
+  /* funny.c */
+	"sum_def",	"\\|\\v'.3m'\\s+5\\(*S\\s-5\\v'-.3m'\\|",
+	"union_def",	"\\|\\v'.3m'\\s+5\\(cu\\s-5\\v'-.3m'\\|",
+	"inter_def",	"\\|\\v'.3m'\\s+5\\(ca\\s-5\\v'-.3m'\\|",
+	"prod_def",	"\\|\\v'.3m'\\s+5\\(*P\\s-5\\v'-.3m'\\|",
+  /* integral.c */
+	"int_def",	"\\v'.1m'\\s+4\\(is\\s-4\\v'-.1m'",
+	0, 0
+};
+
+tbl	*ftunetbl[TBLSIZE];	/* user-defined names */
+
+char *ftunes[] ={	/* this table intentionally left small */
+	"Subbase",
+	"Supshift",
+	0
+};
+
+void init_tune(void)
+{
+	int i;
+
+	for (i = 0; tune[i].name != NULL; i++)
+		install(deftbl, tune[i].name, tune[i].cval, 0);
+	for (i = 0; ftunes[i] != NULL; i++)
+		install(ftunetbl, ftunes[i], (char *) 0, 0);
+}
+
+#define eq(s, t) (strcmp(s,t) == 0)
+
+void ftune(char *s, char *t)	/* brute force for now */
+{
+	double f = atof(t);
+	double *target;
+
+	while (*t == ' ' || *t == '\t')
+		t++;
+	if (eq(s, "Subbase"))
+		target = &Subbase;
+	else if (eq(s, "Supshift"))
+		target = &Supshift;
+	if (t[0] == '+' || t[0] == '-')
+		*target += f;
+	else
+		*target = f;
+}
blob - /dev/null
blob + 1f6d3c718dc69a167a48bdaa376132ca3e8be589 (mode 644)
--- /dev/null
+++ src/cmd/eqn/y.tab.h
@@ -0,0 +1,57 @@
+#define	CONTIG	57346
+#define	QTEXT	57347
+#define	SPACE	57348
+#define	THIN	57349
+#define	TAB	57350
+#define	MATRIX	57351
+#define	LCOL	57352
+#define	CCOL	57353
+#define	RCOL	57354
+#define	COL	57355
+#define	ABOVE	57356
+#define	MARK	57357
+#define	LINEUP	57358
+#define	SUM	57359
+#define	INT	57360
+#define	PROD	57361
+#define	UNION	57362
+#define	INTER	57363
+#define	DEFINE	57364
+#define	TDEFINE	57365
+#define	NDEFINE	57366
+#define	DELIM	57367
+#define	GSIZE	57368
+#define	GFONT	57369
+#define	INCLUDE	57370
+#define	IFDEF	57371
+#define	DOTEQ	57372
+#define	DOTEN	57373
+#define	FROM	57374
+#define	TO	57375
+#define	OVER	57376
+#define	SQRT	57377
+#define	SUP	57378
+#define	SUB	57379
+#define	SIZE	57380
+#define	FONT	57381
+#define	ROMAN	57382
+#define	ITALIC	57383
+#define	BOLD	57384
+#define	FAT	57385
+#define	UP	57386
+#define	DOWN	57387
+#define	BACK	57388
+#define	FWD	57389
+#define	LEFT	57390
+#define	RIGHT	57391
+#define	DOT	57392
+#define	DOTDOT	57393
+#define	HAT	57394
+#define	TILDE	57395
+#define	BAR	57396
+#define	LOWBAR	57397
+#define	HIGHBAR	57398
+#define	UNDER	57399
+#define	VEC	57400
+#define	DYAD	57401
+#define	UTILDE	57402
blob - /dev/null
blob + 72f0fc3ae8d1573fab3d8819c23803b151db4037 (mode 644)
--- /dev/null
+++ src/cmd/grap/coord.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "grap.h"
+#include "y.tab.h"
+
+char	*dflt_coord = "gg";
+char	*curr_coord = "gg";
+int	ncoord	= 0;	/* number of explicit coord's given */
+
+Point	xcoord;
+Point	ycoord;
+int	xcflag	= 0;	/* 1 if xcoord set */
+int	ycflag	= 0;
+int	logcoord = 0;
+
+void coord_x(Point pt)	/* remember x coord */
+{
+	xcoord = pt;
+	xcflag = 1;
+	margin = 0;	/* no extra space around picture if explicit coords */
+}
+
+void coord_y(Point pt)
+{
+	ycoord = pt;
+	ycflag = 1;
+	margin = 0;	/* no extra space if explicit coords */
+}
+
+void coordlog(int n)	/* remember log scaling */
+{
+	logcoord = n;
+}
+
+void coord(Obj *p)	/* set coord range */
+{
+	static char buf[10];
+
+	ncoord++;
+	if (ncoord > 1 && strcmp(p->name, dflt_coord) == 0) {
+		/* resetting default coordinate by implication */
+		sprintf(buf, "gg%d", ncoord);
+		dflt_coord = buf;
+		p = lookup(dflt_coord, 1);
+	}
+	if (xcflag) {
+		p->coord |= XFLAG;
+		p->pt.x = min(xcoord.x,xcoord.y);	/* "xcoord" is xmin, xmax */
+		p->pt1.x = max(xcoord.x,xcoord.y);
+		if ((logcoord&XFLAG) && p->pt.x <= 0.0)
+			ERROR "can't have log of x coord %g,%g", p->pt.x, p->pt1.x FATAL;
+		xcflag = 0;
+	}
+	if (ycflag) {
+		p->coord |= YFLAG;
+		p->pt.y = min(ycoord.x,ycoord.y);	/* "ycoord" is ymin, ymax */
+		p->pt1.y = max(ycoord.x,ycoord.y);
+		if ((logcoord&YFLAG) && p->pt.y <= 0.0)
+			ERROR "can't have log of y coord %g,%g", p->pt.y, p->pt1.y FATAL;
+		ycflag = 0;
+	}
+	p->log = logcoord;
+	logcoord = 0;
+	auto_x = 0;
+}
+
+void resetcoord(Obj *p)	/* reset current coordinate */
+{
+	curr_coord = p->name;
+}
blob - /dev/null
blob + 1c2e905b7e41715703979478a52c125416fd29b7 (mode 644)
--- /dev/null
+++ src/cmd/grap/find
@@ -0,0 +1 @@
+exec /usr/bin/egrep -n "$1" *.[chyl]
blob - /dev/null
blob + 84de388d4d7ac4f8b82e5e1b2eb344e58640839b (mode 644)
--- /dev/null
+++ src/cmd/grap/for.c
@@ -0,0 +1,89 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "grap.h"
+#include "y.tab.h"
+
+typedef struct {
+	Obj	*var;	/* index variable */
+	double	to;	/* limit */
+	double	by;
+	int	op;	/* operator */
+	char	*str;	/* string to push back */
+} For;
+
+#define	MAXFOR	10
+
+For	forstk[MAXFOR];	/* stack of for loops */
+For	*forp = forstk;	/* pointer to current top */
+
+void forloop(Obj *var, double from, double to, int op, double by, char *str)	/* set up a for loop */
+{
+	fprintf(tfd, "# for %s from %g to %g by %c %g \n",
+		var->name, from, to, op, by);
+	if (++forp >= forstk+MAXFOR)
+		ERROR "for loop nested too deep" FATAL;
+	forp->var = var;
+	forp->to = to;
+	forp->op = op;
+	forp->by = by;
+	forp->str = str;
+	setvar(var, from);
+	nextfor();
+	unput('\n');
+}
+
+void nextfor(void)	/* do one iteration of a for loop */
+{
+	/* BUG:  this should depend on op and direction */
+	if (forp->var->fval > SLOP * forp->to) {	/* loop is done */
+		free(forp->str);
+		if (--forp < forstk)
+			ERROR "forstk popped too far" FATAL;
+	} else {		/* another iteration */
+		pushsrc(String, "\nEndfor\n");
+		pushsrc(String, forp->str);
+	}
+}
+
+void endfor(void)	/* end one iteration of for loop */
+{
+	switch (forp->op) {
+	case '+':
+	case ' ':
+		forp->var->fval += forp->by;
+		break;
+	case '-':
+		forp->var->fval -= forp->by;
+		break;
+	case '*':
+		forp->var->fval *= forp->by;
+		break;
+	case '/':
+		forp->var->fval /= forp->by;
+		break;
+	}
+	nextfor();
+}
+
+char *ifstat(double expr, char *thenpart, char *elsepart)
+{
+	dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : "");
+	if (expr) {
+		unput('\n');
+		pushsrc(Free, thenpart);
+		pushsrc(String, thenpart);
+		unput('\n');
+  		if (elsepart)
+			free(elsepart);
+		return thenpart;	/* to be freed later */
+	} else {
+		free(thenpart);
+		if (elsepart) {
+			unput('\n');
+			pushsrc(Free, elsepart);
+			pushsrc(String, elsepart);
+			unput('\n');
+		}
+		return elsepart;
+	}
+}
blob - /dev/null
blob + a00a9d8d05678a3a4d0d869a5b379f89b71042f5 (mode 644)
--- /dev/null
+++ src/cmd/grap/frame.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "grap.h"
+#include "y.tab.h"
+
+double	frame_ht;	/* default frame height */
+double	frame_wid;	/* and width */
+
+int	nsides	= 0;		/* how many sides given on this frame */
+char	*sides[] = {
+		"\tline from Frame.nw to Frame.ne",
+		"\tline from Frame.sw to Frame.se",
+		"\tline from Frame.sw to Frame.nw",
+		"\tline from Frame.se to Frame.ne"
+};
+char	*newsides[4] = { 0, 0, 0, 0 };	/* filled in later */
+
+void frame(void)		/* pump out frame definition, reset for next */
+{
+	int i;
+
+	fprintf(tfd, "\tframeht = %g\n", frame_ht);
+	fprintf(tfd, "\tframewid = %g\n", frame_wid);
+	fprintf(tfd, "Frame:\tbox ht frameht wid framewid with .sw at 0,0 ");
+	if (nsides == 0)
+		fprintf(tfd, "\n");
+	else {
+		fprintf(tfd, "invis\n");
+		for (i = 0; i < 4; i++) {
+			if (newsides[i]) {
+				fprintf(tfd, "%s\n", newsides[i]);
+				free(newsides[i]);
+				newsides[i] = 0;
+			} else
+				fprintf(tfd, "%s\n", sides[i]);
+		}
+		nsides = 0;
+	}
+}
+
+void frameht(double f)	/* set height of frame */
+{
+	frame_ht = f;
+}
+
+void framewid(double f)	/* set width of frame */
+{
+	frame_wid = f;
+}
+
+void frameside(int type, Attr *desc)	/* create and remember sides */
+{
+	int n;
+	char buf[100];
+
+	nsides++;
+	switch (type) {
+	case 0:		/* no side specified; kludge up all */
+		frameside(TOP, desc);
+		frameside(BOT, desc);
+		frameside(LEFT, desc);
+		frameside(RIGHT, desc);
+		return;
+	case TOP:	n = 0; break;
+	case BOT:	n = 1; break;
+	case LEFT:	n = 2; break;
+	case RIGHT:	n = 3; break;
+	}
+	sprintf(buf, "%s %s", sides[n], desc_str(desc));
+	newsides[n] = tostring(buf);
+}
blob - /dev/null
blob + 65c7f83f28e078ac011e6ff63e9949b4620554ef (mode 644)
--- /dev/null
+++ src/cmd/grap/grap.h
@@ -0,0 +1,236 @@
+extern	char	errbuf[200];
+#define	ERROR	sprintf(errbuf,
+#define	FATAL	), yyerror(errbuf), exit(1)
+#define	WARNING	), yyerror(errbuf)
+
+#define	dprintf	if(dbg)printf
+
+#define	String	01
+#define	Macro	02
+#define	File	04
+#define	Char	010
+#define	Thru	020
+#define	Free	040
+
+#define	MARGIN	0.07	/* default margin around data */
+#define	SLOP	1.001	/* slop for limits of for loops */
+#define	FRAMEWID 3	/* default width for boxes and ellipses */
+#define	FRAMEHT	2	/* default height and line length */
+#define	TICKLEN	0.1
+
+#define	MAXNUM	200
+
+#define	XFLAG	01
+#define	YFLAG	02
+
+#define	INTICK	01
+#define	OUTICK	02
+
+#define	BOT	01
+#define	TOP	02
+#define	RIGHT	04
+#define	LEFT	010
+
+#define	RJUST	01
+#define	LJUST	02
+#define	ABOVE	04
+#define	BELOW	010
+
+typedef struct infile {
+	FILE	*fin;
+	char	*fname;
+	int	lineno;
+} Infile;
+
+typedef struct {	/* input source */
+	int	type;	/* Macro, String, File */
+	char	*sp;	/* if String or Macro */
+} Src;
+
+extern	Src	src[], *srcp;	/* input source stack */
+
+#define	MAXARGS	100
+typedef struct {	/* argument stack */
+	char	*argstk[MAXARGS];	/* pointers to args */
+	char	*argval;	/* points to space containing args */
+} Arg;
+
+extern	Infile	infile[10];
+extern	Infile	*curfile;
+
+typedef struct {
+	struct obj *obj;
+	double	x, y;
+} Point;
+
+typedef struct attr {	/* e.g., DASH 1.1 or "..." rjust size *.5 */
+	int	type;
+	double	fval;
+	char	*sval;
+	int	just;	/* justification, for STRING type */
+	int	op;	/* optional operator, ditto */
+	struct attr *next;
+} Attr;
+
+typedef struct obj {	/* a name and its properties */
+	char	*name;
+	char	*val;	/* body of define, etc. */
+	double	fval;	/* if a numeric variable */
+	Point	pt;	/* usually for max and min */
+	Point	pt1;
+	int	type;	/* NAME, DEFNAME, ... */
+	int	first;	/* 1 after 1st item seen */
+	int	coord;	/* 1 if coord system specified for this name */
+	int	log;	/* x, y, or z (= x+y) */
+	Attr	*attr;	/* DASH, etc., for now */
+	struct obj *next;
+} Obj;
+
+typedef union {		/* the yacc stack type */
+	int	i;
+	char	*p;
+	double	f;
+	Point	pt;
+	Obj	*op;
+	Attr	*ap;
+} YYSTYPE;
+
+extern	YYSTYPE	yylval, yyval;
+
+extern	int	dbg;
+
+extern	int	ntext;
+extern	double	num[MAXNUM];
+extern	int	nnum;
+extern	int	ntick, tside;
+
+extern	char	*tostring(char *);
+extern char *grow(char *, char *, int, int);
+
+extern	int	lineno;
+extern	int	synerr;
+extern	int	codegen;
+extern	char	tempfile[];
+extern	FILE	*tfd;
+
+extern	Point	ptmin, ptmax;
+
+extern	char	*dflt_coord;
+extern	char	*curr_coord;
+extern	int	ncoord;
+extern	int	auto_x;
+extern	double	margin;
+extern	int	autoticks;
+extern	int	pointsize, ps_set;
+
+
+#define	logit(x) (x) = log10(x)
+#define	Log10(x) errcheck(log10(x), "log")
+#define	Exp(x)	errcheck(exp(x), "exp")
+#define	Sqrt(x)	errcheck(sqrt(x), "sqrt")
+
+#define	min(x,y)	(((x) <= (y)) ? (x) : (y))
+#define	max(x,y)	(((x) >= (y)) ? (x) : (y))
+
+extern	void	yyerror(char *);
+extern void coord_x(Point);
+extern void coord_y(Point);
+extern void coordlog(int);
+extern void coord(Obj *);
+extern void resetcoord(Obj *);
+extern void savenum(int, double);
+extern void setjust(int);
+extern void setsize(int, double);
+extern void range(Point);
+extern void halfrange(Obj *, int, double);
+extern Obj *lookup(char *, int);
+extern double getvar(Obj *);
+extern double setvar(Obj *, double);
+extern Point makepoint(Obj *, double, double);
+extern Attr *makefattr(int, double);
+extern Attr *makesattr(char *);
+extern Attr *makeattr(int, double, char *, int, int);
+extern Attr *addattr(Attr *, Attr *);
+extern void freeattr(Attr *);
+extern char *slprint(Attr *);
+extern char *juststr(int);
+extern char *sprntf(char *, Attr *);
+extern void forloop(Obj *, double, double, int, double, char *);
+extern void nextfor(void);
+extern void endfor(void);
+extern char *ifstat(double, char *, char *);
+extern void frame(void);
+extern void frameht(double);
+extern void framewid(double);
+extern void frameside(int, Attr *);
+extern void pushsrc(int, char *);
+extern void popsrc(void);
+extern void definition(char *);
+extern char *delimstr(char *);
+extern int baldelim(int, char *);
+extern void dodef(Obj *);
+extern int getarg(char *);
+extern int input(void);
+extern int nextchar(void);
+extern void do_thru(void);
+extern int unput(int);
+extern void pbstr(char *);
+extern double errcheck(double, char *);
+extern void yyerror(char *);
+extern void eprint(void);
+extern int yywrap(void);
+extern void copyfile(char *);
+extern void copydef(Obj *);
+extern Obj *copythru(char *);
+extern char *addnewline(char *);
+extern void copyuntil(char *);
+extern void copy(void);
+extern void shell_init(void);
+extern void shell_text(char *);
+extern void shell_exec(void);
+extern void labelwid(double);
+extern void labelmove(int, double);
+extern void label(int, Attr *);
+extern void lab_adjust(void);
+extern char *sizeit(Attr *);
+extern void line(int, Point, Point, Attr *);
+extern void circle(double, Point);
+extern char *xyname(Point);
+extern void pic(char *);
+extern void numlist(void);
+extern void plot(Attr *, Point);
+extern void plotnum(double, char *, Point);
+extern void drawdesc(int, Obj *, Attr *, char *);
+extern void next(Obj *, Point, Attr *);
+extern void print(void);
+extern void endstat(void);
+extern void graph(char *);
+extern void setup(void);
+extern void do_first(void);
+extern void reset(void);
+extern void opentemp(void);
+extern void savetick(double, char *);
+extern void dflt_tick(double);
+extern void tickside(int);
+extern void tickoff(int);
+extern void gridtickoff(void);
+extern void setlist(void);
+extern void tickdir(int, double, int);
+extern void ticks(void);
+extern double modfloor(double, double);
+extern double modceil(double, double);
+extern void do_autoticks(Obj *);
+extern void logtick(double, double, double);
+extern Obj *setauto(void);
+extern void autoside(Obj *, int);
+extern void autolog(Obj *, int);
+extern void iterator(double, double, int, double, char *);
+extern void ticklist(Obj *, int);
+extern void print_ticks(int, int, Obj *, char *, char *);
+extern void maketick(int, char *, int, int, double, char *, char *, char *);
+extern void griddesc(Attr *);
+extern void gridlist(Obj *);
+extern char *desc_str(Attr *);
+extern int sidelog(int, int);
+
+extern	Obj	*objlist;
blob - /dev/null
blob + 6d96b2f18e51d075edfc856ed2e3f82458a660a5 (mode 644)
--- /dev/null
+++ src/cmd/grap/grap.y
@@ -0,0 +1,396 @@
+%{
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "grap.h"
+
+//#define	RAND_MAX 32767	/* if your rand() returns bigger, change this too */
+
+extern int yylex(void);
+extern int yyparse(void);
+
+%}
+
+%token	<i>	FRAME TICKS GRID LABEL COORD
+%token	<i>	LINE ARROW CIRCLE DRAW NEW PLOT NEXT
+%token	<p>	PIC
+%token	<i>	COPY THRU UNTIL
+%token	<i>	FOR FROM TO BY AT WITH
+%token	<i>	IF
+%token	<p>	GRAPH THEN ELSE DOSTR
+%token	<i>	DOT DASH INVIS SOLID
+%token	<i>	TEXT JUST SIZE
+%token	<i>	LOG EXP SIN COS ATAN2 SQRT RAND MAX MIN INT PRINT SPRINTF
+%token	<i>	X Y SIDE IN OUT OFF UP DOWN ACROSS
+%token	<i>	HEIGHT WIDTH RADIUS
+%token	<f>	NUMBER
+%token	<op>	NAME VARNAME DEFNAME
+%token	<p>	STRING
+%token	<i>	ST '(' ')' ','
+
+%right	<f>	'='
+%left	<f>	OR
+%left	<f>	AND
+%nonassoc <f>	GT LT LE GE EQ NE
+%left	<f>	'+' '-'
+%left	<f>	'*' '/' '%'
+%right	<f>	UMINUS NOT
+%right	<f>	'^'
+
+%type	<f>	expr optexpr if_expr number assign
+%type	<i>	optop
+%type	<p>	optstring if
+%type	<op>	optname iterator name
+%type	<pt>	point
+%type	<i>	side optside numlist comma linetype drawtype
+%type	<ap>	linedesc optdesc stringlist string stringattr sattrlist exprlist
+%type	<i>	frameitem framelist coordlog
+%type	<f>	string_expr
+
+%%
+
+top:
+	  graphseq		{ if (codegen && !synerr) graph((char *) 0); }
+	| /* empty */		{ codegen = 0; }
+	| error			{ codegen = 0; ERROR "syntax error" WARNING; }
+	;
+
+graphseq:
+	  statlist
+	| graph statlist
+	| graphseq graph statlist
+	;
+graph:
+	  GRAPH			{ graph($1); endstat(); }
+	;
+
+statlist:
+	  ST
+	| stat ST		{ endstat(); }
+	| statlist stat ST	{ endstat(); }
+	;
+
+stat:
+	  FRAME framelist	{ codegen = 1; }
+	| ticks			{ codegen = 1; }
+	| grid			{ codegen = 1; }
+	| label			{ codegen = 1; }
+	| coord
+	| plot			{ codegen = 1; }
+	| line			{ codegen = 1; }
+	| circle		{ codegen = 1; }
+	| draw
+	| next			{ codegen = 1; }
+	| PIC			{ codegen = 1; pic($1); }
+	| for
+	| if
+	| copy
+	| numlist		{ codegen = 1; numlist(); }
+	| assign
+	| PRINT expr		{ fprintf(stderr, "\t%g\n", $2); }
+	| PRINT string		{ fprintf(stderr, "\t%s\n", $2->sval); freeattr($2); }
+	| /* empty */
+	;
+
+numlist:
+	  number		{ savenum(0, $1); $$ = 1; }
+	| numlist number	{ savenum($1, $2); $$ = $1+1; }
+	| numlist comma number	{ savenum($1, $3); $$ = $1+1; }
+	;
+number:
+	  NUMBER
+	| '-' NUMBER %prec UMINUS	{ $$ = -$2; }
+	| '+' NUMBER %prec UMINUS	{ $$ = $2; }
+	;
+
+label:
+	  LABEL optside stringlist lablist	{ label($2, $3); }
+	;
+lablist:
+	  labattr
+	| lablist labattr
+	| /* empty */
+	;
+labattr:
+	  UP expr		{ labelmove($1, $2); }
+	| DOWN expr		{ labelmove($1, $2); }
+	| SIDE expr		{ labelmove($1, $2); /* LEFT or RIGHT only */ }
+	| WIDTH expr		{ labelwid($2); }
+	;
+
+framelist:
+	  framelist frameitem
+	| /* empty */		{ $$ = 0; }
+	;
+frameitem:
+	  HEIGHT expr		{ frameht($2); }
+	| WIDTH expr		{ framewid($2); }
+	| side linedesc		{ frameside($1, $2); }
+	| linedesc		{ frameside(0, $1); }
+	;
+side:
+	  SIDE
+	;
+optside:
+	  side
+	| /* empty */		{ $$ = 0; }
+	;
+
+linedesc:
+	  linetype optexpr	{ $$ = makeattr($1, $2, (char *) 0, 0, 0); }
+	;
+linetype:
+	  DOT | DASH | SOLID | INVIS
+	;
+optdesc:
+	  linedesc
+	| /* empty */		{ $$ = makeattr(0, 0.0, (char *) 0, 0, 0); }
+	;
+
+ticks:
+	  TICKS tickdesc	{ ticks(); }
+	;
+tickdesc:
+	  tickattr
+	| tickdesc tickattr
+	;
+tickattr:
+	  side			{ tickside($1); }
+	| IN expr		{ tickdir(IN, $2, 1); }
+	| OUT expr		{ tickdir(OUT, $2, 1); }
+	| IN			{ tickdir(IN, 0.0, 0); }
+	| OUT			{ tickdir(OUT, 0.0, 0); }
+	| AT optname ticklist	{ setlist(); ticklist($2, AT); }
+	| iterator		{ setlist(); ticklist($1, AT); }
+	| side OFF		{ tickoff($1); }
+	| OFF			{ tickoff(LEFT|RIGHT|TOP|BOT); }
+	| labattr
+	;
+ticklist:
+	  tickpoint
+	| ticklist comma tickpoint
+	;
+tickpoint:
+	  expr			{ savetick($1, (char *) 0); }
+	| expr string		{ savetick($1, $2->sval); }
+	;
+iterator:
+	  FROM optname expr TO optname expr BY optop expr optstring
+			{ iterator($3, $6, $8, $9, $10); $$ = $2; }
+	| FROM optname expr TO optname expr optstring
+			{ iterator($3, $6, '+', 1.0, $7); $$ = $2; }
+	;
+optop:
+	  '+'		{ $$ = '+'; }
+	| '-'		{ $$ = '-'; }
+	| '*'		{ $$ = '*'; }
+	| '/'		{ $$ = '/'; }
+	| /* empty */	{ $$ = ' '; }
+	;
+optstring:
+	  string	{ $$ = $1->sval; }
+	| /* empty */	{ $$ = (char *) 0; }
+	;
+
+grid:
+	  GRID griddesc		{ ticks(); }
+	;
+griddesc:
+	  gridattr
+	| griddesc gridattr
+	;
+gridattr:
+	  side			{ tickside($1); }
+	| X			{ tickside(BOT); }
+	| Y			{ tickside(LEFT); }
+	| linedesc		{ griddesc($1); }
+	| AT optname ticklist	{ setlist(); gridlist($2); }
+	| iterator		{ setlist(); gridlist($1); }
+	| TICKS OFF		{ gridtickoff(); }
+	| OFF			{ gridtickoff(); }
+	| labattr
+	;
+
+line:
+	  LINE FROM point TO point optdesc	{ line($1, $3, $5, $6); }
+	| LINE optdesc FROM point TO point	{ line($1, $4, $6, $2); }
+	;
+circle:
+	  CIRCLE RADIUS expr AT point		{ circle($3, $5); }
+	| CIRCLE AT point RADIUS expr		{ circle($5, $3); }
+	| CIRCLE AT point			{ circle(0.0, $3); }
+	;
+
+stringlist:
+	  string
+	| stringlist string	{ $$ = addattr($1, $2); }
+	;
+string:
+	  STRING sattrlist	{ $$ = makesattr($1); }
+	| SPRINTF '(' STRING ')' sattrlist
+				{ $$ = makesattr(sprntf($3, (Attr*) 0)); }
+	| SPRINTF '(' STRING ',' exprlist ')' sattrlist
+				{ $$ = makesattr(sprntf($3, $5)); }
+	;
+exprlist:
+	  expr			{ $$ = makefattr(NUMBER, $1); }
+	| exprlist ',' expr	{ $$ = addattr($1, makefattr(NUMBER, $3)); }
+	;
+sattrlist:
+	  stringattr
+	| sattrlist stringattr
+	| /* empty */		{ $$ = (Attr *) 0; }
+	;
+stringattr:
+	  JUST			{ setjust($1); }
+	| SIZE optop expr	{ setsize($2, $3); }
+	;
+
+coord:
+	  COORD optname coordlist	{ coord($2); }
+	| COORD optname			{ resetcoord($2); }
+	;
+coordlist:
+	  coorditem
+	| coordlist coorditem
+	;
+coorditem:
+	  coordlog	{ coordlog($1); }
+	| X point	{ coord_x($2); }
+	| Y point	{ coord_y($2); }
+	| X optname expr TO expr		{ coord_x(makepoint($2, $3, $5)); }
+	| Y optname expr TO expr		{ coord_y(makepoint($2, $3, $5)); }
+	| X FROM optname expr TO expr		{ coord_x(makepoint($3, $4, $6)); }
+	| Y FROM optname expr TO expr		{ coord_y(makepoint($3, $4, $6)); }
+	;
+coordlog:
+	  LOG X		{ $$ = XFLAG; }
+	| LOG Y		{ $$ = YFLAG; }
+	| LOG X LOG Y	{ $$ = XFLAG|YFLAG; }
+	| LOG Y LOG X	{ $$ = XFLAG|YFLAG; }
+	| LOG LOG	{ $$ = XFLAG|YFLAG; }
+	;
+
+plot:
+	  stringlist AT point		{ plot($1, $3); }
+	| PLOT stringlist AT point	{ plot($2, $4); }
+	| PLOT expr optstring AT point	{ plotnum($2, $3, $5); }
+	;
+
+draw:
+	  drawtype optname linedesc		{ drawdesc($1, $2, $3, (char *) 0); }
+	| drawtype optname optdesc string	{ drawdesc($1, $2, $3, $4->sval); }
+	| drawtype optname string optdesc	{ drawdesc($1, $2, $4, $3->sval); }
+	;
+drawtype:
+	  DRAW
+	| NEW
+	;
+
+next:
+	  NEXT optname AT point optdesc		{ next($2, $4, $5); }
+
+copy:
+	  COPY copylist		{ copy(); }
+	;
+copylist:
+	  copyattr
+	| copylist copyattr
+	;
+copyattr:
+	  string		{ copyfile($1->sval); }
+	| THRU DEFNAME		{ copydef($2); }
+	| UNTIL string		{ copyuntil($2->sval); }
+	;
+
+for:
+	  FOR name FROM expr TO expr BY optop expr DOSTR
+		{ forloop($2, $4, $6, $8, $9, $10); }
+	| FOR name FROM expr TO expr DOSTR
+		{ forloop($2, $4, $6, '+', 1.0, $7); }
+	| FOR name '=' expr TO expr BY optop expr DOSTR
+		{ forloop($2, $4, $6, $8, $9, $10); }
+	| FOR name '=' expr TO expr DOSTR
+		{ forloop($2, $4, $6, '+', 1.0, $7); }
+	;
+
+if:
+	  IF if_expr THEN ELSE		{ $$ = ifstat($2, $3, $4); }
+	| IF if_expr THEN		{ $$ = ifstat($2, $3, (char *) 0); }
+	;
+if_expr:
+	  expr
+	| string_expr
+	| if_expr AND string_expr	{ $$ = $1 && $3; }
+	| if_expr OR string_expr	{ $$ = $1 || $3; }
+	;
+string_expr:
+	  STRING EQ STRING	{ $$ = strcmp($1,$3) == 0; free($1); free($3); }
+	| STRING NE STRING	{ $$ = strcmp($1,$3) != 0; free($1); free($3); }
+	;
+
+point:
+	  optname expr comma expr		{ $$ = makepoint($1, $2, $4); }
+	| optname '(' expr comma expr ')'	{ $$ = makepoint($1, $3, $5); }
+	;
+comma:
+	  ','		{ $$ = ','; }
+	;
+
+optname:
+	  NAME		{ $$ = $1; }
+	| /* empty */	{ $$ = lookup(curr_coord, 1); }
+	;
+
+expr:
+	  NUMBER
+	| assign
+	| '(' string_expr ')'	{ $$ = $2; }
+	| VARNAME		{ $$ = getvar($1); }
+	| expr '+' expr		{ $$ = $1 + $3; }
+	| expr '-' expr		{ $$ = $1 - $3; }
+	| expr '*' expr		{ $$ = $1 * $3; }
+	| expr '/' expr		{ if ($3 == 0.0) {
+					ERROR "division by 0" WARNING; $3 = 1; }
+				  $$ = $1 / $3; }
+	| expr '%' expr		{ if ((long)$3 == 0) {
+					ERROR "mod division by 0" WARNING; $3 = 1; }
+				  $$ = (long)$1 % (long)$3; }
+	| '-' expr %prec UMINUS	{ $$ = -$2; }
+	| '+' expr %prec UMINUS	{ $$ = $2; }
+	| '(' expr ')'		{ $$ = $2; }
+	| LOG '(' expr ')'		{ $$ = Log10($3); }
+	| EXP '(' expr ')'		{ $$ = Exp($3 * log(10.0)); }
+	| expr '^' expr			{ $$ = pow($1, $3); }
+	| SIN '(' expr ')'		{ $$ = sin($3); }
+	| COS '(' expr ')'		{ $$ = cos($3); }
+	| ATAN2 '(' expr ',' expr ')'	{ $$ = atan2($3, $5); }
+	| SQRT '(' expr ')'		{ $$ = Sqrt($3); }
+	| RAND '(' ')'			{ $$ = (double)rand() / (double)RAND_MAX; }
+	| MAX '(' expr ',' expr ')'	{ $$ = $3 >= $5 ? $3 : $5; }
+	| MIN '(' expr ',' expr ')'	{ $$ = $3 <= $5 ? $3 : $5; }
+	| INT '(' expr ')'	{ $$ = (long) $3; }
+	| expr GT expr		{ $$ = $1 > $3; }
+	| expr LT expr		{ $$ = $1 < $3; }
+	| expr LE expr		{ $$ = $1 <= $3; }
+	| expr GE expr		{ $$ = $1 >= $3; }
+	| expr EQ expr		{ $$ = $1 == $3; }
+	| expr NE expr		{ $$ = $1 != $3; }
+	| expr AND expr		{ $$ = $1 && $3; }
+	| expr OR expr		{ $$ = $1 || $3; }
+	| NOT expr		{ $$ = !($2); }
+	;
+assign:
+	  name '=' expr		{ $$ = setvar($1, $3); }
+	;
+
+name:
+	  NAME
+	| VARNAME
+	;
+
+optexpr:
+	  expr
+	| /* empty */		{ $$ = 0.0; }
+	;
blob - /dev/null
blob + 0023aded84cb6a1f0062372cc82c2469aab7bc66 (mode 644)
--- /dev/null
+++ src/cmd/grap/grapl.lx
@@ -0,0 +1,213 @@
+%Start A str def thru sh
+
+%{
+#undef	input
+#undef	unput
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "grap.h"
+#include "y.tab.h"
+
+extern	struct	symtab	symtab[];
+
+int	yyback(int *, int);
+int	yylook(void);
+int	yywrap(void);
+void	shell_init(void), shell_exec(void), shell_text(char *);
+
+#define	CADD	cbuf[clen++] = yytext[0]; \
+		if (clen >= CBUFLEN-1) { \
+			ERROR "string too long", cbuf WARNING; BEGIN A; }
+#define	CBUFLEN	1500
+char	cbuf[CBUFLEN];
+int	clen, cflag;
+int	c, delim, shcnt;
+%}
+
+A	[a-zA-Z_]
+B	[a-zA-Z0-9_]
+D	[0-9]
+WS	[ \t]
+
+%%
+	if (yybgin-yysvec-1 == 0) {	/* witchcraft */
+		BEGIN A;
+	}
+
+<A>{WS}		;
+<A>"\\"\n	;
+<A>\n		return(ST);
+<A>";"		return(ST);
+
+<A>line		return(yylval.i = LINE);
+<A>arrow	{ yylval.i = ARROW; return(LINE); }
+<A>circle	return(yylval.i = CIRCLE);
+<A>frame	return(FRAME);
+<A>tick(s)?	return(TICKS);
+<A>grid(line)?(s)?	return(GRID);
+<A>coord(s)?	return(COORD);
+<A>log		return(LOG);
+<A>exp		return(EXP);
+<A>sin		return(SIN);
+<A>cos		return(COS);
+<A>atan2	return(ATAN2);
+<A>sqrt		return(SQRT);
+<A>rand		return(RAND);
+<A>max		return(MAX);
+<A>min		return(MIN);
+<A>int		return(INT);
+<A>print	return(PRINT);
+<A>sprintf	return(SPRINTF);
+<A>pic{WS}.*	{ yylval.p = tostring(yytext+3); return(PIC); }
+<A>graph{WS}.*	{ yylval.p = tostring(yytext+5); return(GRAPH); }
+
+<A>for		return(FOR);
+<A>^Endfor\n	{ endfor(); }
+<A>do		{ yylval.p = delimstr("loop body"); BEGIN A; return(DOSTR); }
+
+<A>copy|include	{ return(COPY); }
+<A>thru|through	{ BEGIN thru; return(THRU); }
+<thru>{WS}+	;
+<thru>{A}{B}*|.	{ yylval.op = copythru(yytext); BEGIN A; return(DEFNAME); }
+<A>until	return(UNTIL);
+
+<A>if		return(IF);
+<A>then		{ yylval.p = delimstr("then part"); BEGIN A; return(THEN); }
+<A>else		{ yylval.p = delimstr("else part"); BEGIN A; return(ELSE); }
+
+<A>next		return(NEXT);
+<A>draw		return(yylval.i = DRAW);
+<A>new		return(yylval.i = NEW);
+<A>plot		return(yylval.i = PLOT);
+<A>label(s)?	return(LABEL);
+<A>x		return(X);
+<A>y		return(Y);
+
+<A>top		{ yylval.i = TOP; return SIDE; }
+<A>bot(tom)?	{ yylval.i = BOT; return SIDE; }
+<A>left		{ yylval.i = LEFT; return SIDE; }
+<A>right	{ yylval.i = RIGHT; return SIDE; }
+<A>up		return(yylval.i = UP);
+<A>down		return(yylval.i = DOWN);
+<A>across	return(yylval.i = ACROSS);
+<A>height|ht	return(yylval.i = HEIGHT);
+<A>wid(th)?	return(yylval.i = WIDTH);
+<A>rad(ius)?	return(yylval.i = RADIUS);
+<A>invis	return(yylval.i = INVIS);
+<A>dot(ted)	return(yylval.i = DOT);
+<A>dash(ed)	return(yylval.i = DASH);
+<A>solid	return(yylval.i = SOLID);
+
+<A>ljust	{ yylval.i = LJUST; return JUST; }
+<A>rjust	{ yylval.i = RJUST; return JUST; }
+<A>above	{ yylval.i = ABOVE; return JUST; }
+<A>below	{ yylval.i = BELOW; return JUST; }
+<A>size		return(yylval.i = SIZE);
+
+<A>from		return(yylval.i = FROM);
+<A>to		return(yylval.i = TO);
+<A>by|step	return(yylval.i = BY);
+<A>at		return(yylval.i = AT);
+<A>with		return(yylval.i = WITH);
+<A>in		return(yylval.i = IN);
+<A>out		return(yylval.i = OUT);
+<A>off		return(yylval.i = OFF);
+
+<A>sh{WS}+ {	BEGIN sh;
+		if ((delim = input()) == '{') {
+			shcnt = 1;
+			delim = '}';
+		}
+		shell_init();
+	}
+<sh>{A}{B}* {
+		int c;
+		Obj *p;
+		if (yytext[0] == delim) {
+			shell_exec();
+			BEGIN A;
+		} else {
+			p = lookup(yytext, 0);
+			if (p != NULL && p->type == DEFNAME) {
+				c = input();
+				unput(c);
+				if (c == '(')
+					dodef(p);
+				else
+					pbstr(p->val);
+			} else
+				shell_text(yytext);
+		}
+	}
+<sh>"{"		{ shcnt++; shell_text(yytext); }
+<sh>"}"		{ if (delim != '}' || --shcnt > 0)
+			shell_text(yytext);
+		  else {
+			shell_exec();
+			BEGIN A;
+		  }
+		}
+<sh>.|\n	{ if (yytext[0] == delim) {
+			shell_exec();
+			BEGIN A;
+		  } else
+			shell_text(yytext);
+		}
+
+<A>define{WS}+	{ BEGIN def; }
+<def>{A}{B}*	{ definition(yytext); BEGIN A; }
+
+<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
+		  yylval.f = atof(yytext); return(NUMBER); }
+
+<A>^"."[^0-9].*	{ if (yytext[1] == 'G' && yytext[2] == '2') {
+			yylval.i = yytext[2];
+			return(EOF);
+		  } else {
+			yylval.p = tostring(yytext);
+			return(PIC);
+		  }
+		}
+
+<A>{A}{B}* {
+		int c;
+		Obj *p;
+		p = lookup(yytext, 1);
+		if (p->type == DEFNAME) {
+			c = input();
+			unput(c);
+			if (c == '(')	/* it's name(...) */
+				dodef(p);
+			else	/* no argument list */
+				pbstr(p->val);
+		} else {
+			yylval.op = p;
+			return p->type;	/* NAME or VARNAME */
+		}
+	}
+
+<A>"=="		return(EQ);
+<A>">="		return(GE);
+<A>"<="		return(LE);
+<A>"!="		return(NE);
+<A>">"		return(GT);
+<A>"<"		return(LT);
+<A>"&&"		return(AND);
+<A>"||"		return(OR);
+<A>"!"		return(NOT);	
+
+<A>\"		{ BEGIN str; clen = 0; }
+
+<A>#.*		;
+
+<A>.		{ yylval.i = yytext[0]; return(yytext[0]); }
+
+<str>\"		{ BEGIN A; cbuf[clen] = 0;
+		  yylval.p = tostring(cbuf); return(STRING); }
+<str>\n		{ ERROR "newline in string" WARNING; BEGIN A; return(ST); }
+<str>"\\\""	{ cbuf[clen++] = '\\'; cbuf[clen++] = '"'; }
+<str>"\\\\"	{ cbuf[clen++] = '\\'; cbuf[clen++] = '\\'; }
+<str>.		{ CADD; }
+
+%%
blob - /dev/null
blob + f558145e1c68aad167714828cf3e488562958162 (mode 644)
--- /dev/null
+++ src/cmd/grap/input.c
@@ -0,0 +1,580 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include "grap.h"
+#include "y.tab.h"
+
+Infile	infile[10];
+Infile	*curfile = infile;
+
+#define	MAXSRC	50
+Src	src[MAXSRC];	/* input source stack */
+Src	*srcp	= src;
+
+void pushsrc(int type, char *ptr)	/* new input source */
+{
+	if (++srcp >= src + MAXSRC)
+		ERROR "inputs nested too deep" FATAL;
+	srcp->type = type;
+	srcp->sp = ptr;
+	if (dbg) {
+		printf("\n%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("push file %s\n", ((Infile *)ptr)->fname);
+			break;
+		case Macro:
+			printf("push macro <%s>\n", ptr);
+			break;
+		case Char:
+			printf("push char <%c>\n", *ptr);
+			break;
+		case Thru:
+			printf("push thru\n");
+			break;
+		case String:
+			printf("push string <%s>\n", ptr);
+			break;
+		case Free:
+			printf("push free <%s>\n", ptr);
+			break;
+		default:
+			ERROR "pushed bad type %d", srcp->type FATAL;
+		}
+	}
+}
+
+void popsrc(void)	/* restore an old one */
+{
+	if (srcp <= src)
+		ERROR "too many inputs popped" FATAL;
+	if (dbg) {
+		printf("%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("pop file\n");
+			break;
+		case Macro:
+			printf("pop macro\n");
+			break;
+		case Char:
+			printf("pop char <%c>\n", *srcp->sp);
+			break;
+		case Thru:
+			printf("pop thru\n");
+			break;
+		case String:
+			printf("pop string\n");
+			break;
+		case Free:
+			printf("pop free\n");
+			break;
+		default:
+			ERROR "pop weird input %d", srcp->type FATAL;
+		}
+	}
+	srcp--;
+}
+
+void definition(char *s)	/* collect definition for s and install */
+				/* definitions picked up lexically */
+{
+	char *p;
+	Obj *stp;
+
+	p = delimstr("definition");
+	stp = lookup(s, 0);
+	if (stp != NULL) {	/* it's there before */
+		if (stp->type != DEFNAME) {
+			ERROR "%s used as variable and definition", s WARNING;
+			return;
+		}
+		free(stp->val);
+	} else {
+		stp = lookup(s, 1);
+		stp->type = DEFNAME;
+	}
+	stp->val = p;
+	dprintf("installing %s as `%s'\n", s, p);
+}
+
+char *delimstr(char *s)	/* get body of X ... X */
+			/* message if too big */
+{
+	int c, delim, rdelim, n, deep;
+	static char *buf = NULL;
+	static int nbuf = 0;
+	char *p;
+
+	if (buf == NULL)
+		buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
+	while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
+		;
+	rdelim = baldelim(delim, "{}");		/* could be "(){}[]`'" */
+	deep = 1;
+	for (p = buf; ; ) {
+		c = input();
+		if (c == rdelim)
+			if (--deep == 0)
+				break;
+		if (c == delim)
+			deep++;
+		if (p >= buf + nbuf) {
+			n = p - buf;
+			buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
+			p = buf + n;
+		}
+		if (c == EOF)
+			ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
+		*p++ = c;
+	}
+	*p = '\0';
+	dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
+	return tostring(buf);
+}
+
+baldelim(int c, char *s)	/* replace c by balancing entry in s */
+{
+	for ( ; *s; s += 2)
+		if (*s == c)
+			return s[1];
+	return c;
+}
+
+Arg	args[10];	/* argument frames */
+Arg	*argfp = args;	/* frame pointer */
+int	argcnt;		/* number of arguments seen so far */
+
+void dodef(Obj *stp)	/* collect args and switch input to defn */
+{
+	int i, len;
+	char *p;
+	Arg *ap;
+
+	ap = argfp+1;
+	if (ap >= args+10)
+		ERROR "arguments too deep" FATAL;
+	argcnt = 0;
+	if (input() != '(')
+		ERROR "disaster in dodef" FATAL;
+	if (ap->argval == 0)
+		ap->argval = malloc(1000);
+	for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
+		ap->argstk[argcnt++] = p;
+		if (input() == ')')
+			break;
+	}
+	for (i = argcnt; i < MAXARGS; i++)
+		ap->argstk[i] = "";
+	if (dbg)
+		for (i = 0; i < argcnt; i++)
+			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
+	argfp = ap;
+	pushsrc(Macro, stp->val);
+}
+
+getarg(char *p)	/* pick up single argument, store in p, return length */
+{
+	int n, c, npar;
+
+	n = npar = 0;
+	for ( ;; ) {
+		c = input();
+		if (c == EOF)
+			ERROR "end of file in getarg!" FATAL;
+		if (npar == 0 && (c == ',' || c == ')'))
+			break;
+		if (c == '"')	/* copy quoted stuff intact */
+			do {
+				*p++ = c;
+				n++;
+			} while ((c = input()) != '"' && c != EOF);
+		else if (c == '(')
+			npar++;
+		else if (c == ')')
+			npar--;
+		n++;
+		*p++ = c;
+	}
+	*p = 0;
+	unput(c);
+	return(n + 1);
+}
+
+#define	PBSIZE	2000
+char	pbuf[PBSIZE];		/* pushback buffer */
+char	*pb	= pbuf-1;	/* next pushed back character */
+
+char	ebuf[200];		/* collect input here for error reporting */
+char	*ep	= ebuf;
+
+int	begin	= 0;
+extern	int	thru;
+extern	Obj	*thrudef;
+extern	char	*untilstr;
+
+input(void)
+{
+	register int c;
+
+	if (thru && begin) {
+		do_thru();
+		begin = 0;
+	}
+	c = nextchar();
+	dprintf(" <%c>", c);
+	if (ep >= ebuf + sizeof ebuf)
+		ep = ebuf;
+	return *ep++ = c;
+}
+
+nextchar(void)
+{
+	register int c;
+
+  loop:
+	switch (srcp->type) {
+	case Free:	/* free string */
+		free(srcp->sp);
+		popsrc();
+		goto loop;
+	case Thru:	/* end of pushed back line */
+		begin = 1;
+		popsrc();
+		c = '\n';
+		break;
+	case Char:
+		if (pb >= pbuf) {
+			c = *pb--;
+			popsrc();
+			break;
+		} else {	/* can't happen? */
+			popsrc();
+			goto loop;
+		}
+	case String:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			popsrc();
+			goto loop;
+		} else {
+			if (*srcp->sp == '\0')	/* empty, so pop */
+				popsrc();
+			break;
+		}
+	case Macro:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			if (--argfp < args)
+				ERROR "argfp underflow" FATAL;
+			popsrc();
+			goto loop;
+		} else if (c == '$' && isdigit(*srcp->sp)) {	/* $3 */
+			int n = 0;
+			while (isdigit(*srcp->sp))
+				n = 10 * n + *srcp->sp++ - '0';
+			if (n > 0 && n <= MAXARGS)
+				pushsrc(String, argfp->argstk[n-1]);
+			goto loop;
+		}
+		break;
+	case File:
+		c = getc(curfile->fin);
+		if (c == EOF) {
+			if (curfile == infile)
+				ERROR "end of file inside .G1/.G2" FATAL;
+			if (curfile->fin != stdin) {
+				fclose(curfile->fin);
+				free(curfile->fname);	/* assumes allocated */
+			}
+			curfile--;
+			printf(".lf %d %s\n", curfile->lineno, curfile->fname);
+			popsrc();
+			thru = 0;	/* chicken out */
+			thrudef = 0;
+			if (untilstr) {
+				free(untilstr);
+				untilstr = 0;
+			}
+			goto loop;
+		}
+		if (c == '\n')
+			curfile->lineno++;
+		break;
+	}
+	return c;
+}
+
+void do_thru(void)	/* read one line, make into a macro expansion */
+{
+	int c, i;
+	char *p;
+	Arg *ap;
+
+	ap = argfp+1;
+	if (ap >= args+10)
+		ERROR "arguments too deep" FATAL;
+	if (ap->argval == NULL)
+		ap->argval = malloc(1000);
+	p = ap->argval;
+	argcnt = 0;
+	c = nextchar();
+	if (thru == 0) {	/* end of file was seen, so thru is done */
+		unput(c);
+		return;
+	}
+	for ( ; c != '\n' && c != EOF; ) {
+		if (c == ' ' || c == '\t') {
+			c = nextchar();
+			continue;
+		}
+		if (argcnt >= MAXARGS)
+			ERROR "too many fields on input line" FATAL;
+		ap->argstk[argcnt++] = p;
+		if (c == '"') {
+			do {
+				*p++ = c;
+				if ((c = nextchar()) == '\\') {
+					*p++ = c;
+					*p++ = nextchar();
+					c = nextchar();
+				}
+			} while (c != '"' && c != '\n' && c != EOF);
+			*p++ = '"';
+			if (c == '"')
+				c = nextchar();
+		} else {
+			do {
+				*p++ = c;
+			} while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
+			if (c == ',')
+				c = nextchar();
+		}
+		*p++ = '\0';
+	}
+	if (c == EOF)
+		ERROR "unexpected end of file in do_thru" FATAL;
+	if (argcnt == 0) {	/* ignore blank line */
+		pushsrc(Thru, (char *) 0);
+		return;
+	}
+	for (i = argcnt; i < MAXARGS; i++)
+		ap->argstk[i] = "";
+	if (dbg)
+		for (i = 0; i < argcnt; i++)
+			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
+	if (strcmp(ap->argstk[0], ".G2") == 0) {
+		thru = 0;
+		thrudef = 0;
+		pushsrc(String, "\n.G2\n");
+		return;
+	}
+	if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
+		thru = 0;
+		thrudef = 0;
+		free(untilstr);
+		untilstr = 0;
+		return;
+	}
+	pushsrc(Thru, (char *) 0);
+	dprintf("do_thru pushing back <%s>\n", thrudef->val);
+	argfp = ap;
+	pushsrc(Macro, thrudef->val);
+}
+
+unput(int c)
+{
+	if (++pb >= pbuf + sizeof pbuf)
+		ERROR "pushback overflow" FATAL;
+	if (--ep < ebuf)
+		ep = ebuf + sizeof(ebuf) - 1;
+	*pb = c;
+	pushsrc(Char, pb);
+	return c;
+}
+
+void pbstr(char *s)
+{
+	pushsrc(String, s);
+}
+
+double errcheck(double x, char *s)
+{
+	extern int errno;
+
+	if (errno == EDOM) {
+		errno = 0;
+		ERROR "%s argument out of domain", s WARNING;
+	} else if (errno == ERANGE) {
+		errno = 0;
+		ERROR "%s result out of range", s WARNING;
+	}
+	return x;
+}
+
+char	errbuf[200];
+
+void yyerror(char *s)
+{
+	extern char *cmdname;
+	int ern = errno;	/* cause some libraries clobber it */
+
+	if (synerr)
+		return;
+	fflush(stdout);
+	fprintf(stderr, "%s: %s", cmdname, s);
+	if (ern > 0) {
+		errno = ern;
+		perror("???");
+	}
+	fprintf(stderr, " near %s:%d\n",
+		curfile->fname, curfile->lineno+1);
+	eprint();
+	synerr = 1;
+	errno = 0;
+}
+
+void eprint(void)	/* try to print context around error */
+{
+	char *p, *q;
+
+	p = ep - 1;
+	if (p > ebuf && *p == '\n')
+		p--;
+	for ( ; p >= ebuf && *p != '\n'; p--)
+		;
+	while (*p == '\n')
+		p++;
+	fprintf(stderr, " context is\n\t");
+	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
+		;
+	for (; p < q; p++)
+		if (isprint(*p))
+			putc(*p, stderr);
+	fprintf(stderr, " >>> ");
+	for (; p < q; p++)
+		if (isprint(*p))
+			putc(*p, stderr);
+	fprintf(stderr, " <<< ");
+	while (pb >= pbuf)
+		putc(*pb--, stderr);
+	fgets(ebuf, sizeof ebuf, curfile->fin);
+	fprintf(stderr, "%s", ebuf);
+	pbstr("\n.G2\n");	/* safety first */
+	ep = ebuf;
+}
+
+int yywrap(void) {return 1;}
+
+char	*newfile = 0;		/* filename for file copy */
+char	*untilstr = 0;		/* string that terminates a thru */
+int	thru	= 0;		/* 1 if copying thru macro */
+Obj	*thrudef = 0;		/* macro being used */
+
+void copyfile(char *s)	/* remember file to start reading from */
+{
+	newfile = s;
+}
+
+void copydef(Obj *p)	/* remember macro Obj */
+{
+	thrudef = p;
+}
+
+Obj *copythru(char *s)	/* collect the macro name or body for thru */
+{
+	Obj *p;
+	char *q;
+
+	p = lookup(s, 0);
+	if (p != NULL) {
+		if (p->type == DEFNAME) {
+			p->val = addnewline(p->val);
+			return p;
+		} else
+			ERROR "%s used as define and name", s FATAL;
+	}
+	/* have to collect the definition */
+	pbstr(s);	/* first char is the delimiter */
+	q = delimstr("thru body");
+	p = lookup("nameless", 1);
+	if (p != NULL)
+		if (p->val)
+			free(p->val);
+	p->type = DEFNAME;
+	p->val = q;
+	p->val = addnewline(p->val);
+	dprintf("installing nameless as `%s'\n", p->val);
+	return p;
+}
+
+char *addnewline(char *p)	/* add newline to end of p */
+{
+	int n;
+
+	n = strlen(p);
+	if (p[n-1] != '\n') {
+		p = realloc(p, n+2);
+		p[n] = '\n';
+		p[n+1] = '\0';
+	}
+	return p;
+}
+
+void copyuntil(char *s)	/* string that terminates a thru */
+{
+	untilstr = s;
+}
+
+void copy(void)	/* begin input from file, etc. */
+{
+	FILE *fin;
+
+	if (newfile) {
+		if ((fin = fopen(unsharp(newfile), "r")) == NULL)
+			ERROR "can't open file %s", newfile FATAL;
+		curfile++;
+		curfile->fin = fin;
+		curfile->fname = tostring(newfile);
+		curfile->lineno = 0;
+		printf(".lf 1 %s\n", curfile->fname);
+		pushsrc(File, curfile->fname);
+		newfile = 0;
+	}
+	if (thrudef) {
+		thru = 1;
+		begin = 1;	/* wrong place */
+	}
+}
+
+char	shellbuf[1000], *shellp;
+
+void shell_init(void)	/* set up to interpret a shell command */
+{
+	fprintf(tfd, "# shell cmd...\n");
+	sprintf(shellbuf, "rc -c '");
+	shellp = shellbuf + strlen(shellbuf);
+}
+
+void shell_text(char *s)	/* add string to command being collected */
+{
+	/* fprintf(tfd, "#add <%s> to <%s>\n", s, shellbuf); */
+	while (*s) {
+		if (*s == '\'')	{	/* protect interior quotes */
+			*shellp++ = '\'';
+			*shellp++ = '\\';
+			*shellp++ = '\'';
+		}
+		*shellp++ = *s++;
+	}
+}
+
+void shell_exec(void)	/* do it */
+{
+	/* fprintf(tfd, "# run <%s>\n", shellbuf); */
+	*shellp++ = '\'';
+	*shellp = '\0';
+	system(shellbuf);
+}
blob - /dev/null
blob + e788dd9d9d21102ec53f62e8955cd5e7e489e0c6 (mode 644)
--- /dev/null
+++ src/cmd/grap/label.c
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include <string.h>
+#include "grap.h"
+#include "y.tab.h"
+
+int	pointsize	= 10;	/* assumed pointsize to start */
+int	ps_set		= 0;	/* someone has set pointsize explicitly */
+
+double	textht	= 1.0/6.0;	/* 6 lines/inch */
+double	textwid = 1;		/* width of text box for vertical */
+
+double	lab_up	= 0.0;		/* extra motion for label */
+double	lab_rt	= 0.0;		/* extra motion for label */
+double	lab_wid	= 0.0;		/* override default width computation */
+
+void labelwid(double amt)
+{
+	lab_wid = amt + .00001;
+}
+
+void labelmove(int dir, double amt)	/* record direction & motion of position corr */
+{
+	switch (dir) {
+	case UP:	lab_up += amt; break;
+	case DOWN:	lab_up -= amt; break;
+	case LEFT:	lab_rt -= amt; break;
+	case RIGHT:	lab_rt += amt; break;
+	}
+}
+
+void label(int label_side, Attr *stringlist)	/* stick label on label_side */
+{
+	int m;
+	Attr *ap;
+
+	fprintf(tfd, "\ttextht = %g\n", textht);
+	if (lab_wid != 0.0) {
+		fprintf(tfd, "\ttextwid = %g\n", lab_wid);
+		lab_wid = 0;
+	} else if (label_side == LEFT || label_side == RIGHT) {
+		textwid = 0;
+		for (ap = stringlist; ap != NULL; ap = ap->next)
+			if ((m = strlen(ap->sval)) > textwid)
+				textwid = m;
+		textwid /= 15;	/* estimate width at 15 chars/inch */
+		fprintf(tfd, "\ttextwid = %g\n", textwid);
+	}
+	fprintf(tfd, "Label:\t%s", slprint(stringlist));
+	freeattr(stringlist);
+	switch (label_side) {
+	case BOT:
+	case 0:
+		fprintf(tfd, " with .n at Frame.s - (0,2 * textht)");
+		break;
+	case LEFT:
+		fprintf(tfd, " wid textwid with .e at Frame.w - (0.2,0)");
+		break;
+	case RIGHT:
+		fprintf(tfd, " wid textwid with .w at Frame.e + (0.2,0)");
+		break;
+	case TOP:
+		fprintf(tfd, " with .s at Frame.n + (0,2 * textht)");
+		break;
+	}
+	lab_adjust();
+	fprintf(tfd, "\n");
+	label_side = BOT;
+}
+
+void lab_adjust(void)	/* add a string to adjust labels, ticks, etc. */
+{
+	if (lab_up != 0.0 || lab_rt != 0.0)
+		fprintf(tfd, " + (%g,%g)", lab_rt, lab_up);
+}
+
+char *sizeit(Attr *ap)		/* add \s..\s to ap->sval */
+{
+	int n;
+	static char buf[1000];
+
+	if (!ap->op) {	/* no explicit size command */
+		if (ps_set) {
+			sprintf(buf, "\\s%d%s\\s0", pointsize, ap->sval);
+			return buf;
+		} else
+			return ap->sval;
+	} else if (!ps_set) {	/* explicit size but no global size */
+		n = (int) ap->fval;
+		switch (ap->op) {
+		case ' ':	/* absolute size */
+			sprintf(buf, "\\s%d%s\\s0", n, ap->sval);
+			break;
+		case '+':	/* better be only one digit! */
+			sprintf(buf, "\\s+%d%s\\s-%d", n, ap->sval, n);
+			break;
+		case '-':
+			sprintf(buf, "\\s-%d%s\\s+%d", n, ap->sval, n);
+			break;
+		case '*':
+		case '/':
+			return ap->sval;	/* ignore for now */
+		}
+		return buf;
+	} else {
+		/* explicit size and a global background size */
+		n = (int) ap->fval;
+		switch (ap->op) {
+		case ' ':	/* absolute size */
+			sprintf(buf, "\\s%d%s\\s0", n, ap->sval);
+			break;
+		case '+':
+			sprintf(buf, "\\s%d%s\\s0", pointsize+n, ap->sval);
+			break;
+		case '-':
+			sprintf(buf, "\\s%d%s\\s0", pointsize-n, ap->sval);
+			break;
+		case '*':
+		case '/':
+			return ap->sval;	/* ignore for now */
+		}
+		return buf;
+	}
+}
blob - /dev/null
blob + 0aa674176e8f752ea61a9a3fd81303fa391aac47 (mode 644)
--- /dev/null
+++ src/cmd/grap/main.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <signal.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "grap.h"
+#include "y.tab.h"
+
+int	dbg	= 0;
+
+#ifndef GRAPDEFINES
+#define GRAPDEFINES "#9/sys/lib/grap.defines"
+#endif
+char	*lib_defines	= GRAPDEFINES;
+
+int	lib	= 1;		/* 1 to include lib_defines */
+FILE	*tfd	= NULL;
+char	tempfile[L_tmpnam];
+
+int	synerr	= 0;
+int	codegen	= 0;   		/* 1=>output for this picture; 0=>no output */
+char	*cmdname;
+
+Obj	*objlist = NULL;	/* all names stored here */
+
+#define	BIG	1e30
+Point	ptmin	= { NULL, -BIG, -BIG };
+Point	ptmax	= { NULL, BIG, BIG };
+
+char	*version = "version Dec 30, 1995";
+
+extern int yyparse(void);
+extern void setdefaults(void);
+extern void getdata(void);
+extern	int	unlink(char *);
+
+main(int argc, char *argv[])
+{
+	extern void onintr(int), fpecatch(int);
+
+	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+		signal(SIGINT, onintr);
+	signal(SIGFPE, fpecatch);
+	cmdname = argv[0];
+	tmpnam(tempfile);
+	while (argc > 1 && *argv[1] == '-') {
+		switch (argv[1][1]) {
+		case 'd':
+			dbg = 1;
+			tfd = stdout;
+			strcpy(tempfile, "grap.temp");
+			unlink(tempfile);
+			fprintf(stderr, "%s\n", version);
+			break;
+		case 'l':	/* turn off /usr/lib inclusion */
+			lib = 0;
+			break;
+		}
+		argc--;
+		argv++;
+	}
+	setdefaults();
+	curfile = infile;
+	if (argc <= 1) {
+		curfile->fin = stdin;
+		curfile->fname = tostring("-");
+		pushsrc(File, curfile->fname);
+		getdata();
+	} else
+		while (argc-- > 1) {
+			if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
+				fprintf(stderr, "grap: can't open %s\n", *argv);
+				onintr(0);
+			}
+			curfile->fname = tostring(*argv);
+			pushsrc(File, curfile->fname);
+			getdata();
+			fclose(curfile->fin);
+			free(curfile->fname);
+		}
+	if (!dbg)
+		unlink(tempfile);
+	exit(0);
+}
+
+void onintr(int n)
+{
+	n;
+	if (!dbg)
+		unlink(tempfile);
+	exit(1);
+}
+
+void fpecatch(int n)
+{
+	ERROR "floating point exception" WARNING;
+	onintr(n);
+}
+
+char *grow(char *ptr, char *name, int num, int size)	/* make array bigger */
+{
+	char *p;
+
+	if (ptr == NULL)
+		p = malloc(num * size);
+	else
+		p = realloc(ptr, num * size);
+	if (p == NULL)
+		ERROR "can't grow %s to %d", name, num * size FATAL;
+	return p;
+}
+
+static struct {
+	char	*name;
+	double	val;
+} defaults[] ={
+	"frameht", FRAMEHT,
+	"framewid", FRAMEWID,
+	"ticklen", TICKLEN,
+	"slop", SLOP,
+	NULL, 0
+};
+
+void setdefaults(void)	/* set default sizes for variables */
+{
+	int i;
+	Obj *p;
+
+	for (i = 0; defaults[i].name != NULL; i++) {
+		p = lookup(defaults[i].name, 1);
+		setvar(p, defaults[i].val);
+	}
+}
+
+void getdata(void)		/* read input */
+{
+	register FILE *fin;
+	char buf[1000], buf1[100];
+	int ln;
+
+	fin = curfile->fin;
+	curfile->lineno = 0;
+	printf(".lf 1 %s\n", curfile->fname);
+	while (fgets(buf, sizeof buf, fin) != NULL) {
+		curfile->lineno++;
+		if (*buf == '.' && *(buf+1) == 'G' && *(buf+2) == '1') {
+			setup();
+			fprintf(stdout, ".PS%s", &buf[3]);	/* maps .G1 [w] to .PS w */
+			printf("scale = 1\n");	/* defends against cip users */
+			printf(".lf %d\n", curfile->lineno+1);
+			yyparse();
+			fprintf(stdout, ".PE\n");
+			printf(".lf %d\n", curfile->lineno+1);
+			fflush(stdout);
+		} else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
+			if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
+				free(curfile->fname);
+				printf(".lf %d %s\n", curfile->lineno = ln, curfile->fname = tostring(buf1));
+			} else
+				printf(".lf %d\n", curfile->lineno = ln);
+		} else
+			fputs(buf, stdout);
+	}
+}
blob - /dev/null
blob + 7a68a69277f0bdf1473ea2912fdeac3ae663fe69 (mode 644)
--- /dev/null
+++ src/cmd/grap/misc.c
@@ -0,0 +1,263 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "grap.h"
+#include "y.tab.h"
+
+int	nnum	= 0;	/* number of saved numbers */
+double	num[MAXNUM];
+
+int	just;		/* current justification mode (RJUST, etc.) */
+int	sizeop;		/* current optional operator for size change */
+double	sizexpr;	/* current size change expression */
+
+void savenum(int n, double f)	/* save f in num[n] */
+{
+	num[n] = f;
+	nnum = n+1;
+	if (nnum >= MAXNUM)
+		ERROR "too many numbers" WARNING;
+}
+
+void setjust(int j)
+{
+	just |= j;
+}
+
+void setsize(int op, double expr)
+{
+	sizeop = op;
+	sizexpr = expr;
+}
+
+char *tostring(char *s)
+{
+	register char *p;
+
+	p = malloc(strlen(s)+1);
+	if (p == NULL)
+		ERROR "out of space in tostring on %s", s FATAL;
+	strcpy(p, s);
+	return(p);
+}
+
+void range(Point pt)	/* update the range for point pt */
+{
+	Obj *p = pt.obj;
+
+	if (!(p->coord & XFLAG)) {
+		if (pt.x > p->pt1.x)
+			p->pt1.x = pt.x;
+		if (pt.x < p->pt.x)
+			p->pt.x = pt.x;
+	}
+	if (!(p->coord & YFLAG)) {
+		if (pt.y > p->pt1.y)
+			p->pt1.y = pt.y;
+		if (pt.y < p->pt.y)
+			p->pt.y = pt.y;
+	}
+}
+
+void halfrange(Obj *p, int side, double val)	/* record max and min for one direction */
+{
+	if (!(p->coord&XFLAG) && (side == LEFT || side == RIGHT)) {
+		if (val < p->pt.y)
+			p->pt.y = val;
+		if (val > p->pt1.y)
+			p->pt1.y = val;
+	} else if (!(p->coord&YFLAG) && (side == TOP || side == BOT)) {
+		if (val < p->pt.x)
+			p->pt.x = val;
+		if (val > p->pt1.x)
+			p->pt1.x = val;
+	}
+}
+
+
+Obj *lookup(char *s, int inst)	/* find s in objlist, install if inst */
+{
+	Obj *p;
+	int found = 0;
+
+	for (p = objlist; p; p = p->next){
+		if (strcmp(s, p->name) == 0) {
+			found = 1;
+			break;
+		}
+	}
+	if (p == NULL && inst != 0) {
+		p = (Obj *) calloc(1, sizeof(Obj));
+		if (p == NULL)
+			ERROR "out of space in lookup" FATAL;
+		p->name = tostring(s);
+		p->type = NAME;
+		p->pt = ptmax;
+		p->pt1 = ptmin;
+		p->fval = 0.0;
+		p->next = objlist;
+		objlist = p;
+	}
+	dprintf("lookup(%s,%d) = %d\n", s, inst, found);
+	return p;
+}
+
+double getvar(Obj *p)	/* return value of variable */
+{
+	return p->fval;
+}
+
+double setvar(Obj *p, double f)	/* set value of variable to f */
+{
+	if (strcmp(p->name, "pointsize") == 0) {	/* kludge */
+		pointsize = f;
+		ps_set = 1;
+	}
+	p->type = VARNAME;
+	return p->fval = f;
+}
+
+Point makepoint(Obj *s, double x, double y)	/* make a Point */
+{
+	Point p;
+	
+	dprintf("makepoint: %s, %g,%g\n", s->name, x, y);
+	p.obj = s;
+	p.x = x;
+	p.y = y;
+	return p;
+}
+
+Attr *makefattr(int type, double fval)	/* set double in attribute */
+{
+	return makeattr(type, fval, (char *) 0, 0, 0);
+}
+
+Attr *makesattr(char *s)		/* make an Attr cell containing s */
+{
+	Attr *ap = makeattr(STRING, sizexpr, s, just, sizeop);
+	just = sizeop = 0;
+	sizexpr = 0.0;
+	return ap;
+}
+
+Attr *makeattr(int type, double fval, char *sval, int just, int op)
+{
+	Attr *a;
+
+	a = (Attr *) malloc(sizeof(Attr));
+	if (a == NULL)
+		ERROR "out of space in makeattr" FATAL;
+	a->type = type;
+	a->fval = fval;
+	a->sval = sval;
+	a->just = just;
+	a->op = op;
+	a->next = NULL;
+	return a;
+}
+
+Attr *addattr(Attr *a1, Attr *ap)	/* add attr ap to end of list a1 */
+{
+	Attr *p;
+
+	if (a1 == 0)
+		return ap;
+	if (ap == 0)
+		return a1;
+	for (p = a1; p->next; p = p->next)
+		;
+	p->next = ap;
+	return a1;
+}
+
+void freeattr(Attr *ap)	/* free an attribute list */
+{
+	Attr *p;
+
+	while (ap) {
+		p = ap->next;	/* save next */
+		if (ap->sval)
+			free(ap->sval);
+		free((char *) ap);
+		ap = p;
+	}
+}
+
+char *slprint(Attr *stringlist)	/* print strings from stringlist */
+{
+	int ntext, n, last_op, last_just;
+	double last_fval;
+	static char buf[1000];
+	Attr *ap;
+
+	buf[0] = '\0';
+	last_op = last_just = 0;
+	last_fval = 0.0;
+	for (ntext = 0, ap = stringlist; ap != NULL; ap = ap->next)
+		ntext++;
+	sprintf(buf, "box invis wid 0 ht %d*textht", ntext);
+	n = strlen(buf);
+	for (ap = stringlist; ap != NULL; ap = ap->next) {
+		if (ap->op == 0) {	/* propagate last value */
+			ap->op = last_op;
+			ap->fval = last_fval;
+		} else {
+			last_op = ap->op;
+			last_fval = ap->fval;
+		}
+		sprintf(buf+n, " \"%s\"", ps_set || ap->op ? sizeit(ap) : ap->sval);
+		if (ap->just)
+			last_just = ap->just;
+		if (last_just)
+			strcat(buf+n, juststr(last_just));
+		n = strlen(buf);
+	}
+	return buf;	/* watch it:  static */
+}
+
+char *juststr(int j)	/* convert RJUST, etc., into string */
+{
+	static char buf[50];
+
+	buf[0] = '\0';
+	if (j & RJUST)
+		strcat(buf, " rjust");
+	if (j & LJUST)
+		strcat(buf, " ljust");
+	if (j & ABOVE)
+		strcat(buf, " above");
+	if (j & BELOW)
+		strcat(buf, " below");
+	return buf;	/* watch it:  static */
+}
+
+char *sprntf(char *s, Attr *ap)	/* sprintf(s, attrlist ap) */
+{
+	char buf[500];
+	int n;
+	Attr *p;
+
+	for (n = 0, p = ap; p; p = p->next)
+		n++;
+	switch (n) {
+	case 0:
+		return s;
+	case 1:
+		sprintf(buf, s, ap->fval);
+		break;
+	case 2:
+		sprintf(buf, s, ap->fval, ap->next->fval);
+		break;
+	case 3:
+		sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval);
+		break;
+	case 5:
+		ERROR "too many expressions in sprintf" WARNING;
+	case 4:
+		sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval, ap->next->next->next->fval);
+		break;
+	}
+	free(s);
+	return tostring(buf);
+}
blob - /dev/null
blob + 872497d1222c20eda3c7ec8a2ebe186b38f6f8e8 (mode 644)
--- /dev/null
+++ src/cmd/grap/mkfile
@@ -0,0 +1,37 @@
+<$PLAN9/src/mkhdr
+
+TARG=grap
+OFILES=\
+	grap.$O\
+	grapl.$O\
+	main.$O\
+	input.$O\
+	print.$O\
+	frame.$O\
+	for.$O\
+	coord.$O\
+	ticks.$O\
+	plot.$O\
+	label.$O\
+	misc.$O\
+
+HFILES=grap.h\
+	y.tab.h\
+
+YFILES=grap.y\
+
+LFILES=grapl.lx\
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
+YFLAGS = -d -S
+LEX=9lex
+
+grap.c:	y.tab.c
+	mv $prereq $target
+
+grapl.c:	$LFILES
+	$LEX -t $prereq > $target
+
+clean:V:
+	rm -f [$OS].out *.[$OS] y.tab.? lex.yy.c grapl.c grap.c grap
blob - /dev/null
blob + ab375953618e1da406827341fa5d8ec3b3453ec3 (mode 644)
--- /dev/null
+++ src/cmd/grap/plot.c
@@ -0,0 +1,132 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "grap.h"
+#include "y.tab.h"
+
+void line(int type, Point p1, Point p2, Attr *desc)	/* draw a line segment */
+{
+	fprintf(tfd, "%s %s from %s",
+		type==LINE ? "line" : "arrow",  desc_str(desc), xyname(p1));
+	fprintf(tfd, " to %s", xyname(p2));	/* 'cause xyname is botched */
+	fprintf(tfd, "\n");
+	range(p1);
+	range(p2);
+}
+
+void circle(double r, Point pt)		/* draw a circle */
+{
+	if (r > 0.0)
+		fprintf(tfd, "circle rad %g at %s\n", r, xyname(pt));
+	else
+		fprintf(tfd, "\"\\s-3\\(ob\\s0\" at %s\n", xyname(pt));
+	range(pt);
+}
+
+char *xyname(Point pt)	/* generate xy name macro for point p */
+{
+	static char buf[200];
+	Obj *p;
+
+	p = pt.obj;
+	if (p->log & XFLAG) {
+		if (pt.x <= 0.0)
+			ERROR "can't take log of x coord %g", pt.x FATAL;
+		logit(pt.x);
+	}
+	if (p->log & YFLAG) {
+		if (pt.y <= 0.0)
+			ERROR "can't take log of y coord %g", pt.y FATAL;
+		logit(pt.y);
+	}
+	sprintf(buf, "xy_%s(%g,%g)", p->name, pt.x, pt.y);
+	return buf;	/* WATCH IT:  static */
+}
+
+void pic(char *s)	/* fire out pic stuff directly */
+{
+	while (*s == ' ')
+		s++;
+	fprintf(tfd, "%s\n", s);
+}
+
+int	auto_x	= 0;	/* counts abscissa if none provided */
+
+void numlist(void)	/* print numbers in default way */
+{
+	Obj *p;
+	Point pt;
+	int i;
+	static char *spot = "\\(bu";
+	Attr *ap;
+
+	p = pt.obj = lookup(curr_coord, 1);
+	if (nnum == 1) {
+		nnum = 2;
+		num[1] = num[0];
+		num[0] = ++auto_x;
+	}
+	pt.x = num[0];
+	if (p->attr && p->attr->sval)
+		spot = p->attr->sval;
+	for (i = 1; i < nnum; i++) {
+		pt.y = num[i];
+		if (p->attr == 0 || p->attr->type == 0) {
+			ap = makesattr(tostring(spot));
+			plot(ap, pt);
+		} else
+			next(p, pt, p->attr);
+	}
+	nnum = 0;
+}
+
+void plot(Attr *sl, Point pt)	/* put stringlist sl at point pt */
+{
+	fprintf(tfd, "%s at %s\n", slprint(sl), xyname(pt));
+	range(pt);
+	freeattr(sl);
+}
+
+void plotnum(double f, char *fmt, Point pt)	/* plot value f at point */
+{
+	char buf[100];
+
+	if (fmt) {
+		sprintf(buf, fmt, f);
+		free(fmt);
+	} else if (f >= 0.0)
+		sprintf(buf, "%g", f);
+	else
+		sprintf(buf, "\\-%g", -f);
+	fprintf(tfd, "\"%s\" at %s\n", buf, xyname(pt));
+	range(pt);
+}
+
+void drawdesc(int type, Obj *p, Attr *desc, char *s)	/* set line description for p */
+{
+	p->attr = desc;
+	p->attr->sval = s;
+	if (type == NEW) {
+		p->first = 0;	/* so it really looks new */
+		auto_x = 0;
+	}
+}
+
+void next(Obj *p, Point pt, Attr *desc)	/* add component to a path */
+{
+	char *s;
+
+	if (p->first == 0) {
+		p->first++;
+		fprintf(tfd, "L%s: %s\n", p->name, xyname(pt));
+	} else {
+		fprintf(tfd, "line %s from L%s to %s; L%s: Here\n",
+			desc_str(desc->type ? desc : p->attr),
+			p->name, xyname(pt), p->name);
+	}
+	if (p->attr && (s=p->attr->sval)) {
+		/* BUG: should fix size here */
+		fprintf(tfd, "\"%s\" at %s\n", s, xyname(pt));
+	}
+	range(pt);
+}
blob - /dev/null
blob + 8f553c8f3b3b6a1481144290ce09b4fa1414e9e5 (mode 644)
--- /dev/null
+++ src/cmd/grap/print.c
@@ -0,0 +1,236 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include "grap.h"
+#include "y.tab.h"
+
+double	margin	= MARGIN;	/* extra space around edges */
+extern	double	frame_ht, frame_wid, ticklen;
+extern int just, sizeop, tick_dir;
+extern double sizexpr, lab_up, lab_rt;
+
+char	graphname[50] = "Graph";
+char	graphpos[200] = "";
+
+void print(void)	/* arrange final output */
+{
+	FILE *fd;
+	Obj *p, *dfp;
+	int c;
+	double dx, dy, xfac, yfac;
+
+	if (tfd != NULL) {
+		fclose(tfd);	/* end the temp file */
+		tfd = stdout;
+	}
+
+	if ((p=lookup("margin",0)) != NULL)
+		margin = p->fval;
+	if (frame_ht < 0)	/* wasn't set explicitly, so use default */
+		frame_ht = getvar(lookup("frameht", 0));
+	if (frame_wid < 0)
+		frame_wid = getvar(lookup("framewid", 0));
+	dfp = NULL;
+	for (p = objlist; p; p = p->next) {
+		dprintf("print: name = <%s>, type = %d\n", p->name, p->type);
+		if (p->type == NAME) {
+			Point pt, pt1;	
+			pt = p->pt;
+			pt1 = p->pt1;
+			fprintf(tfd, "\t# %s %g .. %g, %g .. %g\n",
+				p->name, pt.x, pt1.x, pt.y, pt1.y);
+			if (p->log & XFLAG) {
+				if (pt.x <= 0.0)
+					ERROR "can't take log of x coord %g", pt.x FATAL;
+				logit(pt.x);
+				logit(pt1.x);
+			}
+			if (p->log & YFLAG) {
+				if (pt.y <= 0.0)
+					ERROR "can't take log of y coord %g", pt.y FATAL;
+				logit(pt.y);
+				logit(pt1.y);
+			}
+			if (!(p->coord & XFLAG)) {
+				dx = pt1.x - pt.x;
+				pt.x -= margin * dx;
+				pt1.x += margin * dx;
+			}
+			if (!(p->coord & YFLAG)) {
+				dy = pt1.y - pt.y;
+				pt.y -= margin * dy;
+				pt1.y += margin * dy;
+			}
+			if (autoticks && strcmp(p->name, dflt_coord) == 0) {
+				p->pt = pt;
+				p->pt1 = pt1;
+				if (p->log & XFLAG) {
+					p->pt.x = pow(10.0, pt.x);
+					p->pt1.x = pow(10.0, pt1.x);
+				}
+				if (p->log & YFLAG) {
+					p->pt.y = pow(10.0, pt.y);
+					p->pt1.y = pow(10.0, pt1.y);
+				}
+				dfp = setauto();
+			}		
+			dx = pt1.x - pt.x;
+			dy = pt1.y - pt.y;
+			xfac = dx > 0 ? frame_wid/dx : frame_wid/2;
+			yfac = dy > 0 ? frame_ht/dy : frame_ht/2;
+
+			fprintf(tfd, "define xy_%s @ ", p->name);
+			if (dx > 0)
+				fprintf(tfd, "\t(($1)-(%g))*%g", pt.x, xfac);
+			else
+				fprintf(tfd, "\t%g", xfac);
+			if (dy > 0)
+				fprintf(tfd, ", (($2)-(%g))*%g @\n", pt.y, yfac);
+			else
+				fprintf(tfd, ", %g @\n", yfac);
+			fprintf(tfd, "define x_%s @ ", p->name);
+			if (dx > 0)
+				fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.x, xfac);
+			else
+				fprintf(tfd, "\t%g @\n", xfac);
+			fprintf(tfd, "define y_%s @ ", p->name);
+			if (dy > 0)
+				fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.y, yfac);
+			else
+				fprintf(tfd, "\t%g @\n", yfac);
+		}
+	}
+	if (codegen)
+		frame();
+	if (codegen && autoticks && dfp)
+		do_autoticks(dfp);
+
+	if ((fd = fopen(tempfile, "r")) != NULL) {
+		while ((c = getc(fd)) != EOF)
+			putc(c, tfd);
+		fclose(fd);
+	}
+	tfd = NULL;
+}
+
+void endstat(void)	/* clean up after each statement */
+{
+
+	just = sizeop = 0;
+	lab_up = lab_rt = 0.0;
+	sizexpr = 0.0;
+	nnum = 0;
+	ntick = 0;
+	tside = 0;
+	tick_dir = OUT;
+	ticklen = TICKLEN;
+}
+
+void graph(char *s)	/* graph statement */
+{
+	char *p, *os;
+	int c;
+
+	if (codegen) {
+		fprintf(stdout, "%s: [\n", graphname);
+		print();	/* pump out previous graph */
+		fprintf(stdout, "\n] %s\n", graphpos);
+		reset();
+	}
+	if (s) {
+		dprintf("into graph with <%s>\n", s);
+		opentemp();
+		os = s;
+		while ((c = *s) == ' ' || c == '\t')
+			s++;
+		if (c == '\0')
+			ERROR "no name on graph statement" WARNING;
+		if (!isupper(s[0]))
+			ERROR "graph name %s must be capitalized", s WARNING;
+		for (p=graphname; (c = *s) != ' ' && c != '\t' && c != '\0'; )
+			*p++ = *s++;
+		*p = '\0';
+		strcpy(graphpos, s);
+		dprintf("graphname = <%s>, graphpos = <%s>\n", graphname, graphpos);
+		free(os);
+	}
+}
+
+void setup(void)		/* done at each .G1 */
+{
+	static int firstG1 = 0;
+
+	reset();
+	opentemp();
+	frame_ht = frame_wid = -1;	/* reset in frame() */
+	ticklen = getvar(lookup("ticklen", 0));
+	if (firstG1++ == 0)
+		do_first();
+	codegen = synerr = 0;
+	strcpy(graphname, "Graph");
+	strcpy(graphpos, "");
+}
+
+void do_first(void)	/* done at first .G1:  definitions, etc. */
+{
+	extern int lib;
+	extern char *lib_defines;
+	static char buf[50], buf1[50];	/* static because pbstr uses them */
+	FILE *fp;
+	extern int getpid(void);
+
+	sprintf(buf, "define pid /%d/\n", getpid());
+	pbstr(buf);	
+	if (lib != 0) {
+		if ((fp = fopen(unsharp(lib_defines), "r")) != NULL) {
+			sprintf(buf1, "copy \"%s\"\n", lib_defines);
+			pbstr(buf1);
+			fclose(fp);
+		} else {
+			fprintf(stderr, "grap warning: can't open %s\n", lib_defines);
+		}
+	}
+}
+
+void reset(void)		/* done at each "graph ..." statement */
+{
+	Obj *p, *np, *deflist;
+	extern int tlist, toffside, autodir;
+
+	curr_coord = dflt_coord;
+	ncoord = auto_x = 0;
+	autoticks = LEFT|BOT;
+	autodir = 0;
+	tside = tlist = toffside = 0;
+	tick_dir = OUT;
+	margin = MARGIN;
+	deflist = NULL;
+	for (p = objlist; p; p = np) {
+		np = p->next;
+		if (p->type == DEFNAME || p->type == VARNAME) {
+			p->next = deflist;
+			deflist = p;
+		} else {
+			free(p->name);
+			freeattr(p->attr);
+			free((char *) p);
+		}
+	}
+	objlist = deflist;
+}
+
+void opentemp(void)
+{
+	if (tfd != NULL)
+		fclose(tfd);
+	if (tfd != stdout) {
+//		if (tfd != NULL)
+//			fclose(tfd);
+		if ((tfd = fopen(tempfile, "w")) == NULL) {
+			fprintf(stderr, "grap: can't open %s\n", tempfile);
+			exit(1);
+		}
+  	}
+}
blob - /dev/null
blob + 72fc06f54bf2cfa4b73f12033ab099faa6254053 (mode 644)
--- /dev/null
+++ src/cmd/grap/ticks.c
@@ -0,0 +1,492 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "grap.h"
+#include "y.tab.h"
+
+#define	MAXTICK	200
+int	ntick	= 0;
+double	tickval[MAXTICK];	/* tick values (one axis at a time */
+char	*tickstr[MAXTICK];	/* and labels */
+
+int	tside	= 0;
+int	tlist	= 0;		/* 1 => explicit values given */
+int	toffside = 0;		/* no ticks on these sides */
+int	goffside = 0;		/* no ticks on grid on these sides */
+int	tick_dir = OUT;
+double	ticklen	= TICKLEN;	/* default tick length */
+int	autoticks = LEFT|BOT;
+int	autodir = 0;		/* set LEFT, etc. if automatic ticks go in */
+
+void savetick(double f, char *s)	/* remember tick location and label */
+{
+	if (ntick >= MAXTICK)
+		ERROR "too many ticks (%d)", MAXTICK FATAL;
+	tickval[ntick] = f;
+	tickstr[ntick] = s;
+	ntick++;
+}
+
+void dflt_tick(double f)
+{
+	if (f >= 0.0)
+		savetick(f, tostring("%g"));
+	else
+		savetick(f, tostring("\\%g"));
+}
+
+void tickside(int n)	/* remember which side these ticks/gridlines go on */
+{
+	tside |= n;
+}
+
+void tickoff(int side)	/* remember explicit sides */
+{
+	toffside |= side;
+}
+
+void gridtickoff(void)	/* turn grid ticks off on the side previously specified (ugh) */
+{
+	goffside = tside;
+}
+
+void setlist(void)	/* remember that there was an explicit list */
+{
+	tlist = 1;
+}
+
+void tickdir(int dir, double val, int explicit)	/* remember in/out [expr] */
+{
+	tick_dir = dir;
+	if (explicit)
+		ticklen = val;
+}
+
+void ticks(void)		/* set autoticks after ticks statement */
+{
+	/* was there an explicit "ticks [side] off"? */
+	if (toffside)
+		autoticks &= ~toffside;
+	/* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */
+	if (tlist) {
+		if (tside & (BOT|TOP))
+			autoticks &= ~(BOT|TOP);
+		if (tside & (LEFT|RIGHT))
+			autoticks &= ~(LEFT|RIGHT);
+	}
+	/* was there a side without a list? (eg "ticks left in") */
+	if (tside && !tlist) {
+		if (tick_dir == IN)
+			autodir |= tside;
+		if (tside & (BOT|TOP))
+			autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP));
+		if (tside & (LEFT|RIGHT))
+			autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT));
+	}
+	tlist = tside = toffside = goffside = 0;
+	tick_dir = OUT;
+}
+
+double modfloor(double f, double t)
+{
+	t = fabs(t);
+	return floor(f/t) * t;
+}
+
+double modceil(double f, double t)
+{
+	t = fabs(t);
+	return ceil(f/t) * t;
+}
+
+double	xtmin, xtmax;	/* range of ticks */
+double	ytmin, ytmax;
+double	xquant, xmult;	/* quantization & scale for auto x ticks */
+double	yquant, ymult;
+double	lograt = 5;
+
+void do_autoticks(Obj *p)	/* make set of ticks for default coord only */
+{
+	double x, xl, xu, q;
+
+	if (p == NULL)
+		return;
+	fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g",
+		p->pt.x, p->pt1.x, p->pt.y, p->pt1.y);
+	fprintf(tfd, ";   xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n",
+		xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult);
+	if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) {	/* make x ticks */
+		q = xquant;
+		xl = p->pt.x;
+		xu = p->pt1.x;
+		if (xl >= xu)
+			dflt_tick(xl);
+		else if ((p->log & XFLAG) && xu/xl >= lograt) {
+			for (x = q; x < xu; x *= 10) {
+				logtick(x, xl, xu);
+				if (xu/xl <= 100) {
+					logtick(2*x, xl, xu);
+					logtick(5*x, xl, xu);
+				}
+			}
+		} else {
+			xl = modceil(xtmin - q/100, q);
+			xu = modfloor(xtmax + q/100, q) + q/2;
+			for (x = xl; x <= xu; x += q)
+				dflt_tick(x);
+		}
+		tside = autoticks & (BOT|TOP);
+		ticklist(p, 0);
+	}
+	if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) {	/* make y ticks */
+		q = yquant;
+		xl = p->pt.y;
+		xu = p->pt1.y;
+		if (xl >= xu)
+			dflt_tick(xl);
+		else if ((p->log & YFLAG) && xu/xl >= lograt) {
+			for (x = q; x < xu; x *= 10) {
+				logtick(x, xl, xu);
+				if (xu/xl <= 100) {
+					logtick(2*x, xl, xu);
+					logtick(5*x, xl, xu);
+				}
+			}
+		} else {
+			xl = modceil(ytmin - q/100, q);
+			xu = modfloor(ytmax + q/100, q) + q/2;
+			for (x = xl; x <= xu; x += q)
+				dflt_tick(x);
+		}
+		tside = autoticks & (LEFT|RIGHT);
+		ticklist(p, 0);
+	}
+}
+
+void logtick(double v, double lb, double ub)
+{
+	float slop = 1.0;	/* was 1.001 */
+
+	if (slop * lb <= v && ub >= slop * v)
+		dflt_tick(v);
+}
+
+Obj *setauto(void)	/* compute new min,max, and quant & mult */
+{
+	Obj *p, *q;
+
+	if ((q = lookup("lograt",0)) != NULL)
+		lograt = q->fval;
+	for (p = objlist; p; p = p->next)
+		if (p->type == NAME && strcmp(p->name,dflt_coord) == 0)
+			break;
+	if (p) {
+		if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt)
+			autolog(p, 'x');
+		else
+			autoside(p, 'x');
+		if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt)
+			autolog(p, 'y');
+		else
+			autoside(p, 'y');
+	}
+	return p;
+}
+
+void autoside(Obj *p, int side)
+{
+	double r, s, d, ub, lb;
+
+	if (side == 'x') {
+		xtmin = lb = p->pt.x;
+		xtmax = ub = p->pt1.x;
+	} else {
+		ytmin = lb = p->pt.y;
+		ytmax = ub = p->pt1.y;
+	}
+	if (ub <= lb)
+		return;	/* cop out on little ranges */
+	d = ub - lb;
+	r = s = 1;
+	while (d * s < 10)
+		s *= 10;
+	d *= s;
+	while (10 * r < d)
+		r *= 10;
+	if (r > d/3)
+		r /= 2;
+	else if (r <= d/6)
+		r *= 2;
+	if (side == 'x') {
+		xquant = r / s;
+	} else {
+		yquant = r / s;
+	}
+}
+
+void autolog(Obj *p, int side)
+{
+	double r, s, t, ub, lb;
+	int flg;
+
+	if (side == 'x') {
+		xtmin = lb = p->pt.x;
+		xtmax = ub = p->pt1.x;
+		flg = p->coord & XFLAG;
+	} else {
+		ytmin = lb = p->pt.y;
+		ytmax = ub = p->pt1.y;
+		flg = p->coord & YFLAG;
+	}
+	for (s = 1; lb * s < 1; s *= 10)
+		;
+	lb *= s;
+	ub *= s;
+	for (r = 1; 10 * r < lb; r *= 10)
+		;
+	for (t = 1; t < ub; t *= 10)
+		;
+	if (side == 'x')
+		xquant = r / s;
+	else
+		yquant = r / s;
+	if (flg)
+		return;
+	if (ub / lb < 100) {
+		if (lb >= 5 * r)
+			r *= 5;
+		else if (lb >= 2 * r)
+			r *= 2;
+		if (ub * 5 <= t)
+			t /= 5;
+		else if (ub * 2 <= t)
+			t /= 2;
+		if (side == 'x') {
+			xtmin = r / s;
+			xtmax = t / s;
+		} else {
+			ytmin = r / s;
+			ytmax = t / s;
+		}
+	}
+}
+
+void iterator(double from, double to, int op, double by, char *fmt)	/* create an iterator */
+{
+	double x;
+
+	/* should validate limits, etc. */
+	/* punt for now */
+
+	dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n",
+		from, to, by, op, fmt ? fmt : "");
+	switch (op) {
+	case '+':
+	case ' ':
+		for (x = from; x <= to + (SLOP-1) * by; x += by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	case '-':
+		for (x = from; x >= to; x -= by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	case '*':
+		for (x = from; x <= SLOP * to; x *= by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	case '/':
+		for (x = from; x >= to; x /= by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	}
+	if (fmt)
+		free(fmt);
+}
+
+void ticklist(Obj *p, int explicit)	/* fire out the accumulated ticks */
+					/* 1 => list, 0 => auto */
+{
+	if (p == NULL)
+		return;
+	fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen);
+	print_ticks(TICKS, explicit, p, "ticklen", "");
+}
+
+void print_ticks(int type, int explicit, Obj *p, char *lenstr, char *descstr)
+{
+	int i, logflag, inside;
+	char buf[100];
+	double tv;
+
+	for (i = 0; i < ntick; i++)	/* any ticks given explicitly? */
+		if (tickstr[i] != NULL)
+			break;
+	if (i >= ntick && type == TICKS)	/* no, so use values */
+		for (i = 0; i < ntick; i++) {
+			if (tickval[i] >= 0.0)
+				sprintf(buf, "%g", tickval[i]);
+			else
+				sprintf(buf, "\\-%g", -tickval[i]);
+			tickstr[i] = tostring(buf);
+		}
+	else
+		for (i = 0; i < ntick; i++) {
+			if (tickstr[i] != NULL) {
+				sprintf(buf, tickstr[i], tickval[i]);
+				free(tickstr[i]);
+				tickstr[i] = tostring(buf);
+			}
+		}
+	logflag = sidelog(p->log, tside);
+	for (i = 0; i < ntick; i++) {
+		tv = tickval[i];
+		halfrange(p, tside, tv);
+		if (logflag) {
+			if (tv <= 0.0)
+				ERROR "can't take log of tick value %g", tv FATAL;
+			logit(tv);
+		}
+		if (type == GRID)
+			inside = LEFT|RIGHT|TOP|BOT;
+		else if (explicit)
+			inside = (tick_dir == IN) ? tside : 0;
+		else
+			inside = autodir;
+		if (tside & BOT)
+			maketick(type, p->name, BOT, inside, tv, tickstr[i], lenstr, descstr);
+		if (tside & TOP)
+			maketick(type, p->name, TOP, inside, tv, tickstr[i], lenstr, descstr);
+		if (tside & LEFT)
+			maketick(type, p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr);
+		if (tside & RIGHT)
+			maketick(type, p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr);
+		if (tickstr[i]) {
+			free(tickstr[i]);
+			tickstr[i] = NULL;
+		}
+	}
+	ntick = 0;
+}
+
+void maketick(int type, char *name, int side, int inflag, double val, char *lab, char *lenstr, char *descstr)
+{
+	char *sidestr, *td;
+
+	fprintf(tfd, "\tline %s ", descstr);
+	inflag &= side;
+	switch (side) {
+	case BOT:
+	case 0:
+		td = inflag ? "up" : "down";
+		fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val);
+		break;
+	case TOP:
+		td = inflag ? "down" : "up";
+		fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val);
+		break;
+	case LEFT:
+		td = inflag ? "right" : "left";
+		fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val);
+		break;
+	case RIGHT:
+		td = inflag ? "left" : "right";
+		fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val);
+		break;
+	}
+	fprintf(tfd, "\n");
+	if (type == GRID && (side & goffside))	/* wanted no ticks on grid */
+		return;
+	sidestr = tick_dir == IN ? "start" : "end";
+	if (lab != NULL) {
+		/* BUG: should fix size of lab here */
+		double wid = strlen(lab)/7.5 + (tick_dir == IN ? 0 : 0.1);	/* estimate width at 15 chars/inch */
+		switch (side) {
+		case BOT: case 0:
+			/* can drop "box invis" with new pic */
+			fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s",
+				lab, sidestr);
+			break;
+		case TOP:
+			fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s",
+				lab, sidestr);
+			break;
+		case LEFT:
+			fprintf(tfd, "\t\"%s \" wid %.2f rjust at last line.%s",
+				lab, wid, sidestr);
+			break;
+		case RIGHT:
+			fprintf(tfd, "\t\" %s\" wid %.2f ljust at last line.%s",
+				lab, wid, sidestr);
+			break;
+		}
+		/* BUG: works only if "down x" comes before "at wherever" */
+		lab_adjust();
+		fprintf(tfd, "\n");
+	}
+}
+
+Attr	*grid_desc	= 0;
+
+void griddesc(Attr *a)
+{
+	grid_desc = a;
+}
+
+void gridlist(Obj *p)
+{
+	char *framestr;
+
+	if ((tside & (BOT|TOP)) || tside == 0)
+		framestr = "frameht";
+	else
+		framestr = "framewid";
+	fprintf(tfd, "Grid_%s:\n", p->name);
+	tick_dir = IN;
+	print_ticks(GRID, 0, p, framestr, desc_str(grid_desc));
+	if (grid_desc) {
+		freeattr(grid_desc);
+		grid_desc = 0;
+	}
+}
+
+char *desc_str(Attr *a)	/* convert DOT to "dotted", etc. */
+{
+	static char buf[50], *p;
+
+	if (a == NULL)
+		return p = "";
+	switch (a->type) {
+	case DOT:	p = "dotted"; break;
+	case DASH:	p = "dashed"; break;
+	case INVIS:	p = "invis"; break;
+	default:	p = "";
+	}
+	if (a->fval != 0.0) {
+		sprintf(buf, "%s %g", p, a->fval);
+		return buf;
+	} else
+		return p;
+}
+
+sidelog(int logflag, int side)	/* figure out whether to scale a side */
+{
+	if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0))
+		return 1;
+	else if ((logflag & YFLAG) && (side & (LEFT|RIGHT)))
+		return 1;
+	else
+		return 0;
+}
blob - e5ddf684f839346b10ff014df984c36a3a20c1af
blob + d08461e90c24753cd296545260dc03f5b43febbd
--- src/cmd/mkfile
+++ src/cmd/mkfile
@@ -5,7 +5,7 @@ SHORTLIB=sec fs mux regexp9 thread bio 9
 
 <$PLAN9/src/mkmany
 
-BUGGERED='CVS|faces|factotum|mailfs|scat|upas|vac|venti|lex|vncv'
+BUGGERED='CVS|faces|factotum|mailfs|scat|upas|vac|venti|lex|vncv|grap|eqn|troff|pic|tbl'
 DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
 
 <$PLAN9/src/mkdirs
blob - /dev/null
blob + d1b64224d24862cd717d3ebe74eb15864ba2a3f4 (mode 644)
--- /dev/null
+++ src/cmd/pic/arcgen.c
@@ -0,0 +1,221 @@
+#include	<stdio.h>
+#include	<math.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+void arc_extreme(double, double, double, double, double, double);
+int quadrant(double x, double y);
+
+obj *arcgen(int type)	/* handles circular and (eventually) elliptical arcs */
+{
+	static double prevw = HT10;
+	static double prevh = HT5;
+	static double prevrad = HT2;
+	static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 };
+	static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 };
+	static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 };
+	static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 };
+	static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR, R_DIR, U_DIR, L_DIR };
+	double dx2, dy2, ht, phi, r, d;
+	int i, head, to, at, cw, invis, ddtype, battr;
+	obj *p, *ppos;
+	double fromx, fromy, tox, toy, fillval = 0;
+	Attr *ap;
+
+	prevrad = getfval("arcrad");
+	prevh = getfval("arrowht");
+	prevw = getfval("arrowwid");
+	fromx = curx;
+	fromy = cury;
+	head = to = at = cw = invis = ddtype = battr = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case HEAD:
+			head += ap->a_val.i;
+			break;
+		case INVIS:
+			invis = INVIS;
+			break;
+		case HEIGHT:	/* length of arrowhead */
+			prevh = ap->a_val.f;
+			break;
+		case WIDTH:	/* width of arrowhead */
+			prevw = ap->a_val.f;
+			break;
+		case RADIUS:
+			prevrad = ap->a_val.f;
+			break;
+		case DIAMETER:
+			prevrad = ap->a_val.f / 2;
+			break;
+		case CW:
+			cw = 1;
+			break;
+		case FROM:	/* start point of arc */
+			ppos = ap->a_val.o;
+			fromx = ppos->o_x;
+			fromy = ppos->o_y;
+			break;
+		case TO:	/* end point of arc */
+			ppos = ap->a_val.o;
+			tox = ppos->o_x;
+			toy = ppos->o_y;
+			to++;
+			break;
+		case AT:	/* center of arc */
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at = 1;
+			break;
+		case UP:
+			hvmode = U_DIR;
+			break;
+		case DOWN:
+			hvmode = D_DIR;
+			break;
+		case RIGHT:
+			hvmode = R_DIR;
+			break;
+		case LEFT:
+			hvmode = L_DIR;
+			break;
+		case FILL:
+			battr |= FILLBIT;
+			if (ap->a_sub == DEFAULT)
+				fillval = getfval("fillval");
+			else
+				fillval = ap->a_val.f;
+			break;
+		}
+	}
+	if (!at && !to) {	/* the defaults are mostly OK */
+		curx = fromx + prevrad * dctrx[cw][hvmode];
+		cury = fromy + prevrad * dctry[cw][hvmode];
+		tox = fromx + prevrad * dtox[cw][hvmode];
+		toy = fromy + prevrad * dtoy[cw][hvmode];
+		hvmode = nexthv[cw][hvmode];
+	}
+	else if (!at) {
+		dx2 = (tox - fromx) / 2;
+		dy2 = (toy - fromy) / 2;
+		phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2);
+		if (prevrad <= 0.0)
+			prevrad = dx2*dx2+dy2*dy2;
+		for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2)
+			;	/* this kludge gets around too-small radii */
+		prevrad = r;
+		ht = sqrt(d);
+		curx = fromx + dx2 + ht * cos(phi);
+		cury = fromy + dy2 + ht * sin(phi);
+		dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n",
+			dx2, dy2, phi, r, ht);
+	}
+	else if (at && !to) {	/* do we have all the cases??? */
+		tox = fromx + prevrad * dtox[cw][hvmode];
+		toy = fromy + prevrad * dtoy[cw][hvmode];
+		hvmode = nexthv[cw][hvmode];
+	}
+	if (cw) {	/* interchange roles of from-to and heads */
+		double temp;
+		temp = fromx; fromx = tox; tox = temp;
+		temp = fromy; fromy = toy; toy = temp;
+		if (head == HEAD1)
+			head = HEAD2;
+		else if (head == HEAD2)
+			head = HEAD1;
+	}
+	p = makenode(type, 7);
+	arc_extreme(fromx, fromy, tox, toy, curx, cury);
+	p->o_val[0] = fromx;
+	p->o_val[1] = fromy;
+	p->o_val[2] = tox;
+	p->o_val[3] = toy;
+	if (cw) {
+		curx = fromx;
+		cury = fromy;
+	} else {
+		curx = tox;
+		cury = toy;
+	}
+	p->o_val[4] = prevw;
+	p->o_val[5] = prevh;
+	p->o_val[6] = prevrad;
+	p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype | battr;
+	p->o_fillval = fillval;
+	if (head)
+		p->o_nhead = getfval("arrowhead");
+	dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n",
+		prevrad, p->o_x, p->o_y,
+		p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]);
+	return(p);
+}
+
+/***************************************************************************
+   bounding box of a circular arc             Eric Grosse  24 May 84
+
+Conceptually, this routine generates a list consisting of the start,
+end, and whichever north, east, south, and west points lie on the arc.
+The bounding box is then the range of this list.
+    list = {start,end}
+    j = quadrant(start)
+    k = quadrant(end)
+    if( j==k && long way 'round )  append north,west,south,east
+    else
+      while( j != k )
+         append center+radius*[j-th of north,west,south,east unit vectors]
+         j += 1  (mod 4)
+    return( bounding box of list )
+The following code implements this, with simple optimizations.
+***********************************************************************/
+
+
+void arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc)
+			  /* start, end, center */
+{
+	/* assumes center isn't too far out */
+	double r, xmin, ymin, xmax, ymax;
+	int j, k;
+	x0 -= xc; y0 -= yc;	/* move to center */
+	x1 -= xc; y1 -= yc;
+	xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
+	xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
+	r = sqrt(x0*x0 + y0*y0);
+	if (r > 0.0) {
+		j = quadrant(x0,y0);
+		k = quadrant(x1,y1);
+		if (j == k && y1*x0 < x1*y0) {
+			/* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
+			if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
+			if( xmax <  r) xmax =  r; if( ymax <  r) ymax =  r;
+		} else {
+			while (j != k) {
+				switch (j) {
+					case 1: if( ymax <  r) ymax =  r; break; /* north */
+					case 2: if( xmin > -r) xmin = -r; break; /* west */
+					case 3: if( ymin > -r) ymin = -r; break; /* south */
+					case 4: if( xmax <  r) xmax =  r; break; /* east */
+				}
+				j = j%4 + 1;
+			}
+		}
+	}
+	xmin += xc; ymin += yc;
+	xmax += xc; ymax += yc;
+	extreme(xmin, ymin);
+	extreme(xmax, ymax);
+}
+
+quadrant(double x, double y)
+{
+	if (     x>=0.0 && y> 0.0) return(1);
+	else if( x< 0.0 && y>=0.0) return(2);
+	else if( x<=0.0 && y< 0.0) return(3);
+	else if( x> 0.0 && y<=0.0) return(4);
+	else			   return 0;	/* shut up lint */
+}
+
blob - /dev/null
blob + 9015d56d2ae001131c56a825e7f631a0c2834559 (mode 644)
--- /dev/null
+++ src/cmd/pic/blockgen.c
@@ -0,0 +1,226 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "pic.h"
+#include "y.tab.h"
+
+#define	NBRACK	20	/* depth of [...] */
+#define	NBRACE	20	/* depth of {...} */
+
+struct pushstack stack[NBRACK];
+int	nstack	= 0;
+struct pushstack bracestack[NBRACE];
+int	nbstack	= 0;
+
+void blockadj(obj *);
+
+obj *leftthing(int c)	/* called for {... or [... */
+			/* really ought to be separate functions */
+{
+	obj *p;
+
+	if (c == '[') {
+		if (nstack >= NBRACK)
+			ERROR "[...] nested too deep" FATAL;
+		stack[nstack].p_x = curx;
+		stack[nstack].p_y = cury;
+		stack[nstack].p_hvmode = hvmode;
+		curx = cury = 0;
+		stack[nstack].p_xmin = xmin;
+		stack[nstack].p_xmax = xmax;
+		stack[nstack].p_ymin = ymin;
+		stack[nstack].p_ymax = ymax;
+		nstack++;
+		xmin = ymin = 30000;
+		xmax = ymax = -30000;
+		p = makenode(BLOCK, 7);
+		p->o_val[4] = nobj;	/* 1st item within [...] */
+		if (p->o_nobj != nobj-1)
+			fprintf(stderr, "nobjs wrong%d %d\n", p->o_nobj, nobj);
+	} else {
+		if (nbstack >= NBRACK)
+			ERROR "{...} nested too deep" FATAL;
+		bracestack[nbstack].p_x = curx;
+		bracestack[nbstack].p_y = cury;
+		bracestack[nbstack].p_hvmode = hvmode;
+		nbstack++;
+		p = NULL;
+	}
+	return(p);
+}
+
+obj *rightthing(obj *p, int c)	/* called for ... ] or ... } */
+{
+	obj *q;
+
+	if (c == '}') {
+		nbstack--;
+		curx = bracestack[nbstack].p_x;
+		cury = bracestack[nbstack].p_y;
+		hvmode = bracestack[nbstack].p_hvmode;
+		q = makenode(MOVE, 0);
+		dprintf("M %g %g\n", curx, cury);
+	} else {
+		nstack--;
+		curx = stack[nstack].p_x;
+		cury = stack[nstack].p_y;
+		hvmode = stack[nstack].p_hvmode;
+		q = makenode(BLOCKEND, 7);
+		q->o_val[4] = p->o_nobj + 1;	/* back pointer */
+		p->o_val[5] = q->o_nobj - 1;	/* forward pointer */
+		if (xmin > xmax)	/* nothing happened */
+			xmin = xmax;
+		if (ymin > ymax)
+			ymin = ymax;
+		p->o_val[0] = xmin; p->o_val[1] = ymin;
+		p->o_val[2] = xmax; p->o_val[3] = ymax;
+		p->o_symtab = q->o_symtab = stack[nstack+1].p_symtab;
+		xmin = stack[nstack].p_xmin;
+		ymin = stack[nstack].p_ymin;
+		xmax = stack[nstack].p_xmax;
+		ymax = stack[nstack].p_ymax;
+	}
+	return(q);
+}
+
+obj *blockgen(obj *p, obj *q)	/* handles [...] */
+{
+	int i, invis, at, with;
+	double ddval, h, w, xwith, ywith;
+	double x0, y0, x1, y1, cx, cy;
+	obj *ppos;
+	Attr *ap;
+
+	invis = at = 0;
+	with = xwith = ywith = 0;
+	ddval = 0;
+	w = p->o_val[2] - p->o_val[0];
+	h = p->o_val[3] - p->o_val[1];
+	cx = (p->o_val[2] + p->o_val[0]) / 2;	/* geom ctr of [] wrt local orogin */
+	cy = (p->o_val[3] + p->o_val[1]) / 2;
+	dprintf("cx,cy=%g,%g\n", cx, cy);
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case HEIGHT:
+			h = ap->a_val.f;
+			break;
+		case WIDTH:
+			w = ap->a_val.f;
+			break;
+		case WITH:
+			with = ap->a_val.i;	/* corner */
+			break;
+		case PLACE:	/* actually with position ... */
+			ppos = ap->a_val.o;
+			xwith = cx - ppos->o_x;
+			ywith = cy - ppos->o_y;
+			with = PLACE;
+			break;
+		case AT:
+		case FROM:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case INVIS:
+			invis = INVIS;
+			break;
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		}
+	}
+	if (with) {
+		switch (with) {
+		case NORTH:	ywith = -h / 2; break;
+		case SOUTH:	ywith = h / 2; break;
+		case EAST:	xwith = -w / 2; break;
+		case WEST:	xwith = w / 2; break;
+		case NE:	xwith = -w / 2; ywith = -h / 2; break;
+		case SE:	xwith = -w / 2; ywith = h / 2; break;
+		case NW:	xwith = w / 2; ywith = -h / 2; break;
+		case SW:	xwith = w / 2; ywith = h / 2; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += w / 2;
+		else if (isleft(hvmode))
+			curx -= w / 2;
+		else if (isup(hvmode))
+			cury += h / 2;
+		else
+			cury -= h / 2;
+	}
+	x0 = curx - w / 2;
+	y0 = cury - h / 2;
+	x1 = curx + w / 2;
+	y1 = cury + h / 2;
+	extreme(x0, y0);
+	extreme(x1, y1);
+	p->o_x = curx;
+	p->o_y = cury;
+	p->o_nt1 = ntext1;
+	p->o_nt2 = ntext;
+	ntext1 = ntext;
+	p->o_val[0] = w;
+	p->o_val[1] = h;
+	p->o_val[2] = cx;
+	p->o_val[3] = cy;
+	p->o_val[5] = q->o_nobj - 1;		/* last item in [...] */
+	p->o_ddval = ddval;
+	p->o_attr = invis;
+	dprintf("[] %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w);
+	if (isright(hvmode))
+		curx = x1;
+	else if (isleft(hvmode))
+		curx = x0;
+	else if (isup(hvmode))
+		cury = y1;
+	else
+		cury = y0;
+	for (i = 0; i <= 5; i++)
+		q->o_val[i] = p->o_val[i];
+	stack[nstack+1].p_symtab = NULL;	/* so won't be found again */
+	blockadj(p);	/* fix up coords for enclosed blocks */
+	return(p);
+}
+
+void blockadj(obj *p)	/* adjust coords in block starting at p */
+{
+	double dx, dy;
+	int n, lev;
+
+	dx = p->o_x - p->o_val[2];
+	dy = p->o_y - p->o_val[3];
+	n = p->o_nobj + 1;
+	dprintf("into blockadj: dx,dy=%g,%g\n", dx, dy);
+	for (lev = 1; lev > 0; n++) {
+		p = objlist[n];
+		if (p->o_type == BLOCK)
+			lev++;
+		else if (p->o_type == BLOCKEND)
+			lev--;
+		dprintf("blockadj: type=%d o_x,y=%g,%g;", p->o_type, p->o_x, p->o_y);
+		p->o_x += dx;
+		p->o_y += dy;
+		dprintf(" becomes %g,%g\n", p->o_x, p->o_y);
+		switch (p->o_type) {	/* other absolute coords */
+		case LINE:
+		case ARROW:
+		case SPLINE:
+			p->o_val[0] += dx;
+			p->o_val[1] += dy;
+			break;
+		case ARC:
+			p->o_val[0] += dx;
+			p->o_val[1] += dy;
+			p->o_val[2] += dx;
+			p->o_val[3] += dy;
+			break;
+		}
+	}
+}
blob - /dev/null
blob + b575cd2f4251383fff6bb332bc76ac33ccbc3b4a (mode 644)
--- /dev/null
+++ src/cmd/pic/boxgen.c
@@ -0,0 +1,115 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj *boxgen(void)
+{
+	static double prevh = HT;
+	static double prevw = WID;	/* golden mean, sort of */
+	int i, at, battr, with;
+	double ddval, fillval, xwith, ywith;
+	double h, w, x0, y0, x1, y1;
+	obj *p, *ppos;
+	Attr *ap;
+
+	h = getfval("boxht");
+	w = getfval("boxwid");
+	at = battr = with = 0;
+	ddval = fillval = xwith = ywith = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case HEIGHT:
+			h = ap->a_val.f;
+			break;
+		case WIDTH:
+			w = ap->a_val.f;
+			break;
+		case SAME:
+			h = prevh;
+			w = prevw;
+			break;
+		case WITH:
+			with = ap->a_val.i;	/* corner */
+			break;
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case INVIS:
+			battr |= INVIS;
+			break;
+		case NOEDGE:
+			battr |= NOEDGEBIT;
+			break;
+		case DOT:
+		case DASH:
+			battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
+			if (ap->a_sub == DEFAULT)
+				ddval = getfval("dashwid");
+			else
+				ddval = ap->a_val.f;
+			break;
+		case FILL:
+			battr |= FILLBIT;
+			if (ap->a_sub == DEFAULT)
+				fillval = getfval("fillval");
+			else
+				fillval = ap->a_val.f;
+			break;
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		}
+	}
+	if (with) {
+		switch (with) {
+		case NORTH:	ywith = -h / 2; break;
+		case SOUTH:	ywith = h / 2; break;
+		case EAST:	xwith = -w / 2; break;
+		case WEST:	xwith = w / 2; break;
+		case NE:	xwith = -w / 2; ywith = -h / 2; break;
+		case SE:	xwith = -w / 2; ywith = h / 2; break;
+		case NW:	xwith = w / 2; ywith = -h / 2; break;
+		case SW:	xwith = w / 2; ywith = h / 2; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += w / 2;
+		else if (isleft(hvmode))
+			curx -= w / 2;
+		else if (isup(hvmode))
+			cury += h / 2;
+		else
+			cury -= h / 2;
+	}
+	x0 = curx - w / 2;
+	y0 = cury - h / 2;
+	x1 = curx + w / 2;
+	y1 = cury + h / 2;
+	extreme(x0, y0);
+	extreme(x1, y1);
+	p = makenode(BOX, 2);
+	p->o_val[0] = w;
+	p->o_val[1] = h;
+	p->o_attr = battr;
+	p->o_ddval = ddval;
+	p->o_fillval = fillval;
+	dprintf("B %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w);
+	if (isright(hvmode))
+		curx = x1;
+	else if (isleft(hvmode))
+		curx = x0;
+	else if (isup(hvmode))
+		cury = y1;
+	else
+		cury = y0;
+	prevh = h;
+	prevw = w;
+	return(p);
+}
blob - /dev/null
blob + f40bae9a1e03953f32275fdcdb25f9a1fda18989 (mode 644)
--- /dev/null
+++ src/cmd/pic/circgen.c
@@ -0,0 +1,126 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj *circgen(int type)
+{
+	static double rad[2] = { HT2, WID2 };
+	static double rad2[2] = { HT2, HT2 };
+	int i, at, t, with, battr;
+	double xwith, ywith;
+	double r, r2, ddval, fillval;
+	obj *p, *ppos;
+	Attr *ap;
+
+	battr = at = 0;
+	with = xwith = ywith = fillval = ddval = 0;
+	t = (type == CIRCLE) ? 0 : 1;
+	if (type == CIRCLE)
+		r = r2 = getfval("circlerad");
+	else if (type == ELLIPSE) {
+		r = getfval("ellipsewid") / 2;
+		r2 = getfval("ellipseht") / 2;
+	}
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case RADIUS:
+			r = ap->a_val.f;
+			break;
+		case DIAMETER:
+		case WIDTH:
+			r = ap->a_val.f / 2;
+			break;
+		case HEIGHT:
+			r2 = ap->a_val.f / 2;
+			break;
+		case SAME:
+			r = rad[t];
+			r2 = rad2[t];
+			break;
+		case WITH:
+			with = ap->a_val.i;
+			break;
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case INVIS:
+			battr |= INVIS;
+			break;
+		case NOEDGE:
+			battr |= NOEDGEBIT;
+			break;
+		case DOT:
+		case DASH:
+			battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
+			if (ap->a_sub == DEFAULT)
+				ddval = getfval("dashwid");
+			else
+				ddval = ap->a_val.f;
+			break;
+		case FILL:
+			battr |= FILLBIT;
+			if (ap->a_sub == DEFAULT)
+				fillval = getfval("fillval");
+			else
+				fillval = ap->a_val.f;
+			break;
+		}
+	}
+	if (type == CIRCLE)
+		r2 = r;	/* probably superfluous */
+	if (with) {
+		switch (with) {
+		case NORTH:	ywith = -r2; break;
+		case SOUTH:	ywith = r2; break;
+		case EAST:	xwith = -r; break;
+		case WEST:	xwith = r; break;
+		case NE:	xwith = -r * 0.707; ywith = -r2 * 0.707; break;
+		case SE:	xwith = -r * 0.707; ywith = r2 * 0.707; break;
+		case NW:	xwith = r * 0.707; ywith = -r2 * 0.707; break;
+		case SW:	xwith = r * 0.707; ywith = r2 * 0.707; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += r;
+		else if (isleft(hvmode))
+			curx -= r;
+		else if (isup(hvmode))
+			cury += r2;
+		else
+			cury -= r2;
+	}
+	p = makenode(type, 2);
+	p->o_val[0] = rad[t] = r;
+	p->o_val[1] = rad2[t] = r2;
+	if (r <= 0 || r2 <= 0) {
+		ERROR "%s has invalid radius %g\n", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2 WARNING;
+	}
+	p->o_attr = battr;
+	p->o_ddval = ddval;
+	p->o_fillval = fillval;
+	extreme(curx+r, cury+r2);
+	extreme(curx-r, cury-r2);
+	if (type == CIRCLE)
+		dprintf("C %g %g %g\n", curx, cury, r);
+	if (type == ELLIPSE)
+		dprintf("E %g %g %g %g\n", curx, cury, r, r2);
+	if (isright(hvmode))
+		curx += r;
+	else if (isleft(hvmode))
+		curx -= r;
+	else if (isup(hvmode))
+		cury += r2;
+	else
+		cury -= r2;
+	return(p);
+}
blob - /dev/null
blob + cece48b573589ae5db4c4e9c3b990fa1fa939332 (mode 644)
--- /dev/null
+++ src/cmd/pic/for.c
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "pic.h"
+#include "y.tab.h"
+
+#define	SLOP	1.001
+
+typedef struct {
+	char	*var;	/* index variable */
+	double	to;	/* limit */
+	double	by;
+	int	op;	/* operator */
+	char	*str;	/* string to push back */
+} For;
+
+For	forstk[10];	/* stack of for loops */
+For	*forp = forstk;	/* pointer to current top */
+
+void	setfval(char *, double);
+void	nextfor(void);
+
+void forloop(char *var, double from, double to, int op,
+	double by, char *str)	/* set up a for loop */
+{
+	dprintf("# for %s from %g to %g by %c %g \n",
+		var, from, to, op, by);
+	if (++forp >= forstk+10)
+		ERROR "for loop nested too deep" FATAL;
+	forp->var = var;
+	forp->to = to;
+	forp->op = op;
+	forp->by = by;
+	forp->str = str;
+	setfval(var, from);
+	nextfor();
+	unput('\n');
+}
+
+void nextfor(void)	/* do one iteration of a for loop */
+{
+	/* BUG:  this should depend on op and direction */
+	if (getfval(forp->var) > SLOP * forp->to) {	/* loop is done */
+		free(forp->str);
+		if (--forp < forstk)
+			ERROR "forstk popped too far" FATAL;
+	} else {		/* another iteration */
+		pushsrc(String, "\nEndfor\n");
+		pushsrc(String, forp->str);
+	}
+}
+
+void endfor(void)	/* end one iteration of for loop */
+{
+	struct symtab *p = lookup(forp->var);
+
+	switch (forp->op) {
+	case '+':
+	case ' ':
+		p->s_val.f += forp->by;
+		break;
+	case '-':
+		p->s_val.f -= forp->by;
+		break;
+	case '*':
+		p->s_val.f *= forp->by;
+		break;
+	case '/':
+		p->s_val.f /= forp->by;
+		break;
+	}
+	nextfor();
+}
+
+char *ifstat(double expr, char *thenpart, char *elsepart)
+{
+	dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : "");
+	if (expr) {
+		unput('\n');
+		pushsrc(Free, thenpart);
+		pushsrc(String, thenpart);
+		unput('\n');
+  		if (elsepart)
+			free(elsepart);
+		return thenpart;	/* to be freed later */
+	} else {
+		free(thenpart);
+		if (elsepart) {
+			unput('\n');
+			pushsrc(Free, elsepart);
+			pushsrc(String, elsepart);
+			unput('\n');
+		}
+		return elsepart;
+	}
+}
blob - /dev/null
blob + 875b1868a7838074048ffd5b4d7b883786a38626 (mode 644)
--- /dev/null
+++ src/cmd/pic/input.c
@@ -0,0 +1,593 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include "pic.h"
+#include "y.tab.h"
+
+Infile	infile[10];
+Infile	*curfile = infile;
+
+#define	MAXSRC	50
+Src	src[MAXSRC];	/* input source stack */
+Src	*srcp	= src;
+
+void	do_thru(void);
+int	nextchar(void);
+int	getarg(char *);
+void	freedef(char *);
+int	baldelim(int, char *);
+
+void pushsrc(int type, char *ptr)	/* new input source */
+{
+	if (++srcp >= src + MAXSRC)
+		ERROR "inputs nested too deep" FATAL;
+	srcp->type = type;
+	srcp->sp = ptr;
+	if (dbg > 1) {
+		printf("\n%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("push file %s\n", ((Infile *)ptr)->fname);
+			break;
+		case Macro:
+			printf("push macro <%s>\n", ptr);
+			break;
+		case Char:
+			printf("push char <%c>\n", *ptr);
+			break;
+		case Thru:
+			printf("push thru\n");
+			break;
+		case String:
+			printf("push string <%s>\n", ptr);
+			break;
+		case Free:
+			printf("push free <%s>\n", ptr);
+			break;
+		default:
+			ERROR "pushed bad type %d", srcp->type FATAL;
+		}
+	}
+}
+
+void popsrc(void)	/* restore an old one */
+{
+	if (srcp <= src)
+		ERROR "too many inputs popped" FATAL;
+	if (dbg > 1) {
+		printf("%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("pop file\n");
+			break;
+		case Macro:
+			printf("pop macro\n");
+			break;
+		case Char:
+			printf("pop char <%c>\n", *srcp->sp);
+			break;
+		case Thru:
+			printf("pop thru\n");
+			break;
+		case String:
+			printf("pop string\n");
+			break;
+		case Free:
+			printf("pop free\n");
+			break;
+		default:
+			ERROR "pop weird input %d", srcp->type FATAL;
+		}
+	}
+	srcp--;
+}
+
+void definition(char *s)	/* collect definition for s and install */
+				/* definitions picked up lexically */
+{
+	char *p;
+	struct symtab *stp;
+
+	p = delimstr("definition");
+	stp = lookup(s);
+	if (stp != NULL) {	/* it's there before */
+		if (stp->s_type != DEFNAME) {
+			ERROR "%s used as variable and definition", s WARNING;
+			return;
+		}
+		free(stp->s_val.p);
+		stp->s_val.p = p;
+	} else {
+		YYSTYPE u;
+		u.p = p;
+		makevar(tostring(s), DEFNAME, u);
+	}
+	dprintf("installing %s as `%s'\n", s, p);
+}
+
+char *delimstr(char *s)	/* get body of X ... X */
+				/* message if too big */
+{
+	int c, delim, rdelim, n, deep;
+	static char *buf = NULL;
+	static int nbuf = 0;
+	char *p;
+
+	if (buf == NULL)
+		buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
+	while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
+		;
+	rdelim = baldelim(delim, "{}");		/* could be "(){}[]`'" */
+	deep = 1;
+	for (p = buf; ; ) {
+		c = input();
+		if (c == rdelim)
+			if (--deep == 0)
+				break;
+		if (c == delim)
+			deep++;
+		if (p >= buf + nbuf) {
+			n = p - buf;
+			buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
+			p = buf + n;
+		}
+		if (c == EOF)
+			ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
+		*p++ = c;
+	}
+	*p = '\0';
+	dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
+	return tostring(buf);
+}
+
+baldelim(int c, char *s)	/* replace c by balancing entry in s */
+{
+	for ( ; *s; s += 2)
+		if (*s == c)
+			return s[1];
+	return c;
+}
+
+void undefine(char *s)	/* undefine macro */
+{
+	while (*s != ' ' && *s != '\t')		/* skip "undef..." */
+		s++;
+	while (*s == ' ' || *s == '\t')
+		s++;
+	freedef(s);
+}
+
+
+Arg	args[10];	/* argument frames */
+Arg	*argfp = args;	/* frame pointer */
+int	argcnt;		/* number of arguments seen so far */
+
+void dodef(struct symtab *stp)	/* collect args and switch input to defn */
+{
+	int i, len;
+	char *p;
+	Arg *ap;
+
+	ap = argfp+1;
+	if (ap >= args+10)
+		ERROR "arguments too deep" FATAL;
+	argcnt = 0;
+	if (input() != '(')
+		ERROR "disaster in dodef" FATAL;
+	if (ap->argval == 0)
+		ap->argval = malloc(1000);
+	for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
+		ap->argstk[argcnt++] = p;
+		if (input() == ')')
+			break;
+	}
+	for (i = argcnt; i < MAXARGS; i++)
+		ap->argstk[i] = "";
+	if (dbg)
+		for (i = 0; i < argcnt; i++)
+			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
+	argfp = ap;
+	pushsrc(Macro, stp->s_val.p);
+}
+
+getarg(char *p)	/* pick up single argument, store in p, return length */
+{
+	int n, c, npar;
+
+	n = npar = 0;
+	for ( ;; ) {
+		c = input();
+		if (c == EOF)
+			ERROR "end of file in getarg" FATAL;
+		if (npar == 0 && (c == ',' || c == ')'))
+			break;
+		if (c == '"')	/* copy quoted stuff intact */
+			do {
+				*p++ = c;
+				n++;
+			} while ((c = input()) != '"' && c != EOF);
+		else if (c == '(')
+			npar++;
+		else if (c == ')')
+			npar--;
+		n++;
+		*p++ = c;
+	}
+	*p = 0;
+	unput(c);
+	return(n + 1);
+}
+
+#define	PBSIZE	2000
+char	pbuf[PBSIZE];		/* pushback buffer */
+char	*pb	= pbuf-1;	/* next pushed back character */
+
+char	ebuf[200];		/* collect input here for error reporting */
+char	*ep	= ebuf;
+
+int	begin	= 0;
+extern	int	thru;
+extern	struct symtab	*thrudef;
+extern	char	*untilstr;
+
+input(void)
+{
+	register int c;
+
+	if (thru && begin) {
+		do_thru();
+		begin = 0;
+	}
+	c = nextchar();
+	if (dbg > 1)
+		printf(" <%c>", c);
+	if (ep >= ebuf + sizeof ebuf)
+		ep = ebuf;
+	return *ep++ = c;
+}
+
+nextchar(void)
+{
+	register int c;
+
+  loop:
+	switch (srcp->type) {
+	case Free:	/* free string */
+		free(srcp->sp);
+		popsrc();
+		goto loop;
+	case Thru:	/* end of pushed back line */
+		begin = 1;
+		popsrc();
+		c = '\n';
+		break;
+	case Char:
+		if (pb >= pbuf) {
+			c = *pb--;
+			popsrc();
+			break;
+		} else {	/* can't happen? */
+			popsrc();
+			goto loop;
+		}
+	case String:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			popsrc();
+			goto loop;
+		} else {
+			if (*srcp->sp == '\0')	/* empty, so pop */
+				popsrc();
+			break;
+		}
+	case Macro:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			if (--argfp < args)
+				ERROR "argfp underflow" FATAL;
+			popsrc();
+			goto loop;
+		} else if (c == '$' && isdigit(*srcp->sp)) {
+			int n = 0;
+			while (isdigit(*srcp->sp))
+				n = 10 * n + *srcp->sp++ - '0';
+			if (n > 0 && n <= MAXARGS)
+				pushsrc(String, argfp->argstk[n-1]);
+			goto loop;
+		}
+		break;
+	case File:
+		c = getc(curfile->fin);
+		if (c == EOF) {
+			if (curfile == infile)
+				ERROR "end of file inside .PS/.PE" FATAL;
+			if (curfile->fin != stdin) {
+				fclose(curfile->fin);
+				free(curfile->fname);	/* assumes allocated */
+			}
+			curfile--;
+			printlf(curfile->lineno, curfile->fname);
+			popsrc();
+			thru = 0;	/* chicken out */
+			thrudef = 0;
+			if (untilstr) {
+				free(untilstr);
+				untilstr = 0;
+			}
+			goto loop;
+		}
+		if (c == '\n')
+			curfile->lineno++;
+		break;
+	}
+	return c;
+}
+
+void do_thru(void)	/* read one line, make into a macro expansion */
+{
+	int c, i;
+	char *p;
+	Arg *ap;
+
+	ap = argfp+1;
+	if (ap >= args+10)
+		ERROR "arguments too deep" FATAL;
+	if (ap->argval == NULL)
+		ap->argval = malloc(1000);
+	p = ap->argval;
+	argcnt = 0;
+	c = nextchar();
+	if (thru == 0) {	/* end of file was seen, so thru is done */
+		unput(c);
+		return;
+	}
+	for ( ; c != '\n' && c != EOF; ) {
+		if (c == ' ' || c == '\t') {
+			c = nextchar();
+			continue;
+		}
+		ap->argstk[argcnt++] = p;
+		if (c == '"') {
+			do {
+				*p++ = c;
+				if ((c = nextchar()) == '\\') {
+					*p++ = c;
+					*p++ = nextchar();
+					c = nextchar();
+				}
+			} while (c != '"' && c != '\n' && c != EOF);
+			*p++ = '"';
+			if (c == '"')
+				c = nextchar();
+		} else {
+			do {
+				*p++ = c;
+			} while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
+			if (c == ',')
+				c = nextchar();
+		}
+		*p++ = '\0';
+	}
+	if (c == EOF)
+		ERROR "unexpected end of file in do_thru" FATAL;
+	if (argcnt == 0) {	/* ignore blank line */
+		pushsrc(Thru, (char *) 0);
+		return;
+	}
+	for (i = argcnt; i < MAXARGS; i++)
+		ap->argstk[i] = "";
+	if (dbg)
+		for (i = 0; i < argcnt; i++)
+			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
+	if (strcmp(ap->argstk[0], ".PE") == 0) {
+		thru = 0;
+		thrudef = 0;
+		pushsrc(String, "\n.PE\n");
+		return;
+	}
+	if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
+		thru = 0;
+		thrudef = 0;
+		free(untilstr);
+		untilstr = 0;
+		return;
+	}
+	pushsrc(Thru, (char *) 0);
+	dprintf("do_thru pushing back <%s>\n", thrudef->s_val.p);
+	argfp = ap;
+	pushsrc(Macro, thrudef->s_val.p);
+}
+
+unput(int c)
+{
+	if (++pb >= pbuf + sizeof pbuf)
+		ERROR "pushback overflow" FATAL;
+	if (--ep < ebuf)
+		ep = ebuf + sizeof(ebuf) - 1;
+	*pb = c;
+	pushsrc(Char, pb);
+	return c;
+}
+
+void pbstr(char *s)
+{
+	pushsrc(String, s);
+}
+
+double errcheck(double x, char  *s)
+{
+	extern int errno;
+
+	if (errno == EDOM) {
+		errno = 0;
+		ERROR "%s argument out of domain", s WARNING;
+	} else if (errno == ERANGE) {
+		errno = 0;
+		ERROR "%s result out of range", s WARNING;
+	}
+	return x;
+}
+
+char	errbuf[200];
+
+void	eprint(void);
+
+void yyerror(char *s)
+{
+	extern char *cmdname;
+	int ern = errno;	/* cause some libraries clobber it */
+
+	if (synerr)
+		return;
+	fflush(stdout);
+	fprintf(stderr, "%s: %s", cmdname, s);
+	if (ern > 0) {
+		errno = ern;
+		perror("???");
+	}
+	fprintf(stderr, " near %s:%d\n",
+		curfile->fname, curfile->lineno+1);
+	eprint();
+	synerr = 1;
+	errno = 0;
+}
+
+void eprint(void)	/* try to print context around error */
+{
+	char *p, *q;
+
+	p = ep - 1;
+	if (p > ebuf && *p == '\n')
+		p--;
+	for ( ; p >= ebuf && *p != '\n'; p--)
+		;
+	while (*p == '\n')
+		p++;
+	fprintf(stderr, " context is\n\t");
+	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
+		;
+	while (p < q)
+		putc(*p++, stderr);
+	fprintf(stderr, " >>> ");
+	while (p < ep)
+		putc(*p++, stderr);
+	fprintf(stderr, " <<< ");
+	while (pb >= pbuf)
+		putc(*pb--, stderr);
+	fgets(ebuf, sizeof ebuf, curfile->fin);
+	fprintf(stderr, "%s", ebuf);
+	pbstr("\n.PE\n");	/* safety first */
+	ep = ebuf;
+}
+
+void yywrap(void) {}
+
+char	*newfile = 0;		/* filename for file copy */
+char	*untilstr = 0;		/* string that terminates a thru */
+int	thru	= 0;		/* 1 if copying thru macro */
+struct symtab	*thrudef = 0;		/* macro being used */
+
+void copyfile(char *s)	/* remember file to start reading from */
+{
+	newfile = s;
+}
+
+void copydef(struct symtab *p)	/* remember macro symtab ptr */
+{
+	thrudef = p;
+}
+
+struct symtab *copythru(char *s)	/* collect the macro name or body for thru */
+{
+	struct symtab *p;
+	char *q, *addnewline(char *);
+
+	p = lookup(s);
+	if (p != NULL) {
+		if (p->s_type == DEFNAME) {
+			p->s_val.p = addnewline(p->s_val.p);
+			return p;
+		} else
+			ERROR "%s used as define and name", s FATAL;
+	}
+	/* have to collect the definition */
+	pbstr(s);	/* first char is the delimiter */
+	q = delimstr("thru body");
+	s = "nameless";
+	p = lookup(s);
+	if (p != NULL) {
+		if (p->s_val.p)
+			free(p->s_val.p);
+		p->s_val.p = q;
+	} else {
+		YYSTYPE u;
+		u.p = q;
+		p = makevar(tostring(s), DEFNAME, u);
+	}
+	p->s_val.p = addnewline(p->s_val.p);
+	dprintf("installing %s as `%s'\n", s, p->s_val.p);
+	return p;
+}
+
+char *addnewline(char *p)	/* add newline to end of p */
+{
+	int n;
+
+	n = strlen(p);
+	if (p[n-1] != '\n') {
+		p = realloc(p, n+2);
+		p[n] = '\n';
+		p[n+1] = '\0';
+	}
+	return p;
+}
+
+void copyuntil(char *s)	/* string that terminates a thru */
+{
+	untilstr = s;
+}
+
+void copy(void)	/* begin input from file, etc. */
+{
+	FILE *fin;
+
+	if (newfile) {
+		if ((fin = fopen(newfile, "r")) == NULL)
+			ERROR "can't open file %s", newfile FATAL;
+		curfile++;
+		curfile->fin = fin;
+		curfile->fname = newfile;
+		curfile->lineno = 0;
+		printlf(1, curfile->fname);
+		pushsrc(File, curfile->fname);
+		newfile = 0;
+	}
+	if (thrudef) {
+		thru = 1;
+		begin = 1;	/* wrong place */
+	}
+}
+
+char	shellbuf[1000], *shellp;
+
+void shell_init(void)	/* set up to interpret a shell command */
+{
+	sprintf(shellbuf, "rc -c '");
+	shellp = shellbuf + strlen(shellbuf);
+}
+
+void shell_text(char *s)	/* add string to command being collected */
+{
+	while (*shellp++ = *s++)
+		;
+	shellp--;
+}
+
+void shell_exec(void)	/* do it */
+{
+	*shellp++ = '\'';
+	*shellp = '\0';
+	system(shellbuf);
+}
blob - /dev/null
blob + eab268f5c4b14124d35f83a564ab36adf2657d63 (mode 644)
--- /dev/null
+++ src/cmd/pic/linegen.c
@@ -0,0 +1,240 @@
+#include <stdio.h>
+#include <math.h>
+#include "pic.h"
+#include "y.tab.h"
+
+obj *linegen(int type)
+{
+	static double prevdx = HT;
+	static double prevdy = 0;
+	static double prevw = HT10;
+	static double prevh = HT5;
+	int i, j, some, head, ddtype, invis, chop, battr, with;
+	double ddval, chop1, chop2, x0, y0, x1, y1;
+	double fillval = 0;
+	double theta;
+	double defx, defy, xwith, ywith;
+	obj *p, *ppos;
+	static int xtab[] = { 1, 0, -1, 0 };	/* R=0, U=1, L=2, D=3 */
+	static int ytab[] = { 0, 1, 0, -1 };
+	double dx[500], dy[500];
+	int ndxy;
+	double nx, ny;
+	Attr *ap, *chop_ap[4];
+
+	nx = curx;
+	ny = cury;
+	defx = getfval("linewid");
+	defy = getfval("lineht");
+	prevh = getfval("arrowht");
+	prevw = getfval("arrowwid");
+	dx[0] = dy[0] = ndxy = some = head = invis = battr = with = 0;
+	chop = chop1 = chop2 = 0;
+	ddtype = ddval = xwith = ywith = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case HEAD:
+			head += ap->a_val.i;
+			break;
+		case INVIS:
+			invis = INVIS;
+			break;
+		case NOEDGE:
+			battr |= NOEDGEBIT;
+			break;
+		case DOT:
+		case DASH:
+			ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT;
+			if (ap->a_sub == DEFAULT)
+				ddval = getfval("dashwid");
+			else
+				ddval = ap->a_val.f;
+			break;
+		case SAME:
+			dx[ndxy] = prevdx;
+			dy[ndxy] = prevdy;
+			some++;
+			break;
+		case LEFT:
+			dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = L_DIR;
+			break;
+		case RIGHT:
+			dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = R_DIR;
+			break;
+		case UP:
+			dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = U_DIR;
+			break;
+		case DOWN:
+			dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = D_DIR;
+			break;
+		case HEIGHT:	/* length of arrowhead */
+			prevh = ap->a_val.f;
+			break;
+		case WIDTH:	/* width of arrowhead */
+			prevw = ap->a_val.f;
+			break;
+		case TO:
+			if (some) {
+				nx += dx[ndxy];
+				ny += dy[ndxy];
+				ndxy++;
+				dx[ndxy] = dy[ndxy] = some = 0;
+			}
+			ppos = attr[i].a_val.o;
+			dx[ndxy] = ppos->o_x - nx;
+			dy[ndxy] = ppos->o_y - ny;
+			some++;
+			break;
+		case BY:
+			if (some) {
+				nx += dx[ndxy];
+				ny += dy[ndxy];
+				ndxy++;
+				dx[ndxy] = dy[ndxy] = some = 0;
+			}
+			ppos = ap->a_val.o;
+			dx[ndxy] = ppos->o_x;
+			dy[ndxy] = ppos->o_y;
+			some++;
+			break;
+		case THEN:	/* turn off any previous accumulation */
+			if (some) {
+				nx += dx[ndxy];
+				ny += dy[ndxy];
+				ndxy++;
+				dx[ndxy] = dy[ndxy] = some = 0;
+			}
+			break;
+		case FROM:
+		case AT:
+			ppos = ap->a_val.o;
+			nx = curx = ppos->o_x;
+			ny = cury = ppos->o_y;
+			break;
+		case WITH:
+			with = ap->a_val.i;
+			break;
+		case CHOP:
+			if (ap->a_sub != PLACENAME) {
+				if( chop == 0)
+					chop1 = chop2 = ap->a_val.f;
+				else
+					chop2 = ap->a_val.f;
+			}
+			chop_ap[chop++] = ap;
+			break;
+		case FILL:
+			battr |= FILLBIT;
+			if (ap->a_sub == DEFAULT)
+				fillval = getfval("fillval");
+			else
+				fillval = ap->a_val.f;
+			break;
+		}
+	}
+	if (with) {	/* this doesn't work at all */
+		switch (with) {
+		case CENTER:
+			xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break;
+		}
+		for (i = 0; i < ndxy; i++) {
+			dx[i] -= xwith;
+			dy[i] -= ywith;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (some) {
+		nx += dx[ndxy];
+		ny += dy[ndxy];
+		ndxy++;
+		defx = dx[ndxy-1];
+		defy = dy[ndxy-1];
+	} else {
+		defx *= xtab[hvmode];
+		defy *= ytab[hvmode];
+		dx[ndxy] = defx;
+		dy[ndxy] = defy;
+		ndxy++;
+		nx += defx;
+		ny += defy;
+	}
+	prevdx = defx;
+	prevdy = defy;
+	if (chop) {
+		if (chop == 1 && chop1 == 0)	/* just said "chop", so use default */
+			chop1 = chop2 = getfval("circlerad");
+		theta = atan2(dy[0], dx[0]);
+		x0 = chop1 * cos(theta);
+		y0 = chop1 * sin(theta);
+		curx += x0;
+		cury += y0;
+		dx[0] -= x0;
+		dy[0] -= y0;
+
+		theta = atan2(dy[ndxy-1], dx[ndxy-1]);
+		x1 = chop2 * cos(theta);
+		y1 = chop2 * sin(theta);
+		nx -= x1;
+		ny -= y1;
+		dx[ndxy-1] -= x1;
+		dy[ndxy-1] -= y1;
+		dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n",
+			x0, y0, x1, y1, curx, cury, nx, ny);
+	}
+	p = makenode(type, 5 + 2 * ndxy);
+	curx = p->o_val[0] = nx;
+	cury = p->o_val[1] = ny;
+	if (head || type == ARROW) {
+		p->o_nhead = getfval("arrowhead");
+		p->o_val[2] = prevw;
+		p->o_val[3] = prevh;
+		if (head == 0)
+			head = HEAD2;	/* default arrow head */
+	}
+	p->o_attr = head | invis | ddtype | battr;
+	p->o_fillval = fillval;
+	p->o_val[4] = ndxy;
+	nx = p->o_x;
+	ny = p->o_y;
+	for (i = 0, j = 5; i < ndxy; i++, j += 2) {
+		p->o_val[j] = dx[i];
+		p->o_val[j+1] = dy[i];
+		if (type == LINE || type == ARROW)
+			extreme(nx += dx[i], ny += dy[i]);
+		else if (type == SPLINE && i < ndxy-1) {
+			/* to compute approx extreme of spline at p,
+			/* compute midway between p-1 and p+1,
+			/* then go 3/4 from there to p */
+			double ex, ey, xi, yi, xi1, yi1;
+			xi = nx + dx[i]; yi = ny + dy[i];	/* p */
+			xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1];	/* p+1 */
+			ex = (nx+xi1)/2; ey = (ny+yi1)/2;	/* midway */
+			ex += 0.75*(xi-ex); ey += 0.75*(yi-ey);
+			extreme(ex, ey);
+			nx = xi; ny = yi;
+		}
+			
+	}
+	p->o_ddval = ddval;
+	if (dbg) {
+		printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy);
+		for (i = 0, j = 5; i < ndxy; i++, j += 2)
+			printf("%g %g\n", p->o_val[j], p->o_val[j+1]);
+	}
+	extreme(p->o_x, p->o_y);
+	extreme(curx, cury);
+	return(p);
+}
blob - /dev/null
blob + ab9966503475b451b9dd675433f397e3c6e9eab1 (mode 644)
--- /dev/null
+++ src/cmd/pic/main.c
@@ -0,0 +1,282 @@
+#include	<stdio.h>
+#include	<signal.h>
+#include	<stdlib.h>
+#include	<string.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+char	*version = "version July 5, 1993";
+
+obj	**objlist = 0;		/* store the elements here */
+int	nobjlist = 0;		/* size of objlist array */
+int	nobj	= 0;
+
+Attr	*attr;	/* attributes stored here as collected */
+int	nattrlist = 0;
+int	nattr	= 0;	/* number of entries in attr_list */
+
+Text	*text	= 0;	/* text strings stored here as collected */
+int	ntextlist = 0;		/* size of text[] array */
+int	ntext	= 0;
+int	ntext1	= 0;	/* record ntext here on entry to each figure */
+
+double	curx	= 0;
+double	cury	= 0;
+
+int	hvmode	= R_DIR;	/* R => join left to right, D => top to bottom, etc. */
+
+int	codegen	= 0;	/* 1=>output for this picture; 0=>no output */
+char	*PEstring;	/* "PS" or "PE" picked up by lexer */
+
+double	deltx	= 6;	/* max x value in output, for scaling */
+double	delty	= 6;	/* max y value in output, for scaling */
+int	dbg	= 0;
+int	lineno	= 0;
+char	*filename	= "-";
+int	synerr	= 0;
+int	anyerr	= 0;	/* becomes 1 if synerr ever 1 */
+char	*cmdname;
+
+double	xmin	= 30000;	/* min values found in actual data */
+double	ymin	= 30000;
+double	xmax	= -30000;	/* max */
+double	ymax	= -30000;
+
+void	fpecatch(int);
+void	getdata(void), setdefaults(void);
+void	setfval(char *, double);
+int	getpid(void);
+
+main(int argc, char *argv[])
+{
+	char buf[20];
+
+	signal(SIGFPE, fpecatch);
+	cmdname = argv[0];
+	while (argc > 1 && *argv[1] == '-') {
+		switch (argv[1][1]) {
+		case 'd':
+			dbg = atoi(&argv[1][2]);
+			if (dbg == 0)
+				dbg = 1;
+			fprintf(stderr, "%s\n", version);
+			break;
+		case 'V':
+			fprintf(stderr, "%s\n", version);
+			return 0;
+		}
+		argc--;
+		argv++;
+	}
+	setdefaults();
+	objlist = (obj **) grow((char *)objlist, "objlist", nobjlist += 1000, sizeof(obj *));
+	text = (Text *) grow((char *)text, "text", ntextlist += 1000, sizeof(Text));
+	attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
+
+	sprintf(buf, "/%d/", getpid());
+	pushsrc(String, buf);
+	definition("pid");
+
+	curfile = infile;
+	pushsrc(File, curfile->fname);
+	if (argc <= 1) {
+		curfile->fin = stdin;
+		curfile->fname = tostring("-");
+		getdata();
+	} else
+		while (argc-- > 1) {
+			if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
+				fprintf(stderr, "%s: can't open %s\n", cmdname, *argv);
+				exit(1);
+			}
+			curfile->fname = tostring(*argv);
+			getdata();
+			fclose(curfile->fin);
+			free(curfile->fname);
+		}
+	return anyerr;
+}
+
+void fpecatch(int n)
+{
+	ERROR "floating point exception %d", n FATAL;
+}
+
+char *grow(char *ptr, char *name, int num, int size)	/* make array bigger */
+{
+	char *p;
+
+	if (ptr == NULL)
+		p = malloc(num * size);
+	else
+		p = realloc(ptr, num * size);
+	if (p == NULL)
+		ERROR "can't grow %s to %d", name, num * size FATAL;
+	return p;
+}
+
+static struct {
+	char *name;
+	double val;
+	short scalable;		/* 1 => adjust when "scale" changes */
+} defaults[] ={
+	"scale", SCALE, 1,
+	"lineht", HT, 1,
+	"linewid", HT, 1,
+	"moveht", HT, 1,
+	"movewid", HT, 1,
+	"dashwid", HT10, 1,
+	"boxht", HT, 1,
+	"boxwid", WID, 1,
+	"circlerad", HT2, 1,
+	"arcrad", HT2, 1,
+	"ellipseht", HT, 1,
+	"ellipsewid", WID, 1,
+	"arrowht", HT5, 1,
+	"arrowwid", HT10, 1,
+	"arrowhead", 2, 0,		/* arrowhead style */
+	"textht", 0.0, 1,		/* 6 lines/inch is also a useful value */
+	"textwid", 0.0, 1,
+	"maxpsht", MAXHT, 0,
+	"maxpswid", MAXWID, 0,
+	"fillval", 0.7, 0,		/* gray value for filling boxes */
+	NULL, 0, 0
+};
+
+void setdefaults(void)	/* set default sizes for variables like boxht */
+{
+	int i;
+	YYSTYPE v;
+
+	for (i = 0; defaults[i].name != NULL; i++) {
+		v.f = defaults[i].val;
+		makevar(tostring(defaults[i].name), VARNAME, v);
+	}
+}
+
+void resetvar(void)	/* reset variables listed */
+{
+	int i, j;
+
+	if (nattr == 0) {	/* none listed, so do all */
+		setdefaults();
+		return;
+	}
+	for (i = 0; i < nattr; i++) {
+		for (j = 0; defaults[j].name != NULL; j++)
+			if (strcmp(defaults[j].name, attr[i].a_val.p) == 0) {
+				setfval(defaults[j].name, defaults[j].val);
+				free(attr[i].a_val.p);
+				break;
+			}
+	}
+}
+
+void checkscale(char *s)	/* if s is "scale", adjust default variables */
+{
+	int i;
+	double scale;
+
+	if (strcmp(s, "scale") == 0) {
+		scale = getfval("scale");
+		for (i = 1; defaults[i].name != NULL; i++)
+			if (defaults[i].scalable)
+				setfval(defaults[i].name, defaults[i].val * scale);
+	}
+}
+
+void getdata(void)
+{
+	char *p, buf[1000], buf1[100];
+	int ln;
+	void reset(void), openpl(char *), closepl(char *), print(void);
+	int yyparse(void);
+
+	curfile->lineno = 0;
+	printlf(1, curfile->fname);
+	while (fgets(buf, sizeof buf, curfile->fin) != NULL) {
+		curfile->lineno++;
+		if (*buf == '.' && *(buf+1) == 'P' && *(buf+2) == 'S') {
+			for (p = &buf[3]; *p == ' '; p++)
+				;
+			if (*p++ == '<') {
+				Infile svfile;
+				svfile = *curfile;
+				sscanf(p, "%s", buf1);
+				if ((curfile->fin=fopen(buf1, "r")) == NULL)
+					ERROR "can't open %s", buf1 FATAL;
+				curfile->fname = tostring(buf1);
+				getdata();
+				fclose(curfile->fin);
+				free(curfile->fname);
+				*curfile = svfile;
+				printlf(curfile->lineno, curfile->fname);
+				continue;
+			}
+			reset();
+			yyparse();
+			anyerr += synerr;
+			deltx = (xmax - xmin) / getfval("scale");
+			delty = (ymax - ymin) / getfval("scale");
+			if (buf[3] == ' ') {	/* next things are wid & ht */
+				if (sscanf(&buf[4],"%lf %lf", &deltx, &delty) < 2)
+					delty = deltx * (ymax-ymin) / (xmax-xmin);
+				/* else {
+				/*	double xfac, yfac; */
+				/*	xfac = deltx / (xmax-xmin);
+				/*	yfac = delty / (ymax-ymin);
+				/*	if (xfac <= yfac)
+				/*		delty = xfac * (ymax-ymin);
+				/*	else
+				/*		deltx = yfac * (xmax-xmin);
+				/*}
+				*/
+			}
+			dprintf("deltx = %g, delty = %g\n", deltx, delty);
+			if (codegen && !synerr) {
+				openpl(&buf[3]);	/* puts out .PS, with ht & wid stuck in */
+				printlf(curfile->lineno+1, NULL);
+				print();	/* assumes \n at end */
+				closepl(PEstring);	/* does the .PE/F */
+				free(PEstring);
+			}
+			printlf(curfile->lineno+1, NULL);
+			fflush(stdout);
+		} else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
+			if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
+				free(curfile->fname);
+				printlf(curfile->lineno = ln, curfile->fname = tostring(buf1));
+			} else
+				printlf(curfile->lineno = ln, NULL);
+		} else
+			fputs(buf, stdout);
+	}
+}
+
+void reset(void)
+{
+	obj *op;
+	int i;
+	extern int nstack;
+	extern	void freesymtab(struct symtab *);
+
+	for (i = 0; i < nobj; i++) {
+		op = objlist[i];
+		if (op->o_type == BLOCK)
+			freesymtab(op->o_symtab);
+		free((char *)objlist[i]);
+	}
+	nobj = 0;
+	nattr = 0;
+	for (i = 0; i < ntext; i++)
+		if (text[i].t_val)
+			free(text[i].t_val);
+	ntext = ntext1 = 0;
+	codegen = synerr = 0;
+	nstack = 0;
+	curx = cury = 0;
+	PEstring = 0;
+	hvmode = R_DIR;
+	xmin = ymin = 30000;
+	xmax = ymax = -30000;
+}
blob - /dev/null
blob + 92d733a0143ea2f58543b85ec33a5470b7e12daa (mode 644)
--- /dev/null
+++ src/cmd/pic/makefile
@@ -0,0 +1,39 @@
+CC = cc     # the usual situation
+CFLAGS =    # the usual situation
+
+CC = lcc        # you will probably want to remove this 
+CFLAGS = -g -N -I/usr/include/lcc -I/usr/include       # and this
+
+YFLAGS = -d
+
+OFILES = picl.o main.o print.o misc.o symtab.o blockgen.o boxgen.o \
+	 circgen.o arcgen.o linegen.o movegen.o textgen.o \
+	 input.o for.o pltroff.o $(ALLOC)
+CFILES = main.c print.c misc.c symtab.c blockgen.c boxgen.c circgen.c \
+	 arcgen.c linegen.c movegen.c textgen.c \
+	 input.c for.c pltroff.c
+SRCFILES = picy.y picl.l pic.h $(CFILES) makefile FIXES README PS-PEmacros
+
+pic:	picy.o $(OFILES) pic.h
+	$(CC) $(CFLAGS) picy.o $(OFILES) -lm
+
+$(OFILES):	pic.h prevy.tab.h
+
+picy.o:	pic.h
+
+prevy.tab.h:	y.tab.h
+	-cmp -s y.tab.h prevy.tab.h || cp y.tab.h prevy.tab.h
+
+bundle:
+	@bundle $(SRCFILES) 
+
+bowell:	 $(SRCFILES)  pictest.a 
+	push bowell $? /usr/src/cmd/pic
+	touch bowell
+
+clean:
+	rm *.o a.out *y.tab.h
+
+install:
+	cp a.out /usr/bin/pic
+	strip /usr/bin/pic
blob - /dev/null
blob + 0a33c67229ace61f5e93d95457b8ba0536340b4b (mode 644)
--- /dev/null
+++ src/cmd/pic/misc.c
@@ -0,0 +1,436 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pic.h"
+#include "y.tab.h"
+
+int whatpos(obj *p, int corner, double *px, double *py);
+void makeattr(int type, int sub, YYSTYPE val);
+YYSTYPE getblk(obj *, char *);
+
+setdir(int n)	/* set direction (hvmode) from LEFT, RIGHT, etc. */
+{
+	switch (n) {
+	case UP:	hvmode = U_DIR; break;
+	case DOWN:	hvmode = D_DIR; break;
+	case LEFT:	hvmode = L_DIR; break;
+	case RIGHT:	hvmode = R_DIR; break;
+	}
+ 	return(hvmode);
+}
+
+curdir(void)	/* convert current dir (hvmode) to RIGHT, LEFT, etc. */
+{
+	switch (hvmode) {
+	case R_DIR:	return RIGHT;
+	case L_DIR:	return LEFT;
+	case U_DIR:	return UP;
+	case D_DIR:	return DOWN;
+	}
+	ERROR "can't happen curdir" FATAL;
+	return 0;
+}
+
+double getcomp(obj *p, int t)	/* return component of a position */
+{
+	switch (t) {
+	case DOTX:
+		return p->o_x;
+	case DOTY:
+		return p->o_y;
+	case DOTWID:
+		switch (p->o_type) {
+		case BOX:
+		case BLOCK:
+		case TEXT:
+			return p->o_val[0];
+		case CIRCLE:
+		case ELLIPSE:
+			return 2 * p->o_val[0];
+		case LINE:
+		case ARROW:
+			return p->o_val[0] - p->o_x;
+		case PLACE:
+			return 0;
+		}
+	case DOTHT:
+		switch (p->o_type) {
+		case BOX:
+		case BLOCK:
+		case TEXT:
+			return p->o_val[1];
+		case CIRCLE:
+		case ELLIPSE:
+			return 2 * p->o_val[1];
+		case LINE:
+		case ARROW:
+			return p->o_val[1] - p->o_y;
+		case PLACE:
+			return 0;
+		}
+	case DOTRAD:
+		switch (p->o_type) {
+		case CIRCLE:
+		case ELLIPSE:
+			return p->o_val[0];
+		}
+	}
+	ERROR "you asked for a weird dimension or position" WARNING;
+	return 0;
+}
+
+double	exprlist[100];
+int	nexpr	= 0;
+
+void exprsave(double f)
+{
+	exprlist[nexpr++] = f;
+}
+
+char *sprintgen(char *fmt)
+{
+	char buf[1000];
+
+	sprintf(buf, fmt, exprlist[0], exprlist[1], exprlist[2], exprlist[3], exprlist[4]);
+	nexpr = 0;
+	free(fmt);
+	return tostring(buf);
+}
+
+void makefattr(int type, int sub, double f)	/* double attr */
+{
+	YYSTYPE val;
+	val.f = f;
+	makeattr(type, sub, val);
+}
+
+void makeoattr(int type, obj *o)	/* obj* attr */
+{
+	YYSTYPE val;
+	val.o = o;
+	makeattr(type, 0, val);
+}
+
+void makeiattr(int type, int i)	/* int attr */
+{
+	YYSTYPE val;
+	val.i = i;
+	makeattr(type, 0, val);
+}
+
+void maketattr(int sub, char *p)	/* text attribute: takes two */
+{
+	YYSTYPE val;
+	val.p = p;
+	makeattr(TEXTATTR, sub, val);
+}
+
+void addtattr(int sub)		/* add text attrib to existing item */
+{
+	attr[nattr-1].a_sub |= sub;
+}
+
+void makevattr(char *p)	/* varname attribute */
+{
+	YYSTYPE val;
+	val.p = p;
+	makeattr(VARNAME, 0, val);
+}
+
+void makeattr(int type, int sub, YYSTYPE val)	/* add attribute type and val */
+{
+	if (type == 0 && val.i == 0) {	/* clear table for next stat */
+		nattr = 0;
+		return;
+	}
+	if (nattr >= nattrlist)
+		attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
+	dprintf("attr %d:  %d %d %d\n", nattr, type, sub, val.i);
+	attr[nattr].a_type = type;
+	attr[nattr].a_sub = sub;
+	attr[nattr].a_val = val;
+	nattr++;
+}
+
+void printexpr(double f)	/* print expression for debugging */
+{
+	printf("%g\n", f);
+}
+
+void printpos(obj *p)	/* print position for debugging */
+{
+	printf("%g, %g\n", p->o_x, p->o_y);
+}
+
+char *tostring(char *s)
+{
+	register char *p;
+
+	p = malloc(strlen(s)+1);
+	if (p == NULL)
+		ERROR "out of space in tostring on %s", s FATAL;
+	strcpy(p, s);
+	return(p);
+}
+
+obj *makepos(double x, double y)	/* make a position cell */
+{
+	obj *p;
+
+	p = makenode(PLACE, 0);
+	p->o_x = x;
+	p->o_y = y;
+	return(p);
+}
+
+obj *makebetween(double f, obj *p1, obj *p2)	/* make position between p1 and p2 */
+{
+	obj *p;
+
+	dprintf("fraction = %.2f\n", f);
+	p = makenode(PLACE, 0);
+	p->o_x = p1->o_x + f * (p2->o_x - p1->o_x);
+	p->o_y = p1->o_y + f * (p2->o_y - p1->o_y);
+	return(p);
+}
+
+obj *getpos(obj *p, int corner)	/* find position of point */
+{
+	double x, y;
+
+	whatpos(p, corner, &x, &y);
+	return makepos(x, y);
+}
+
+int whatpos(obj *p, int corner, double *px, double *py)	/* what is the position (no side effect) */
+{
+	double x, y, x1, y1;
+
+	dprintf("whatpos %o %d %d\n", p, p->o_type, corner);
+	x = p->o_x;
+	y = p->o_y;
+	if (p->o_type != PLACE && p->o_type != MOVE) {
+		x1 = p->o_val[0];
+		y1 = p->o_val[1];
+	}
+	switch (p->o_type) {
+	case PLACE:
+		break;
+	case BOX:
+	case BLOCK:
+	case TEXT:
+		switch (corner) {
+		case NORTH:	y += y1 / 2; break;
+		case SOUTH:	y -= y1 / 2; break;
+		case EAST:	x += x1 / 2; break;
+		case WEST:	x -= x1 / 2; break;
+		case NE:	x += x1 / 2; y += y1 / 2; break;
+		case SW:	x -= x1 / 2; y -= y1 / 2; break;
+		case SE:	x += x1 / 2; y -= y1 / 2; break;
+		case NW:	x -= x1 / 2; y += y1 / 2; break;
+		case START:
+			if (p->o_type == BLOCK)
+				return whatpos(objlist[(int)p->o_val[2]], START, px, py);
+		case END:
+			if (p->o_type == BLOCK)
+				return whatpos(objlist[(int)p->o_val[3]], END, px, py);
+		}
+		break;
+	case ARC:
+		switch (corner) {
+		case START:
+			if (p->o_attr & CW_ARC) {
+				x = p->o_val[2]; y = p->o_val[3];
+			} else {
+				x = x1; y = y1;
+			}
+			break;
+		case END:
+			if (p->o_attr & CW_ARC) {
+				x = x1; y = y1;
+			} else {
+				x = p->o_val[2]; y = p->o_val[3];
+			}
+			break;
+		}
+		if (corner == START || corner == END)
+			break;
+		x1 = y1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y));
+		/* Fall Through! */
+	case CIRCLE:
+	case ELLIPSE:
+		switch (corner) {
+		case NORTH:	y += y1; break;
+		case SOUTH:	y -= y1; break;
+		case EAST:	x += x1; break;
+		case WEST:	x -= x1; break;
+		case NE:	x += 0.707 * x1; y += 0.707 * y1; break;
+		case SE:	x += 0.707 * x1; y -= 0.707 * y1; break;
+		case NW:	x -= 0.707 * x1; y += 0.707 * y1; break;
+		case SW:	x -= 0.707 * x1; y -= 0.707 * y1; break;
+		}
+		break;
+	case LINE:
+	case SPLINE:
+	case ARROW:
+		switch (corner) {
+		case START:	break;	/* already in place */
+		case END:	x = x1; y = y1; break;
+		default: /* change! */
+		case CENTER:	x = (x+x1)/2; y = (y+y1)/2; break;
+		case NORTH:	if (y1 > y) { x = x1; y = y1; } break;
+		case SOUTH:	if (y1 < y) { x = x1; y = y1; } break;
+		case EAST:	if (x1 > x) { x = x1; y = y1; } break;
+		case WEST:	if (x1 < x) { x = x1; y = y1; } break;
+		}
+		break;
+	case MOVE:
+		/* really ought to be same as line... */
+		break;
+	}
+	dprintf("whatpos returns %g %g\n", x, y);
+	*px = x;
+	*py = y;
+	return 1;
+}
+
+obj *gethere(void)	/* make a place for curx,cury */
+{
+	dprintf("gethere %g %g\n", curx, cury);
+	return(makepos(curx, cury));
+}
+
+obj *getlast(int n, int t)	/* find n-th previous occurrence of type t */
+{
+	int i, k;
+	obj *p;
+
+	k = n;
+	for (i = nobj-1; i >= 0; i--) {
+		p = objlist[i];
+		if (p->o_type == BLOCKEND) {
+			i = p->o_val[4];
+			continue;
+		}
+		if (p->o_type != t)
+			continue;
+		if (--k > 0)
+			continue;	/* not there yet */
+		dprintf("got a last of x,y= %g,%g\n", p->o_x, p->o_y);
+		return(p);
+	}
+	ERROR "there is no %dth last", n FATAL;
+	return(NULL);
+}
+
+obj *getfirst(int n, int t)	/* find n-th occurrence of type t */
+{
+	int i, k;
+	obj *p;
+
+	k = n;
+	for (i = 0; i < nobj; i++) {
+		p = objlist[i];
+		if (p->o_type == BLOCK && t != BLOCK) {	/* skip whole block */
+			i = p->o_val[5] + 1;
+			continue;
+		}
+		if (p->o_type != t)
+			continue;
+		if (--k > 0)
+			continue;	/* not there yet */
+		dprintf("got a first of x,y= %g,%g\n", p->o_x, p->o_y);
+		return(p);
+	}
+	ERROR "there is no %dth ", n FATAL;
+	return(NULL);
+}
+
+double getblkvar(obj *p, char *s)	/* find variable s2 in block p */
+{
+	YYSTYPE y;
+
+	y = getblk(p, s);
+	return y.f;
+}
+
+obj *getblock(obj *p, char *s)	/* find variable s in block p */
+{
+	YYSTYPE y;
+
+	y = getblk(p, s);
+	return y.o;
+}
+
+YYSTYPE getblk(obj *p, char *s)	/* find union type for s in p */
+{
+	static YYSTYPE bug;
+	struct symtab *stp;
+
+	if (p->o_type != BLOCK) {
+		ERROR ".%s is not in that block", s WARNING;
+		return(bug);
+	}
+	for (stp = p->o_symtab; stp != NULL; stp = stp->s_next)
+		if (strcmp(s, stp->s_name) == 0) {
+			dprintf("getblk %s found x,y= %g,%g\n",
+				s, (stp->s_val.o)->o_x, (stp->s_val.o)->o_y);
+			return(stp->s_val);
+		}
+	ERROR "there is no .%s in that []", s WARNING;
+	return(bug);
+}
+
+obj *fixpos(obj *p, double x, double y)
+{
+	dprintf("fixpos returns %g %g\n", p->o_x + x, p->o_y + y);
+	return makepos(p->o_x + x, p->o_y + y);
+}
+
+obj *addpos(obj *p, obj *q)
+{
+	dprintf("addpos returns %g %g\n", p->o_x+q->o_x, p->o_y+q->o_y);
+	return makepos(p->o_x+q->o_x, p->o_y+q->o_y);
+}
+
+obj *subpos(obj *p, obj *q)
+{
+	dprintf("subpos returns %g %g\n", p->o_x-q->o_x, p->o_y-q->o_y);
+	return makepos(p->o_x-q->o_x, p->o_y-q->o_y);
+}
+
+obj *makenode(int type, int n)
+{
+	obj *p;
+
+	p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(ofloat));
+	if (p == NULL)
+		ERROR "out of space in makenode" FATAL;
+	p->o_type = type;
+	p->o_count = n;
+	p->o_nobj = nobj;
+	p->o_mode = hvmode;
+	p->o_x = curx;
+	p->o_y = cury;
+	p->o_nt1 = ntext1;
+	p->o_nt2 = ntext;
+	ntext1 = ntext;	/* ready for next caller */
+	if (nobj >= nobjlist)
+		objlist = (obj **) grow((char *) objlist, "objlist",
+			nobjlist *= 2, sizeof(obj *));
+	objlist[nobj++] = p;
+	return(p);
+}
+
+void extreme(double x, double y)	/* record max and min x and y values */
+{
+	if (x > xmax)
+		xmax = x;
+	if (y > ymax)
+		ymax = y;
+	if (x < xmin)
+		xmin = x;
+	if (y < ymin)
+		ymin = y;
+}
blob - /dev/null
blob + b27e07db67680144a69093106f84285e7042053a (mode 644)
--- /dev/null
+++ src/cmd/pic/mkfile
@@ -0,0 +1,38 @@
+<$PLAN9/src/mkhdr
+
+TARG=pic
+OFILES=picy.$O\
+	picl.$O\
+	main.$O\
+	print.$O\
+	misc.$O\
+	symtab.$O\
+	blockgen.$O\
+	boxgen.$O\
+	circgen.$O\
+	arcgen.$O\
+	linegen.$O\
+	movegen.$O\
+	textgen.$O\
+	input.$O\
+	for.$O\
+	pltroff.$O\
+
+HFILES=pic.h\
+	y.tab.h\
+
+YFILES=picy.y\
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
+YFLAGS=-S -d
+LEX=9lex
+
+picy.c:	y.tab.c
+	mv $prereq $target
+
+picl.c:	picl.lx
+	$LEX -t $prereq > $target
+
+clean:V:
+	rm -f *.[$OS] [$OS].out y.tab.? y.debug $TARG picy.c picl.c
blob - /dev/null
blob + 5ff44d46b01dcca94e57d5a0f90faa83b78b043d (mode 644)
--- /dev/null
+++ src/cmd/pic/movegen.c
@@ -0,0 +1,86 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj *movegen(void)
+{
+	static double prevdx, prevdy;
+	int i, some;
+	double defx, defy, dx, dy;
+	obj *p;
+	obj *ppos;
+	static int xtab[] = { 1, 0, -1, 0 };	/* R=0, U=1, L=2, D=3 */
+	static int ytab[] = { 0, 1, 0, -1 };
+	Attr *ap;
+
+	defx = getfval("movewid");
+	defy = getfval("moveht");
+	dx = dy = some = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case SAME:
+			dx = prevdx;
+			dy = prevdy;
+			some++;
+			break;
+		case LEFT:
+			dx -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = L_DIR;
+			break;
+		case RIGHT:
+			dx += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = R_DIR;
+			break;
+		case UP:
+			dy += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = U_DIR;
+			break;
+		case DOWN:
+			dy -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = D_DIR;
+			break;
+		case TO:
+			ppos = ap->a_val.o;
+			dx = ppos->o_x - curx;
+			dy = ppos->o_y - cury;
+			some++;
+			break;
+		case BY:
+			ppos = ap->a_val.o;
+			dx = ppos->o_x;
+			dy = ppos->o_y;
+			some++;
+			break;
+		case FROM:
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			break;
+		}
+	}
+	if (some) {
+		defx = dx;
+		defy = dy;
+	} else {
+		defx *= xtab[hvmode];
+		defy *= ytab[hvmode];
+	}
+	prevdx = defx;
+	prevdy = defy;
+	extreme(curx, cury);
+	curx += defx;
+	cury += defy;
+	extreme(curx, cury);
+	p = makenode(MOVE, 0);
+	dprintf("M %g %g\n", curx, cury);
+	return(p);
+}
blob - /dev/null
blob + a4f7a6a49284a148f10355e7462832855bdb414c (mode 644)
--- /dev/null
+++ src/cmd/pic/pic.h
@@ -0,0 +1,219 @@
+#ifndef PI
+#define PI 3.1415926535897932384626433832795028841971693993751
+#endif
+
+#define	MAXWID	8.5	/* default limits max picture to 8.5 x 11; */
+#define	MAXHT	11	/* change to taste without peril */
+
+#define	dprintf	if(dbg)printf
+
+extern	void	yyerror(char *);
+
+extern	char	errbuf[200];
+#define	ERROR	sprintf(errbuf,
+#define	FATAL	), yyerror(errbuf), exit(1)
+#define	WARNING	), yyerror(errbuf)
+
+#define	DEFAULT	0
+
+#define	HEAD1	1
+#define	HEAD2	2
+#define	HEAD12	(HEAD1+HEAD2)
+#define	INVIS	4
+#define	CW_ARC	8	/* clockwise arc */
+#define	DOTBIT	16	/* line styles */
+#define	DASHBIT	32
+#define	FILLBIT	64	/* gray-fill on boxes, etc. */
+#define NOEDGEBIT 128	/* no edge on filled object */
+
+#define	CENTER	01	/* text attributes */
+#define	LJUST	02
+#define	RJUST	04
+#define	ABOVE	010
+#define	BELOW	020
+#define	SPREAD	040
+
+#define	SCALE	1.0	/* default scale: units/inch */
+#define	WID	0.75	/* default width for boxes and ellipses */
+#define	WID2	0.375
+#define	HT	0.5	/* default height and line length */
+#define	HT2	(HT/2)
+#define	HT5	(HT/5)
+#define	HT10	(HT/10)
+
+/* these have to be like so, so that we can write */
+/* things like R & V, etc. */
+#define	H	0
+#define	V	1
+#define	R_DIR	0
+#define	U_DIR	1
+#define	L_DIR	2
+#define	D_DIR	3
+#define	ishor(n)	(((n) & V) == 0)
+#define	isvert(n)	(((n) & V) != 0)
+#define	isright(n)	((n) == R_DIR)
+#define	isleft(n)	((n) == L_DIR)
+#define	isdown(n)	((n) == D_DIR)
+#define	isup(n)		((n) == U_DIR)
+
+typedef	float	ofloat;	/* for o_val[] in obj;  could be double */
+
+typedef struct obj {	/* stores various things in variable length */
+	int	o_type;
+	int	o_count;	/* number of things */
+	int	o_nobj;		/* index in objlist */
+	int	o_mode;		/* hor or vert */
+	float	o_x;		/* coord of "center" */
+	float	o_y;
+	int	o_nt1;		/* 1st index in text[] for this object */
+	int	o_nt2;		/* 2nd; difference is #text strings */
+	int	o_attr;		/* HEAD, CW, INVIS, etc., go here */
+	int	o_size;		/* linesize */
+	int	o_nhead;	/* arrowhead style */
+	struct symtab *o_symtab; /* symtab for [...] */
+	float	o_ddval;	/* value of dot/dash expression */
+	float	o_fillval;	/* gray scale value */
+	ofloat	o_val[1];	/* actually this will be > 1 in general */
+				/* type is not always FLOAT!!!! */
+} obj;
+
+typedef union {		/* the yacc stack type */
+	int	i;
+	char	*p;
+	obj	*o;
+	double	f;
+	struct symtab *st;
+} YYSTYPE;
+
+extern	YYSTYPE	yylval, yyval;
+
+struct symtab {
+	char	*s_name;
+	int	s_type;
+	YYSTYPE	s_val;
+	struct symtab *s_next;
+};
+
+typedef struct {	/* attribute of an object */
+	int	a_type;
+	int	a_sub;
+	YYSTYPE	a_val;
+} Attr;
+
+typedef struct {
+	int	t_type;		/* CENTER, LJUST, etc. */
+	char	t_op;		/* optional sign for size changes */
+	char	t_size;		/* size, abs or rel */
+	char	*t_val;
+} Text;
+
+#define	String	01
+#define	Macro	02
+#define	File	04
+#define	Char	010
+#define	Thru	020
+#define	Free	040
+
+typedef struct {	/* input source */
+	int	type;	/* Macro, String, File */
+	char	*sp;	/* if String or Macro */
+} Src;
+
+extern	Src	src[], *srcp;	/* input source stack */
+
+typedef struct {
+	FILE	*fin;
+	char	*fname;
+	int	lineno;
+} Infile;
+
+extern	Infile	infile[], *curfile;
+
+#define	MAXARGS	20
+typedef struct {	/* argument stack */
+	char	*argstk[MAXARGS];	/* pointers to args */
+	char	*argval;	/* points to space containing args */
+} Arg;
+
+extern	int	dbg;
+extern	obj	**objlist;
+extern	int	nobj, nobjlist;
+extern	Attr	*attr;
+extern	int	nattr, nattrlist;
+extern	Text	*text;
+extern	int	ntextlist;
+extern	int	ntext;
+extern	int	ntext1;
+extern	double	curx, cury;
+extern	int	hvmode;
+extern	int	codegen;
+extern	char	*PEstring;
+
+char	*tostring(char *);
+char	*grow(char *, char *, int, int);
+double	getfval(char *), getcomp(obj *, int), getblkvar(obj *, char *);
+YYSTYPE	getvar(char *);
+struct	symtab *lookup(char *), *makevar(char *, int, YYSTYPE);
+char	*ifstat(double, char *, char *), *delimstr(char *), *sprintgen(char *);
+void	forloop(char *var, double from, double to, int op, double by, char *_str);
+int	setdir(int), curdir(void);
+void	resetvar(void);
+void	checkscale(char *);
+void	pushsrc(int, char *);
+void	copy(void);
+void	copyuntil(char *);
+void	copyfile(char *);
+void	copydef(struct symtab *);
+void	definition(char *);
+struct symtab *copythru(char *);
+int	input(void);
+int	unput(int);
+void	extreme(double, double);
+
+extern	double	deltx, delty;
+extern	int	lineno;
+extern	int	synerr;
+
+extern	double	xmin, ymin, xmax, ymax;
+
+obj	*leftthing(int), *boxgen(void), *circgen(int), *arcgen(int);
+obj	*linegen(int), *splinegen(void), *movegen(void);
+obj	*textgen(void), *plotgen(void);
+obj	*troffgen(char *), *rightthing(obj *, int), *blockgen(obj *, obj *);
+obj	*makenode(int, int), *makepos(double, double);
+obj	*fixpos(obj *, double, double);
+obj	*addpos(obj *, obj *), *subpos(obj *, obj *);
+obj	*makebetween(double, obj *, obj *);
+obj	*getpos(obj *, int), *gethere(void), *getfirst(int, int);
+obj	*getlast(int, int), *getblock(obj *, char *);
+void	savetext(int, char *);
+void	makeiattr(int, int);
+void	makevattr(char *);
+void	makefattr(int type, int sub, double f);
+void	maketattr(int, char *);
+void	makeoattr(int, obj *);
+void	makeattr(int type, int sub, YYSTYPE val);
+void	printexpr(double);
+void	printpos(obj *);
+void	exprsave(double);
+void	addtattr(int);
+void	printlf(int, char *);
+
+struct pushstack {
+	double	p_x;
+	double	p_y;
+	int	p_hvmode;
+	double	p_xmin;
+	double	p_ymin;
+	double	p_xmax;
+	double	p_ymax;
+	struct symtab *p_symtab;
+};
+extern	struct pushstack stack[];
+extern	int	nstack;
+extern	int	cw;
+
+extern	double	errcheck(double, char *);
+#define	Log10(x) errcheck(log10(x), "log")
+#define	Exp(x)	errcheck(exp(x), "exp")
+#define	Sqrt(x)	errcheck(sqrt(x), "sqrt")
blob - /dev/null
blob + dbe2a3d5c86c3a18b1c66c9383ec360a630d7a22 (mode 644)
--- /dev/null
+++ src/cmd/pic/picl.lx
@@ -0,0 +1,273 @@
+%Start A str def sc br thru sh
+%e 1700
+%k 120
+%a 1800
+%o 1500
+%p 5000
+%n 700
+
+%{
+#undef	input
+#undef	unput
+/* #include <stdio.h> lex puts one out for us */
+#include <ctype.h>
+#include <stdlib.h>
+#include "pic.h"
+#include "y.tab.h"
+
+extern	char	*filename;
+extern	struct	symtab	symtab[];
+
+void	pbstr(char *);
+void	dodef(struct symtab *stp);
+void	undefine(char *s);
+void	shell_init(void), shell_exec(void), shell_text(char *);
+void	endfor(void);
+
+int	yyback(int *, int);
+int	yylook(void);
+int	yywrap(void);
+
+#define	CADD	cbuf[clen++]=yytext[0]; \
+		if (clen>=CBUFLEN-1) { ERROR "string too long", cbuf WARNING; BEGIN A; }
+#define	CBUFLEN	500
+char	cbuf[CBUFLEN];
+int	c, clen, cflag, delim;
+int	ifsw	= 0;	/* 1 if if statement in progress */
+%}
+
+A	[a-zA-Z_]
+B	[a-zA-Z0-9_]
+D	[0-9]
+WS	[ \t]
+
+%%
+	switch (yybgin-yysvec-1) {	/* witchcraft */
+	case 0:
+		BEGIN A;
+		break;
+	case sc:
+		BEGIN A;
+		return('}');
+	case br:
+		BEGIN A;
+		return(']');
+	}
+
+<A>{WS}		;
+<A>"\\"\n	;
+<A>\n		{ return(ST); }
+<A>";"		{ return(ST); }
+<A>"}"		{ BEGIN sc; return(ST); }
+<A>"]"		{ BEGIN br; return(ST); }
+<A>"{"{WS}*(#.*)?\n+	{ return(yylval.i = yytext[0]); }
+
+<A>^".PS".*	{ if (curfile == infile) ERROR ".PS found inside .PS/.PE" WARNING; }
+<A>^".PE".*	{ if (curfile == infile) {
+			yylval.p = PEstring = tostring(yytext);
+			return(EOF);
+		  }
+		}
+<A>^".".*	{ yylval.p = tostring(yytext); return(TROFF); }
+
+<A>print	return(yylval.i = PRINT);
+<A>box		return(yylval.i = BOX);
+<A>circle	return(yylval.i = CIRCLE);
+<A>arc		return(yylval.i = ARC);
+<A>ellipse	return(yylval.i = ELLIPSE);
+<A>arrow	return(yylval.i = ARROW);
+<A>spline	return(yylval.i = SPLINE);
+<A>line		return(yylval.i = LINE);
+<A>move		return(yylval.i = MOVE);
+<A>"[]"		return(yylval.i = BLOCK);
+<A>reset	return(RESET);
+<A>sprintf	return(SPRINTF);
+
+<A>same		return(SAME);
+<A>between	return(BETWEEN);
+<A>and		return(AND);
+
+<A>of		;
+<A>the		;
+<A>way		;
+
+<A>"."(e|east)		{ yylval.i = EAST; return(CORNER); }
+<A>"."(r|right)		{ yylval.i = EAST; return(CORNER); }
+<A>"."(w|west)		{ yylval.i = WEST; return(CORNER); }
+<A>"."(l|left)		{ yylval.i = WEST; return(CORNER); }
+<A>"."(n|north)		{ yylval.i = NORTH; return(CORNER); }
+<A>"."(t|top)		{ yylval.i = NORTH; return(CORNER); }
+<A>"."(s|south)		{ yylval.i = SOUTH; return(CORNER); }
+<A>"."(b|bot|bottom)	{ yylval.i = SOUTH; return(CORNER); }
+<A>"."(c|center)	{ yylval.i = CENTER; return(CORNER); }
+<A>".start"		{ yylval.i = START; return(CORNER); }
+<A>".end"		{ yylval.i = END; return(CORNER); }
+<A>".ne"		{ yylval.i = NE; return(CORNER); }
+<A>".se"		{ yylval.i = SE; return(CORNER); }
+<A>".nw"		{ yylval.i = NW; return(CORNER); }
+<A>".sw"		{ yylval.i = SW; return(CORNER); }
+
+<A>top" "+of		{ yylval.i = NORTH; return(CORNER); }
+<A>north" "+of		{ yylval.i = NORTH; return(CORNER); }
+<A>bottom" "+of		{ yylval.i = SOUTH; return(CORNER); }
+<A>south" "+of		{ yylval.i = SOUTH; return(CORNER); }
+<A>left" "+of		{ yylval.i = WEST; return(CORNER); }
+<A>west" "+of		{ yylval.i = WEST; return(CORNER); }
+<A>right" "+of		{ yylval.i = EAST; return(CORNER); }
+<A>east" "+of		{ yylval.i = EAST; return(CORNER); }
+<A>center" "+of		{ yylval.i = CENTER; return(CORNER); }
+<A>start" "+of		{ yylval.i = START; return(CORNER); }
+<A>end" "+of		{ yylval.i = END; return(CORNER); }
+
+<A>height|ht	{ yylval.i = HEIGHT; return(ATTR); }
+<A>width|wid	{ yylval.i = WIDTH; return(ATTR); }
+<A>radius|rad	{ yylval.i = RADIUS; return(ATTR); }
+<A>diameter|diam { yylval.i = DIAMETER; return(ATTR); }
+<A>size		{ yylval.i = SIZE; return(ATTR); }
+<A>left		{ yylval.i = LEFT; return(DIR); }
+<A>right	{ yylval.i = RIGHT; return(DIR); }
+<A>up		{ yylval.i = UP; return(DIR); }
+<A>down		{ yylval.i = DOWN; return(DIR); }
+<A>cw		{ yylval.i = CW; return(ATTR); }
+<A>clockwise	{ yylval.i = CW; return(ATTR); }
+<A>ccw		{ yylval.i = CCW; return(ATTR); }
+<A>invis(ible)?	{ yylval.i = INVIS; return(ATTR); }
+<A>noedge	{ yylval.i = INVIS; return ATTR; }
+<A>fill		return(yylval.i = FILL);
+<A>solid	;
+<A>dot(ted)?	return(yylval.i = DOT);
+<A>dash(ed)?	return(yylval.i = DASH);
+<A>chop		return(yylval.i = CHOP);
+
+<A>spread	{ yylval.i = SPREAD; return TEXTATTR; }
+<A>ljust	{ yylval.i = LJUST; return TEXTATTR; }
+<A>rjust	{ yylval.i = RJUST; return TEXTATTR; }
+<A>above	{ yylval.i = ABOVE; return TEXTATTR; }
+<A>below	{ yylval.i = BELOW; return TEXTATTR; }
+<A>center	{ yylval.i = CENTER; return TEXTATTR; }
+
+<A>"<-"		{ yylval.i = HEAD1; return(HEAD); }
+<A>"->"		{ yylval.i = HEAD2; return(HEAD); }
+<A>"<->"	{ yylval.i = HEAD12; return(HEAD); }
+
+<A>".x"			return(yylval.i = DOTX);
+<A>".y"			return(yylval.i = DOTY);
+<A>"."(ht|height)	return(yylval.i = DOTHT);
+<A>"."(wid|width)	return(yylval.i = DOTWID);
+<A>"."(rad|radius)	return(yylval.i = DOTRAD);
+
+<A>from		return(yylval.i = FROM);
+<A>to		return(yylval.i = TO);
+<A>at		return(yylval.i = AT);
+<A>by		return(yylval.i = BY);
+<A>with		return(yylval.i = WITH);
+<A>last		return(yylval.i = LAST);
+
+<A>log		return(LOG);
+<A>exp		return(EXP);
+<A>sin		return(SIN);
+<A>cos		return(COS);
+<A>atan2	return(ATAN2);
+<A>sqrt		return(SQRT);
+<A>rand		return(RAND);
+<A>max		return(MAX);
+<A>min		return(MIN);
+<A>int		return(INT);
+
+<A>"=="		return(EQ);
+<A>">="		return(GE);
+<A>"<="		return(LE);
+<A>"!="		return(NEQ);
+<A>">"		return(GT);
+<A>"<"		return(LT);
+<A>"&&"		return(ANDAND);
+<A>"||"		return(OROR);
+<A>"!"		return(NOT);	
+
+<A>Here		return(yylval.i = HERE);
+
+<A>for		return(FOR);
+<A>^Endfor\n	{ endfor(); }
+<A>do		{ yylval.p = delimstr("loop body"); return(DOSTR); }
+
+<A>copy|include		return(COPY);
+<A>(thru|through){WS}+	{ BEGIN thru; return(THRU); }
+<thru>{A}{B}*|.		{ yylval.st = copythru(yytext); BEGIN A; return(DEFNAME); }
+<A>until		return(UNTIL);
+
+<A>if		{ ifsw = 1; return(IF); }
+<A>then		{ if (!ifsw) { yylval.i = THEN; return(ATTR); }
+		  yylval.p = delimstr("then part"); ifsw = 0;
+		  return(THENSTR); }
+<A>else		{ yylval.p = delimstr("else part"); return(ELSESTR); }
+
+<A>sh{WS}+	{ BEGIN sh;
+		  if ((delim = input()) == '{') delim = '}';	/* no nested {} */
+		  shell_init(); }
+<sh>{A}{B}*	{ struct symtab *p;
+		  if (yytext[0] == delim) {
+			shell_exec();
+			BEGIN A;
+		  } else {
+			p = lookup(yytext);
+			if (p != NULL && p->s_type == DEFNAME) {
+				c = input();
+				unput(c);
+				if (c == '(')
+					dodef(p);
+				else
+					pbstr(p->s_val.p);
+			} else
+				shell_text(yytext);
+		  }
+		}
+<sh>.|\n	{ if (yytext[0] == delim) {
+			shell_exec();
+			BEGIN A;
+		  } else
+			shell_text(yytext);
+		}
+
+<A>define{WS}+		{ BEGIN def; }
+<def>{A}{B}*		{ definition(yytext); BEGIN A; }
+<A>undef(ine)?{WS}+{A}{B}*	{ undefine(yytext); }
+
+<A>first		{ yylval.i = 1; return(NTH); }
+<A>{D}+(th|nd|rd|st)	{ yylval.i = atoi(yytext); return(NTH); }
+<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
+		  	yylval.f = atof(yytext); return(NUMBER); }
+
+<A>{A}{B}* {	struct symtab *p;
+		p = lookup(yytext);
+		if (p != NULL && p->s_type == DEFNAME) {
+			c = input();
+			unput(c);
+			if (c == '(')	/* it's name(...) */
+				dodef(p);
+			else {	/* no argument list */
+				pbstr(p->s_val.p);
+				dprintf("pushing back `%s'\n", p->s_val.p);
+			}
+		} else if (islower(yytext[0])) {
+			yylval.p = tostring(yytext);
+			return(VARNAME);
+		} else {
+			yylval.p = tostring(yytext);
+			return(PLACENAME);
+		}
+	}
+
+<A>\"		{ BEGIN str; clen=0; }
+<str>\"		{ cbuf[clen]=0; yylval.p = tostring(cbuf); BEGIN A; return(TEXT); }
+<str>\n		{ cbuf[clen]=0; ERROR "missing quote in string \"%s\"", cbuf WARNING;
+				BEGIN A; return(ST); }
+<str>"\\\""	{ cbuf[clen++]='"'; }
+<str>"\\"t	{ cbuf[clen++]='\t'; }
+<str>"\\\\"	{ cbuf[clen++]='\\'; }
+<str>.		{ CADD; }
+
+<A>#.*		;
+
+<A>.		return(yylval.i = yytext[0]);
+
+%%
blob - /dev/null
blob + b534b5a53e437f63849a6d153eb01f39a22c9868 (mode 644)
--- /dev/null
+++ src/cmd/pic/picy.y
@@ -0,0 +1,328 @@
+%{
+#include <stdio.h>
+#include "pic.h"
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+YYSTYPE	y;
+
+extern	void	yyerror(char *);
+extern	int	yylex(void);
+%}
+
+%token	<i>	BOX	1	/* DON'T CHANGE THESE! */
+%token	<i>	LINE	2
+%token	<i>	ARROW	3
+%token	<i>	CIRCLE	4
+%token	<i>	ELLIPSE	5
+%token	<i>	ARC	6
+%token	<i>	SPLINE	7
+%token	<i>	BLOCK	8
+%token	<p>	TEXT	9
+%token	<p>	TROFF	10
+%token	<i>	MOVE	11
+%token	<i>	BLOCKEND 12
+%token	<i>	PLACE	13
+%token	<i>	PRINT RESET THRU UNTIL
+%token	<o>	FOR IF COPY
+%token	<p>	THENSTR ELSESTR DOSTR PLACENAME VARNAME SPRINTF
+%token	<st>	DEFNAME
+%token	<i>	ATTR TEXTATTR
+%token	<i>	LEFT RIGHT UP DOWN FROM TO AT BY WITH HEAD CW CCW THEN
+%token	<i>	HEIGHT WIDTH RADIUS DIAMETER LENGTH SIZE
+%token	<i>	CORNER HERE LAST NTH SAME BETWEEN AND
+%token	<i>	EAST WEST NORTH SOUTH NE NW SE SW START END
+%token	<i>	DOTX DOTY DOTHT DOTWID DOTRAD
+%token	<f>	NUMBER
+%token	<f>	LOG EXP SIN COS ATAN2 SQRT RAND MIN MAX INT
+%token	<i>	DIR
+%token	<i>	DOT DASH CHOP FILL NOEDGE
+%token	<o>	ST	/* statement terminator */
+
+%right	<f>	'='
+%left	<f>	OROR
+%left	<f>	ANDAND
+%nonassoc <f>	GT LT LE GE EQ NEQ
+%left	<f>	'+' '-'
+%left	<f>	'*' '/' '%'
+%right	<f>	UMINUS NOT
+%right	<f>	'^'
+
+%type	<f>	expr if_expr asgn
+%type	<p>	name text
+%type	<i>	optop exprlist
+%type	<o>	if for copy
+
+/* this is a lie:  picture and position are really the whole union */
+%type	<o>	leftbrace picture piclist position lbracket
+%type	<o>	prim place blockname
+%type	<i>	textlist textattr	/* not a sensible value */
+%type	<i>	last type
+
+%%
+
+top:
+	  piclist
+	| /* empty */
+	| error		{ ERROR "syntax error" WARNING; }
+	;
+
+piclist:
+	  picture
+	| piclist picture
+	;
+
+picture:
+	  prim ST			{ codegen = 1; makeiattr(0, 0); }
+	| leftbrace piclist '}'		{ rightthing($1, '}'); $$ = $2; }
+	| PLACENAME ':' picture		{ y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
+	| PLACENAME ':' ST picture	{ y.o=$4; makevar($1,PLACENAME,y); $$ = $4; }
+	| PLACENAME ':' position ST	{ y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
+	| asgn ST			{ y.f = $1; $$ = y.o; $$ = makenode(PLACE, 0); }
+	| DIR				{ setdir($1); $$ = makenode(PLACE, 0); }
+	| PRINT expr ST			{ printexpr($2); $$ = makenode(PLACE, 0); }
+	| PRINT position ST		{ printpos($2); $$ = makenode(PLACE, 0); }
+	| PRINT text ST			{ printf("%s\n", $2); free($2); $$ = makenode(PLACE, 0); }
+	| RESET varlist ST		{ resetvar(); makeiattr(0, 0); $$ = makenode(PLACE, 0); }
+	| copy
+	| for
+	| if
+	| ST
+	;
+
+varlist:
+	  /* empty */
+	| VARNAME		{ makevattr($1); }
+	| varlist VARNAME	{ makevattr($2); }
+	| varlist ',' VARNAME	{ makevattr($3); }
+	;
+
+asgn:
+	  VARNAME '=' expr	{ $$=y.f=$3; makevar($1,VARNAME,y); checkscale($1); }
+	;
+
+copy:
+	  COPY copylist		{ copy(); }
+	;
+copylist:
+	  copyattr
+	| copylist copyattr
+	;
+copyattr:
+	  text			{ copyfile($1); }
+	| THRU DEFNAME		{ copydef($2); }
+	| UNTIL text		{ copyuntil($2); }
+	;
+
+for:
+	  FOR name FROM expr TO expr BY optop expr DOSTR
+		{ forloop($2, $4, $6, $8, $9, $10); }
+	| FOR name FROM expr TO expr DOSTR
+		{ forloop($2, $4, $6, '+', 1.0, $7); }
+	| FOR name '=' expr TO expr BY optop expr DOSTR
+		{ forloop($2, $4, $6, $8, $9, $10); }
+	| FOR name '=' expr TO expr DOSTR
+		{ forloop($2, $4, $6, '+', 1.0, $7); }
+	;
+
+if:
+	  IF if_expr THENSTR ELSESTR	{ ifstat($2, $3, $4); }
+	| IF if_expr THENSTR		{ ifstat($2, $3, (char *) 0); }
+	;
+if_expr:
+	  expr
+	| text EQ text		{ $$ = strcmp($1,$3) == 0; free($1); free($3); }
+	| text NEQ text		{ $$ = strcmp($1,$3) != 0; free($1); free($3); }
+	;
+
+name:
+	  VARNAME	{ y.f = 0; makevar($1, VARNAME, y); }
+	;
+optop:
+	  '+'		{ $$ = '+'; }
+	| '-'		{ $$ = '-'; }
+	| '*'		{ $$ = '*'; }
+	| '/'		{ $$ = '/'; }
+	| /* empty */	{ $$ = ' '; }
+	;
+
+
+leftbrace:
+	  '{'			{ $$ = leftthing('{'); }
+	;
+
+prim:
+	  BOX attrlist		{ $$ = boxgen(); }
+	| CIRCLE attrlist	{ $$ = circgen($1); }
+	| ELLIPSE attrlist	{ $$ = circgen($1); }
+	| ARC attrlist		{ $$ = arcgen($1); }
+	| LINE attrlist		{ $$ = linegen($1); }
+	| ARROW attrlist	{ $$ = linegen($1); }
+	| SPLINE attrlist	{ $$ = linegen($1); }
+	| MOVE attrlist		{ $$ = movegen(); }
+	| textlist attrlist	{ $$ = textgen(); }
+	| TROFF			{ $$ = troffgen($1); }
+	| lbracket piclist ']' { $<o>$=rightthing($1,']'); } attrlist
+				{ $$ = blockgen($1, $<o>4); }
+	;
+
+lbracket:
+	  '['			{ $$ = leftthing('['); }
+	;
+
+attrlist:
+	  attrlist attr
+	| /* empty */
+	;
+
+attr:
+	  ATTR expr		{ makefattr($1, !DEFAULT, $2); }
+	| ATTR			{ makefattr($1, DEFAULT, 0.0); }
+	| expr			{ makefattr(curdir(), !DEFAULT, $1); }
+	| DIR expr		{ makefattr($1, !DEFAULT, $2); }
+	| DIR			{ makefattr($1, DEFAULT, 0.0); }
+	| FROM position		{ makeoattr($1, $2); }
+	| TO position		{ makeoattr($1, $2); }
+	| AT position		{ makeoattr($1, $2); }
+	| BY position		{ makeoattr($1, $2); }
+	| WITH CORNER		{ makeiattr(WITH, $2); }
+	| WITH '.' PLACENAME	{ makeoattr(PLACE, getblock(getlast(1,BLOCK), $3)); }
+	| WITH '.' PLACENAME CORNER
+		{ makeoattr(PLACE, getpos(getblock(getlast(1,BLOCK), $3), $4)); }
+	| WITH position		{ makeoattr(PLACE, $2); }
+	| SAME			{ makeiattr(SAME, $1); }
+	| TEXTATTR		{ maketattr($1, (char *) 0); }
+	| HEAD			{ makeiattr(HEAD, $1); }
+	| DOT expr		{ makefattr(DOT, !DEFAULT, $2); }
+	| DOT			{ makefattr(DOT, DEFAULT, 0.0); }
+	| DASH expr		{ makefattr(DASH, !DEFAULT, $2); }
+	| DASH			{ makefattr(DASH, DEFAULT, 0.0); }
+	| CHOP expr		{ makefattr(CHOP, !DEFAULT, $2); }
+	| CHOP			{ makefattr(CHOP, DEFAULT, 0.0); }
+	| CHOP PLACENAME	{ makeattr(CHOP, PLACENAME, getvar($2)); }
+	| FILL expr		{ makefattr(FILL, !DEFAULT, $2); }
+	| FILL			{ makefattr(FILL, DEFAULT, 0.0); }
+	| NOEDGE		{ makeiattr(NOEDGE, 0); }
+	| textlist
+	;
+
+textlist:
+	  textattr
+	| textlist textattr
+	;
+textattr:
+	  text			{ maketattr(CENTER, $1); }
+	| text TEXTATTR		{ maketattr($2, $1); }
+	| textattr TEXTATTR	{ addtattr($2); }
+	;
+text:
+	  TEXT
+	| SPRINTF '(' text ')'			{ $$ = sprintgen($3); }
+	| SPRINTF '(' text ',' exprlist ')'	{ $$ = sprintgen($3); }
+	;
+
+exprlist:
+	  expr			{ exprsave($1); $$ = 0; }
+	| exprlist ',' expr	{ exprsave($3); }
+	;
+
+position:		/* absolute, not relative */
+	  place
+	| '(' position ')'			{ $$ = $2; }
+	| expr ',' expr				{ $$ = makepos($1, $3); }
+	| position '+' expr ',' expr		{ $$ = fixpos($1, $3, $5); }
+	| position '-' expr ',' expr		{ $$ = fixpos($1, -$3, -$5); }
+	| position '+' '(' expr ',' expr ')'	{ $$ = fixpos($1, $4, $6); }
+	| position '-' '(' expr ',' expr ')'	{ $$ = fixpos($1, -$4, -$6); }
+	| position '+' place			{ $$ = addpos($1, $3); }
+	| position '-' place			{ $$ = subpos($1, $3); }
+	| '(' place ',' place ')'	{ $$ = makepos(getcomp($2,DOTX), getcomp($4,DOTY)); }
+	| expr LT position ',' position GT	{ $$ = makebetween($1, $3, $5); }
+	| expr BETWEEN position AND position	{ $$ = makebetween($1, $3, $5); }
+	;
+
+place:
+	  PLACENAME		{ y = getvar($1); $$ = y.o; }
+	| PLACENAME CORNER	{ y = getvar($1); $$ = getpos(y.o, $2); }
+	| CORNER PLACENAME	{ y = getvar($2); $$ = getpos(y.o, $1); }
+	| HERE			{ $$ = gethere(); }
+	| last type		{ $$ = getlast($1, $2); }
+	| last type CORNER	{ $$ = getpos(getlast($1, $2), $3); }
+	| CORNER last type	{ $$ = getpos(getlast($2, $3), $1); }
+	| NTH type		{ $$ = getfirst($1, $2); }
+	| NTH type CORNER	{ $$ = getpos(getfirst($1, $2), $3); }
+	| CORNER NTH type	{ $$ = getpos(getfirst($2, $3), $1); }
+	| blockname
+	| blockname CORNER	{ $$ = getpos($1, $2); }
+	| CORNER blockname	{ $$ = getpos($2, $1); }
+	;
+
+blockname:
+	  last BLOCK '.' PLACENAME	{ $$ = getblock(getlast($1,$2), $4); }
+	| NTH BLOCK '.' PLACENAME	{ $$ = getblock(getfirst($1,$2), $4); }
+	| PLACENAME '.' PLACENAME	{ y = getvar($1); $$ = getblock(y.o, $3); }
+	;
+
+last:
+	  last LAST		{ $$ = $1 + 1; }
+	| NTH LAST		{ $$ = $1; }
+	| LAST			{ $$ = 1; }
+	;
+
+type:
+	  BOX
+	| CIRCLE
+	| ELLIPSE
+	| ARC
+	| LINE
+	| ARROW
+	| SPLINE
+	| BLOCK
+	;
+
+expr:
+	  NUMBER
+	| VARNAME		{ $$ = getfval($1); }
+	| asgn
+	| expr '+' expr		{ $$ = $1 + $3; }
+	| expr '-' expr		{ $$ = $1 - $3; }
+	| expr '*' expr		{ $$ = $1 * $3; }
+	| expr '/' expr		{ if ($3 == 0.0) {
+					ERROR "division by 0" WARNING; $3 = 1; }
+				  $$ = $1 / $3; }
+	| expr '%' expr		{ if ((long)$3 == 0) {
+					ERROR "mod division by 0" WARNING; $3 = 1; }
+				  $$ = (long)$1 % (long)$3; }
+	| '-' expr %prec UMINUS	{ $$ = -$2; }
+	| '+' expr %prec UMINUS	{ $$ = $2; }
+	| '(' expr ')'		{ $$ = $2; }
+	| place DOTX		{ $$ = getcomp($1, $2); }
+	| place DOTY		{ $$ = getcomp($1, $2); }
+	| place DOTHT		{ $$ = getcomp($1, $2); }
+	| place DOTWID		{ $$ = getcomp($1, $2); }
+	| place DOTRAD		{ $$ = getcomp($1, $2); }
+	| PLACENAME '.' VARNAME	{ y = getvar($1); $$ = getblkvar(y.o, $3); }
+	| last BLOCK '.' VARNAME { $$ = getblkvar(getlast($1,$2), $4); }
+	| NTH BLOCK '.' VARNAME	{ $$ = getblkvar(getfirst($1,$2), $4); }
+	| expr GT expr		{ $$ = $1 > $3; }
+	| expr LT expr		{ $$ = $1 < $3; }
+	| expr LE expr		{ $$ = $1 <= $3; }
+	| expr GE expr		{ $$ = $1 >= $3; }
+	| expr EQ expr		{ $$ = $1 == $3; }
+	| expr NEQ expr		{ $$ = $1 != $3; }
+	| expr ANDAND expr	{ $$ = $1 && $3; }
+	| expr OROR expr	{ $$ = $1 || $3; }
+	| NOT expr		{ $$ = !($2); }
+	| LOG '(' expr ')'		{ $$ = Log10($3); }
+	| EXP '(' expr ')'		{ $$ = Exp($3 * log(10.0)); }
+	| expr '^' expr			{ $$ = pow($1, $3); }
+	| SIN '(' expr ')'		{ $$ = sin($3); }
+	| COS '(' expr ')'		{ $$ = cos($3); }
+	| ATAN2 '(' expr ',' expr ')'	{ $$ = atan2($3, $5); }
+	| SQRT '(' expr ')'		{ $$ = Sqrt($3); }
+	| RAND '(' ')'			{ $$ = (float)rand() / 32767.0; /* might be 2^31-1 */ }
+	| MAX '(' expr ',' expr ')'	{ $$ = $3 >= $5 ? $3 : $5; }
+	| MIN '(' expr ',' expr ')'	{ $$ = $3 <= $5 ? $3 : $5; }
+	| INT '(' expr ')'		{ $$ = (long) $3; }
+	;
blob - /dev/null
blob + d3e3151bac28b062f5fae01dce5ffa20ddc75bce (mode 644)
--- /dev/null
+++ src/cmd/pic/pltroff.c
@@ -0,0 +1,357 @@
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "pic.h"
+extern int dbg;
+
+#define	abs(n)	(n >= 0 ? n : -(n))
+#define	max(x,y)	((x)>(y) ? (x) : (y))
+
+char	*textshift = "\\v'.2m'";	/* move text this far down */
+
+/* scaling stuff defined by s command as X0,Y0 to X1,Y1 */
+/* output dimensions set by -l,-w options to 0,0 to hmax, vmax */
+/* default output is 6x6 inches */
+
+
+double	xscale;
+double	yscale;
+
+double	hpos	= 0;	/* current horizontal position in output coordinate system */
+double	vpos	= 0;	/* current vertical position; 0 is top of page */
+
+double	htrue	= 0;	/* where we really are */
+double	vtrue	= 0;
+
+double	X0, Y0;		/* left bottom of input */
+double	X1, Y1;		/* right top of input */
+
+double	hmax;		/* right end of output */
+double	vmax;		/* top of output (down is positive) */
+
+extern	double	deltx;
+extern	double	delty;
+extern	double	xmin, ymin, xmax, ymax;
+
+double	xconv(double), yconv(double), xsc(double), ysc(double);
+void	space(double, double, double, double);
+void	hgoto(double), vgoto(double), hmot(double), vmot(double);
+void	move(double, double), movehv(double, double);
+void	cont(double, double);
+
+void openpl(char *s)	/* initialize device; s is residue of .PS invocation line */
+{
+	double maxw, maxh, ratio = 1;
+	double odeltx = deltx, odelty = delty;
+
+	hpos = vpos = 0;
+	maxw = getfval("maxpswid");
+	maxh = getfval("maxpsht");
+	if (deltx > maxw) {	/* shrink horizontal */
+		ratio = maxw / deltx;
+		deltx *= ratio;
+		delty *= ratio;
+	}
+	if (delty > maxh) {	/* shrink vertical */
+		ratio = maxh / delty;
+		deltx *= ratio;
+		delty *= ratio;
+	}
+	if (ratio != 1) {
+		fprintf(stderr, "pic: %g X %g picture shrunk to", odeltx, odelty);
+		fprintf(stderr, " %g X %g\n", deltx, delty);
+	}
+	space(xmin, ymin, xmax, ymax);
+	printf("... %g %g %g %g\n", xmin, ymin, xmax, ymax);
+	printf("... %.3fi %.3fi %.3fi %.3fi\n",
+		xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax));
+	printf(".nr 00 \\n(.u\n");
+	printf(".nf\n");
+	printf(".PS %.3fi %.3fi %s", yconv(ymin), xconv(xmax), s);
+		/* assumes \n comes as part of s */
+}
+
+void space(double x0, double y0, double x1, double y1)	/* set limits of page */
+{
+	X0 = x0;
+	Y0 = y0;
+	X1 = x1;
+	Y1 = y1;
+	xscale = deltx == 0.0 ? 1.0 : deltx / (X1-X0);
+	yscale = delty == 0.0 ? 1.0 : delty / (Y1-Y0);
+}
+
+double xconv(double x)	/* convert x from external to internal form */
+{
+	return (x-X0) * xscale;
+}
+
+double xsc(double x)	/* convert x from external to internal form, scaling only */
+{
+
+	return (x) * xscale;
+}
+
+double yconv(double y)	/* convert y from external to internal form */
+{
+	return (Y1-y) * yscale;
+}
+
+double ysc(double y)	/* convert y from external to internal form, scaling only */
+{
+	return (y) * yscale;
+}
+
+void closepl(char *PEline)	/* clean up after finished */
+{
+	movehv(0.0, 0.0);	/* get back to where we started */
+	if (strchr(PEline, 'F') == NULL) {
+		printf(".sp 1+%.3fi\n", yconv(ymin));
+	}
+	printf("%s\n", PEline);
+	printf(".if \\n(00 .fi\n");
+}
+
+void move(double x, double y)	/* go to position x, y in external coords */
+{
+	hgoto(xconv(x));
+	vgoto(yconv(y));
+}
+
+void movehv(double h, double v)	/* go to internal position h, v */
+{
+	hgoto(h);
+	vgoto(v);
+}
+
+void hmot(double n)	/* generate n units of horizontal motion */
+{
+	hpos += n;
+}
+
+void vmot(double n)	/* generate n units of vertical motion */
+{
+	vpos += n;
+}
+
+void hgoto(double n)
+{
+	hpos = n;
+}
+
+void vgoto(double n)
+{
+	vpos = n;
+}
+
+double fabs(double x)
+{
+	return x < 0 ? -x : x;
+}
+
+void hvflush(void)	/* get to proper point for output */
+{
+	if (fabs(hpos-htrue) >= 0.0005) {
+		printf("\\h'%.3fi'", hpos - htrue);
+		htrue = hpos;
+	}
+	if (fabs(vpos-vtrue) >= 0.0005) {
+		printf("\\v'%.3fi'", vpos - vtrue);
+		vtrue = vpos;
+	}
+}
+
+void flyback(void)	/* return to upper left corner (entry point) */
+{
+	printf(".sp -1\n");
+	htrue = vtrue = 0;
+}
+
+void printlf(int n, char *f)
+{
+	if (f)
+		printf(".lf %d %s\n", n, f);
+	else
+		printf(".lf %d\n", n);
+}
+
+void troff(char *s)	/* output troff right here */
+{
+	printf("%s\n", s);
+}
+
+void label(char *s, int t, int nh)	/* text s of type t nh half-lines up */
+{
+	int q;
+	char *p;
+
+	if (!s)
+		return;
+	hvflush();
+	dprintf("label: %s %o %d\n", s, t, nh);
+	printf("%s", textshift);	/* shift down and left */
+	if (t & ABOVE)
+		nh++;
+	else if (t & BELOW)
+		nh--;
+	if (nh)
+		printf("\\v'%du*\\n(.vu/2u'", -nh);
+	/* just in case the text contains a quote: */
+	q = 0;
+	for (p = s; *p; p++)
+		if (*p == '\'') {
+			q = 1;
+			break;
+		}
+	t &= ~(ABOVE|BELOW);
+	if (t & LJUST) {
+		printf("%s", s);
+	} else if (t & RJUST) {
+		if (q)
+			printf("\\h\\(ts-\\w\\(ts%s\\(tsu\\(ts%s", s, s);
+		else
+			printf("\\h'-\\w'%s'u'%s", s, s);
+	} else {	/* CENTER */
+		if (q)
+			printf("\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts%s", s, s);
+		else
+			printf("\\h'-\\w'%s'u/2u'%s", s, s);
+	}
+	printf("\n");
+	flyback();
+}
+
+void line(double x0, double y0, double x1, double y1)	/* draw line from x0,y0 to x1,y1 */
+{
+	move(x0, y0);
+	cont(x1, y1);
+}
+
+void arrow(double x0, double y0, double x1, double y1, double w, double h,
+	 double ang, int nhead) 	/* draw arrow (without shaft) */
+{
+	double alpha, rot, drot, hyp;
+	double dx, dy;
+	int i;
+
+	rot = atan2(w / 2, h);
+	hyp = sqrt(w/2 * w/2 + h * h);
+	alpha = atan2(y1-y0, x1-x0) + ang;
+	if (nhead < 2)
+		nhead = 2;
+	dprintf("rot=%g, hyp=%g, alpha=%g\n", rot, hyp, alpha);
+	for (i = nhead-1; i >= 0; i--) {
+		drot = 2 * rot / (double) (nhead-1) * (double) i;
+		dx = hyp * cos(alpha + PI - rot + drot);
+		dy = hyp * sin(alpha + PI - rot + drot);
+		dprintf("dx,dy = %g,%g\n", dx, dy);
+		line(x1+dx, y1+dy, x1, y1);
+	}
+}
+
+double lastgray = 0;
+
+void fillstart(double v)	/* this works only for postscript, obviously. */
+{				/* uses drechsler's dpost conventions... */
+	hvflush();
+	printf("\\X'BeginObject %g setgray'\n", v);
+	lastgray = v;
+	flyback();
+}
+
+void fillend(int vis, int fill)
+{
+	hvflush();
+	printf("\\X'EndObject gsave eofill grestore %g setgray %s'\n",
+		!vis ? lastgray : 0.0,
+		vis ? "stroke" : "");
+	/* for dashed: [50] 0 setdash just before stroke. */
+	lastgray = 0;
+	flyback();
+}
+
+void box(double x0, double y0, double x1, double y1)
+{
+	move(x0, y0);
+	cont(x0, y1);
+	cont(x1, y1);
+	cont(x1, y0);
+	cont(x0, y0);
+}
+
+void cont(double x, double y)	/* continue line from here to x,y */
+{
+	double h1, v1;
+	double dh, dv;
+
+	h1 = xconv(x);
+	v1 = yconv(y);
+	dh = h1 - hpos;
+	dv = v1 - vpos;
+	hvflush();
+	printf("\\D'l%.3fi %.3fi'\n", dh, dv);
+	flyback();	/* expensive */
+	hpos = h1;
+	vpos = v1;
+}
+
+void circle(double x, double y, double r)
+{
+	move(x-r, y);
+	hvflush();
+	printf("\\D'c%.3fi'\n", xsc(2 * r));
+	flyback();
+}
+
+void spline(double x, double y, double n, ofloat *p, int dashed, double ddval)
+{
+	int i;
+	double dx, dy;
+	double xerr, yerr;
+
+	move(x, y);
+	hvflush();
+	xerr = yerr = 0.0;
+	printf("\\D'~");
+	for (i = 0; i < 2 * n; i += 2) {
+		dx = xsc(xerr += p[i]);
+		xerr -= dx/xscale;
+		dy = ysc(yerr += p[i+1]);
+		yerr -= dy/yscale;
+		printf(" %.3fi %.3fi", dx, -dy);	/* WATCH SIGN */
+	}
+	printf("'\n");
+	flyback();
+}
+
+void ellipse(double x, double y, double r1, double r2)
+{
+	double ir1, ir2;
+
+	move(x-r1, y);
+	hvflush();
+	ir1 = xsc(r1);
+	ir2 = ysc(r2);
+	printf("\\D'e%.3fi %.3fi'\n", 2 * ir1, 2 * abs(ir2));
+	flyback();
+}
+
+void arc(double x, double y, double x0, double y0, double x1, double y1)	/* draw arc with center x,y */
+{
+
+	move(x0, y0);
+	hvflush();
+	printf("\\D'a%.3fi %.3fi %.3fi %.3fi'\n",
+		xsc(x-x0), -ysc(y-y0), xsc(x1-x), -ysc(y1-y));	/* WATCH SIGNS */
+	flyback();
+}
+
+void dot(void) {
+	hvflush();
+	/* what character to draw here depends on what's available. */
+	/* on the 202, l. is good but small. */
+	/* in general, use a smaller, shifted period and hope */
+
+	printf("\\&\\f1\\h'-.1m'\\v'.03m'\\s-3.\\s+3\\fP\n");
+	flyback();
+}
blob - /dev/null
blob + 4782af9bdb49c4c3537c1810ae457924ce32f66b (mode 644)
--- /dev/null
+++ src/cmd/pic/prevy.tab.h
@@ -0,0 +1,97 @@
+# define BOX 1
+# define LINE 2
+# define ARROW 3
+# define CIRCLE 4
+# define ELLIPSE 5
+# define ARC 6
+# define SPLINE 7
+# define BLOCK 8
+# define TEXT 9
+# define TROFF 10
+# define MOVE 11
+# define BLOCKEND 12
+# define PLACE 13
+# define PRINT 270
+# define RESET 271
+# define THRU 272
+# define UNTIL 273
+# define FOR 274
+# define IF 275
+# define COPY 276
+# define THENSTR 277
+# define ELSESTR 278
+# define DOSTR 279
+# define PLACENAME 280
+# define VARNAME 281
+# define SPRINTF 282
+# define DEFNAME 283
+# define ATTR 284
+# define TEXTATTR 285
+# define LEFT 286
+# define RIGHT 287
+# define UP 288
+# define DOWN 289
+# define FROM 290
+# define TO 291
+# define AT 292
+# define BY 293
+# define WITH 294
+# define HEAD 295
+# define CW 296
+# define CCW 297
+# define THEN 298
+# define HEIGHT 299
+# define WIDTH 300
+# define RADIUS 301
+# define DIAMETER 302
+# define LENGTH 303
+# define SIZE 304
+# define CORNER 305
+# define HERE 306
+# define LAST 307
+# define NTH 308
+# define SAME 309
+# define BETWEEN 310
+# define AND 311
+# define EAST 312
+# define WEST 313
+# define NORTH 314
+# define SOUTH 315
+# define NE 316
+# define NW 317
+# define SE 318
+# define SW 319
+# define START 320
+# define END 321
+# define DOTX 322
+# define DOTY 323
+# define DOTHT 324
+# define DOTWID 325
+# define DOTRAD 326
+# define NUMBER 327
+# define LOG 328
+# define EXP 329
+# define SIN 330
+# define COS 331
+# define ATAN2 332
+# define SQRT 333
+# define RAND 334
+# define MIN 335
+# define MAX 336
+# define INT 337
+# define DIR 338
+# define DOT 339
+# define DASH 340
+# define CHOP 341
+# define FILL 342
+# define ST 343
+# define OROR 344
+# define ANDAND 345
+# define GT 346
+# define LT 347
+# define LE 348
+# define GE 349
+# define EQ 350
+# define NEQ 351
+# define UMINUS 352
+# define NOT 353
blob - /dev/null
blob + ad21e0d70ed99b3df401e6156a36c425061934f7 (mode 644)
--- /dev/null
+++ src/cmd/pic/print.c
@@ -0,0 +1,238 @@
+#include <stdio.h>
+#include <math.h>
+#include "pic.h"
+#include "y.tab.h"
+
+void dotext(obj *);
+void dotline(double, double, double, double, int, double);
+void dotbox(double, double, double, double, int, double);
+void ellipse(double, double, double, double);
+void circle(double, double, double);
+void arc(double, double, double, double, double, double);
+void arrow(double, double, double, double, double, double, double, int);
+void line(double, double, double, double);
+void box(double, double, double, double);
+void spline(double x, double y, double n, ofloat *p, int dashed, double ddval);
+void move(double, double);
+void troff(char *);
+void dot(void);
+void fillstart(double), fillend(int vis, int noedge);
+
+void print(void)
+{
+	obj *p;
+	int i, j, k, m;
+	int fill, vis, invis;
+	double x0, y0, x1, y1, ox, oy, dx, dy, ndx, ndy;
+
+	for (i = 0; i < nobj; i++) {
+		p = objlist[i];
+		ox = p->o_x;
+		oy = p->o_y;
+		if (p->o_count >= 1)
+			x1 = p->o_val[0];
+		if (p->o_count >= 2)
+			y1 = p->o_val[1];
+		m = p->o_mode;
+		fill = p->o_attr & FILLBIT;
+		invis = p->o_attr & INVIS;
+		vis = !invis;
+		switch (p->o_type) {
+		case TROFF:
+			troff(text[p->o_nt1].t_val);
+			break;
+		case BOX:
+		case BLOCK:
+			x0 = ox - x1 / 2;
+			y0 = oy - y1 / 2;
+			x1 = ox + x1 / 2;
+			y1 = oy + y1 / 2;
+			if (fill) {
+				move(x0, y0);
+				fillstart(p->o_fillval);
+			}
+			if (p->o_type == BLOCK)
+				;	/* nothing at all */
+			else if (invis && !fill)
+				;	/* nothing at all */
+			else if (p->o_attr & (DOTBIT|DASHBIT))
+				dotbox(x0, y0, x1, y1, p->o_attr, p->o_ddval);
+			else
+				box(x0, y0, x1, y1);
+			if (fill)
+				fillend(vis, fill);
+			move(ox, oy);
+			dotext(p);	/* if there are any text strings */
+			if (ishor(m))
+				move(isright(m) ? x1 : x0, oy);	/* right side */
+			else
+				move(ox, isdown(m) ? y0 : y1);	/* bottom */
+			break;
+		case BLOCKEND:
+			break;
+		case CIRCLE:
+			if (fill)
+				fillstart(p->o_fillval);
+			if (vis || fill)
+				circle(ox, oy, x1);
+			if (fill)
+				fillend(vis, fill);
+			move(ox, oy);
+			dotext(p);
+			if (ishor(m))
+				move(ox + isright(m) ? x1 : -x1, oy);
+			else
+				move(ox, oy + isup(m) ? x1 : -x1);
+			break;
+		case ELLIPSE:
+			if (fill)
+				fillstart(p->o_fillval);
+			if (vis || fill)
+				ellipse(ox, oy, x1, y1);
+			if (fill)
+				fillend(vis, fill);
+			move(ox, oy);
+			dotext(p);
+			if (ishor(m))
+				move(ox + isright(m) ? x1 : -x1, oy);
+			else
+				move(ox, oy - isdown(m) ? y1 : -y1);
+			break;
+		case ARC:
+			if (fill) {
+				move(ox, oy);
+				fillstart(p->o_fillval);
+			}
+			if (p->o_attr & HEAD1)
+				arrow(x1 - (y1 - oy), y1 + (x1 - ox),
+				      x1, y1, p->o_val[4], p->o_val[5], p->o_val[5]/p->o_val[6]/2, p->o_nhead);
+                        if (invis && !fill)
+                                /* probably wrong when it's cw */
+                                move(x1, y1);
+                        else
+				arc(ox, oy, x1, y1, p->o_val[2], p->o_val[3]);
+			if (p->o_attr & HEAD2)
+				arrow(p->o_val[2] + p->o_val[3] - oy, p->o_val[3] - (p->o_val[2] - ox),
+				      p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5], -p->o_val[5]/p->o_val[6]/2, p->o_nhead);
+			if (fill)
+				fillend(vis, fill);
+			if (p->o_attr & CW_ARC)
+				move(x1, y1);	/* because drawn backwards */
+			move(ox, oy);
+			dotext(p);
+			break;
+		case LINE:
+		case ARROW:
+		case SPLINE:
+			if (fill) {
+				move(ox, oy);
+				fillstart(p->o_fillval);
+			}
+			if (vis && p->o_attr & HEAD1)
+				arrow(ox + p->o_val[5], oy + p->o_val[6], ox, oy, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
+                        if (invis && !fill)
+                                move(x1, y1);
+			else if (p->o_type == SPLINE)
+				spline(ox, oy, p->o_val[4], &p->o_val[5], p->o_attr & (DOTBIT|DASHBIT), p->o_ddval);
+			else {
+				dx = ox;
+				dy = oy;
+				for (k=0, j=5; k < p->o_val[4]; k++, j += 2) {
+					ndx = dx + p->o_val[j];
+					ndy = dy + p->o_val[j+1];
+					if (p->o_attr & (DOTBIT|DASHBIT))
+						dotline(dx, dy, ndx, ndy, p->o_attr, p->o_ddval);
+					else
+						line(dx, dy, ndx, ndy);
+					dx = ndx;
+					dy = ndy;
+				}
+			}
+			if (vis && p->o_attr & HEAD2) {
+				dx = ox;
+				dy = oy;
+				for (k = 0, j = 5; k < p->o_val[4] - 1; k++, j += 2) {
+					dx += p->o_val[j];
+					dy += p->o_val[j+1];
+				}
+				arrow(dx, dy, x1, y1, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
+			}
+			if (fill)
+				fillend(vis, fill);
+			move((ox + x1)/2, (oy + y1)/2);	/* center */
+			dotext(p);
+			break;
+		case MOVE:
+			move(ox, oy);
+			break;
+		case TEXT:
+			move(ox, oy);
+                        if (vis)
+				dotext(p);
+			break;
+		}
+	}
+}
+
+void dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted line */
+{
+	static double prevval = 0.05;	/* 20 per inch by default */
+	int i, numdots;
+	double a, b, dx, dy;
+
+	if (ddval == 0)
+		ddval = prevval;
+	prevval = ddval;
+	/* don't save dot/dash value */
+	dx = x1 - x0;
+	dy = y1 - y0;
+	if (ddtype & DOTBIT) {
+		numdots = sqrt(dx*dx + dy*dy) / prevval + 0.5;
+		if (numdots > 0)
+			for (i = 0; i <= numdots; i++) {
+				a = (double) i / (double) numdots;
+				move(x0 + (a * dx), y0 + (a * dy));
+				dot();
+			}
+	} else if (ddtype & DASHBIT) {
+		double d, dashsize, spacesize;
+		d = sqrt(dx*dx + dy*dy);
+		if (d <= 2 * prevval) {
+			line(x0, y0, x1, y1);
+			return;
+		}
+		numdots = d / (2 * prevval) + 1;	/* ceiling */
+		dashsize = prevval;
+		spacesize = (d - numdots * dashsize) / (numdots - 1);
+		for (i = 0; i < numdots-1; i++) {
+			a = i * (dashsize + spacesize) / d;
+			b = a + dashsize / d;
+			line(x0 + (a*dx), y0 + (a*dy), x0 + (b*dx), y0 + (b*dy));
+			a = b;
+			b = a + spacesize / d;
+			move(x0 + (a*dx), y0 + (a*dy));
+		}
+		line(x0 + (b * dx), y0 + (b * dy), x1, y1);
+	}
+	prevval = 0.05;
+}
+
+void dotbox(double x0, double y0, double x1, double y1, int ddtype, double ddval)	/* dotted or dashed box */
+{
+	dotline(x0, y0, x1, y0, ddtype, ddval);
+	dotline(x1, y0, x1, y1, ddtype, ddval);
+	dotline(x1, y1, x0, y1, ddtype, ddval);
+	dotline(x0, y1, x0, y0, ddtype, ddval);
+}
+
+void dotext(obj *p)	/* print text strings of p in proper vertical spacing */
+{
+	int i, nhalf;
+	void label(char *, int, int);
+
+	nhalf = p->o_nt2 - p->o_nt1 - 1;
+	for (i = p->o_nt1; i < p->o_nt2; i++) {
+		label(text[i].t_val, text[i].t_type, nhalf);
+		nhalf -= 2;
+	}
+}
blob - /dev/null
blob + 879075c6854b3083ccc2f4f09e530bbc0151a8c5 (mode 644)
--- /dev/null
+++ src/cmd/pic/symtab.c
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "pic.h"
+#include "y.tab.h"
+
+YYSTYPE getvar(char *s)	/* return value of variable s (usually pointer) */
+{
+	struct symtab *p;
+	static YYSTYPE bug;
+
+	p = lookup(s);
+	if (p == NULL) {
+		if (islower(s[0]))
+			ERROR "no such variable as %s", s WARNING;
+		else
+			ERROR "no such place as %s", s WARNING;
+		return(bug);
+	}
+	return(p->s_val);
+}
+
+double getfval(char *s)	/* return float value of variable s */
+{
+	YYSTYPE y;
+
+	y = getvar(s);
+	return y.f;
+}
+
+void setfval(char *s, double f)	/* set variable s to f */
+{
+	struct symtab *p;
+
+	if ((p = lookup(s)) != NULL)
+		p->s_val.f = f;
+}
+
+struct symtab *makevar(char *s, int t, YYSTYPE v)	/* make variable named s in table */
+		/* assumes s is static or from tostring */
+{
+	struct symtab *p;
+
+	for (p = stack[nstack].p_symtab; p != NULL; p = p->s_next)
+		if (strcmp(s, p->s_name) == 0)
+			break;
+	if (p == NULL) {	/* it's a new one */
+		p = (struct symtab *) malloc(sizeof(struct symtab));
+		if (p == NULL)
+			ERROR "out of symtab space with %s", s FATAL;
+		p->s_next = stack[nstack].p_symtab;
+		stack[nstack].p_symtab = p;	/* stick it at front */
+	}
+	p->s_name = s;
+	p->s_type = t;
+	p->s_val = v;
+	return(p);
+}
+
+struct symtab *lookup(char *s)	/* find s in symtab */
+{
+	int i;
+	struct symtab *p;
+
+	for (i = nstack; i >= 0; i--)	/* look in each active symtab */
+		for (p = stack[i].p_symtab; p != NULL; p = p->s_next)
+			if (strcmp(s, p->s_name) == 0)
+				return(p);
+	return(NULL);
+}
+
+void freesymtab(struct symtab *p)	/* free space used by symtab at p */
+{
+	struct symtab *q;
+
+	for ( ; p != NULL; p = q) {
+		q = p->s_next;
+		free(p->s_name);	/* assumes done with tostring */
+		free((char *)p);
+	}
+}
+
+void freedef(char *s)	/* free definition for string s */
+{
+	struct symtab *p, *q, *op;
+
+	for (p = op = q = stack[nstack].p_symtab; p != NULL; p = p->s_next) {
+		if (strcmp(s, p->s_name) == 0) { 	/* got it */
+			if (p->s_type != DEFNAME)
+				break;
+			if (p == op)	/* 1st elem */
+				stack[nstack].p_symtab = p->s_next;
+			else
+				q->s_next = p->s_next;
+			free(p->s_name);
+			free(p->s_val.p);
+			free((char *)p);
+			return;
+		}
+		q = p;
+	}
+	/* ERROR "%s is not defined at this point", s WARNING; */
+}
blob - /dev/null
blob + 98dfbb57b2dc67bb234edd85c45296ab2ff1eaff (mode 644)
--- /dev/null
+++ src/cmd/pic/textgen.c
@@ -0,0 +1,115 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj *textgen(void)
+{
+	int i, sub, nstr, at, with, hset, invis;
+	double xwith, ywith, h, w, x0, y0, x1, y1;
+	obj *p, *ppos;
+	static double prevh = 0;
+	static double prevw = 0;
+	Attr *ap;
+
+	at = with = nstr = hset = invis = 0;
+	h = getfval("textht");
+	w = getfval("textwid");
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case HEIGHT:
+			h = ap->a_val.f;
+			hset++;
+			break;
+		case WIDTH:
+			w = ap->a_val.f;
+			break;
+		case WITH:
+			with = ap->a_val.i;
+			break;
+		case INVIS:
+			invis = INVIS;
+			break;
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case TEXTATTR:
+			sub = ap->a_sub;
+			if (ap->a_val.p == NULL)	/* an isolated modifier */
+				text[ntext-1].t_type = sub;
+			else {
+				savetext(sub, ap->a_val.p);
+				nstr++;
+			}
+			break;
+		}
+	}
+	if (hset == 0)		/* no explicit ht cmd */
+		h *= nstr;
+	if (with) {
+		xwith = ywith = 0.0;
+		switch (with) {
+		case NORTH:	ywith = -h / 2; break;
+		case SOUTH:	ywith = h / 2; break;
+		case EAST:	xwith = -w / 2; break;
+		case WEST:	xwith = w / 2; break;
+		case NE:	xwith = -w / 2; ywith = -h / 2; break;
+		case SE:	xwith = -w / 2; ywith = h / 2; break;
+		case NW:	xwith = w / 2; ywith = -h / 2; break;
+		case SW:	xwith = w / 2; ywith = h / 2; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += w / 2;
+		else if (isleft(hvmode))
+			curx -= w / 2;
+		else if (isup(hvmode))
+			cury += h / 2;
+		else
+			cury -= h / 2;
+	}
+	x0 = curx - w / 2;
+	y0 = cury - h / 2;
+	x1 = curx + w / 2;
+	y1 = cury + h / 2;
+	extreme(x0, y0);
+	extreme(x1, y1);
+	dprintf("Text h %g w %g at %g,%g\n", h, w, curx, cury);
+	p = makenode(TEXT, 2);
+	p->o_attr = invis;
+	p->o_val[0] = w;
+	p->o_val[1] = h;
+	if (isright(hvmode))
+		curx = x1;
+	else if (isleft(hvmode))
+		curx = x0;
+	else if (isup(hvmode))
+		cury = y1;
+	else
+		cury = y0;
+	prevh = h;
+	prevw = w;
+	return(p);
+}
+
+obj *troffgen(char *s)	/* save away a string of troff commands */
+{
+	savetext(CENTER, s);	/* use the existing text mechanism */
+	return makenode(TROFF, 0);
+}
+
+void savetext(int t, char *s)	/* record text elements for current object */
+{
+	if (ntext >= ntextlist)
+		text = (Text *) grow((char *) text, "text", ntextlist += 200, sizeof(Text));
+	text[ntext].t_type = t;
+	text[ntext].t_val = s;
+	dprintf("saving %d text %s at %d\n", t, s, ntext);
+	ntext++;
+}
blob - /dev/null
blob + cdaf4a7ebd04cb8578d652d9e72c4f4dd80598fd (mode 644)
--- /dev/null
+++ src/cmd/tbl/mkfile
@@ -0,0 +1,32 @@
+<$PLAN9/src/mkhdr
+
+TARG=tbl
+OFILES=\
+	t8.$O\
+	t4.$O\
+	t6.$O\
+	tu.$O\
+	t5.$O\
+	t7.$O\
+	tv.$O\
+	tg.$O\
+	t3.$O\
+	tb.$O\
+	tt.$O\
+	t9.$O\
+	t1.$O\
+	tf.$O\
+	tc.$O\
+	ti.$O\
+	tm.$O\
+	t0.$O\
+	tr.$O\
+	te.$O\
+	ts.$O\
+	t2.$O\
+
+HFILES=\
+	t.h\
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
blob - /dev/null
blob + efcab373f705f3b8b96d840376df732599d7423b (mode 644)
--- /dev/null
+++ src/cmd/tbl/t.h
@@ -0,0 +1,192 @@
+/* t..c : external declarations */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+# include <ctype.h>
+
+# define MAXLIN 250
+# define MAXHEAD 44
+# define MAXCOL 30
+ /* Do NOT make MAXCOL bigger with adjusting nregs[] in tr.c */
+# define MAXCHS 2000
+#define MAXLINLEN 300
+# define MAXRPT 100
+# define CLLEN 10
+# define SHORTLINE 4
+extern int nlin, ncol, iline, nclin, nslin;
+
+extern int (*style)[MAXHEAD];
+extern char (*font)[MAXHEAD][2];
+extern char (*csize)[MAXHEAD][4];
+extern char (*vsize)[MAXHEAD][4];
+extern char (*cll)[CLLEN];
+extern int (*flags)[MAXHEAD];
+# define ZEROW 001
+# define HALFUP 002
+# define CTOP 004
+# define CDOWN 010
+extern int stynum[];
+extern int qcol;
+extern int *doubled, *acase, *topat;
+extern int F1, F2;
+extern int (*lefline)[MAXHEAD];
+extern int fullbot[];
+extern char *instead[];
+extern int expflg;
+extern int ctrflg;
+extern int evenflg;
+extern int *evenup;
+extern int boxflg;
+extern int dboxflg;
+extern int linsize;
+extern int tab;
+extern int pr1403;
+extern int linsize, delim1, delim2;
+extern int allflg;
+extern int textflg;
+extern int left1flg;
+extern int rightl;
+struct colstr {char *col, *rcol;};
+extern struct colstr *table[];
+extern char *cspace, *cstore;
+extern char *exstore, *exlim, *exspace;
+extern int *sep;
+extern int *used, *lused, *rused;
+extern int linestop[];
+extern char *leftover;
+extern char *last, *ifile;
+extern int texname;
+extern int texct, texmax;
+extern char texstr[];
+extern int linstart;
+
+
+extern Biobuf *tabin, tabout;
+# define CRIGHT 2
+# define CLEFT 0
+# define CMID 1
+# define S1 31
+# define S2 32
+# define S3 33
+# define TMP 38
+#define S9 39
+# define SF 35
+# define SL 34
+# define LSIZE 33
+# define SIND 37
+# define SVS 36
+/* this refers to the relative position of lines */
+# define LEFT 1
+# define RIGHT 2
+# define THRU 3
+# define TOP 1
+# define BOT 2
+
+int tbl(int argc,char *argv[]);		/*t1.c*/
+void setinp(int, char **);
+int swapin(void);
+
+void tableput(void);			/*t2.c*/
+
+void getcomm(void);			/*t3.c*/
+void backrest(char *);
+
+void getspec(void);			/*t4.c*/
+void readspec(void);
+int findcol(void);
+void garray(int);
+char *getcore(int, int);
+void freearr(void);
+
+void gettbl(void);			/*t5.c*/
+int nodata(int);
+int oneh(int);
+int vspand(int, int, int);
+int vspen(char *);
+void permute(void);
+
+void maktab(void);			/*t6.c*/
+void wide(char *, char *, char *);
+int filler(char *);
+
+void runout(void);			/*t7.c*/
+void runtabs(int, int);
+int ifline(char *);
+void need(void);
+void deftail(void);
+
+void putline(int, int);			/*t8.c*/
+void puttext(char *, char *, char *);
+void funnies(int, int);
+void putfont(char *);
+void putsize(char *);
+
+void yetmore(void);			/*t9.c*/
+int domore(char *);
+
+void checkuse(void);			/*tb.c*/
+int real(char *);
+char *chspace(void);
+int *alocv(int);
+void release(void);
+
+void choochar(void);			/*tc.c*/
+int point(char *);
+
+void error(char *);			/*te.c*/
+char *gets1(char *, int);
+void un1getc(int);
+int get1char(void);
+
+void savefill(void);			/*tf.c*/
+void rstofill(void);
+void endoff(void);
+void freearr(void);
+void saveline(void);
+void ifdivert(void);
+void restline(void);
+void cleanfc(void);
+
+int gettext(char *, int, int, char *, char *);		/*tg.c*/
+void untext(void);
+
+int interv(int, int);			/*ti.c*/
+int interh(int, int);
+int up1(int);
+
+char *maknew(char *);			/*tm.c*/
+int ineqn (char *, char *);
+
+char *reg(int, int);			/*tr.c*/
+
+int match (char *, char *);		/*ts.c*/
+int prefix(char *, char *);
+int letter (int);
+int numb(char *);
+int digit(int);
+int max(int, int);
+void tcopy (char *, char *);
+
+int ctype(int, int);			/*tt.c*/
+int min(int, int);
+int fspan(int, int);
+int lspan(int, int);
+int ctspan(int, int);
+void tohcol(int);
+int allh(int);
+int thish(int, int);
+
+void makeline(int, int, int);		/*tu.c*/
+void fullwide(int, int);
+void drawline(int, int, int, int, int, int);
+void getstop(void);
+int left(int, int, int *);
+int lefdata(int, int);
+int next(int);
+int prev(int);
+
+void drawvert(int, int, int, int);			/*tv.c*/
+int midbar(int, int);
+int midbcol(int, int);
+int barent(char *);
blob - /dev/null
blob + 0c0895bdee83d9a322e069f0227a4785d872a3aa (mode 644)
--- /dev/null
+++ src/cmd/tbl/t0.c
@@ -0,0 +1,49 @@
+ /* t0.c: storage allocation */
+#
+# include "t.h"
+int expflg = 0;
+int ctrflg = 0;
+int boxflg = 0;
+int dboxflg = 0;
+int tab = '\t';
+int linsize;
+int pr1403;
+int delim1, delim2;
+int evenflg;
+int *evenup;
+int F1 = 0;
+int F2 = 0;
+int allflg = 0;
+char *leftover = 0;
+int textflg = 0;
+int left1flg = 0;
+int rightl = 0;
+char *cstore, *cspace;
+char *last;
+struct colstr *table[MAXLIN];
+int stynum[MAXLIN+1];
+int fullbot[MAXLIN];
+char *instead[MAXLIN];
+int linestop[MAXLIN];
+int (*style)[MAXHEAD];
+char (*font)[MAXHEAD][2];
+char (*csize)[MAXHEAD][4];
+char (*vsize)[MAXHEAD][4];
+int (*lefline)[MAXHEAD];
+char (*cll)[CLLEN];
+int (*flags)[MAXHEAD];
+int qcol;
+int *doubled, *acase, *topat;
+int nslin, nclin;
+int *sep;
+int *used, *lused, *rused;
+int nlin, ncol;
+int iline = 1;
+char *ifile = "Input";
+int texname = 'a';
+int texct = 0;
+char texstr[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYXZ0123456789";
+int linstart;
+char *exstore, *exlim, *exspace;
+Biobuf *tabin  /*= stdin */;
+Biobuf tabout  /* = stdout */;
blob - /dev/null
blob + 1e6cbf1140ce358f8c5f800685cb984bff664afd (mode 644)
--- /dev/null
+++ src/cmd/tbl/t1.c
@@ -0,0 +1,95 @@
+/* t1.c: main control and input switching */
+#
+# include "t.h"
+
+# define MACROS "/usr/lib/tmac.s"
+# define PYMACS "/usr/lib/tmac.m"
+
+
+# define ever (;;)
+
+void
+main(int argc, char *argv[])
+{
+	exits(tbl(argc, argv)? "error" : 0);
+}
+
+
+int
+tbl(int argc, char *argv[])
+{
+	char	line[5120];
+	/*int x;*/
+	/*x=malloc((char *)0);	uncomment when allocation breaks*/
+	Binit(&tabout, 1, OWRITE);
+	setinp(argc, argv);
+	while (gets1(line, sizeof(line))) {
+		Bprint(&tabout, "%s\n", line);
+		if (prefix(".TS", line))
+			tableput();
+	}
+	Bterm(tabin);
+	return(0);
+}
+
+
+int	sargc;
+char	**sargv;
+
+void
+setinp(int argc, char **argv)
+{
+	sargc = argc;
+	sargv = argv;
+	sargc--; 
+	sargv++;
+	if (sargc > 0)
+		swapin();
+	else {
+		tabin = (Biobuf*)getcore(sizeof(Biobuf), 1);
+		Binit(tabin, 0, OREAD);
+	}
+}
+
+
+int
+swapin(void)
+{
+	char	*name;
+	while (sargc > 0 && **sargv == '-') {
+		if (match("-ms", *sargv)) {
+			*sargv = MACROS;
+			break;
+		}
+		if (match("-mm", *sargv)) {
+			*sargv = PYMACS;
+			break;
+		}
+		if (match("-TX", *sargv))
+			pr1403 = 1;
+		if (match("-", *sargv))
+			break;
+		sargc--; 
+		sargv++;
+	}
+	if (sargc <= 0) 
+		return(0);
+	/* file closing is done by GCOS troff preprocessor */
+	if(tabin)
+		Bterm(tabin);
+	ifile = *sargv;
+	name = ifile;
+	if (match(ifile, "-")) {
+		tabin = (Biobuf*)getcore(sizeof(Biobuf), 1);
+		Binit(tabin, 0, OREAD);
+	} else
+		tabin = Bopen(ifile, OREAD);
+	iline = 1;
+	Bprint(&tabout, ".ds f. %s\n", ifile);
+	Bprint(&tabout, ".lf %d %s\n", iline, name);
+	if (tabin == 0)
+		error("Can't open file");
+	sargc--;
+	sargv++;
+	return(1);
+}
blob - /dev/null
blob + 6d2d7414a77b3275a4860b7d23ffe7095454c534 (mode 644)
--- /dev/null
+++ src/cmd/tbl/t2.c
@@ -0,0 +1,25 @@
+/* t2.c:  subroutine sequencing for one table */
+# include "t.h"
+void
+tableput(void)
+{
+	saveline();
+	savefill();
+	ifdivert();
+	cleanfc();
+	getcomm();
+	getspec();
+	gettbl();
+	getstop();
+	checkuse();
+	choochar();
+	maktab();
+	runout();
+	release();
+	rstofill();
+	endoff();
+	freearr();
+	restline();
+}
+
+
blob - /dev/null
blob + a4dc9f9f536e615eef305576b3e84837c7549b90 (mode 644)
--- /dev/null
+++ src/cmd/tbl/t3.c
@@ -0,0 +1,104 @@
+/* t3.c: interpret commands affecting whole table */
+# include "t.h"
+struct optstr {
+	char	*optnam; 
+	int	*optadd;
+} options [] = {
+	"expand", &expflg,
+	"EXPAND", &expflg,
+	"center", &ctrflg,
+	"CENTER", &ctrflg,
+	"box", &boxflg,
+	"BOX", &boxflg,
+	"allbox", &allflg,
+	"ALLBOX", &allflg,
+	"doublebox", &dboxflg,
+	"DOUBLEBOX", &dboxflg,
+	"frame", &boxflg,
+	"FRAME", &boxflg,
+	"doubleframe", &dboxflg,
+	"DOUBLEFRAME", &dboxflg,
+	"tab", &tab,
+	"TAB", &tab,
+	"linesize", &linsize,
+	"LINESIZE", &linsize,
+	"delim", &delim1,
+	"DELIM", &delim1,
+	0, 0};
+
+
+void
+getcomm(void)
+{
+	char	line[200], *cp, nb[25], *t;
+	struct optstr *lp;
+	int	c, ci, found;
+
+	for (lp = options; lp->optnam; lp++)
+		*(lp->optadd) = 0;
+	texname = texstr[texct=0];
+	tab = '\t';
+	Bprint(&tabout, ".nr %d \\n(.s\n", LSIZE);
+	gets1(line, sizeof(line));
+	/* see if this is a command line */
+	if (strchr(line, ';') == 0) {
+		backrest(line);
+		return;
+	}
+	for (cp = line; (c = *cp) != ';'; cp++) {
+		if (!letter(c)) 
+			continue;
+		found = 0;
+		for (lp = options; lp->optadd; lp++) {
+			if (prefix(lp->optnam, cp)) {
+				*(lp->optadd) = 1;
+				cp += strlen(lp->optnam);
+				if (letter(*cp))
+					error("Misspelled global option");
+				while (*cp == ' ')
+					cp++;
+				t = nb;
+				if ( *cp == '(')
+					while ((ci = *++cp) != ')')
+						*t++ = ci;
+				else 
+					cp--;
+				*t++ = 0; 
+				*t = 0;
+				if (lp->optadd == &tab) {
+					if (nb[0])
+						*(lp->optadd) = nb[0];
+				}
+				if (lp->optadd == &linsize)
+					Bprint(&tabout, ".nr %d %s\n", LSIZE, nb);
+				if (lp->optadd == &delim1) {
+					delim1 = nb[0];
+					delim2 = nb[1];
+				}
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			error("Illegal option");
+	}
+	cp++;
+	backrest(cp);
+	return;
+}
+
+
+void
+backrest(char *cp)
+{
+	char	*s;
+
+	for (s = cp; *s; s++)
+		;
+	un1getc('\n');
+	while (s > cp)
+		un1getc(*--s);
+	return;
+}
+
+
blob - /dev/null
blob + 558d3ba3ab9246e78901081cf0b6159f69d12343 (mode 644)
--- /dev/null
+++ src/cmd/tbl/t4.c
@@ -0,0 +1,405 @@
+/* t4.c: read table specification */
+# include "t.h"
+int	oncol;
+
+void
+getspec(void)
+{
+	int	icol, i;
+
+	qcol = findcol() + 1;/* must allow one extra for line at right */
+	garray(qcol);
+	sep[-1] = -1;
+	for (icol = 0; icol < qcol; icol++) {
+		sep[icol] = -1;
+		evenup[icol] = 0;
+		cll[icol][0] = 0;
+		for (i = 0; i < MAXHEAD; i++) {
+			csize[icol][i][0] = 0;
+			vsize[icol][i][0] = 0;
+			font[icol][i][0] = lefline[icol][i] = 0;
+			flags[icol][i] = 0;
+			style[icol][i] = 'l';
+		}
+	}
+	for (i = 0; i < MAXHEAD; i++)
+		lefline[qcol][i] = 0;	/* fixes sample55 looping */
+	nclin = ncol = 0;
+	oncol = 0;
+	left1flg = rightl = 0;
+	readspec();
+	Bprint(&tabout, ".rm");
+	for (i = 0; i < ncol; i++)
+		Bprint(&tabout, " %2s", reg(i, CRIGHT));
+	Bprint(&tabout, "\n");
+}
+
+
+void
+readspec(void)
+{
+	int	icol, c, sawchar, stopc, i;
+	char	sn[10], *snp, *temp;
+
+	sawchar = icol = 0;
+	while (c = get1char()) {
+		switch (c) {
+		default:
+			if (c != tab) {
+				char buf[64];
+				sprint(buf, "bad table specification character %c", c);
+				error(buf);
+			}
+		case ' ': /* note this is also case tab */
+			continue;
+		case '\n':
+			if (sawchar == 0) 
+				continue;
+		case ',':
+		case '.': /* end of table specification */
+			ncol = max(ncol, icol);
+			if (lefline[ncol][nclin] > 0) {
+				ncol++; 
+				rightl++;
+			};
+			if (sawchar)
+				nclin++;
+			if (nclin >= MAXHEAD)
+				error("too many lines in specification");
+			icol = 0;
+			if (ncol == 0 || nclin == 0)
+				error("no specification");
+			if (c == '.') {
+				while ((c = get1char()) && c != '\n')
+					if (c != ' ' && c != '\t')
+						error("dot not last character on format line");
+				/* fix up sep - default is 3 except at edge */
+				for (icol = 0; icol < ncol; icol++)
+					if (sep[icol] < 0)
+						sep[icol] =  icol + 1 < ncol ? 3 : 2;
+				if (oncol == 0)
+					oncol = ncol;
+				else if (oncol + 2 < ncol)
+					error("tried to widen table in T&, not allowed");
+				return;
+			}
+			sawchar = 0;
+			continue;
+		case 'C': 
+		case 'S': 
+		case 'R': 
+		case 'N': 
+		case 'L':  
+		case 'A':
+			c += ('a' - 'A');
+		case '_': 
+			if (c == '_') 
+				c = '-';
+		case '=': 
+		case '-':
+		case '^':
+		case 'c': 
+		case 's': 
+		case 'n': 
+		case 'r': 
+		case 'l':  
+		case 'a':
+			style[icol][nclin] = c;
+			if (c == 's' && icol <= 0)
+				error("first column can not be S-type");
+			if (c == 's' && style[icol-1][nclin] == 'a') {
+				Bprint(&tabout, ".tm warning: can't span a-type cols, changed to l\n");
+				style[icol-1][nclin] = 'l';
+			}
+			if (c == 's' && style[icol-1][nclin] == 'n') {
+				Bprint(&tabout, ".tm warning: can't span n-type cols, changed to c\n");
+				style[icol-1][nclin] = 'c';
+			}
+			icol++;
+			if (c == '^' && nclin <= 0)
+				error("first row can not contain vertical span");
+			if (icol > qcol)
+				error("too many columns in table");
+			sawchar = 1;
+			continue;
+		case 'b': 
+		case 'i':
+			c += 'A' - 'a';
+		case 'B': 
+		case 'I':
+			if (icol == 0) 
+				continue;
+			snp = font[icol-1][nclin];
+			snp[0] = (c == 'I' ? '2' : '3');
+			snp[1] = 0;
+			continue;
+		case 't': 
+		case 'T':
+			if (icol > 0)
+				flags[icol-1][nclin] |= CTOP;
+			continue;
+		case 'd': 
+		case 'D':
+			if (icol > 0)
+				flags[icol-1][nclin] |= CDOWN;
+			continue;
+		case 'f': 
+		case 'F':
+			if (icol == 0) 
+				continue;
+			snp = font[icol-1][nclin];
+			snp[0] = snp[1] = stopc = 0;
+			for (i = 0; i < 2; i++) {
+				c = get1char();
+				if (i == 0 && c == '(') {
+					stopc = ')';
+					c = get1char();
+				}
+				if (c == 0) 
+					break;
+				if (c == stopc) {
+					stopc = 0; 
+					break;
+				}
+				if (stopc == 0)  
+					if (c == ' ' || c == tab ) 
+						break;
+				if (c == '\n' || c == '|') {
+					un1getc(c); 
+					break;
+				}
+				snp[i] = c;
+				if (c >= '0' && c <= '9') 
+					break;
+			}
+			if (stopc) 
+				if (get1char() != stopc)
+					error("Nonterminated font name");
+			continue;
+		case 'P': 
+		case 'p':
+			if (icol <= 0) 
+				continue;
+			temp = snp = csize[icol-1][nclin];
+			while (c = get1char()) {
+				if (c == ' ' || c == tab || c == '\n') 
+					break;
+				if (c == '-' || c == '+')
+					if (snp > temp)
+						break;
+					else
+						*snp++ = c;
+				else if (digit(c))
+					*snp++ = c;
+				else 
+					break;
+				if (snp - temp > 4)
+					error("point size too large");
+			}
+			*snp = 0;
+			if (atoi(temp) > 36)
+				error("point size unreasonable");
+			un1getc (c);
+			continue;
+		case 'V': 
+		case 'v':
+			if (icol <= 0) 
+				continue;
+			temp = snp = vsize[icol-1][nclin];
+			while (c = get1char()) {
+				if (c == ' ' || c == tab || c == '\n') 
+					break;
+				if (c == '-' || c == '+')
+					if (snp > temp)
+						break;
+					else
+						*snp++ = c;
+				else if (digit(c))
+					*snp++ = c;
+				else 
+					break;
+				if (snp - temp > 4)
+					error("vertical spacing value too large");
+			}
+			*snp = 0;
+			un1getc(c);
+			continue;
+		case 'w': 
+		case 'W':
+			snp = cll [icol-1];
+			/* Dale Smith didn't like this check - possible to have two text blocks
+		   of different widths now ....
+			if (*snp)
+				{
+				Bprint(&tabout, "Ignored second width specification");
+				continue;
+				}
+		/* end commented out code ... */
+			stopc = 0;
+			while (c = get1char()) {
+				if (snp == cll[icol-1] && c == '(') {
+					stopc = ')';
+					continue;
+				}
+				if ( !stopc && (c > '9' || c < '0'))
+					break;
+				if (stopc && c == stopc)
+					break;
+				*snp++ = c;
+			}
+			*snp = 0;
+			if (snp - cll[icol-1] > CLLEN)
+				error ("column width too long");
+			if (!stopc)
+				un1getc(c);
+			continue;
+		case 'e': 
+		case 'E':
+			if (icol < 1) 
+				continue;
+			evenup[icol-1] = 1;
+			evenflg = 1;
+			continue;
+		case 'z': 
+		case 'Z': /* zero width-ignre width this item */
+			if (icol < 1) 
+				continue;
+			flags[icol-1][nclin] |= ZEROW;
+			continue;
+		case 'u': 
+		case 'U': /* half line up */
+			if (icol < 1) 
+				continue;
+			flags[icol-1][nclin] |= HALFUP;
+			continue;
+		case '0': 
+		case '1': 
+		case '2': 
+		case '3': 
+		case '4':
+		case '5': 
+		case '6': 
+		case '7': 
+		case '8': 
+		case '9':
+			sn[0] = c;
+			snp = sn + 1;
+			while (digit(*snp++ = c = get1char()))
+				;
+			un1getc(c);
+			sep[icol-1] = max(sep[icol-1], numb(sn));
+			continue;
+		case '|':
+			lefline[icol][nclin]++;
+			if (icol == 0) 
+				left1flg = 1;
+			continue;
+		}
+	}
+	error("EOF reading table specification");
+}
+
+
+int
+findcol(void)
+{
+# define FLNLIM 200
+	/* this counts the number of columns and then puts the line back*/
+	char	*s, line[FLNLIM+2], *p;
+	int	c, n = 0, inpar = 0;
+
+	while ((c = get1char()) != 0 && c == ' ')
+		;
+	if (c != '\n')
+		un1getc(c);
+	for (s = line; *s = c = get1char(); s++) {
+		if (c == ')') 
+			inpar = 0;
+		if (inpar) 
+			continue;
+		if (c == '\n' || c == 0 || c == '.' || c == ',')
+			break;
+		else if (c == '(')
+			inpar = 1;
+		else if (s >= line + FLNLIM)
+			error("too long spec line");
+	}
+	for (p = line; p < s; p++)
+		switch (*p) {
+		case 'l': 
+		case 'r': 
+		case 'c': 
+		case 'n': 
+		case 'a': 
+		case 's':
+		case 'L': 
+		case 'R': 
+		case 'C': 
+		case 'N': 
+		case 'A': 
+		case 'S':
+		case '-': 
+		case '=': 
+		case '_':
+			n++;
+		}
+	while (p >= line)
+		un1getc(*p--);
+	return(n);
+}
+
+
+void
+garray(int qcol)
+{
+	style =  (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int));
+	evenup = (int *) getcore(qcol, sizeof(int));
+	lefline = (int (*)[]) getcore(MAXHEAD * (qcol + 1), sizeof (int)); /*+1 for sample55 loop - others may need it too*/
+	font = (char (*)[][2]) getcore(MAXHEAD * qcol, 2);
+	csize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4);
+	vsize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4);
+	flags =  (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int));
+	cll = (char (*)[])getcore(qcol, CLLEN);
+	sep = (int *) getcore(qcol + 1, sizeof(int));
+	sep++; /* sep[-1] must be legal */
+	used = (int *) getcore(qcol + 1, sizeof(int));
+	lused = (int *) getcore(qcol + 1, sizeof(int));
+	rused = (int *) getcore(qcol + 1, sizeof(int));
+	doubled = (int *) getcore(qcol + 1, sizeof(int));
+	acase = (int *) getcore(qcol + 1, sizeof(int));
+	topat = (int *) getcore(qcol + 1, sizeof(int));
+}
+
+
+char	*
+getcore(int a, int b)
+{
+	char	*x;
+	x = calloc(a, b);
+	if (x == 0)
+		error("Couldn't get memory");
+	return(x);
+}
+
+
+void
+freearr(void)
+{
+	free(style);
+	free(evenup);
+	free(lefline);
+	free(flags);
+	free(font);
+	free(csize);
+	free(vsize);
+	free(cll);
+	free(--sep);	/* netnews says this should be --sep because incremented earlier! */
+	free(used);
+	free(lused);
+	free(rused);
+	free(doubled);
+	free(acase);
+	free(topat);
+}
+
+
blob - /dev/null
blob + 8b7a65d8ffc9083baaee45d75d95aa3f83b053d3 (mode 644)
--- /dev/null
+++ src/cmd/tbl/t5.c
@@ -0,0 +1,198 @@
+/* t5.c: read data for table */
+# include "t.h"
+
+void
+gettbl(void)
+{
+	int	icol, ch;
+
+	cstore = cspace = chspace();
+	textflg = 0;
+	for (nlin = nslin = 0; gets1(cstore, MAXCHS - (cstore - cspace)); nlin++) {
+		stynum[nlin] = nslin;
+		if (prefix(".TE", cstore)) {
+			leftover = 0;
+			break;
+		}
+		if (prefix(".TC", cstore) || prefix(".T&", cstore)) {
+			readspec();
+			nslin++;
+		}
+		if (nlin >= MAXLIN) {
+			leftover = cstore;
+			break;
+		}
+		fullbot[nlin] = 0;
+		if (cstore[0] == '.' && !isdigit(cstore[1])) {
+			instead[nlin] = cstore;
+			while (*cstore++)
+				;
+			continue;
+		} else 
+			instead[nlin] = 0;
+		if (nodata(nlin)) {
+			if (ch = oneh(nlin))
+				fullbot[nlin] = ch;
+			table[nlin] = (struct colstr *) alocv((ncol + 2) * sizeof(table[0][0]));
+			for (icol = 0; icol < ncol; icol++) {
+				table[nlin][icol].rcol = "";
+				table[nlin][icol].col = "";
+			}
+			nlin++;
+			nslin++;
+			fullbot[nlin] = 0;
+			instead[nlin] = (char *) 0;
+		}
+		table[nlin] = (struct colstr *) alocv((ncol + 2) * sizeof(table[0][0]));
+		if (cstore[1] == 0)
+			switch (cstore[0]) {
+			case '_': 
+				fullbot[nlin] = '-'; 
+				continue;
+			case '=': 
+				fullbot[nlin] = '='; 
+				continue;
+			}
+		stynum[nlin] = nslin;
+		nslin = min(nslin + 1, nclin - 1);
+		for (icol = 0; icol < ncol; icol++) {
+			table[nlin][icol].col = cstore;
+			table[nlin][icol].rcol = 0;
+			ch = 1;
+			if (match(cstore, "T{")) { /* text follows */
+				table[nlin][icol].col = 
+				    (char *)gettext(cstore, nlin, icol,
+				    font[icol][stynum[nlin]],
+				    csize[icol][stynum[nlin]]);
+			} else
+			 {
+				for (; (ch = *cstore) != '\0' && ch != tab; cstore++)
+					;
+				*cstore++ = '\0';
+				switch (ctype(nlin, icol)) /* numerical or alpha, subcol */ {
+				case 'n':
+					table[nlin][icol].rcol = maknew(table[nlin][icol].col);
+					break;
+				case 'a':
+					table[nlin][icol].rcol = table[nlin][icol].col;
+					table[nlin][icol].col = "";
+					break;
+				}
+			}
+			while (ctype(nlin, icol + 1) == 's') /* spanning */
+				table[nlin][++icol].col = "";
+			if (ch == '\0') 
+				break;
+		}
+		while (++icol < ncol + 2) {
+			table[nlin][icol].col = "";
+			table [nlin][icol].rcol = 0;
+		}
+		while (*cstore != '\0')
+			cstore++;
+		if (cstore - cspace + MAXLINLEN > MAXCHS)
+			cstore = cspace = chspace();
+	}
+	last = cstore;
+	permute();
+	if (textflg) 
+		untext();
+	return;
+}
+
+
+int
+nodata(int il)
+{
+	int	c;
+
+	for (c = 0; c < ncol; c++) {
+		switch (ctype(il, c)) {
+		case 'c': 
+		case 'n': 
+		case 'r': 
+		case 'l': 
+		case 's': 
+		case 'a':
+			return(0);
+		}
+	}
+	return(1);
+}
+
+
+int
+oneh(int lin)
+{
+	int	k, icol;
+
+	k = ctype(lin, 0);
+	for (icol = 1; icol < ncol; icol++) {
+		if (k != ctype(lin, icol))
+			return(0);
+	}
+	return(k);
+}
+
+
+# define SPAN "\\^"
+
+void
+permute(void)
+{
+	int	irow, jcol, is;
+	char	*start, *strig;
+
+	for (jcol = 0; jcol < ncol; jcol++) {
+		for (irow = 1; irow < nlin; irow++) {
+			if (vspand(irow, jcol, 0)) {
+				is = prev(irow);
+				if (is < 0)
+					error("Vertical spanning in first row not allowed");
+				start = table[is][jcol].col;
+				strig = table[is][jcol].rcol;
+				while (irow < nlin && vspand(irow, jcol, 0))
+					irow++;
+				table[--irow][jcol].col = start;
+				table[irow][jcol].rcol = strig;
+				while (is < irow) {
+					table[is][jcol].rcol = 0;
+					table[is][jcol].col = SPAN;
+					is = next(is);
+				}
+			}
+		}
+	}
+}
+
+
+int
+vspand(int ir, int ij, int ifform)
+{
+	if (ir < 0) 
+		return(0);
+	if (ir >= nlin)
+		return(0);
+	if (instead[ir]) 
+		return(0);
+	if (ifform == 0 && ctype(ir, ij) == '^') 
+		return(1);
+	if (table[ir][ij].rcol != 0) 
+		return(0);
+	if (fullbot[ir]) 
+		return(0);
+	return(vspen(table[ir][ij].col));
+}
+
+
+int
+vspen(char *s)
+{
+	if (s == 0) 
+		return(0);
+	if (!point(s)) 
+		return(0);
+	return(match(s, SPAN));
+}
+
+
blob - /dev/null
blob + a78368fcc564fb2cc8e3b79b3afc1fc60a19f311 (mode 644)
--- /dev/null
+++ src/cmd/tbl/t6.c
@@ -0,0 +1,223 @@
+/* t6.c: compute tab stops */
+# define tx(a) (a>0 && a<128)
+# include "t.h"
+# define FN(i,c) font[c][stynum[i]]
+# define SZ(i,c) csize[c][stynum[i]]
+# define TMP1 S1
+# define TMP2 S2
+
+void
+maktab(void)			/* define the tab stops of the table */
+{
+	int	icol, ilin, tsep, k, ik, vforml, il, text;
+	char	*s;
+
+	for (icol = 0; icol < ncol; icol++) {
+		doubled[icol] = acase[icol] = 0;
+		Bprint(&tabout, ".nr %2s 0\n", reg(icol, CRIGHT));
+		for (text = 0; text < 2; text++) {
+			if (text)
+				Bprint(&tabout, ".%2s\n.rm %2s\n", reg(icol, CRIGHT),
+				    reg(icol, CRIGHT));
+			for (ilin = 0; ilin < nlin; ilin++) {
+				if (instead[ilin] || fullbot[ilin]) 
+					continue;
+				vforml = ilin;
+				for (il = prev(ilin); il >= 0 && vspen(table[il][icol].col); il = prev(il))
+					vforml = il;
+				if (fspan(vforml, icol)) 
+					continue;
+				if (filler(table[ilin][icol].col)) 
+					continue;
+				if ((flags[icol][stynum[ilin]] & ZEROW) != 0) 
+					continue;
+				switch (ctype(vforml, icol)) {
+				case 'a':
+					acase[icol] = 1;
+					s = table[ilin][icol].col;
+					if ((int)s > 0 && (int)s < 128 && text) {
+						if (doubled[icol] == 0)
+							Bprint(&tabout, ".nr %d 0\n.nr %d 0\n",
+							    S1, S2);
+						doubled[icol] = 1;
+						Bprint(&tabout, ".if \\n(%c->\\n(%d .nr %d \\n(%c-\n",
+						    (int)s, S2, S2, (int)s);
+					}
+				case 'n':
+					if (table[ilin][icol].rcol != 0) {
+						if (doubled[icol] == 0 && text == 0)
+							Bprint(&tabout, ".nr %d 0\n.nr %d 0\n",
+							    S1, S2);
+						doubled[icol] = 1;
+						if (real(s = table[ilin][icol].col) && !vspen(s)) {
+							if (tx((int)s) != text) 
+								continue;
+							Bprint(&tabout, ".nr %d ", TMP);
+							wide(s, FN(vforml, icol), SZ(vforml, icol)); 
+							Bprint(&tabout, "\n");
+							Bprint(&tabout, ".if \\n(%d<\\n(%d .nr %d \\n(%d\n",
+							    S1, TMP, S1, TMP);
+						}
+						if (text == 0 && real(s = table[ilin][icol].rcol) && !vspen(s) && !barent(s)) {
+							Bprint(&tabout, ".nr %d \\w%c%s%c\n",
+							    TMP, F1, s, F1);
+							Bprint(&tabout, ".if \\n(%d<\\n(%d .nr %d \\n(%d\n", S2, TMP, S2,
+							     TMP);
+						}
+						continue;
+					}
+				case 'r':
+				case 'c':
+				case 'l':
+					if (real(s = table[ilin][icol].col) && !vspen(s)) {
+						if (tx((int)s) != text) 
+							continue;
+						Bprint(&tabout, ".nr %d ", TMP);
+						wide(s, FN(vforml, icol), SZ(vforml, icol)); 
+						Bprint(&tabout, "\n");
+						Bprint(&tabout, ".if \\n(%2s<\\n(%d .nr %2s \\n(%d\n",
+						     reg(icol, CRIGHT), TMP, reg(icol, CRIGHT), TMP);
+					}
+				}
+			}
+		}
+		if (acase[icol]) {
+			Bprint(&tabout, ".if \\n(%d>=\\n(%2s .nr %2s \\n(%du+2n\n", 
+			     S2, reg(icol, CRIGHT), reg(icol, CRIGHT), S2);
+		}
+		if (doubled[icol]) {
+			Bprint(&tabout, ".nr %2s \\n(%d\n", reg(icol, CMID), S1);
+			Bprint(&tabout, ".nr %d \\n(%2s+\\n(%d\n", TMP, reg(icol, CMID), S2);
+			Bprint(&tabout, ".if \\n(%d>\\n(%2s .nr %2s \\n(%d\n", TMP,
+			    reg(icol, CRIGHT), reg(icol, CRIGHT), TMP);
+			Bprint(&tabout, ".if \\n(%d<\\n(%2s .nr %2s +(\\n(%2s-\\n(%d)/2\n",
+			     TMP, reg(icol, CRIGHT), reg(icol, CMID), reg(icol, CRIGHT), TMP);
+		}
+		if (cll[icol][0]) {
+			Bprint(&tabout, ".nr %d %sn\n", TMP, cll[icol]);
+			Bprint(&tabout, ".if \\n(%2s<\\n(%d .nr %2s \\n(%d\n",
+			    reg(icol, CRIGHT), TMP, reg(icol, CRIGHT), TMP);
+		}
+		for (ilin = 0; ilin < nlin; ilin++)
+			if (k = lspan(ilin, icol)) {
+				s = table[ilin][icol-k].col;
+				if (!real(s) || barent(s) || vspen(s) ) 
+					continue;
+				Bprint(&tabout, ".nr %d ", TMP);
+				wide(table[ilin][icol-k].col, FN(ilin, icol - k), SZ(ilin, icol - k));
+				for (ik = k; ik >= 0; ik--) {
+					Bprint(&tabout, "-\\n(%2s", reg(icol - ik, CRIGHT));
+					if (!expflg && ik > 0) 
+						Bprint(&tabout, "-%dn", sep[icol-ik]);
+				}
+				Bprint(&tabout, "\n");
+				Bprint(&tabout, ".if \\n(%d>0 .nr %d \\n(%d/%d\n", TMP,
+				      TMP, TMP, k);
+				Bprint(&tabout, ".if \\n(%d<0 .nr %d 0\n", TMP, TMP);
+				for (ik = 1; ik <= k; ik++) {
+					if (doubled[icol-k+ik])
+						Bprint(&tabout, ".nr %2s +\\n(%d/2\n",
+						     reg(icol - k + ik, CMID), TMP);
+					Bprint(&tabout, ".nr %2s +\\n(%d\n",
+					     reg(icol - k + ik, CRIGHT), TMP);
+				}
+			}
+	}
+	if (textflg) 
+		untext();
+				/* if even requested, make all columns widest width */
+	if (evenflg) {
+		Bprint(&tabout, ".nr %d 0\n", TMP);
+		for (icol = 0; icol < ncol; icol++) {
+			if (evenup[icol] == 0) 
+				continue;
+			Bprint(&tabout, ".if \\n(%2s>\\n(%d .nr %d \\n(%2s\n",
+			    reg(icol, CRIGHT), TMP, TMP, reg(icol, CRIGHT));
+		}
+		for (icol = 0; icol < ncol; icol++) {
+			if (evenup[icol] == 0)
+				/* if column not evened just retain old interval */
+				continue;
+			if (doubled[icol])
+				Bprint(&tabout, ".nr %2s (100*\\n(%2s/\\n(%2s)*\\n(%d/100\n",
+				    reg(icol, CMID), reg(icol, CMID), reg(icol, CRIGHT), TMP);
+			/* that nonsense with the 100's and parens tries
+				   to avoid overflow while proportionally shifting
+				   the middle of the number */
+			Bprint(&tabout, ".nr %2s \\n(%d\n", reg(icol, CRIGHT), TMP);
+		}
+	}
+				/* now adjust for total table width */
+	for (tsep = icol = 0; icol < ncol; icol++)
+		tsep += sep[icol];
+	if (expflg) {
+		Bprint(&tabout, ".nr %d 0", TMP);
+		for (icol = 0; icol < ncol; icol++)
+			Bprint(&tabout, "+\\n(%2s", reg(icol, CRIGHT));
+		Bprint(&tabout, "\n");
+		Bprint(&tabout, ".nr %d \\n(.l-\\n(%d\n", TMP, TMP);
+		if (boxflg || dboxflg || allflg)
+			/* tsep += 1; */ {}
+		else
+			tsep -= sep[ncol-1];
+		Bprint(&tabout, ".nr %d \\n(%d/%d\n", TMP, TMP,  tsep);
+		Bprint(&tabout, ".if \\n(%d<0 .nr %d 0\n", TMP, TMP);
+	} else
+		Bprint(&tabout, ".nr %d 1n\n", TMP);
+	Bprint(&tabout, ".nr %2s 0\n", reg(-1, CRIGHT));
+	tsep = (boxflg || allflg || dboxflg || left1flg) ? 2 : 0;
+	if (sep[-1] >= 0) 
+		tsep = sep[-1];
+	for (icol = 0; icol < ncol; icol++) {
+		Bprint(&tabout, ".nr %2s \\n(%2s+((%d*\\n(%d)/2)\n", reg(icol, CLEFT),
+		    reg(icol - 1, CRIGHT), tsep, TMP);
+		Bprint(&tabout, ".nr %2s +\\n(%2s\n", reg(icol, CRIGHT), reg(icol, CLEFT));
+		if (doubled[icol]) {
+			/* the next line is last-ditch effort to avoid zero field width */
+			/*Bprint(&tabout, ".if \\n(%2s=0 .nr %2s 1\n",reg(icol,CMID), reg(icol,CMID));*/
+			Bprint(&tabout, ".nr %2s +\\n(%2s\n", reg(icol, CMID),
+			    reg(icol, CLEFT));
+			/*  Bprint(&tabout, ".if n .if \\n(%s%%24>0 .nr %s +12u\n",reg(icol,CMID), reg(icol,CMID)); */
+		}
+		tsep = sep[icol] * 2;
+	}
+	if (rightl)
+		Bprint(&tabout, ".nr %s (\\n(%s+\\n(%s)/2\n", reg(ncol - 1, CRIGHT),
+		      reg(ncol - 1, CLEFT), reg(ncol - 2, CRIGHT));
+	Bprint(&tabout, ".nr TW \\n(%2s\n", reg(ncol - 1, CRIGHT));
+	tsep = sep[ncol-1];
+	if (boxflg || allflg || dboxflg)
+		Bprint(&tabout, ".nr TW +((%d*\\n(%d)/2)\n", tsep, TMP);
+	Bprint(&tabout,
+	    ".if t .if (\\n(TW+\\n(.o)>7.65i .tm Table at line %d file %s is too wide - \\n(TW units\n", iline - 1, ifile);
+	return;
+}
+
+
+void
+wide(char *s, char *fn, char *size)
+{
+	if (point(s)) {
+		Bprint(&tabout, "\\w%c", F1);
+		if (*fn > 0) 
+			putfont(fn);
+		if (*size) 
+			putsize(size);
+		Bprint(&tabout, "%s", s);
+		if (*fn > 0) 
+			putfont("P");
+		if (*size) 
+			putsize("0");
+		Bprint(&tabout, "%c", F1);
+	} else
+		Bprint(&tabout, "\\n(%c-", (int)s);
+}
+
+
+int
+filler(char *s)
+{
+	return (point(s) && s[0] == '\\' && s[1] == 'R');
+}
+
+
blob - /dev/null
blob + 2fa9de53bbfcc30b7b04135f7d22bf590983795f (mode 644)
--- /dev/null
+++ src/cmd/tbl/t7.c
@@ -0,0 +1,150 @@
+/* t7.c: control to write table entries */
+# include "t.h"
+# define realsplit ((ct=='a'||ct=='n') && table[ldata][c].rcol)
+
+void
+runout(void)
+{
+	int	i;
+
+	if (boxflg || allflg || dboxflg) 
+		need();
+	if (ctrflg) {
+		Bprint(&tabout, ".nr #I \\n(.i\n");
+		Bprint(&tabout, ".in +(\\n(.lu-\\n(TWu-\\n(.iu)/2u\n");
+	}
+	Bprint(&tabout, ".fc %c %c\n", F1, F2);
+	Bprint(&tabout, ".nr #T 0-1\n");
+	deftail();
+	for (i = 0; i < nlin; i++)
+		putline(i, i);
+	if (leftover)
+		yetmore();
+	Bprint(&tabout, ".fc\n");
+	Bprint(&tabout, ".nr T. 1\n");
+	Bprint(&tabout, ".T# 1\n");
+	if (ctrflg)
+		Bprint(&tabout, ".in \\n(#Iu\n");
+}
+
+
+void
+runtabs(int lform, int ldata)
+{
+	int	c, ct, vforml, lf;
+
+	Bprint(&tabout, ".ta ");
+	for (c = 0; c < ncol; c++) {
+		vforml = lform;
+		for (lf = prev(lform); lf >= 0 && vspen(table[lf][c].col); lf = prev(lf))
+			vforml = lf;
+		if (fspan(vforml, c))
+			continue;
+		switch (ct = ctype(vforml, c)) {
+		case 'n':
+		case 'a':
+			if (table[ldata][c].rcol)
+				if (lused[c]) /*Zero field width*/
+					Bprint(&tabout, "\\n(%2su ", reg(c, CMID));
+		case 'c':
+		case 'l':
+		case 'r':
+			if (realsplit ? rused[c] : (used[c] + lused[c]))
+				Bprint(&tabout, "\\n(%2su ", reg(c, CRIGHT));
+			continue;
+		case 's':
+			if (lspan(lform, c))
+				Bprint(&tabout, "\\n(%2su ", reg(c, CRIGHT));
+			continue;
+		}
+	}
+	Bprint(&tabout, "\n");
+}
+
+
+int
+ifline(char *s)
+{
+	if (!point(s)) 
+		return(0);
+	if (s[0] == '\\') 
+		s++;
+	if (s[1] ) 
+		return(0);
+	if (s[0] == '_') 
+		return('-');
+	if (s[0] == '=') 
+		return('=');
+	return(0);
+}
+
+
+void
+need(void)
+{
+	int	texlin, horlin, i;
+
+	for (texlin = horlin = i = 0; i < nlin; i++) {
+		if (fullbot[i] != 0)
+			horlin++;
+		else if (instead[i] != 0)
+			continue;
+		else
+			texlin++;
+	}
+	Bprint(&tabout, ".ne %dv+%dp\n", texlin, 2 * horlin);
+}
+
+
+void
+deftail(void)
+{
+	int	i, c, lf, lwid;
+
+	for (i = 0; i < MAXHEAD; i++)
+		if (linestop[i])
+			Bprint(&tabout, ".nr #%c 0-1\n", linestop[i] + 'a' - 1);
+	Bprint(&tabout, ".nr #a 0-1\n");
+	Bprint(&tabout, ".eo\n");
+	Bprint(&tabout, ".de T#\n");
+	Bprint(&tabout, ".nr 35 1m\n");
+	Bprint(&tabout, ".ds #d .d\n");
+	Bprint(&tabout, ".if \\(ts\\n(.z\\(ts\\(ts .ds #d nl\n");
+	Bprint(&tabout, ".mk ##\n");
+	Bprint(&tabout, ".nr ## -1v\n");
+	Bprint(&tabout, ".ls 1\n");
+	for (i = 0; i < MAXHEAD; i++)
+		if (linestop[i])
+			Bprint(&tabout, ".if \\n(#T>=0 .nr #%c \\n(#T\n",
+			     linestop[i] + 'a' - 1);
+	if (boxflg || allflg || dboxflg) /* bottom of table line */
+		if (fullbot[nlin-1] == 0) {
+			if (!pr1403)
+				Bprint(&tabout, ".if \\n(T. .vs \\n(.vu-\\n(.sp\n");
+			Bprint(&tabout, ".if \\n(T. ");
+			drawline(nlin, 0, ncol, dboxflg ? '=' : '-', 1, 0);
+			Bprint(&tabout, "\n.if \\n(T. .vs\n");
+			/* T. is really an argument to a macro but because of 
+		   eqn we don't dare pass it as an argument and reference by $1 */
+		}
+	for (c = 0; c < ncol; c++) {
+		if ((lf = left(nlin - 1, c, &lwid)) >= 0) {
+			Bprint(&tabout, ".if \\n(#%c>=0 .sp -1\n", linestop[lf] + 'a' - 1);
+			Bprint(&tabout, ".if \\n(#%c>=0 ", linestop[lf] + 'a' - 1);
+			tohcol(c);
+			drawvert(lf, nlin - 1, c, lwid);
+			Bprint(&tabout, "\\h'|\\n(TWu'\n");
+		}
+	}
+	if (boxflg || allflg || dboxflg) /* right hand line */ {
+		Bprint(&tabout, ".if \\n(#a>=0 .sp -1\n");
+		Bprint(&tabout, ".if \\n(#a>=0 \\h'|\\n(TWu'");
+		drawvert (0, nlin - 1, ncol, dboxflg ? 2 : 1);
+		Bprint(&tabout, "\n");
+	}
+	Bprint(&tabout, ".ls\n");
+	Bprint(&tabout, "..\n");
+	Bprint(&tabout, ".ec\n");
+}
+
+
blob - /dev/null
blob + 92277e2a8c4453ba7654c789acba4176f76a2328 (mode 644)
--- /dev/null
+++ src/cmd/tbl/t8.c
@@ -0,0 +1,367 @@
+/* t8.c: write out one line of output table */
+# include "t.h"
+# define realsplit ((ct=='a'||ct=='n') && table[nl][c].rcol)
+int	watchout;
+int	once;
+
+void
+putline(int i, int nl)
+				/* i is line number for deciding format */
+				/* nl is line number for finding data   usually identical */
+{
+	int	c, lf, ct, form, lwid, vspf, ip, cmidx, exvspen, vforml;
+	int	vct, chfont, uphalf;
+	char	*s, *size, *fn, *rct;
+
+	cmidx = watchout = vspf = exvspen = 0;
+	if (i == 0) 
+		once = 0;
+	if (i == 0 && ( allflg || boxflg || dboxflg))
+		fullwide(0,   dboxflg ? '=' : '-');
+	if (instead[nl] == 0 && fullbot[nl] == 0)
+		for (c = 0; c < ncol; c++) {
+			s = table[nl][c].col;
+			if (s == 0) 
+				continue;
+			if (vspen(s)) {
+				for (ip = nl; ip < nlin; ip = next(ip))
+					if (!vspen(s = table[ip][c].col)) 
+						break;
+				if ((int)s > 0 && (int)s < 128)
+					Bprint(&tabout, ".ne \\n(%c|u+\\n(.Vu\n", (int)s);
+				continue;
+			}
+			if (point(s)) 
+				continue;
+			Bprint(&tabout, ".ne \\n(%c|u+\\n(.Vu\n", (int)s);
+			watchout = 1;
+		}
+	if (linestop[nl])
+		Bprint(&tabout, ".mk #%c\n", linestop[nl] + 'a' - 1);
+	lf = prev(nl);
+	if (instead[nl]) {
+		Bprint(&tabout, "%s\n", instead[nl]);
+		return;
+	}
+	if (fullbot[nl]) {
+		switch (ct = fullbot[nl]) {
+		case '=':
+		case '-':
+			fullwide(nl, ct);
+		}
+		return;
+	}
+	for (c = 0; c < ncol; c++) {
+		if (instead[nl] == 0 && fullbot[nl] == 0)
+			if (vspen(table[nl][c].col)) 
+				vspf = 1;
+		if (lf >= 0)
+			if (vspen(table[lf][c].col)) 
+				vspf = 1;
+	}
+	if (vspf) {
+		Bprint(&tabout, ".nr #^ \\n(\\*(#du\n");
+		Bprint(&tabout, ".nr #- \\n(#^\n"); /* current line position relative to bottom */
+	}
+	vspf = 0;
+	chfont = 0;
+	for (c = 0; c < ncol; c++) {
+		s = table[nl][c].col;
+		if (s == 0) 
+			continue;
+		chfont |= (int)(font[c][stynum[nl]]);
+		if (point(s) ) 
+			continue;
+		lf = prev(nl);
+		if (lf >= 0 && vspen(table[lf][c].col))
+			Bprint(&tabout,
+			   ".if (\\n(%c|+\\n(^%c-1v)>\\n(#- .nr #- +(\\n(%c|+\\n(^%c-\\n(#--1v)\n",
+			    (int)s, 'a' + c, (int)s, 'a' + c);
+		else
+			Bprint(&tabout,
+			    ".if (\\n(%c|+\\n(#^-1v)>\\n(#- .nr #- +(\\n(%c|+\\n(#^-\\n(#--1v)\n",
+			    (int)s, (int)s);
+	}
+	if (allflg && once > 0 )
+		fullwide(i, '-');
+	once = 1;
+	runtabs(i, nl);
+	if (allh(i) && !pr1403) {
+		Bprint(&tabout, ".nr %d \\n(.v\n", SVS);
+		Bprint(&tabout, ".vs \\n(.vu-\\n(.sp\n");
+		Bprint(&tabout, ".nr 35 \\n(.vu\n");
+	} else
+		Bprint(&tabout, ".nr 35 1m\n");
+	if (chfont)
+		Bprint(&tabout, ".nr %2d \\n(.f\n", S1);
+	Bprint(&tabout, "\\&");
+	vct = 0;
+	for (c = 0; c < ncol; c++) {
+		uphalf = 0;
+		if (watchout == 0 && i + 1 < nlin && (lf = left(i, c, &lwid)) >= 0) {
+			tohcol(c);
+			drawvert(lf, i, c, lwid);
+			vct += 2;
+		}
+		if (rightl && c + 1 == ncol) 
+			continue;
+		vforml = i;
+		for (lf = prev(nl); lf >= 0 && vspen(table[lf][c].col); lf = prev(lf))
+			vforml = lf;
+		form = ctype(vforml, c);
+		if (form != 's') {
+			rct = reg(c, CLEFT);
+			if (form == 'a') 
+				rct = reg(c, CMID);
+			if (form == 'n' && table[nl][c].rcol && lused[c] == 0) 
+				rct = reg(c, CMID);
+			Bprint(&tabout, "\\h'|\\n(%2su'", rct);
+		}
+		s = table[nl][c].col;
+		fn = font[c][stynum[vforml]];
+		size = csize[c][stynum[vforml]];
+		if (*size == 0)
+			size = 0;
+		if ((flags[c][stynum[nl]] & HALFUP) != 0 && pr1403 == 0)
+			uphalf = 1;
+		switch (ct = ctype(vforml, c)) {
+		case 'n':
+		case 'a':
+			if (table[nl][c].rcol) {
+				if (lused[c]) /*Zero field width*/ {
+					ip = prev(nl);
+					if (ip >= 0)
+						if (vspen(table[ip][c].col)) {
+							if (exvspen == 0) {
+								Bprint(&tabout, "\\v'-(\\n(\\*(#du-\\n(^%cu", c + 'a');
+								if (cmidx)
+/* code folded from here */
+	Bprint(&tabout, "-((\\n(#-u-\\n(^%cu)/2u)", c + 'a');
+/* unfolding */
+								vct++;
+								if (pr1403) /* must round to whole lines */
+/* code folded from here */
+	Bprint(&tabout, "/1v*1v");
+/* unfolding */
+								Bprint(&tabout, "'");
+								exvspen = 1;
+							}
+						}
+					Bprint(&tabout, "%c%c", F1, F2);
+					if (uphalf) 
+						Bprint(&tabout, "\\u");
+					puttext(s, fn, size);
+					if (uphalf) 
+						Bprint(&tabout, "\\d");
+					Bprint(&tabout, "%c", F1);
+				}
+				s = table[nl][c].rcol;
+				form = 1;
+				break;
+			}
+		case 'c':
+			form = 3; 
+			break;
+		case 'r':
+			form = 2; 
+			break;
+		case 'l':
+			form = 1; 
+			break;
+		case '-':
+		case '=':
+			if (real(table[nl][c].col))
+				fprint(2, "%s: line %d: Data ignored on table line %d\n", ifile, iline - 1, i + 1);
+			makeline(i, c, ct);
+			continue;
+		default:
+			continue;
+		}
+		if (realsplit ? rused[c] : used[c]) /*Zero field width*/ {
+			/* form: 1 left, 2 right, 3 center adjust */
+			if (ifline(s)) {
+				makeline(i, c, ifline(s));
+				continue;
+			}
+			if (filler(s)) {
+				Bprint(&tabout, "\\l'|\\n(%2su\\&%s'", reg(c, CRIGHT), s + 2);
+				continue;
+			}
+			ip = prev(nl);
+			cmidx = (flags[c][stynum[nl]] & (CTOP | CDOWN)) == 0;
+			if (ip >= 0)
+				if (vspen(table[ip][c].col)) {
+					if (exvspen == 0) {
+						Bprint(&tabout, "\\v'-(\\n(\\*(#du-\\n(^%cu", c + 'a');
+						if (cmidx)
+							Bprint(&tabout, "-((\\n(#-u-\\n(^%cu)/2u)", c + 'a');
+						vct++;
+						if (pr1403) /* round to whole lines */
+							Bprint(&tabout, "/1v*1v");
+						Bprint(&tabout, "'");
+					}
+				}
+			Bprint(&tabout, "%c", F1);
+			if (form != 1)
+				Bprint(&tabout, "%c", F2);
+			if (vspen(s))
+				vspf = 1;
+			else
+			 {
+				if (uphalf) 
+					Bprint(&tabout, "\\u");
+				puttext(s, fn, size);
+				if (uphalf) 
+					Bprint(&tabout, "\\d");
+			}
+			if (form != 2)
+				Bprint(&tabout, "%c", F2);
+			Bprint(&tabout, "%c", F1);
+		}
+		ip = prev(nl);
+		if (ip >= 0)
+			if (vspen(table[ip][c].col)) {
+				exvspen = (c + 1 < ncol) && vspen(table[ip][c+1].col) && 
+				    (topat[c] == topat[c+1]) && 
+				    (cmidx == (flags[c+1] [stynum[nl]] & (CTOP | CDOWN) == 0))
+				     && (left(i, c + 1, &lwid) < 0);
+				if (exvspen == 0) {
+					Bprint(&tabout, "\\v'(\\n(\\*(#du-\\n(^%cu", c + 'a');
+					if (cmidx)
+						Bprint(&tabout, "-((\\n(#-u-\\n(^%cu)/2u)", c + 'a');
+					vct++;
+					if (pr1403) /* round to whole lines */
+						Bprint(&tabout, "/1v*1v");
+					Bprint(&tabout, "'");
+				}
+			}
+			else
+				exvspen = 0;
+		/* if lines need to be split for gcos here is the place for a backslash */
+		if (vct > 7 && c < ncol) {
+			Bprint(&tabout, "\n.sp-1\n\\&");
+			vct = 0;
+		}
+	}
+	Bprint(&tabout, "\n");
+	if (allh(i) && !pr1403) 
+		Bprint(&tabout, ".vs \\n(%du\n", SVS);
+	if (watchout)
+		funnies(i, nl);
+	if (vspf) {
+		for (c = 0; c < ncol; c++)
+			if (vspen(table[nl][c].col) && (nl == 0 || (lf = prev(nl)) < 0 ||
+			    !vspen(table[lf][c].col))) {
+				Bprint(&tabout, ".nr ^%c \\n(#^u\n", 'a' + c);
+				topat[c] = nl;
+			}
+	}
+}
+
+
+void
+puttext(char *s, char *fn, char *size)
+{
+	if (point(s)) {
+		putfont(fn);
+		putsize(size);
+		Bprint(&tabout, "%s", s);
+		if (*fn > 0) 
+			Bprint(&tabout, "\\f\\n(%2d", S1);
+		if (size != 0) 
+			putsize("0");
+	}
+}
+
+
+void
+funnies(int stl, int lin)
+{
+					/* write out funny diverted things */
+	int	c, s, pl, lwid, dv, lf, ct;
+	char	*fn, *ss;
+
+	Bprint(&tabout, ".mk ##\n");	 /* rmember current vertical position */
+	Bprint(&tabout, ".nr %d \\n(##\n", S1);		 /* bottom position */
+	for (c = 0; c < ncol; c++) {
+		ss = table[lin][c].col;
+		if (point(ss)) 
+			continue;
+		if (ss == 0) 
+			continue;
+		s = (int)ss;
+		Bprint(&tabout, ".sp |\\n(##u-1v\n");
+		Bprint(&tabout, ".nr %d ", SIND);
+		ct = 0;
+		for (pl = stl; pl >= 0 && !isalpha(ct = ctype(pl, c)); pl = prev(pl))
+			;
+		switch (ct) {
+		case 'n':
+		case 'c':
+			Bprint(&tabout, "(\\n(%2su+\\n(%2su-\\n(%c-u)/2u\n", reg(c, CLEFT),
+			     reg(c - 1 + ctspan(lin, c), CRIGHT),
+			     s);
+			break;
+		case 'l':
+			Bprint(&tabout, "\\n(%2su\n", reg(c, CLEFT));
+			break;
+		case 'a':
+			Bprint(&tabout, "\\n(%2su\n", reg(c, CMID));
+			break;
+		case 'r':
+			Bprint(&tabout, "\\n(%2su-\\n(%c-u\n", reg(c, CRIGHT), s);
+			break;
+		}
+		Bprint(&tabout, ".in +\\n(%du\n", SIND);
+		fn = font[c][stynum[stl]];
+		putfont(fn);
+		pl = prev(stl);
+		if (stl > 0 && pl >= 0 && vspen(table[pl][c].col)) {
+			Bprint(&tabout, ".sp |\\n(^%cu\n", 'a' + c);
+			if ((flags[c][stynum[stl]] & (CTOP | CDOWN)) == 0) {
+				Bprint(&tabout, ".nr %d \\n(#-u-\\n(^%c-\\n(%c|+1v\n",
+				     TMP, 'a' + c, s);
+				Bprint(&tabout, ".if \\n(%d>0 .sp \\n(%du/2u", TMP, TMP);
+				if (pr1403)		 /* round */
+					Bprint(&tabout, "/1v*1v");
+				Bprint(&tabout, "\n");
+			}
+		}
+		Bprint(&tabout, ".%c+\n", s);
+		Bprint(&tabout, ".in -\\n(%du\n", SIND);
+		if (*fn > 0) 
+			putfont("P");
+		Bprint(&tabout, ".mk %d\n", S2);
+		Bprint(&tabout, ".if \\n(%d>\\n(%d .nr %d \\n(%d\n", S2, S1, S1, S2);
+	}
+	Bprint(&tabout, ".sp |\\n(%du\n", S1);
+	for (c = dv = 0; c < ncol; c++) {
+		if (stl + 1 < nlin && (lf = left(stl, c, &lwid)) >= 0) {
+			if (dv++ == 0)
+				Bprint(&tabout, ".sp -1\n");
+			tohcol(c);
+			dv++;
+			drawvert(lf, stl, c, lwid);
+		}
+	}
+	if (dv)
+		Bprint(&tabout, "\n");
+}
+
+
+void
+putfont(char *fn)
+{
+	if (fn && *fn)
+		Bprint(&tabout,  fn[1] ? "\\f(%.2s" : "\\f%.2s",  fn);
+}
+
+
+void
+putsize(char *s)
+{
+	if (s && *s)
+		Bprint(&tabout, "\\s%s", s);
+}
+
+
blob - /dev/null
blob + bf1978a990029d51e7be38db1dd043d6361b9c99 (mode 644)
--- /dev/null
+++ src/cmd/tbl/t9.c
@@ -0,0 +1,76 @@
+/* t9.c: write lines for tables over 200 lines */
+# include "t.h"
+static useln;
+
+void
+yetmore(void)
+{
+	for (useln = 0; useln < MAXLIN && table[useln] == 0; useln++)
+		;
+	if (useln >= MAXLIN)
+		error("Wierd.  No data in table.");
+	table[0] = table[useln];
+	for (useln = nlin - 1; useln >= 0 && (fullbot[useln] || instead[useln]); useln--)
+		;
+	if (useln < 0)
+		error("Wierd.  No real lines in table.");
+	domore(leftover);
+	while (gets1(cstore = cspace, MAXCHS) && domore(cstore))
+		;
+	last = cstore;
+	return;
+}
+
+
+int
+domore(char *dataln)
+{
+	int	icol, ch;
+
+	if (prefix(".TE", dataln))
+		return(0);
+	if (dataln[0] == '.' && !isdigit(dataln[1])) {
+		Bprint(&tabout, "%s\n", dataln);
+		return(1);
+	}
+	fullbot[0] = 0;
+	instead[0] = (char *)0;
+	if (dataln[1] == 0)
+		switch (dataln[0]) {
+		case '_': 
+			fullbot[0] = '-'; 
+			putline(useln, 0);  
+			return(1);
+		case '=': 
+			fullbot[0] = '='; 
+			putline(useln, 0); 
+			return(1);
+		}
+	for (icol = 0; icol < ncol; icol++) {
+		table[0][icol].col = dataln;
+		table[0][icol].rcol = 0;
+		for (; (ch = *dataln) != '\0' && ch != tab; dataln++)
+			;
+		*dataln++ = '\0';
+		switch (ctype(useln, icol)) {
+		case 'n':
+			table[0][icol].rcol = maknew(table[0][icol].col);
+			break;
+		case 'a':
+			table[0][icol].rcol = table[0][icol].col;
+			table[0][icol].col = "";
+			break;
+		}
+		while (ctype(useln, icol + 1) == 's') /* spanning */
+			table[0][++icol].col = "";
+		if (ch == '\0') 
+			break;
+	}
+	while (++icol < ncol)
+		table[0][icol].col = "";
+	putline(useln, 0);
+	exstore = exspace;		 /* reuse space for numerical items */
+	return(1);
+}
+
+
blob - /dev/null
blob + 5cc59880165974a8ef51d2d1af76c235754e3869 (mode 644)
--- /dev/null
+++ src/cmd/tbl/tb.c
@@ -0,0 +1,101 @@
+/* tb.c: check which entries exist, also storage allocation */
+# include "t.h"
+
+void
+checkuse(void)
+{
+	int	i, c, k;
+
+	for (c = 0; c < ncol; c++) {
+		used[c] = lused[c] = rused[c] = 0;
+		for (i = 0; i < nlin; i++) {
+			if (instead[i] || fullbot[i]) 
+				continue;
+			k = ctype(i, c);
+			if (k == '-' || k == '=') 
+				continue;
+			if ((k == 'n' || k == 'a')) {
+				rused[c] |= real(table[i][c].rcol);
+				if ( !real(table[i][c].rcol))
+					used[c] |= real(table[i][c].col);
+				if (table[i][c].rcol)
+					lused[c] |= real(table[i][c].col);
+			} else
+				used[c] |= real(table[i][c].col);
+		}
+	}
+}
+
+
+int
+real(char *s)
+{
+	if (s == 0) 
+		return(0);
+	if (!point(s)) 
+		return(1);
+	if (*s == 0) 
+		return(0);
+	return(1);
+}
+
+
+int	spcount = 0;
+# define MAXVEC 20
+char	*spvecs[MAXVEC];
+
+char	*
+chspace(void)
+{
+	char	*pp;
+
+	if (spvecs[spcount])
+		return(spvecs[spcount++]);
+	if (spcount >= MAXVEC)
+		error("Too many characters in table");
+	spvecs[spcount++] = pp = calloc(MAXCHS + MAXLINLEN, 1);
+	if (pp == (char *) - 1 || pp == (char *)0)
+		error("no space for characters");
+	return(pp);
+}
+
+
+# define MAXPC 50
+char	*thisvec;
+int	tpcount = -1;
+char	*tpvecs[MAXPC];
+
+int	*
+alocv(int n)
+{
+	int	*tp, *q;
+
+	if (tpcount < 0 || thisvec + n > tpvecs[tpcount] + MAXCHS) {
+		tpcount++;
+		if (tpvecs[tpcount] == 0) {
+			tpvecs[tpcount] = calloc(MAXCHS, 1);
+		}
+		thisvec = tpvecs[tpcount];
+		if (thisvec == (char *)0)
+			error("no space for vectors");
+	}
+	tp = (int *)thisvec;
+	thisvec += n;
+	for (q = tp; q < (int *)thisvec; q++)
+		*q = 0;
+	return(tp);
+}
+
+
+void
+release(void)
+{
+			/* give back unwanted space in some vectors */
+			/* this should call free; it does not because
+				alloc() is so buggy */
+	spcount = 0;
+	tpcount = -1;
+	exstore = 0;
+}
+
+
blob - /dev/null
blob + 635dbf8ad17a91593fe1788b95dc077f00e82e27 (mode 644)
--- /dev/null
+++ src/cmd/tbl/tc.c
@@ -0,0 +1,65 @@
+/* tc.c: find character not in table to delimit fields */
+# include "t.h"
+
+void
+choochar(void)
+{
+				/* choose funny characters to delimit fields */
+	int	had[128], ilin, icol, k;
+	char	*s;
+
+	for (icol = 0; icol < 128; icol++)
+		had[icol] = 0;
+	F1 = F2 = 0;
+	for (ilin = 0; ilin < nlin; ilin++) {
+		if (instead[ilin]) 
+			continue;
+		if (fullbot[ilin]) 
+			continue;
+		for (icol = 0; icol < ncol; icol++) {
+			k = ctype(ilin, icol);
+			if (k == 0 || k == '-' || k == '=')
+				continue;
+			s = table[ilin][icol].col;
+			if (point(s))
+				while (*s)
+					had[*s++] = 1;
+			s = table[ilin][icol].rcol;
+			if (point(s))
+				while (*s)
+					had[*s++] = 1;
+		}
+	}
+				/* choose first funny character */
+	for (
+	    s = "\002\003\005\006\007!%&#/?,:;<=>@`^~_{}+-*ABCDEFGHIJKMNOPQRSTUVWXYZabcdefgjkoqrstwxyz"; 
+	    *s; s++) {
+		if (had[*s] == 0) {
+			F1 = *s;
+			had[F1] = 1;
+			break;
+		}
+	}
+				/* choose second funny character */
+	for (
+	    s = "\002\003\005\006\007:_~^`@;,<=>#%&!/?{}+-*ABCDEFGHIJKMNOPQRSTUVWXZabcdefgjkoqrstuwxyz"; 
+	    *s; s++) {
+		if (had[*s] == 0) {
+			F2 = *s;
+			break;
+		}
+	}
+	if (F1 == 0 || F2 == 0)
+		error("couldn't find characters to use for delimiters");
+	return;
+}
+
+
+int
+point(char *s)
+{
+	int	ss = (int)s;
+	return(ss >= 128 || ss < 0);
+}
+
+
blob - /dev/null
blob + 3df8d445d4463329c46b451afbc6a8ea99279f0b (mode 644)
--- /dev/null
+++ src/cmd/tbl/te.c
@@ -0,0 +1,75 @@
+/* te.c: error message control, input line count */
+# include "t.h"
+
+void
+error(char *s)
+{
+	fprint(2, "\n%s:%d: %s\n", ifile, iline, s);
+	fprint(2, "tbl quits\n");
+	exits(s);
+}
+
+
+char	*
+gets1(char *s, int size)
+{
+	char	*p, *ns;
+	int	nbl;
+
+	iline++;
+	ns = s;
+	p = Brdline(tabin, '\n');
+	while (p == 0) {
+		if (swapin() == 0)
+			return(0);
+		p = Brdline(tabin, '\n');
+	}
+	nbl = Blinelen(tabin)-1;
+	if(nbl >= size)
+		error("input buffer too small");
+	p[nbl] = 0;
+	strcpy(s, p);
+	s += nbl;
+	for (nbl = 0; *s == '\\' && s > ns; s--)
+		nbl++;
+	if (linstart && nbl % 2) /* fold escaped nl if in table */
+		gets1(s + 1, size - (s-ns));
+
+	return(p);
+}
+
+
+# define BACKMAX 500
+char	backup[BACKMAX];
+char	*backp = backup;
+
+void
+un1getc(int c)
+{
+	if (c == '\n')
+		iline--;
+	*backp++ = c;
+	if (backp >= backup + BACKMAX)
+		error("too much backup");
+}
+
+
+int
+get1char(void)
+{
+	int	c;
+	if (backp > backup)
+		c = *--backp;
+	else
+		c = Bgetc(tabin);
+	if (c == 0) /* EOF */ {
+		if (swapin() == 0)
+			error("unexpected EOF");
+		c = Bgetc(tabin);
+	}
+	if (c == '\n')
+		iline++;
+	return(c);
+}
+
+
blob - /dev/null
blob + 3791c32fe25ffc0804444615064a174ec1b81ad5 (mode 644)
--- /dev/null
+++ src/cmd/tbl/tf.c
@@ -0,0 +1,74 @@
+/* tf.c: save and restore fill mode around table */
+# include "t.h"
+
+void
+savefill(void)
+{
+			/* remembers various things: fill mode, vs, ps in mac 35 (SF) */
+	Bprint(&tabout, ".de %d\n", SF);
+	Bprint(&tabout, ".ps \\n(.s\n");
+	Bprint(&tabout, ".vs \\n(.vu\n");
+	Bprint(&tabout, ".in \\n(.iu\n");
+	Bprint(&tabout, ".if \\n(.u .fi\n");
+	Bprint(&tabout, ".if \\n(.j .ad\n");
+	Bprint(&tabout, ".if \\n(.j=0 .na\n");
+	Bprint(&tabout, "..\n");
+	Bprint(&tabout, ".nf\n");
+	/* set obx offset if useful */
+	Bprint(&tabout, ".nr #~ 0\n");
+	Bprint(&tabout, ".if \\n(.T .if n .nr #~ 0.6n\n");
+}
+
+
+void
+rstofill(void)
+{
+	Bprint(&tabout, ".%d\n", SF);
+}
+
+
+void
+endoff(void)
+{
+	int	i;
+
+	for (i = 0; i < MAXHEAD; i++)
+		if (linestop[i])
+			Bprint(&tabout, ".nr #%c 0\n", linestop[i] + 'a' - 1);
+	for (i = 0; i < texct; i++)
+		Bprint(&tabout, ".rm %c+\n", texstr[i]);
+	Bprint(&tabout, "%s\n", last);
+}
+
+
+void
+ifdivert(void)
+{
+	Bprint(&tabout, ".ds #d .d\n");
+	Bprint(&tabout, ".if \\(ts\\n(.z\\(ts\\(ts .ds #d nl\n");
+}
+
+
+void
+saveline(void)
+{
+	Bprint(&tabout, ".if \\n+(b.=1 .nr d. \\n(.c-\\n(c.-1\n");
+	linstart = iline;
+}
+
+
+void
+restline(void)
+{
+	Bprint(&tabout, ".if \\n-(b.=0 .nr c. \\n(.c-\\n(d.-%d\n", iline - linstart);
+	linstart = 0;
+}
+
+
+void
+cleanfc(void)
+{
+	Bprint(&tabout, ".fc\n");
+}
+
+
blob - /dev/null
blob + 6abb149081ca6383bd67ce17ffd4af57191e2453 (mode 644)
--- /dev/null
+++ src/cmd/tbl/tg.c
@@ -0,0 +1,81 @@
+/* tg.c: process included text blocks */
+# include "t.h"
+
+int
+gettext(char *sp, int ilin, int icol, char *fn, char *sz)
+{
+					/* get a section of text */
+	char	line[4096];
+	int	oname;
+	char	*vs;
+
+	if (texname == 0) 
+		error("Too many text block diversions");
+	if (textflg == 0) {
+		Bprint(&tabout, ".nr %d \\n(.lu\n", SL); /* remember old line length */
+		textflg = 1;
+	}
+	Bprint(&tabout, ".eo\n");
+	Bprint(&tabout, ".am %s\n", reg(icol, CRIGHT));
+	Bprint(&tabout, ".br\n");
+	Bprint(&tabout, ".di %c+\n", texname);
+	rstofill();
+	if (fn && *fn) 
+		Bprint(&tabout, ".nr %d \\n(.f\n.ft %s\n", S1, fn);
+	Bprint(&tabout, ".ft \\n(.f\n"); /* protect font */
+	vs = vsize[icol][stynum[ilin]];
+	if ((sz && *sz) || (vs && *vs)) {
+		Bprint(&tabout, ".nr %d \\n(.v\n", S9);
+		if (vs == 0 || *vs == 0) 
+			vs = "\\n(.s+2";
+		if (sz && *sz)
+			Bprint(&tabout, ".ps %s\n", sz);
+		Bprint(&tabout, ".vs %s\n", vs);
+		Bprint(&tabout, ".if \\n(%du>\\n(.vu .sp \\n(%du-\\n(.vu\n", S9, S9);
+	}
+	if (cll[icol][0])
+		Bprint(&tabout, ".ll %sn\n", cll[icol]);
+	else
+		Bprint(&tabout, ".ll \\n(%du*%du/%du\n", SL, ctspan(ilin, icol), ncol + 1);
+	Bprint(&tabout, ".if \\n(.l<\\n(%2s .ll \\n(%2su\n", reg(icol, CRIGHT),
+	     reg(icol, CRIGHT));
+	if (ctype(ilin, icol) == 'a')
+		Bprint(&tabout, ".ll -2n\n");
+	Bprint(&tabout, ".in 0\n");
+	while (gets1(line, sizeof(line))) {
+		if (line[0] == 'T' && line[1] == '}' && line[2] == tab) 
+			break;
+		if (match("T}", line)) 
+			break;
+		Bprint(&tabout, "%s\n", line);
+	}
+	if (fn && *fn) 
+		Bprint(&tabout, ".ft \\n(%d\n", S1);
+	if (sz && *sz) 
+		Bprint(&tabout, ".br\n.ps\n.vs\n");
+	Bprint(&tabout, ".br\n");
+	Bprint(&tabout, ".di\n");
+	Bprint(&tabout, ".nr %c| \\n(dn\n", texname);
+	Bprint(&tabout, ".nr %c- \\n(dl\n", texname);
+	Bprint(&tabout, "..\n");
+	Bprint(&tabout, ".ec \\\n");
+	/* copy remainder of line */
+	if (line[2])
+		tcopy (sp, line + 3);
+	else
+		*sp = 0;
+	oname = texname;
+	texname = texstr[++texct];
+	return(oname);
+}
+
+
+void
+untext(void)
+{
+	rstofill();
+	Bprint(&tabout, ".nf\n");
+	Bprint(&tabout, ".ll \\n(%du\n", SL);
+}
+
+
blob - /dev/null
blob + ef995bbb35e0237a497ced61647d691de3c7f3fd (mode 644)
--- /dev/null
+++ src/cmd/tbl/ti.c
@@ -0,0 +1,75 @@
+/* ti.c: classify line intersections */
+# include "t.h"
+/* determine local environment for intersections */
+
+int
+interv(int i, int c)
+{
+	int	ku, kl;
+
+	if (c >= ncol || c == 0) {
+		if (dboxflg) {
+			if (i == 0) 
+				return(BOT);
+			if (i >= nlin) 
+				return(TOP);
+			return(THRU);
+		}
+		if (c >= ncol)
+			return(0);
+	}
+	ku = i > 0 ? lefdata(i - 1, c) : 0;
+	if (i + 1 >= nlin && allh(i))
+		kl = 0;
+	else
+		kl = lefdata(allh(i) ? i + 1 : i, c);
+	if (ku == 2 && kl == 2) 
+		return(THRU);
+	if (ku == 2) 
+		return(TOP);
+	if (kl == BOT) 
+		return(2);
+	return(0);
+}
+
+
+int
+interh(int i, int c)
+{
+	int	kl, kr;
+
+	if (fullbot[i] == '=' || (dboxflg && (i == 0 || i >= nlin - 1))) {
+		if (c == ncol)
+			return(LEFT);
+		if (c == 0)
+			return(RIGHT);
+		return(THRU);
+	}
+	if (i >= nlin) 
+		return(0);
+	kl = c > 0 ? thish (i, c - 1) : 0;
+	if (kl <= 1 && i > 0 && allh(up1(i)))
+		kl = c > 0 ? thish(up1(i), c - 1) : 0;
+	kr = thish(i, c);
+	if (kr <= 1 && i > 0 && allh(up1(i)))
+		kr = c > 0 ? thish(up1(i), c) : 0;
+	if (kl == '=' && kr ==  '=') 
+		return(THRU);
+	if (kl == '=') 
+		return(LEFT);
+	if (kr == '=') 
+		return(RIGHT);
+	return(0);
+}
+
+
+int
+up1(int i)
+{
+	i--;
+	while (instead[i] && i > 0) 
+		i--;
+	return(i);
+}
+
+
blob - /dev/null
blob + 8fa4e497222abd7fcd085cc1a5445d7a1c2bdfb7 (mode 644)
--- /dev/null
+++ src/cmd/tbl/tm.c
@@ -0,0 +1,65 @@
+/* tm.c: split numerical fields */
+# include "t.h"
+
+char	*
+maknew(char *str)
+{
+				/* make two numerical fields */
+	int	dpoint, c;
+	char	*p, *q, *ba;
+
+	p = str;
+	for (ba = 0; c = *str; str++)
+		if (c == '\\' && *(str + 1) == '&')
+			ba = str;
+	str = p;
+	if (ba == 0) {
+		for (dpoint = 0; *str; str++) {
+			if (*str == '.' && !ineqn(str, p) && 
+			    (str > p && digit(*(str - 1)) || 
+			    digit(*(str + 1))))
+				dpoint = (int)str;
+		}
+		if (dpoint == 0)
+			for (; str > p; str--) {
+				if (digit( *(str - 1) ) && !ineqn(str, p))
+					break;
+			}
+		if (!dpoint && p == str) /* not numerical, don't split */
+			return(0);
+		if (dpoint) 
+			str = (char *)dpoint;
+	} else
+		str = ba;
+	p = str;
+	if (exstore == 0 || exstore > exlim) {
+		exstore = exspace = chspace();
+		exlim = exstore + MAXCHS;
+	}
+	q = exstore;
+	while (*exstore++ = *str++)
+		;
+	*p = 0;
+	return(q);
+}
+
+
+int
+ineqn (char *s, char *p)
+{
+				/* true if s is in a eqn within p */
+	int	ineq = 0, c;
+
+	while (c = *p) {
+		if (s == p)
+			return(ineq);
+		p++;
+		if ((ineq == 0) && (c == delim1))
+			ineq = 1;
+		else if ((ineq == 1) && (c == delim2))
+			ineq = 0;
+	}
+	return(0);
+}
+
+
blob - /dev/null
blob + 7d586e8b8388622eb1f651460a936bb16da1dcdc (mode 644)
--- /dev/null
+++ src/cmd/tbl/tr.c
@@ -0,0 +1,28 @@
+# include "t.h"
+/* tr.c: number register allocation */
+char	*nregs[] = {
+	/* this array must have at least 3*qcol entries
+	   or illegal register names will result */
+	"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
+	"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
+	"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
+	"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
+	"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
+	"90", "91", "92", "93", "94", "95", "96", "97", "4q", "4r",
+	"4s", "4t", "4u", "4v", "4w", "4x", "4y", "4z", "4;", "4.",
+	"4a", "4b", "4c", "4d", "4e", "4f", "4g", "4h", "4i", "4j",
+	"4k", "4l", "4m", "4n", "4o", "4p", "5a", "5b", "5c", "5d",
+	"5e", "5f", "5g", "5h", "5i", "5j", "5k", "5l", "5m", "5n",
+	"5o", "5p", "5q", "5r", "5s", "5t", "5u", "5v", "5w", "5x",
+	0};
+
+
+char	*
+reg(int col, int place)
+{
+	if (sizeof(nregs) < 2 * 3 * qcol)
+		error("Too many columns for registers");
+	return (nregs[qcol*place+col]);
+}
+
+
blob - /dev/null
blob + 43cc84ecdf85ab5021de973c4d5e28572364d073 (mode 644)
--- /dev/null
+++ src/cmd/tbl/ts.c
@@ -0,0 +1,71 @@
+/* ts.c: minor string processing subroutines */
+#include "t.h"
+
+int
+match (char *s1, char *s2)
+{
+	while (*s1 == *s2)
+		if (*s1++ == '\0')
+			return(1);
+		else
+			s2++;
+	return(0);
+}
+
+
+int
+prefix(char *small, char *big)
+{
+	int	c;
+
+	while ((c = *small++) == *big++)
+		if (c == 0) 
+			return(1);
+	return(c == 0);
+}
+
+
+int
+letter (int ch)
+{
+	if (ch >= 'a' && ch <= 'z')
+		return(1);
+	if (ch >= 'A' && ch <= 'Z')
+		return(1);
+	return(0);
+}
+
+
+int
+numb(char *str)
+{
+				/* convert to integer */
+	int	k;
+	for (k = 0; *str >= '0' && *str <= '9'; str++)
+		k = k * 10 + *str - '0';
+	return(k);
+}
+
+
+int
+digit(int x)
+{
+	return(x >= '0' && x <= '9');
+}
+
+
+int
+max(int a, int b)
+{
+	return( a > b ? a : b);
+}
+
+
+void
+tcopy (char *s, char *t)
+{
+	while (*s++ = *t++)
+		;
+}
+
+
blob - /dev/null
blob + 96270b7580ae4955da049991ce787dc831ca9895 (mode 644)
--- /dev/null
+++ src/cmd/tbl/tt.c
@@ -0,0 +1,127 @@
+/* tt.c: subroutines for drawing horizontal lines */
+# include "t.h"
+
+int
+ctype(int il, int ic)
+{
+	if (instead[il])
+		return(0);
+	if (fullbot[il])
+		return(0);
+	il = stynum[il];
+	return(style[ic][il]);
+}
+
+
+int
+min(int a, int b)
+{
+	return(a < b ? a : b);
+}
+
+
+int
+fspan(int i, int c)
+{
+	c++;
+	return(c < ncol && ctype(i, c) == 's');
+}
+
+
+int
+lspan(int i, int c)
+{
+	int	k;
+
+	if (ctype(i, c) != 's') 
+		return(0);
+	c++;
+	if (c < ncol && ctype(i, c) == 's')
+		return(0);
+	for (k = 0; ctype(i, --c) == 's'; k++)
+		;
+	return(k);
+}
+
+
+int
+ctspan(int i, int c)
+{
+	int	k;
+	c++;
+	for (k = 1; c < ncol && ctype(i, c) == 's'; k++)
+		c++;
+	return(k);
+}
+
+
+void
+tohcol(int ic)
+{
+	if (ic == 0)
+		Bprint(&tabout, "\\h'|0'");
+	else
+		Bprint(&tabout, "\\h'(|\\n(%2su+|\\n(%2su)/2u'", reg(ic, CLEFT),
+		     reg(ic - 1, CRIGHT));
+}
+
+
+int
+allh(int i)
+{
+			/* return true if every element in line i is horizontal */
+				/* also at least one must be horizontl */
+	int	c, one, k;
+
+	if (fullbot[i]) 
+		return(1);
+	if (i >= nlin) 
+		return(dboxflg || boxflg);
+	for (one = c = 0; c < ncol; c++) {
+		k = thish(i, c);
+		if (k == 0) 
+			return(0);
+		if (k == 1) 
+			continue;
+		one = 1;
+	}
+	return(one);
+}
+
+
+int
+thish(int i, int c)
+{
+	int	t;
+	char	*s;
+	struct colstr *pc;
+
+	if (c < 0)
+		return(0);
+	if (i < 0) 
+		return(0);
+	t = ctype(i, c);
+	if (t == '_' || t == '-')
+		return('-');
+	if (t == '=')
+		return('=');
+	if (t == '^') 
+		return(1);
+	if (fullbot[i] )
+		return(fullbot[i]);
+	if (t == 's') 
+		return(thish(i, c - 1));
+	if (t == 0) 
+		return(1);
+	pc = &table[i][c];
+	s = (t == 'a' ? pc->rcol : pc->col);
+	if (s == 0 || (point(s) && *s == 0))
+		return(1);
+	if (vspen(s)) 
+		return(1);
+	if (t = barent( s))
+		return(t);
+	return(0);
+}
+
+
blob - /dev/null
blob + 217869e1a46759cae0e91957d6043354f0e03b90 (mode 644)
--- /dev/null
+++ src/cmd/tbl/tu.c
@@ -0,0 +1,257 @@
+/* tu.c: draws horizontal lines */
+# include "t.h"
+
+void
+makeline(int i, int c, int lintype)
+{
+	int	cr, type, shortl;
+
+	type = thish(i, c);
+	if (type == 0) 
+		return;
+	shortl = (table[i][c].col[0] == '\\');
+	if (c > 0 && !shortl && thish(i, c - 1) == type)
+		return;
+	if (shortl == 0)
+		for (cr = c; cr < ncol && (ctype(i, cr) == 's' || type == thish(i, cr)); cr++)
+			;
+	else
+		for (cr = c + 1; cr < ncol && ctype(i, cr) == 's'; cr++)
+			;
+	drawline(i, c, cr - 1, lintype, 0, shortl);
+}
+
+
+void
+fullwide(int i, int lintype)
+{
+	int	cr, cl;
+
+	if (!pr1403)
+		Bprint(&tabout, ".nr %d \\n(.v\n.vs \\n(.vu-\\n(.sp\n", SVS);
+	cr = 0;
+	while (cr < ncol) {
+		cl = cr;
+		while (i > 0 && vspand(prev(i), cl, 1))
+			cl++;
+		for (cr = cl; cr < ncol; cr++)
+			if (i > 0 && vspand(prev(i), cr, 1))
+				break;
+		if (cl < ncol)
+			drawline(i, cl, (cr < ncol ? cr - 1 : cr), lintype, 1, 0);
+	}
+	Bprint(&tabout, "\n");
+	if (!pr1403)
+		Bprint(&tabout, ".vs \\n(%du\n", SVS);
+}
+
+
+void
+drawline(int i, int cl, int cr, int lintype, int noheight, int shortl)
+{
+	char	*exhr, *exhl, *lnch;
+	int	lcount, ln, linpos, oldpos, nodata;
+
+	lcount = 0;
+	exhr = exhl = "";
+	switch (lintype) {
+	case '-': 
+		lcount = 1;
+		break;
+	case '=': 
+		lcount = pr1403 ? 1 : 2; 
+		break;
+	case SHORTLINE: 
+		lcount = 1; 
+		break;
+	}
+	if (lcount <= 0) 
+		return;
+	nodata = cr - cl >= ncol || noheight || allh(i);
+	if (!nodata)
+		Bprint(&tabout, "\\v'-.5m'");
+	for (ln = oldpos = 0; ln < lcount; ln++) {
+		linpos = 2 * ln - lcount + 1;
+		if (linpos != oldpos)
+			Bprint(&tabout, "\\v'%dp'", linpos - oldpos);
+		oldpos = linpos;
+		if (shortl == 0) {
+			tohcol(cl);
+			if (lcount > 1) {
+				switch (interv(i, cl)) {
+				case TOP: 
+					exhl = ln == 0 ? "1p" : "-1p"; 
+					break;
+				case BOT: 
+					exhl = ln == 1 ? "1p" : "-1p"; 
+					break;
+				case THRU: 
+					exhl = "1p"; 
+					break;
+				}
+				if (exhl[0])
+					Bprint(&tabout, "\\h'%s'", exhl);
+			} else if (lcount == 1) {
+				switch (interv(i, cl)) {
+				case TOP: 
+				case BOT: 
+					exhl = "-1p"; 
+					break;
+				case THRU: 
+					exhl = "1p"; 
+					break;
+				}
+				if (exhl[0])
+					Bprint(&tabout, "\\h'%s'", exhl);
+			}
+			if (lcount > 1) {
+				switch (interv(i, cr + 1)) {
+				case TOP: 
+					exhr = ln == 0 ? "-1p" : "+1p"; 
+					break;
+				case BOT: 
+					exhr = ln == 1 ? "-1p" : "+1p"; 
+					break;
+				case THRU: 
+					exhr = "-1p"; 
+					break;
+				}
+			} else if (lcount == 1) {
+				switch (interv(i, cr + 1)) {
+				case TOP: 
+				case BOT: 
+					exhr = "+1p"; 
+					break;
+				case THRU: 
+					exhr = "-1p"; 
+					break;
+				}
+			}
+		} else
+			Bprint(&tabout, "\\h'|\\n(%2su'", reg(cl, CLEFT));
+		Bprint(&tabout, "\\s\\n(%d", LSIZE);
+		if (linsize)
+			Bprint(&tabout, "\\v'-\\n(%dp/6u'", LSIZE);
+		if (shortl)
+			Bprint(&tabout, "\\l'|\\n(%2su'", reg(cr, CRIGHT));
+		else
+		 {
+			lnch = "\\(ul";
+			if (pr1403)
+				lnch = lintype == 2 ? "=" : "\\(ru";
+			if (cr + 1 >= ncol)
+				Bprint(&tabout, "\\l'|\\n(TWu%s%s'", exhr, lnch);
+			else
+				Bprint(&tabout, "\\l'(|\\n(%2su+|\\n(%2su)/2u%s%s'", reg(cr, CRIGHT),
+				    reg(cr + 1, CLEFT), exhr, lnch);
+		}
+		if (linsize)
+			Bprint(&tabout, "\\v'\\n(%dp/6u'", LSIZE);
+		Bprint(&tabout, "\\s0");
+	}
+	if (oldpos != 0)
+		Bprint(&tabout, "\\v'%dp'", -oldpos);
+	if (!nodata)
+		Bprint(&tabout, "\\v'+.5m'");
+}
+
+
+void
+getstop(void)
+{
+	int	i, c, k, junk, stopp;
+
+	stopp = 1;
+	for (i = 0; i < MAXLIN; i++)
+		linestop[i] = 0;
+	for (i = 0; i < nlin; i++)
+		for (c = 0; c < ncol; c++) {
+			k = left(i, c, &junk);
+			if (k >= 0 && linestop[k] == 0)
+				linestop[k] = ++stopp;
+		}
+	if (boxflg || allflg || dboxflg)
+		linestop[0] = 1;
+}
+
+
+int
+left(int i, int c, int *lwidp)
+{
+	int	kind, li, lj;
+					/* returns -1 if no line to left */
+					/* returns number of line where it starts */
+					/* stores into lwid the kind of line */
+	*lwidp = 0;
+	if (i < 0) 
+		return(-1);
+	kind = lefdata(i, c);
+	if (kind == 0) 
+		return(-1);
+	if (i + 1 < nlin)
+		if (lefdata(next(i), c) == kind) 
+			return(-1);
+	li = i;
+	while (i >= 0 && lefdata(i, c) == kind)
+		i = prev(li = i);
+	if (prev(li) == -1) 
+		li = 0;
+	*lwidp = kind;
+	for (lj = i + 1; lj < li; lj++)
+		if (instead[lj] && strcmp(instead[lj], ".TH") == 0)
+			return(li);
+	for (i = i + 1; i < li; i++)
+		if (fullbot[i])
+			li = i;
+	return(li);
+}
+
+
+int
+lefdata(int i, int c)
+{
+	int	ck;
+
+	if (i >= nlin) 
+		i = nlin - 1;
+	if (ctype(i, c) == 's') {
+		for (ck = c; ctype(i, ck) == 's'; ck--)
+			;
+		if (thish(i, ck) == 0)
+			return(0);
+	}
+	i = stynum[i];
+	i = lefline[c][i];
+	if (i > 0) 
+		return(i);
+	if (dboxflg && c == 0) 
+		return(2);
+	if (allflg)
+		return(1);
+	if (boxflg && c == 0) 
+		return(1);
+	return(0);
+}
+
+
+int
+next(int i)
+{
+	while (i + 1 < nlin) {
+		i++;
+		if (!fullbot[i] && !instead[i]) 
+			break;
+	}
+	return(i);
+}
+
+
+int
+prev(int i)
+{
+	while (--i >= 0  && (fullbot[i] || instead[i]))
+		;
+	return(i);
+}
+
+
blob - /dev/null
blob + 19a4b03fda16cf4977869fc761af16e0a159c98b (mode 644)
--- /dev/null
+++ src/cmd/tbl/tv.c
@@ -0,0 +1,183 @@
+/* tv.c: draw vertical lines */
+# include "t.h"
+
+void
+drawvert(int start, int end, int c, int lwid)
+{
+	char	*exb = 0, *ext = 0;
+	int	tp = 0, sl, ln, pos, epb, ept, vm;
+
+	end++;
+	vm = 'v';
+				/* note: nr 35 has value of 1m outside of linesize */
+	while (instead[end]) 
+		end++;
+	for (ln = 0; ln < lwid; ln++) {
+		epb = ept = 0;
+		pos = 2 * ln - lwid + 1;
+		if (pos != tp) 
+			Bprint(&tabout, "\\h'%dp'", pos - tp);
+		tp = pos;
+		if (end < nlin) {
+			if (fullbot[end] || (!instead[end] && allh(end)))
+				epb = 2;
+			else
+				switch (midbar(end, c)) {
+				case '-':
+					exb = "1v-.5m"; 
+					break;
+				case '=':
+					exb = "1v-.5m";
+					epb = 1; 
+					break;
+				}
+		}
+		if (lwid > 1)
+			switch (interh(end, c)) {
+			case THRU: 
+				epb -= 1; 
+				break;
+			case RIGHT: 
+				epb += (ln == 0 ? 1 : -1); 
+				break;
+			case LEFT: 
+				epb += (ln == 1 ? 1 : -1); 
+				break;
+			}
+		if (lwid == 1)
+			switch (interh(end, c)) {
+			case THRU: 
+				epb -= 1; 
+				break;
+			case RIGHT: 
+			case LEFT: 
+				epb += 1; 
+				break;
+			}
+		if (start > 0) {
+			sl = start - 1;
+			while (sl >= 0 && instead[sl]) 
+				sl--;
+			if (sl >= 0 && (fullbot[sl] || allh(sl)))
+				ept = 0;
+			else if (sl >= 0)
+				switch (midbar(sl, c)) {
+				case '-':
+					ext = ".5m"; 
+					break;
+				case '=':
+					ext = ".5m"; 
+					ept = -1; 
+					break;
+				default:
+					vm = 'm'; 
+					break;
+				}
+			else
+				ept = -4;
+		} else if (start == 0 && allh(0)) {
+			ept = 0;
+			vm = 'm';
+		}
+		if (lwid > 1)
+			switch (interh(start, c)) {
+			case THRU: 
+				ept += 1; 
+				break;
+			case LEFT: 
+				ept += (ln == 0 ? 1 : -1); 
+				break;
+			case RIGHT: 
+				ept += (ln == 1 ? 1 : -1); 
+				break;
+			}
+		else if (lwid == 1)
+			switch (interh(start, c)) {
+			case THRU: 
+				ept += 1; 
+				break;
+			case LEFT: 
+			case RIGHT: 
+				ept -= 1; 
+				break;
+			}
+		if (exb)
+			Bprint(&tabout, "\\v'%s'", exb);
+		if (epb)
+			Bprint(&tabout, "\\v'%dp'", epb);
+		Bprint(&tabout, "\\s\\n(%d", LSIZE);
+		if (linsize)
+			Bprint(&tabout, "\\v'-\\n(%dp/6u'", LSIZE);
+		Bprint(&tabout, "\\h'-\\n(#~u'");	 /* adjustment for T450 nroff boxes */
+		Bprint(&tabout, "\\L'|\\n(#%cu-%s", linestop[start] + 'a' - 1,
+		      vm == 'v' ? "1v" : "\\n(35u");
+		if (ext)
+			Bprint(&tabout, "-(%s)", ext);
+		if (exb)
+			Bprint(&tabout, "-(%s)", exb);
+		pos = ept - epb;
+		if (pos)
+			Bprint(&tabout, "%s%dp", pos >= 0 ? "+" : "", pos);
+		/* the string #d is either "nl" or ".d" depending
+	   on diversions; on GCOS not the same */
+		Bprint(&tabout, "'\\s0\\v'\\n(\\*(#du-\\n(#%cu+%s",
+		     linestop[start] + 'a' - 1, vm == 'v' ? "1v" : "\\n(35u");
+		if (ext)
+			Bprint(&tabout, "+%s", ext);
+		if (ept)
+			Bprint(&tabout, "%s%dp", (-ept) > 0 ? "+" : "", (-ept));
+		Bprint(&tabout, "'");
+		if (linsize)
+			Bprint(&tabout, "\\v'\\n(%dp/6u'", LSIZE);
+	}
+}
+
+
+int
+midbar(int i, int c)
+{
+	int	k;
+
+	k = midbcol(i, c);
+	if (k == 0 && c > 0)
+		k = midbcol(i, c - 1);
+	return(k);
+}
+
+
+int
+midbcol(int i, int c)
+{
+	int	ct;
+
+	while ( (ct = ctype(i, c)) == 's')
+		c--;
+	if (ct == '-' || ct == '=')
+		return(ct);
+	if (ct = barent(table[i][c].col))
+		return(ct);
+	return(0);
+}
+
+
+int
+barent(char *s)
+{
+	if (s == 0) 
+		return (1);
+	if (!point(s)) 
+		return(0);
+	if (s[0] == '\\') 
+		s++;
+	if (s[1] != 0)
+		return(0);
+	switch (s[0]) {
+	case '_':
+		return('-');
+	case '=':
+		return('=');
+	}
+	return(0);
+}
+
+
blob - /dev/null
blob + 5765832c36a98cb3e1910e55075c7ae934a081e8 (mode 644)
--- /dev/null
+++ src/cmd/troff/FIXES
@@ -0,0 +1,821 @@
+March 11, 1994
+
+	If we are just plain old nroff (and not doing UNICODE) we should
+	only Lookup characters, not Install when we don't know them.
+	If we are troff, we Install them anyway
+
+March 8, 1994
+
+	Nroff had problems with parsing quoted white space as options or
+	character code in some terminals tables. Changed by having scanf
+	include white space when necessary as suggested by Rich.
+
+March 1, 1994
+
+	Made sanity check for terminal type depending on the trace level;
+	trace level set with -tn flag at start up
+
+22 Feb, 1994
+
+	More pointer shuffling fixes.
+
+18 Feb, 1994
+
+	More disabling of multibyte stuff. Fixed bug in n5.c: casetm didn'
+	know about the new format in the fontables.
+
+Feb 17, 1994
+
+	Removed extra include <setlocale> from n1.c
+
+	Fixed dubious pointer shuffling in n7.c, t10.c & n8.c. Thanks Rich!
+
+Feb 10, 1994
+
+	Disabled the multybyte stuff; only plan 9 will get it.
+
+Jan 24, 1994
+
+	Fixed nasty bug discovered by td, which caused core dumps on
+	\D'l-0.002775i 0i' and apparently all numbers closer to 0
+	than -.002775. Fixed in storeline() and storeword() (n7.c).
+
+Dec 16, 1993
+
+	nroff & troff -N were looking for the TYPESETTER variable, causing
+
+	troff: cannot open /sys/lib/troff/term/tab.202; line 1, file stdin
+
+	fixed my moving getenv("TYPESETTER") to t10.c in t_ptinit(void).
+
+Dec 3, 1993:
+
+	The sequence \s+2\H'+10' came sometimes out in the wrong order
+	(x H before s), so there wasn't a difference bewteen \s+2\H'+10'
+	and \H'+10'\s+2. Now the fonts bits of the CHARHT are used to
+	register the current pontsize, so we can issue a s10 in t10.c
+	if needed. A bit sneaky.
+
+	Try to prevent double slashes in path names. Especially under
+	plan9 things started to look ugly.
+
+	Exception word list now grows dynamic.
+
+Nov 30, 1993:
+
+	Allow multiple calls to .pi, requested by Rob.
+		.pi cat
+		.pi dogs
+	is now equivalent with
+		.pi cat | dogs
+
+
+	.ab now takes also optional error code:
+		.ab [n] [string]
+	If n and string, n is exit code, string is message
+	If n, n is exit code, ``User Abort, exit code n" is message
+	If !n and string, standard exit code, string is message
+	If !n and ! string, standard exit code, "User Abort" is message
+
+Nov 24, 1993:
+
+	Reordered code to keep the UNASNI scripts happy.
+
+	Nroff dumped core reading terminal tables: apparenty under plan 9,
+	scanf includes the '\n'; added test for '\0' in parse in n10.c.
+
+	Relative tab settings (.ta +1C +2C) didn't work; anding the
+	previous value with TABMASK fixes this (caseta).
+
+Nov 23, 1993:
+
+	Included code, originally done by bwk for plan 9, to handle
+	multi-byte characters.
+
+Nov 3, 1993:
+
+	``pair internal'' two char names by shifting 16 bits. Will allow
+	the use of 16 bit characters sets (Unicode in plan9 etc.) for
+	macro's etc.
+
+Oct 20, 1993:
+
+	Word & line buffers are now dynamic: No more word or line overflow
+	unless when we run out of memory.
+
+Oct 11, 1993:
+
+	lost diversion warning pops up regularly with man macro's. Due
+	to a possible macro coding problem. Triggered by something like
+	troff -man:
+		.TP
+		.TP
+		foo
+		.ex
+    	Minimal code:
+		.di aa
+		throw away this diversion (aa) while being defined.
+		.rm aa
+		.br
+		.di
+
+	Fixed by disallowing .rm to throw away current diversion. The
+	rn request will complain with:
+
+		cannot remove diversion aa during definition; etc.
+
+Sep 29, 1993:
+
+	Some long standing fixes which never went back in the source.
+	Thanks to Janet & Rich.
+
+Sep 28, 1993:
+
+	Changed getach() (n1.c), so it does't consider truncated
+	special characters as (8-bit) ascii.  STX ETX ENQ ACK and BELL
+	are still allowed for the ultimate backwards compatibility.
+
+	Some code changes, so real ANSI compilers like the SGI version
+	(acc from Sun is a poor excuse for an ANSI compiler) don't
+	barf.  Some compromises (static Tchar wbuf in n9.c) allowed so
+	the unansified stuff for non-ansi compilers (cc on Sun's) will
+	work as well.
+
+Sep 9, 1993:
+
+	Be nice to Gerard. Now also word spaces in .tl and after
+	tabs/fleids etc.
+
+Aug 12, 1993:
+
+	Tabs setting can now be humongous. We also allow 99 tabs to
+	accomodate tbl. As a side effect, NTM buffers are now 1K
+
+Aug 11, 1993:
+
+	.R register, now contains maximum number of addessable
+	registers minus the number actually used.
+
+	Small esthetic changes in error messages; removed a statement
+	which wasn't reached anyway.
+
+Aug 10, 1993:
+
+	Some more speed hacks: be smarter doing the linear table
+	lookups in alloc() and finds().
+
+	The real name of the det diversion size macro is now gd.
+
+Aug 9, 1993:
+
+	A much faster way to find the end of a string/macro, by
+	remembering that when defined.
+
+Aug 6, 1993:
+
+	 Slightly more eficient way of skipping to the end of a
+	 string/macro
+
+Aug 5, 1993:
+
+	Prevent character sign extension for 8-bit charnames diversions
+	etc. by unpair
+
+Aug 4, 1993:
+
+	Growing the dynamical macro/strings name space and registers
+	space (See the experiment of 21 July) now with bigger
+	increments. Casts added to satisfy non-ANSI compilers.
+
+Aug 3, 1993:
+
+	Should check return value in alloc (n3.c), to prevent core dump
+	when memory gets tight.
+
+July 28, 1993:
+
+	New request: .sg <div> sets the dn and dl registers to the size
+	of the diversion named in the argument. Doesn't do anything
+	when the named diversion doesn't exist. The name sg is
+	temporary until we find a better one.
+
+July 21, 1993:
+
+	Experiment: Macro space  & registers name allocated
+	dynamically. Note that current reallocation occurs in
+	increments of 1, to force the code to be executed a lot; a kind
+	of stress testing. Also, eight bit characters allowed in
+	macro/string names.
+
+July 21, 1993:
+
+	Turn on the escape mode if the end macro is called.
+
+July 20, 1993:
+
+	Tracing mode now default off
+
+	Don't print s stackdump either when a file specfied on the
+	command line argument cannot be opened
+
+July 15, 1993:
+
+	Don't print useless line & current file informations when a
+	file specfied on the command line argument cannot be opened.
+
+	Sun ansi compiler doesn't default adhere to standards. Undid
+	the kludge in tdef.h
+
+July 14, 1993:
+
+	Coding error made the tab type R not function properly
+
+July 12, 1993:
+
+	Fixed a typo in the version stuff, noticed by Rich
+
+July 9, 1993:
+
+	Added the dwb home configuration stuff, thanks RIch. Also,
+	NCHARS is big enough. Added a fflush to casetm, so .fm <file>
+	will be up to date.
+
+June 25, 1993 (Rich):
+
+    -t option
+
+	reinstated for the sake of compatibility. Some old
+	shells scripts and man(1) from SunOs want this, sigh
+
+    Compiler and system dependencies
+
+	Some systems pull in sys/types.h via #include <time.h> and then
+	the compiler complains about two ushort typedefs. Therefore,
+	ushort is now Ushort (and uchar Uchar).
+
+	The SVID specifies a strdup, POSIX doesn't, anyway, troff
+	provides its own version, slightly different then the standard
+	one. A To prevent name clashes with that definion, renamed to
+	strdupl.
+
+June 24, 1993 (Rich):
+
+	-V option added for DWB3.4 (rich)
+
+May 18, 1993:
+
+    Trivial fix (.cf) request for troff -a 
+
+	issuing
+
+		.cf /dev/null
+
+	with troff -a gives some spurious output:
+
+		H720
+		H720
+		s10
+		f1
+
+	fixed  by checking for ascii mode it ptesc(), ptps() and
+	ptfont() in t10.c
+
+
+    Enhancement
+
+	Added a .tm request to roff. Works just like .tm, but now
+	it will do it to file. The name is coined by Carmela. Great
+	for creating indeces & toc's (we hope).
+
+May 18 1993:
+
+    Compatibilty change
+
+	Somebody complained that his favorite macro didn't work:
+	it had a BELL (^G) in the name.  This was a non-documented
+	feature of earlier versions of troff (although the
+	documentation actually doesn't say that you can. (They can
+	only be used for delimiters or with the tr request), so it
+	isn't that important).
+
+	But the sake of eternal backward compatibilaty I allowed
+	some control characters like, STX, ACK,  etc. also be part
+	of a macro/string name.
+
+	While at it, I made it also possible to have eight bit
+	characters be part of the name. It might be that this screws
+	up the way users think about these things. For UNICODE
+	versions, they probably want to do that as well, and that
+	won't work as easy, (because these characters are 16-bits
+	wide), so it is dubious whether we actually want this.
+
+	BTW. Now
+
+		.de \(ts\ts
+		.tm terminal sigma macro
+		..
+		.\(ts\(ts
+
+	also works, as long the internal cookie for ts isn't more then
+	eight bits.
+
+May 12, 1993:
+
+    Syntax change
+
+	Some requests accept tabs as a separator, some don't and
+	this can be a nuisance.  Now a tab is also recognized as
+	an argument separator for requests, this makes
+
+		.so	/dev/null
+
+	works.
+
+	To be more precise, any motion character is allowed, so
+
+		.so\h'5i'/dev/null
+
+	will work as well, if one really wants that.
+
+	It will be a problem for users who really relied on this as in
+
+		.ds x	string
+	
+	and expect the tab to become part of the string a, but I haven't
+	seen any use of that (obscure trick).
+
+May 6, 1993:
+
+    Eileen count fixed
+
+	Troff sometimes went in a loop, and exited with: ``job
+	looping; check abuse of macros'' (also known as the Eileen's
+	loop). It can be forced with the next trivial programme:
+
+		.de ff
+		.di xx
+		..
+		.wh -1 ff
+		.bp
+
+	Basically what happens is that a page transition now will
+	happen in a diversion, which doesn't make sense. Wat really
+	happens is that eject() (in n7.c) doesn't eject the frame
+	because we are in a diversion.  This cause the loop in n1.c
+	(because now always stack->pname <= ejl). Adding check on
+	whether we are not in a diversion takes care of the problem.
+
+March 30, 1993:
+
+    Need request, .ne
+
+	When there is a begin of page trap set, and the first thing
+	in the file is a .ne request, the trap gets fired, but,
+	the x font R etc. cookies doen't come out, because the
+	troff thinks that the first page pseudo transition already
+	took place.  Fixed by forcing the start of the first page
+	in the casene request with the same code as in casetl (which
+	caused a similar problem quite some time ago).
+
+    Change to .cf request ``Here document''
+
+	If the argument of .cf starts with a <<, the rest of it is taken
+	as an EOF token. It will reat the rest of the input until it hits
+	the EOF token and copies it to the output. This is similar as
+	the shell's ``here document'' mechanisme and put in place to
+	improve the kludgy way picasso, picpack etc. now include
+	postscript.
+
+    Using troff -TLatin1 (DWB version) and \N'...' caused core dump
+
+	In t11, in chadd, it should test on NCHARS - ALPHABET to see
+	whether we run out of table space (and we probably should beaf
+	up NCHARS for the DWB version).
+
+March 16, 1993:
+
+    Diversion rename bug fix
+
+	It is possible to get troff in an infinite loop by renaming a
+	diversion in progress, and calling it later with the
+	new name (as in .di xx, .rn xx yy, .yy). The effect depends on
+	whether troff already put stuff in the diversion or not.
+
+	Fix by having .rn also rename the current diversion (if
+	there is any and when appropriate).  If the diversion calls
+	itself by the new name and given the fix made on 11 nov
+	1992, this will now result in an error.  (BTW, the fix from
+	11 nov is improved: diversions nest, so we have to account
+	for that).
+
+December 18, 1992:
+	Some people have complete novels as comments, so we need
+	to skip comments while checking the legality of font files.
+	thaks Rixh
+
+December 16, 1992
+
+	Some people rely on the order that -r arguments are given,
+	so that troff -rC1 -rC3 ends up setting register C to 3.
+	Because cpushback() pushes things in a LIFO order back, we
+	have to do the same to get -r args in a FIFO order.
+
+Nov 17, 1992:
+
+	Giving a -rL8 option cuased the string .nr L 8 to be printed
+	on the output, using the wonderful 3b2. Some garbage was
+	left in buf[100] in main(). Fixed by setting buf[0] explicitly
+	to 0 (because some C-compilers complain about ``no automatic
+	aggregate initialization'').
+
+Nov 11, 1992:
+
+    Diversion bug fix
+
+	If a diversion was being read and the input is faulty so
+	the diversion was reading in itself, it caused troff to
+	loop undefinitely. This was easily fixed by a test in
+	control(a,b) in n1.c.
+
+	Something similar things might happen with macros causing
+	the ``eileenct problem'', but I didn't look for that. We
+	have to wait until it happens.
+
+Oct 26, 1992:
+
+    Numeric arguments:
+
+	Illegal argments are treated as missing arguments. This
+	changed the semantics of .ll, .ls, .in, .lg,  .ul, .cu .lt
+	(which acted as if the argument was 0) and .ps which was
+	simply ignored with an illegal argument.
+
+	Tidied up number parsing in atoi1(). This prevents arguments
+	like .x or 1.2.3.4 being interpret as a legal number (nonumb = 0)
+
+    Numeric arguments error reporting:
+
+	Controlled by .pt, illegal numbers are now reported (default
+	trace mode is 1).  This is also true for the escapes:
+	\h'..', \v'..' \H'..', \S'..', \N'..', \D'..', \l'.., \L'..
+	and \x'..'.
+
+	\D'c' is the only drawing request which doesn't take a pair
+	of numbers as arguments, so a special case is put here in
+	setdraw() (This code actually could use an overhaul to get
+	better parsing. As long as the \D'..' cookies are machine
+	generated it is low on the priority list).
+
+	Don't generate an error if the illegal argument to a request
+	is a \}. It is too painful to do right (although it can be
+	done, but it would clutter getch() and getcho() even more).
+
+    Input line numbers (.c register) bug fixes:
+
+	In not taken branches of .if or .ie, the input line #
+	(numtab[CD].val) should be raised when necessary (in eatblk()).
+
+	For concealed newlines, we still should count the line for input.
+
+	Setfield (n9.c) sometimes pushes the rest of the line back to
+	the input (including \n), without adjusting numtab[CD].val
+
+	Because .c (and so numtab[CD].val) is the number of lines read
+	and the error might actually happen in the current line
+	(before seeing the '\n), we need to apply correction in
+	errprint when nlflg set. (This correction needs to be undone
+	when inside a macro because the nlflg is set by reading the
+	args to the macro).
+
+    Line number setting (.lf) request bug fixes:
+
+	I interpret that the .c register will contain the number of
+	read lines, not including the current one.
+
+	Also, don't change the input line number when the first
+	argument of .lf is not a number.
+
+	As a net effect, the next input
+
+		.EQ
+		.EN
+		.ab
+
+	will generate the same output whether eqn has been used or not.
+
+    If request bug fix:
+
+	A ``.if page .tm foo'' caused the next line being ignored;
+	This bcause when the 2nd delimiter of a string couldn't be
+	found in cmpstr, the next line was always eaten. Solution:
+	in caseif1, if the condition is false, we should check
+	nlflg before eating a block.  (Note: We might have eaten
+	\{\ as well.  We could disallow the \{\ in a string to be
+	compared to prevent that but that might break other things).
+
+    Enhancement to .pt:
+
+	The .pt now pops the previous values when no argument is
+	specified. Turned out to be handy when chasing for problems.
+	Just ``bracked'' the code with .pt 7 and .pt and you get
+	a trace of only that block. The meaning of the arguments
+	is now:
+		01      trace numeric arguments (default on)
+		02	trace requests
+		04	trace macros
+
+    Abort request (.ab) beautification:
+
+	Don't print the extra carriage return when .ab is called
+	without an argument.
+
+Oct 12, 1992:
+
+	(Comments & spelling errors from this day on by jaap)
+
+	replaced 32767 by INT_MAX in several places to allow for very
+	long pages (on 32-but machines).
+
+	The ``.fp 1 R   \"COMMENT'' complains about ``./troff: Can't
+	open font file /usr/lib/font/devpost/h'' on some systems. It
+	sees the tab as part of the optional font file.  Apparently it
+	is system dependent whether isgraph() includes the tab
+	character.  Fixed by using getach() in getname() in n1.c
+	instead.
+
+Aug 28, 1992:
+	removed call to popi from rdtty();  it was eating up the
+	rest of the macro if it was used from within one.  (thanks, jaap)
+
+
+Jul 21, 1992:
+	added extra test in nextfile() to pop current input file
+	only if not in .nx command.  thanks to jaap.
+
+	added test in getword() to avoid hyphenating after \z character,
+	which prevents any hyphenation inside \X'...'.  thanks to jaap.
+
+	added, then removed, code in getword() to prevent hyphenating
+	anything shorter than 6 characters.  looks like it changed a
+	lot more than i thought.
+
+Jul 12, 1992:
+	added .pt request to trace macros and requests (from jaap).
+	.pt N Print trace of macros (N=1), requests (N=2) or both (N=3)
+
+Jun 5, 1992:
+	added tests to t.twrest and t.twinit to avoid 0 deref in
+	n2 and n10, for nroff -t xxxxx.  thanks to Rich Drechsler.
+
+May 22, 1992:
+	added extern decls to e.g., void Tchar (*hmot)(void) in tdef.h
+	and added definition to ni.c, so pointers are defined explicitly.
+	makes it work on turbo c++ and probably others.
+
+	changed a couple of isdigit's and isgraph(getch()) to avoid
+	multiple evaluation (even though it shouldn't happen).
+
+	Made /usr/bin/nroff a shell script.
+
+May 12, 1992:
+	n1.c: need p++ after strrchr to skip / in program name.
+	thanks to Rich Drechsler.
+
+Apr 17, 1992:
+	casefi(), n5.c: .u register should be 0 or 1, not incremented
+	with each .fi.
+
+Apr 5, 1992:
+	fiddled n7.c and added _nmwid to the environment, to add a
+	5th argument to .nm:  the maximum number of digits in any
+	line number.  default is 3, which was previously hardwired in.
+
+	added jaap's code for yet another register which actually delivers
+	a string, called .S (so it can easily go in the switch in setn()
+	in n4.c); it delivers the current tabstop and alignment modes in
+	a format suitable for a subsequent .ta \n(.S command:
+		.ds T \n(.S
+		...
+		.ta \*T
+
+Mar 30, 1992:
+	added test in getword to avoid hyphenating things with motions
+	(and avoid a core dump sometimes too).
+
+Mar 13, 1992:
+	\n(sb initialized wrong in setwd().
+
+	TYPESETTER=foo troff -Tpost used foo instead of post.
+
+Mar 12, 1992:
+	rearranged tests in popf so that .so is closed properly before
+	moving on to the next macro package.
+
+Mar 1, 1992:
+	input mechanism rearranged to use getc() instead of stack of
+	explicit input buffers.  5-10% slowdown.
+
+Jan 28, 1992:
+	fixed .tm \(mi to print something sensible.  thanks to jaap.
+
+Jan 2, 1992:
+	fiddle setfp so doesn't put out font stuff if -a turned on.
+
+Dec 17, 1991:
+	copy 3rd argument in .fp commands to x font ... lines when it contains
+	a /, for testing fonts locally.
+
+Dec 13, 1991:
+	parameterize the font directories, etc., so can be set in makefiles.
+	added -N argument to run as nroff.
+
+Nov 8, 1991:
+	add a maplow(towlower...) in n8.c to handle brain-damaged libraries.
+
+Nov 2, 1991:
+	merged nroff into troff, based on Ken's plan 9 version.
+	merged nii.c into ni.c, removed tw.h, etc.  more work needed
+	to make this stuff cleaner.
+
+July 27, 1991:
+	added test in setn in n4 to fix bug that permitted things like
+	\n (ab to work "properly".  thanks to jaap for finding and fixing.
+
+	added paranoid testing in t11 to make sure font files look ok.
+
+May 13, 1991:
+	moved evaluation of \(xx from copy mode to non-copy mode, so that
+	weird character names wouldn't get reevaluated in argument parsing.
+	installed july 27.
+
+May 6, 1991:
+	increased size of hyphenation exception buffer to 512 from 128
+
+Apr 14, 1991:
+	added an extra redundant call of ptfont in setfp, since it appears
+	that some versions of adobe transcript assume that an "x font" command
+	means to change the actual font as well.  the fix preserves the current font.
+	thanks to david brailsford and friends for spotting the problem.
+
+	fixed up tests in alpha() in n8 to defend isalpha() against too-big inputs.
+	punct() argument had wrong type too.  thanks to rich drexler and peter nelson.
+
+Mar 19, 1991:
+	fixed bug that prevented .rd from working with new corebuf organization.
+
+	fixed bug that caused .ig inside diversions to give bad storage
+	allocation.  thanks to arthur david olson, whose fix was on netnews
+	3 years earlier.
+
+Mar 5, 1991:
+	huge table sizes for kanji.
+
+Feb ??, 1991:
+	working on dealing with large alphabets, notably kanji.
+	added "defaultwidth" to font descriptions, for characters
+	not given an explicit width.
+
+Jan, 1991:
+	added tex hyphenation, using standard tex data files, but not the
+	elaborate compressed trie, which is a lot of trouble to save maybe
+	40k bytes.  this appears to run at exactly the same speed as before.
+
+	so far this stuff reads into a fixed size array; that should change.
+	it should also be possible to deal with multiple languages.
+
+	the command .ha sets the algorithm.  .ha 1 => tex, with troff rules
+	if tex doesn't hyphenate;  .ha 0 gives troff rules, and .ha resets
+	to the default, which is tex.  the hyphenation algorithm is part of
+	the environment, a nod to a future in which i handle more than one
+	language.
+
+	replaced the fixed size corebuf array for string/macro storage by
+	a dynamic structure that can grow.
+
+	this appears to slow things down by maybe 3%.  the code is about
+	the same complexity.
+
+Dec 27, 1990:
+	converted to ansi c, based on some work by ken thompson, but not
+	as thoroughly as he did.  there is a shell script unansi and an awk
+	program cvt that will help you step back in time if you do not have
+	an ansi c compiler.
+
+	moved the special-name characters up to 256 instead of 128, although
+	done in terms of ALPHABET, so one can pass 8 bit characters through.
+	removed lots of 0177's and similar numbers.  input is now not filtered,
+	and if a character with the 8th bit on comes in, it will go out again.
+
+	fixed t11.c to read character names in hex or octal as well as
+	single-character ascii.
+
+	unknown characters are now carried through with width = spacewidth.
+	needs a way to set widths.
+
+	removed all signal handling from troff.  you signal, you die.
+
+	added -d option to print version number.
+
+Dec 7, 1990:
+	.fp 3 V VERYLONGNAME used to truncate the name to 10 chars; fixed.
+
+	increased the limit on FBUFSZ for tables with very long fields.
+
+	changed atoi1() to use double to avoid intermediate overflow.
+
+	moved filenames like /usr/lib/font into tdef.h for easy change.
+	removed some dreggish definitions.
+
+	cleaned up non-portable error printing stuff;  fixed up some messages.
+
+Dec 12, 1989:
+	Removed the .! command, an undocumented synonym for .sy.
+
+Dec 4, 1989:
+	Another wart to the \X code, to try to preserve blanks in all situations.
+
+Nov 17, 1989:
+	A number of small changes preparatory to getting rid of nroff.
+	The argument -Tnroff or -Tnroff-12 changes some internal values
+	so that the predicate .if n is true and certain arithmetic operations
+	are done as if nroff.  This design is not yet final.
+
+Nov 7, 1989:
+	Fixed hyphenation for nov-ice, ad-vice, de-vice, ser-vice, *-vice.
+
+Oct 11, 1989:
+	It is now permitted to do an explicit change to font S.
+	It is not clear what will break (though nothing seems to have).
+
+Oct 10, 1989:
+	Modified flush code to always put out \nH instead of sometimes h.
+	This makes it easier to parse the output for positioning.
+
+Sep 9, 1989:
+	Fixed internal representation of \D'~...' so that it
+	is immune to .tr ~ and variations.  No external change.
+
+Aug 9, 1989:
+	Changed .tm so it outputs \e, \%, \-, \&, \(blank).
+	This might break indexing code.
+	Only in the new version, as are all subsequent fixes.
+
+July, 1989:
+	A major internal change:  font information is read in ascii
+	instead of the weird binary format of makedev (which is now dead).
+	character names need not all appear in DESC;  new names that
+	appear when a font is used become part of the set of known names.
+
+	There are some flaky bits here (it's conceivable that some \N
+	number will collide with a real name), and it's probably 10-15%
+	slower.  Tant pis.
+
+	As a by-product, nroff no longer compiles.  I'll probably get
+	back to this, but an alternative is to bag it once and for all.
+
+May 25, 1989:
+	Another bug in \l, this time when width is 0.  Not installed,
+	since it's in the new font version.
+
+Apr 23, 1989:
+	Fixed bug in n9 that caused core dump with unterminated
+	\l command, like \l'1.5i
+
+	ptflush no longer called when -a is on.
+
+Apr 12, 1989:
+	fixed bug in n2 that failed to suppress printing of \!
+	output when a -o was in effect.
+
+Apr 5, 1989:
+	.fl and \X now cause output of size, font, hpos and vpos.
+	this is necesary for postprocessors that intend to insert
+	independent material, such as postscript.
+
+Feb 1, 1989:
+	wait for .pi pipe to empty before exiting
+
+Oct 2, 1988:
+	default is now -Tpost
+
+Sep 19, 1988:
+	added abortive code to handle built-up characters by
+	passing something through as \D'b...'.  never used.
+
+Jul 4, 1988:
+	replaced the sbrk nonsense in n3.c by calls to malloc.
+
+	\N now tests against proper font size.
+
+	installed Jaap Akkerhuis's code (mutatis mutandis) for
+	permitting up to 99 fonts, swapping them into font pos 0
+	as needed.  fixes the long-standing problem of having
+	multiple font changes on a single output line.
+
+Jul 2, 1988:
+	\X now preserves spaces even when contents are diverted.
+
+	\N code safer -- NTRTAB and NWIDCACHE enlarged.
+
+Jul 14, 1987:
+	Fixed obscure bug causing incorrect indentation of .mc output.
blob - /dev/null
blob + 6dc8fa0953a7bb5411dd02f8fd459949019124cb (mode 644)
--- /dev/null
+++ src/cmd/troff/README
@@ -0,0 +1,31 @@
+To make troff (actually a.out):
+
+	make
+
+You will also need to write a driver for your favorite output device.
+d202.c provides a model, although it is specialized to a machine no
+one has.  There are also a variety of postscript drivers that are the
+best thing to use if you have a postscript device.
+
+You will also have to make a DESC file for your typesetter and some
+font description files; see dev202 for examples.  These describe the
+named characters, widths, kerning information, and output codes.
+
+Nroff is the same program as troff, so you should
+
+	cp a.out /usr/bin/troff
+	ln /usr/bin/troff /usr/bin/nroff
+
+or the equivalent.
+
+You will also need terminal description files for your terminals; see
+tab.37, tab.450 and tab.lp for examples.
+
+Troff uses files that are normally stored in /usr/lib/font;
+macro packages are in /usr/lib/tmac; and nroff tables are in
+/usr/lib/term.  You can edit tdef.h to change these assumptions.
+
+There have been a few features since the last version, and a number of
+significant internal changes.  Not all are improvements, of course.
+Most of the more recent changes, including bug fixes, are in FIXES,
+which you should read also.
blob - /dev/null
blob + 3426d626676923632f3d5ee921746a5a77c25af7 (mode 644)
--- /dev/null
+++ src/cmd/troff/cvt
@@ -0,0 +1,45 @@
+
+awk '
+
+/^{/ {
+	if (prev != "") {
+		# comments can be trouble (e.g. ffree())
+		if ( (c = match(prev, /\/\*.*\*\/$/)) != 0 ) {
+			comment = substr(prev, c)
+			sub(/\/\*.*\*\/$/, "", prev)
+		} else comment = ""
+
+		x = prev
+
+		# isolate argument list
+		sub(/^[^(]*\(/, "", x)
+		sub(/\)[^)]*$/, "", x)
+
+		# find the names in it
+		n = split(x, args)
+		arglist = ""
+		for (i = 2; i <= n; i += 2)
+			arglist = arglist args[i]
+		gsub(/\(\*f\)\(Tchar\)/, "f", arglist)	# special case for n4.c
+		gsub(/\[[0-9]+\]/, "", arglist)		#     for n8.c
+		gsub(/[*()\[\]]/, "", arglist)		# discard noise characters *()[]
+		gsub(/,/, ", ", arglist)		# space nicely
+		sub(/\(.*\)/, "(" arglist ")", prev)	# reconstruct
+		print prev comment
+
+		# argument declarations
+		gsub(/,/, ";", x)
+		gsub(/\(\*f\)\(Tchar\)/, "(*f)()", x)	# special case for n4.c
+		if (x != "")
+			print "\t" x ";"
+	}
+	prev = $0
+	next
+}
+
+{	print prev
+	prev = $0
+}
+
+END { print prev }
+' $*
blob - /dev/null
blob + a63e5fdeed896d5f27aba63425ee25aa2d1bc931 (mode 644)
--- /dev/null
+++ src/cmd/troff/dwbinit.c
@@ -0,0 +1,313 @@
+/*
+ *
+ * Pathname management routines for DWB C programs.
+ *
+ * Applications should initialize a dwbinit array with the string
+ * pointers and arrays that need to be updated, and then hand that
+ * array to DWBinit before much else happens in their main program.
+ * DWBinit calls DWBhome to get the current home directory. DWBhome
+ * uses the last definition of DWBENV (usually "DWBHOME") in file
+ * DWBCONFIG (e.g., /usr/lib/dwb3.4) or the value assigned to that
+ * variable in the environment if the DWBCONFIG file doesn't exist,
+ * can't be read, or doesn't define DWBENV.
+ *
+ * DWBCONFIG must be a simple shell script - comments, a definition
+ * of DWBHOME, and perhaps an export or echo is about all that's
+ * allowed. The parsing in DWBhome is simple and makes no attempt
+ * to duplicate the shell. It only looks for DWBHOME= as the first
+ * non-white space string on a line, so
+ *
+ *	#
+ *	# A sample DWBCONFIG shell script
+ *	#
+ *
+ *	DWBHOME=/usr/add-on/dwb3.4
+ *	export DWBHOME
+ *
+ * means DWBhome would return "/usr/add-on/dwb3.4" for the DWB home
+ * directory. A DWBCONFIG file means there can only be one working
+ * copy of a DWB release on a system, which seems like a good idea.
+ * Using DWBCONFIG also means programs will always include correct
+ * versions of files (e.g., prologues or macro packages).
+ *
+ * Relying on an environment variable guarantees nothing. You could
+ * execute a version of dpost, but your environment might point at
+ * incorrect font tables or prologues. Despite the obvious problems
+ * we've also implemented an environment variable approach, but it's
+ * only used if there's no DWBCONFIG file.
+ *
+ * DWBinit calls DWBhome to get the DWB home directory prefix and
+ * then marches through its dwbinit argument, removing the default
+ * home directory and prepending the new home. DWBinit stops when
+ * it reaches an element that has NULL for its address and value
+ * fields. Pointers in a dwbinit array are reallocated and properly
+ * initialized; arrays are simply reinitialized if there's room.
+ * All pathnames that are to be adjusted should be relative. For
+ * example,
+ *
+ *	char	*fontdir = "lib/font";
+ *	char	xyzzy[25] = "etc/xyzzy";
+ *
+ * would be represented in a dwbinit array as,
+ *
+ *	dwbinit allpaths[] = {
+ *		&fontdir, NULL, 0,
+ *		NULL, xyzzy, sizeof(xyzzy),
+ *		NULL, NULL, 0
+ *	};
+ *		
+ * The last element must have NULL entries for the address and
+ * value fields. The main() routine would then do,
+ *
+ *	#include "dwbinit.h"
+ *
+ *	main() {
+ *
+ *		DWBinit("program name", allpaths);
+ *		...
+ *	}
+ *
+ * Debugging is enabled if DWBDEBUG is in the environment and has
+ * the value ON. Output is occasionally useful and probably should
+ * be documented.
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dwbinit.h"
+
+#ifndef DWBCONFIG
+#define DWBCONFIG	"/dev/null"
+#endif
+
+#ifndef DWBENV
+#define DWBENV		"DWBHOME"
+#endif
+
+#ifndef DWBHOME
+#define DWBHOME		""
+#endif
+
+#ifndef DWBDEBUG
+#define DWBDEBUG	"DWBDEBUG"
+#endif
+
+#ifndef DWBPREFIX
+#define DWBPREFIX	"\\*(.P"
+#endif
+
+/*****************************************************************************/
+
+void DWBdebug(dwbinit *ptr, int level)
+{
+
+    char	*path;
+    char	*home;
+    static char	*debug = NULL;
+
+/*
+ *
+ * Debugging output, but only if DWBDEBUG is defined to be ON in the
+ * environment. Dumps general info the first time through.
+ *
+ */
+
+    if ( debug == NULL && (debug = getenv(DWBDEBUG)) == NULL )
+	debug = "OFF";
+
+    if ( strcmp(debug, "ON") == 0 ) {
+	if ( level == 0 ) {
+	    fprintf(stderr, "Environment variable: %s\n", DWBENV);
+	    fprintf(stderr, "Configuration file: %s\n", DWBCONFIG);
+	    fprintf(stderr, "Default home: %s\n", DWBHOME);
+	    if ( (home = DWBhome()) != NULL )
+		fprintf(stderr, "Current home: %s\n", home);
+	}   /* End if */
+
+	fprintf(stderr, "\n%s pathnames:\n", level == 0 ? "Original" : "Final");
+	for ( ; ptr->value != NULL || ptr->address != NULL; ptr++ ) {
+	    if ( (path = ptr->value) == NULL ) {
+		path = *ptr->address;
+		fprintf(stderr, " pointer: %s\n", path);
+	    } else fprintf(stderr, " array[%d]: %s\n", ptr->length, path);
+	    if ( level == 0 && *path == '/' )
+		fprintf(stderr, "  WARNING - absolute path\n");
+	}   /* End for */
+    }	/* End if */
+
+}   /* End of DWBdebug */
+
+/*****************************************************************************/
+
+char *DWBhome(void)
+{
+
+    FILE	*fp;
+    char	*ptr;
+    char	*path;
+    int		len;
+    char	buf[200];
+    char	*home = NULL;
+
+/*
+ *
+ * Return the DWB home directory. Uses the last definition of DWBENV
+ * (usually "DWBHOME") in file DWBCONFIG (perhaps /usr/lib/dwb3.4) or
+ * the value assigned to the variable named by the DWBENV string in
+ * the environment if DWBCONFIG doesn't exist or doesn't define DWBENV.
+ * Skips the file lookup if DWBCONFIG can't be read. Returns NULL if
+ * there's no home directory.
+ *
+ */
+
+    if ( (fp = fopen(DWBCONFIG, "r")) != NULL ) {
+	len = strlen(DWBENV);
+	while ( fgets(buf, sizeof(buf), fp) != NULL ) {
+	    for ( ptr = buf; isspace(*ptr); ptr++ ) ;
+	    if ( strncmp(ptr, DWBENV, len) == 0 && *(ptr+len) == '=' ) {
+		path = ptr + len + 1;
+		for ( ptr = path; !isspace(*ptr) && *ptr != ';'; ptr++ ) ;
+		*ptr = '\0';
+		if ( home != NULL )
+		    free(home);
+		if ( (home = malloc(strlen(path)+1)) != NULL )
+		    strcpy(home, path);
+	    }	/* End if */
+	}   /* End while */
+	fclose(fp);
+    }   /* End if */
+
+    if ( home == NULL ) {
+	if ( (home = getenv(DWBENV)) == NULL ) {
+	    if ( (home = DWBHOME) == NULL || *home == '\0' || *home == ' ' )
+		home = NULL;
+	}   /* End if */
+    }	/* End if */
+
+    while (home && *home == '/' && *(home +1) == '/')	/* remove extra slashes */
+	home++;
+    return(home);
+
+}   /* End of DWBhome */
+
+/*****************************************************************************/
+
+void DWBinit(char *prog, dwbinit *paths)
+{
+
+    char	*prefix;
+    char	*value;
+    char	*path;
+    int		plen;
+    int		length;
+    dwbinit	*opaths = paths;
+
+/*
+ *
+ * Adjust the pathnames listed in paths, using the home directory
+ * returned by DWBhome(). Stops when it reaches an element that has
+ * NULL address and value fields. Assumes pathnames are relative,
+ * but changes everything. DWBdebug issues a warning if an original
+ * path begins with a /.
+ *
+ * A non-NULL address refers to a pointer, which is reallocated and
+ * then reinitialized. A NULL address implies a non-NULL value field
+ * and describes a character array that we only reinitialize. The
+ * length field for an array is the size of that array. The length
+ * field of a pointer is an increment that's added to the length
+ * required to store the new pathname string - should help when we
+ * want to change character arrays to pointers in applications like
+ * troff.
+ *
+ */
+
+    if ( (prefix = DWBhome()) == NULL ) {
+	fprintf(stderr, "%s: no DWB home directory\n", prog);
+	exit(1);
+    }	/* End if */
+
+    DWBdebug(opaths, 0);
+    plen = strlen(prefix);
+
+    for ( ; paths->value != NULL || paths->address != NULL; paths++ ) {
+	if ( paths->address == NULL ) {
+	    length = 0;
+	    value = paths->value;
+	} else {
+	    length = paths->length;
+	    value = *paths->address;
+	}   /* End else */
+
+	length += plen + 1 + strlen(value);	/* +1 is for the '/' */
+
+	if ( (path = malloc(length+1)) == NULL ) {
+	    fprintf(stderr, "%s: can't allocate pathname memory\n", prog);
+	    exit(1);
+	}   /* End if */
+
+	if ( *value != '\0' ) {
+	    char *eop = prefix;
+	    while(*eop++)
+		;
+	    eop -= 2;
+	    if (*value != '/' && *eop != '/') {
+		sprintf(path, "%s/%s", prefix, value);
+	    } else if (*value == '/' && *eop == '/') {
+		value++;
+		sprintf(path, "%s%s", prefix, value);
+	    } else
+		sprintf(path, "%s%s", prefix, value);
+	} else
+		sprintf(path, "%s", prefix);
+
+	if ( paths->address == NULL ) {
+	    if ( strlen(path) >= paths->length ) {
+		fprintf(stderr, "%s: no room for %s\n", prog, path);
+		exit(1);
+	    }	/* End if */
+	    strcpy(paths->value, path);
+	    free(path);
+	} else *paths->address = path;
+    }	/* End for */
+
+    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 */
+
+/*****************************************************************************/
+
blob - /dev/null
blob + acb1476cc17c1495fa77e9b26ef6174212328da9 (mode 644)
--- /dev/null
+++ src/cmd/troff/dwbinit.h
@@ -0,0 +1,19 @@
+/*
+ *
+ * A structure used to adjust pathnames in DWB C code. Pointers
+ * set the address field, arrays use the value field and must
+ * also set length to the number elements in the array. Pointers
+ * are always reallocated and then reinitialized; arrays are only
+ * reinitialized, if there's room.
+ *
+ */
+
+typedef struct {
+	char	**address;
+	char	*value;
+	int	length;
+} dwbinit;
+
+extern void	DWBinit(char *, dwbinit *);
+extern char*	DWBhome(void);
+extern void	DWBprefix(char *, char *, int);
blob - /dev/null
blob + 42147880128836d939ce2fe7f42d2162425fe0e1 (mode 644)
--- /dev/null
+++ src/cmd/troff/ext.h
@@ -0,0 +1,184 @@
+extern	int	TROFF;
+
+extern	int	alphabet;
+extern	char	**argp;
+extern	char	*eibuf;
+extern	char	*ibufp;
+extern	char	*obufp;
+extern	char	*unlkp;
+extern	char	*xbufp;
+extern	char	*xeibuf;
+extern	char	cfname[NSO+1][NS];
+extern  int	trace;
+extern	char	devname[];
+extern	char	ibuf[IBUFSZ];
+extern	char	mfiles[NMF][NS];
+extern	char	nextf[];
+extern	char	obuf[];
+extern	char	termtab[];
+extern	char	fontdir[];
+extern	Font	fonts[MAXFONTS+1];
+extern	char	xbuf[IBUFSZ];
+extern	Offset	apptr;
+extern	Offset	ip;
+extern	Offset	nextb;
+extern	Offset	offset;
+extern	Offset	woff;
+extern	Numerr	numerr;
+extern	int	*pnp;
+extern	int	pstab[];
+extern	int	nsizes;
+extern	int	app;
+extern	int	ascii;
+extern	int	bd;
+extern	int	bdtab[];
+extern	int	ccs;
+extern	char	*chnames[];	/* chnames[n-ALPHABET] -> name of char n */
+extern	int	copyf;
+extern	int	cs;
+extern	int	dfact;
+extern	int	dfactd;
+extern	int	diflg;
+extern	int	dilev;
+extern	int	donef;
+extern	int	dotT;
+extern	int	dpn;
+extern	int	ds;
+extern	int	ejf;
+extern	int	em;
+extern	int	eqflg;
+extern	int	error;
+extern	int	esc;
+extern	int	eschar;
+extern	int	ev;
+extern	int	evi;
+extern	int	evlist[EVLSZ];
+extern	int	fc;
+extern	int	flss;
+extern	int	fontlab[];
+extern	int	hflg;
+extern	int	ibf;
+extern	int	ifi;
+extern	int	iflg;
+extern	int	init;
+extern	int	lead;
+extern	int	lg;
+extern	int	lgf;
+extern	int	macerr;
+extern	int	mflg;
+extern	int	mfont;
+extern	int	mlist[NTRAP];
+extern	int	mpts;
+extern	int	nchnames;
+extern	int	ndone;
+extern	int	newmn;
+extern	int	nflush;
+extern	int	nfo;
+extern	int	nfonts;
+extern	int	nform;
+extern	int	nhyp;
+extern	int	nlflg;
+extern	int	nlist[NTRAP];
+extern	int	nmfi;
+extern	int	nonumb;
+extern	int	noscale;
+extern	int	npn;
+extern	int	npnflg;
+extern	int	nx;
+extern	int	oldbits;
+extern	int	oldmn;
+extern	int	over;
+extern	int	padc;
+extern	int	pfont;
+extern	int	pfrom;
+extern	int	pipeflg;
+extern	int	pl;
+extern	int	pnlist[];
+extern	int	po1;
+extern	int	po;
+extern	int	ppts;
+extern	int	print;
+extern	FILE	*ptid;
+extern	int	pto;
+extern	int	quiet;
+extern	int	ralss;
+extern	int	rargc;
+extern	int	raw;
+extern	int	res;
+extern	int	sbold;
+extern	int	setwdf;
+extern	int	sfont;
+extern	int	smnt;
+extern	int	stdi;
+extern	int	stop;
+extern	int	sv;
+extern	int	tabch,	ldrch;
+extern	int	tflg;
+extern	int	totout;
+extern	int	trap;
+extern	Ushort	trtab[];
+extern	int	tty;
+extern	int	ulfont;
+extern	int	vflag;
+extern	int	whichroff;
+extern	int	widthp;
+extern	int	xfont;
+extern	int	xpts;
+extern	Stack	*ejl;
+extern	Stack	*frame;
+extern	Stack	*stk;
+extern	Stack	*nxf;
+extern	Tchar	**hyp;
+extern	Tchar	*olinep;
+extern	Tchar	pbbuf[NC];
+extern	Tchar	*pbp;
+extern	Tchar	*lastpbp;
+extern	Tchar	ch;
+extern	Tchar	nrbits;
+extern	Tbuf	_oline;
+extern	Wcache	widcache[];
+extern	char	gchtab[];
+extern	Diver	d[NDI];
+extern	Diver	*dip;
+
+
+extern	char	xchname[];
+extern	short	xchtab[];
+extern	char	*codestr;
+extern	char	*chnamep;
+extern	short	*chtab;
+extern	int	nchtab;
+
+extern Numtab *numtabp;
+
+/* these characters are used as various signals or values
+/* in miscellaneous places.
+/* values are set in specnames in t10.c
+*/
+
+extern int	c_hyphen;
+extern int	c_emdash;
+extern int	c_rule;
+extern int	c_minus;
+extern int	c_fi;
+extern int	c_fl;
+extern int	c_ff;
+extern int	c_ffi;
+extern int	c_ffl;
+extern int	c_acute;
+extern int	c_grave;
+extern int	c_under;
+extern int	c_rooten;
+extern int	c_boxrule;
+extern int	c_lefthand;
+extern int	c_dagger;
+extern int	c_isalnum;
+
+/*
+ * String pointers for DWB pathname management.
+ */
+
+extern char	*DWBfontdir;
+extern char	*DWBntermdir;
+extern char	*DWBalthyphens;
+
blob - /dev/null
blob + eccbfbdb655be1402020ec4c28a5cd7cfc76af70 (mode 644)
--- /dev/null
+++ src/cmd/troff/find
@@ -0,0 +1 @@
+grep $1 *.[ch]
blob - /dev/null
blob + 6bd94ada6d478a7ac4b580a24285575888f84363 (mode 644)
--- /dev/null
+++ src/cmd/troff/fns.h
@@ -0,0 +1,384 @@
+/*
+ * other
+ */
+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);
+
+/*
+ * c1.c
+ */
+void	init0(void);
+void	init2(void);
+void	cvtime(void);
+void	errprint(void);
+int	control(int a, int b);
+void	casept(void);
+int	getrq(void);
+Tchar	getch(void);
+void	setxon(void);
+Tchar	getch0(void);
+Tchar	get1ch(FILE *);
+void	pushback(Tchar *b);
+void	cpushback(char *b);
+int	nextfile(void);
+int	popf(void);
+void	flushi(void);
+int	getach(void);
+void	casenx(void);
+int	getname(void);
+void	caseso(void);
+void	caself(void);
+void	casecf(void);
+void	getline(char *s, int n);
+void	casesy(void);
+void	getpn(char *a);
+void	setrpt(void);
+
+/*
+ * n2.c
+ */
+int	pchar(Tchar i);
+void	pchar1(Tchar i);
+int	pchar2(Tchar i);
+int	flusho(void);
+void	casedone(void);
+void	caseex(void);
+void	done(int x);
+void	done1(int x);
+void	done2(int x);
+void	done3(int x);
+void	edone(int x);
+void	casepi(void);
+
+/*
+ * c3.c
+ */
+void	blockinit(void);
+char*	grow(char *, int, int);
+void	mnspace(void);
+void	caseig(void);
+void	casern(void);
+void	maddhash(Contab *rp);
+void	munhash(Contab *mp);
+void	mrehash(void);
+void	caserm(void);
+void	caseas(void);
+void	caseds(void);
+void	caseam(void);
+void	casede(void);
+int	findmn(int i);
+void	clrmn(int i);
+Offset	finds(int mn);
+int	skip(void);
+int	copyb(void);
+void	copys(void);
+Offset	alloc(void);
+void	ffree(Offset i);
+void	wbf(Tchar i);
+Tchar	rbf(void);
+Tchar	popi(void);
+Offset	pushi(Offset newip, int mname);
+void*	setbrk(int x);
+int	getsn(void);
+Offset	setstr(void);
+void	collect(void);
+void	seta(void);
+void	caseda(void);
+void	casegd(void);
+void	casedi(void);
+void	casedt(void);
+void	casetl(void);
+void	casepc(void);
+void	casepm(void);
+void	stackdump(void);
+
+/*
+ * c4.c
+ */
+void	setn(void);
+int	wrc(Tchar i);
+void	setn1(int i, int form, Tchar bits);
+void	nnspace(void);
+void	nrehash(void);
+void	nunhash(Numtab *rp);
+int	findr(int i);
+int	usedr(int i);
+int	fnumb(int i, int (*f)(Tchar));
+int	decml(int i, int (*f)(Tchar));
+int	roman(int i, int (*f)(Tchar));
+int	roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp);
+int	abc(int i, int (*f)(Tchar));
+int	abc0(int i, int (*f)(Tchar));
+long	atoi0(void);
+long	ckph(void);
+long	atoi1(Tchar ii);
+void	caserr(void);
+void	casenr(void);
+void	caseaf(void);
+void	setaf(void);
+int	vnumb(int *i);
+int	hnumb(int *i);
+int	inumb(int *n);
+int	quant(int n, int m);
+
+/*
+ * c5.c
+ */
+void	casead(void);
+void	casena(void);
+void	casefi(void);
+void	casenf(void);
+void	casers(void);
+void	casens(void);
+int	chget(int c);
+void	casecc(void);
+void	casec2(void);
+void	casehc(void);
+void	casetc(void);
+void	caselc(void);
+void	casehy(void);
+int	max(int aa, int bb);
+void	casenh(void);
+void	casece(void);
+void	casein(void);
+void	casell(void);
+void	caselt(void);
+void	caseti(void);
+void	casels(void);
+void	casepo(void);
+void	casepl(void);
+void	casewh(void);
+void	casech(void);
+int	findn(int i);
+void	casepn(void);
+void	casebp(void);
+void	casextm(void);
+void	casetm(void);
+void	casefm(void);
+void	casetm1(int ab, FILE *out);
+void	casesp(void);
+void	casesp1(int a);
+void	casert(void);
+void	caseem(void);
+void	casefl(void);
+void	caseev(void);
+void	envcopy(Env *e1, Env *e2);
+void	caseel(void);
+void	caseie(void);
+void	casexif(void);
+void	caseif(void);
+void	caseif1(int);
+void	eatblk(int inblk);
+int	cmpstr(Tchar c);
+void	caserd(void);
+int	rdtty(void);
+void	caseec(void);
+void	caseeo(void);
+void	caseta(void);
+void	casene(void);
+void	casetr(void);
+void	casecu(void);
+void	caseul(void);
+void	caseuf(void);
+void	caseit(void);
+void	casemc(void);
+void	casemk(void);
+void	casesv(void);
+void	caseos(void);
+void	casenm(void);
+void	getnm(int *p, int min);
+void	casenn(void);
+void	caseab(void);
+void	save_tty(void);
+void	restore_tty(void);
+void	set_tty(void);
+void	echo_off(void);
+void	echo_on(void);
+
+/*
+ * t6.c
+ */
+int	t_width(Tchar j);
+void	zapwcache(int s);
+int	onfont(int n, int f);
+int	getcw(int i);
+void	xbits(Tchar i, int bitf);
+Tchar	t_setch(int c);
+Tchar	t_setabs(void);
+int	t_findft(int i);
+void	caseps(void);
+void	casps1(int i);
+int	findps(int i);
+void	t_mchbits(void);
+void	t_setps(void);
+Tchar	t_setht(void);
+Tchar	t_setslant(void);
+void	caseft(void);
+void	t_setfont(int a);
+void	t_setwd(void);
+Tchar	t_vmot(void);
+Tchar	t_hmot(void);
+Tchar	t_mot(void);
+Tchar	t_sethl(int k);
+Tchar	t_makem(int i);
+Tchar	getlg(Tchar i);
+void	caselg(void);
+void	casefp(void);
+char	*strdupl(const char *);
+int	setfp(int pos, int f, char *truename, int print);
+void	casecs(void);
+void	casebd(void);
+void	casevs(void);
+void	casess(void);
+Tchar	t_xlss(void);
+Uchar*	unpair(int i);
+void	outascii(Tchar i);
+
+/*
+ * c7.c
+ */
+void	tbreak(void);
+void	donum(void);
+void	text(void);
+void	nofill(void);
+void	callsp(void);
+void	ckul(void);
+void	storeline(Tchar c, int w);
+void	newline(int a);
+int	findn1(int a);
+void	chkpn(void);
+int	findt(int a);
+int	findt1(void);
+void	eject(Stack *a);
+int	movword(void);
+void	horiz(int i);
+void	setnel(void);
+int	getword(int x);
+void	storeword(Tchar c, int w);
+Tchar	gettch(void);
+
+/*
+ * c8.c
+ */
+void	hyphen(Tchar *wp);
+int	punct(Tchar i);
+int	alph(int i);
+void	caseha(void);
+void	caseht(void);
+void	casehw(void);
+int	exword(void);
+int	suffix(void);
+int	maplow(int i);
+int	vowel(int i);
+Tchar*	chkvow(Tchar *w);
+void	digram(void);
+int	dilook(int a, int b, char t[26][13]);
+
+/*
+ * c9.c
+ */
+Tchar	setz(void);
+void	setline(void);
+int	eat(int c);
+void	setov(void);
+void	setbra(void);
+void	setvline(void);
+void	setdraw(void);
+void	casefc(void);
+Tchar	setfield(int x);
+
+/*
+ * t10.c
+ */
+void	t_ptinit(void);
+void	t_specnames(void);
+void	t_ptout(Tchar i);
+int	ptout0(Tchar *pi);
+void	ptchname(int);
+void	ptflush(void);
+void	ptps(void);
+void	ptfont(void);
+void	ptfpcmd(int f, char *s, char *fn);
+void	t_ptlead(void);
+void	ptesc(void);
+void	ptpage(int n);
+void	pttrailer(void);
+void	ptstop(void);
+void	t_ptpause(void);
+
+/*
+ * t11.c
+ */
+int	getdesc(char *name);
+int	getfont(char *name, int pos);
+int	chadd(char *s, int, int);
+char*	chname(int n);
+int	getlig(FILE *fin);
+
+/*
+ * n6.c
+ */
+int	n_width(Tchar j);
+Tchar	n_setch(int c);
+Tchar	n_setabs(void);
+int	n_findft(int i);
+void	n_mchbits(void);
+void	n_setps(void);
+Tchar	n_setht(void);
+Tchar	n_setslant(void);
+void	n_caseft(void);
+void	n_setfont(int a);
+void	n_setwd(void);
+Tchar	n_vmot(void);
+Tchar	n_hmot(void);
+Tchar	n_mot(void);
+Tchar	n_sethl(int k);
+Tchar	n_makem(int i);
+void	n_casefp(void);
+void	n_casebd(void);
+void	n_casevs(void);
+Tchar	n_xlss(void);
+
+/*
+ * n10.c
+ */
+void	n_ptinit(void);
+char*	skipstr(char *s);
+char*	getstr(char *s, char *t);
+char*	getint(char *s, int *pn);
+void	twdone(void);
+void	n_specnames(void);
+int	findch(char *s);
+void	n_ptout(Tchar i);
+void	ptout1(void);
+char*	plot(char *x);
+void	move(void);
+void	n_ptlead(void);
+void	n_ptpause(void);
+
+/*
+ * indirect calls on TROFF/!TROFF.  these are variables!
+ */
+extern Tchar	(*hmot)(void);
+extern Tchar	(*makem)(int i);
+extern Tchar	(*setabs)(void);
+extern Tchar	(*setch)(int c);
+extern Tchar	(*sethl)(int k);
+extern Tchar	(*setht)(void);
+extern Tchar	(*setslant)(void);
+extern Tchar	(*vmot)(void);
+extern Tchar	(*xlss)(void);
+extern int	(*findft)(int i);
+extern int	(*width)(Tchar j);
+extern void	(*mchbits)(void);
+extern void	(*ptlead)(void);
+extern void	(*ptout)(Tchar i);
+extern void	(*ptpause)(void);
+extern void	(*setfont)(int a);
+extern void	(*setps)(void);
+extern void	(*setwd)(void);
blob - /dev/null
blob + 623637fc7f420a8a2868ec7d9e56d19254a6a5bf (mode 644)
--- /dev/null
+++ src/cmd/troff/hytab.c
@@ -0,0 +1,126 @@
+/*
+ * Hyphenation digram tables
+ */
+
+typedef unsigned char Uchar;
+
+
+Uchar	bxh[26][13] = {
+	0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0040,0000,0040
+};
+
+Uchar	hxx[26][13] = {
+	0006,0042,0041,0123,0021,0024,0063,0042,0002,0043,0021,0001,0022,
+	0140,0000,0200,0003,0260,0006,0000,0160,0007,0000,0140,0000,0320,
+	0220,0000,0160,0005,0240,0010,0000,0100,0006,0000,0200,0000,0320,
+	0240,0000,0120,0003,0140,0000,0000,0240,0010,0000,0220,0000,0160,
+	0042,0023,0041,0040,0040,0022,0043,0041,0030,0064,0021,0000,0041,
+	0100,0000,0140,0000,0220,0006,0000,0140,0003,0000,0200,0000,0000,
+	0200,0000,0120,0002,0220,0010,0000,0160,0006,0000,0140,0000,0320,
+	0020,0000,0020,0000,0020,0000,0000,0020,0000,0000,0020,0000,0000,
+	0043,0163,0065,0044,0022,0043,0104,0042,0061,0146,0061,0000,0007,
+	0100,0000,0140,0000,0040,0000,0000,0100,0000,0000,0120,0000,0000,
+	0140,0000,0040,0011,0060,0004,0001,0120,0003,0000,0140,0000,0040,
+	0200,0000,0100,0000,0140,0000,0000,0140,0000,0000,0140,0000,0240,
+	0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0140,0000,0240,
+	0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0060,0000,0240,
+	0021,0043,0041,0121,0040,0023,0042,0003,0142,0042,0061,0001,0022,
+	0120,0000,0140,0010,0140,0010,0000,0140,0002,0000,0120,0000,0120,
+	0000,0000,0000,0000,0360,0000,0000,0000,0000,0000,0160,0000,0000,
+	0100,0000,0040,0005,0120,0000,0000,0100,0000,0000,0060,0000,0140,
+	0140,0040,0100,0001,0240,0041,0000,0242,0000,0002,0140,0000,0100,
+	0240,0000,0120,0002,0200,0000,0000,0320,0007,0000,0240,0000,0340,
+	0101,0021,0041,0020,0040,0005,0042,0121,0002,0021,0201,0000,0020,
+	0160,0000,0100,0000,0140,0000,0000,0160,0006,0000,0220,0000,0140,
+	0140,0000,0020,0001,0020,0000,0000,0100,0001,0000,0300,0000,0000,
+	0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
+	0106,0041,0040,0147,0040,0000,0063,0041,0001,0102,0160,0002,0002,
+	0300,0000,0040,0017,0140,0017,0000,0240,0000,0000,0140,0000,0120,
+};
+
+Uchar	bxxh[26][13] = {
+	0005,0150,0153,0062,0062,0246,0152,0127,0146,0203,0310,0017,0206,
+	0100,0000,0120,0000,0140,0000,0000,0100,0000,0000,0120,0000,0060,
+	0100,0000,0040,0000,0060,0000,0000,0060,0000,0000,0220,0000,0040,
+	0100,0000,0120,0000,0200,0000,0000,0100,0000,0000,0140,0000,0060,
+	0043,0142,0046,0140,0062,0147,0210,0131,0046,0106,0246,0017,0111,
+	0060,0000,0020,0000,0060,0000,0000,0040,0000,0000,0100,0000,0000,
+	0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0100,0000,0040,
+	0100,0000,0100,0000,0100,0000,0000,0040,0000,0000,0100,0000,0140,
+	0066,0045,0145,0140,0000,0070,0377,0030,0130,0103,0003,0017,0006,
+	0040,0000,0040,0000,0020,0000,0000,0040,0000,0000,0100,0000,0000,
+	0200,0000,0020,0000,0140,0000,0000,0120,0000,0000,0120,0000,0040,
+	0120,0000,0040,0000,0060,0000,0000,0060,0000,0000,0160,0000,0040,
+	0120,0000,0040,0000,0120,0000,0000,0040,0000,0000,0160,0000,0040,
+	0120,0000,0020,0000,0140,0000,0000,0120,0000,0000,0140,0000,0040,
+	0051,0126,0150,0140,0060,0210,0146,0006,0006,0165,0003,0017,0244,
+	0120,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0000,0140,
+	0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
+	0140,0000,0140,0000,0060,0000,0000,0100,0000,0000,0140,0000,0020,
+	0120,0000,0020,0000,0060,0000,0000,0060,0000,0000,0060,0000,0040,
+	0140,0000,0020,0000,0100,0000,0000,0140,0000,0000,0140,0000,0020,
+	0070,0125,0051,0162,0120,0105,0126,0104,0006,0044,0000,0017,0052,
+	0140,0000,0020,0000,0140,0000,0000,0060,0000,0000,0060,0000,0040,
+	0020,0000,0000,0000,0020,0000,0000,0000,0000,0000,0000,0000,0060,
+	0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0000,0240,
+	0065,0042,0060,0200,0000,0210,0222,0146,0006,0204,0220,0012,0003,
+	0240,0000,0020,0000,0120,0000,0000,0200,0000,0000,0200,0000,0240,
+};
+
+Uchar	xhx[26][13] = {
+	0032,0146,0042,0107,0076,0102,0042,0146,0202,0050,0006,0000,0051,
+	0036,0377,0057,0013,0057,0366,0377,0057,0001,0377,0057,0000,0040,
+	0037,0377,0020,0000,0100,0022,0377,0057,0362,0116,0100,0000,0017,
+	0057,0377,0057,0031,0137,0363,0377,0037,0362,0270,0077,0000,0117,
+	0074,0142,0012,0236,0076,0125,0063,0165,0341,0046,0047,0000,0024,
+	0020,0017,0075,0377,0040,0001,0377,0017,0001,0204,0020,0000,0040,
+	0057,0017,0057,0340,0140,0362,0314,0117,0003,0302,0100,0000,0057,
+	0057,0357,0077,0017,0100,0366,0314,0057,0342,0346,0037,0000,0060,
+	0252,0145,0072,0157,0377,0165,0063,0066,0164,0050,0363,0000,0362,
+	0000,0000,0020,0000,0020,0000,0000,0017,0000,0000,0020,0000,0000,
+	0117,0017,0237,0377,0200,0354,0125,0110,0004,0257,0000,0000,0300,
+	0057,0367,0054,0357,0157,0216,0314,0114,0217,0353,0053,0000,0057,
+	0077,0213,0077,0077,0177,0317,0377,0114,0377,0352,0077,0000,0076,
+	0077,0213,0077,0077,0157,0177,0377,0054,0377,0352,0117,0000,0075,
+	0125,0230,0065,0216,0057,0066,0063,0047,0345,0126,0011,0000,0033,
+	0057,0377,0051,0360,0120,0361,0273,0056,0001,0256,0057,0000,0060,
+	0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
+	0076,0310,0056,0310,0137,0174,0273,0055,0335,0266,0033,0000,0155,
+	0077,0157,0057,0360,0057,0063,0042,0024,0077,0206,0020,0000,0040,
+	0057,0037,0077,0360,0100,0365,0377,0037,0362,0176,0050,0000,0026,
+	0167,0146,0042,0112,0077,0110,0062,0254,0366,0052,0377,0000,0163,
+	0060,0000,0040,0000,0120,0000,0377,0060,0012,0000,0037,0000,0257,
+	0037,0232,0157,0361,0040,0003,0125,0010,0001,0256,0000,0000,0340,
+	0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0017,0277,
+	0253,0315,0257,0216,0377,0206,0146,0306,0371,0126,0232,0000,0004,
+	0057,0012,0100,0360,0160,0360,0000,0040,0000,0017,0157,0000,0176,
+};
+
+Uchar	xxh[26][13] = {
+	0045,0150,0154,0162,0042,0246,0210,0147,0152,0103,0230,0017,0206,
+	0100,0000,0040,0000,0140,0000,0000,0100,0000,0021,0120,0017,0060,
+	0100,0000,0040,0002,0140,0320,0000,0060,0000,0001,0220,0017,0040,
+	0100,0001,0120,0001,0241,0000,0000,0100,0000,0020,0140,0017,0060,
+	0023,0162,0046,0142,0022,0207,0210,0131,0052,0106,0250,0017,0110,
+	0060,0000,0042,0000,0160,0000,0000,0040,0000,0212,0100,0017,0000,
+	0140,0000,0040,0002,0140,0000,0000,0120,0000,0040,0120,0017,0040,
+	0100,0000,0100,0000,0140,0001,0021,0140,0000,0046,0100,0017,0140,
+	0066,0045,0025,0201,0020,0130,0146,0030,0130,0103,0025,0017,0006,
+	0100,0000,0040,0000,0020,0000,0000,0040,0000,0000,0200,0017,0000,
+	0200,0000,0020,0001,0140,0000,0000,0140,0000,0000,0120,0017,0040,
+	0120,0026,0042,0020,0140,0161,0042,0143,0000,0022,0162,0017,0040,
+	0121,0042,0060,0020,0140,0200,0000,0123,0000,0021,0220,0017,0041,
+	0121,0042,0060,0120,0140,0200,0000,0123,0000,0021,0160,0017,0041,
+	0051,0126,0150,0141,0060,0210,0146,0066,0026,0165,0026,0017,0247,
+	0120,0000,0040,0003,0160,0000,0000,0140,0000,0021,0100,0017,0140,
+	0000,0000,0000,0000,0200,0000,0000,0000,0000,0000,0000,0017,0000,
+	0141,0023,0122,0040,0160,0143,0042,0142,0000,0047,0143,0017,0020,
+	0120,0000,0040,0006,0140,0060,0000,0141,0000,0026,0100,0017,0040,
+	0140,0000,0020,0007,0100,0000,0000,0140,0000,0001,0140,0017,0020,
+	0110,0125,0051,0162,0120,0125,0127,0104,0006,0104,0000,0017,0052,
+	0140,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0017,0000,
+	0040,0005,0020,0000,0040,0313,0231,0030,0000,0140,0000,0017,0056,
+	0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0017,0240,
+	0065,0042,0060,0040,0000,0206,0231,0146,0006,0224,0220,0017,0004,
+	0240,0000,0020,0000,0140,0000,0000,0220,0000,0000,0200,0017,0141,
+};
blob - /dev/null
blob + 66a98219366827439082bccd8d01a5f2904a6d8d (mode 644)
--- /dev/null
+++ src/cmd/troff/mbwc.c
@@ -0,0 +1,165 @@
+#include <stdlib.h>
+
+/*
+ * Use the FSS-UTF transformation proposed by posix.
+ *	We define 7 byte types:
+ *	T0	0xxxxxxx	7 free bits
+ *	Tx	10xxxxxx	6 free bits
+ *	T1	110xxxxx	5 free bits
+ *	T2	1110xxxx	4 free bits
+ *
+ *	Encoding is as follows.
+ *	From hex	Thru hex	Sequence		Bits
+ *	00000000	0000007F	T0			7
+ *	00000080	000007FF	T1 Tx			11
+ *	00000800	0000FFFF	T2 Tx Tx		16
+ */
+
+int
+mblen(const char *s, size_t n)
+{
+
+	return mbtowc(0, s, n);
+}
+
+int
+mbtowc(wchar_t *pwc, const char *s, size_t n)
+{
+	int c, c1, c2;
+	long l;
+
+	if(!s)
+		return 0;
+
+	if(n < 1)
+		goto bad;
+	c = s[0] & 0xff;
+	if((c & 0x80) == 0x00) {
+		if(pwc)
+			*pwc = c;
+		if(c == 0)
+			return 0;
+		return 1;
+	}
+
+	if(n < 2)
+		goto bad;
+	c1 = (s[1] ^ 0x80) & 0xff;
+	if((c1 & 0xC0) != 0x00)
+		goto bad;
+	if((c & 0xE0) == 0xC0) {
+		l = ((c << 6) | c1) & 0x7FF;
+		if(l < 0x080)
+			goto bad;
+		if(pwc)
+			*pwc = l;
+		return 2;
+	}
+
+	if(n < 3)
+		goto bad;
+	c2 = (s[2] ^ 0x80) & 0xff;
+	if((c2 & 0xC0) != 0x00)
+		goto bad;
+	if((c & 0xF0) == 0xE0) {
+		l = ((((c << 6) | c1) << 6) | c2) & 0xFFFF;
+		if(l < 0x0800)
+			goto bad;
+		if(pwc)
+			*pwc = l;
+		return 3;
+	}
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	return -1;
+
+}
+
+int
+wctomb(char *s, wchar_t wchar)
+{
+	long c;
+
+	if(!s)
+		return 0;
+
+	c = wchar & 0xFFFF;
+	if(c < 0x80) {
+		s[0] = c;
+		return 1;
+	}
+
+	if(c < 0x800) {
+		s[0] = 0xC0 | (c >> 6);
+		s[1] = 0x80 | (c & 0x3F);
+		return 2;
+	}
+
+	s[0] = 0xE0 |  (c >> 12);
+	s[1] = 0x80 | ((c >> 6) & 0x3F);
+	s[2] = 0x80 |  (c & 0x3F);
+	return 3;
+}
+
+size_t
+mbstowcs(wchar_t *pwcs, const char *s, size_t n)
+{
+	int i, d, c;
+
+	for(i=0; i < n; i++) {
+		c = *s & 0xff;
+		if(c < 0x80) {
+			*pwcs = c;
+			if(c == 0)
+				break;
+			s++;
+		} else {
+			d = mbtowc(pwcs, s, 3);
+			if(d <= 0)
+				return (size_t)((d<0) ? -1 : i);
+			s += d;
+		}
+		pwcs++;
+	}
+	return i;
+}
+
+size_t
+wcstombs(char *s, const wchar_t *pwcs, size_t n)
+{
+	int i, d;
+	long c;
+	char *p, *pe;
+	char buf[3];
+
+	p = s;
+	pe = p+n-3;
+	while(p < pe) {
+		c = *pwcs++;
+		if(c < 0x80)
+			*p++ = c;
+		else
+			p += wctomb(p, c);
+		if(c == 0)
+			return p-s;
+	}
+	while(p < pe+3) {
+		c = *pwcs++;
+		d = wctomb(buf, c);
+		if(p+d <= pe+3) {
+			*p++ = buf[0];
+			if(d > 1) {
+				*p++ = buf[2];
+				if(d > 2)
+					*p++ = buf[3];
+			}
+		}
+		if(c == 0)
+			break;
+	}
+	return p-s;
+}
+
blob - /dev/null
blob + 26b610d6dca329fb9343f912a8dcd39f10e15b47 (mode 644)
--- /dev/null
+++ src/cmd/troff/mk.log
@@ -0,0 +1,136 @@
+9c -c -DUNICODE -DFONTDIR="sys/lib/troff/font" -DNTERMDIR="sys/lib/troff/term/tab." -DTEXHYPHENS="#9/sys/lib/texmf/tex/generic/hyphen/hyphen.tex" -DALTHYPHENS="sys/lib/texmf/tex/generic/hyphen/hyphen.tex" -DDWBHOME="#9/" n1.c
+n1.c:51: warning: return type defaults to `int'
+n1.c: In function `getch0':
+n1.c:676: warning: unused variable `j'
+n1.c:719: warning: label `g2' defined but not used
+n1.c: In function `get1ch':
+n1.c:745: warning: `n' might be used uninitialized in this function
+n1.c:745: warning: `c' might be used uninitialized in this function
+n1.c: In function `nextfile':
+n1.c:830: warning: implicit declaration of function `unsharp'
+n1.c:830: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n1.c: At top level:
+n1.c:842: warning: return type defaults to `int'
+n1.c:875: warning: return type defaults to `int'
+n1.c:915: warning: return type defaults to `int'
+n1.c: In function `getname':
+n1.c:917: warning: unused variable `i'
+n1.c: In function `caseso':
+n1.c:939: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n1.c:935: warning: unused variable `p'
+n1.c:935: warning: unused variable `q'
+n1.c:934: warning: `fp' might be used uninitialized in this function
+n1.c: In function `casecf':
+n1.c:1008: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+9c -c -DUNICODE n2.c
+n2.c: In function `outascii':
+n2.c:140: warning: unused variable `p'
+9c -c -DUNICODE n3.c
+n3.c: In function `grow':
+n3.c:67: warning: unused variable `new'
+n3.c: In function `finds':
+n3.c:310: warning: unused variable `j'
+n3.c: In function `copyb':
+n3.c:372: warning: `savoff' might be used uninitialized in this function
+9c -c -DUNICODE n4.c
+n4.c: In function `setn':
+n4.c:144: warning: int format, long unsigned int arg (arg 3)
+9c -c -DUNICODE n5.c
+n5.c:83: warning: return type defaults to `int'
+n5.c: In function `chget':
+n5.c:84: warning: `i' might be used uninitialized in this function
+n5.c: At top level:
+n5.c:147: warning: return type defaults to `int'
+n5.c:338: warning: return type defaults to `int'
+n5.c: In function `casefm':
+n5.c:411: warning: implicit declaration of function `unsharp'
+n5.c:411: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n5.c: At top level:
+n5.c:747: warning: return type defaults to `int'
+n5.c:835: warning: return type defaults to `int'
+9c -c -DUNICODE t6.c
+t6.c:18: warning: return type defaults to `int'
+t6.c:79: warning: return type defaults to `int'
+t6.c:112: warning: return type defaults to `int'
+t6.c: In function `t_setch':
+t6.c:217: warning: unused variable `j'
+t6.c: At top level:
+t6.c:288: warning: return type defaults to `int'
+t6.c:367: warning: return type defaults to `int'
+t6.c: In function `t_setps':
+t6.c:397: warning: `j' might be used uninitialized in this function
+t6.c: At top level:
+t6.c:707: warning: return type defaults to `int'
+t6.c: In function `setfp':
+t6.c:708: warning: unused variable `sl'
+t6.c: In function `casebd':
+t6.c:781: warning: `j' might be used uninitialized in this function
+9c -c -DUNICODE n6.c
+n6.c:11: warning: return type defaults to `int'
+n6.c: In function `n_casebd':
+n6.c:295: warning: `j' might be used uninitialized in this function
+9c -c -DUNICODE n7.c
+n7.c: In function `newline':
+n7.c:354: warning: `nlss' might be used uninitialized in this function
+n7.c: At top level:
+n7.c:450: warning: return type defaults to `int'
+n7.c:482: warning: return type defaults to `int'
+n7.c:509: warning: return type defaults to `int'
+n7.c:544: warning: return type defaults to `int'
+n7.c:653: warning: return type defaults to `int'
+n7.c: In function `getword':
+n7.c:654: warning: `j' might be used uninitialized in this function
+9c -c -DUNICODE -DTEXHYPHENS="#9/sys/lib/texmf/tex/generic/hyphen/hyphen.tex" n8.c
+n8.c:76: warning: return type defaults to `int'
+n8.c:87: warning: return type defaults to `int'
+n8.c:222: warning: return type defaults to `int'
+n8.c:274: warning: return type defaults to `int'
+n8.c:282: warning: return type defaults to `int'
+n8.c: In function `digram':
+n8.c:310: warning: `maxw' might be used uninitialized in this function
+n8.c: At top level:
+n8.c:346: warning: return type defaults to `int'
+n8.c: In function `readpats':
+n8.c:469: warning: implicit declaration of function `unsharp'
+n8.c:469: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n8.c:470: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+9c -c -DUNICODE n9.c
+n9.c:80: warning: return type defaults to `int'
+n9.c: In function `setfield':
+n9.c:340: warning: `rchar' might be used uninitialized in this function
+9c -c -DUNICODE -DTDEVNAME="utf" t10.c
+t10.c: In function `ptout0':
+t10.c:179: warning: int format, long int arg (arg 3)
+t10.c:183: warning: int format, long unsigned int arg (arg 3)
+t10.c:303: warning: int format, long int arg (arg 3)
+t10.c:157: warning: `w' might be used uninitialized in this function
+9c -c -DUNICODE -DTDEVNAME="utf" n10.c
+n10.c: In function `getnrfont':
+n10.c:77: warning: unused variable `fin'
+n10.c:81: warning: unused variable `cmd'
+n10.c:80: warning: `code' might be used uninitialized in this function
+n10.c: In function `n_ptinit':
+n10.c:189: warning: implicit declaration of function `unsharp'
+n10.c:189: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+n10.c:142: warning: unused variable `cp'
+9c -c -DUNICODE t11.c
+t11.c:21: warning: return type defaults to `int'
+t11.c: In function `getdesc':
+t11.c:26: warning: implicit declaration of function `unsharp'
+t11.c:26: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+t11.c: In function `checkfont':
+t11.c:67: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+t11.c: At top level:
+t11.c:89: warning: return type defaults to `int'
+t11.c: In function `getfont':
+t11.c:100: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
+t11.c:94: warning: `nw' might be used uninitialized in this function
+t11.c:94: warning: `code' might be used uninitialized in this function
+t11.c: At top level:
+t11.c:193: warning: return type defaults to `int'
+t11.c:235: warning: return type defaults to `int'
+9c -c -DUNICODE -DTMACDIR="sys/lib/tmac/tmac." ni.c
+9c -c -DUNICODE hytab.c
+9c -c -DUNICODE suftab.c
+9c -c -DUNICODE -DDWBHOME="#9/" dwbinit.c
+9l -o o.troff n1.o n2.o n3.o n4.o n5.o t6.o n6.o n7.o n8.o n9.o t10.o n10.o t11.o ni.o hytab.o suftab.o dwbinit.o /usr/local/plan9/lib/libbio.a /usr/local/plan9/lib/lib9.a 
blob - /dev/null
blob + c02084e7f897fd8b499ba33e0f20fa443086f592 (mode 644)
--- /dev/null
+++ src/cmd/troff/mkfile
@@ -0,0 +1,58 @@
+<$PLAN9/src/mkhdr
+
+TARG=troff
+OFILES=n1.$O\
+	n2.$O\
+	n3.$O\
+	n4.$O\
+	n5.$O\
+	t6.$O\
+	n6.$O\
+	n7.$O\
+	n8.$O\
+	n9.$O\
+	t10.$O\
+	n10.$O\
+	t11.$O\
+	ni.$O\
+	hytab.$O\
+	suftab.$O\
+	dwbinit.$O\
+	mbwc.$O
+
+HFILES=tdef.h\
+	fns.h\
+	ext.h\
+	dwbinit.h\
+
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
+CFLAGS=-c -DUNICODE
+
+TMACDIR='"tmac/tmac."'
+FONTDIR='"troff/font"'
+NTERMDIR='"troff/term/tab."'
+ALTHYPHENS='"lib/hyphen.tex"'
+TEXHYPHENS='"#9/lib/hyphen.tex"'
+DWBHOME='"#9/"'
+TDEVNAME='"utf"'
+NDEVNAME='"utf"'
+
+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=$ALTHYPHENS -DDWBHOME=$DWBHOME n1.c
+
+n10.$O:	n10.c $HFILES
+	$CC $CFLAGS -DTDEVNAME=$NDEVNAME n10.c
+
+n8.$O:	n8.c $HFILES
+	$CC $CFLAGS -DTEXHYPHENS=$TEXHYPHENS n8.c
+
+dwbinit.$O:	dwbinit.c
+	$CC $CFLAGS -DDWBHOME=$DWBHOME dwbinit.c
blob - /dev/null
blob + d0949fe290040b9f947ff871334911a4be5599de (mode 644)
--- /dev/null
+++ src/cmd/troff/n1.c
@@ -0,0 +1,1136 @@
+/*
+ * n1.c
+ *
+ *	consume options, initialization, main loop,
+ *	input routines, escape function calling
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+#include "dwbinit.h"
+
+#undef MB_CUR_MAX
+#define MB_CUR_MAX 3
+
+#include <setjmp.h>
+#include <time.h>
+
+char	*Version	= "March 11, 1994";
+
+#ifndef DWBVERSION
+#define DWBVERSION      "???"
+#endif
+
+char	*DWBfontdir = FONTDIR;
+char	*DWBntermdir = NTERMDIR;
+char	*DWBalthyphens = ALTHYPHENS;
+char	*DWBhomedir = "";
+
+dwbinit dwbpaths[] = {
+	&DWBfontdir, NULL, 0,
+	&DWBntermdir, NULL, 0,
+	&DWBalthyphens, NULL, 0,
+	&DWBhomedir, NULL, 0,
+	NULL, nextf, NS,
+	NULL, NULL, 0
+};
+
+int	TROFF	= 1;	/* assume we started in troff... */
+
+jmp_buf sjbuf;
+Offset	ipl[NSO];
+
+static	FILE	*ifile;
+static	FILE	*ifl[NSO];	/* open input file pointers */
+char	cfname[NSO+1][NS] = {  "stdin" };	/* file name stack */
+int	cfline[NSO];		/* input line count stack */
+char	*progname;		/* program name (troff or nroff) */
+
+int	trace = 0;	/* tracing mode: default off */
+int	trace1 = 0;
+
+main(int argc, char *argv[])
+{
+	char *p;
+	int j;
+	Tchar i;
+	char buf[100];
+
+	ifile = stdin;
+	ptid = stdout;
+
+	buf[0] = '\0';		/* make sure it's empty (silly 3b2) */
+	progname = argv[0];
+	if ((p = strrchr(progname, '/')) == NULL)
+		p = progname;
+	else
+		p++;
+	DWBinit(progname, dwbpaths);
+	if (strcmp(p, "nroff") == 0)
+		TROFF = 0;
+#ifdef UNICODE
+	alphabet = 128;	/* unicode for plan 9 */
+#endif	/*UNICODE*/
+	mnspace();
+	nnspace();
+	mrehash();
+	nrehash();
+	numtabp[NL].val = -1;
+
+	while (--argc > 0 && (++argv)[0][0] == '-')
+		switch (argv[0][1]) {
+
+		case 'N':	/* ought to be used first... */
+			TROFF = 0;
+			break;
+		case 'd':
+			fprintf(stderr, "troff/nroff version %s\n", Version);
+			break;
+		case 'F':	/* switch font tables from default */
+			if (argv[0][2] != '\0') {
+				strcpy(termtab, &argv[0][2]);
+				strcpy(fontdir, &argv[0][2]);
+			} else {
+				argv++; argc--;
+				strcpy(termtab, argv[0]);
+				strcpy(fontdir, argv[0]);
+			}
+			break;
+		case 0:
+			goto start;
+		case 'i':
+			stdi++;
+			break;
+		case 'n':
+			npn = atoi(&argv[0][2]);
+			break;
+		case 'u':	/* set emboldening amount */
+			bdtab[3] = atoi(&argv[0][2]);
+			if (bdtab[3] < 0 || bdtab[3] > 50)
+				bdtab[3] = 0;
+			break;
+		case 's':
+			if (!(stop = atoi(&argv[0][2])))
+				stop++;
+			break;
+		case 'r':
+			sprintf(buf + strlen(buf), ".nr %c %s\n",
+				argv[0][2], &argv[0][3]);
+			/* not yet cpushback(buf);*/
+			/* dotnr(&argv[0][2], &argv[0][3]); */
+			break;
+		case 'm':
+			if (mflg++ >= NMF) {
+				ERROR "Too many macro packages: %s", argv[0] WARN;
+				break;
+			}
+			strcpy(mfiles[nmfi], nextf);
+			strcat(mfiles[nmfi++], &argv[0][2]);
+			break;
+		case 'o':
+			getpn(&argv[0][2]);
+			break;
+		case 'T':
+			strcpy(devname, &argv[0][2]);
+			dotT++;
+			break;
+		case 'a':
+			ascii = 1;
+			break;
+		case 'h':
+			hflg++;
+			break;
+		case 'e':
+			eqflg++;
+			break;
+		case 'q':
+			quiet++;
+			save_tty();
+			break;
+		case 'V':
+			fprintf(stdout, "%croff: DWB %s\n", 
+					TROFF ? 't' : 'n', DWBVERSION);
+			exit(0);
+		case 't':
+			if (argv[0][2] != '\0')
+				trace = trace1 = argv[0][2];
+			break;		/* for the sake of compatibility */
+		default:
+			ERROR "unknown option %s", argv[0] WARN;
+			done(02);
+		}
+
+start:
+	/*
+	 * cpushback maintains a LIFO, so push pack the -r arguments
+	 * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
+	 */
+	if (buf[0]) {
+		char *p = buf;
+		while(*p++)
+			;
+		while(p > buf) {
+			while(strncmp(p, ".nr", 3) != 0)
+				p--;
+			cpushback(p);
+			*p-- = '\0';
+		}
+	}
+	argp = argv;
+	rargc = argc;
+	nmfi = 0;
+	init2();
+	setjmp(sjbuf);
+loop:
+	copyf = lgf = nb = nflush = nlflg = 0;
+	if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
+		nflush++;
+		trap = 0;
+		eject((Stack *)0);
+		goto loop;
+	}
+	i = getch();
+	if (pendt)
+		goto Lt;
+	if ((j = cbits(i)) == XPAR) {
+		copyf++;
+		tflg++;
+		while (cbits(i) != '\n')
+			pchar(i = getch());
+		tflg = 0;
+		copyf--;
+		goto loop;
+	}
+	if (j == cc || j == c2) {
+		if (j == c2)
+			nb++;
+		copyf++;
+		while ((j = cbits(i = getch())) == ' ' || j == '\t')
+			;
+		ch = i;
+		copyf--;
+		control(getrq(), 1);
+		flushi();
+		goto loop;
+	}
+Lt:
+	ch = i;
+	text();
+	if (nlflg)
+		numtabp[HP].val = 0;
+	goto loop;
+}
+
+
+
+void init2(void)
+{
+	int i;
+	char buf[100];
+
+	for (i = NTRTAB; --i; )
+		trtab[i] = i;
+	trtab[UNPAD] = ' ';
+	iflg = 0;
+	obufp = obuf;
+	if (TROFF)
+		t_ptinit();
+	else
+		n_ptinit();
+	mchbits();
+	cvtime();
+	numtabp[PID].val = getpid();
+	numtabp[HP].val = init = 0;
+	numtabp[NL].val = -1;
+	nfo = 0;
+	copyf = raw = 0;
+	sprintf(buf, ".ds .T %s\n", devname);
+	cpushback(buf);
+	sprintf(buf, ".ds .P %s\n", DWBhomedir);
+	cpushback(buf);
+	numtabp[CD].val = -1;	/* compensation */
+	nx = mflg;
+	frame = stk = (Stack *)setbrk(STACKSIZE);
+	dip = &d[0];
+	nxf = frame + 1;
+	for (i = 1; i < NEV; i++)	/* propagate the environment */
+		envcopy(&env[i], &env[0]);
+	for (i = 0; i < NEV; i++) {
+		if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
+			ERROR "not enough room for word buffers" WARN;
+			done2(1);
+		}
+		env[i]._word._size = WDSIZE;
+		if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
+			ERROR "not enough room for line buffers" WARN;
+			done2(1);
+		}
+		env[i]._line._size = LNSIZE;
+	}
+	if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
+		ERROR "not enough room for line buffers" WARN;
+		done2(1);
+	}
+	olinep = oline;
+	olnsize = OLNSIZE;
+	blockinit();
+}
+
+void cvtime(void)
+{
+	long tt;
+	struct tm *ltime;
+
+	time(&tt);
+	ltime = localtime(&tt);
+	numtabp[YR].val = ltime->tm_year % 100;
+	numtabp[YR].fmt = 2;
+	numtabp[MO].val = ltime->tm_mon + 1;	/* troff uses 1..12 */
+	numtabp[DY].val = ltime->tm_mday;
+	numtabp[DW].val = ltime->tm_wday + 1;	/* troff uses 1..7 */
+}
+
+
+
+char	errbuf[200];
+
+void errprint(void)	/* error message printer */
+{
+	int savecd = numtabp[CD].val;
+
+	if (!nlflg)
+		numtabp[CD].val++;
+
+	fprintf(stderr, "%s: ", progname);
+	fputs(errbuf, stderr);
+	if (cfname[ifi][0])
+		fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
+	fputs("\n", stderr);
+	if (cfname[ifi][0])
+		stackdump();
+	numtabp[CD].val = savecd;
+}
+
+
+int control(int a, int b)
+{
+	int j, k;
+	extern Contab *contabp;
+
+	numerr.type = RQERR;
+	numerr.req = a;
+	if (a == 0 || (j = findmn(a)) == -1)
+		return(0);
+	if (contabp[j].f == 0) {
+		if (trace & TRMAC)
+			fprintf(stderr, "invoke macro %s\n", unpair(a));
+		if (dip != d)
+			for (k = dilev; k; k--)
+				if (d[k].curd == a) {
+					ERROR "diversion %s invokes itself during diversion",
+								unpair(a) WARN;
+					edone(0100);
+				}
+		nxf->nargs = 0;
+		if (b)
+			collect();
+		flushi();
+		return pushi(contabp[j].mx, a);	/* BUG??? all that matters is 0/!0 */
+	}
+	if (b) {
+		if (trace & TRREQ)
+			fprintf(stderr, "invoke request %s\n", unpair(a));
+		 (*contabp[j].f)();
+	}
+	return(0);
+}
+
+void casept(void)
+{
+	int i;
+
+	noscale++;
+	if (skip())
+		i = trace1;
+	else {
+		i = max(inumb(&trace), 0);
+		if (nonumb)
+			i = trace1;
+	}
+	trace1 = trace;
+	trace = i;
+	noscale = 0;
+}
+
+
+int getrq(void)
+{
+	int i, j;
+
+	if ((i = getach()) == 0 || (j = getach()) == 0)
+		goto rtn;
+	i = PAIR(i, j);
+rtn:
+	return(i);
+}
+
+/*
+ * table encodes some special characters, to speed up tests
+ * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
+ */
+
+char gchtab[NCHARS] = {
+	000,004,000,000,010,000,000,000, /* fc, ldr */
+	001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
+	000,000,000,000,000,000,000,000,
+	000,001,000,001,000,000,000,000, /* FLSS, ESC */
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,001,000, /* f */
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+	000,000,000,000,000,000,000,000,
+};
+
+int realcbits(Tchar c)	/* return character bits, or MOTCH if motion */
+{
+	if (ismot(c))
+		return MOTCH;
+	else
+		return c & 0xFFFF;
+}
+
+Tchar getch(void)
+{
+	int k;
+	Tchar i, j;
+
+g0:
+	if (ch) {
+		i = ch;
+		if (cbits(i) == '\n')
+			nlflg++;
+		ch = 0;
+		return(i);
+	}
+
+	if (nlflg)
+		return('\n');
+	i = getch0();
+	if (ismot(i))
+		return(i);
+	k = cbits(i);
+	if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0)	/* nothing special */
+		return(i);
+	if (k != ESC) {
+		if (k == '\n') {
+			nlflg++;
+			if (ip == 0)
+				numtabp[CD].val++; /* line number */
+			return(k);
+		}
+		if (k == FLSS) {
+			copyf++; 
+			raw++;
+			i = getch0();
+			if (!fi)
+				flss = i;
+			copyf--; 
+			raw--;
+			goto g0;
+		}
+		if (k == RPT) {
+			setrpt();
+			goto g0;
+		}
+		if (!copyf) {
+			if (k == 'f' && lg && !lgf) {
+				i = getlg(i);
+				return(i);
+			}
+			if (k == fc || k == tabch || k == ldrch) {
+				if ((i = setfield(k)) == 0)
+					goto g0; 
+				else 
+					return(i);
+			}
+			if (k == '\b') {
+				i = makem(-width(' ' | chbits));
+				return(i);
+			}
+		}
+		return(i);
+	}
+
+	k = cbits(j = getch0());
+	if (ismot(j))
+		return(j);
+
+	switch (k) {
+	case 'n':	/* number register */
+		setn();
+		goto g0;
+	case '$':	/* argument indicator */
+		seta();
+		goto g0;
+	case '*':	/* string indicator */
+		setstr();
+		goto g0;
+	case '{':	/* LEFT */
+		i = LEFT;
+		goto gx;
+	case '}':	/* RIGHT */
+		i = RIGHT;
+		goto gx;
+	case '"':	/* comment */
+		while (cbits(i = getch0()) != '\n')
+			;
+		if (ip == 0)
+			numtabp[CD].val++; /* line number */
+		nlflg++;
+		return(i);
+
+/* experiment: put it here instead of copy mode */
+	case '(':	/* special char name \(xx */
+	case 'C':	/* 		\C'...' */
+		if ((i = setch(k)) == 0)
+			goto g0;
+		goto gx;
+
+	case ESC:	/* double backslash */
+		i = eschar;
+		goto gx;
+	case 'e':	/* printable version of current eschar */
+		i = PRESC;
+		goto gx;
+	case '\n':	/* concealed newline */
+		numtabp[CD].val++;
+		goto g0;
+	case ' ':	/* unpaddable space */
+		i = UNPAD;
+		goto gx;
+	case '\'':	/* \(aa */
+		i = ACUTE;
+		goto gx;
+	case '`':	/* \(ga */
+		i = GRAVE;
+		goto gx;
+	case '_':	/* \(ul */
+		i = UNDERLINE;
+		goto gx;
+	case '-':	/* current font minus */
+		i = MINUS;
+		goto gx;
+	case '&':	/* filler */
+		i = FILLER;
+		goto gx;
+	case 'c':	/* to be continued */
+		i = CONT;
+		goto gx;
+	case '!':	/* transparent indicator */
+		i = XPAR;
+		goto gx;
+	case 't':	/* tab */
+		i = '\t';
+		return(i);
+	case 'a':	/* leader (SOH) */
+/* old:		*pbp++ = LEADER; goto g0; */
+		i = LEADER;
+		return i;
+	case '%':	/* ohc */
+		i = OHC;
+		return(i);
+	case 'g':	/* return format of a number register */
+		setaf();	/* should this really be in copy mode??? */
+		goto g0;
+	case '.':	/* . */
+		i = '.';
+gx:
+		setsfbits(i, sfbits(j));
+		return(i);
+	}
+	if (copyf) {
+		*pbp++ = j;
+		return(eschar);
+	}
+	switch (k) {
+
+	case 'f':	/* font indicator */
+		setfont(0);
+		goto g0;
+	case 's':	/* size indicator */
+		setps();
+		goto g0;
+	case 'v':	/* vert mot */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		if (i = vmot()) {
+			return(i);
+		}
+		goto g0;
+	case 'h': 	/* horiz mot */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		if (i = hmot())
+			return(i);
+		goto g0;
+	case '|':	/* narrow space */
+		if (NROFF)
+			goto g0;
+		return(makem((int)(EM)/6));
+	case '^':	/* half narrow space */
+		if (NROFF)
+			goto g0;
+		return(makem((int)(EM)/12));
+	case 'w':	/* width function */
+		setwd();
+		goto g0;
+	case 'p':	/* spread */
+		spread++;
+		goto g0;
+	case 'N':	/* absolute character number */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		if ((i = setabs()) == 0)
+			goto g0;
+		return i;
+	case 'H':	/* character height */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		return(setht());
+	case 'S':	/* slant */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		return(setslant());
+	case 'z':	/* zero with char */
+		return(setz());
+	case 'l':	/* hor line */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		setline();
+		goto g0;
+	case 'L':	/* vert line */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		setvline();
+		goto g0;
+	case 'D':	/* drawing function */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		setdraw();
+		goto g0;
+	case 'X':	/* \X'...' for copy through */
+		setxon();
+		goto g0;
+	case 'b':	/* bracket */
+		setbra();
+		goto g0;
+	case 'o':	/* overstrike */
+		setov();
+		goto g0;
+	case 'k':	/* mark hor place */
+		if ((k = findr(getsn())) != -1) {
+			numtabp[k].val = numtabp[HP].val;
+		}
+		goto g0;
+	case '0':	/* number space */
+		return(makem(width('0' | chbits)));
+	case 'x':	/* extra line space */
+		numerr.type = numerr.escarg = 0; numerr.esc = k;
+		if (i = xlss())
+			return(i);
+		goto g0;
+	case 'u':	/* half em up */
+	case 'r':	/* full em up */
+	case 'd':	/* half em down */
+		return(sethl(k));
+	default:
+		return(j);
+	}
+	/* NOTREACHED */
+}
+
+void setxon(void)	/* \X'...' for copy through */
+{
+	Tchar xbuf[NC];
+	Tchar *i;
+	Tchar c;
+	int delim, k;
+
+	if (ismot(c = getch()))
+		return;
+	delim = cbits(c);
+	i = xbuf;
+	*i++ = XON | chbits;
+	while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
+		if (k == ' ')
+			setcbits(c, WORDSP);
+		*i++ = c | ZBIT;
+	}
+	*i++ = XOFF | chbits;
+	*i = 0;
+	pushback(xbuf);
+}
+
+
+char	ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
+
+Tchar getch0(void)
+{
+	int j;
+	Tchar i;
+
+again:
+	if (pbp > lastpbp)
+		i = *--pbp;
+	else if (ip) {
+		/* i = rbf(); */
+		i = rbf0(ip);
+		if (i == 0)
+			i = rbf();
+		else {
+			++ip;
+			if (pastend(ip)) {
+				--ip;
+				rbf();
+			}
+		}
+	} else {
+		if (donef || ndone)
+			done(0);
+		if (nx || 1) {	/* BUG: was ibufp >= eibuf, so EOF test is wrong */
+			if (nfo < 0)
+				ERROR "in getch0, nfo = %d", nfo WARN;
+			if (nfo == 0) {
+g0:
+				if (nextfile()) {
+					if (ip)
+						goto again;
+				}
+			}
+			nx = 0;
+#ifdef UNICODE
+			if (MB_CUR_MAX > 1)
+				i = get1ch(ifile);
+			else
+#endif	/*UNICODE*/
+				i = getc(ifile);
+			if (i == EOF)
+				goto g0;
+			if (ip)
+				goto again;
+		}
+g2:
+		if (i >= 040)			/* zapped: && i < 0177 */
+			goto g4;
+		i = ifilt[i];
+	}
+	if (cbits(i) == IMP && !raw)
+		goto again;
+	if (i == 0 && !init && !raw) {		/* zapped:  || i == 0177 */
+		goto again;
+	}
+g4:
+	if (ismot(i))
+		return i;
+	if (copyf == 0 && sfbits(i) == 0)
+		i |= chbits;
+	if (cbits(i) == eschar && !raw)
+		setcbits(i, ESC);
+	return(i);
+}
+
+
+#ifdef UNICODE
+Tchar get1ch(FILE *fp)	/* get one "character" from input, figure out what alphabet */
+{
+	wchar_t wc;
+	char buf[100], *p;
+	int i, n, c;
+
+	for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
+		if ((c = getc(fp)) == EOF)
+			return c;
+		*p++ = c;
+		if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
+			break;
+	}
+	if (n == 1)	/* real ascii, presumably */
+		return wc;
+	if (n == 0)
+		return p[-1];	/* illegal, but what else to do? */
+	if (c == EOF)
+		return EOF;
+	*p = 0;
+	return chadd(buf, MBchar, Install);	/* add name even if haven't seen it */
+}
+#endif	/*UNICODE*/
+
+void pushback(Tchar *b)
+{
+	Tchar *ob = b;
+
+	while (*b++)
+		;
+	b--;
+	while (b > ob && pbp < &pbbuf[NC-3])
+		*pbp++ = *--b;
+	if (pbp >= &pbbuf[NC-3]) {
+		ERROR "pushback overflow" WARN;
+		done(2);
+	}
+}
+
+void cpushback(char *b)
+{
+	char *ob = b;
+
+	while (*b++)
+		;
+	b--;
+	while (b > ob && pbp < &pbbuf[NC-3])
+		*pbp++ = *--b;
+	if (pbp >= &pbbuf[NC-3]) {
+		ERROR "cpushback overflow" WARN;
+		done(2);
+	}
+}
+
+int nextfile(void)
+{
+	char *p;
+
+n0:
+	if (ifile != stdin)
+		fclose(ifile);
+	if (ifi > 0 && !nx) {
+		if (popf())
+			goto n0; /* popf error */
+		return(1);	 /* popf ok */
+	}
+	if (nx || nmfi < mflg) {
+		p = mfiles[nmfi++];
+		if (*p != 0)
+			goto n1;
+	}
+	if (rargc-- <= 0) {
+		if ((nfo -= mflg) && !stdi) {
+			done(0);
+}
+		nfo++;
+		numtabp[CD].val = stdi = mflg = 0;
+		ifile = stdin;
+		strcpy(cfname[ifi], "stdin");
+		return(0);
+	}
+	p = (argp++)[0];
+	if (rargc >= 0)
+		cfname[ifi][0] = 0;
+n1:
+	numtabp[CD].val = 0;
+	if (p[0] == '-' && p[1] == 0) {
+		ifile = stdin;
+		strcpy(cfname[ifi], "stdin");
+	} else if ((ifile = fopen(unsharp(p), "r")) == NULL) {
+		ERROR "cannot open file %s", p WARN;
+		nfo -= mflg;
+		done(02);
+	} else
+		strcpy(cfname[ifi],p);
+	nfo++;
+	return(0);
+}
+
+
+popf(void)
+{
+	--ifi;
+	if (ifi < 0) {
+		ERROR "popf went negative" WARN;
+		return 1;
+	}
+	numtabp[CD].val = cfline[ifi];	/* restore line counter */
+	ip = ipl[ifi];			/* input pointer */
+	ifile = ifl[ifi];		/* input FILE * */
+	return(0);
+}
+
+
+void flushi(void)
+{
+	if (nflush)
+		return;
+	ch = 0;
+	copyf++;
+	while (!nlflg) {
+		if (donef && frame == stk)
+			break;
+		getch();
+	}
+	copyf--;
+}
+
+/*
+ * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
+ * (internal names), spaces and special cookies (below 040).
+ * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
+ */
+getach(void)
+{
+	Tchar i;
+	int j;
+
+	lgf++;
+	j = cbits(i = getch());
+        if (ismot(i)
+	    || j > SHORTMASK
+	    || (j <= 040 && j != 002	/*STX*/
+			&& j != 003	/*ETX*/
+			&& j != 005	/*ENQ*/
+			&& j != 006	/*ACK*/
+			&& j != 007)) {	/*BELL*/
+		ch = i;
+		j = 0;
+	}
+	lgf--;
+	return j;
+}
+
+
+void casenx(void)
+{
+	lgf++;
+	skip();
+	getname();
+	nx++;
+	if (nmfi > 0)
+		nmfi--;
+	strcpy(mfiles[nmfi], nextf);
+	nextfile();
+	nlflg++;
+	ip = 0;
+	pendt = 0;
+	frame = stk;
+	nxf = frame + 1;
+}
+
+
+getname(void)
+{
+	int j, k;
+	Tchar i;
+
+	lgf++;
+	for (k = 0; k < NS - 1; k++) {
+		j = getach();
+		if (!j)
+			break;
+		nextf[k] = j;
+	}
+	nextf[k] = 0;
+	lgf--;
+	return(nextf[0]);
+}
+
+
+void caseso(void)
+{
+	FILE *fp;
+	char *p, *q;
+
+	lgf++;
+	nextf[0] = 0;
+	if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) {
+		ERROR "can't open file %s", nextf WARN;
+		done(02);
+	}
+	strcpy(cfname[ifi+1], nextf);
+	cfline[ifi] = numtabp[CD].val;		/*hold line counter*/
+	numtabp[CD].val = 0;
+	flushi();
+	ifl[ifi] = ifile;
+	ifile = fp;
+	ipl[ifi] = ip;
+	ip = 0;
+	nx++;
+	nflush++;
+	ifi++;
+}
+
+void caself(void)	/* set line number and file */
+{
+	int n;
+
+	if (skip())
+		return;
+	n = atoi0();
+	if (!nonumb)
+		cfline[ifi] = numtabp[CD].val = n - 1;
+	if (!skip())
+		if (getname()) {	/* eats '\n' ? */
+			strcpy(cfname[ifi], nextf);
+			if (!nonumb)
+				numtabp[CD].val--;
+		}
+}
+
+void cpout(FILE *fin, char *token)
+{
+	int n;
+	char buf[1024];
+
+	if (token) {	/* BUG: There should be no NULL bytes in input */
+		char *newl = buf;
+		while ((fgets(buf, sizeof buf, fin)) != NULL) {
+			if (newl) {
+				numtabp[CD].val++; /* line number */
+				if (strcmp(token, buf) == 0)
+					return;
+			}
+			newl = strchr(buf, '\n');
+			fputs(buf, ptid);
+		}
+	} else {
+		while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
+			fwrite(buf, n, 1, ptid);
+		fclose(fin);
+	}
+}
+
+void casecf(void)
+{	/* copy file without change */
+	FILE *fd;
+	char *eof, *p;
+	extern int hpos, esc, po;
+
+	/* this may not make much sense in nroff... */
+
+	lgf++;
+	nextf[0] = 0;
+	if (!skip() && getname()) {
+		if (strncmp("<<", nextf, 2) != 0) {
+			if ((fd = fopen(unsharp(nextf), "r")) == NULL) {
+				ERROR "can't open file %s", nextf WARN;
+				done(02);
+			}
+			eof = (char *) NULL;
+		} else {	/* current file */
+			if (pbp > lastpbp || ip) {
+				ERROR "casecf: not reading from file" WARN;
+				done(02);
+			}
+			eof = &nextf[2];
+			if (!*eof)  {
+				ERROR "casecf: missing end of input token" WARN;
+				done(02);
+			}
+			p = eof;
+			while(*++p)
+				;
+			*p++ = '\n';
+			*p = 0;
+			fd = ifile;
+		}
+	} else {
+		ERROR "casecf: no argument" WARN;
+		lgf--;
+		return;
+	}
+	lgf--;
+
+	/* make it into a clean state, be sure that everything is out */
+	tbreak();
+	hpos = po;
+	esc = 0;
+	ptesc();	/* to left margin */
+	esc = un;
+	ptesc();
+	ptlead();
+	ptps();
+	ptfont();
+	flusho();
+	cpout(fd, eof);
+	ptps();
+	ptfont();
+}
+
+void getline(char *s, int n)	/* get rest of input line into s */
+{
+	int i;
+
+	lgf++;
+	copyf++;
+	skip();
+	for (i = 0; i < n-1; i++)
+		if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
+			break;
+	s[i] = 0;
+	copyf--;
+	lgf--;
+}
+
+void casesy(void)	/* call system */
+{
+	char sybuf[NTM];
+
+	getline(sybuf, NTM);
+	system(sybuf);
+}
+
+
+void getpn(char *a)
+{
+	int n, neg;
+
+	if (*a == 0)
+		return;
+	neg = 0;
+	for ( ; *a; a++)
+		switch (*a) {
+		case '+':
+		case ',':
+			continue;
+		case '-':
+			neg = 1;
+			continue;
+		default:
+			n = 0;
+			if (isdigit(*a)) {
+				do
+					n = 10 * n + *a++ - '0';
+				while (isdigit(*a));
+				a--;
+			} else
+				n = 9999;
+			*pnp++ = neg ? -n : n;
+			neg = 0;
+			if (pnp >= &pnlist[NPN-2]) {
+				ERROR "too many page numbers" WARN;
+				done3(-3);
+			}
+		}
+	if (neg)
+		*pnp++ = -9999;
+	*pnp = -INT_MAX;
+	print = 0;
+	pnp = pnlist;
+	if (*pnp != -INT_MAX)
+		chkpn();
+}
+
+
+void setrpt(void)
+{
+	Tchar i, j;
+
+	copyf++;
+	raw++;
+	i = getch0();
+	copyf--;
+	raw--;
+	if ((long) i < 0 || cbits(j = getch0()) == RPT)
+		return;
+	while (i > 0 && pbp < &pbbuf[NC-3]) {
+		i--;
+		*pbp++ = j;
+	}
+}
blob - /dev/null
blob + 0183cadc41cc2d88f9e34bb4787ae2bb5814faa3 (mode 644)
--- /dev/null
+++ src/cmd/troff/n10.c
@@ -0,0 +1,549 @@
+/*
+n10.c
+
+Device interfaces
+*/
+
+#include "tdef.h"
+#include "ext.h"
+#include "fns.h"
+#include <ctype.h>
+
+Term	t;	/* terminal characteristics */
+
+int	dtab;
+int	plotmode;
+int	esct;
+
+enum	{ Notype = 0, Type = 1 };
+
+static char *parse(char *s, int typeit)	/* convert \0, etc to nroff driving table format */
+{		/* typeit => add a type id to the front for later use */
+	static char buf[100], *t, *obuf;
+	int quote = 0;
+	wchar_t wc;
+
+	obuf = typeit == Type ? buf : buf+1;
+#ifdef UNICODE
+	if (mbtowc(&wc, s, strlen(s)) > 1) {	/* it's multibyte, */
+		buf[0] = MBchar;
+		strcpy(buf+1, s);
+		return obuf;
+	}			/* so just hand it back */
+#endif	/*UNICODE*/
+	buf[0] = Troffchar;
+	t = buf + 1;
+	if (*s == '"') {
+		s++;
+		quote = 1;
+	}
+	for (;;) {
+		if (quote && *s == '"') {
+			s++;
+			break;
+		}
+		if (!quote && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\0'))
+			break;
+		if (*s != '\\')
+			*t++ = *s++;
+		else {
+			s++;	/* skip \\ */
+			if (isdigit(s[0]) && isdigit(s[1]) && isdigit(s[2])) {
+				*t++ = (s[0]-'0')<<6 | (s[1]-'0')<<3 | s[2]-'0';
+				s += 2;
+			} else if (isdigit(s[0])) {
+				*t++ = *s - '0';
+			} else if (*s == 'b') {
+				*t++ = '\b';
+			} else if (*s == 'n') {
+				*t++ = '\n';
+			} else if (*s == 'r') {
+				*t++ = '\r';
+			} else if (*s == 't') {
+				*t++ = '\t';
+			} else {
+				*t++ = *s;
+			}
+			s++;
+		}
+	}
+	*t = '\0';
+	return obuf;
+}
+
+
+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];
+	wchar_t wc;
+
+
+	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 */
+		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 */
+
+		/* 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];
+		} 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);
+			n = nw;
+			nw++;
+#endif	/*UNICODE*/
+		} else {
+			if (strcmp(ch, "---") == 0) { /* no name */
+				sprintf(ch, "%d", code);
+				type = Number;
+			} else
+				type = Troffchar;
+/* BUG in here somewhere when same character occurs twice in table */
+			chtemp[nw].num = chadd(ch, type, Install);
+			n = nw;
+			nw++;
+		}
+		chtemp[n].wid = wid;
+		chtemp[n].str = strdupl(parse(s2, Type));
+	}
+	t.tfont.nchars = nw;
+	t.tfont.wp = (Chwid *) malloc(nw * sizeof(Chwid));
+	if (t.tfont.wp == NULL)
+		return -1;
+	for (i = 0; i < nw; i++)
+		t.tfont.wp[i] = chtemp[i];
+	return 1;
+}
+
+
+void n_ptinit(void)
+{
+	int i;
+	char *p, *cp;
+	char opt[50], cmd[100];
+	FILE *fp;
+
+	hmot = n_hmot;
+	makem = n_makem;
+	setabs = n_setabs;
+	setch = n_setch;
+	sethl = n_sethl;
+	setht = n_setht;
+	setslant = n_setslant;
+	vmot = n_vmot;
+	xlss = n_xlss;
+	findft = n_findft;
+	width = n_width;
+	mchbits = n_mchbits;
+	ptlead = n_ptlead;
+	ptout = n_ptout;
+	ptpause = n_ptpause;
+	setfont = n_setfont;
+	setps = n_setps;
+	setwd = n_setwd;
+
+	if ((p = getenv("NROFFTERM")) != 0)
+		strcpy(devname, p);
+	if (termtab[0] == 0)
+		strcpy(termtab,DWBntermdir);
+	if (fontdir[0] == 0)
+		strcpy(fontdir, "");
+	if (devname[0] == 0)
+		strcpy(devname, NDEVNAME);
+	pl = 11*INCH;
+	po = PO;
+	hyf = 0;
+	ascii = 1;
+	lg = 0;
+	fontlab[1] = 'R';
+	fontlab[2] = 'I';
+	fontlab[3] = 'B';
+	fontlab[4] = PAIR('B','I');
+	fontlab[5] = 'D';
+	bdtab[3] = 3;
+	bdtab[4] = 3;
+
+	/* hyphalg = 0;	/* for testing */
+
+	strcat(termtab, devname);
+	if ((fp = fopen(unsharp(termtab), "r")) == NULL) {
+		ERROR "cannot open %s", termtab WARN;
+		exit(-1);
+	}
+
+
+/* this loop isn't robust about input format errors. */
+/* it assumes  name, name-value pairs..., charset */
+/* god help us if we get out of sync. */
+
+	fscanf(fp, "%s", cmd);	/* should be device name... */
+	if (!is(devname) && trace)
+		ERROR "wrong terminal name: saw %s, wanted %s", cmd, devname WARN;
+	for (;;) {
+		fscanf(fp, "%s", cmd);
+		if (is("charset"))
+			break;
+		fscanf(fp, " %[^\n]", opt);
+		if (is("bset")) t.bset = atoi(opt);
+		else if (is("breset")) t.breset = atoi(opt);
+		else if (is("Hor")) t.Hor = atoi(opt);
+		else if (is("Vert")) t.Vert = atoi(opt);
+		else if (is("Newline")) t.Newline = atoi(opt);
+		else if (is("Char")) t.Char = atoi(opt);
+		else if (is("Em")) t.Em = atoi(opt);
+		else if (is("Halfline")) t.Halfline = atoi(opt);
+		else if (is("Adj")) t.Adj = atoi(opt);
+		else if (is("twinit")) t.twinit = strdupl(parse(opt, Notype));
+		else if (is("twrest")) t.twrest = strdupl(parse(opt, Notype));
+		else if (is("twnl")) t.twnl = strdupl(parse(opt, Notype));
+		else if (is("hlr")) t.hlr = strdupl(parse(opt, Notype));
+		else if (is("hlf")) t.hlf = strdupl(parse(opt, Notype));
+		else if (is("flr")) t.flr = strdupl(parse(opt, Notype));
+		else if (is("bdon")) t.bdon = strdupl(parse(opt, Notype));
+		else if (is("bdoff")) t.bdoff = strdupl(parse(opt, Notype));
+		else if (is("iton")) t.iton = strdupl(parse(opt, Notype));
+		else if (is("itoff")) t.itoff = strdupl(parse(opt, Notype));
+		else if (is("ploton")) t.ploton = strdupl(parse(opt, Notype));
+		else if (is("plotoff")) t.plotoff = strdupl(parse(opt, Notype));
+		else if (is("up")) t.up = strdupl(parse(opt, Notype));
+		else if (is("down")) t.down = strdupl(parse(opt, Notype));
+		else if (is("right")) t.right = strdupl(parse(opt, Notype));
+		else if (is("left")) t.left = strdupl(parse(opt, Notype));
+		else
+			ERROR "bad tab.%s file, %s %s", devname, cmd, opt WARN;
+	}
+
+	getnrfont(fp);
+	fclose(fp);
+
+	sps = EM;
+	ics = EM * 2;
+	dtab = 8 * t.Em;
+	for (i = 0; i < 16; i++)
+		tabtab[i] = dtab * (i + 1);
+	pl = 11 * INCH;
+	po = PO;
+	spacesz = SS;
+	lss = lss1 = VS;
+	ll = ll1 = lt = lt1 = LL;
+	smnt = nfonts = 5;	/* R I B BI S */
+	n_specnames();	/* install names like "hyphen", etc. */
+	if (eqflg)
+		t.Adj = t.Hor;
+}
+
+
+void n_specnames(void)
+{
+
+	int	i;
+
+	for (i = 0; spnames[i].n; i++)
+		*spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
+	if (c_isalnum == 0)
+		c_isalnum = NROFFCHARS;
+}
+
+void twdone(void)
+{
+	if (!TROFF && t.twrest) {
+		obufp = obuf;
+		oputs(t.twrest);
+		flusho();
+		if (pipeflg) {
+			pclose(ptid);
+		}
+		restore_tty();
+	}
+}
+
+
+void n_ptout(Tchar i)
+{
+	*olinep++ = i;
+	if (olinep >= &oline[LNSIZE])
+		olinep--;
+	if (cbits(i) != '\n')
+		return;
+	olinep--;
+	lead += dip->blss + lss - t.Newline;
+	dip->blss = 0;
+	esct = esc = 0;
+	if (olinep > oline) {
+		move();
+		ptout1();
+		oputs(t.twnl);
+	} else {
+		lead += t.Newline;
+		move();
+	}
+	lead += dip->alss;
+	dip->alss = 0;
+	olinep = oline;
+}
+
+
+void ptout1(void)
+{
+	int k;
+	char *codep;
+	int w, j, phyw;
+	Tchar *q, i;
+	static int oxfont = FT;	/* start off in roman */
+
+	for (q = oline; q < olinep; q++) {
+		i = *q;
+		if (ismot(i)) {
+			j = absmot(i);
+			if (isnmot(i))
+				j = -j;
+			if (isvmot(i))
+				lead += j;
+			else 
+				esc += j;
+			continue;
+		}
+		if ((k = cbits(i)) <= ' ') {
+			switch (k) {
+			case ' ': /*space*/
+				esc += t.Char;
+				break;
+			case '\033':
+			case '\007':
+			case '\016':
+			case '\017':
+				oput(k);
+				break;
+			}
+			continue;
+		}
+		phyw = w = t.Char * t.tfont.wp[k].wid;
+		if (iszbit(i))
+			w = 0;
+		if (esc || lead)
+			move();
+		esct += w;
+		xfont = fbits(i);
+		if (xfont != oxfont) {
+			switch (oxfont) {
+			case ULFONT:	oputs(t.itoff); break;
+			case BDFONT:	oputs(t.bdoff); break;
+			case BIFONT:	oputs(t.itoff); oputs(t.bdoff); break;
+			}
+			switch (xfont) {
+			case ULFONT:
+				if (*t.iton & 0377) oputs(t.iton); break;
+			case BDFONT:
+				if (*t.bdon & 0377) oputs(t.bdon); break;
+			case BIFONT:
+				if (*t.bdon & 0377) oputs(t.bdon);
+				if (*t.iton & 0377) oputs(t.iton);
+				break;
+			}
+			oxfont = xfont;
+		}
+		if ((xfont == ulfont || xfont == BIFONT) && !(*t.iton & 0377)) {
+			for (j = w / t.Char; j > 0; j--)
+				oput('_');
+			for (j = w / t.Char; j > 0; j--)
+				oput('\b');
+		}
+		if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) || xfont == BDFONT || xfont == BIFONT))
+			j++;
+		else
+			j = 1;	/* number of overstrikes for bold */
+		if (k < ALPHABET) {	/* ordinary ascii */
+			oput(k);
+			while (--j > 0) {
+				oput('\b');
+				oput(k);
+			}
+		} 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... */
+		} 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 */
+/* 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 */
+			while (*codep != 0) {
+				if (*codep & 0200) {
+					codep = plot(codep);
+					oput(' ');
+				} else {
+					if (*codep == '%')	/* escape */
+						codep++;
+					oput(*codep);
+					if (*codep == '\033')
+						oput(*++codep);
+					else if (*codep != '\b')
+						for (j = oj; --j > 0; ) {
+							oput('\b');
+							oput(*codep);
+						}
+					codep++;
+				}
+			}
+		}
+		if (!w)
+			for (j = phyw / t.Char; j > 0; j--)
+				oput('\b');
+	}
+}
+
+
+char *plot(char *x)
+{
+	int	i;
+	char	*j, *k;
+
+	oputs(t.ploton);
+	k = x;
+	if ((*k & 0377) == 0200)
+		k++;
+	for (; *k; k++) {
+		if (*k == '%') {	/* quote char within plot mode */
+			oput(*++k);
+		} else if (*k & 0200) {
+			if (*k & 0100) {
+				if (*k & 040)
+					j = t.up; 
+				else 
+					j = t.down;
+			} else {
+				if (*k & 040)
+					j = t.left; 
+				else 
+					j = t.right;
+			}
+			if ((i = *k & 037) == 0) {	/* 2nd 0200 turns it off */
+				++k;
+				break;
+			}
+			while (i--)
+				oputs(j);
+		} else 
+			oput(*k);
+	}
+	oputs(t.plotoff);
+	return(k);
+}
+
+
+void move(void)
+{
+	int k;
+	char *i, *j;
+	char *p, *q;
+	int iesct, dt;
+
+	iesct = esct;
+	if (esct += esc)
+		i = "\0"; 
+	else 
+		i = "\n\0";
+	j = t.hlf;
+	p = t.right;
+	q = t.down;
+	if (lead) {
+		if (lead < 0) {
+			lead = -lead;
+			i = t.flr;
+			/*	if(!esct)i = t.flr; else i = "\0";*/
+			j = t.hlr;
+			q = t.up;
+		}
+		if (*i & 0377) {
+			k = lead / t.Newline;
+			lead = lead % t.Newline;
+			while (k--)
+				oputs(i);
+		}
+		if (*j & 0377) {
+			k = lead / t.Halfline;
+			lead = lead % t.Halfline;
+			while (k--)
+				oputs(j);
+		} else { /* no half-line forward, not at line begining */
+			k = lead / t.Newline;
+			lead = lead % t.Newline;
+			if (k > 0) 
+				esc = esct;
+			i = "\n";
+			while (k--) 
+				oputs(i);
+		}
+	}
+	if (esc) {
+		if (esc < 0) {
+			esc = -esc;
+			j = "\b";
+			p = t.left;
+		} else {
+			j = " ";
+			if (hflg)
+				while ((dt = dtab - (iesct % dtab)) <= esc) {
+					if (dt % t.Em)
+						break;
+					oput(TAB);
+					esc -= dt;
+					iesct += dt;
+				}
+		}
+		k = esc / t.Em;
+		esc = esc % t.Em;
+		while (k--)
+			oputs(j);
+	}
+	if ((*t.ploton & 0377) && (esc || lead)) {
+		oputs(t.ploton);
+		esc /= t.Hor;
+		lead /= t.Vert;
+		while (esc--)
+			oputs(p);
+		while (lead--)
+			oputs(q);
+		oputs(t.plotoff);
+	}
+	esc = lead = 0;
+}
+
+
+void n_ptlead(void)
+{
+	move();
+}
+
+
+void n_ptpause(void )
+{
+	char	junk;
+
+	flusho();
+	read(2, &junk, 1);
+}
blob - /dev/null
blob + 8164c0387ca2cc8077c19111e02fb52fffe1a51f (mode 644)
--- /dev/null
+++ src/cmd/troff/n2.c
@@ -0,0 +1,325 @@
+/*
+ * n2.c
+ *
+ * output, cleanup
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+#include <setjmp.h>
+
+#ifdef STRICT
+	/* not in ANSI or POSIX */
+FILE*	popen(char*, char*);
+#endif
+
+
+extern	jmp_buf	sjbuf;
+int	toolate;
+int	error;
+
+char	obuf[2*BUFSIZ];
+char	*obufp = obuf;
+
+	/* pipe command structure; allows redicously long commends for .pi */
+struct Pipe {
+	char	*buf;
+	int	tick;
+	int	cnt;
+} Pipe;
+
+
+int	xon	= 0;	/* records if in middle of \X */
+
+int pchar(Tchar i)
+{
+	int j;
+	static int hx = 0;	/* records if have seen HX */
+
+	if (hx) {
+		hx = 0;
+		j = absmot(i);
+		if (isnmot(i)) {
+			if (j > dip->blss)
+				dip->blss = j;
+		} else {
+			if (j > dip->alss)
+				dip->alss = j;
+			ralss = dip->alss;
+		}
+		return 0;
+	}
+	if (ismot(i)) {
+		pchar1(i); 
+		return 0;
+	}
+	switch (j = cbits(i)) {
+	case 0:
+	case IMP:
+	case RIGHT:
+	case LEFT:
+		return 0;
+	case HX:
+		hx = 1;
+		return 0;
+	case XON:
+		xon++;
+		break;
+	case XOFF:
+		xon--;
+		break;
+	case PRESC:
+		if (!xon && !tflg && dip == &d[0])
+			j = eschar;	/* fall through */
+	default:
+		setcbits(i, trtab[j]);
+	}
+	if (NROFF & xon)	/* rob fix for man2html */
+		return 0;
+	pchar1(i);
+	return 0;
+}
+
+
+void pchar1(Tchar i)
+{
+	int j;
+
+	j = cbits(i);
+	if (dip != &d[0]) {
+		wbf(i);
+		dip->op = offset;
+		return;
+	}
+	if (!tflg && !print) {
+		if (j == '\n')
+			dip->alss = dip->blss = 0;
+		return;
+	}
+	if (j == FILLER && !xon)
+		return;
+	if (tflg) {	/* transparent mode, undiverted */
+		if (print)			/* assumes that it's ok to print */
+			/* OUT "%c", j PUT;	/* i.e., is ascii */
+			outascii(i);
+		return;
+	}
+	if (TROFF && ascii)
+		outascii(i);
+	else
+		ptout(i);
+}
+
+
+void outweird(int k)	/* like ptchname() but ascii */
+{
+	char *chn = chname(k);
+
+	switch (chn[0]) {
+	case MBchar:
+		OUT "%s", chn+1 PUT;	/* \n not needed? */
+		break;
+	case Number:
+		OUT "\\N'%s'", chn+1 PUT;
+		break;
+	case Troffchar:
+		if (strlen(chn+1) == 2)
+			OUT "\\(%s", chn+1 PUT;
+		else
+			OUT "\\C'%s'", chn+1 PUT;
+		break;
+	default:
+		OUT " %s? ", chn PUT;
+		break;
+	}
+}
+
+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. */
+
+	if (ismot(i))
+		oput(' ');
+	else if (j < ALPHABET && j >= ' ' || j == '\n' || j == '\t')
+		oput(j);
+	else if (j == DRAWFCN)
+		oputs("\\D");
+	else if (j == HYPHEN)
+		oput('-');
+	else if (j == MINUS)	/* special pleading for strange encodings */
+		oputs("\\-");
+	else if (j == PRESC)
+		oputs("\\e");
+	else if (j == FILLER)
+		oputs("\\&");
+	else if (j == UNPAD)
+		oputs("\\ ");
+	else if (j == OHC)	/* this will never occur;  stripped out earlier */
+		oputs("\\%");
+	else if (j == XON)
+		oputs("\\X");
+	else if (j == XOFF)
+		oputs(" ");
+	else if (j == LIG_FI)
+		oputs("fi");
+	else if (j == LIG_FL)
+		oputs("fl");
+	else if (j == LIG_FF)
+		oputs("ff");
+	else if (j == LIG_FFI)
+		oputs("ffi");
+	else if (j == LIG_FFL)
+		oputs("ffl");
+	else if (j == WORDSP) {		/* nothing at all */
+		if (xon)		/* except in \X */
+			oput(' ');
+
+	} else
+		outweird(j);
+}
+
+int flusho(void)
+{
+	if (NROFF && !toolate && t.twinit)
+			fwrite(t.twinit, strlen(t.twinit), 1, ptid);
+
+	if (obufp > obuf) {
+		if (pipeflg && !toolate) {
+			/* fprintf(stderr, "Pipe to <%s>\n", Pipe.buf); */
+			if (!Pipe.buf[0] || (ptid = popen(Pipe.buf, "w")) == NULL)
+				ERROR "pipe %s not created.", Pipe.buf WARN;
+			if (Pipe.buf)
+				free(Pipe.buf);
+		}
+		if (!toolate)
+			toolate++;
+		*obufp = 0;
+		fputs(obuf, ptid);
+		fflush(ptid);
+		obufp = obuf;
+	}
+	return 1;
+}
+
+
+void caseex(void)
+{
+	done(0);
+}
+
+
+void done(int x) 
+{
+	int i;
+
+	error |= x;
+	app = ds = lgf = 0;
+	if (i = em) {
+		donef = -1;
+		eschar = '\\';
+		em = 0;
+		if (control(i, 0))
+			longjmp(sjbuf, 1);
+	}
+	if (!nfo)
+		done3(0);
+	mflg = 0;
+	dip = &d[0];
+	if (woff)	/* BUG!!! This isn't set anywhere */
+		wbf((Tchar)0);
+	if (pendw)
+		getword(1);
+	pendnf = 0;
+	if (donef == 1)
+		done1(0);
+	donef = 1;
+	ip = 0;
+	frame = stk;
+	nxf = frame + 1;
+	if (!ejf)
+		tbreak();
+	nflush++;
+	eject((Stack *)0);
+	longjmp(sjbuf, 1);
+}
+
+
+void done1(int x) 
+{
+	error |= x;
+	if (numtabp[NL].val) {
+		trap = 0;
+		eject((Stack *)0);
+		longjmp(sjbuf, 1);
+	}
+	if (!ascii)
+		pttrailer();
+	done2(0);
+}
+
+
+void done2(int x) 
+{
+	ptlead();
+	if (TROFF && !ascii)
+		ptstop();
+	flusho();
+	done3(x);
+}
+
+void done3(int x) 
+{
+	error |= x;
+	flusho();
+	if (NROFF)
+		twdone();
+	if (pipeflg)
+		pclose(ptid);
+	exit(error);
+}
+
+
+void edone(int x) 
+{
+	frame = stk;
+	nxf = frame + 1;
+	ip = 0;
+	done(x);
+}
+
+
+void casepi(void)
+{
+	int j;
+	char buf[NTM];
+
+	if (Pipe.buf == NULL) {
+		if ((Pipe.buf = (char *)calloc(NTM, sizeof(char))) == NULL) {
+			ERROR "No buf space for pipe cmd" WARN;
+			return;
+		}
+		Pipe.tick = 1;
+	} else
+		Pipe.buf[Pipe.cnt++] = '|';
+
+	getline(buf, NTM);
+	j = strlen(buf);
+	if (toolate) {
+		ERROR "Cannot create pipe to %s", buf WARN;
+		return;
+	}
+	Pipe.cnt += j;
+	if (j >= NTM +1) {
+		Pipe.tick++;
+		if ((Pipe.buf = (char *)realloc(Pipe.buf, Pipe.tick * NTM * sizeof(char))) == NULL) {
+			ERROR "No more buf space for pipe cmd" WARN;
+			return;
+		}
+	}
+	strcat(Pipe.buf, buf);
+	pipeflg++;
+}
blob - /dev/null
blob + 6918d06de4ea5055da78dea45fdfc2a166b7a34c (mode 644)
--- /dev/null
+++ src/cmd/troff/n3.c
@@ -0,0 +1,954 @@
+/*
+ * troff3.c
+ * 
+ * macro and string routines, storage allocation
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+Tchar	*argtop;
+int	pagech = '%';
+int	strflg;
+
+#define	MHASHSIZE	128	/* must be 2**n */
+#define	MHASH(x)	((x>>6)^x) & (MHASHSIZE-1)
+Contab	*mhash[MHASHSIZE];
+
+
+Blockp	*blist;		/* allocated blocks for macros and strings */
+int	nblist;		/* how many there are */
+int	bfree = -1;	/* first (possible) free block in the list */
+
+Contab *contabp = NULL;
+#define MDELTA 500
+int	nm = 0;
+
+int savname;		/* name of macro/string being defined */
+int savslot;		/* place in Contab of savname */
+int freeslot = -1;	/* first (possible) free slot in contab */
+
+void prcontab(Contab *p)
+{
+	int i;
+	for (i = 0; i < nm; i++)
+		if (p)
+			if (p[i].rq != 0)
+				fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq));
+			else
+				fprintf(stderr, "slot %d empty\n", i);
+		else
+			fprintf(stderr, "slot %d empty\n", i);
+}
+
+
+void blockinit(void)
+{
+	blist = (Blockp *) calloc(NBLIST, sizeof(Blockp));
+	if (blist == NULL) {
+		ERROR "not enough room for %d blocks", NBLIST WARN;
+		done2(1);
+	}
+	nblist = NBLIST;
+	blist[0].nextoff = blist[1].nextoff = -1;
+	blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+	blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+		/* -1 prevents blist[0] from being used; temporary fix */
+		/* for a design botch: offset==0 is overloaded. */
+		/* blist[1] reserved for .rd indicator -- also unused. */
+		/* but someone unwittingly looks at these, so allocate something */
+	bfree = 2;
+}
+
+
+char *grow(char *ptr, int num, int size)	/* make array bigger */
+{
+	char *p, new;
+
+	if (ptr == NULL)
+		p = (char *) calloc(num, size);
+	else
+		p = (char *) realloc(ptr, num * size);
+	return p;
+}
+
+void mnspace(void)
+{
+	nm = sizeof(contab)/sizeof(Contab) + MDELTA;
+	freeslot = sizeof(contab)/sizeof(Contab) + 1;
+	contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab));
+	if (contabp == NULL) {
+		ERROR "not enough memory for namespace of %d marcos", nm WARN;
+		exit(1);
+	}
+	contabp = (Contab *) memcpy((char *) contabp, (char *)contab,
+							sizeof(contab));
+	if (contabp == NULL) {
+		ERROR "Cannot reinitialize macro/request name list" WARN;
+		exit(1);
+	}
+
+}
+
+void caseig(void)
+{
+	int i;
+	Offset oldoff = offset;
+
+	offset = 0;
+	i = copyb();
+	offset = oldoff;
+	if (i != '.')
+		control(i, 1);
+}
+
+
+void casern(void)
+{
+	int i, j, k;
+
+	lgf++;
+	skip();
+	if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
+		return;
+	skip();
+	clrmn(findmn(j = getrq()));
+	if (j) {
+		munhash(&contabp[oldmn]);
+		contabp[oldmn].rq = j;
+		maddhash(&contabp[oldmn]);
+		if (dip != d )
+			for (k = dilev; k; k--)
+				if (d[k].curd == i)
+					d[k].curd = j;
+	}
+}
+
+void maddhash(Contab *rp)
+{
+	Contab **hp;
+
+	if (rp->rq == 0)
+		return;
+	hp = &mhash[MHASH(rp->rq)];
+	rp->link = *hp;
+	*hp = rp;
+}
+
+void munhash(Contab *mp)
+{	
+	Contab *p;
+	Contab **lp;
+
+	if (mp->rq == 0)
+		return;
+	lp = &mhash[MHASH(mp->rq)];
+	p = *lp;
+	while (p) {
+		if (p == mp) {
+			*lp = p->link;
+			p->link = 0;
+			return;
+		}
+		lp = &p->link;
+		p = p->link;
+	}
+}
+
+void mrehash(void)
+{
+	Contab *p;
+	int i;
+
+	for (i=0; i < MHASHSIZE; i++)
+		mhash[i] = 0;
+	for (p=contabp; p < &contabp[nm]; p++)
+		p->link = 0;
+	for (p=contabp; p < &contabp[nm]; p++) {
+		if (p->rq == 0)
+			continue;
+		i = MHASH(p->rq);
+		p->link = mhash[i];
+		mhash[i] = p;
+	}
+}
+
+void caserm(void)
+{
+	int j;
+	int k = 0;
+
+	lgf++;
+g0:
+	while (!skip() && (j = getrq()) != 0) {
+		if (dip != d)
+			for (k = dilev; k; k--)
+				if (d[k].curd == j) {
+					ERROR "cannot remove diversion %s during definition",
+								unpair(j) WARN;
+					goto g0;
+				}
+		clrmn(findmn(j));
+	}
+	lgf--;
+}
+
+
+void caseas(void)
+{
+	app++;
+	caseds();
+}
+
+
+void caseds(void)
+{
+	ds++;
+	casede();
+}
+
+
+void caseam(void)
+{
+	app++;
+	casede();
+}
+
+
+void casede(void)
+{
+	int i, req;
+	Offset savoff;
+
+	req = '.';
+	lgf++;
+	skip();
+	if ((i = getrq()) == 0)
+		goto de1;
+	if ((offset = finds(i)) == 0)
+		goto de1;
+	if (newmn)
+		savslot = newmn;
+	else
+		savslot = findmn(i);
+	savname = i;
+	if (ds)
+		copys();
+	else
+		req = copyb();
+	clrmn(oldmn);
+	if (newmn) {
+		if (contabp[newmn].rq)
+			munhash(&contabp[newmn]);
+		contabp[newmn].rq = i;
+		maddhash(&contabp[newmn]);
+
+	}
+	if (apptr) {
+		savoff = offset;
+		offset = apptr;
+		wbf((Tchar) IMP);
+		offset = savoff;
+	}
+	offset = dip->op;
+	if (req != '.')
+		control(req, 1);
+de1:
+	ds = app = 0;
+}
+
+
+int findmn(int i)
+{
+	Contab *p;
+
+	for (p = mhash[MHASH(i)]; p; p = p->link)
+		if (i == p->rq)
+			return(p - contabp);
+	return(-1);
+}
+
+
+void clrmn(int i)
+{
+	if (i >= 0) {
+		if (contabp[i].mx)
+			ffree(contabp[i].mx);
+		munhash(&contabp[i]);
+		contabp[i].rq = 0;
+		contabp[i].mx = 0;
+		contabp[i].emx = 0;
+		contabp[i].f = 0;
+		if (contabp[i].divsiz != NULL) {
+			free(contabp[i].divsiz);
+			contabp[i].divsiz = NULL;
+		}
+		if (freeslot > i)
+			freeslot = i;
+	}
+}
+
+void growcontab(void)
+{
+	nm += MDELTA;
+	contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab));
+	if (contabp == NULL) {
+		ERROR "Too many (%d) string/macro names", nm WARN;
+		done2(02);
+	} else {
+		memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab),
+						0, MDELTA * sizeof(Contab));
+		mrehash();
+	}
+}
+
+
+Offset finds(int mn)
+{
+	int i;
+	Tchar j = IMP;
+	Offset savip;
+
+	oldmn = findmn(mn);
+	newmn = 0;
+	apptr = 0;
+	if (app && oldmn >= 0 && contabp[oldmn].mx) {
+		savip = ip;
+		ip = contabp[oldmn].emx;
+		oldmn = -1;
+		apptr = ip;
+		if (!diflg)
+			ip = incoff(ip);
+		nextb = ip;
+		ip = savip;
+	} else {
+		for (i = freeslot; i < nm; i++) {
+			if (contabp[i].rq == 0)
+				break;
+		}
+		if (i == nm) 
+			growcontab();
+		freeslot = i + 1;
+		if ((nextb = alloc()) == -1) {
+			app = 0;
+			if (macerr++ > 1)
+				done2(02);
+			if (nextb == 0)
+				ERROR "Not enough space for string/macro names" WARN;
+			edone(04);
+			return(offset = 0);
+		}
+		contabp[i].mx = nextb;
+		if (!diflg) {
+			newmn = i;
+			if (oldmn == -1)
+				contabp[i].rq = -1;
+		} else {
+			contabp[i].rq = mn;
+			maddhash(&contabp[i]);
+		}
+	}
+	app = 0;
+	return(offset = nextb);
+}
+
+int skip(void)
+{
+	Tchar i;
+
+	while (cbits(i = getch()) == ' ' || ismot(i))
+		;
+	ch = i;
+	return(nlflg);
+}
+
+
+int copyb(void)
+{
+	int i, j, state;
+	Tchar ii;
+	int req, k;
+	Offset savoff;
+	Uchar *p;
+
+	if (skip() || !(j = getrq()))
+		j = '.';
+	req = j;
+	p = unpair(j);
+	/* was: k = j >> BYTE; j &= BYTEMASK; */
+	j = p[0];
+	k = p[1];
+	copyf++;
+	flushi();
+	nlflg = 0;
+	state = 1;
+
+/* state 0	eat up
+ * state 1	look for .
+ * state 2	look for first char of end macro
+ * state 3	look for second char of end macro
+ */
+
+	while (1) {
+		i = cbits(ii = getch());
+		if (state == 3) {
+			if (i == k)
+				break;
+			if (!k) {
+				ch = ii;
+				i = getach();
+				ch = ii;
+				if (!i)
+					break;
+			}
+			state = 0;
+			goto c0;
+		}
+		if (i == '\n') {
+			state = 1;
+			nlflg = 0;
+			goto c0;
+		}
+		if (state == 1 && i == '.') {
+			state++;
+			savoff = offset;
+			goto c0;
+		}
+		if (state == 2 && i == j) {
+			state++;
+			goto c0;
+		}
+		state = 0;
+c0:
+		if (offset)
+			wbf(ii);
+	}
+	if (offset) {
+		offset = savoff;
+		wbf((Tchar)0);
+	}
+	copyf--;
+	return(req);
+}
+
+
+void copys(void)
+{
+	Tchar i;
+
+	copyf++;
+	if (skip())
+		goto c0;
+	if (cbits(i = getch()) != '"')
+		wbf(i);
+	while (cbits(i = getch()) != '\n')
+		wbf(i);
+c0:
+	wbf((Tchar)0);
+	copyf--;
+}
+
+
+Offset alloc(void)	/* return free Offset in nextb */
+{
+	int i, j;
+
+	for (i = bfree; i < nblist; i++)
+		if (blist[i].nextoff == 0)
+			break;
+	if (i == nblist) {
+		blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp));
+		if (blist == NULL) {
+			ERROR "can't grow blist for string/macro defns" WARN;
+			done2(2);
+		}
+		nblist *= 2;
+		for (j = i; j < nblist; j++) {
+			blist[j].nextoff = 0;
+			blist[j].bp = 0;
+		}
+	}
+	blist[i].nextoff = -1;	/* this block is the end */
+	bfree = i + 1;
+	if (blist[i].bp == 0)
+		blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+	if (blist[i].bp == NULL) {
+		ERROR "can't allocate memory for string/macro definitions" WARN;
+		done2(2);
+	}
+	nextb = (Offset) i * BLK;
+	return nextb;
+}
+
+
+void ffree(Offset i)	/* free list of blocks starting at blist(o) */
+{			/* (doesn't actually free the blocks, just the pointers) */
+	int j;
+
+	for ( ; blist[j = bindex(i)].nextoff != -1; ) {
+		if (bfree > j)
+			bfree = j;
+		i = blist[j].nextoff;
+		blist[j].nextoff = 0;
+	}
+	blist[j].nextoff = 0;
+}
+
+
+void wbf(Tchar i)	/* store i into offset, get ready for next one */
+{
+	int j, off;
+
+	if (!offset)
+		return;
+	j = bindex(offset);
+	if (i == 0)
+		contabp[savslot].emx = offset;
+	off = boffset(offset);
+	blist[j].bp[off++] = i;
+	offset++;
+	if (pastend(offset)) {	/* off the end of this block */
+		if (blist[j].nextoff == -1) {
+			if ((nextb = alloc()) == -1) {
+				ERROR "Out of temp file space" WARN;
+				done2(01);
+			}
+			blist[j].nextoff = nextb;
+		}
+		offset = blist[j].nextoff;
+	}
+}
+
+
+Tchar rbf(void)	/* return next char from blist[] block */
+{
+	Tchar i, j;
+
+	if (ip == RD_OFFSET) {		/* for rdtty */
+		if (j = rdtty())
+			return(j);
+		else
+			return(popi());
+	}
+	
+	i = rbf0(ip);
+	if (i == 0) {
+		if (!app)
+			i = popi();
+		return(i);
+	}
+	ip = incoff(ip);
+	return(i);
+}
+
+
+Offset xxxincoff(Offset p)		/* get next blist[] block */
+{
+	p++;
+	if (pastend(p)) {		/* off the end of this block */
+		if ((p = blist[bindex(p-1)].nextoff) == -1) {	/* and nothing was allocated after it */
+			ERROR "Bad storage allocation" WARN;
+			done2(-5);
+		}
+	}
+	return(p);
+}
+
+
+Tchar popi(void)
+{
+	Stack *p;
+
+	if (frame == stk)
+		return(0);
+	if (strflg)
+		strflg--;
+	p = nxf = frame;
+	p->nargs = 0;
+	frame = p->pframe;
+	ip = p->pip;
+	pendt = p->ppendt;
+	lastpbp = p->lastpbp;
+	return(p->pch);
+}
+
+/*
+ *	test that the end of the allocation is above a certain location
+ *	in memory
+ */
+#define SPACETEST(base, size) \
+	if ((char*)base + size >= (char*)stk+STACKSIZE) \
+		ERROR "Stacksize overflow in n3" WARN
+
+Offset pushi(Offset newip, int  mname)
+{
+	Stack *p;
+
+	SPACETEST(nxf, sizeof(Stack));
+	p = nxf;
+	p->pframe = frame;
+	p->pip = ip;
+	p->ppendt = pendt;
+	p->pch = ch;
+	p->lastpbp = lastpbp;
+	p->mname = mname;
+	lastpbp = pbp;
+	pendt = ch = 0;
+	frame = nxf;
+	if (nxf->nargs == 0) 
+		nxf += 1;
+	else 
+		nxf = (Stack *)argtop;
+	return(ip = newip);
+}
+
+
+void *setbrk(int x)
+{
+	char *i;
+
+	if ((i = (char *) calloc(x, 1)) == 0) {
+		ERROR "Core limit reached" WARN;
+		edone(0100);
+	}
+	return(i);
+}
+
+
+int getsn(void)
+{
+	int i;
+
+	if ((i = getach()) == 0)
+		return(0);
+	if (i == '(')
+		return(getrq());
+	else 
+		return(i);
+}
+
+
+Offset setstr(void)
+{
+	int i, j;
+
+	lgf++;
+	if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) {
+		lgf--;
+		return(0);
+	} else {
+		SPACETEST(nxf, sizeof(Stack));
+		nxf->nargs = 0;
+		strflg++;
+		lgf--;
+		return pushi(contabp[j].mx, i);
+	}
+}
+
+
+
+void collect(void)
+{
+	int j;
+	Tchar i, *strp, *lim, **argpp, **argppend;
+	int quote;
+	Stack *savnxf;
+
+	copyf++;
+	nxf->nargs = 0;
+	savnxf = nxf;
+	if (skip())
+		goto rtn;
+
+	{
+		char *memp;
+		memp = (char *)savnxf;
+		/*
+		 *	1 s structure for the macro descriptor
+		 *	APERMAC Tchar *'s for pointers into the strings
+		 *	space for the Tchar's themselves
+		 */
+		memp += sizeof(Stack);
+		/*
+		 *	CPERMAC = the total # of characters for ALL arguments
+		 */
+#define	CPERMAC	200
+#define	APERMAC	9
+		memp += APERMAC * sizeof(Tchar *);
+		memp += CPERMAC * sizeof(Tchar);
+		nxf = (Stack *)memp;
+	}
+	lim = (Tchar *)nxf;
+	argpp = (Tchar **)(savnxf + 1);
+	argppend = &argpp[APERMAC];
+	SPACETEST(argppend, sizeof(Tchar *));
+	strp = (Tchar *)argppend;
+	/*
+	 *	Zero out all the string pointers before filling them in.
+	 */
+	for (j = 0; j < APERMAC; j++)
+		argpp[j] = 0;
+	/* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x",
+	 * 	savnxf, nxf, argpp, strp, lim WARN;
+	 */
+	strflg = 0;
+	while (argpp != argppend && !skip()) {
+		*argpp++ = strp;
+		quote = 0;
+		if (cbits(i = getch()) == '"')
+			quote++;
+		else 
+			ch = i;
+		while (1) {
+			i = getch();
+/* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */
+			if (nlflg || (!quote && argpp != argppend && cbits(i) == ' '))
+				break;	/* collects rest into $9 */
+			if (   quote
+			    && cbits(i) == '"'
+			    && cbits(i = getch()) != '"') {
+				ch = i;
+				break;
+			}
+			*strp++ = i;
+			if (strflg && strp >= lim) {
+				/* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */
+				ERROR "Macro argument too long" WARN;
+				copyf--;
+				edone(004);
+			}
+			SPACETEST(strp, 3 * sizeof(Tchar));
+		}
+		*strp++ = 0;
+	}
+	nxf = savnxf;
+	nxf->nargs = argpp - (Tchar **)(savnxf + 1);
+	argtop = strp;
+rtn:
+	copyf--;
+}
+
+
+void seta(void)
+{
+	int i;
+
+	i = cbits(getch()) - '0';
+	if (i > 0 && i <= APERMAC && i <= frame->nargs)
+		pushback(*(((Tchar **)(frame + 1)) + i - 1));
+}
+
+
+void caseda(void)
+{
+	app++;
+	casedi();
+}
+
+void casegd(void)
+{
+	int i, j;
+
+	skip();
+	if ((i = getrq()) == 0)
+		return;
+	if ((j = findmn(i)) >= 0) {
+		if (contabp[j].divsiz != NULL) {
+			numtabp[DN].val = contabp[j].divsiz->dix;
+			numtabp[DL].val = contabp[j].divsiz->diy;
+		}
+	}
+}
+
+#define FINDDIV(o) if ((o =  findmn(dip->curd)) < 0) \
+			ERROR "lost diversion %s", unpair(dip->curd) WARN
+
+void casedi(void)
+{
+	int i, j, *k;
+
+	lgf++;
+	if (skip() || (i = getrq()) == 0) {
+		if (dip != d) {
+			FINDDIV(savslot);
+			wbf((Tchar)0);
+		}
+		if (dilev > 0) {
+			numtabp[DN].val = dip->dnl;
+			numtabp[DL].val = dip->maxl;
+			FINDDIV(j);
+			if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) {
+				ERROR "Cannot alloc diversion size" WARN;
+				done2(1);
+			} else {
+				contabp[j].divsiz->dix = numtabp[DN].val;
+				contabp[j].divsiz->diy = numtabp[DL].val;
+			}
+			dip = &d[--dilev];
+			offset = dip->op;
+		}
+		goto rtn;
+	}
+	if (++dilev == NDI) {
+		--dilev;
+		ERROR "Diversions nested too deep" WARN;
+		edone(02);
+	}
+	if (dip != d) {
+		FINDDIV(j);
+		savslot = j;
+		wbf((Tchar)0);
+	}
+	diflg++;
+	dip = &d[dilev];
+	dip->op = finds(i);
+	dip->curd = i;
+	clrmn(oldmn);
+	k = (int *) & dip->dnl;
+	for (j = 0; j < 10; j++)
+		k[j] = 0;	/*not op and curd*/
+rtn:
+	app = 0;
+	diflg = 0;
+}
+
+
+void casedt(void)
+{
+	lgf++;
+	dip->dimac = dip->ditrap = dip->ditf = 0;
+	skip();
+	dip->ditrap = vnumb((int *)0);
+	if (nonumb)
+		return;
+	skip();
+	dip->dimac = getrq();
+}
+
+#define LNSIZE 4000
+void casetl(void)
+{
+	int j;
+	int w[3];
+	Tchar buf[LNSIZE];
+	Tchar *tp;
+	Tchar i, delim;
+
+ 	/*
+ 	 * bug fix
+ 	 *
+ 	 * if .tl is the first thing in the file, the p1
+ 	 * doesn't come out, also the pagenumber will be 0
+ 	 *
+ 	 * tends too confuse the device filter (and the user as well)
+ 	 */
+ 	if (dip == d && numtabp[NL].val == -1)
+ 		newline(1);
+	dip->nls = 0;
+	skip();
+	if (ismot(delim = getch())) {
+		ch = delim;
+		delim = '\'';
+	} else 
+		delim = cbits(delim);
+	tp = buf;
+	numtabp[HP].val = 0;
+	w[0] = w[1] = w[2] = 0;
+	j = 0;
+	while (cbits(i = getch()) != '\n') {
+		if (cbits(i) == cbits(delim)) {
+			if (j < 3)
+				w[j] = numtabp[HP].val;
+			numtabp[HP].val = 0;
+			if (w[j] != 0)
+				*tp++ = WORDSP;
+			j++;
+			*tp++ = 0;
+		} else {
+			if (cbits(i) == pagech) {
+				setn1(numtabp[PN].val, numtabp[findr('%')].fmt,
+				      i&SFMASK);
+				continue;
+			}
+			numtabp[HP].val += width(i);
+			if (tp < &buf[LNSIZE-10]) {
+				if (cbits(i) == ' ' && *tp != WORDSP)
+					*tp++ = WORDSP;
+				*tp++ = i;
+			} else {
+				ERROR "Overflow in casetl" WARN;
+			}
+		}
+	}
+	if (j<3)
+		w[j] = numtabp[HP].val;
+	*tp++ = 0;
+	*tp++ = 0;
+	*tp = 0;
+	tp = buf;
+	if (NROFF)
+		horiz(po);
+	while (i = *tp++)
+		pchar(i);
+	if (w[1] || w[2])
+		horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
+	while (i = *tp++)
+		pchar(i);
+	if (w[2]) {
+		horiz(lt - w[0] - w[1] - w[2] - j);
+		while (i = *tp++)
+			pchar(i);
+	}
+	newline(0);
+	if (dip != d) {
+		if (dip->dnl > dip->hnl)
+			dip->hnl = dip->dnl;
+	} else {
+		if (numtabp[NL].val > dip->hnl)
+			dip->hnl = numtabp[NL].val;
+	}
+}
+
+
+void casepc(void)
+{
+	pagech = chget(IMP);
+}
+
+
+void casepm(void)
+{
+	int i, k;
+	int xx, cnt, tcnt, kk, tot;
+	Offset j;
+
+	kk = cnt = tcnt = 0;
+	tot = !skip();
+	stackdump();
+	for (i = 0; i < nm; i++) {
+		if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0)
+			continue;
+		tcnt++;
+		j = contabp[i].mx;
+		for (k = 1; (j = blist[bindex(j)].nextoff) != -1; )
+			k++; 
+		cnt++;
+		kk += k;
+		if (!tot)
+			fprintf(stderr, "%-2.2s %d\n", unpair(xx), k);
+	}
+	fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
+}
+
+void stackdump(void)	/* dumps stack of macros in process */
+{
+	Stack *p;
+
+	if (frame != stk) {
+		fprintf(stderr, "stack: ");
+		for (p = frame; p != stk; p = p->pframe)
+			fprintf(stderr, "%s ", unpair(p->mname));
+		fprintf(stderr, "\n");
+	}
+}
blob - /dev/null
blob + 3b3698e4c3160c29dd26bc3622ec5e39f1c0a12a (mode 644)
--- /dev/null
+++ src/cmd/troff/n4.c
@@ -0,0 +1,828 @@
+/*
+ * troff4.c
+ *
+ * number registers, conversion, arithmetic
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+
+int	regcnt = NNAMES;
+int	falsef	= 0;	/* on if inside false branch of if */
+
+#define	NHASHSIZE	128	/* must be 2**n */
+#define	NHASH(i)	((i>>6)^i) & (NHASHSIZE-1)
+Numtab	*nhash[NHASHSIZE];
+
+Numtab *numtabp = NULL;
+#define NDELTA 400
+int ncnt = 0;
+
+void setn(void)
+{
+	int i, j, f;
+	Tchar ii;
+	Uchar *p;
+	char buf[NTM];		/* for \n(.S */
+
+	f = nform = 0;
+	if ((i = cbits(ii = getach())) == '+')
+		f = 1;
+	else if (i == '-')
+		f = -1;
+	else if (ii)	/* don't put it back if it's already back (thanks to jaap) */
+		ch = ii;
+	if (falsef)
+		f = 0;
+	if ((i = getsn()) == 0)
+		return;
+	p = unpair(i);
+	if (p[0] == '.')
+		switch (p[1]) {
+		case 's':
+			i = pts;
+			break;
+		case 'v':
+			i = lss;
+			break;
+		case 'f':
+			i = font;
+			break;
+		case 'p':
+			i = pl;
+			break;
+		case 't':
+			i = findt1();
+			break;
+		case 'o':
+			i = po;
+			break;
+		case 'l':
+			i = ll;
+			break;
+		case 'i':
+			i = in;
+			break;
+		case '$':
+			i = frame->nargs;
+			break;
+		case 'A':
+			i = ascii;
+			break;
+		case 'c':
+			i = numtabp[CD].val;
+			break;
+		case 'n':
+			i = lastl;
+			break;
+		case 'a':
+			i = ralss;
+			break;
+		case 'h':
+			i = dip->hnl;
+			break;
+		case 'd':
+			if (dip != d)
+				i = dip->dnl;
+			else
+				i = numtabp[NL].val;
+			break;
+		case 'u':
+			i = fi;
+			break;
+		case 'j':
+			i = ad + 2 * admod;
+			break;
+		case 'w':
+			i = widthp;
+			break;
+		case 'x':
+			i = nel;
+			break;
+		case 'y':
+			i = un;
+			break;
+		case 'T':
+			i = dotT;
+			break;	 /* -Tterm used in nroff */
+		case 'V':
+			i = VERT;
+			break;
+		case 'H':
+			i = HOR;
+			break;
+		case 'k':
+			i = ne;
+			break;
+		case 'P':
+			i = print;
+			break;
+		case 'L':
+			i = ls;
+			break;
+		case 'R':	/* maximal # of regs that can be addressed */
+			i = 255*256 - regcnt; 
+			break;
+		case 'z':
+			p = unpair(dip->curd);
+			*pbp++ = p[1];	/* watch order */
+			*pbp++ = p[0];
+			return;
+		case 'b':
+			i = bdtab[font];
+			break;
+		case 'F':
+			cpushback(cfname[ifi]);
+			return;
+ 		case 'S':
+ 			buf[0] = j = 0;	
+ 			for( i = 0; tabtab[i] != 0 && i < NTAB; i++) {
+ 				if (i > 0)
+ 					buf[j++] = ' ';
+ 				sprintf(&buf[j], "%d", tabtab[i] & TABMASK);
+ 				j = strlen(buf);
+ 				if ( tabtab[i] & RTAB)
+ 					sprintf(&buf[j], "uR");
+ 				else if (tabtab[i] & CTAB)
+ 					sprintf(&buf[j], "uC");
+ 				else
+ 					sprintf(&buf[j], "uL");
+ 				j += 2;
+ 			}
+ 			cpushback(buf);
+ 			return;
+		default:
+			goto s0;
+		}
+	else {
+s0:
+		if ((j = findr(i)) == -1)
+			i = 0;
+		else {
+			i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f;
+			nform = numtabp[j].fmt;
+		}
+	}
+	setn1(i, nform, (Tchar) 0);
+}
+
+Tchar	numbuf[25];
+Tchar	*numbufp;
+
+int wrc(Tchar i)
+{
+	if (numbufp >= &numbuf[24])
+		return(0);
+	*numbufp++ = i;
+	return(1);
+}
+
+
+
+/* insert into input number i, in format form, with size-font bits bits */
+void setn1(int i, int form, Tchar bits)
+{
+	numbufp = numbuf;
+	nrbits = bits;
+	nform = form;
+	fnumb(i, wrc);
+	*numbufp = 0;
+	pushback(numbuf);
+}
+
+void prnumtab(Numtab *p)
+{
+	int i;
+	for (i = 0; i < ncnt; i++)
+		if (p)
+			if (p[i].r != 0)
+				fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val);
+			else
+				fprintf(stderr, "slot %d empty\n", i);
+		else
+			fprintf(stderr, "slot %d empty\n", i);
+}
+
+void nnspace(void)
+{
+	ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA;
+	numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab));
+	if (numtabp == NULL) {
+		ERROR "not enough memory for registers (%d)", ncnt WARN;
+		exit(1);
+	}
+	numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
+							sizeof(numtab));
+	if (numtabp == NULL) {
+		ERROR "Cannot initialize registers" WARN;
+		exit(1);
+	}
+}
+
+void grownumtab(void)
+{
+	ncnt += NDELTA;
+	numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab));
+	if (numtabp == NULL) {
+		ERROR "Too many number registers (%d)", ncnt WARN;
+		done2(04);
+	} else {
+		memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab),
+						0, NDELTA * sizeof(Numtab));
+		nrehash();
+	}
+}
+
+void nrehash(void)
+{
+	Numtab *p;
+	int i;
+
+	for (i=0; i<NHASHSIZE; i++)
+		nhash[i] = 0;
+	for (p=numtabp; p < &numtabp[ncnt]; p++)
+		p->link = 0;
+	for (p=numtabp; p < &numtabp[ncnt]; p++) {
+		if (p->r == 0)
+			continue;
+		i = NHASH(p->r);
+		p->link = nhash[i];
+		nhash[i] = p;
+	}
+}
+
+void nunhash(Numtab *rp)
+{
+	Numtab *p;
+	Numtab **lp;
+
+	if (rp->r == 0)
+		return;
+	lp = &nhash[NHASH(rp->r)];
+	p = *lp;
+	while (p) {
+		if (p == rp) {
+			*lp = p->link;
+			p->link = 0;
+			return;
+		}
+		lp = &p->link;
+		p = p->link;
+	}
+}
+
+int findr(int i)
+{
+	Numtab *p;
+	int h = NHASH(i);
+
+	if (i == 0)
+		return(-1);
+a0:
+	for (p = nhash[h]; p; p = p->link)
+		if (i == p->r)
+			return(p - numtabp);
+	for (p = numtabp; p < &numtabp[ncnt]; p++) {
+		if (p->r == 0) {
+			p->r = i;
+			p->link = nhash[h];
+			nhash[h] = p;
+			regcnt++;
+			return(p - numtabp);
+		}
+	}
+	grownumtab();
+	goto a0;
+}
+
+int usedr(int i)	/* returns -1 if nr i has never been used */
+{
+	Numtab *p;
+
+	if (i == 0)
+		return(-1);
+	for (p = nhash[NHASH(i)]; p; p = p->link)
+		if (i == p->r)
+			return(p - numtabp);
+	return -1;
+}
+
+
+int fnumb(int i, int (*f)(Tchar))
+{
+	int j;
+
+	j = 0;
+	if (i < 0) {
+		j = (*f)('-' | nrbits);
+		i = -i;
+	}
+	switch (nform) {
+	default:
+	case '1':
+	case 0:
+		return decml(i, f) + j;
+	case 'i':
+	case 'I':
+		return roman(i, f) + j;
+	case 'a':
+	case 'A':
+		return abc(i, f) + j;
+	}
+}
+
+
+int decml(int i, int (*f)(Tchar))
+{
+	int j, k;
+
+	k = 0;
+	nform--;
+	if ((j = i / 10) || (nform > 0))
+		k = decml(j, f);
+	return(k + (*f)((i % 10 + '0') | nrbits));
+}
+
+
+int roman(int i, int (*f)(Tchar))
+{
+
+	if (!i)
+		return((*f)('0' | nrbits));
+	if (nform == 'i')
+		return(roman0(i, f, "ixcmz", "vldw"));
+	else
+		return(roman0(i, f, "IXCMZ", "VLDW"));
+}
+
+
+int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
+{
+	int q, rem, k;
+
+	if (!i)
+		return(0);
+	k = roman0(i / 10, f, onesp + 1, fivesp + 1);
+	q = (i = i % 10) / 5;
+	rem = i % 5;
+	if (rem == 4) {
+		k += (*f)(*onesp | nrbits);
+		if (q)
+			i = *(onesp + 1);
+		else
+			i = *fivesp;
+		return(k += (*f)(i | nrbits));
+	}
+	if (q)
+		k += (*f)(*fivesp | nrbits);
+	while (--rem >= 0)
+		k += (*f)(*onesp | nrbits);
+	return(k);
+}
+
+
+int abc(int i, int (*f)(Tchar))
+{
+	if (!i)
+		return((*f)('0' | nrbits));
+	else
+		return(abc0(i - 1, f));
+}
+
+
+int abc0(int i, int (*f)(Tchar))
+{
+	int j, k;
+
+	k = 0;
+	if (j = i / 26)
+		k = abc0(j - 1, f);
+	return(k + (*f)((i % 26 + nform) | nrbits));
+}
+
+long atoi0(void)
+{
+	int c, k, cnt;
+	Tchar ii;
+	long i, acc;
+
+	acc = 0;
+	nonumb = 0;
+	cnt = -1;
+a0:
+	cnt++;
+	ii = getch();
+	c = cbits(ii);
+	switch (c) {
+	default:
+		ch = ii;
+		if (cnt)
+			break;
+	case '+':
+		i = ckph();
+		if (nonumb)
+			break;
+		acc += i;
+		goto a0;
+	case '-':
+		i = ckph();
+		if (nonumb)
+			break;
+		acc -= i;
+		goto a0;
+	case '*':
+		i = ckph();
+		if (nonumb)
+			break;
+		acc *= i;
+		goto a0;
+	case '/':
+		i = ckph();
+		if (nonumb)
+			break;
+		if (i == 0) {
+			flusho();
+			ERROR "divide by zero." WARN;
+			acc = 0;
+		} else
+			acc /= i;
+		goto a0;
+	case '%':
+		i = ckph();
+		if (nonumb)
+			break;
+		acc %= i;
+		goto a0;
+	case '&':	/*and*/
+		i = ckph();
+		if (nonumb)
+			break;
+		if ((acc > 0) && (i > 0))
+			acc = 1;
+		else
+			acc = 0;
+		goto a0;
+	case ':':	/*or*/
+		i = ckph();
+		if (nonumb)
+			break;
+		if ((acc > 0) || (i > 0))
+			acc = 1;
+		else
+			acc = 0;
+		goto a0;
+	case '=':
+		if (cbits(ii = getch()) != '=')
+			ch = ii;
+		i = ckph();
+		if (nonumb) {
+			acc = 0;
+			break;
+		}
+		if (i == acc)
+			acc = 1;
+		else
+			acc = 0;
+		goto a0;
+	case '>':
+		k = 0;
+		if (cbits(ii = getch()) == '=')
+			k++;
+		else
+			ch = ii;
+		i = ckph();
+		if (nonumb) {
+			acc = 0;
+			break;
+		}
+		if (acc > (i - k))
+			acc = 1;
+		else
+			acc = 0;
+		goto a0;
+	case '<':
+		k = 0;
+		if (cbits(ii = getch()) == '=')
+			k++;
+		else
+			ch = ii;
+		i = ckph();
+		if (nonumb) {
+			acc = 0;
+			break;
+		}
+		if (acc < (i + k))
+			acc = 1;
+		else
+			acc = 0;
+		goto a0;
+	case ')':
+		break;
+	case '(':
+		acc = atoi0();
+		goto a0;
+	}
+	return(acc);
+}
+
+
+long ckph(void)
+{
+	Tchar i;
+	long j;
+
+	if (cbits(i = getch()) == '(')
+		j = atoi0();
+	else {
+		j = atoi1(i);
+	}
+	return(j);
+}
+
+
+/*
+ * print error about illegal numeric argument;
+ */
+void prnumerr(void)
+{
+	char err_buf[40];
+	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);
+	else
+		sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
+									warn);
+	if (frame != stk)	/* uncertainty correction */
+		numtabp[CD].val--;
+	ERROR err_buf WARN;
+	numtabp[CD].val = savcd;
+}
+
+
+long atoi1(Tchar ii)
+{
+	int i, j, digits;
+	double acc;	/* this is the only double in troff! */
+	int neg, abs, field, decpnt;
+	extern int ifnum;
+
+
+	neg = abs = field = decpnt = digits = 0;
+	acc = 0;
+	for (;;) {
+		i = cbits(ii);
+		switch (i) {
+		default:
+			break;
+		case '+':
+			ii = getch();
+			continue;
+		case '-':
+			neg = 1;
+			ii = getch();
+			continue;
+		case '|':
+			abs = 1 + neg;
+			neg = 0;
+			ii = getch();
+			continue;
+		}
+		break;
+	}
+a1:
+	while (i >= '0' && i <= '9') {
+		field++;
+		digits++;
+		acc = 10 * acc + i - '0';
+		ii = getch();
+		i = cbits(ii);
+	}
+	if (i == '.' && !decpnt++) {
+		field++;
+		digits = 0;
+		ii = getch();
+		i = cbits(ii);
+		goto a1;
+	}
+	if (!field) {
+		ch = ii;
+		goto a2;
+	}
+	switch (i) {
+	case 'u':
+		i = j = 1;	/* should this be related to HOR?? */
+		break;
+	case 'v':	/*VSs - vert spacing*/
+		j = lss;
+		i = 1;
+		break;
+	case 'm':	/*Ems*/
+		j = EM;
+		i = 1;
+		break;
+	case 'n':	/*Ens*/
+		j = EM;
+		if (TROFF)
+			i = 2;
+		else
+			i = 1;	/*Same as Ems in NROFF*/
+		break;
+	case 'p':	/*Points*/
+		j = INCH;
+		i = 72;
+		break;
+	case 'i':	/*Inches*/
+		j = INCH;
+		i = 1;
+		break;
+	case 'c':	/*Centimeters*/
+		/* if INCH is too big, this will overflow */
+		j = INCH * 50;
+		i = 127;
+		break;
+	case 'P':	/*Picas*/
+		j = INCH;
+		i = 6;
+		break;
+	default:
+		j = dfact;
+		ch = ii;
+		i = dfactd;
+	}
+	if (neg)
+		acc = -acc;
+	if (!noscale) {
+		acc = (acc * j) / i;
+	}
+	if (field != digits && digits > 0)
+		while (digits--)
+			acc /= 10;
+	if (abs) {
+		if (dip != d)
+			j = dip->dnl;
+		else
+			j = numtabp[NL].val;
+		if (!vflag) {
+			j = numtabp[HP].val;
+		}
+		if (abs == 2)
+			j = -j;
+		acc -= j;
+	}
+a2:
+	nonumb = (!field || field == decpnt);
+	if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
+		if (cbits(ii) != RIGHT ) /* Too painful to do right */
+			prnumerr();
+	}
+	return(acc);
+}
+
+
+void caserr(void)
+{
+	int i, j;
+	Numtab *p;
+
+	lgf++;
+	while (!skip() && (i = getrq()) ) {
+		j = usedr(i);
+		if (j < 0)
+			continue;
+		p = &numtabp[j];
+		nunhash(p);
+		p->r = p->val = p->inc = p->fmt = 0;
+		regcnt--;
+	}
+}
+
+/*
+ * .nr request; if tracing, don't check optional
+ * 2nd argument because tbl generates .in 1.5n
+ */
+void casenr(void)
+{
+	int i, j;
+	int savtr = trace;
+
+	lgf++;
+	skip();
+	if ((i = findr(getrq())) == -1)
+		goto rtn;
+	skip();
+	j = inumb(&numtabp[i].val);
+	if (nonumb)
+		goto rtn;
+	numtabp[i].val = j;
+	skip();
+	trace = 0;
+	j = atoi0();		/* BUG??? */
+	trace = savtr;
+	if (nonumb)
+		goto rtn;
+	numtabp[i].inc = j;
+rtn:
+	return;
+}
+
+void caseaf(void)
+{
+	int i, k;
+	Tchar j;
+
+	lgf++;
+	if (skip() || !(i = getrq()) || skip())
+		return;
+	k = 0;
+	j = getch();
+	if (!isalpha(cbits(j))) {
+		ch = j;
+		while ((j = cbits(getch())) >= '0' &&  j <= '9')
+			k++;
+	}
+	if (!k)
+		k = j;
+	numtabp[findr(i)].fmt = k;	/* was k & BYTEMASK */
+}
+
+void setaf(void)	/* return format of number register */
+{
+	int i, j;
+
+	i = usedr(getsn());
+	if (i == -1)
+		return;
+	if (numtabp[i].fmt > 20)	/* it was probably a, A, i or I */
+		*pbp++ = numtabp[i].fmt;
+	else
+		for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
+			*pbp++ = '0';
+}
+
+
+int vnumb(int *i)
+{
+	vflag++;
+	dfact = lss;
+	res = VERT;
+	return(inumb(i));
+}
+
+
+int hnumb(int *i)
+{
+	dfact = EM;
+	res = HOR;
+	return(inumb(i));
+}
+
+
+int inumb(int *n)
+{
+	int i, j, f;
+	Tchar ii;
+
+	f = 0;
+	if (n) {
+		if ((j = cbits(ii = getch())) == '+')
+			f = 1;
+		else if (j == '-')
+			f = -1;
+		else
+			ch = ii;
+	}
+	i = atoi0();
+	if (n && f)
+		i = *n + f * i;
+	i = quant(i, res);
+	vflag = 0;
+	res = dfactd = dfact = 1;
+	if (nonumb)
+		i = 0;
+	return(i);
+}
+
+
+int quant(int n, int m)
+{
+	int i, neg;
+
+	neg = 0;
+	if (n < 0) {
+		neg++;
+		n = -n;
+	}
+	/* better as i = ((n + m/2)/m)*m */
+	i = n / m;
+	if (n - m * i > m / 2)
+		i += 1;
+	i *= m;
+	if (neg)
+		i = -i;
+	return(i);
+}
blob - /dev/null
blob + c2801e4709d31dd2dac33ce79a56d72356a3735b (mode 644)
--- /dev/null
+++ src/cmd/troff/n5.c
@@ -0,0 +1,1149 @@
+/*
+ * 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;
+
+	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(&lt), 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(unsharp(nextf), "w")) == NULL) {
+			ERROR "fm: cannot open %s", nextf WARN;
+			return;
+		}
+		fcache[i].name = strdupl(nextf);
+	}
+	casetm1(0, fcache[i].fp);
+}
+
+void casetm1(int ab, FILE *out) 
+{
+	int i, j, c;
+	char *p;
+	char tmbuf[NTM];
+
+	lgf++;
+	copyf++;
+	if (ab) {
+		if (skip())
+			ERROR "User Abort" WARN;
+		else {
+			extern int error;
+			int savtrac = trace;
+			i = trace = 0;
+			noscale++;
+			i = inumb(&trace);
+			noscale--;
+			if (i) {
+				error = i;
+				if (nlflg || skip())
+					ERROR "User Abort, exit code %d", i WARN;
+			}
+			trace = savtrac;
+		}
+	} else
+		skip();	
+	for (i = 0; i < NTM - 2; ) {
+		if ((c = cbits(getch())) == '\n' || c == RIGHT)
+			break;
+		else if (c == MINUS) {	/* special pleading for strange encodings */
+			tmbuf[i++] = '\\';
+			tmbuf[i++] = '-';
+		} else if (c == PRESC) {
+			tmbuf[i++] = '\\';
+			tmbuf[i++] = 'e';
+		} else if (c == FILLER) {
+			tmbuf[i++] = '\\';
+			tmbuf[i++] = '&';
+		} else if (c == UNPAD) {
+			tmbuf[i++] = '\\';
+			tmbuf[i++] = ' ';
+		} else if (c == OHC) {
+			tmbuf[i++] = '\\';
+			tmbuf[i++] = '%';
+		} else if (c >= ALPHABET) {
+			p = chname(c);
+			switch (*p) {
+			case MBchar:
+				sprintf(&tmbuf[i], p+1);
+				break;
+			case Number:
+				sprintf(&tmbuf[i], "\\N'%s'", p+1);
+				break;
+			case Troffchar:
+				if ((j = strlen(p+1)) == 2)
+					sprintf(&tmbuf[i], "\\(%s", p+1);
+				else
+					sprintf(&tmbuf[i], "\\C'%s'", p+1);
+				break;
+			default:
+				sprintf(&tmbuf[i]," %s? ", p);
+				break;
+			}
+			j = strlen(&tmbuf[i]);
+			i += j;
+		} else
+			tmbuf[i++] = c;
+	}
+	tmbuf[i] = 0;
+	if (ab)	/* truncate output */
+		obufp = obuf;	/* should be a function in n2.c */
+	flusho();
+	if (i)
+		fprintf(out, "%s\n", tmbuf);
+	fflush(out);
+	copyf--;
+	lgf--;
+}
+
+
+void casesp(void)
+{
+	casesp1(0);
+}
+
+void casesp1(int a)
+{
+	int i, j, savlss;
+
+	tbreak();
+	if (dip->nls || trap)
+		return;
+	i = findt1();
+	if (!a) {
+		skip();
+		j = vnumb((int *)0);
+		if (nonumb)
+			j = lss;
+	} else 
+		j = a;
+	if (j == 0)
+		return;
+	if (i < j)
+		j = i;
+	savlss = lss;
+	if (dip != d)
+		i = dip->dnl; 
+	else 
+		i = numtabp[NL].val;
+	if ((i + j) < 0)
+		j = -i;
+	lss = j;
+	newline(0);
+	lss = savlss;
+}
+
+
+void casert(void)
+{
+	int a, *p;
+
+	skip();
+	if (dip != d)
+		p = &dip->dnl; 
+	else 
+		p = &numtabp[NL].val;
+	a = vnumb(p);
+	if (nonumb)
+		a = dip->mkline;
+	if ((a < 0) || (a >= *p))
+		return;
+	nb++;
+	casesp1(a - *p);
+}
+
+
+void caseem(void)
+{
+	lgf++;
+	skip();
+	em = getrq();
+}
+
+
+void casefl(void)
+{
+	tbreak();
+	if (!ascii)
+		ptflush();
+	flusho();
+}
+
+
+void caseev(void)
+{
+	int nxev;
+
+	if (skip()) {
+e0:
+		if (evi == 0)
+			return;
+		nxev =  evlist[--evi];
+		goto e1;
+	}
+	noscale++;
+	nxev = atoi0();
+	noscale = 0;
+	if (nonumb)
+		goto e0;
+	flushi();
+	if (nxev >= NEV || nxev < 0 || evi >= EVLSZ) {
+		flusho();
+		ERROR "cannot do .ev %d", nxev WARN;
+		if (error)
+			done2(040);
+		else 
+			edone(040);
+		return;
+	}
+	evlist[evi++] = ev;
+e1:
+	if (ev == nxev)
+		return;
+	ev = nxev;
+	envp = &env[ev];
+}
+
+void envcopy(Env *e1, Env *e2)	/* copy env e2 to e1 */
+{
+	*e1 = *e2;	/* rumor hath that this fails on some machines */
+}
+
+
+void caseel(void)
+{
+	if (--ifx < 0) {
+		ifx = 0;
+		iflist[0] = 0;
+	}
+	caseif1(2);
+}
+
+
+void caseie(void)
+{
+	if (ifx >= NIF) {
+		ERROR "if-else overflow." WARN;
+		ifx = 0;
+		edone(040);
+	}
+	caseif1(1);
+	ifx++;
+}
+
+
+void caseif(void)
+{
+	caseif1(0);
+}
+
+void caseif1(int x)
+{
+	extern int falsef;
+	int notflag, true;
+	Tchar i;
+
+	if (x == 2) {
+		notflag = 0;
+		true = iflist[ifx];
+		goto i1;
+	}
+	true = 0;
+	skip();
+	if ((cbits(i = getch())) == '!') {
+		notflag = 1;
+	} else {
+		notflag = 0;
+		ch = i;
+	}
+	ifnum++;
+	i = atoi0();
+	ifnum = 0;
+	if (!nonumb) {
+		if (i > 0)
+			true++;
+		goto i1;
+	}
+	i = getch();
+	switch (cbits(i)) {
+	case 'e':
+		if (!(numtabp[PN].val & 01))
+			true++;
+		break;
+	case 'o':
+		if (numtabp[PN].val & 01)
+			true++;
+		break;
+	case 'n':
+		if (NROFF)
+			true++;
+		break;
+	case 't':
+		if (TROFF)
+			true++;
+		break;
+	case ' ':
+		break;
+	default:
+		true = cmpstr(i);
+	}
+i1:
+	true ^= notflag;
+	if (x == 1)
+		iflist[ifx] = !true;
+	if (true) {
+i2:
+		while ((cbits(i = getch())) == ' ')
+			;
+		if (cbits(i) == LEFT)
+			goto i2;
+		ch = i;
+		nflush++;
+	} else {
+		if (!nlflg) {
+			copyf++;
+			falsef++;
+			eatblk(0);
+			copyf--;
+			falsef--;
+		}
+	}
+}
+
+void eatblk(int inblk)
+{
+	int cnt, i;
+
+	cnt = 0;
+	do {
+		if (ch)	{
+			i = cbits(ch);
+			ch = 0;
+		} else
+			i = cbits(getch0());
+		if (i == ESC)
+			cnt++;
+		else {
+			if (cnt == 1)
+				switch (i) {
+				case '{':  i = LEFT; break;
+				case '}':  i = RIGHT; break;
+				case '\n': i = 'x'; break;
+				}
+			cnt = 0;
+		}
+		if (i == LEFT) eatblk(1);
+	} while ((!inblk && (i != '\n')) || (inblk && (i != RIGHT)));
+	if (i == '\n') {
+		nlflg++;
+		if (ip == 0)
+			numtabp[CD].val++;
+	}
+}
+
+
+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*/
+{
+}
blob - /dev/null
blob + e4affa17d3a0a72583823b9745043adec806a182 (mode 644)
--- /dev/null
+++ src/cmd/troff/n6.c
@@ -0,0 +1,362 @@
+#include "tdef.h"
+#include "ext.h"
+#include "fns.h"
+#include <ctype.h>
+
+/*
+ * n6.c -- width functions, sizes and fonts
+*/
+
+n_width(Tchar j)
+{
+	int i, k;
+
+	if (iszbit(j))
+		return 0;
+	if (ismot(j)) {
+		if (isvmot(j))
+			return(0);
+		k = absmot(j);
+		if (isnmot(j))
+			k = -k;
+		return(k);
+	}
+	i = cbits(j);
+	if (i < ' ') {
+		if (i == '\b')
+			return(-widthp);
+		if (i == PRESC)
+			i = eschar;
+		else if (i == HX)
+			return(0);
+	}
+	if (i == ohc)
+		return(0);
+	i = trtab[i];
+	if (i < ' ')
+		return(0);
+	if (i >= t.tfont.nchars)	/* not on the font */
+		k = t.Char;		/* really ought to check properly */
+	else
+		k = t.tfont.wp[i].wid * t.Char;
+	widthp = k;
+	return(k);
+}
+
+
+Tchar n_setch(int c)
+{
+	return t_setch(c);
+}
+
+Tchar n_setabs(void)	/* set absolute char from \N'...' */
+{			/* for now, a no-op */
+	return t_setabs();
+}
+
+int n_findft(int i)
+{
+	int k;
+
+	if ((k = i - '0') >= 0 && k <= nfonts && k < smnt)
+		return(k);
+	for (k = 0; fontlab[k] != i; k++)
+		if (k > nfonts)
+			return(-1);
+	return(k);
+}
+
+
+
+void n_mchbits(void)
+{
+	chbits = 0;
+	setfbits(chbits, font);
+	sps = width(' ' | chbits);
+}
+
+
+void n_setps(void )
+{
+	int i, j;
+
+	i = cbits(getch());
+	if (isdigit(i)) {		/* \sd or \sdd */
+		i -= '0';
+		if (i == 0)		/* \s0 */
+			;
+		else if (i <= 3 && (ch=getch()) && isdigit(cbits(ch))) {	/* \sdd */
+			ch = 0;
+		}
+	} else if (i == '(') {		/* \s(dd */
+		getch();
+		getch();
+	} else if (i == '+' || i == '-') {	/* \s+, \s- */
+		j = cbits(getch());
+		if (isdigit(j)) {		/* \s+d, \s-d */
+			;
+		} else if (j == '(') {		/* \s+(dd, \s-(dd */
+			getch();
+			getch();
+		}
+	}
+}
+
+
+Tchar n_setht(void)		/* set character height from \H'...' */
+{
+
+	getch();
+	inumb(&apts);
+	getch();
+	return(0);
+}
+
+
+Tchar n_setslant(void)		/* set slant from \S'...' */
+{
+	int n;
+
+	getch();
+	n = 0;
+	n = inumb(&n);
+	getch();
+	return(0);
+}
+
+
+void n_caseft(void)
+{
+	skip();
+	setfont(1);
+}
+
+
+void n_setfont(int a)
+{
+	int i, j;
+
+	if (a)
+		i = getrq();
+	else 
+		i = getsn();
+	if (!i || i == 'P') {
+		j = font1;
+		goto s0;
+	}
+	if (i == 'S' || i == '0')
+		return;
+	if ((j = findft(i)) == -1)
+		return;
+s0:
+	font1 = font;
+	font = j;
+	mchbits();
+}
+
+
+void n_setwd(void)
+{
+	int base, wid;
+	Tchar i;
+	int	delim, emsz, k;
+	int	savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
+
+	base = numtabp[ST].val = numtabp[ST].val = wid = numtabp[CT].val = 0;
+	if (ismot(i = getch()))
+		return;
+	delim = cbits(i);
+	savhp = numtabp[HP].val;
+	numtabp[HP].val = 0;
+	savapts = apts;
+	savapts1 = apts1;
+	savfont = font;
+	savfont1 = font1;
+	savpts = pts;
+	savpts1 = pts1;
+	setwdf++;
+	while (cbits(i = getch()) != delim && !nlflg) {
+		k = width(i);
+		wid += k;
+		numtabp[HP].val += k;
+		if (!ismot(i)) {
+			emsz = (INCH * pts + 36) / 72;
+		} else if (isvmot(i)) {
+			k = absmot(i);
+			if (isnmot(i))
+				k = -k;
+			base -= k;
+			emsz = 0;
+		} else 
+			continue;
+		if (base < numtabp[SB].val)
+			numtabp[SB].val = base;
+		if ((k = base + emsz) > numtabp[ST].val)
+			numtabp[ST].val = k;
+	}
+	setn1(wid, 0, (Tchar) 0);
+	numtabp[HP].val = savhp;
+	apts = savapts;
+	apts1 = savapts1;
+	font = savfont;
+	font1 = savfont1;
+	pts = savpts;
+	pts1 = savpts1;
+	mchbits();
+	setwdf = 0;
+}
+
+
+Tchar n_vmot(void)
+{
+	dfact = lss;
+	vflag++;
+	return n_mot();
+}
+
+
+Tchar n_hmot(void)
+{
+	dfact = EM;
+	return n_mot();
+}
+
+
+Tchar n_mot(void)
+{
+	int j, n;
+	Tchar i;
+
+	j = HOR;
+	getch(); /*eat delim*/
+	if (n = atoi0()) {
+		if (vflag)
+			j = VERT;
+		i = makem(quant(n, j));
+	} else
+		i = 0;
+	getch();
+	vflag = 0;
+	dfact = 1;
+	return(i);
+}
+
+
+Tchar n_sethl(int k)
+{
+	int j;
+	Tchar i;
+
+	j = t.Halfline;
+	if (k == 'u')
+		j = -j;
+	else if (k == 'r')
+		j = -2 * j;
+	vflag++;
+	i = makem(j);
+	vflag = 0;
+	return(i);
+}
+
+
+Tchar n_makem(int i)
+{
+	Tchar j;
+
+	if (i >= 0)
+		j = i;
+	else
+		j = -i;
+	j |= MOT;
+	if (i < 0)
+		j |= NMOT;
+	if (vflag)
+		j |= VMOT;
+	return(j);
+}
+
+
+void n_casefp(void)
+{
+	int i, j;
+
+	skip();
+	if ((i = cbits(getch()) - '0') < 0 || i > nfonts)
+		return;
+	if (skip() || !(j = getrq()))
+		return;
+	fontlab[i] = j;
+}
+
+
+
+void n_casebd(void)
+{
+	int i, j, k;
+
+	k = 0;
+bd0:
+	if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
+		if (k)
+			goto bd1;
+		else 
+			return;
+	}
+	if (j == smnt) {
+		k = smnt;
+		goto bd0;
+	}
+	if (k) {
+		sbold = j;
+		j = k;
+	}
+bd1:
+	skip();
+	noscale++;
+	bdtab[j] = atoi0();
+	noscale = 0;
+}
+
+
+void n_casevs(void)
+{
+	int i;
+
+	skip();
+	vflag++;
+	dfact = INCH; /*default scaling is points!*/
+	dfactd = 72;
+	res = VERT;
+	i = inumb(&lss);
+	if (nonumb)
+		i = lss1;
+	if (i < VERT)
+		i = VERT;	/* was VERT */
+	lss1 = lss;
+	lss = i;
+}
+
+
+
+
+Tchar n_xlss(void)
+{
+	/* stores \x'...' into
+	/* two successive Tchars.
+	/* the first contains HX, the second the value,
+	/* encoded as a vertical motion.
+	/* decoding is done in n2.c by pchar().
+	*/
+	int	i;
+
+	getch();
+	dfact = lss;
+	i = quant(atoi0(), VERT);
+	dfact = 1;
+	getch();
+	if (i >= 0)
+		*pbp++ = MOT | VMOT | i;
+	else
+		*pbp++ = MOT | VMOT | NMOT | -i;
+	return(HX);
+}
blob - /dev/null
blob + c22a485c40500041447e5b5fb9ac181f76df109e (mode 644)
--- /dev/null
+++ src/cmd/troff/n7.c
@@ -0,0 +1,834 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+#ifdef STRICT
+	/* not in ANSI or POSIX */
+#define	isascii(a) ((a) >= 0 && (a) <= 127)
+#endif
+
+#define GETCH gettch
+Tchar	gettch(void);
+
+
+/*
+ * troff7.c
+ * 
+ * text
+ */
+
+int	brflg;
+
+void tbreak(void)
+{
+	int pad, k;
+	Tchar *i, j;
+	int resol;
+	int un0 = un;
+
+	trap = 0;
+	if (nb)
+		return;
+	if (dip == d && numtabp[NL].val == -1) {
+		newline(1);
+		return;
+	}
+	if (!nc) {
+		setnel();
+		if (!wch)
+			return;
+		if (pendw)
+			getword(1);
+		movword();
+	} else if (pendw && !brflg) {
+		getword(1);
+		movword();
+	}
+	*linep = dip->nls = 0;
+	if (NROFF && dip == d)
+		horiz(po);
+	if (lnmod)
+		donum();
+	lastl = ne;
+	if (brflg != 1) {
+		totout = 0;
+	} else if (ad) {
+		if ((lastl = ll - un) < ne)
+			lastl = ne;
+	}
+	if (admod && ad && (brflg != 2)) {
+		lastl = ne;
+		adsp = adrem = 0;
+		if (admod == 1)
+			un +=  quant(nel / 2, HOR);
+		else if (admod == 2)
+			un += nel;
+	}
+	totout++;
+	brflg = 0;
+	if (lastl + un > dip->maxl)
+		dip->maxl = lastl + un;
+	horiz(un);
+	if (NROFF) {
+		if (adrem % t.Adj)
+			resol = t.Hor; 
+		else 
+			resol = t.Adj;
+	} else
+		resol = HOR;
+
+	lastl = ne + (nwd-1) * adsp + adrem;
+	for (i = line; nc > 0; ) {
+		if ((cbits(j = *i++)) == ' ') {
+			pad = 0;
+			do {
+				pad += width(j);
+				nc--;
+			} while ((cbits(j = *i++)) == ' ');
+			i--;
+			pad += adsp;
+			--nwd;
+			if (adrem) {
+				if (adrem < 0) {
+					pad -= resol;
+					adrem += resol;
+				} else if ((totout & 01) || adrem / resol >= nwd) {
+					pad += resol;
+					adrem -= resol;
+				}
+			}
+			pchar((Tchar) WORDSP);
+			horiz(pad);
+		} else {
+			pchar(j);
+			nc--;
+		}
+	}
+	if (ic) {
+		if ((k = ll - un0 - lastl + ics) > 0)
+			horiz(k);
+		pchar(ic);
+	}
+	if (icf)
+		icf++;
+	else 
+		ic = 0;
+	ne = nwd = 0;
+	un = in;
+	setnel();
+	newline(0);
+	if (dip != d) {
+		if (dip->dnl > dip->hnl)
+			dip->hnl = dip->dnl;
+	} else {
+		if (numtabp[NL].val > dip->hnl)
+			dip->hnl = numtabp[NL].val;
+	}
+	for (k = ls - 1; k > 0 && !trap; k--)
+		newline(0);
+	spread = 0;
+}
+
+void donum(void)
+{
+	int i, nw;
+	int lnv = numtabp[LN].val;
+
+	nrbits = nmbits;
+	nw = width('1' | nrbits);
+	if (nn) {
+		nn--;
+		goto d1;
+	}
+	if (lnv % ndf) {
+		numtabp[LN].val++;
+d1:
+		un += nw * (nmwid + nms + ni);
+		return;
+	}
+	i = 0;
+	do {		/* count digits in numtabp[LN].val */
+		i++;
+	} while ((lnv /= 10) > 0);
+	horiz(nw * (ni + max(nmwid-i, 0)));
+	nform = 0;
+	fnumb(numtabp[LN].val, pchar);
+	un += nw * nms;
+	numtabp[LN].val++;
+}
+
+
+void text(void)
+{
+	Tchar i;
+	static int spcnt;
+
+	nflush++;
+	numtabp[HP].val = 0;
+	if ((dip == d) && (numtabp[NL].val == -1)) {
+		newline(1); 
+		return;
+	}
+	setnel();
+	if (ce || !fi) {
+		nofill();
+		return;
+	}
+	if (pendw)
+		goto t4;
+	if (pendt)
+		if (spcnt)
+			goto t2; 
+		else 
+			goto t3;
+	pendt++;
+	if (spcnt)
+		goto t2;
+	while ((cbits(i = GETCH())) == ' ') {
+		spcnt++;
+		numtabp[HP].val += sps;
+		widthp = sps;
+	}
+	if (nlflg) {
+t1:
+		nflush = pendt = ch = spcnt = 0;
+		callsp();
+		return;
+	}
+	ch = i;
+	if (spcnt) {
+t2:
+		tbreak();
+		if (nc || wch)
+			goto rtn;
+		un += spcnt * sps;
+		spcnt = 0;
+		setnel();
+		if (trap)
+			goto rtn;
+		if (nlflg)
+			goto t1;
+	}
+t3:
+	if (spread)
+		goto t5;
+	if (pendw || !wch)
+t4:
+		if (getword(0))
+			goto t6;
+	if (!movword())
+		goto t3;
+t5:
+	if (nlflg)
+		pendt = 0;
+	adsp = adrem = 0;
+	if (ad) {
+		if (nwd == 1)
+			adsp = nel; 
+		else 
+			adsp = nel / (nwd - 1);
+		adsp = (adsp / HOR) * HOR;
+		adrem = nel - adsp*(nwd-1);
+	}
+	brflg = 1;
+	tbreak();
+	spread = 0;
+	if (!trap)
+		goto t3;
+	if (!nlflg)
+		goto rtn;
+t6:
+	pendt = 0;
+	ckul();
+rtn:
+	nflush = 0;
+}
+
+
+void nofill(void)
+{
+	int j;
+	Tchar i;
+
+	if (!pendnf) {
+		over = 0;
+		tbreak();
+		if (trap)
+			goto rtn;
+		if (nlflg) {
+			ch = nflush = 0;
+			callsp();
+			return;
+		}
+		adsp = adrem = 0;
+		nwd = 10000;
+	}
+	while ((j = (cbits(i = GETCH()))) != '\n') {
+		if (j == ohc)
+			continue;
+		if (j == CONT) {
+			pendnf++;
+			nflush = 0;
+			flushi();
+			ckul();
+			return;
+		}
+		j = width(i);
+		widthp = j;
+		numtabp[HP].val += j;
+		storeline(i, j);
+	}
+	if (ce) {
+		ce--;
+		if ((i = quant(nel / 2, HOR)) > 0)
+			un += i;
+	}
+	if (!nc)
+		storeline((Tchar)FILLER, 0);
+	brflg = 2;
+	tbreak();
+	ckul();
+rtn:
+	pendnf = nflush = 0;
+}
+
+
+void callsp(void)
+{
+	int i;
+
+	if (flss)
+		i = flss; 
+	else 
+		i = lss;
+	flss = 0;
+	casesp1(i);
+}
+
+
+void ckul(void)
+{
+	if (ul && (--ul == 0)) {
+		cu = 0;
+		font = sfont;
+		mchbits();
+	}
+	if (it && --it == 0 && itmac)
+		control(itmac, 0);
+}
+
+
+void storeline(Tchar c, int w)
+{
+	int diff;
+
+	if (linep >= line + lnsize - 2) {
+		lnsize += LNSIZE;
+		diff = linep - line;
+		if (( line = (Tchar *)realloc((char *)line, lnsize * sizeof(Tchar))) != NULL) {
+			if (linep && diff)
+				linep = line + diff;
+		} else {
+			if (over) {
+				return;
+			} else {
+				flusho();
+				ERROR "Line overflow." WARN;
+				over++;
+				*linep++ = LEFTHAND;
+				w = width(LEFTHAND);
+				nc++;
+				c = '\n';
+			}
+		}
+	}
+	*linep++ = c;
+	ne += w;
+	nel -= w;
+	nc++;
+}
+
+
+void newline(int a)
+{
+	int i, j, nlss;
+	int opn;
+
+	if (a)
+		goto nl1;
+	if (dip != d) {
+		j = lss;
+		pchar1((Tchar)FLSS);
+		if (flss)
+			lss = flss;
+		i = lss + dip->blss;
+		dip->dnl += i;
+		pchar1((Tchar)i);
+		pchar1((Tchar)'\n');
+		lss = j;
+		dip->blss = flss = 0;
+		if (dip->alss) {
+			pchar1((Tchar)FLSS);
+			pchar1((Tchar)dip->alss);
+			pchar1((Tchar)'\n');
+			dip->dnl += dip->alss;
+			dip->alss = 0;
+		}
+		if (dip->ditrap && !dip->ditf && dip->dnl >= dip->ditrap && dip->dimac)
+			if (control(dip->dimac, 0)) {
+				trap++; 
+				dip->ditf++;
+			}
+		return;
+	}
+	j = lss;
+	if (flss)
+		lss = flss;
+	nlss = dip->alss + dip->blss + lss;
+	numtabp[NL].val += nlss;
+	if (TROFF && ascii) {
+		dip->alss = dip->blss = 0;
+	}
+	pchar1((Tchar)'\n');
+	flss = 0;
+	lss = j;
+	if (numtabp[NL].val < pl)
+		goto nl2;
+nl1:
+	ejf = dip->hnl = numtabp[NL].val = 0;
+	ejl = frame;
+	if (donef) {
+		if ((!nc && !wch) || ndone)
+			done1(0);
+		ndone++;
+		donef = 0;
+		if (frame == stk)
+			nflush++;
+	}
+	opn = numtabp[PN].val;
+	numtabp[PN].val++;
+	if (npnflg) {
+		numtabp[PN].val = npn;
+		npn = npnflg = 0;
+	}
+nlpn:
+	if (numtabp[PN].val == pfrom) {
+		print++;
+		pfrom = -1;
+	} else if (opn == pto) {
+		print = 0;
+		opn = -1;
+		chkpn();
+		goto nlpn;
+	}
+	if (print)
+		ptpage(numtabp[PN].val);	/* supposedly in a clean state so can pause */
+	if (stop && print) {
+		dpn++;
+		if (dpn >= stop) {
+			dpn = 0;
+			ptpause();
+		}
+	}
+nl2:
+	trap = 0;
+	if (numtabp[NL].val == 0) {
+		if ((j = findn(0)) != NTRAP)
+			trap = control(mlist[j], 0);
+	} else if ((i = findt(numtabp[NL].val - nlss)) <= nlss) {
+		if ((j = findn1(numtabp[NL].val - nlss + i)) == NTRAP) {
+			flusho();
+			ERROR "Trap botch." WARN;
+			done2(-5);
+		}
+		trap = control(mlist[j], 0);
+	}
+}
+
+
+findn1(int a)
+{
+	int i, j;
+
+	for (i = 0; i < NTRAP; i++) {
+		if (mlist[i]) {
+			if ((j = nlist[i]) < 0)
+				j += pl;
+			if (j == a)
+				break;
+		}
+	}
+	return(i);
+}
+
+
+void chkpn(void)
+{
+	pto = *(pnp++);
+	pfrom = pto>=0 ? pto : -pto;
+	if (pto == -INT_MAX) {
+		flusho();
+		done1(0);
+	}
+	if (pto < 0) {
+		pto = -pto;
+		print++;
+		pfrom = 0;
+	}
+}
+
+
+findt(int a)
+{
+	int i, j, k;
+
+	k = INT_MAX;
+	if (dip != d) {
+		if (dip->dimac && (i = dip->ditrap - a) > 0)
+			k = i;
+		return(k);
+	}
+	for (i = 0; i < NTRAP; i++) {
+		if (mlist[i]) {
+			if ((j = nlist[i]) < 0)
+				j += pl;
+			if ((j -= a) <= 0)
+				continue;
+			if (j < k)
+				k = j;
+		}
+	}
+	i = pl - a;
+	if (k > i)
+		k = i;
+	return(k);
+}
+
+
+findt1(void)
+{
+	int i;
+
+	if (dip != d)
+		i = dip->dnl;
+	else 
+		i = numtabp[NL].val;
+	return(findt(i));
+}
+
+
+void eject(Stack *a)
+{
+	int savlss;
+
+	if (dip != d)
+		return;
+	ejf++;
+	if (a)
+		ejl = a;
+	else 
+		ejl = frame;
+	if (trap)
+		return;
+e1:
+	savlss = lss;
+	lss = findt(numtabp[NL].val);
+	newline(0);
+	lss = savlss;
+	if (numtabp[NL].val && !trap)
+		goto e1;
+}
+
+
+movword(void)
+{
+	int w;
+	Tchar i, *wp;
+	int savwch, hys;
+
+	over = 0;
+	wp = wordp;
+	if (!nwd) {
+		while (cbits(*wp++) == ' ') {
+			wch--;
+			wne -= sps;
+		}
+		wp--;
+	}
+	if (wne > nel && !hyoff && hyf && (!nwd || nel > 3 * sps) &&
+	   (!(hyf & 02) || (findt1() > lss)))
+		hyphen(wp);
+	savwch = wch;
+	hyp = hyptr;
+	nhyp = 0;
+	while (*hyp && *hyp <= wp)
+		hyp++;
+	while (wch) {
+		if (hyoff != 1 && *hyp == wp) {
+			hyp++;
+			if (!wdstart || (wp > wdstart + 1 && wp < wdend &&
+			   (!(hyf & 04) || wp < wdend - 1) &&		/* 04 => last 2 */
+			   (!(hyf & 010) || wp > wdstart + 2))) {	/* 010 => 1st 2 */
+				nhyp++;
+				storeline((Tchar)IMP, 0);
+			}
+		}
+		i = *wp++;
+		w = width(i);
+		wne -= w;
+		wch--;
+		storeline(i, w);
+	}
+	if (nel >= 0) {
+		nwd++;
+		return(0);	/* line didn't fill up */
+	}
+	if (TROFF)
+		xbits((Tchar)HYPHEN, 1);
+	hys = width((Tchar)HYPHEN);
+m1:
+	if (!nhyp) {
+		if (!nwd)
+			goto m3;
+		if (wch == savwch)
+			goto m4;
+	}
+	if (*--linep != IMP)
+		goto m5;
+	if (!(--nhyp))
+		if (!nwd)
+			goto m2;
+	if (nel < hys) {
+		nc--;
+		goto m1;
+	}
+m2:
+	if ((i = cbits(*(linep - 1))) != '-' && i != EMDASH) {
+		*linep = (*(linep - 1) & SFMASK) | HYPHEN;
+		w = width(*linep);
+		nel -= w;
+		ne += w;
+		linep++;
+	}
+m3:
+	nwd++;
+m4:
+	wordp = wp;
+	return(1);	/* line filled up */
+m5:
+	nc--;
+	w = width(*linep);
+	ne -= w;
+	nel += w;
+	wne += w;
+	wch++;
+	wp--;
+	goto m1;
+}
+
+
+void horiz(int i)
+{
+	vflag = 0;
+	if (i)
+		pchar(makem(i));
+}
+
+
+void setnel(void)
+{
+	if (!nc) {
+		linep = line;
+		if (un1 >= 0) {
+			un = un1;
+			un1 = -1;
+		}
+		nel = ll - un;
+		ne = adsp = adrem = 0;
+	}
+}
+
+
+getword(int x)
+{
+	int j, k;
+	Tchar i, *wp;
+	int noword;
+	int obits;
+
+	noword = 0;
+	if (x)
+		if (pendw) {
+			*pendw = 0;
+			goto rtn;
+		}
+	if (wordp = pendw)
+		goto g1;
+	hyp = hyptr;
+	wordp = word;
+	over = wne = wch = 0;
+	hyoff = 0;
+	obits = chbits;
+	while (1) {	/* picks up 1st char of word */
+		j = cbits(i = GETCH());
+		if (j == '\n') {
+			wne = wch = 0;
+			noword = 1;
+			goto rtn;
+		}
+		if (j == ohc) {
+			hyoff = 1;	/* 1 => don't hyphenate */
+			continue;
+		}
+		if (j == ' ') {
+			numtabp[HP].val += sps;
+			widthp = sps;
+			storeword(i, sps);
+			continue;
+		}
+		break;
+	}
+	storeword(' ' | obits, sps);
+	if (spflg) {
+		storeword(' ' | obits, sps);
+		spflg = 0;
+	}
+g0:
+	if (j == CONT) {
+		pendw = wordp;
+		nflush = 0;
+		flushi();
+		return(1);
+	}
+	if (hyoff != 1) {
+		if (j == ohc) {
+			hyoff = 2;
+			*hyp++ = wordp;
+			if (hyp > hyptr + NHYP - 1)
+				hyp = hyptr + NHYP - 1;
+			goto g1;
+		}
+		if (((j == '-' || j == EMDASH)) && !(i & ZBIT))	/* zbit avoids \X */
+			if (wordp > word + 1) {
+				hyoff = 2;
+				*hyp++ = wordp + 1;
+				if (hyp > hyptr + NHYP - 1)
+					hyp = hyptr + NHYP - 1;
+			}
+	}
+	j = width(i);
+	numtabp[HP].val += j;
+	storeword(i, j);
+g1:
+	j = cbits(i = GETCH());
+	if (j != ' ') {
+		static char *sentchar = ".?!";	/* sentence terminators */
+		if (j != '\n')
+			goto g0;
+		wp = wordp-1;	/* handle extra space at end of sentence */
+		while (wp >= word) {
+			j = cbits(*wp--);
+			if (j=='"' || j=='\'' || j==')' || j==']' || j=='*' || j==DAGGER)
+				continue;
+			for (k = 0; sentchar[k]; k++)
+				if (j == sentchar[k]) {
+					spflg++;
+					break;
+				}
+			break;
+		}
+	}
+	*wordp = 0;
+	numtabp[HP].val += sps;
+rtn:
+	for (wp = word; *wp; wp++) {
+		if (ismot(j))
+			break;	/* drechsler */
+		j = cbits(*wp);
+		if (j == ' ')
+			continue;
+		if (!(isascii(j) && isdigit(j)) && j != '-')
+			break;
+	}
+	if (*wp == 0)	/* all numbers, so don't hyphenate */
+		hyoff = 1;
+	wdstart = 0;
+	wordp = word;
+	pendw = 0;
+	*hyp++ = 0;
+	setnel();
+	return(noword);
+}
+
+
+void storeword(Tchar c, int w)
+{
+	Tchar *savp;
+	int i;
+
+	if (wordp >= word + wdsize - 2) {
+		wdsize += WDSIZE;
+		savp = word;
+		if (( word = (Tchar *)realloc((char *)word, wdsize * sizeof(Tchar))) != NULL) {
+			if (wordp)
+				wordp = word + (wordp - savp);
+			if (pendw)
+				pendw = word + (pendw - savp);
+			if (wdstart)
+				wdstart = word + (wdstart - savp);
+			if (wdend)
+				wdend = word + (wdend - savp);
+			for (i = 0; i < NHYP; i++)
+				if (hyptr[i])
+					hyptr[i] = word + (hyptr[i] - savp);
+		} else {
+			if (over) {
+				return;
+			} else {
+				flusho();
+				ERROR "Word overflow." WARN;
+				over++;
+				c = LEFTHAND;
+				w = width(LEFTHAND);
+			}
+		}
+	}
+	widthp = w;
+	wne += w;
+	*wordp++ = c;
+	wch++;
+}
+
+
+Tchar gettch(void)
+{
+	extern int c_isalnum;
+	Tchar i;
+	int j;
+
+	if (TROFF)
+		return getch();
+
+	i = getch();
+	j = cbits(i);
+	if (ismot(i) || fbits(i) != ulfont)
+		return(i);
+	if (cu) {
+		if (trtab[j] == ' ') {
+			setcbits(i, '_');
+			setfbits(i, FT);	/* default */
+		}
+		return(i);
+	}
+	/* should test here for characters that ought to be underlined */
+	/* in the old nroff, that was the 200 bit on the width! */
+	/* for now, just do letters, digits and certain special chars */
+	if (j <= 127) {
+		if (!isalnum(j))
+			setfbits(i, FT);
+	} else {
+		if (j < c_isalnum)
+			setfbits(i, FT);
+	}
+	return(i);
+}
blob - /dev/null
blob + d1be50805bb6eb7336ed94638c7fb20870e0c683 (mode 644)
--- /dev/null
+++ src/cmd/troff/n8.c
@@ -0,0 +1,540 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+#define	HY_BIT	0200	/* stuff in here only works for 7-bit ascii */
+			/* this value is used (as a literal) in suftab.c */
+			/* to encode possible hyphenation points in suffixes. */
+			/* it could be changed, by widening the tables */
+			/* to be shorts instead of chars. */
+
+/*
+ * troff8.c
+ * 
+ * hyphenation
+ */
+
+int	hexsize = 0;		/* hyphenation exception list size */
+char	*hbufp = NULL;		/* base of list */
+char	*nexth = NULL;		/* first free slot in list */
+Tchar	*hyend;
+
+#define THRESH 160 		/* digram goodness threshold */
+int	thresh = THRESH;
+
+int	texhyphen(void);
+static	int	alpha(Tchar);
+
+void hyphen(Tchar *wp)
+{
+	int j;
+	Tchar *i;
+
+	i = wp;
+	while (punct((*i++)))
+		;
+	if (!alpha(*--i))
+		return;
+	wdstart = i++;
+	while (alpha(*i++))
+		;
+	hyend = wdend = --i - 1;
+	while (punct((*i++)))
+		;
+	if (*--i)
+		return;
+	if (wdend - wdstart < 4)	/* 4 chars is too short to hyphenate */
+		return;
+	hyp = hyptr;
+	*hyp = 0;
+	hyoff = 2;
+
+	/* for now, try exceptions first, then tex (if hyphalg is non-zero),
+	   then suffix and digram if tex didn't hyphenate it at all.
+	*/
+
+	if (!exword() && !texhyphen() && !suffix())
+		digram();
+
+	/* this appears to sort hyphenation points into increasing order */
+	*hyp++ = 0;
+	if (*hyptr) 
+		for (j = 1; j; ) {
+			j = 0;
+			for (hyp = hyptr + 1; *hyp != 0; hyp++) {
+				if (*(hyp - 1) > *hyp) {
+					j++;
+					i = *hyp;
+					*hyp = *(hyp - 1);
+					*(hyp - 1) = i;
+				}
+			}
+		}
+}
+
+static alpha(Tchar i)	/* non-zero if really alphabetic */
+{
+	if (ismot(i))
+		return 0;
+	else if (cbits(i) >= ALPHABET)	/* this isn't very elegant, but there's */
+		return 0;		/* no good way to make sure i is in range for */
+	else				/* the call of isalpha */
+		return isalpha(cbits(i));
+}
+
+
+punct(Tchar i)
+{
+	if (!i || alpha(i))
+		return(0);
+	else
+		return(1);
+}
+
+
+void caseha(void)	/* set hyphenation algorithm */
+{
+	hyphalg = HYPHALG;
+	if (skip())
+		return;
+	noscale++;
+	hyphalg = atoi0();
+	noscale = 0;
+}
+
+
+void caseht(void)	/* set hyphenation threshold;  not in manual! */
+{
+	thresh = THRESH;
+	if (skip())
+		return;
+	noscale++;
+	thresh = atoi0();
+	noscale = 0;
+}
+
+
+char *growh(char *where)
+{
+	char *new;
+
+	hexsize += NHEX;
+	if ((new = grow(hbufp, hexsize, sizeof(char))) == NULL)
+		return NULL;
+	if (new == hbufp) {
+		return where;
+	} else {
+		int diff;
+		diff = where - hbufp;
+		hbufp = new;
+		return new + diff;
+	}
+}
+
+
+void casehw(void)
+{
+	int i, k;
+	char *j;
+	Tchar t;
+
+	if (nexth == NULL) {
+		if ((nexth = hbufp = grow(hbufp, NHEX, sizeof(char))) == NULL) {
+			ERROR "No space for exception word list." WARN;
+			return;
+		}
+		hexsize = NHEX;
+	}
+	k = 0;
+	while (!skip()) {
+		if ((j = nexth) >= hbufp + hexsize - 2)
+			if ((j = nexth = growh(j)) == NULL)
+				goto full;
+		for (;;) {
+			if (ismot(t = getch()))
+				continue;
+			i = cbits(t);
+			if (i == ' ' || i == '\n') {
+				*j++ = 0;
+				nexth = j;
+				*j = 0;
+				if (i == ' ')
+					break;
+				else
+					return;
+			}
+			if (i == '-') {
+				k = HY_BIT;
+				continue;
+			}
+			*j++ = maplow(i) | k;
+			k = 0;
+			if (j >= hbufp + hexsize - 2)
+				if ((j = growh(j)) == NULL)
+					goto full;
+		}
+	}
+	return;
+full:
+	ERROR "Cannot grow exception word list." WARN;
+	*nexth = 0;
+}
+
+
+int exword(void)
+{
+	Tchar *w;
+	char *e, *save;
+
+	e = hbufp;
+	while (1) {
+		save = e;
+		if (e == NULL || *e == 0)
+			return(0);
+		w = wdstart;
+		while (*e && w <= hyend && (*e & 0177) == maplow(cbits(*w))) {
+			e++; 
+			w++;
+		}
+		if (!*e) {
+			if (w-1 == hyend || (w == wdend && maplow(cbits(*w)) == 's')) {
+				w = wdstart;
+				for (e = save; *e; e++) {
+					if (*e & HY_BIT)
+						*hyp++ = w;
+					if (hyp > hyptr + NHYP - 1)
+						hyp = hyptr + NHYP - 1;
+					w++;
+				}
+				return(1);
+			} else {
+				e++; 
+				continue;
+			}
+		} else 
+			while (*e++)
+				;
+	}
+}
+
+
+suffix(void)
+{
+	Tchar *w;
+	char *s, *s0;
+	Tchar i;
+	extern char *suftab[];
+
+again:
+	i = cbits(*hyend);
+	if (!alpha(i))
+		return(0);
+	if (i < 'a')
+		i -= 'A' - 'a';
+	if ((s0 = suftab[i-'a']) == 0)
+		return(0);
+	for (;;) {
+		if ((i = *s0 & 017) == 0)
+			return(0);
+		s = s0 + i - 1;
+		w = hyend - 1;
+		while (s > s0 && w >= wdstart && (*s & 0177) == maplow(cbits(*w))) {
+			s--;
+			w--;
+		}
+		if (s == s0)
+			break;
+		s0 += i;
+	}
+	s = s0 + i - 1;
+	w = hyend;
+	if (*s0 & HY_BIT) 
+		goto mark;
+	while (s > s0) {
+		w--;
+		if (*s-- & HY_BIT) {
+mark:
+			hyend = w - 1;
+			if (*s0 & 0100)	/* 0100 used in suftab to encode something too */
+				continue;
+			if (!chkvow(w))
+				return(0);
+			*hyp++ = w;
+		}
+	}
+	if (*s0 & 040)
+		return(0);
+	if (exword())
+		return(1);
+	goto again;
+}
+
+
+maplow(int i)
+{
+	if (isupper(i)) 
+		i = tolower(i);
+	return(i);
+}
+
+
+vowel(int i)
+{
+	switch (i) {
+	case 'a': case 'A':
+	case 'e': case 'E':
+	case 'i': case 'I':
+	case 'o': case 'O':
+	case 'u': case 'U':
+	case 'y': case 'Y':
+		return(1);
+	default:
+		return(0);
+	}
+}
+
+
+Tchar *chkvow(Tchar *w)
+{
+	while (--w >= wdstart)
+		if (vowel(cbits(*w)))
+			return(w);
+	return(0);
+}
+
+
+void digram(void)
+{
+	Tchar *w;
+	int val;
+	Tchar *nhyend, *maxw;
+	int maxval;
+	extern char bxh[26][13], bxxh[26][13], xxh[26][13], xhx[26][13], hxx[26][13];
+
+again:
+	if (!(w = chkvow(hyend + 1)))
+		return;
+	hyend = w;
+	if (!(w = chkvow(hyend)))
+		return;
+	nhyend = w;
+	maxval = 0;
+	w--;
+	while (++w < hyend && w < wdend - 1) {
+		val = 1;
+		if (w == wdstart)
+			val *= dilook('a', cbits(*w), bxh);
+		else if (w == wdstart + 1)
+			val *= dilook(cbits(*(w-1)), cbits(*w), bxxh);
+		else 
+			val *= dilook(cbits(*(w-1)), cbits(*w), xxh);
+		val *= dilook(cbits(*w), cbits(*(w+1)), xhx);
+		val *= dilook(cbits(*(w+1)), cbits(*(w+2)), hxx);
+		if (val > maxval) {
+			maxval = val;
+			maxw = w + 1;
+		}
+	}
+	hyend = nhyend;
+	if (maxval > thresh)
+		*hyp++ = maxw;
+	goto again;
+}
+
+
+dilook(int a, int b, char t[26][13])
+{
+	int i, j;
+
+	i = t[maplow(a)-'a'][(j = maplow(b)-'a')/2];
+	if (!(j & 01))
+		i >>= 4;
+	return(i & 017);
+}
+
+
+/* here beginneth the tex hyphenation code, as interpreted freely */
+/* the main difference is that there is no attempt to squeeze space */
+/* as tightly at tex does. */
+
+static int	texit(Tchar *, Tchar *);
+static int	readpats(void);
+static void	install(char *);
+static void	fixup(void);
+static int	trieindex(int, int);
+
+static char	pats[50000];	/* size ought to be computed dynamically */
+static char	*nextpat = pats;
+static char	*trie[27*27];	/* english-specific sizes */
+
+int texhyphen(void)
+{
+	static int loaded = 0;		/* -1: couldn't find tex file */
+
+	if (hyphalg == 0 || loaded == -1)	/* non-zero => tex for now */
+		return 0;
+	if (loaded == 0) {
+		if (readpats())
+			loaded = 1;
+		else
+			loaded = -1;
+	}
+	return texit(wdstart, wdend);
+}
+
+static int texit(Tchar *start, Tchar *end)	/* hyphenate as in tex, return # found */
+{
+	int nw, i, k, equal, cnt[500];
+	char w[500+1], *np, *pp, *wp, *xpp, *xwp;
+
+	w[0] = '.';
+	for (nw = 1; start <= end && nw < 500-1; nw++, start++)
+		w[nw] = maplow(tolower(cbits(*start)));
+	start -= (nw - 1);
+	w[nw++] = '.';
+	w[nw] = 0;
+/*
+ * printf("try %s\n", w);
+*/
+	for (i = 0; i <= nw; i++)
+		cnt[i] = '0';
+
+	for (wp = w; wp < w + nw; wp++) {
+		for (pp = trie[trieindex(*wp, *(wp+1))]; pp < nextpat; ) {
+			if (pp == 0		/* no trie entry */
+			 || *pp != *wp		/* no match on 1st letter */
+			 || *(pp+1) != *(wp+1))	/* no match on 2nd letter */
+				break;		/*   so move to next letter of word */
+			equal = 1;
+			for (xpp = pp+2, xwp = wp+2; *xpp; )
+				if (*xpp++ != *xwp++) {
+					equal = 0;
+					break;
+				}
+			if (equal) {
+				np = xpp+1;	/* numpat */
+				for (k = wp-w; *np; k++, np++)
+					if (*np > cnt[k])
+						cnt[k] = *np;
+/*
+ * printf("match: %s  %s\n", pp, xpp+1);
+*/
+			}
+			pp += *(pp-1);	/* skip over pattern and numbers to next */
+		}
+	}
+/*
+ * for (i = 0; i < nw; i++) printf("%c", w[i]);
+ * printf("  ");
+ * for (i = 0; i <= nw; i++) printf("%c", cnt[i]);
+ * printf("\n");
+*/
+/*
+ * 	for (i = 1; i < nw - 1; i++) {
+ * 		if (i > 2 && i < nw - 3 && cnt[i] % 2)
+ * 			printf("-");
+ * 		if (cbits(start[i-1]) != '.')
+ * 			printf("%c", cbits(start[i-1]));
+ * 	}
+ * 	printf("\n");
+*/
+	for (i = 1; i < nw -1; i++)
+		if (i > 2 && i < nw - 3 && cnt[i] % 2)
+			*hyp++ = start + i - 1;
+	return hyp - hyptr;	/* non-zero if a hyphen was found */
+}
+
+/*
+	This code assumes that hyphen.tex looks like
+		% some comments
+		\patterns{ % more comments
+		pat5ter4ns, 1 per line, SORTED, nothing else
+		}
+		more goo
+		\hyphenation{ % more comments
+		ex-cep-tions, one per line; i ignore this part for now
+		}
+
+	this code is NOT robust against variations.  unfortunately,
+	it looks like every local language version of this file has
+	a different format.  i have also made no provision for weird
+	characters.  sigh.
+*/
+
+static int readpats(void)
+{
+	FILE *fp;
+	char buf[200], buf1[200];
+
+	if ((fp = fopen(unsharp(TEXHYPHENS), "r")) == NULL
+	 && (fp = fopen(unsharp(DWBalthyphens), "r")) == NULL) {
+		ERROR "warning: can't find hyphen.tex" WARN;
+		return 0;
+	}
+
+	while (fgets(buf, sizeof buf, fp) != NULL) {
+		sscanf(buf, "%s", buf1);
+		if (strcmp(buf1, "\\patterns{") == 0)
+			break;
+	}
+	while (fgets(buf, sizeof buf, fp) != NULL) {
+		if (buf[0] == '}')
+			break;
+		install(buf);
+	}
+	fclose(fp);
+	fixup();
+	return 1;
+}
+
+static void install(char *s)	/* map ab4c5de to: 12 abcde \0 00405 \0 */
+{
+	int npat, lastpat;
+	char num[500], *onextpat = nextpat;
+
+	num[0] = '0';
+	*nextpat++ = ' ';	/* fill in with count later */
+	for (npat = lastpat = 0; *s != '\n' && *s != '\0'; s++) {
+		if (isdigit(*s)) {
+			num[npat] = *s;
+			lastpat = npat;
+		} else {
+			*nextpat++ = *s;
+			npat++;
+			num[npat] = '0';
+		}
+	}
+	*nextpat++ = 0;
+	if (nextpat > pats + sizeof(pats)-20) {
+		ERROR "tex hyphenation table overflow, tail end ignored" WARN;
+		nextpat = onextpat;
+	}
+	num[lastpat+1] = 0;
+	strcat(nextpat, num);
+	nextpat += strlen(nextpat) + 1;
+}
+
+static void fixup(void)	/* build indexes of where . a b c ... start */
+{
+	char *p, *lastc;
+	int n;
+
+	for (lastc = pats, p = pats+1; p < nextpat; p++)
+		if (*p == ' ') {
+			*lastc = p - lastc;
+			lastc = p;
+		}
+	*lastc = p - lastc;
+	for (p = pats+1; p < nextpat; ) {
+		n = trieindex(p[0], p[1]);
+		if (trie[n] == 0)
+			trie[n] = p;
+		p += p[-1];
+	}
+	/* printf("pats = %d\n", nextpat - pats); */
+}
+
+static int trieindex(int d1, int d2)
+{
+	return 27 * (d1 == '.' ? 0 : d1 - 'a' + 1) + (d2 == '.' ? 0 : d2 - 'a' + 1);
+}
blob - /dev/null
blob + 5cd70648cd77a9a560f1d1d02c5520df02ac76ef (mode 644)
--- /dev/null
+++ src/cmd/troff/n9.c
@@ -0,0 +1,488 @@
+#include "tdef.h"
+#include "ext.h"
+#include "fns.h"
+
+/*
+ * troff9.c
+ * 
+ * misc functions
+ */
+
+Tchar setz(void)
+{
+	Tchar i;
+
+	if (!ismot(i = getch()))
+		i |= ZBIT;
+	return(i);
+}
+
+void setline(void)
+{
+	Tchar *i;
+	Tchar c;
+	int length;
+	int j, w, cnt, delim, rem, temp;
+	Tchar linebuf[NC];
+
+	if (ismot(c = getch()))
+		return;
+	delim = cbits(c);
+	vflag = 0;
+	dfact = EM;
+	length = quant(atoi0(), HOR);
+	dfact = 1;
+	if (!length) {
+		eat(delim);
+		return;
+	}
+s0:
+	if ((j = cbits(c = getch())) == delim || j == '\n') {
+		ch = c;
+		c = RULE | chbits;
+	} else if (cbits(c) == FILLER)
+		goto s0;
+	w = width(c);
+	if (w <= 0) {
+		ERROR "zero-width underline character ignored" WARN;
+		c = RULE | chbits;
+		w = width(c);
+	}
+	i = linebuf;
+	if (length < 0) {
+		*i++ = makem(length);
+		length = -length;
+	}
+	if (!(cnt = length / w)) {
+		*i++ = makem(-(temp = ((w - length) / 2)));
+		*i++ = c;
+		*i++ = makem(-(w - length - temp));
+		goto s1;
+	}
+	if (rem = length % w) {
+		if (cbits(c) == RULE || cbits(c) == UNDERLINE || cbits(c) == ROOTEN)
+			*i++ = c | ZBIT;
+		*i++ = makem(rem);
+	}
+	if (cnt) {
+		*i++ = RPT;
+		*i++ = cnt;
+		*i++ = c;
+	}
+s1:
+	*i = 0;
+	eat(delim);
+	pushback(linebuf);
+}
+
+
+eat(int c)
+{
+	int i;
+
+	while ((i = cbits(getch())) != c && i != '\n')
+		;
+	return(i);
+}
+
+
+void setov(void)
+{
+	int j, k;
+	Tchar i, o[NOV+1];
+	int delim, w[NOV+1];
+
+	if (ismot(i = getch()))
+		return;
+	delim = cbits(i);
+	for (k = 0; k < NOV && (j = cbits(i = getch())) != delim && j != '\n'; k++) {
+		o[k] = i;
+		w[k] = width(i);
+	}
+	o[k] = w[k] = 0;
+	if (o[0])
+		for (j = 1; j; ) {
+			j = 0;
+			for (k = 1; o[k] ; k++) {
+				if (w[k-1] < w[k]) {
+					j++;
+					i = w[k];
+					w[k] = w[k-1];
+					w[k-1] = i;
+					i = o[k];
+					o[k] = o[k-1];
+					o[k-1] = i;
+				}
+			}
+		}
+	else 
+		return;
+	*pbp++ = makem(w[0] / 2);
+	for (k = 0; o[k]; k++)
+		;
+	while (k>0) {
+		k--;
+		*pbp++ = makem(-((w[k] + w[k+1]) / 2));
+		*pbp++ = o[k];
+	}
+}
+
+
+void setbra(void)
+{
+	int k;
+	Tchar i, *j, dwn;
+	int cnt, delim;
+	Tchar brabuf[NC];
+
+	if (ismot(i = getch()))
+		return;
+	delim = cbits(i);
+	j = brabuf + 1;
+	cnt = 0;
+	if (NROFF)
+		dwn = (2 * t.Halfline) | MOT | VMOT;
+	else
+		dwn = EM | MOT | VMOT;
+	while ((k = cbits(i = getch())) != delim && k != '\n' && j <= brabuf + NC - 4) {
+		*j++ = i | ZBIT;
+		*j++ = dwn;
+		cnt++;
+	}
+	if (--cnt < 0)
+		return;
+	else if (!cnt) {
+		ch = *(j - 2);
+		return;
+	}
+	*j = 0;
+	if (NROFF)
+		*--j = *brabuf = (cnt * t.Halfline) | MOT | NMOT | VMOT;
+	else
+		*--j = *brabuf = (cnt * EM) / 2 | MOT | NMOT | VMOT;
+	*--j &= ~ZBIT;
+	pushback(brabuf);
+}
+
+
+void setvline(void)
+{
+	int i;
+	Tchar c, rem, ver, neg;
+	int cnt, delim, v;
+	Tchar vlbuf[NC];
+	Tchar *vlp;
+
+	if (ismot(c = getch()))
+		return;
+	delim = cbits(c);
+	dfact = lss;
+	vflag++;
+	i = quant(atoi0(), VERT);
+	dfact = 1;
+	if (!i) {
+		eat(delim);
+		vflag = 0;
+		return;
+	}
+	if ((cbits(c = getch())) == delim) {
+		c = BOXRULE | chbits;	/*default box rule*/
+	} else 
+		getch();
+	c |= ZBIT;
+	neg = 0;
+	if (i < 0) {
+		i = -i;
+		neg = NMOT;
+	}
+	if (NROFF)
+		v = 2 * t.Halfline;
+	else {
+		v = EM;
+		if (v < VERT)		/* ATT EVK hack: Erik van Konijnenburg, */
+			v = VERT;	/* hvlpb!evkonij, ATT NSI Hilversum, Holland */
+	}
+
+	cnt = i / v;
+	rem = makem(i % v) | neg;
+	ver = makem(v) | neg;
+	vlp = vlbuf;
+	if (!neg)
+		*vlp++ = ver;
+	if (absmot(rem) != 0) {
+		*vlp++ = c;
+		*vlp++ = rem;
+	}
+	while (vlp < vlbuf + NC - 3 && cnt--) {
+		*vlp++ = c;
+		*vlp++ = ver;
+	}
+	*(vlp - 2) &= ~ZBIT;
+	if (!neg)
+		vlp--;
+	*vlp = 0;
+	pushback(vlbuf);
+	vflag = 0;
+}
+
+#define	NPAIR	(NC/2-6)	/* max pairs in spline, etc. */
+
+void setdraw(void)	/* generate internal cookies for a drawing function */
+{
+	int i, j, k, dx[NPAIR], dy[NPAIR], delim, type;
+	Tchar c, drawbuf[NC];
+	int drawch = '.';	/* character to draw with */
+
+	/* input is \D'f dx dy dx dy ... c' (or at least it had better be) */
+	/* this does drawing function f with character c and the */
+	/* specified dx,dy pairs interpreted as appropriate */
+	/* pairs are deltas from last point, except for radii */
+
+	/* l dx dy:	line from here by dx,dy */
+	/* c x:		circle of diameter x, left side here */
+	/* e x y:	ellipse of diameters x,y, left side here */
+	/* a dx1 dy1 dx2 dy2:
+			ccw arc: ctr at dx1,dy1, then end at dx2,dy2 from there */
+	/* ~ dx1 dy1 dx2 dy2...:
+			spline to dx1,dy1 to dx2,dy2 ... */
+	/* b x c:
+			built-up character of type c, ht x */
+	/* f dx dy ...:	f is any other char:  like spline */
+
+	if (ismot(c = getch()))
+		return;
+	delim = cbits(c);
+	numerr.escarg = type = cbits(getch());
+	if (type == '~')	/* head off the .tr ~ problem */
+		type = 's';
+	for (i = 0; i < NPAIR ; i++) {
+		skip();
+		vflag = 0;
+		dfact = EM;
+		dx[i] = quant(atoi0(), HOR);
+		if (dx[i] > MAXMOT)
+			dx[i] = MAXMOT;
+		else if (dx[i] < -MAXMOT)
+			dx[i] = -MAXMOT;
+		skip();
+		if (type == 'c') {
+			dy[i] = 0;
+			goto eat;
+		}
+		vflag = 1;
+		dfact = lss;
+		dy[i] = quant(atoi0(), VERT);
+		if (dy[i] > MAXMOT)
+			dy[i] = MAXMOT;
+		else if (dy[i] < -MAXMOT)
+			dy[i] = -MAXMOT;
+eat:
+		if (cbits(c = getch()) != ' ') {	/* must be the end */
+			if (cbits(c) != delim) {
+				drawch = cbits(c);
+				getch();
+			}
+			i++;
+			break;
+		}
+	}
+	dfact = 1;
+	vflag = 0;
+	if (TROFF) {
+		drawbuf[0] = DRAWFCN | chbits | ZBIT;
+		drawbuf[1] = type | chbits | ZBIT;
+		drawbuf[2] = drawch | chbits | ZBIT;
+		for (k = 0, j = 3; k < i; k++) {
+			drawbuf[j++] = MOT | ((dx[k] >= 0) ? dx[k] : (NMOT | -dx[k]));
+			drawbuf[j++] = MOT | VMOT | ((dy[k] >= 0) ? dy[k] : (NMOT | -dy[k]));
+		}
+		if (type == DRAWELLIPSE) {
+			drawbuf[5] = drawbuf[4] | NMOT;	/* so the net vertical is zero */
+			j = 6;
+		} else if (type == DRAWBUILD) {
+			drawbuf[4] = drawbuf[3] | NMOT;	/* net horizontal motion is zero */
+			drawbuf[2] &= ~ZBIT;		/* width taken from drawing char */
+			j = 5;
+		}
+		drawbuf[j++] = DRAWFCN | chbits | ZBIT;	/* marks end for ptout */
+		drawbuf[j] = 0;
+		pushback(drawbuf);
+	}
+}
+
+
+void casefc(void)
+{
+	int i;
+	Tchar j;
+
+	gchtab[fc] &= ~FCBIT;
+	fc = IMP;
+	padc = ' ';
+	if (skip() || ismot(j = getch()) || (i = cbits(j)) == '\n')
+		return;
+	fc = i;
+	gchtab[fc] |= FCBIT;
+	if (skip() || ismot(ch) || (ch = cbits(ch)) == fc)
+		return;
+	padc = ch;
+}
+
+
+Tchar setfield(int x)
+{
+	Tchar ii, jj, *fp;
+	int i, j;
+	int length, ws, npad, temp, type;
+	Tchar **pp, *padptr[NPP];
+	Tchar fbuf[FBUFSZ];
+	int savfc, savtc, savlc;
+	Tchar rchar;
+	int savepos;
+	static Tchar wbuf[] = { WORDSP, 0};
+
+	if (x == tabch) 
+		rchar = tabc | chbits;
+	else if (x ==  ldrch) 
+		rchar = dotc | chbits;
+	temp = npad = ws = 0;
+	savfc = fc;
+	savtc = tabch;
+	savlc = ldrch;
+	tabch = ldrch = fc = IMP;
+	savepos = numtabp[HP].val;
+	gchtab[tabch] &= ~TABBIT;
+	gchtab[ldrch] &= ~LDRBIT;
+	gchtab[fc] &= ~FCBIT;
+	gchtab[IMP] |= TABBIT|LDRBIT|FCBIT;
+	for (j = 0; ; j++) {
+		if ((tabtab[j] & TABMASK) == 0) {
+			if (x == savfc)
+				ERROR "zero field width." WARN;
+			jj = 0;
+			goto rtn;
+		}
+		if ((length = ((tabtab[j] & TABMASK) - numtabp[HP].val)) > 0 )
+			break;
+	}
+	type = tabtab[j] & ~TABMASK;
+	fp = fbuf;
+	pp = padptr;
+	if (x == savfc) {
+		while (1) {
+			j = cbits(ii = getch());
+			jj = width(ii);
+			widthp = jj;
+			numtabp[HP].val += jj;
+			if (j == padc) {
+				npad++;
+				*pp++ = fp;
+				if (pp > padptr + NPP - 1)
+					break;
+				goto s1;
+			} else if (j == savfc) 
+				break;
+			else if (j == '\n') {
+				temp = j;
+				if (nlflg && ip == 0) {
+					numtabp[CD].val--;
+					nlflg = 0;
+				}
+				break;
+			}
+			ws += jj;
+s1:
+			*fp++ = ii;
+			if (fp > fbuf + FBUFSZ - 3)
+				break;
+		}
+		if (ws)
+			*fp++ = WORDSP;
+		if (!npad) {
+			npad++;
+			*pp++ = fp;
+			*fp++ = 0;
+		}
+		*fp++ = temp;
+		*fp = 0;
+		temp = i = (j = length - ws) / npad;
+		i = (i / HOR) * HOR;
+		if ((j -= i * npad) < 0)
+			j = -j;
+		ii = makem(i);
+		if (temp < 0)
+			ii |= NMOT;
+		for (; npad > 0; npad--) {
+			*(*--pp) = ii;
+			if (j) {
+				j -= HOR;
+				(*(*pp)) += HOR;
+			}
+		}
+		pushback(fbuf);
+		jj = 0;
+	} else if (type == 0) {
+		/*plain tab or leader*/
+		if ((j = width(rchar)) > 0) {
+			int nchar = length / j;
+			while (nchar-->0 && pbp < &pbbuf[NC-3]) {
+				numtabp[HP].val += j;
+				widthp = j;
+				*pbp++ = rchar;
+			}
+			length %= j;
+		}
+		if (length)
+			jj = length | MOT;
+		else 
+			jj = getch0();
+		if (savepos > 0)
+			pushback(wbuf);
+	} else {
+		/*center tab*/
+		/*right tab*/
+		while ((j = cbits(ii = getch())) != savtc && j != '\n' && j != savlc) {
+			jj = width(ii);
+			ws += jj;
+			numtabp[HP].val += jj;
+			widthp = jj;
+			*fp++ = ii;
+			if (fp > fbuf + FBUFSZ - 3) 
+				break;
+		}
+		*fp++ = ii;
+		*fp = 0;
+		if (type == RTAB)
+			length -= ws;
+		else 
+			length -= ws / 2; /*CTAB*/
+		pushback(fbuf);
+		if ((j = width(rchar)) != 0 && length > 0) {
+			int nchar = length / j;
+			while (nchar-- > 0 && pbp < &pbbuf[NC-3])
+				*pbp++ = rchar;
+			length %= j;
+		}
+		if (savepos > 0)
+			pushback(wbuf);
+		length = (length / HOR) * HOR;
+		jj = makem(length);
+		if (nlflg) {
+			if (ip == 0)
+				numtabp[CD].val--;
+			nlflg = 0;
+		}
+	}
+rtn:
+	gchtab[fc] &= ~FCBIT;
+	gchtab[tabch] &= ~TABBIT;
+	gchtab[ldrch] &= ~LDRBIT;
+	fc = savfc;
+	tabch = savtc;
+	ldrch = savlc;
+	gchtab[fc] |= FCBIT;
+	gchtab[tabch] = TABBIT;
+	gchtab[ldrch] |= LDRBIT;
+	numtabp[HP].val = savepos;
+	return(jj);
+}
blob - /dev/null
blob + a80cec6437edd23dfd4e7ec144b8a0d061e126b7 (mode 644)
--- /dev/null
+++ src/cmd/troff/ni.c
@@ -0,0 +1,390 @@
+#include <stdio.h>
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+char	termtab[NS];	/* term type added in ptinit() */
+char	fontdir[NS];	/* added in casefp; not used by nroff */
+char	devname[20];	/* default output device */
+
+Numtab numtab[NN] = {
+	{ PAIR('%', 0) },
+	{ PAIR('n', 'l') },
+	{ PAIR('y', 'r') },
+	{ PAIR('h', 'p') },
+	{ PAIR('c', 't') },
+	{ PAIR('d', 'n') },
+	{ PAIR('m', 'o') },
+	{ PAIR('d', 'y') },
+	{ PAIR('d', 'w') },
+	{ PAIR('l', 'n') },
+	{ PAIR('d', 'l') },
+	{ PAIR('s', 't') },
+	{ PAIR('s', 'b') },
+	{ PAIR('c', '.') },
+	{ PAIR('$', '$') },
+};
+
+
+int	alphabet	= 256;	/* latin-1 */
+int	pto	= 10000;
+int	pfrom	= 1;
+int	print	= 1;
+char	nextf[NS]	= TMACDIR;
+char	mfiles[NMF][NS];
+int	nmfi	= 0;
+int	oldbits	= -1;
+int	init	= 1;
+int	fc	= IMP;	/* field character */
+int	eschar	= '\\';
+int	pl;
+int	po;
+FILE	*ptid;
+
+int	dfact	= 1;
+int	dfactd	= 1;
+int	res	= 1;
+int	smnt	= 0;	/* beginning of special fonts */
+int	ascii	= 0;	/* ascii normally off for troff, on for nroff;  -a turns on */
+int	lg;
+int	pnlist[NPN] = { -1 };
+
+
+int	*pnp	= pnlist;
+int	npn	= 1;
+int	npnflg	=  1;
+int	dpn	=  -1;
+int	totout	=  1;
+int	ulfont	=  ULFONT;
+int	tabch	=  TAB;
+int	ldrch	=  LEADER;
+
+
+Contab contab[NM] = {
+	C(PAIR('d', 's'), caseds),
+	C(PAIR('a', 's'), caseas),
+	C(PAIR('s', 'p'), casesp),
+	C(PAIR('f', 't'), caseft),
+	C(PAIR('p', 's'), caseps),
+	C(PAIR('v', 's'), casevs),
+	C(PAIR('n', 'r'), casenr),
+	C(PAIR('i', 'f'), caseif),
+	C(PAIR('i', 'e'), caseie),
+	C(PAIR('e', 'l'), caseel),
+	C(PAIR('p', 'o'), casepo),
+	C(PAIR('t', 'l'), casetl),
+	C(PAIR('t', 'm'), casetm),
+	C(PAIR('f', 'm'), casefm),
+	C(PAIR('b', 'p'), casebp),
+	C(PAIR('c', 'h'), casech),
+	C(PAIR('p', 'n'), casepn),
+	C(PAIR('b', 'r'), tbreak),
+	C(PAIR('t', 'i'), caseti),
+	C(PAIR('n', 'e'), casene),
+	C(PAIR('n', 'f'), casenf),
+	C(PAIR('c', 'e'), casece),
+	C(PAIR('f', 'i'), casefi),
+	C(PAIR('i', 'n'), casein),
+	C(PAIR('l', 'l'), casell),
+	C(PAIR('n', 's'), casens),
+	C(PAIR('m', 'k'), casemk),
+	C(PAIR('r', 't'), casert),
+	C(PAIR('a', 'm'), caseam),
+	C(PAIR('d', 'e'), casede),
+	C(PAIR('d', 'i'), casedi),
+	C(PAIR('d', 'a'), caseda),
+	C(PAIR('w', 'h'), casewh),
+	C(PAIR('d', 't'), casedt),
+	C(PAIR('i', 't'), caseit),
+	C(PAIR('r', 'm'), caserm),
+	C(PAIR('r', 'r'), caserr),
+	C(PAIR('r', 'n'), casern),
+	C(PAIR('a', 'd'), casead),
+	C(PAIR('r', 's'), casers),
+	C(PAIR('n', 'a'), casena),
+	C(PAIR('p', 'l'), casepl),
+	C(PAIR('t', 'a'), caseta),
+	C(PAIR('t', 'r'), casetr),
+	C(PAIR('u', 'l'), caseul),
+	C(PAIR('c', 'u'), casecu),
+	C(PAIR('l', 't'), caselt),
+	C(PAIR('n', 'x'), casenx),
+	C(PAIR('s', 'o'), caseso),
+	C(PAIR('i', 'g'), caseig),
+	C(PAIR('t', 'c'), casetc),
+	C(PAIR('f', 'c'), casefc),
+	C(PAIR('e', 'c'), caseec),
+	C(PAIR('e', 'o'), caseeo),
+	C(PAIR('l', 'c'), caselc),
+	C(PAIR('e', 'v'), caseev),
+	C(PAIR('r', 'd'), caserd),
+	C(PAIR('a', 'b'), caseab),
+	C(PAIR('f', 'l'), casefl),
+	C(PAIR('e', 'x'), caseex),
+	C(PAIR('s', 's'), casess),
+	C(PAIR('f', 'p'), casefp),
+	C(PAIR('c', 's'), casecs),
+	C(PAIR('b', 'd'), casebd),
+	C(PAIR('l', 'g'), caselg),
+	C(PAIR('h', 'c'), casehc),
+	C(PAIR('h', 'y'), casehy),
+	C(PAIR('n', 'h'), casenh),
+	C(PAIR('n', 'm'), casenm),
+	C(PAIR('n', 'n'), casenn),
+	C(PAIR('s', 'v'), casesv),
+	C(PAIR('o', 's'), caseos),
+	C(PAIR('l', 's'), casels),
+	C(PAIR('c', 'c'), casecc),
+	C(PAIR('c', '2'), casec2),
+	C(PAIR('e', 'm'), caseem),
+	C(PAIR('a', 'f'), caseaf),
+	C(PAIR('h', 'a'), caseha),
+	C(PAIR('h', 'w'), casehw),
+	C(PAIR('m', 'c'), casemc),
+	C(PAIR('p', 'm'), casepm),
+	C(PAIR('p', 'i'), casepi),
+	C(PAIR('u', 'f'), caseuf),
+	C(PAIR('p', 'c'), casepc),
+	C(PAIR('h', 't'), caseht),
+	C(PAIR('c', 'f'), casecf),
+	C(PAIR('s', 'y'), casesy),
+	C(PAIR('l', 'f'), caself),
+	C(PAIR('p', 't'), casept),
+	C(PAIR('g', 'd'), casegd),
+};
+
+
+Tbuf _oline;
+
+/*
+ * troff environment block
+ */
+
+Env env[NEV] = { {	/* this sets up env[0] */
+/* int	ics	 */	0,	/* insertion character space, set by .mc */
+/* int	sps	 */	0,
+/* int	spacesz	 */	0,
+/* int	lss	 */	0,
+/* int	lss1	 */	0,
+/* int	ll	 */	0,
+/* int	ll1	 */	0,
+/* int	lt	 */	0,
+/* int	lt1	 */	0,
+/* Tchar ic	 */	0,	/* insertion character (= margin character) */
+/* int	icf	 */	0,	/* insertion character flag */
+/* Tchar chbits	 */	0,	/* size+font bits for current character */
+/* Tchar spbits	 */	0,
+/* Tchar nmbits	 */	0,	/* size+font bits for number from .nm */
+/* int	apts	 */	PS,	/* actual point size -- as requested by user */
+/* int	apts1	 */	PS,	/* need not match an existent size */
+/* int	pts	 */	PS,	/* hence, this is the size that really exists */
+/* int	pts1	 */	PS,
+/* int	font	 */	FT,
+/* int	font1	 */	FT,
+/* int	ls	 */	1,
+/* int	ls1	 */	1,
+/* int	ad	 */	1,
+/* int	nms	 */	1,	/* .nm multiplier */
+/* int	ndf	 */	1,	/* .nm separator */
+/* int	nmwid	 */	3,	/* max width of .nm numbers */
+/* int	fi	 */	1,
+/* int	cc	 */	'.',
+/* int	c2	 */	'\'',
+/* int	ohc	 */	OHC,
+/* int	tdelim	 */	IMP,
+/* int	hyf	 */	1,
+/* int	hyoff	 */	0,
+/* int	hyphalg  */	HYPHALG,
+/* int	un1	 */	-1,
+/* int	tabc	 */	0,
+/* int	dotc	 */	'.',
+/* int	adsp	 */	0,	/* add this much space to each padding point */
+/* int	adrem	 */	0,	/* excess space to add until it runs out */
+/* int	lastl	 */	0,	/* last text on current output line */
+/* int	nel	 */	0,	/* how much space left on current output line */
+/* int	admod	 */	0,	/* adjust mode */
+/* Tchar *wordp	 */	0,
+/* int	spflg	 */	0,	/* probably to indicate space after punctuation needed */
+/* Tchar *linep	 */	0,
+/* Tchar *wdend	 */	0,
+/* Tchar *wdstart */	0,
+/* int	wne	 */	0,
+/* int	ne	 */	0,	/* how much space taken on current output line */
+/* int	nc	 */	0,	/* #characters (incl blank) on output line */
+/* int	nb	 */	0,
+/* int	lnmod	 */	0,	/* line number mode, set by .nm */
+/* int	nwd	 */	0,	/* number of words on current output line */
+/* int	nn	 */	0,	/* from .nn command */
+/* int	ni	 */	0,	/* indent of .nm numbers, probably */
+/* int	ul	 */	0,
+/* int	cu	 */	0,
+/* int	ce	 */	0,
+/* int	in	 */	0,	/* indent and previous value */
+/* int	in1	 */	0,
+/* int	un	 */	0,	/* unindent of left margin in some way */
+/* int	wch	 */	0,
+/* int	pendt	 */	0,
+/* Tchar *pendw	 */	(Tchar *)0,
+/* int	pendnf	 */	0,
+/* int	spread	 */	0,
+/* int	it	 */	0,	/* input trap count */
+/* int	itmac	 */	0,
+} };
+
+Env	*envp	= env;	/* start off in env 0 */
+
+Numerr	numerr;
+
+Stack	*frame, *stk, *ejl;
+Stack	*nxf;
+
+int	pipeflg;
+int	hflg;	/* used in nroff only */
+int	eqflg;	/* used in nroff only */
+
+int	xpts;
+int	ppts;
+int	pfont;
+int	mpts;
+int	mfont;
+int	cs;
+int	ccs;
+int	bd;
+
+int	stdi;
+int	quiet;
+int	stop;
+char	ibuf[IBUFSZ];
+char	xbuf[IBUFSZ];
+char	*ibufp;
+char	*xbufp;
+char	*eibuf;
+char	*xeibuf;
+Tchar	pbbuf[NC];		/* pushback buffer for arguments, \n, etc. */
+Tchar	*pbp = pbbuf;		/* next free slot in pbbuf */
+Tchar	*lastpbp = pbbuf;	/* pbp in previous stack frame */
+int	nx;
+int	mflg;
+Tchar	ch = 0;
+int	ibf;
+int	ifi;
+int	iflg;
+int	rargc;
+char	**argp;
+Ushort	trtab[NTRTAB];
+int	lgf;
+int	copyf;
+Offset	ip;
+int	nlflg;
+int	donef;
+int	nflush;
+int	nfo;
+int	padc;
+int	raw;
+int	flss;
+int	nonumb;
+int	trap;
+int	tflg;
+int	ejf;
+int	dilev;
+Offset	offset;
+int	em;
+int	ds;
+Offset	woff;
+int	app;
+int	ndone;
+int	lead;
+int	ralss;
+Offset	nextb;
+Tchar	nrbits;
+int	nform;
+int	oldmn;
+int	newmn;
+int	macerr;
+Offset	apptr;
+int	diflg;
+int	evi;
+int	vflag;
+int	noscale;
+int	po1;
+int	nlist[NTRAP];
+int	mlist[NTRAP];
+int	evlist[EVLSZ];
+int	ev;
+int	tty;
+int	sfont	= FT;	/* appears to be "standard" font; used by .ul */
+int	sv;
+int	esc;
+int	widthp;
+int	xfont;
+int	setwdf;
+int	over;
+int	nhyp;
+Tchar	**hyp;
+Tchar	*olinep;
+int	dotT;
+char	*unlkp;
+Wcache	widcache[NWIDCACHE];
+Diver	d[NDI];
+Diver	*dip;
+
+int	c_hyphen;
+int	c_emdash;
+int	c_rule;
+int	c_minus;
+int	c_fi;
+int	c_fl;
+int	c_ff;
+int	c_ffi;
+int	c_ffl;
+int	c_acute;
+int	c_grave;
+int	c_under;
+int	c_rooten;
+int	c_boxrule;
+int	c_lefthand;
+int	c_dagger;
+int	c_isalnum;
+
+Spnames	spnames[] =
+{
+	&c_hyphen,	"hy",
+	&c_emdash,	"em",
+	&c_rule,	"ru",
+	&c_minus,	"\\-",
+	&c_fi,		"fi",
+	&c_fl,		"fl",
+	&c_ff,		"ff",
+	&c_ffi,		"Fi",
+	&c_ffl,		"Fl",
+	&c_acute,	"aa",
+	&c_grave,	"ga",
+	&c_under,	"ul",
+	&c_rooten,	"rn",
+	&c_boxrule,	"br",
+	&c_lefthand,	"lh",
+	&c_dagger,	"dg",	/* not in nroff?? */
+	&c_isalnum,	"__",
+	0, 0
+};
+
+
+Tchar	(*hmot)(void);
+Tchar	(*makem)(int i);
+Tchar	(*setabs)(void);
+Tchar	(*setch)(int c);
+Tchar	(*sethl)(int k);
+Tchar	(*setht)(void);
+Tchar	(*setslant)(void);
+Tchar	(*vmot)(void);
+Tchar	(*xlss)(void);
+int	(*findft)(int i);
+int	(*width)(Tchar j);
+void	(*mchbits)(void);
+void	(*ptlead)(void);
+void	(*ptout)(Tchar i);
+void	(*ptpause)(void);
+void	(*setfont)(int a);
+void	(*setps)(void);
+void	(*setwd)(void);
+
blob - /dev/null
blob + 1aa8a009b7a6671bb1e25ae76119285ed6a88b74 (mode 644)
--- /dev/null
+++ src/cmd/troff/suftab.c
@@ -0,0 +1,612 @@
+/*
+ * Suffix table
+ */
+
+typedef unsigned char Uchar;
+
+static	Uchar sufa[] = {
+	02,0200+'t',	/* -TA */
+	02,0200+'s',	/* -SA */
+	03,0200+'t','r',	/* -TRA */
+	03,0200+'d','r',	/* -DRA */
+	03,0200+'b','r',	/* -BRA */
+	02,0200+'p',	/* -PA */
+	02,0200+'n',	/* -NA */
+	02,0200+'m',	/* -MA */
+	03,0200+'p','l',	/* -PLA */
+	02,0200+'l',	/* -LA */
+	02,0200+'k',	/* -KA */
+	03,0200+'t','h',	/* -THA */
+	03,0200+'s','h',	/* -SHA */
+	02,0200+'g',	/* -GA */
+	02,0200+'d',	/* -DA */
+	02,0200+'c',	/* -CA */
+	02,0200+'b',	/* -BA */
+	00
+};
+
+static	Uchar sufc[] = {
+	04,'e','t',0200+'i',	/* ET-IC */
+	07,'a','l',0200+'i','s',0200+'t','i',	/* AL-IS-TIC */
+	04,'s',0200+'t','i',	/* S-TIC */
+	04,'p',0200+'t','i',	/* P-TIC */
+	05,0200+'l','y','t',0200+'i',	/* -LYT-IC */
+	04,'o','t',0200+'i',	/* OT-IC */
+	05,'a','n',0200+'t','i',	/* AN-TIC */
+	04,'n',0200+'t','i',	/* N-TIC */
+	04,'c',0200+'t','i',	/* C-TIC */
+	04,'a','t',0200+'i',	/* AT-IC */
+	04,'h',0200+'n','i',	/* H-NIC */
+	03,'n',0200+'i',	/* N-IC */
+	03,'m',0200+'i',	/* M-IC */
+	04,'l',0200+'l','i',	/* L-LIC */
+	04,'b',0200+'l','i',	/* B-LIC */
+	04,0200+'c','l','i',	/* -CLIC */
+	03,'l',0200+'i',	/* L-IC */
+	03,'h',0200+'i',	/* H-IC */
+	03,'f',0200+'i',	/* F-IC */
+	03,'d',0200+'i',	/* D-IC */
+	03,0200+'b','i',	/* -BIC */
+	03,'a',0200+'i',	/* A-IC */
+	03,0200+'m','a',	/* -MAC */
+	03,'i',0200+'a',	/* I-AC */
+	00
+};
+
+static	Uchar sufd[] = {
+	04,0200+'w','o','r',	/* -WORD */
+	04,0200+'l','o','r',	/* -LORD */
+	04,0200+'f','o','r',	/* -FORD */
+	04,0200+'y','a','r',	/* -YARD */
+	04,0200+'w','a','r',	/* -WARD */
+	05,0200+'g','u','a','r',	/* -GUARD */
+	04,0200+'t','a','r',	/* -TARD */
+	05,0200+'b','o','a','r',	/* -BOARD */
+	04,0200+'n','a','r',	/* -NARD */
+	05,0200+'l','i','a','r',	/* -LIARD */
+	04,0200+'i','a','r',	/* -IARD */
+	04,0200+'g','a','r',	/* -GARD */
+	04,0200+'b','a','r',	/* -BARD */
+	03,0200+'r','o',	/* -ROD */
+	04,0200+'w','o','o',	/* -WOOD */
+	04,0200+'h','o','o',	/* -HOOD */
+	04,0200+'m','o','n',	/* -MOND */
+	04,0200+'t','e','n',	/* -TEND */
+	05,0200+'s','t','a','n',	/* -STAND */
+	04,0200+'l','a','n',	/* -LAND */
+	04,0200+'h','a','n',	/* -HAND */
+	04,0200+'h','o','l',	/* -HOLD */
+	04,0200+'f','o','l',	/* -FOLD */
+	05,0200+'f','i','e','l',	/* -FIELD */
+	03,0200+'v','i',	/* -VID */
+	03,0200+'c','i',	/* -CID */
+	04,0200+'s','a','i',	/* -SAID */
+	04,0200+'m','a','i',	/* -MAID */
+	04,'t',0200+'t','e',	/* T-TED */
+	03,'t',0200+'e',	/* T-ED */
+	04,0200+'d','r','e',	/* -DRED */
+	04,0200+'c','r','e',	/* -CRED */
+	04,0200+'b','r','e',	/* -BRED */
+	05,'v',0200+'e','l','e',	/* V-ELED */
+	0100+04,'a','l',0200+'e',	/* AL/ED */
+	0140+03,0200+'e','e',	/* /EED */
+	040+05,'e','d',0200+'d','e',	/* ED-DED */
+	04,'d',0200+'d','e',	/* D-DED */
+	040+04,'e','d',0200+'e',	/* ED-ED */
+	03,'d',0200+'e',	/* D-ED */
+	05,0200+'d','u','c','e',	/* -DUCED */
+	0300+02,'e',	/* E/D */
+	05,0200+'s','t','e','a',	/* -STEAD */
+	05,0200+'a','h','e','a',	/* -AHEAD */
+	04,0200+'h','e','a',	/* -HEAD */
+	00
+};
+
+static	Uchar sufe[] = {
+	05,'a','r',0200+'i','z',	/* AR-IZE */
+	05,'a','n',0200+'i','z',	/* AN-IZE */
+	05,'a','l',0200+'i','z',	/* AL-IZE */
+	06,0200+'a','r','d',0200+'i','z',	/* -ARD-IZE */
+	05,0200+'s','e','l','v',	/* -SELVE */
+	05,0200+'k','n','i','v',	/* -KNIVE */
+	05,0200+'l','i','e','v',	/* -LIEVE */
+	0100+03,0200+'q','u',	/* /QUE */
+	07,'o','n',0200+'t','i','n',0200+'u',	/* ON-TIN-UE */
+	03,0200+'n','u',	/* -NUE */
+	03,0200+'d','u',	/* -DUE */
+	0300+02,'u',	/* U/E */
+	0300+05,'q','u','a','t',	/*  QUAT/E */
+	04,'u',0200+'a','t',	/* U-ATE */
+	05,0200+'s','t','a','t',	/* -STATE */
+	04,0200+'t','a','t',	/* -TATE */
+	06,0200+'t','o','r',0200+'a','t',	/* -TOR-ATE */
+	05,'e','n',0200+'a','t',	/* EN-ATE */
+	04,0200+'m','a','t',	/* -MATE */
+	05,0200+'h','o','u','s',	/* -HOUSE */
+	05,0200+'c','l','o','s',	/* -CLOSE */
+	04,'i',0200+'o','s',	/* I-OSE */
+	04,0200+'w','i','s',	/* -WISE */
+	05,'a','s',0200+'u','r',	/* AS-URE */
+	040+04,0200+'s','u','r',	/* -SURE */
+	06,0200+'f','i','g',0200+'u','r',	/* -FIG-URE */
+	040+03,0200+'t','r',	/* -TRE */
+	05,0200+'s','t','o','r',	/* -STORE */
+	04,0200+'f','o','r',	/* -FORE */
+	05,0200+'w','h','e','r',	/* -WHERE */
+	06,0200+'s','p','h','e','r',	/* -SPHERE */
+	03,0200+'d','r',	/* -DRE */
+	03,0200+'c','r',	/* -CRE */
+	03,0200+'b','r',	/* -BRE */
+	05,0200+'s','c','o','p',	/* -SCOPE */
+	04,'y',0200+'o','n',	/* Y-ONE */
+	05,0200+'s','t','o','n',	/* -STONE */
+	05,0200+'p','h','o','n',	/* -PHONE */
+	04,0200+'g','o','n',	/* -GONE */
+	04,'e',0200+'o','n',	/* E-ONE */
+	040+04,0200+'e','n','n',	/* -ENNE */
+	040+05,'a',0200+'r','i','n',	/* A-RINE */
+	05,0200+'c','l','i','n',	/* -CLINE */
+	04,0200+'l','i','n',	/* -LINE */
+	007,00200+'r','o','u',00200+'t','i','n',	/*-ROU-TINE */
+	04,0200+'s','o','m',	/* -SOME */
+	04,0200+'c','o','m',	/* -COME */
+	04,0200+'t','i','m',	/* -TIME */
+	03,0200+'z','l',	/* -ZLE */
+	03,0200+'t','l',	/* -TLE */
+	03,0200+'s','l',	/* -SLE */
+	03,0200+'p','l',	/* -PLE */
+	05,0200+'v','i','l','l',	/* -VILLE */
+	04,'c','k',0200+'l',	/* CK-LE */
+	03,0200+'k','l',	/* -KLE */
+	03,0200+'g','l',	/* -GLE */
+	03,0200+'f','l',	/* -FLE */
+	03,0200+'d','l',	/* -DLE */
+	03,0200+'c','l',	/* -CLE */
+	05,0200+'p','a',0200+'b','l',	/* -PA-BLE */
+	05,'f','a',0200+'b','l',	/* FA-BLE */
+	05,0200+'c','a',0200+'b','l',	/* -CA-BLE */
+	06,0200+'s','t','a','b','l',	/* -STABLE */
+	04,0200+'a','b','l',	/* -ABLE */
+	03,0200+'b','l',	/* -BLE */
+	04,0200+'d','a','l',	/* -DALE */
+	04,0200+'m','a','l',	/* -MALE */
+	04,0200+'s','a','l',	/* -SALE */
+	04,0200+'l','i','k',	/* -LIKE */
+	0340+05,'g',0200+'u','a','g',	/* -G/UAGE */
+	05,0200+'r','i','a','g',	/* -RIAGE */
+	05,'e','r',0200+'a','g',	/* ER-AGE */
+	04,'m',0200+'a','g',	/* M-AGE */
+	04,'k',0200+'a','g',	/* K-AGE */
+	04,'d',0200+'a','g',	/* D-AGE */
+	04,0200+'w','i','f',	/* -WIFE */
+	05,0200+'k','n','i','f',	/* -KNIFE */
+	03,0200+'s','e',	/* -SEE */
+	04,0200+'f','r','e',	/* -FREE */
+	0340+02,'e',	/* EE */
+	04,0200+'w','i','d',	/* -WIDE */
+	04,0200+'t','i','d',	/* -TIDE */
+	04,0200+'s','i','d',	/* -SIDE */
+	06,0200+'q','u','e','n','c',	/* -QUENCE */
+	07,0200+'f','l','u',0200+'e','n','c',	/* -FLU-ENCE */
+	040+06,'e','s',0200+'e','n','c',	/* ES-ENCE */
+	06,'e','r',0200+'e','n','c',	/* ER-ENCE */
+	05,'i',0200+'e','n','c',	/* I-ENCE */
+	040+05,0200+'s','a','n','c',	/* -SANCE */
+	06,'e','r',0200+'a','n','c',	/* ER-ANCE */
+	06,'a','r',0200+'a','n','c',	/* AR-ANCE */
+	05,0200+'n','a','n','c',	/* -NANCE */
+	07,0200+'b','a','l',0200+'a','n','c',	/* -BAL-ANCE */
+	05,'i',0200+'a','n','c',	/* I-ANCE */
+	07,0200+'j','u','s',0200+'t','i','c',	/* -JUS-TICE */
+	05,0200+'s','t','i','c',	/* -STICE */
+	06,0200+'n','o','v',0200+'i','c',	/* NOV-ICE */
+	04,0200+'v','i','c',	/* -VICE */
+	05,0200+'p','i','e','c',	/* -PIECE */
+	05,0200+'p','l','a','c',	/* -PLACE */
+	0340+01,	/* /E */
+	00
+};
+
+static	Uchar suff[] = {
+	03,0200+'o','f',	/* -OFF */
+	05,0200+'p','r','o','o',	/* -PROOF */
+	04,0200+'s','e','l',	/* -SELF */
+	03,0200+'r','i',	/* -RIF */
+	040+04,0200+'l','i','e',	/* -LIEF */
+	00
+};
+
+static	Uchar sufg[] = {
+	03,0200+'l','o',	/* -LOG */
+	04,0200+'l','o','n',	/* -LONG */
+	05,'t',0200+'t','i','n',	/* T-TING */
+	06,0200+'s','t','r','i','n',	/*  -STRING */
+	05,'r',0200+'r','i','n',	/* R-RING */
+	05,'p',0200+'p','i','n',	/* P-PING */
+	05,'n',0200+'n','i','n',	/* N-NING */
+	05,'m',0200+'m','i','n',	/* M-MING */
+	05,'l',0200+'l','i','n',	/*  L-LING */
+	05,0200+'z','l','i','n',	/* -ZLING */
+	05,0200+'t','l','i','n',	/* -TLING */
+	040+05,'s',0200+'l','i','n',	/* S-LING */
+	05,'r',0200+'l','i','n',	/* R-LING */
+	05,0200+'p','l','i','n',	/* -PLING */
+	06,'n',0200+'k','l','i','n',	/* N-KLING */
+	05,'k',0200+'l','i','n',	/* K-LING */
+	05,0200+'g','l','i','n',	/* -GLING */
+	05,0200+'f','l','i','n',	/* -FLING */
+	05,0200+'d','l','i','n',	/* -DLING */
+	05,0200+'c','l','i','n',	/* -CLING */
+	05,0200+'b','l','i','n',	/* -BLING */
+	06,'y',0200+'t','h','i','n',	/* Y-THING */
+	07,'e','e','t','h',0200+'i','n',	/* EETH-ING */
+	06,'e',0200+'t','h','i','n',	/* E-THING */
+	05,'g',0200+'g','i','n',	/* G-GING */
+	05,'d',0200+'d','i','n',	/* D-DING */
+	05,'b',0200+'b','i','n',	/* B-BING */
+	03,0200+'i','n',	/* -ING */
+	00
+};
+
+static	Uchar sufh[] = {
+	05,0200+'m','o','u','t',	/* -MOUTH */
+	05,0200+'w','o','r','t',	/* -WORTH */
+	04,0200+'w','i','t',	/* -WITH */
+	05,'t',0200+'t','i','s',	/* T-TISH */
+	05,'e',0200+'t','i','s',	/* E-TISH */
+	05,'p',0200+'p','i','s',	/* P-PISH */
+	05,'r',0200+'n','i','s',	/* R-NISH */
+	05,'n',0200+'n','i','s',	/* N-NISH */
+	05,0200+'p','l','i','s',	/* -PLISH */
+	05,0200+'g','u','i','s',	/*  -GUISH */
+	05,0200+'g','l','i','s',	/*  -GLISH */
+	05,'b',0200+'l','i','s',	/*  B-LISH */
+	05,'g',0200+'g','i','s',	/* G-GISH */
+	05,'d',0200+'d','i','s',	/* D-DISH */
+	03,0200+'i','s',	/* -ISH */
+	05,0200+'g','r','a','p',	/* -GRAPH */
+	07,0200+'b','o','r',0200+'o','u','g',	/* -BOR-OUGH */
+	05,0200+'b','u','r','g',	/* -BURGH */
+	04,0200+'v','i','c',	/* -VICH */
+	03,0200+'n','a',	/* -NAH */
+	03,0200+'l','a',	/* -LAH */
+	04,0200+'m','i',0200+'a',	/* -MI-AH */
+	00
+};
+
+static	Uchar sufi[] = {
+	03,0200+'t','r',	/* -TRI */
+	03,0200+'c','h',	/* -CHI */
+	0200+03,'i','f',	/* IF-I */
+	0200+03,'e','d',	/* ED-I */
+	05,0200+'a','s','c','i',	/* -ASCII */
+	04,0200+'s','e','m',	/* -SEMI */
+	00
+};
+
+static	Uchar sufk[] = {
+	04,0200+'w','o','r',	/* -WORK */
+	04,0200+'m','a','r',	/* -MARK */
+	04,0200+'b','o','o',	/* -BOOK */
+	04,0200+'w','a','l',	/* -WALK */
+	05,0200+'c','r','a','c',	/* -CRACK */
+	04,0200+'b','a','c',	/* -BACK */
+	00
+};
+
+static	Uchar sufl[] = {
+	03,0200+'f','u',	/* -FUL */
+	05,'s',0200+'w','e','l',	/* S-WELL */
+	04,0200+'t','e','l',	/* -TELL */
+	05,0200+'s','h','e','l',	/* -SHELL */
+	05,0200+'s','t','a','l',	/* -STALL */
+	04,'s',0200+'t','a',	/* S-TAL */
+	04,0200+'b','a','l',	/* -BALL */
+	04,0200+'c','a','l',	/* -CALL */
+	03,'v',0200+'e',	/* V-EL */
+	03,'u',0200+'e',	/* U-EL */
+	03,'k',0200+'e',	/* K-EL */
+	04,'t','h',0200+'e',	/* TH-EL */
+	05,'t','c','h',0200+'e',	/* TCH-EL */
+	03,'a',0200+'e',	/* A-EL */
+	0140+04,0200+'q','u','a',	/* /QUAL */
+	040+03,'u',0200+'a',	/* U-AL */
+	03,0200+'t','a',	/* -TAL */
+	04,'u','r',0200+'a',	/* UR-AL */
+	040+05,'g',0200+'o',0200+'n','a',	/* G-O-NAL */
+	04,'o','n',0200+'a',	/* ON-AL */
+	03,0200+'n','a',	/* -NAL */
+	04,0200+'t','i','a',	/* -TIAL */
+	04,0200+'s','i','a',	/* -SIAL */
+	040+05,0200+'t','r','i',0200+'a',	/* -TRI-AL */
+	04,'r','i',0200+'a',	/* RI-AL */
+	04,0200+'n','i',0200+'a',	/* -NI-AL */
+	04,0200+'d','i',0200+'a',	/* -DI-AL */
+	04,0200+'c','i','a',	/* -CIAL */
+	03,0200+'g','a',	/* -GAL */
+	04,0200+'m','e','a',	/* -MEAL */
+/*	040+04,0200+'r','e',0200+'a',	/* -RE-AL */
+	040+04,0200+'r','e','a',	/* -REAL */
+	06,'c',0200+'t','i',0200+'c','a',	/* C-TI-CAL */
+	05,0200+'s','i',0200+'c','a',	/* -SI-CAL */
+	04,0200+'i',0200+'c','a',	/* -I-CAL */
+	03,0200+'c','a',	/* -CAL */
+	03,0200+'b','a',	/* -BAL */
+	06,0200+'n','o',0200+'m','i',0200+'a',	/* -NO-MI-AL */
+	00
+};
+
+static	Uchar sufm[] = {
+	03,0200+'n','u',	/* -NUM */
+	05,'o',0200+'r','i',0200+'u',	/* O-RI-UM */
+	040+03,'i',0200+'u',	/* I-UM */
+	040+03,'e',0200+'u',	/* E-UM */
+	05,'i','v',0200+'i','s',	/* IV-ISM */
+	04,0200+'t','i','s',	/* -TISM */
+	05,'i',0200+'m','i','s',	/* I-MISM */
+	05,'a','l',0200+'i','s',	/* AL-ISM */
+	040+04,'e',0200+'i','s',	/* E-ISM */
+	040+04,'a',0200+'i','s',	/* A-ISM */
+	04,0200+'r','o','o',	/* -ROOM */
+	03,0200+'d','o',	/* -DOM */
+	03,0200+'h','a',	/* -HAM */
+	06,0200+'a',0200+'r','i','t','h',	/* -A-RITHM */
+	05,0200+'r','i','t','h',	/* -RITHM */
+	00
+};
+
+static	Uchar sufn[] = {
+	05,0200+'k','n','o','w', /* -KNOWN */
+	04,0200+'t','o','w',	/* -TOWN */
+	04,0200+'d','o','w',	/* -DOWN */
+	04,0200+'t','u','r',	/* -TURN */
+	05,0200+'s','p','o','o',	/* -SPOON */
+	04,0200+'n','o','o',	/* -NOON */
+	04,0200+'m','o','o',	/* -MOON */
+	011,'a','l',0200+'i',0200+'z','a',0200+'t','i','o',	/* AL-I-ZA-TION */
+	07,0200+'i',0200+'z','a',0200+'t','i','o',	/* -I-ZA-TION */
+	07,'l',0200+'i',0200+'a',0200+'t','i','o',	/* L-I-A-TION */
+	04,0200+'t','i','o',	/* -TION */
+	040+05,'s',0200+'s','i','o',	/* S-SION */
+	04,0200+'s','i','o',	/* -SION */
+	04,'n',0200+'i','o',	/* N-ION */
+	04,0200+'g','i','o',	/* -GION */
+	04,0200+'c','i','o',	/* -CION */
+	03,0200+'c','o',	/* -CON */
+	05,0200+'c','o','l','o',	/* -COLON */
+	03,0200+'t','o',	/* -TON */
+	04,'i','s',0200+'o',		/* IS-ON */
+	03,0200+'s','o',	/* -SON */
+	03,0200+'r','i',	/* -RIN */
+	03,0200+'p','i',	/* -PIN */
+	03,0200+'n','i',	/* -NIN */
+	03,0200+'m','i',	/* -MIN */
+	03,0200+'l','i',	/* -LIN */
+	03,0200+'k','i',	/* -KIN */
+	05,0200+'s','t','e','i',	/* -STEIN */
+	04,0200+'t','a','i',	/* -TAIN */
+	05,'g','h','t',0200+'e',	/* GHT-EN */
+	05,0200+'w','o','m',0200+'e',	/* -WOM-EN */
+	03,0200+'m','e',	/* -MEN */
+	04,'o',0200+'k','e',	/* O-KEN */
+	03,'k',0200+'e',	/* K-EN */
+	04,0200+'t','e','e',	/* -TEEN */
+	04,0200+'s','e','e',	/* -SEEN */
+	040+03,0200+'s','a',	/* -SAN */
+	05,0200+'w','o','m',0200+'a',	/* -WOM-AN */
+	03,0200+'m','a',	/* -MAN */
+	04,0200+'t','i','a',	/* -TIAN */
+	04,0200+'s','i','a',	/* -SIAN */
+	040+04,'e',0200+'i','a',	/* E-IAN */
+	04,0200+'c','i','a',	/* -CIAN */
+	0300+03,'i','a',	/* IA/N */
+	05,0200+'c','l','e','a',	/* -CLEAN */
+	04,0200+'m','e','a',	/* -MEAN */
+	040+03,'e',0200+'a',	/* E-AN */
+	00
+};
+
+static	Uchar sufo[] = {
+	05,0200+'m','a','c',0200+'r',	/* -MAC-RO */
+	00
+};
+
+static	Uchar sufp[] = {
+	05,0200+'g','r','o','u',	/* -GROUP */
+	02,0200+'u',	/* -UP */
+	04,0200+'s','h','i',	/* -SHIP */
+	04,0200+'k','e','e',	/* -KEEP */
+	00
+};
+
+static	Uchar sufr[] = {
+	04,0200+'z','a','r',	/* -ZARR */
+	0300+02,'r',	/* R/R */
+	03,0200+'t','o',	/* -TOR */
+	040+03,0200+'s','o',	/* -SOR */
+	040+04,0200+'r','i',0200+'o',	/* -RI-OR */
+	04,'i','z',0200+'e',	/* IZ-ER */
+	05,0200+'c','o','v',0200+'e',	/* -COV-ER */
+	04,0200+'o','v','e',	/* -OVER */
+	04,0200+'e','v',0200+'e',	/* -EV-ER */
+	8,0200+'c','o','m',0200+'p','u','t',0200+'e',	/* -COM-PUT-ER */
+	040+05,'u','s',0200+'t','e',	/* US-TER */
+	05,'o','s','t',0200+'e',	/* OST-ER */
+	040+05,0200+'a','c',0200+'t','e',	/* -AC-TER */
+	06,0200+'w','r','i','t',0200+'e',	/* -WRIT-ER */
+	040+05,'i','s',0200+'t','e',	/* IS-TER */
+	040+05,'e','s',0200+'t','e',	/* ES-TER */
+	040+05,'a','s',0200+'t','e',	/* AS-TER */
+	04,0200+'s','t','e',	/* -STER */
+	05,'a','r',0200+'t','e',	/* AR-TER */
+	04,'r','t',0200+'e',	/* RT-ER */
+	040+05,'m',0200+'e',0200+'t','e',	/* M-E-TER */
+	05,0200+'w','a',0200+'t','e',	/* -WA-TER */
+	03,'r',0200+'e',	/* R-ER */
+	04,'o','p',0200+'e',	/* OP-ER */
+	05,0200+'p','a',0200+'p','e',	/* -PA-PER */
+	04,'w','n',0200+'e',	/* WN-ER */
+	040+04,'s',0200+'n','e',	/* S-NER */
+	04,'o','n',0200+'e',	/* ON-ER */
+	04,'r','m',0200+'e',	/* RM-ER */
+	03,0200+'m','e',	/* -MER */
+	04,'l','l',0200+'e',	/* LL-ER */
+	05,'d',0200+'d','l','e',	/* D-DLER */
+	04,0200+'b','l','e',	/* -BLER */
+	03,'k',0200+'e',	/* K-ER */
+	05,'n',0200+'t','h','e',	/* N-THER */
+	06,0200+'f','a',0200+'t','h','e',	/* -FA-THER */
+	06,'e','i',0200+'t','h','e',	/* EI-THER */
+	04,'t','h',0200+'e',	/* TH-ER */
+	04,'s','h',0200+'e',	/* SH-ER */
+	04,0200+'p','h','e',	/* -PHER */
+	04,'c','h',0200+'e',	/* CH-ER */
+	04,'d','g',0200+'e',	/* DG-ER */
+	04,'r','d',0200+'e',	/* RD-ER */
+	06,'o','u','n','d',0200+'e',	/* OUND-ER */
+	04,'l','d',0200+'e',	/* LD-ER */
+	04,'i','d',0200+'e',	/* ID-ER */
+	05,0200+'d','u','c',0200+'e',	/* -DUC-ER */
+	04,'n','c',0200+'e',	/* NC-ER */
+	0100+02, 0200+'e',	/*  /ER */
+	03,0200+'s','a',	/* -SAR */
+	040+06,'a','c',0200+'u',0200+'l','a',	/* AC-U-LAR */
+	040+06,'e','c',0200+'u',0200+'l','a',	/* EC-U-LAR */
+	040+06,'i','c',0200+'u',0200+'l','a',	/* IC-U-LAR */
+	040+06,'e','g',0200+'u',0200+'l','a',	/* EG-U-LAR */
+	00
+};
+
+static	Uchar sufs[] = {
+	040+04,'u',0200+'o','u',	/* U-OUS */
+	05,0200+'t','i','o','u',	/* -TIOUS */
+	05,0200+'g','i','o','u',	/* -GIOUS */
+	05,0200+'c','i','o','u',	/* -CIOUS */
+	040+04,'i',0200+'o','u',	/* I-OUS */
+	05,0200+'g','e','o','u',	/* -GEOUS */
+	05,0200+'c','e','o','u',	/* -CEOUS */
+	04,'e',0200+'o','u',	/* E-OUS */
+	0140+02,0200+'u',	/* /US */
+	04,0200+'n','e','s',	/* -NESS */
+	04,0200+'l','e','s',	/* -LESS */
+	0140+02,0200+'s',	/* /SS */
+	040+05,'p',0200+'o',0200+'l','i',	/* P-O-LIS */
+	0140+02,0200+'i',	/* /IS */
+	0100+03,0200+'x','e',	/* X/ES */
+	0100+03,0200+'s','e',	/* S/ES */
+	0100+04,'s','h',0200+'e',	/* SH/ES */
+	0100+04,'c','h',0200+'e',	/* CH/ES */
+	0300+01,	/* /S */
+	00
+};
+
+static	Uchar suft[] = {
+	05,0200+'l','i','m',0200+'i',	/* -LIM-IT */
+	06,'i','o','n',0200+'i','s',	/* ION-IST */
+	05,'i','n',0200+'i','s',	/* IN-IST */
+	05,'a','l',0200+'i','s',	/* AL-IST */
+	06,'l',0200+'o',0200+'g','i','s',	/* L-O-GIST */
+	05,'h','t',0200+'e','s',	/* HT-EST */
+	04,'i',0200+'e','s',	/* I-EST */
+	05,'g',0200+'g','e','s',	/* G-GEST */
+	04,'g',0200+'e','s',	/* G-EST */
+	05,'d',0200+'d','e','s',	/* D-DEST */
+	04,'d',0200+'e','s',	/* D-EST */
+	04,0200+'c','a','s',	/* -CAST */
+	05,0200+'h','e','a','r',	/* -HEART */
+	04,0200+'f','o','o',	/* -FOOT */
+	03,'i',0200+'o',	/* I-OT */
+	05,0200+'f','r','o','n',	/* -FRONT */
+	05,0200+'p','r','i','n',	/* -PRINT */
+	04,0200+'m','e','n',	/* -MENT */
+	05,0200+'c','i','e','n',	/* -CIENT */
+	04,'i',0200+'a','n',	/* I-ANT */
+	06,0200+'w','r','i','g','h',	/* -WRIGHT */
+	06,0200+'b','r','i','g','h',	/* -BRIGHT */
+	06,0200+'f','l','i','g','h',	/* -FLIGHT */
+	06,0200+'w','e','i','g','h',	/* -WEIGHT */
+	05,0200+'s','h','i','f',	/* -SHIFT */
+	05,0200+'c','r','a','f',	/* -CRAFT */
+	040+04,'d','g',0200+'e',	/* DG-ET */
+	04,0200+'g','o','a',	/* -GOAT */
+	04,0200+'c','o','a',	/* -COAT */
+	04,0200+'b','o','a',	/* -BOAT */
+	04,0200+'w','h','a',	/* -WHAT */
+	04,0200+'c','u','i',	/* -CUIT */
+	00
+};
+
+static	Uchar sufy[] = {
+	040+04,'e','s',0200+'t',	/* ES-TY */
+	040+05,'q','u','i',0200+'t',	/* QUI-TY */
+	04,0200+'t','i',0200+'t',	/* -TI-TY */
+	040+05,'o','s',0200+'i',0200+'t',	/* OS-I-TY */
+	04,0200+'s','i',0200+'t',	/* -SI-TY */
+	05,'i','n',0200+'i',0200+'t',	/* IN-I-TY */
+	04,'n','i',0200+'t',	/* NI-TY */
+	040+010,'f','a',0200+'b','i','l',0200+'i',0200+'t',	/* FA-BIL-I-TY */
+	010,0200+'c','a',0200+'b','i','l',0200+'i',0200+'t',	/* -CA-BIL-I-TY */
+	010,0200+'p','a',0200+'b','i','l',0200+'i',0200+'t',	/* -PA-BIL-I-TY */
+	06,0200+'b','i','l',0200+'i',0200+'t',	/* -BIL-I-TY */
+	03,'i',0200+'t',	/* I-TY */
+	04,0200+'b','u','r',	/* -BUR-Y */
+	04,0200+'t','o',0200+'r',	/* -TO-RY */
+	05,0200+'q','u','a','r',	/* -QUAR-Y */
+	040+04,'u',0200+'a','r',	/* U-ARY */
+	07,0200+'m','e','n',0200+'t','a',0200+'r',	/* -MEN-TA-RY */
+	06,'i','o','n',0200+'a','r',	/* ION-ARY */
+	04,'i',0200+'a','r',	/* I-ARY */
+	04,'n',0200+'o',0200+'m',	/* N-O-MY */
+	03,0200+'p','l',	/* -PLY */
+	04,'g',0200+'g','l',	/* G-GLY */
+	05,0200+'p','a',0200+'b','l',	/* -PA-BLY */
+	05,'f','a',0200+'b','l',	/* FA-BLY */
+	05,0200+'c','a',0200+'b','l',	/* -CA-BLY */
+	04,0200+'a','b','l',	/* -ABLY */
+	03,0200+'b','l',	/* -BLY */
+	02,0200+'l',	/* -LY */
+	03,0200+'s','k',	/* -SKY */
+	040+06,'g',0200+'r','a',0200+'p','h',	/* G-RA-PHY */
+	04,'l',0200+'o',0200+'g',	/* L-O-GY */
+	02,0200+'f',	/* -FY */
+	03,0200+'n','e',	/* -NEY */
+	03,0200+'l','e',	/* -LEY */
+	04,'c','k',0200+'e',	/* CK-EY */
+	03,0200+'k','e',	/* -KEY */
+	04,0200+'b','o','d',	/* -BODY */
+	05,0200+'s','t','u','d',	/* -STUDY */
+	0340+04,'e','e','d',	/* EEDY */
+	02,0200+'b',	/* -BY */
+	03,0200+'w','a',	/* -WAY */
+	03,0200+'d','a',	/* -DAY */
+	00
+};
+
+Uchar	*suftab[] = {
+	sufa,
+	0,
+	sufc,
+	sufd,
+	sufe,
+	suff,
+	sufg,
+	sufh,
+	sufi,
+	0,
+	sufk,
+	sufl,
+	sufm,
+	sufn,
+	sufo,
+	sufp,
+	0,
+	sufr,
+	sufs,
+	suft,
+	0,
+	0,
+	0,
+	0,
+	sufy,
+	0,
+};
blob - /dev/null
blob + 3e8026d1178c6c7ff28d4bc6f632439662b16114 (mode 644)
--- /dev/null
+++ src/cmd/troff/t10.c
@@ -0,0 +1,512 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+/*
+ * troff10.c
+ * 
+ * typesetter interface
+ */
+
+int	vpos	 = 0;	/* absolute vertical position on page */
+int	hpos	 = 0;	/* ditto horizontal */
+
+extern Font fonts[MAXFONTS+1];
+
+int	Inch;
+int	Hor;
+int	Vert;
+int	Unitwidth;
+int	nfonts;
+
+
+
+void t_ptinit(void)
+{
+	int i;
+	char buf[100], *p;
+
+	hmot = t_hmot;
+	makem = t_makem;
+	setabs = t_setabs;
+	setch = t_setch;
+	sethl = t_sethl;
+	setht = t_setht;
+	setslant = t_setslant;
+	vmot = t_vmot;
+	xlss = t_xlss;
+	findft = t_findft;
+	width = t_width;
+	mchbits = t_mchbits;
+	ptlead = t_ptlead;
+	ptout = t_ptout;
+	ptpause = t_ptpause;
+	setfont = t_setfont;
+	setps = t_setps;
+	setwd = t_setwd;
+
+	/* open table for device, */
+	/* read in resolution, size info, font info, etc., set params */
+	if ((p = getenv("TYPESETTER")) != 0)
+		strcpy(devname, p);
+	if (termtab[0] == 0)
+		strcpy(termtab, DWBfontdir);
+	if (fontdir[0] == 0)
+		strcpy(fontdir, DWBfontdir);
+	if (devname[0] == 0)
+		strcpy(devname, TDEVNAME);
+	hyf = 1;
+	lg = 1;
+
+	sprintf(buf, "/dev%s/DESC", devname);
+	strcat(termtab, buf);
+	if (getdesc(termtab) < 0) {
+		ERROR "can't open DESC file %s", termtab WARN;
+		done3(1);
+	}
+	if (!ascii) {
+		OUT "x T %s\n", devname PUT;
+		OUT "x res %d %d %d\n", Inch, Hor, Vert PUT;
+		OUT "x init\n" PUT;
+	}
+	for (i = 1; i <= nfonts; i++)
+		setfp(i, fontlab[i], (char *) 0, 0);
+	sps = EM/3;	/* space size */
+	ics = EM;	/* insertion character space */
+	for (i = 0; i < (NTAB - 1) && DTAB * (i + 1) < TABMASK; i++)
+		tabtab[i] = DTAB * (i + 1);
+	tabtab[NTAB] = 0;
+	pl = 11 * INCH;			/* paper length */
+	po = PO;		/* page offset */
+	spacesz = SS;
+	lss = lss1 = VS;
+	ll = ll1 = lt = lt1 = LL;
+	t_specnames();	/* install names like "hyphen", etc. */
+}
+
+void t_specnames(void)
+{
+	int	i;
+
+	for (i = 0; spnames[i].n; i++)
+		*spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
+}
+
+void t_ptout(Tchar i)
+{
+	int dv;
+	Tchar *k;
+	int temp, a, b;
+	int diff;
+
+	if (cbits(i) != '\n') {
+		if (olinep >= oline + olnsize) {
+			diff = olinep - oline;
+			olnsize += OLNSIZE;
+			if ((oline = (Tchar *)realloc((char *)oline, olnsize * sizeof(Tchar))) != NULL) {
+				if (diff && olinep)
+					olinep = oline + diff;
+			} else {
+				ERROR "Output line overflow." WARN;
+				done(2);
+			}
+		}
+		*olinep++ = i;
+		return;
+	}
+	if (olinep == oline) {
+		lead += lss;
+		return;
+	}
+
+	hpos = po;	/* ??? */
+	esc = 0;	/* ??? */
+	ptesc();	/* the problem is to get back to the left end of the line */
+	dv = 0;
+	for (k = oline; k < olinep; k++) {
+		if (ismot(*k) && isvmot(*k)) {
+			temp = absmot(*k);
+			if (isnmot(*k))
+				temp = -temp;
+			dv += temp;
+		}
+	}
+	if (dv) {
+		vflag++;
+		*olinep++ = makem(-dv);
+		vflag = 0;
+	}
+
+	b = dip->blss + lss;
+	lead += dip->blss + lss;
+	dip->blss = 0;
+	for (k = oline; k < olinep; )
+		k += ptout0(k);	/* now passing a pointer! */
+	olinep = oline;
+	lead += dip->alss;
+	a = dip->alss;
+	dip->alss = 0;
+	/*
+	OUT "x xxx end of line: hpos=%d, vpos=%d\n", hpos, vpos PUT;
+*/
+	OUT "n%d %d\n", b, a PUT;	/* be nice to chuck */
+}
+
+int ptout0(Tchar *pi)
+{
+	int j, k, w;
+	int z, dx, dy, dx2, dy2, n;
+	Tchar i;
+	int outsize;	/* size of object being printed */
+
+	outsize = 1;	/* default */
+	i = *pi;
+	k = cbits(i);
+	if (ismot(i)) {
+		j = absmot(i);
+		if (isnmot(i))
+			j = -j;
+		if (isvmot(i))
+			lead += j;
+		else 
+			esc += j;
+		return(outsize);
+	}
+	if (k == CHARHT) {
+		xpts = fbits(i);	/* sneaky, font bits as size bits */
+		if (xpts != mpts)
+			ptps();
+		OUT "x H %d\n", sbits(i) PUT;
+		return(outsize);
+	}
+	if (k == SLANT) {
+		OUT "x S %d\n", sfbits(i)-180 PUT;
+		return(outsize);
+	}
+	if (k == WORDSP) {
+		oput('w');
+		return(outsize);
+	}
+	if (sfbits(i) == oldbits) {
+		xfont = pfont;
+		xpts = ppts;
+	} else 
+		xbits(i, 2);
+	if (k == XON) {
+		extern int xon;
+		ptflush();	/* guarantee that everything is out */
+		if (esc)
+			ptesc();
+		if (xfont != mfont)
+			ptfont();
+		if (xpts != mpts)
+			ptps();
+		if (lead)
+			ptlead();
+		OUT "x X " PUT;
+		xon++;
+		for (j = 1; cbits(pi[j]) != XOFF; j++)
+			outascii(pi[j]);
+		oput('\n');
+		xon--;
+		return j+1;
+	}
+	if (k < 040 && k != DRAWFCN)
+		return(outsize);
+	j = z = 0;
+	if (k != DRAWFCN) {
+		if (widcache[k].fontpts == (xfont<<8) + xpts  && !setwdf) {
+			w = widcache[k].width;
+			bd = 0;
+			cs = 0;
+		} else
+			w = getcw(k);
+		if (cs) {
+			if (bd)
+				w += (bd - 1) * HOR;
+			j = (cs - w) / 2;
+			w = cs - j;
+			if (bd)
+				w -= (bd - 1) * HOR;
+		}
+		if (iszbit(i)) {
+			if (cs)
+				w = -j; 
+			else 
+				w = 0;
+			z = 1;
+		}
+	}
+	esc += j;
+	if (xfont != mfont)
+		ptfont();
+	if (xpts != mpts)
+		ptps();
+	if (lead)
+		ptlead();
+	/* put out the real character here */
+	if (k == DRAWFCN) {
+		if (esc)
+			ptesc();
+		w = 0;
+		dx = absmot(pi[3]);
+		if (isnmot(pi[3]))
+			dx = -dx;
+		dy = absmot(pi[4]);
+		if (isnmot(pi[4]))
+			dy = -dy;
+		switch (cbits(pi[1])) {
+		case DRAWCIRCLE:	/* circle */
+			OUT "D%c %d\n", DRAWCIRCLE, dx PUT;	/* dx is diameter */
+			hpos += dx;
+			break;
+		case DRAWELLIPSE:
+			OUT "D%c %d %d\n", DRAWELLIPSE, dx, dy PUT;
+			hpos += dx;
+			break;
+		case DRAWBUILD:
+			k = cbits(pi[2]);
+			OUT "D%c %d ", DRAWBUILD, dx PUT;
+			if (k < ALPHABET)
+				OUT "%c\n", k PUT;
+			else
+				ptchname(k);
+			hpos += dx;
+			break;
+		case DRAWLINE:	/* line */
+			k = cbits(pi[2]);
+			OUT "D%c %d %d ", DRAWLINE, dx, dy PUT;
+			if (k < ALPHABET)
+				OUT "%c\n", k PUT;
+			else
+				ptchname(k);
+			hpos += dx;
+			vpos += dy;
+			break;
+		case DRAWARC:	/* arc */
+			dx2 = absmot(pi[5]);
+			if (isnmot(pi[5]))
+				dx2 = -dx2;
+			dy2 = absmot(pi[6]);
+			if (isnmot(pi[6]))
+				dy2 = -dy2;
+			OUT "D%c %d %d %d %d\n", DRAWARC,
+				dx, dy, dx2, dy2 PUT;
+			hpos += dx + dx2;
+			vpos += dy + dy2;
+			break;
+
+		case 's':	/* using 's' internally to avoid .tr ~ */
+			pi[1] = '~';
+		case DRAWSPLINE:	/* spline */
+		default:	/* something else; copy it like spline */
+			OUT "D%c %d %d", cbits(pi[1]), dx, dy PUT;
+			hpos += dx;
+			vpos += dy;
+			if (cbits(pi[3]) == DRAWFCN || cbits(pi[4]) == DRAWFCN) {
+				/* it was somehow defective */
+				OUT "\n" PUT;
+				break;
+			}
+			for (n = 5; cbits(pi[n]) != DRAWFCN; n += 2) {
+				dx = absmot(pi[n]);
+				if (isnmot(pi[n]))
+					dx = -dx;
+				dy = absmot(pi[n+1]);
+				if (isnmot(pi[n+1]))
+					dy = -dy;
+				OUT " %d %d", dx, dy PUT;
+				hpos += dx;
+				vpos += dy;
+			}
+			OUT "\n" PUT;
+			break;
+		}
+		for (n = 3; cbits(pi[n]) != DRAWFCN; n++)
+			;
+		outsize = n + 1;
+	} else if (k < ALPHABET) {
+		/* try to go faster and compress output */
+		/* by printing nnc for small positive motion followed by c */
+		/* kludgery; have to make sure set all the vars too */
+		if (esc > 0 && esc < 100) {
+			oput(esc / 10 + '0');
+			oput(esc % 10 + '0');
+			oput(k);
+			hpos += esc;
+			esc = 0;
+		} else {
+			if (esc)
+				ptesc();
+			oput('c');
+			oput(k);
+			oput('\n');
+		}
+	} else {
+		if (esc)
+			ptesc();
+		ptchname(k);
+	}
+	if (bd) {
+		bd -= HOR;
+		if (esc += bd)
+			ptesc();
+		if (k < ALPHABET)
+			OUT "c%c\n", k PUT;
+		else
+			ptchname(k);
+		if (z)
+			esc -= bd;
+	}
+	esc += w;
+	return(outsize);
+}
+
+void ptchname(int k)
+{
+	char *chn = chname(k);
+
+	switch (chn[0]) {
+	case MBchar:
+		OUT "c%s\n", chn+1 PUT;	/* \n not needed? */
+		break;
+	case Number:
+		OUT "N%s\n", chn+1 PUT;
+		break;
+	case Troffchar:
+		OUT "C%s\n", chn+1 PUT;
+		break;
+	default:
+		ERROR "illegal char type %s", chn WARN;
+		break;
+	}
+}
+
+void ptflush(void)	/* get us to a clean output state */
+{
+	if (TROFF) {
+		/* ptesc(); but always H, no h */
+		hpos += esc;
+		OUT "\nH%d\n", hpos PUT;
+		esc = 0;
+		ptps();
+		ptfont();
+		ptlead();
+	}
+}
+
+void ptps(void)
+{
+	int i, j, k;
+
+	i = xpts;
+	for (j = 0; i > (k = pstab[j]); j++)
+		if (!k) {
+			k = pstab[--j];
+			break;
+		}
+	if (!ascii)
+		OUT "s%d\n", k PUT;	/* really should put out string rep of size */
+	mpts = i;
+}
+
+void ptfont(void)
+{
+	mfont = xfont;
+	if (ascii)
+		return;
+	if (xfont > nfonts) {
+		ptfpcmd(0, fonts[xfont].longname, 0);	/* Put the desired font in the
+					 * fontcache of the filter */
+		OUT "f0\n" PUT;	/* make sure that it gets noticed */
+	} else
+		OUT "f%d\n", xfont PUT;
+}
+
+void ptfpcmd(int f, char *s, char *longname)
+{
+	if (f > nfonts)		/* a bit risky? */
+		f = 0;
+	if (longname) {
+		OUT "x font %d %s %s\n", f, s, longname PUT;
+	} else {
+		OUT "x font %d %s\n", f, s PUT;
+	}
+/*	OUT "f%d\n", xfont PUT;	/* need this for buggy version of adobe transcript */
+				/* which apparently believes that x font means */
+				/* to set the font, not just the position. */
+}
+
+void t_ptlead(void)
+{
+	vpos += lead;
+	if (!ascii)
+		OUT "V%d\n", vpos PUT;
+	lead = 0;
+}
+
+void ptesc(void)
+{
+	hpos += esc;
+	if (!ascii)
+		if (esc > 0) {
+			oput('h');
+			if (esc>=10 && esc<100) {
+				oput(esc/10 + '0');
+				oput(esc%10 + '0');
+			} else
+				OUT "%d", esc PUT;
+		} else
+			OUT "H%d\n", hpos PUT;
+	esc = 0;
+}
+
+void ptpage(int n)	/* called at end of each output page, we hope */
+{
+	int i;
+
+	if (NROFF)
+		return;
+	ptlead();
+	vpos = 0;
+	if (ascii)
+		return;
+	OUT "p%d\n", n PUT;	/* new page */
+	for (i = 0; i <= nfonts; i++)
+		if (fontlab[i]) {
+			if (fonts[i].truename)
+				OUT "x font %d %s %s\n", i, fonts[i].longname, fonts[i].truename PUT;
+			else
+				OUT "x font %d %s\n", i, fonts[i].longname PUT;
+		}
+	ptps();
+	ptfont();
+}
+
+void pttrailer(void)
+{
+	if (TROFF)
+		OUT "x trailer\n" PUT;
+}
+
+void ptstop(void)
+{
+	if (TROFF)
+		OUT "x stop\n" PUT;
+}
+
+void t_ptpause(void)
+{
+	if (ascii)
+		return;
+	ptlead();
+	vpos = 0;
+	pttrailer();
+	ptlead();
+	OUT "x pause\n" PUT;
+	flusho();
+	mpts = mfont = 0;
+	ptesc();
+	esc = po;
+	hpos = vpos = 0;	/* probably in wrong place */
+}
blob - /dev/null
blob + 5511748c6c85bbc3b53e19a20dcf4f796c68c839 (mode 644)
--- /dev/null
+++ src/cmd/troff/t11.c
@@ -0,0 +1,255 @@
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+#define	MAXCH NCHARS		/* maximum number of global char names */
+char	*chnames[MAXCH];	/* chnames[n-ALPHABET] -> name of char n */
+int	nchnames;		/* number of Cxy names currently seen */
+
+#define	MAXPS	100		/* max number of point sizes */
+int	pstab[MAXPS];		/* point sizes */
+int	nsizes;			/* number in DESC */
+
+Font	fonts[MAXFONTS+1];	/* font info + ptr to width info */
+
+
+#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;
+
+	if ((fin = fopen(unsharp(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) {
+			nsizes = 0;
+			while (fscanf(fin, "%d", &v) != EOF && v != 0 && nsizes < MAXPS)
+				pstab[nsizes++] = v;
+		} else if (strcmp(cmd, "fonts") == 0) {
+			fscanf(fin, "%d", &nfonts);
+			for (i = 1; i <= nfonts; i++) {
+				fscanf(fin, "%s", s);
+				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);
+			break;
+		}
+		/* else 
+			just skip anything else */
+		skipline(fin);
+	}
+	fclose(fin);
+	return 1;
+}
+
+static int checkfont(char *name)
+{		/* in case it's not really a font description file */
+		/* really paranoid, but consider \f. */
+	FILE *fp;
+	char buf[300], buf2[300];
+	int i, status = -1;
+
+	if ((fp = fopen(unsharp(name), "r")) == NULL)
+		return -1;
+	for (i = 1; i <= 10; i++) {
+		if (fgets(buf, sizeof buf, fp) == NULL)
+			break;
+		sscanf(buf, "%s", buf2);
+		if (buf2[0] == '#') {
+			i--;
+			continue;
+		}
+		if (eq(buf2, "name") || eq(buf2, "fontname") ||
+		    eq(buf2, "special") || eq(buf2, "charset")) {
+			status = 1;
+			break;
+		}
+	}
+	fclose(fp);
+	return status;
+	
+}
+
+getfont(char *name, int pos)	/* create width tab for font */
+{
+	FILE *fin;
+	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];
+
+	/* fprintf(stderr, "read font %s onto %d\n", name, pos); */
+	if (checkfont(name) == -1)
+		return -1;
+	if ((fin = fopen(unsharp(name), "r")) == NULL)
+		return -1;
+	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) {
+		if (strcmp(cmd, "name") == 0)
+			fscanf(fin, "%s", ftemp->longname);
+		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);
+			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 */
+				}
+				/* 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];
+				} 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);
+					n = nw;
+					nw++;
+#endif	/*UNICODE*/
+				} else {
+					if (strcmp(ch, "---") == 0) { /* no name */
+						sprintf(ch, "%d", code);
+						type = Number;
+					} else
+						type = Troffchar;
+					chtemp[nw].num = chadd(ch, type, Install);
+					n = nw;
+					nw++;
+				}
+				chtemp[n].wid = wid;
+				chtemp[n].kern = kern;
+				chtemp[n].code = code;
+				/*fprintf(stderr, "font %2.2s char %4.4s num %3d wid %2d code %3d\n",
+					ftemp->longname, ch, n, wid, code);
+				*/
+			}
+			break;
+		}
+		skipline(fin);
+	}
+	fclose(fin);
+	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 */
+	ftemp->wp = (Chwid *) malloc(nw * sizeof(Chwid));
+	if (ftemp->wp == NULL)
+		return -1;
+	for (i = 0; i < nw; i++)
+		ftemp->wp[i] = chtemp[i];
+/*
+ *	printf("%d chars: ", nw);
+ *	for (i = 0; i < nw; i++)
+ *		if (ftemp->wp[i].num > 0 && ftemp->wp[i].num < ALPHABET) {
+ *			printf("%c %d ", ftemp->wp[i].num, ftemp->wp[i].wid);
+ *		else if (i >= ALPHABET)
+ *			printf("%d (%s) %d ", ftemp->wp[i].num,
+ *				chnames[ftemp->wp[i].num-ALPHABET], ftemp->wp[i].wid);
+ *	}
+ *	printf("\n");
+ */
+	return 1;
+}
+
+chadd(char *s, int type, int install)	/* add s to global character name table; */
+{					/* or just look it up */
+
+	/* a temporary kludge:  store the "type" as the first character */
+	/* of the string, so we can remember from whence it came */
+
+	char *p;
+	int i;
+
+/* 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 */
+			break;
+/* fprintf(stderr, "i %d, nchnames %d\n", i, nchnames); /* */
+	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 */
+		return -1;
+
+	chnames[nchnames] = p = (char *) malloc(strlen(s)+1+1);	/* type + \0 */
+	if (p == NULL) {
+		ERROR "out of space adding character %s", s WARN;
+		return LEFTHAND;
+	}
+	if (nchnames >= NCHARS - ALPHABET) {
+		ERROR "out of table space adding character %s", s WARN;
+		return LEFTHAND;
+	}
+	strcpy(chnames[nchnames]+1, s);
+	chnames[nchnames][0] = type;
+/* fprintf(stderr, "installed %c%s at %d\n", type, s, nchnames); /* */
+	return nchnames++ + ALPHABET;
+}
+
+char *chname(int n)	/* return string for char with index n */
+{			/* includes type char at front, to be peeled off elsewhere */
+	if (n >= ALPHABET && n < nchnames + ALPHABET)
+		return chnames[n-ALPHABET];
+	else
+		return "";
+}
+
+getlig(FILE *fin)	/* pick up ligature list */
+{
+	int lig;
+	char temp[200];
+
+	lig = 0;
+	while (fscanf(fin, "%s", temp) != EOF && strcmp(temp, "0") != 0) {
+		if (strcmp(temp, "fi") == 0)
+			lig |= LFI;
+		else if (strcmp(temp, "fl") == 0)
+			lig |= LFL;
+		else if (strcmp(temp, "ff") == 0)
+			lig |= LFF;
+		else if (strcmp(temp, "ffi") == 0)
+			lig |= LFFI;
+		else if (strcmp(temp, "ffl") == 0)
+			lig |= LFFL;
+		else
+			fprintf(stderr, "illegal ligature %s ignored\n", temp);
+	}
+	return lig;
+}
blob - /dev/null
blob + b778916c852d713638fe42e121e9bbba080e048d (mode 644)
--- /dev/null
+++ src/cmd/troff/t6.c
@@ -0,0 +1,881 @@
+/*
+ * t6.c
+ * 
+ * width functions, sizes and fonts
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+int	fontlab[MAXFONTS+1];
+int	cstab[MAXFONTS+1];
+int	ccstab[MAXFONTS+1];
+int	bdtab[MAXFONTS+1];
+int	sbold = 0;
+
+t_width(Tchar j)
+{
+	int i, k;
+
+	if (iszbit(j))
+		return 0;
+	if (ismot(j)) {
+		if (isvmot(j))
+			return(0);
+		k = absmot(j);
+		if (isnmot(j))
+			k = -k;
+		return(k);
+	}
+	i = cbits(j);
+	if (i < ' ') {
+		if (i == '\b')
+			return(-widthp);
+		if (i == PRESC)
+			i = eschar;
+		else if (i == HX)
+			return(0);
+	}
+	if (i == ohc)
+		return(0);
+	i = trtab[i];
+	if (i < ' ')
+		return(0);
+	if (sfbits(j) == oldbits) {
+		xfont = pfont;
+		xpts = ppts;
+	} else 
+		xbits(j, 0);
+	if (i < nchnames + ALPHABET && widcache[i].fontpts == (xfont<<8) + xpts && !setwdf)
+		k = widcache[i].width;
+	else {
+		k = getcw(i);
+		if (bd)
+			k += (bd - 1) * HOR;
+		if (cs)
+			k = cs;
+	}
+	widthp = k;
+	return(k);
+}
+
+/*
+ * clear width cache-- s means just space
+ */
+void zapwcache(int s)
+{
+	int i;
+
+	if (s) {
+		widcache[' '].fontpts = 0;
+		return;
+	}
+	for (i=0; i<NWIDCACHE; i++)
+		widcache[i].fontpts = 0;
+}
+
+onfont(int n, int f)	/* is char n on font f? */
+{
+	int i;
+	Font *fp = &fonts[f];
+	Chwid *cp, *ep;
+	char *np;
+
+	if (n < ALPHABET) {
+		if (fp->wp[n].num == n)	/* ascii at front */
+			return n;
+		else
+			return -1;
+	}
+	cp = &fp->wp[ALPHABET];
+	ep = &fp->wp[fp->nchars];
+	for ( ; cp < ep; cp++)	/* search others */
+		if (cp->num == n)
+			return cp - &fp->wp[0];
+	/* maybe it was a \N... */
+	np = chname(n);
+	if (*np == Number) {
+		i = atoi(np+1);		/* sscanf(np+1, "%d", &i); */
+		cp = &fp->wp[0];
+		ep = &fp->wp[fp->nchars];
+		for ( ; cp < ep; cp++) {	/* search others */
+			if (cp->code == i)
+				return cp - &fp->wp[0];
+		}
+		return -2;	/* a \N that doesn't have an entry */
+	}
+	return -1;	/* vanilla not found */
+}
+
+getcw(int i)
+{
+	int k, n, x;
+	Font *fp;
+	int nocache = 0;
+	if (i < ' ')
+		return 0;
+	bd = 0;
+	fp = &fonts[xfont];
+	if (i == ' ') {	/* a blank */
+		k = (fp->spacewidth * spacesz + 6) / 12;
+		/* this nonsense because .ss cmd uses 1/36 em as its units */
+		/* 	and default is 12 */
+	} else if ((n = onfont(i, xfont)) >= 0) {	/* on this font at n */
+		k = fp->wp[n].wid;
+		if (setwdf)
+			numtabp[CT].val |= fp->wp[n].kern;
+	} else if (n == -2) {		/* \N with default width */
+		
+		k = fp->defaultwidth;
+	} else {			/* not on current font */
+		nocache = 1;
+		k = fp->defaultwidth;	/* default-size space */
+		if (smnt) {
+			int ii, jj;
+			for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
+				if ((n = onfont(i, ii)) >= 0) {
+					k = fonts[ii].wp[n].wid;
+					if (xfont == sbold)
+						bd = bdtab[ii];
+					if (setwdf)
+						numtabp[CT].val |= fonts[ii].wp[n].kern;
+					break;
+				}
+			}
+		}
+	}
+	if (!bd)
+		bd = bdtab[xfont];
+	if (cs = cstab[xfont]) {
+		nocache = 1;
+		if (ccs = ccstab[xfont])
+			x = ccs; 
+		else 
+			x = xpts;
+		cs = (cs * EMPTS(x)) / 36;
+	}
+	/* was (k & BYTEMASK);  since .wid is unsigned, should never happen */
+	if (k < 0)
+		ERROR "can't happen: negative width %d in getcw %d\n", k, i WARN;
+	k = (k * xpts + (Unitwidth / 2)) / Unitwidth;
+	if (nocache|bd)
+		widcache[i].fontpts = 0;
+	else {
+		widcache[i].fontpts = (xfont<<8) + xpts;
+		widcache[i].width = k;
+	}
+	return(k);
+	/* Unitwidth is Units/Point, where
+	/* Units is the fundamental digitization
+	/* of the character set widths, and
+	/* Point is the number of goobies in a point
+	/* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6
+	/* In effect, it's the size at which the widths
+	/* translate directly into units.
+	*/
+}
+
+void xbits(Tchar i, int bitf)
+{
+	int k;
+
+	if(TROFF) {
+		xfont = fbits(i);
+		k = sbits(i);
+		if(k) {
+			xpts = pstab[k-1];
+			oldbits = sfbits(i);
+			pfont = xfont;
+			ppts = xpts;
+			return;
+		}
+		switch(bitf) {
+		case 0:
+			xfont = font;
+			xpts = pts;
+			break;
+		case 1:
+			xfont = pfont;
+			xpts = ppts;
+			break;
+		case 2:
+			xfont = mfont;
+			xpts = mpts;
+		}
+	}
+}
+
+
+/* these next two functions ought to be the same in troff and nroff, */
+/* but the data structures they search are different. */
+/* silly historical problem. */
+
+
+Tchar t_setch(int c)
+{
+	int j;
+	char temp[50];
+	char *s;
+
+	s = temp;
+	if (c == '(') {	/* \(xx */
+		if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
+			return(0);
+	} else {	/* \C'...' */
+		c = getach();
+		while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1)
+			s++;
+	}
+	*s = '\0';
+#ifdef UNICODE
+	return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
+#else
+	if (NROFF) {
+		j = chadd(temp, Troffchar, Lookup);
+		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*/
+}
+
+Tchar t_setabs(void)		/* set absolute char from \N'...' */
+{
+	int n;
+	char temp[10];
+
+	getch();	/* delim */
+	n = 0;
+	n = inumb(&n);
+	getch();	/* delim */
+	if (nonumb)
+		return 0;
+	sprintf(temp, "%d", n);	/* convert into "#n" */
+	n = chadd(temp, Number, Install);
+	return n | chbits;
+}
+
+
+/*
+ * fontlab[] is a cache that contains font information
+ * for each font.
+ * fontlab[] contains the 1- or 2-character name of the
+ * font current associated with that font.
+ * fonts 1..nfonts correspond to the mounted fonts;
+ * the last of these are the special fonts.
+ * If we don't use the (named) font in one of the
+ * standard positions, we install the name in the next
+ * free slot of fontlab[] and font[].
+ * Whenever we need info about the font, we
+ * read in the data into the next free slot with getfont.
+ * The ptfont() (t10.c) routine will tell
+ * the device filter to put the font always at position
+ * zero if xfont > nfonts, so no need to change these filters.
+ * Yes, this is a bit kludgy.
+ *
+ * This gives the new specs of findft:
+ * 	find the font name i, where i also can be a number.
+ * 	Installs the font(name) i when not present
+ * 	returns -1 on error
+ */
+
+
+t_findft(int i)
+{
+	int k;
+	Uchar *p;
+
+	p = unpair(i);
+
+	if (isdigit(p[0])) {		/* first look for numbers */
+		k = p[0] - '0';
+		if (p[1] > 0 && isdigit(p[1]))
+			k = 10 * k + p[1] - '0';
+		if (k > 0 && k <= nfonts && k < smnt)
+			return(k);	/* mounted font:  .ft 3 */
+		if (fontlab[k] && k <= MAXFONTS) {	/* translate */
+			return(k);			/*number to a name */
+		} else {
+			fprintf(stderr, "troff: no font at position %d\n", k);
+			return(-1);	/* wild number */
+		}
+	}
+
+	/*
+	 * Now we look for font names
+	 */
+	for (k = 1; fontlab[k] != i; k++) {
+		if (k > MAXFONTS)
+			return(-1);	/* running out of fontlab space */
+		if (fontlab[k] == 0) {	/* passed all existing names */
+			if (setfp(k, i, (char *) 0, 1) == -1)
+				return(-1);
+			else {
+				fontlab[k] = i;	/* install the name */
+				return(k);
+			}
+		}
+	}
+	return(k);			/* was one of the existing names */
+}
+
+
+void caseps(void)
+{
+	int i;
+
+	if (TROFF) {
+		if(skip())
+			i = apts1;
+		else {
+			noscale++;
+			i = inumb(&apts);	/* this is a disaster for fractional point sizes */
+			noscale = 0;
+			if(nonumb)
+				i = apts1;
+		}
+		casps1(i);
+	}
+}
+
+
+void casps1(int i)
+{
+
+/*
+ * in olden times, it used to ignore changes to 0 or negative.
+ * this is meant to allow the requested size to be anything,
+ * in particular so eqn can generate lots of \s-3's and still
+ * get back by matching \s+3's.
+
+	if (i <= 0)
+		return;
+*/
+	apts1 = apts;
+	apts = i;
+	pts1 = pts;
+	pts = findps(i);
+	mchbits();
+}
+
+
+findps(int i)
+{
+	int j, k;
+
+	for (j=k=0 ; pstab[j] != 0 ; j++)
+		if (abs(pstab[j]-i) < abs(pstab[k]-i))
+			k = j;
+
+	return(pstab[k]);
+}
+
+
+void t_mchbits(void)
+{
+	int i, j, k;
+
+	i = pts;
+	for (j = 0; i > (k = pstab[j]); j++)
+		if (!k) {
+			j--;
+			break;
+		}
+	chbits = 0;
+	setsbits(chbits, ++j);
+	setfbits(chbits, font);
+	sps = width(' ' | chbits);
+	zapwcache(1);
+}
+
+void t_setps(void)
+{
+	int i, j;
+
+	i = cbits(getch());
+	if (isdigit(i)) {		/* \sd or \sdd */
+		i -= '0';
+		if (i == 0)		/* \s0 */
+			j = apts1;
+		else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) {	/* \sdd */
+			j = 10 * i + j - '0';
+			ch = 0;
+		} else		/* \sd */
+			j = i;
+	} else if (i == '(') {		/* \s(dd */
+		j = cbits(getch()) - '0';
+		j = 10 * j + cbits(getch()) - '0';
+		if (j == 0)		/* \s(00 */
+			j = apts1;
+	} else if (i == '+' || i == '-') {	/* \s+, \s- */
+		j = cbits(getch());
+		if (isdigit(j)) {		/* \s+d, \s-d */
+			j -= '0';
+		} else if (j == '(') {		/* \s+(dd, \s-(dd */
+			j = cbits(getch()) - '0';
+			j = 10 * j + cbits(getch()) - '0';
+		}
+		if (i == '-')
+			j = -j;
+		j += apts;
+	}
+	casps1(j);
+}
+
+
+Tchar t_setht(void)		/* set character height from \H'...' */
+{
+	int n;
+	Tchar c;
+
+	getch();
+	n = inumb(&apts);
+	getch();
+	if (n == 0 || nonumb)
+		n = apts;	/* does this work? */
+	c = CHARHT;
+	c |= ZBIT;
+	setsbits(c, n);
+	setfbits(c, pts);	/* sneaky, CHARHT font bits are size bits */
+	return(c);
+}
+
+Tchar t_setslant(void)		/* set slant from \S'...' */
+{
+	int n;
+	Tchar c;
+
+	getch();
+	n = 0;
+	n = inumb(&n);
+	getch();
+	if (nonumb)
+		n = 0;
+	c = SLANT;
+	c |= ZBIT;
+	setsfbits(c, n+180);
+	return(c);
+}
+
+
+void caseft(void)
+{
+	if (!TROFF) {
+		n_caseft();
+		return;
+	}
+	skip();
+	setfont(1);
+}
+
+
+void t_setfont(int a)
+{
+	int i, j;
+
+	if (a)
+		i = getrq();
+	else 
+		i = getsn();
+	if (!i || i == 'P') {
+		j = font1;
+		goto s0;
+	}
+	if (/* i == 'S' || */ i == '0')	/* an experiment -- why can't we change to it? */
+		return;
+	if ((j = findft(i)) == -1)
+		if ((j = setfp(0, i, (char*) 0, 1)) == -1)	/* try to put it in position 0 */
+			return;
+s0:
+	font1 = font;
+	font = j;
+	mchbits();
+}
+
+
+void t_setwd(void)
+{
+	int base, wid;
+	Tchar i;
+	int delim, emsz, k;
+	int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
+
+	base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0;
+	if (ismot(i = getch()))
+		return;
+	delim = cbits(i);
+	savhp = numtabp[HP].val;
+	numtabp[HP].val = 0;
+	savapts = apts;
+	savapts1 = apts1;
+	savfont = font;
+	savfont1 = font1;
+	savpts = pts;
+	savpts1 = pts1;
+	setwdf++;
+	while (cbits(i = getch()) != delim && !nlflg) {
+		k = width(i);
+		wid += k;
+		numtabp[HP].val += k;
+		if (!ismot(i)) {
+			emsz = (INCH/72) * xpts;
+		} else if (isvmot(i)) {
+			k = absmot(i);
+			if (isnmot(i))
+				k = -k;
+			base -= k;
+			emsz = 0;
+		} else 
+			continue;
+		if (base < numtabp[SB].val)
+			numtabp[SB].val = base;
+		if ((k = base + emsz) > numtabp[ST].val)
+			numtabp[ST].val = k;
+	}
+	setn1(wid, 0, (Tchar) 0);
+	numtabp[HP].val = savhp;
+	apts = savapts;
+	apts1 = savapts1;
+	font = savfont;
+	font1 = savfont1;
+	pts = savpts;
+	pts1 = savpts1;
+	mchbits();
+	setwdf = 0;
+}
+
+
+Tchar t_vmot(void)
+{
+	dfact = lss;
+	vflag++;
+	return t_mot();
+}
+
+
+Tchar t_hmot(void)
+{
+	dfact = EM;
+	return t_mot();
+}
+
+
+Tchar t_mot(void)
+{
+	int j, n;
+	Tchar i;
+
+	j = HOR;
+	getch(); /*eat delim*/
+	if (n = atoi0()) {
+		if (vflag)
+			j = VERT;
+		i = makem(quant(n, j));
+	} else
+		i = 0;
+	getch();
+	vflag = 0;
+	dfact = 1;
+	return(i);
+}
+
+
+Tchar t_sethl(int k)
+{
+	int j;
+	Tchar i;
+
+	j = EM / 2;
+	if (k == 'u')
+		j = -j;
+	else if (k == 'r')
+		j = -2 * j;
+	vflag++;
+	i = makem(j);
+	vflag = 0;
+	return(i);
+}
+
+
+Tchar t_makem(int i)
+{
+	Tchar j;
+
+	if (i >= 0)
+		j = i;
+	else
+		j = -i;
+	if (Hor > 1 && !vflag)
+		j = (j + Hor/2)/Hor * Hor;
+	j |= MOT;
+	if (i < 0)
+		j |= NMOT;
+	if (vflag)
+		j |= VMOT;
+	return(j);
+}
+
+
+Tchar getlg(Tchar i)
+{
+	Tchar j, k;
+	int lf;
+
+	if (!TROFF)
+		return i;
+	if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */
+		return(i);
+	j = getch0();
+	if (cbits(j) == 'i' && (lf & LFI))
+		j = LIG_FI;
+	else if (cbits(j) == 'l' && (lf & LFL))
+		j = LIG_FL;
+	else if (cbits(j) == 'f' && (lf & LFF)) {
+		if ((lf & (LFFI|LFFL)) && lg != 2) {
+			k = getch0();
+			if (cbits(k)=='i' && (lf&LFFI))
+				j = LIG_FFI;
+			else if (cbits(k)=='l' && (lf&LFFL))
+				j = LIG_FFL;
+			else {
+				*pbp++ = k;
+				j = LIG_FF;
+			}
+		} else 
+			j = LIG_FF;
+	} else {
+		*pbp++ = j;
+		j = i;
+	}
+	return(i & SFMASK | j);
+}
+
+
+void caselg(void)
+{
+
+	if(TROFF) {
+		skip();
+		lg = atoi0();
+		if (nonumb)
+			lg = 1;
+	}
+}
+
+void casefp(void)
+{
+	int i, j;
+
+	if (!TROFF) {
+		n_casefp();
+		return;
+	}
+	skip();
+	i = cbits(getch());
+	if (isdigit(i)) {
+		i -= '0';
+		j = cbits(getch());
+		if (isdigit(j))
+			i = 10 * i + j - '0';
+	}
+	if (i <= 0 || i > nfonts)
+		ERROR "fp: bad font position %d", i WARN;
+	else if (skip() || !(j = getrq()))
+		ERROR "fp: no font name" WARN; 
+	else if (skip() || !getname())
+		setfp(i, j, (char*) 0, 1);
+	else		/* 3rd argument = filename */
+		setfp(i, j, nextf, 1);
+}
+
+char *strdupl(const char *s)	/* make a copy of s */
+{
+	char *t;
+
+	t = (char *) malloc(strlen(s) + 1);
+	if (t == NULL)
+		ERROR "out of space in strdupl(%s)", s FATAL;
+	strcpy(t, s);
+	return t;
+}
+
+setfp(int pos, int f, char *truename, int print)	/* mount font f at position pos[0...nfonts] */
+{
+	char pathname[NS], shortname[NS], *sl;
+
+	zapwcache(0);
+	if (truename)
+		strcpy(shortname, truename);
+	else
+		strcpy(shortname, (char *) unpair(f));
+	if (truename && strrchr(truename, '/')) {	/* .fp 1 R dir/file: use verbatim */
+		sprintf(pathname, "%s", truename);
+		if (fonts[pos].truename)
+			free(fonts[pos].truename);
+		fonts[pos].truename = strdupl(truename);
+	} else if (truename) {			/* synonym: .fp 1 R Avant */
+		sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename);
+		truename = 0;	/* so doesn't get repeated by ptfpcmd */
+	} else					/* vanilla: .fp 5 XX */
+		sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname);
+	if (truename == 0 && fonts[pos].truename != 0) {
+		free(fonts[pos].truename);
+		fonts[pos].truename = 0;
+	}
+	if (getfont(pathname, pos) < 0) {
+		ERROR "Can't open font file %s", pathname WARN;
+		return -1;
+	}
+	if (print && !ascii) {
+		ptfpcmd(pos, fonts[pos].longname, truename);
+		ptfont();
+	}
+	if (pos == smnt) {
+		smnt = 0; 
+		sbold = 0; 
+	}
+	fontlab[pos] = f;
+	if (smnt == 0 && fonts[pos].specfont)
+		smnt = pos;
+	bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
+	return pos;
+}
+
+/*
+ * .cs request; don't check legality of optional arguments
+ */
+void casecs(void)
+{
+	int i, j;
+
+	if (TROFF) {
+		int savtr = trace;
+
+		trace = 0;
+		noscale++;
+		skip();
+		if (!(i = getrq()) || (i = findft(i)) < 0)
+			goto rtn;
+		skip();
+		cstab[i] = atoi0();
+		skip();
+		j = atoi0();
+		if(nonumb)
+			ccstab[i] = 0;
+		else
+			ccstab[i] = findps(j);
+	rtn:
+		zapwcache(0);
+		noscale = 0;
+		trace = savtr;
+	}
+}
+
+
+void casebd(void)
+{
+	int i, j, k;
+
+	if (!TROFF) {
+		n_casebd();
+		return;
+	}
+	zapwcache(0);
+	k = 0;
+bd0:
+	if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
+		if (k)
+			goto bd1;
+		else 
+			return;
+	}
+	if (j == smnt) {
+		k = smnt;
+		goto bd0;
+	}
+	if (k) {
+		sbold = j;
+		j = k;
+	}
+bd1:
+	skip();
+	noscale++;
+	bdtab[j] = atoi0();
+	noscale = 0;
+}
+
+
+void casevs(void)
+{
+	int i;
+
+	if (!TROFF) {
+		n_casevs();
+		return;
+	}
+	skip();
+	vflag++;
+	dfact = INCH; /* default scaling is points! */
+	dfactd = 72;
+	res = VERT;
+	i = inumb(&lss);
+	if (nonumb)
+		i = lss1;
+	if (i < VERT) 
+		i = VERT;
+	lss1 = lss;
+	lss = i;
+}
+
+
+void casess(void)
+{
+	int i;
+
+	if(TROFF) {
+		noscale++;
+		skip();
+		if(i = atoi0()) {
+			spacesz = i & 0177;
+			zapwcache(0);
+			sps = width(' ' | chbits);
+		}
+		noscale = 0;
+	}
+}
+
+
+Tchar t_xlss(void)
+{
+	/* stores \x'...' into two successive Tchars.
+	/* the first contains HX, the second the value,
+	/* encoded as a vertical motion.
+	/* decoding is done in n2.c by pchar().
+	*/
+	int i;
+
+	getch();
+	dfact = lss;
+	i = quant(atoi0(), VERT);
+	dfact = 1;
+	getch();
+	if (i >= 0)
+		*pbp++ = MOT | VMOT | i;
+	else
+		*pbp++ = MOT | VMOT | NMOT | -i;
+	return(HX);
+}
+
+Uchar *unpair(int i)
+{
+	static Uchar name[3];
+
+	name[0] = i & SHORTMASK;
+	name[1] = (i >> SHORT) & SHORTMASK;
+	name[2] = 0;
+	return name;
+}
blob - /dev/null
blob + e9e1f65caad9fd56067794751a639c2f67c3bb46 (mode 644)
--- /dev/null
+++ src/cmd/troff/tdef.h
@@ -0,0 +1,670 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+
+#define	NROFF	(!TROFF)
+
+
+/* Site dependent definitions */
+
+#ifndef TMACDIR
+#define TMACDIR		"lib/tmac/tmac."
+#endif
+#ifndef FONTDIR
+#define FONTDIR		"lib/font"
+#endif
+#ifndef NTERMDIR
+#define NTERMDIR	"lib/term/tab."
+#endif
+#ifndef TDEVNAME
+#define TDEVNAME	"post"
+#endif
+#ifndef NDEVNAME
+#define NDEVNAME	"37"
+#endif
+#ifndef TEXHYPHENS
+#define	TEXHYPHENS	"/usr/lib/tex/macros/hyphen.tex"
+#endif
+#ifndef ALTHYPHENS
+#define	ALTHYPHENS	"lib/tmac/hyphen.tex"	/* another place to look */
+#endif
+
+typedef	unsigned char	Uchar;
+typedef unsigned short	Ushort;
+
+typedef	/*unsigned*/ long	Tchar;
+
+typedef	struct	Blockp	Blockp;
+typedef	struct	Diver	Diver;
+typedef	struct	Stack	Stack;
+typedef	struct	Divsiz	Divsiz;
+typedef	struct	Contab	Contab;
+typedef	struct	Numtab	Numtab;
+typedef	struct	Numerr	Numerr;
+typedef	struct	Env	Env;
+typedef	struct	Term	Term;
+typedef struct	Chwid	Chwid;
+typedef struct	Font	Font;
+typedef	struct	Spnames	Spnames;
+typedef	struct	Wcache	Wcache;
+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	PUT		)) > obuf+BUFSIZ ? flusho() : 1
+#endif
+
+#define	oputs(a)	OUT "%s", a PUT
+#define	oput(c)		( *obufp++ = (c), obufp > obuf+BUFSIZ ? flusho() : 1 )
+
+extern	char	errbuf[];
+#define	ERROR	sprintf(errbuf,
+#define	WARN	), errprint()
+#define	FATAL	), errprint(), exit(1)
+
+/* starting values for typesetting parameters: */
+
+#define	PS	10	/* default point size */
+#define	FT	1	/* default font position */
+#define ULFONT	2	/* default underline font */
+#define	BDFONT	3	/* default emboldening font */
+#define	BIFONT	4	/* default bold italic font */
+#define	LL	(unsigned) 65*INCH/10	/* line length; 39picas=6.5in */
+#define	VS	((12*INCH)/72)	/* initial vert space */
+
+
+#define	EMPTS(pts)	(((long)Inch*(pts) + 36) / 72)
+#define	EM	(TROFF? EMPTS(pts): t.Em)
+#define	INCH	(TROFF? Inch: 240)
+#define	HOR	(TROFF? Hor: t.Adj)
+#define	VERT	(TROFF? Vert: t.Vert)
+#define	PO	(TROFF? Inch: 0)
+#define	SPS	(TROFF? EMPTS(pts)/3: INCH/10)
+#define	SS	(TROFF? 12: INCH/10)
+#define	ICS	(TROFF? EMPTS(pts): 2*INCH/10)
+#define	DTAB	(TROFF? (INCH/2): 0)
+
+/* These "characters" are used to encode various internal functions
+/* Some make use of the fact that most ascii characters between
+/* 0 and 040 don't have any graphic or other function.
+/* The few that do have a purpose (e.g., \n, \b, \t, ...
+/* are avoided by the ad hoc choices here.
+/* See ifilt[] in n1.c for others -- 1, 2, 3, 5, 6, 7, 010, 011, 012 
+*/
+
+#define	LEADER	001
+#define	IMP	004	/* impossible char; glues things together */
+#define	TAB	011
+#define	RPT	014	/* next character is to be repeated many times */
+#define	CHARHT	015	/* size field sets character height */
+#define	SLANT	016	/* size field sets amount of slant */
+#define	DRAWFCN	017	/* next several chars describe arb drawing fcns */
+#	define	DRAWLINE	'l'	/* line: 'l' dx dy char */
+#	define	DRAWCIRCLE	'c'	/* circle: 'c' r */
+#	define	DRAWELLIPSE	'e'	/* ellipse: 'e' rx ry */
+#	define	DRAWARC		'a'	/* arc: 'a' dx dy dx dy */
+#	define	DRAWSPLINE	'~'	/* quadratic B spline: '~' dx dy dx dy ... */
+					/* other splines go thru too */
+/* NOTE:  the use of ~ is a botch since it's often used in .tr commands */
+/* better to use a letter like s, but change it in the postprocessors too */
+/* for now, this is taken care of in n9.c and t10.c */
+#	define	DRAWBUILD	'b'	/* built-up character (e.g., { */
+
+#define	LEFT	020	/* \{ */
+#define	RIGHT	021	/* \} */
+#define	FILLER	022	/* \& and similar purposes */
+#define	XON	023	/* \X'...' starts here */
+#define	OHC	024	/* optional hyphenation character \% */
+#define	CONT	025	/* \c character */
+#define	PRESC	026	/* printable escape */
+#define	UNPAD	027	/* unpaddable blank */
+#define	XPAR	030	/* transparent mode indicator */
+#define	FLSS	031	/* next Tchar contains vertical space */
+			/* used when recalling diverted text */
+#define	WORDSP	032	/* paddable word space */
+#define	ESC	033	/* current escape character */
+#define	XOFF	034	/* \X'...' ends here */
+			/* matches XON, but they will probably never nest */
+			/* so could drop this when another control is needed */
+#define	HX	035	/* next character is value of \x'...' */
+#define MOTCH	036	/* this "character" is really motion; used by cbits() */
+
+#define	HYPHEN	c_hyphen
+#define	EMDASH	c_emdash	/* \(em */
+#define	RULE	c_rule		/* \(ru */
+#define	MINUS	c_minus		/* minus sign on current font */
+#define	LIG_FI	c_fi		/* \(ff */
+#define	LIG_FL	c_fl		/* \(fl */
+#define	LIG_FF	c_ff		/* \(ff */
+#define	LIG_FFI	c_ffi		/* \(Fi */
+#define	LIG_FFL	c_ffl		/* \(Fl */
+#define	ACUTE	c_acute		/* acute accent \(aa */
+#define	GRAVE	c_grave		/* grave accent \(ga */
+#define	UNDERLINE c_under	/* \(ul */
+#define	ROOTEN	c_rooten	/* root en \(rn */
+#define	BOXRULE	c_boxrule	/* box rule \(br */
+#define	LEFTHAND c_lefthand	/* left hand for word overflow */
+#define	DAGGER	 c_dagger	/* dagger for end of sentence/footnote */
+
+#define	HYPHALG	1	/* hyphenation algorithm: 0=>good old troff, 1=>tex */
+
+
+/* array sizes, and similar limits: */
+
+#define MAXFONTS 99	/* Maximum number of fonts in fontab */
+#define	NM	90	/* requests + macros */
+#define	NN	NNAMES	/* number registers */
+#define	NNAMES	15	/* predefined reg names */
+#define	NIF	15	/* if-else nesting */
+#define	NS	128	/* name buffer */
+#define	NTM	1024	/* tm buffer */
+#define	NEV	3	/* environments */
+#define	EVLSZ	10	/* size of ev stack */
+
+#define	STACKSIZE (6*1024)	/* stack for macros and strings in progress */
+#define	NHYP	10	/* max hyphens per word */
+#define	NHEX	512	/* byte size of exception word list */
+#define	NTAB	100	/* tab stops */
+#define	NSO	5	/* "so" depth */
+#define	NMF	5	/* number of -m flags */
+#define	WDSIZE	500	/* word buffer click size */
+#define	LNSIZE	4000	/* line buffer click size */
+#define	OLNSIZE	5000	/* output line buffer click; bigger for 'w', etc. */
+#define	NDI	5	/* number of diversions */
+
+#define	ALPHABET alphabet	/* number of characters in basic alphabet. */
+			/* 128 for parochial USA 7-bit ascii, */
+			/* 256 for "European" mode with e.g., Latin-1 */
+
+	/* NCHARS must be greater than 
+		ALPHABET (ascii stuff) + total number of distinct char names
+		from all fonts that will be run in this job (including
+		unnamed ones and \N's)
+	*/
+
+#define	NCHARS	(8*1024)	/* maximum size of troff character set*/
+
+
+	/* However for nroff you want only :
+	1. number of special codes in charset of DESC, which ends up being the
+		value of nchtab and which must be less than 512.
+	2. ALPHABET, which apparently is the size of the portion of the tables reserved
+		for special control symbols
+	Apparently the max N of \N is irrelevant; */
+	/* to allow \N of up to 254 with up to 338 special characters
+		you need NCHARS of 338 + ALPHABET = 466 */
+
+#define	NROFFCHARS	1024	/* maximum size of nroff character set */
+
+#define	NTRTAB		NCHARS	/* number of items in trtab[] */
+#define NWIDCACHE	NCHARS	/* number of items in widcache[] */
+
+#define	NTRAP	20	/* number of traps */
+#define	NPN	20	/* numbers in "-o" */
+#define	FBUFSZ	512	/* field buf size words */
+#define	IBUFSZ	4096	/* bytes */
+#define	NC	1024	/* cbuf size words */
+#define	NOV	10	/* number of overstrike chars */
+#define	NPP	10	/* pads per field */
+
+/*
+	Internal character representation:
+	Internally, every character is carried around as
+	a 32 bit cookie, called a "Tchar" (typedef long).
+	Bits are numbered 31..0 from left to right.
+	If bit 15 is 1, the character is motion, with
+		if bit 16 it's vertical motion
+		if bit 17 it's negative motion
+	If bit 15 is 0, the character is a real character.
+		if bit 31	zero motion
+		bits 30..24	size
+		bits 23..16	font
+*/
+
+/* in the following, "L" should really be a Tchar, but ... */
+/* numerology leaves room for 16 bit chars */
+
+#define	MOT	(01uL << 16)	/* motion character indicator */
+#define	VMOT	(01uL << 30)	/* vertical motion bit */
+#define	NMOT	(01uL << 29)	/* negative motion indicator */
+/* #define	MOTV	(MOT|VMOT|NMOT)	/* motion flags */
+/* #define	MAXMOT	(~MOTV)		/* maximum motion permitted */
+#define	MAXMOT	0xFFFF
+
+#define	ismot(n)	((n) & MOT)
+#define	isvmot(n)	(((n) & (MOT|VMOT)) == (MOT|VMOT))	/* must have tested MOT previously */
+#define	isnmot(n)	(((n) & (MOT|NMOT)) == (MOT|NMOT))	/* ditto */
+#define	absmot(n)	((n) & 0xFFFF)
+
+#define	ZBIT	(01uL << 31)	/* zero width char */
+#define	iszbit(n)	((n) &  ZBIT)
+
+#define	FSHIFT	17
+#define	SSHIFT	(FSHIFT+7)
+#define	SMASK		(0177uL << SSHIFT)	/* 128 distinct sizes */
+#define	FMASK		(0177uL << FSHIFT)	/* 128 distinct fonts */
+#define	SFMASK		(SMASK|FMASK)	/* size and font in a Tchar */
+#define	sbits(n)	(((n) >> SSHIFT) & 0177)
+#define	fbits(n)	(((n) >> FSHIFT) & 0177)
+#define	sfbits(n)	(((n) & SFMASK) >> FSHIFT)
+#define	cbits(n)	((n) & 0x1FFFF)		/* isolate character bits,  */
+						/* but don't include motions */
+extern	int	realcbits(Tchar);
+
+#define	setsbits(n,s)	n = (n & ~SMASK) | (Tchar)(s) << SSHIFT
+#define	setfbits(n,f)	n = (n & ~FMASK) | (Tchar)(f) << FSHIFT
+#define	setsfbits(n,sf)	n = (n & ~SFMASK) | (Tchar)(sf) << FSHIFT
+#define	setcbits(n,c)	n = (n & ~0xFFFFuL | (c))	/* set character bits */
+
+#define	BYTEMASK 0377
+#define	BYTE	 8
+
+#define	SHORTMASK 0XFFFF
+#define	SHORT	 16
+
+#define	TABMASK	 ((unsigned) INT_MAX >> 1)
+#define	RTAB	((TABMASK << 1) & ~TABMASK)
+#define	CTAB	(RTAB << 1)
+
+#define	TABBIT	02		/* bits in gchtab */
+#define	LDRBIT	04
+#define	FCBIT	010
+
+#define	PAIR(A,B)	(A|(B<<SHORT))
+
+
+extern	int	Inch, Hor, Vert, Unitwidth;
+
+struct	Spnames
+{
+	int	*n;
+	char	*v;
+};
+
+extern	Spnames	spnames[];
+
+/*
+	String and macro definitions are stored conceptually in a giant array
+	indexed by type Offset.  In olden times, this array was real, and thus
+	both huge and limited in size, leading to the "Out of temp file space"
+	error.  In this version, the array is represented by a list of blocks,
+	pointed to by blist[].bp.  Each block is of size BLK Tchars, and BLK
+	MUST be a power of 2 for the macros below to work.
+	
+	The blocks associated with a particular string or macro are chained
+	together in the array blist[].  Each blist[i].nextoff contains the
+	Offset associated with the next block in the giant array, or -1 if
+	this is the last block in the chain.  If .nextoff is 0, the block is
+	free.
+	
+	To find the right index in blist for an Offset, divide by BLK.
+*/
+
+#define	NBLIST	2048	/* starting number of blocks in all definitions */
+
+#define	BLK	128	/* number of Tchars in a block; must be 2^N with defns below */
+
+#define	rbf0(o)		(blist[bindex(o)].bp[boffset(o)])
+#define	bindex(o)	((o) / BLK)
+#define	boffset(o)	((o) & (BLK-1))
+#define	pastend(o)	(((o) & (BLK-1)) == 0)
+/* #define	incoff(o)	( (++o & (BLK-1)) ? o : blist[bindex(o-1)].nextoff ) */
+#define	incoff(o)	( (((o)+1) & (BLK-1)) ? o+1 : blist[bindex(o)].nextoff )
+
+#define	skipline(f)	while (getc(f) != '\n')
+#define is(s)		(strcmp(cmd, s) == 0)
+#define	eq(s1, s2)	(strcmp(s1, s2) == 0)
+
+
+typedef	unsigned long	Offset;		/* an offset in macro/string storage */
+
+struct Blockp {		/* info about a block: */
+	Tchar	*bp;		/* the data */
+	Offset	nextoff;	/* offset of next block in a chain */
+};
+
+extern	Blockp	*blist;
+
+#define	RD_OFFSET	(1 * BLK)	/* .rd command uses block 1 */
+
+struct Diver {		/* diversion */
+	Offset	op;
+	int	dnl;
+	int	dimac;
+	int	ditrap;
+	int	ditf;
+	int	alss;
+	int	blss;
+	int	nls;
+	int	mkline;
+	int	maxl;
+	int	hnl;
+	int	curd;
+};
+
+struct Stack {		/* stack frame */
+	int	nargs;
+	Stack	*pframe;
+	Offset	pip;
+	int	pnchar;
+	Tchar	prchar;
+	int	ppendt;
+	Tchar	pch;
+	Tchar	*lastpbp;
+	int	mname;
+};
+
+extern	Stack	s;
+
+struct Divsiz {
+	int dix;
+	int diy;
+};
+
+struct Contab {		/* command or macro */
+	unsigned int	rq;
+	Contab	*link;
+	void	(*f)(void);
+	Offset	mx;
+	Offset	emx;
+	Divsiz	*divsiz;
+};
+
+#define	C(a,b)	{a, 0, b, 0, 0}		/* how to initialize a contab entry */
+
+extern	Contab	contab[NM];
+
+struct Numtab {	/* number registers */
+	unsigned int	r;		/* name */
+	int	val;
+	short	fmt;
+	short	inc;
+	Numtab	*link;
+};
+
+extern	Numtab	numtab[NN];
+
+#define	PN	0
+#define	NL	1
+#define	YR	2
+#define	HP	3
+#define	CT	4
+#define	DN	5
+#define	MO	6
+#define	DY	7
+#define	DW	8
+#define	LN	9
+#define	DL	10
+#define	ST	11
+#define	SB	12
+#define	CD	13
+#define	PID	14
+
+struct	Wcache {	/* width cache, indexed by character */
+	short	fontpts;
+	short	width;
+};
+
+struct	Tbuf {		/* growable Tchar buffer */
+	Tchar *_bufp;
+	unsigned int _size;
+};
+
+/* the infamous environment block */
+
+#define	ics	envp->_ics
+#define	sps	envp->_sps
+#define	spacesz	envp->_spacesz
+#define	lss	envp->_lss
+#define	lss1	envp->_lss1
+#define	ll	envp->_ll
+#define	ll1	envp->_ll1
+#define	lt	envp->_lt
+#define	lt1	envp->_lt1
+#define	ic	envp->_ic
+#define	icf	envp->_icf
+#define	chbits	envp->_chbits
+#define	spbits	envp->_spbits
+#define	nmbits	envp->_nmbits
+#define	apts	envp->_apts
+#define	apts1	envp->_apts1
+#define	pts	envp->_pts
+#define	pts1	envp->_pts1
+#define	font	envp->_font
+#define	font1	envp->_font1
+#define	ls	envp->_ls
+#define	ls1	envp->_ls1
+#define	ad	envp->_ad
+#define	nms	envp->_nms
+#define	ndf	envp->_ndf
+#define	nmwid	envp->_nmwid
+#define	fi	envp->_fi
+#define	cc	envp->_cc
+#define	c2	envp->_c2
+#define	ohc	envp->_ohc
+#define	tdelim	envp->_tdelim
+#define	hyf	envp->_hyf
+#define	hyoff	envp->_hyoff
+#define	hyphalg	envp->_hyphalg
+#define	un1	envp->_un1
+#define	tabc	envp->_tabc
+#define	dotc	envp->_dotc
+#define	adsp	envp->_adsp
+#define	adrem	envp->_adrem
+#define	lastl	envp->_lastl
+#define	nel	envp->_nel
+#define	admod	envp->_admod
+#define	wordp	envp->_wordp
+#define	spflg	envp->_spflg
+#define	linep	envp->_linep
+#define	wdend	envp->_wdend
+#define	wdstart	envp->_wdstart
+#define	wne	envp->_wne
+#define	ne	envp->_ne
+#define	nc	envp->_nc
+#define	nb	envp->_nb
+#define	lnmod	envp->_lnmod
+#define	nwd	envp->_nwd
+#define	nn	envp->_nn
+#define	ni	envp->_ni
+#define	ul	envp->_ul
+#define	cu	envp->_cu
+#define	ce	envp->_ce
+#define	in	envp->_in
+#define	in1	envp->_in1
+#define	un	envp->_un
+#define	wch	envp->_wch
+#define	pendt	envp->_pendt
+#define	pendw	envp->_pendw
+#define	pendnf	envp->_pendnf
+#define	spread	envp->_spread
+#define	it	envp->_it
+#define	itmac	envp->_itmac
+#define	hyptr	envp->_hyptr
+#define	tabtab	envp->_tabtab
+#define	line	envp->_line._bufp
+#define	lnsize	envp->_line._size
+#define	word	envp->_word._bufp
+#define wdsize	envp->_word._size
+
+#define oline	_oline._bufp
+#define olnsize	_oline._size
+
+/*
+ * Note:
+ * If this structure changes in ni.c, you must change
+ * this as well, and vice versa.
+ */
+
+struct Env {
+	int	_ics;
+	int	_sps;
+	int	_spacesz;
+	int	_lss;
+	int	_lss1;
+	int	_ll;
+	int	_ll1;
+	int	_lt;
+	int	_lt1;
+	Tchar	_ic;
+	int	_icf;
+	Tchar	_chbits;
+	Tchar	_spbits;
+	Tchar	_nmbits;
+	int	_apts;
+	int	_apts1;
+	int	_pts;
+	int	_pts1;
+	int	_font;
+	int	_font1;
+	int	_ls;
+	int	_ls1;
+	int	_ad;
+	int	_nms;
+	int	_ndf;
+	int	_nmwid;
+	int	_fi;
+	int	_cc;
+	int	_c2;
+	int	_ohc;
+	int	_tdelim;
+	int	_hyf;
+	int	_hyoff;
+	int	_hyphalg;
+	int	_un1;
+	int	_tabc;
+	int	_dotc;
+	int	_adsp;
+	int	_adrem;
+	int	_lastl;
+	int	_nel;
+	int	_admod;
+	Tchar	*_wordp;
+	int	_spflg;
+	Tchar	*_linep;
+	Tchar	*_wdend;
+	Tchar	*_wdstart;
+	int	_wne;
+	int	_ne;
+	int	_nc;
+	int	_nb;
+	int	_lnmod;
+	int	_nwd;
+	int	_nn;
+	int	_ni;
+	int	_ul;
+	int	_cu;
+	int	_ce;
+	int	_in;
+	int	_in1;
+	int	_un;
+	int	_wch;
+	int	_pendt;
+	Tchar	*_pendw;
+	int	_pendnf;
+	int	_spread;
+	int	_it;
+	int	_itmac;
+	Tchar	*_hyptr[NHYP];
+	long	_tabtab[NTAB];
+	Tbuf	_line;
+	Tbuf	_word;
+};
+
+extern	Env	env[];
+extern	Env	*envp;
+
+enum {	MBchar = 'U', Troffchar = 'C', Number = 'N', Install = 'i', Lookup = 'l' };
+	/* U => utf, for instance;  C => \(xx, N => \N'...' */
+
+
+
+struct Chwid {	/* data on one character */
+	Ushort	num;		/* character number:
+					0 -> not on this font
+					>= ALPHABET -> its number among all Cxy's */
+	Ushort	code;		/* char code for actual device.  used for \N */
+	char	*str;		/* code string for nroff */
+	Uchar	wid;		/* width */
+	Uchar	kern;		/* ascender/descender */
+};
+
+struct Font {	/* characteristics of a font */
+	int	name;		/* int name, e.g., BI (2 chars) */
+	char	longname[64];	/* long name of this font (e.g., "Bembo" */
+	char	*truename;	/* path name of table if not in standard place */
+	int	nchars;		/* number of width entries for this font */
+	char	specfont;	/* 1 == special font */
+	int	spacewidth;	/* width of space on this font */
+	int	defaultwidth;	/* default width of characters on this font */
+	Chwid	*wp;		/* widths, etc., of the real characters */
+	char	ligfont;	/* 1 == ligatures exist on this font */
+};
+
+/* ligatures, ORed into ligfont */
+
+#define	LFF	01
+#define	LFI	02
+#define	LFL	04
+#define	LFFI	010
+#define	LFFL	020
+
+/* tracing modes */
+#define TRNARGS	01		/* trace legality of numeric arguments */
+#define TRREQ	02		/* trace requests */
+#define TRMAC	04		/* trace macros */
+#define RQERR	01		/* processing request/macro */
+
+/* typewriter driving table structure */
+
+
+extern	Term	t;
+struct Term {
+	int	bset;		/* these bits have to be on */
+	int	breset;		/* these bits have to be off */
+	int	Hor;		/* #units in minimum horiz motion */
+	int	Vert;		/* #units in minimum vert motion */
+	int	Newline;	/* #units in single line space */
+	int	Char;		/* #units in character width */
+	int	Em;		/* ditto */
+	int	Halfline;	/* half line units */
+	int	Adj;		/* minimum units for horizontal adjustment */
+	char	*twinit;	/* initialize terminal */
+	char	*twrest;	/* reinitialize terminal */
+	char	*twnl;		/* terminal sequence for newline */
+	char	*hlr;		/* half-line reverse */
+	char	*hlf;		/* half-line forward */
+	char	*flr;		/* full-line reverse */
+	char	*bdon;		/* turn bold mode on */
+	char	*bdoff;		/* turn bold mode off */
+	char	*iton;		/* turn italic mode on */
+	char	*itoff;		/* turn italic mode off */
+	char	*ploton;	/* turn plot mode on */
+	char	*plotoff;	/* turn plot mode off */
+	char	*up;		/* sequence to move up in plot mode */
+	char	*down;		/* ditto */
+	char	*right;		/* ditto */
+	char	*left;		/* ditto */
+
+	Font	tfont;		/* widths and other info, as in a troff font */
+};
+
+extern	Term	t;
+
+/*
+ * for error reporting; keep track of escapes/requests with numeric arguments
+ */
+struct Numerr {
+	char	type;	/* request or escape? */
+	char	esc;	/* was escape sequence named esc */
+	char	escarg;	/* argument of esc's like \D'l' */
+	unsigned int	req;	/* was request or macro named req */
+};
blob - /dev/null
blob + 67aed817b4e4fffc6f1f9121b5e0617014c966f8 (mode 644)
--- /dev/null
+++ src/cmd/troff/unansi
@@ -0,0 +1,49 @@
+# The awk program cvt will convert the relatively sterotyped ansi c
+# in this troff distribution into older-style c, by munging function
+# declarations.
+
+# You will also have to edit fns.h, by
+#	sed 's/(.*)/()/g' fns.h >foo; mv foo fns.h
+# check this before doing the move!
+
+# you will also have to make some editing changes in
+# tdef.h in the Contab structure: s/(void)/()/
+# you may have to fix up some function declarations
+# in n4.c, the ones with (*f)(Tchar).
+
+# you will surely also have header files to deal with.
+
+# the most obvious cases are dealt with by the following
+# commands.  make sure you do this stuff on a copy!
+
+# function prototypes in n8.c probably belong in fns.h. readpats(void) must
+# be readpats() before cvt runs.
+
+sed \
+	-e 's/(void)/()/' \
+	-e 's/(Tchar[^)]*);/();/' \
+	-e 's/(char[^)]*);/();/' \
+	-e 's/(int[^)]*);/();/' \
+n8.c >foo
+mv foo n8.c
+
+for i in *.c
+do
+	cvt $i >foo
+	mv foo $i
+done
+
+sed 's/(.*)/()/g' fns.h >foo
+mv foo fns.h
+
+sed -e 's/(void)/()/g' -e '/stdlib/d' tdef.h >foo
+mv foo tdef.h
+
+# Compliers may not approve of void *setbrk() in fns.h and n3.c.
+
+sed 's/^void\*[ 	]setbrk/char*	setbrk/' fns.h >foo
+mv foo fns.h
+
+sed 's/^void \*setbrk/char *setbrk/' n3.c >foo
+mv foo n3.c
+