shithub: neatroff

Download patch

ref: 7e51746ad98afe340fb62e9ea196d77414401fd7
parent: 8b5fcf6aa4de48b8d5f2e75da580a4556277c1cf
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat Jul 6 21:01:29 EDT 2013

tr: long register/macro names and named environments

--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
 all: roff
 %.o: %.c roff.h
 	$(CC) -c $(CFLAGS) $<
-roff: roff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o draw.o wb.o hyph.o
+roff: roff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o draw.o wb.o hyph.o map.o
 	$(CC) -o $@ $^ $(LDFLAGS)
 clean:
 	rm -f *.o roff
--- a/cp.c
+++ b/cp.c
@@ -10,6 +10,8 @@
 
 static int regid(void)
 {
+	char key[NMLEN];
+	int i = 0;
 	int c1;
 	int c2 = 0;
 	c1 = cp_next();
@@ -16,6 +18,14 @@
 	if (c1 == '(') {
 		c1 = cp_next();
 		c2 = cp_next();
+	} else if (!n_cp && c1 == '[') {
+		c1 = cp_next();
+		while (i < NMLEN - 1 && c1 >= 0 && c1 != ']') {
+			key[i++] = c1;
+			c1 = cp_next();
+		}
+		key[i] = '\0';
+		return map(key);
 	}
 	return REG(c1, c2);
 }
--- /dev/null
+++ b/map.c
@@ -1,0 +1,31 @@
+#include <stdio.h>
+#include <string.h>
+#include "roff.h"
+
+static char keys[NREGS][GNLEN];
+static int nkeys;
+
+/* map register names to [0..NREGS * 2) */
+int map(char *s)
+{
+	int i;
+	if (n_cp || !s[1] || !s[2])
+		return REG(s[0], s[1]);
+	for (i = 0; i < nkeys; i++)
+		if (keys[i][0] == s[0] && !strcmp(keys[i], s))
+			return NREGS + i;
+	strcpy(keys[nkeys++], s);
+	return NREGS + nkeys - 1;
+}
+
+/* returns a static buffer */
+char *map_name(int id)
+{
+	static char map_buf[NMLEN];
+	if (id >= NREGS)
+		return keys[id - NREGS];
+	map_buf[0] = (id >> 8) & 0xff;
+	map_buf[1] = id & 0xff;
+	map_buf[2] = '\0';
+	return map_buf;
+}
--- a/out.c
+++ b/out.c
@@ -92,6 +92,12 @@
 			s++;
 			*d++ = *s++;
 			*d++ = *s++;
+		} else if (!n_cp && *s == '[') {
+			s++;
+			while (*s && *s != ']')
+				*d++ = *s++;
+			if (*s == ']')
+				s++;
 		} else {
 			*d++ = *s++;
 			if (cmd == 's' && s[-1] >= '1' && s[-1] <= '3')
@@ -170,6 +176,7 @@
  */
 int out_readc(char **s, char *d)
 {
+	char *r = d;
 	if (!**s)
 		return -1;
 	utf8read(s, d);
@@ -178,6 +185,11 @@
 		if (d[1] == '(') {
 			utf8read(s, d);
 			utf8read(s, d + strlen(d));
+		} else if (!n_cp && d[1] == '[') {
+			while (**s && **s != ']')
+				*r++ = *(*s)++;
+			if (**s == ']')
+				(*s)++;
 		} else if (strchr("CDfhsvXx", d[1])) {
 			int c = d[1];
 			escarg(s, d, d[1]);
--- a/reg.c
+++ b/reg.c
@@ -6,8 +6,7 @@
 #include <time.h>
 #include "roff.h"
 
-#define NREGS		(1 << 16)
-#define NENVS		(1 << 5)
+#define NENVS		32	/* number of environment registers */
 
 struct env {
 	int eregs[NENVS];	/* environment-specific number registers */
@@ -16,13 +15,14 @@
 	char hc[GNLEN];		/* hyphenation character */
 };
 
-static int nregs[NREGS];	/* global number registers */
-static int nregs_inc[NREGS];	/* number register auto-increment size */
-static int nregs_fmt[NREGS];	/* number register format */
-static char *sregs[NREGS];	/* global string registers */
-static void *sregs_dat[NREGS];	/* builtin function data */
-static struct env envs[3];	/* environments */
+static int nregs[NREGS2];	/* global number registers */
+static int nregs_inc[NREGS2];	/* number register auto-increment size */
+static int nregs_fmt[NREGS2];	/* number register format */
+static char *sregs[NREGS2];	/* global string registers */
+static void *sregs_dat[NREGS2];	/* builtin function data */
+static struct env *envs[NREGS2];/* environments */
 static struct env *env;		/* current enviroment */
+static int env_id;		/* current environment id */
 static int eregs_idx[NREGS];	/* register environment index in eregs[] */
 
 static int eregs[] = {		/* environment-specific number registers */
@@ -55,13 +55,6 @@
 	return &nregs[id];
 }
 
-static void reg_name(char *s, int id)
-{
-	s[0] = (id >> 8) & 0xff;
-	s[1] = id & 0xff;
-	s[3] = '\0';
-}
-
 static int num_fmt(char *s, int n, int fmt);
 
 /* the contents of a number register (returns a static buffer) */
@@ -78,7 +71,7 @@
 		break;
 	case REG('.', 'z'):
 		if (f_divreg() >= 0)
-			reg_name(numbuf, f_divreg());
+			sprintf(numbuf, "%s", map_name(f_divreg()));
 		break;
 	case REG('.', 'F'):
 		sprintf(numbuf, "%s", in_filename());
@@ -162,12 +155,28 @@
 	sregs_dat[src] = NULL;
 }
 
+static struct env *env_alloc(void)
+{
+	struct env *env = malloc(sizeof(*env));
+	memset(env, 0, sizeof(*env));
+	env->adj = adj_alloc();
+	return env;
+}
+
+static void env_free(struct env *env)
+{
+	adj_free(env->adj);
+	free(env);
+}
+
 static void env_set(int id)
 {
 	int i;
-	env = &envs[id];
-	if (!env->adj) {
-		env->adj = adj_alloc();
+	env = envs[id];
+	env_id = id;
+	if (!env) {
+		envs[id] = env_alloc();
+		env = envs[id];
 		n_f = 1;
 		n_i = 0;
 		n_j = AD_B;
@@ -208,12 +217,12 @@
 	env_set(0);
 }
 
-void env_free(void)
+void env_done(void)
 {
 	int i;
 	for (i = 0; i < LEN(envs); i++)
-		if (envs[i].adj)
-			adj_free(envs[i].adj);
+		if (envs[i])
+			env_free(envs[i]);
 }
 
 static int oenv[NPREV];		/* environment stack */
@@ -221,13 +230,15 @@
 
 void tr_ev(char **args)
 {
-	int id = args[1] ? atoi(args[1]) : -1;
-	if (id < 0 && nenv)
-		id = oenv[--nenv];
-	if (id >= LEN(envs) || id < 0)
+	int id = -1;
+	if (args[1])
+		id = map(args[1]);
+	else
+		id = nenv ? oenv[--nenv] : -1;
+	if (id < 0)
 		return;
 	if (args[1] && env && nenv < NPREV)
-		oenv[nenv++] = env - envs;
+		oenv[nenv++] = env_id;
 	env_set(id);
 }
 
--- a/ren.c
+++ b/ren.c
@@ -56,7 +56,7 @@
 		cdiv = cdiv ? cdiv + 1 : divs;
 		memset(cdiv, 0, sizeof(*cdiv));
 		sbuf_init(&cdiv->sbuf);
-		cdiv->reg = REG(args[1][0], args[1][1]);
+		cdiv->reg = map(args[1]);
 		cdiv->treg = -1;
 		if (args[0][2] == 'a' && str_get(cdiv->reg))	/* .da */
 			sbuf_append(&cdiv->sbuf, str_get(cdiv->reg));
@@ -323,7 +323,7 @@
 void tr_mk(char **args)
 {
 	if (args[1])
-		num_set(REG(args[1][0], args[1][1]), n_d);
+		num_set(map(args[1]), n_d);
 	else
 		n_mk = n_d;
 }
@@ -498,6 +498,12 @@
 		if (c == '(') {
 			*d++ = next();
 			*d++ = next();
+		} else if (!n_cp && c == '[') {
+			c = next();
+			while (c > 0 && c != '\n' && c != ']') {
+				*d++ = c;
+				c = next();
+			}
 		} else {
 			*d++ = c;
 			if (cmd == 's' && c >= '1' && c <= '3') {
@@ -560,8 +566,7 @@
 		wb_hmov(wb, eval(arg, 'm'));
 		break;
 	case 'k':
-		num_set(REG(arg[0], arg[1]),
-			RENWB(wb) ? f_hpos() - n_lb : wb_wid(wb));
+		num_set(map(arg), RENWB(wb) ? f_hpos() - n_lb : wb_wid(wb));
 		break;
 	case 'L':
 		ren_vline(wb, arg);
@@ -621,7 +626,7 @@
 	char c[GNLEN * 4];
 	char arg[ILNLEN];
 	char *s;
-	int w, n;
+	int w, n, l;
 	nextchar(c, next);
 	if (c[0] == ' ' || c[0] == '\n') {
 		wb_put(wb, c);
@@ -639,9 +644,17 @@
 	if (c[0] == c_ec) {
 		nextchar(c + 1, next);
 		if (c[1] == '(') {
-			int l = nextchar(c + 2, next);
+			l = nextchar(c + 2, next);
 			l += nextchar(c + 2 + l, next);
 			c[2 + l] = '\0';
+		} else if (!n_cp && c[1] == '[') {
+			l = 0;
+			n = next();
+			while (n >= 0 && n != '\n' && n != ']' && l < GNLEN - 1) {
+				c[l++] = n;
+				n = next();
+			}
+			c[l] = '\0';
 		} else if (c[1] == 'z') {
 			w = wb_wid(wb);
 			ren_char(wb, next, back);
@@ -898,7 +911,7 @@
 			treg[id] = -1;
 		return;
 	}
-	reg = REG(args[2][0], args[2][1]);
+	reg = map(args[2]);
 	if (id < 0)
 		id = trap_byreg(-1);
 	if (id < 0)
@@ -913,7 +926,7 @@
 	int id;
 	if (!args[1])
 		return;
-	reg = REG(args[1][0], args[1][1]);
+	reg = map(args[1]);
 	id = trap_byreg(reg);
 	if (id >= 0)
 		tpos[id] = args[2] ? eval(args[2], 'v') : -1;
@@ -925,7 +938,7 @@
 		return;
 	if (args[2]) {
 		cdiv->tpos = eval(args[1], 'v');
-		cdiv->treg = REG(args[2][0], args[2][1]);
+		cdiv->treg = map(args[2]);
 	} else {
 		cdiv->treg = -1;
 	}
@@ -933,7 +946,7 @@
 
 void tr_em(char **args)
 {
-	trap_em = args[1] ? REG(args[1][0], args[1][1]) : -1;
+	trap_em = args[1] ? map(args[1]) : -1;
 }
 
 static int trap_pos(int pos)
--- a/roff.c
+++ b/roff.c
@@ -45,6 +45,8 @@
 	for (i = 1; i < argc; i++) {
 		if (argv[i][0] != '-' || !argv[i][0])
 			break;
+		if (argv[i][1] == 'C')
+			n_cp = 1;
 		if (argv[i][1] == 'm') {
 			sprintf(path, TROFFROOT "/tmac/tmac.%s", argv[i] + 2);
 			in_queue(path);
@@ -56,7 +58,7 @@
 		in_queue(!strcmp("-", argv[i]) ? NULL : argv[i]);
 	str_set(REG('.', 'P'), TROFFROOT);
 	compile();
-	env_free();
+	env_done();
 	dev_close();
 	return 0;
 }
--- a/roff.h
+++ b/roff.h
@@ -13,12 +13,13 @@
 #define NKERNS		128	/* number of font pairwise kerning pairs */
 #define FNLEN		32	/* font name length */
 #define NGLYPHS		512	/* glyphs in fonts */
-#define GNLEN		32	/* glyph name length */
+#define NMLEN		32	/* macro/register/environment/glyph name length */
+#define GNLEN		NMLEN	/* glyph name length */
+#define RNLEN		NMLEN	/* register/macro name */
 #define ILNLEN		1000	/* line limit of input files */
 #define LNLEN		4000	/* line buffer length (ren.c/out.c) */
 #define NWORDS		256	/* number of words in line buffer */
 #define NARGS		9	/* number of macro arguments */
-#define RLEN		4	/* register/macro name */
 #define NPREV		16	/* environment stack depth */
 #define NTRAPS		1024	/* number of traps per page */
 #define NIES		128	/* number of nested .ie commands */
@@ -54,6 +55,10 @@
 int eval_up(char **s, int unit);
 int eval_re(char *s, int orig, int unit);
 
+/* mapping register, macro and environment names to numbers */
+int map(char *s);
+char *map_name(int id);
+
 /* string registers */
 void str_set(int id, char *s);
 void str_dset(int id, void *d);
@@ -68,7 +73,7 @@
 
 /* enviroments */
 void env_init(void);
-void env_free(void);
+void env_done(void);
 struct adj *env_adj(void);
 char *env_hc(void);
 int tab_next(int pos);
@@ -298,9 +303,14 @@
 #define TR_DIVEND	"\07>"	/* diversion ends */
 #define TR_EJECT	"\07P"	/* page eject */
 
-/* builtin number registers; n_X for .X register */
+/* register mapping */
+#define NREGS		(1 << 16)
+#define NREGS2		(NREGS * 2)
 #define REG(c1, c2)	((c1) * 256 + (c2))
+
+/* builtin number registers; n_X for .X register */
 #define n_a		(*nreg(REG('.', 'a')))
+#define n_cp		(*nreg(REG('.', 'C')))
 #define n_d		(*nreg(REG('.', 'd')))
 #define n_f		(*nreg(REG('.', 'f')))
 #define n_h		(*nreg(REG('.', 'h')))
--- a/tr.c
+++ b/tr.c
@@ -44,7 +44,7 @@
 	int id;
 	if (!args[2])
 		return;
-	id = REG(args[1][0], args[1][1]);
+	id = map(args[1]);
 	num_set(id, eval_re(args[2], num_get(id, 0), 'u'));
 	num_inc(id, args[3] ? eval(args[3], 'u') : 0);
 }
@@ -54,19 +54,19 @@
 	int i;
 	for (i = 1; i <= NARGS; i++)
 		if (args[i])
-			num_del(REG(args[i][0], args[i][1]));
+			num_del(map(args[i]));
 }
 
 static void tr_af(char **args)
 {
 	if (args[2])
-		num_setfmt(REG(args[1][0], args[1][1]), args[2]);
+		num_setfmt(map(args[1]), args[2]);
 }
 
 static void tr_ds(char **args)
 {
 	if (args[2])
-		str_set(REG(args[1][0], args[1][1]), args[2]);
+		str_set(map(args[1]), args[2]);
 }
 
 static void tr_as(char **args)
@@ -75,7 +75,7 @@
 	char *s1, *s2, *s;
 	if (!args[2])
 		return;
-	reg = REG(args[1][0], args[1][1]);
+	reg = map(args[1]);
 	s1 = str_get(reg) ? str_get(reg) : "";
 	s2 = args[2];
 	s = malloc(strlen(s1) + strlen(s2) + 1);
@@ -90,7 +90,7 @@
 	int i;
 	for (i = 1; i <= NARGS; i++)
 		if (args[i])
-			str_rm(REG(args[i][0], args[i][1]));
+			str_rm(map(args[i]));
 }
 
 static void tr_rn(char **args)
@@ -97,7 +97,7 @@
 {
 	if (!args[2])
 		return;
-	str_rn(REG(args[1][0], args[1][1]), REG(args[2][0], args[2][1]));
+	str_rn(map(args[1]), map(args[2]));
 }
 
 static void tr_po(char **args)
@@ -111,7 +111,7 @@
 
 static void macrobody(struct sbuf *sbuf, char *end)
 {
-	char buf[4];
+	char buf[NMLEN];
 	int i, c;
 	int first = 1;
 	cp_back('\n');
@@ -123,8 +123,9 @@
 		if (c == '\n') {
 			c = cp_next();
 			if (c == '.') {
-				arg_regname(buf, 4);
-				if (buf[0] == end[0] && buf[1] == end[1]) {
+				arg_regname(buf, sizeof(buf));
+				if ((n_cp && end[0] == buf[0] && end[1] == buf[1]) ||
+							!strcmp(end, buf)) {
 					jmp_eol();
 					break;
 				}
@@ -148,7 +149,7 @@
 	int id;
 	if (!args[1])
 		return;
-	id = REG(args[1][0], args[1][1]);
+	id = map(args[1]);
 	sbuf_init(&sbuf);
 	if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
 		sbuf_append(&sbuf, str_get(id));
@@ -428,9 +429,15 @@
 		n_kn = atoi(args[1]);
 }
 
+static void tr_cp(char **args)
+{
+	if (args[1])
+		n_cp = atoi(args[1]);
+}
+
 static char *arg_regname(char *s, int len)
 {
-	char *e = s + 2;
+	char *e = n_cp ? s + 2 : s + len;
 	int c = cp_next();
 	while (c == ' ' || c == '\t')
 		c = cp_next();
@@ -608,6 +615,7 @@
 	{"cc", tr_cc},
 	{"ce", tr_ce},
 	{"ch", tr_ch},
+	{"cp", tr_cp},
 	{"da", tr_di},
 	{"de", tr_de, mkargs_reg1},
 	{"di", tr_di},
@@ -670,7 +678,7 @@
 	int c = cp_next();
 	int nl = c == '\n';
 	char *args[NARGS + 3] = {NULL};
-	char cmd[RLEN];
+	char cmd[RNLEN];
 	char buf[LNLEN];
 	struct cmd *req;
 	while (tr_nl && c >= 0 && (c == c_cc || c == c_c2)) {
@@ -680,7 +688,7 @@
 		cmd[0] = c;
 		req = NULL;
 		arg_regname(cmd + 1, sizeof(cmd) - 1);
-		req = str_dget(REG(cmd[1], cmd[2]));
+		req = str_dget(map(cmd + 1));
 		if (req) {
 			if (req->args)
 				req->args(args + 1, buf, sizeof(buf));
@@ -691,8 +699,8 @@
 			cp_wid(0);
 			mkargs(args + 1, buf, sizeof(buf));
 			cp_wid(1);
-			if (str_get(REG(cmd[1], cmd[2])))
-				in_push(str_get(REG(cmd[1], cmd[2])), args + 1);
+			if (str_get(map(cmd + 1)))
+				in_push(str_get(map(cmd + 1)), args + 1);
 		}
 		c = cp_next();
 		nl = c == '\n';
@@ -705,7 +713,7 @@
 {
 	int i;
 	for (i = 0; i < LEN(cmds); i++)
-		str_dset(REG(cmds[i].id[0], cmds[i].id[1]), &cmds[i]);
+		str_dset(map(cmds[i].id), &cmds[i]);
 }
 
 void tr_first(void)