shithub: neatroff

Download patch

ref: e09893889703797eb671aa56f59e109da1caa569
parent: cb39077a4a8e2be1b11b02c0f3f93730f8de4658
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sun Oct 13 13:08:11 EDT 2013

map: more compact mapping of register names

Now only ".x" built-in style names have predefined indices.

--- a/map.c
+++ b/map.c
@@ -2,7 +2,9 @@
 #include <string.h>
 #include "roff.h"
 
-/* register, macro, or environments names with more than two characters */
+#define MAPBEG		256	/* the entries reserved for .x names */
+
+/* register, macro, or environments names */
 static char keys[NREGS][GNLEN];
 static int nkeys = 1;
 /* per starting character name lists */
@@ -14,11 +16,15 @@
 {
 	int head = (unsigned char) s[0];
 	int i = key_head[head];
+	if (*s == '\0')
+		return 0;
 	while (i > 0) {
-		if (!strcmp(keys[i], s))
+		if (keys[i][1] == s[1] && !strcmp(keys[i], s))
 			return i;
 		i = key_next[i];
 	}
+	if (nkeys >= NREGS - MAPBEG)
+		errdie("neatroff: out of register names (NREGS)\n");
 	i = nkeys++;
 	strcpy(keys[i], s);
 	key_next[i] = key_head[head];
@@ -26,22 +32,22 @@
 	return i;
 }
 
-/* map register names to [0..NREGS * 2) */
+/* map register names to [0..NREGS] */
 int map(char *s)
 {
-	if (n_cp || !s[1] || !s[2])
-		return REG(s[0], s[1]);
-	return NREGS + key_get(s);
+	if (s[0] == '.' && s[1] && !s[2])	/* ".x" is mapped to 'x' */
+		return (unsigned char) s[1];
+	return MAPBEG + key_get(s);
 }
 
-/* returns a static buffer */
+/* return the name mapped to id; 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;
+	if (id >= MAPBEG)
+		return keys[id - MAPBEG];
+	map_buf[0] = '.';
+	map_buf[1] = id;
 	map_buf[2] = '\0';
 	return map_buf;
 }
--- a/reg.c
+++ b/reg.c
@@ -19,15 +19,15 @@
 	char mc[GNLEN];		/* margin character (.mc) */
 };
 
-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 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[NREGS];/* environments */
 static struct env *env;		/* current enviroment */
 static int env_id;		/* current environment id */
-static int eregs_idx[NREGS2];	/* register environment index in eregs[] */
+static int eregs_idx[NREGS];	/* register environment index in eregs[] */
 
 static char *eregs[] = {	/* environment-specific number registers */
 	"ln", ".f", ".i", ".j", ".l",
@@ -34,9 +34,9 @@
 	".L", ".nI", ".nm", ".nM", ".nn",
 	".nS", ".m", ".s", ".u", ".v",
 	".it", ".itn", ".mc", ".mcn",
-	"\0c", "\0f", "\0h", "\0i", "\0l",
-	"\0L", "\0n", "\0m", "\0p", "\0s",
-	"\0t", "\0T", "\0v",
+	".ce", ".f0", ".hy", ".i0", ".l0",
+	".L0", ".m0", ".n0", ".s0", ".ss",
+	".lt", ".lt0", ".v0",
 };
 
 /* return the address of a number register */
@@ -53,40 +53,43 @@
 char *num_str(int id)
 {
 	static char numbuf[128];
+	char *s = map_name(id);
 	numbuf[0] = '\0';
-	switch (id) {
-	case REG('.', 'b'):
-		sprintf(numbuf, "%d", dev_getbd(n_f));
-		break;
-	case REG('.', 'c'):
-		sprintf(numbuf, "%d", in_lnum());
-		break;
-	case REG('.', 'k'):
-		sprintf(numbuf, "%d", f_hpos());
-		break;
-	case REG('.', 'm'):
-		sprintf(numbuf, "#%02x%02x%02x", CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
-		break;
-	case REG('.', 't'):
-		sprintf(numbuf, "%d", f_nexttrap());
-		break;
-	case REG('.', 'z'):
-		if (f_divreg() >= 0)
-			sprintf(numbuf, "%s", map_name(f_divreg()));
-		break;
-	case REG('.', 'F'):
-		sprintf(numbuf, "%s", in_filename());
-		break;
-	case REG('.', '$'):
-		sprintf(numbuf, "%d", in_nargs());
-		break;
-	case REG('y', 'r'):
+	if (s[0] == '.' && !s[2]) {
+		switch (s[1]) {
+		case 'b':
+			sprintf(numbuf, "%d", dev_getbd(n_f));
+			return numbuf;
+		case 'c':
+			sprintf(numbuf, "%d", in_lnum());
+			return numbuf;
+		case 'k':
+			sprintf(numbuf, "%d", f_hpos());
+			return numbuf;
+		case 'm':
+			sprintf(numbuf, "#%02x%02x%02x", CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
+			return numbuf;
+		case 't':
+			sprintf(numbuf, "%d", f_nexttrap());
+			return numbuf;
+		case 'z':
+			if (f_divreg() >= 0)
+				sprintf(numbuf, "%s", map_name(f_divreg()));
+			return numbuf;
+		case 'F':
+			sprintf(numbuf, "%s", in_filename());
+			return numbuf;
+		case '$':
+			sprintf(numbuf, "%d", in_nargs());
+			return numbuf;
+		}
+	}
+	if (id == map("yr")) {
 		sprintf(numbuf, "%02d", nregs[id]);
-		break;
-	default:
-		if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
-			sprintf(numbuf, "%d", *nreg(id));
+		return numbuf;
 	}
+	if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
+		sprintf(numbuf, "%d", *nreg(id));
 	return numbuf;
 }
 
@@ -207,10 +210,10 @@
 {
 	time_t t = time(NULL);
 	struct tm *tm = localtime(&t);
-	nregs[REG('d', 'w')] = tm->tm_wday + 1;
-	nregs[REG('d', 'y')] = tm->tm_mday;
-	nregs[REG('m', 'o')] = tm->tm_mon + 1;
-	nregs[REG('y', 'r')] = tm->tm_year % 100;
+	nregs[map("dw")] = tm->tm_wday + 1;
+	nregs[map("dy")] = tm->tm_mday;
+	nregs[map("mo")] = tm->tm_mon + 1;
+	nregs[map("yr")] = tm->tm_year % 100;
 }
 
 void env_init(void)
--- a/ren.c
+++ b/ren.c
@@ -306,7 +306,7 @@
 	wb_done(&wb);
 }
 
-/* return 1 if triggered a trap */
+/* output current line; returns 1 if triggered a trap */
 static int ren_bradj(struct adj *adj, int fill, int ad, int body)
 {
 	char cmd[16];
@@ -356,7 +356,7 @@
 	return 0;
 }
 
-/* return 1 if triggered a trap */
+/* output current line; returns 1 if triggered a trap */
 static int ren_br(int force)
 {
 	int ad = n_j;
@@ -900,7 +900,6 @@
 int render(void)
 {
 	struct wb *wb = &ren_wb;
-	int fillreq;
 	int c;
 	n_nl = -1;
 	wb_init(wb);
@@ -925,14 +924,11 @@
 			continue;
 		}
 		ren_cnl = c == '\n';
-		fillreq = 0;
 		/* add wb (the current word) to cadj */
 		if (c == ' ' || c == '\n') {
 			adj_swid(cadj, spacewid(n_f, n_s));
 			if (!wb_part(wb)) {	/* not after a \c */
 				adj_wb(cadj, wb);
-				fillreq = ren_fillreq;
-				ren_fillreq = 0;
 				if (c == '\n')
 					adj_nl(cadj);
 				else
@@ -939,9 +935,13 @@
 					adj_sp(cadj);
 			}
 		}
-		while ((fillreq && !n_ce && n_u) || adj_full(cadj, !n_ce && n_u)) {
-			ren_br(0);
-			fillreq = 0;
+		/* flush the line if necessary */
+		if (c == ' ' || c == '\n') {
+			while ((ren_fillreq && !wb_part(wb) && !n_ce && n_u) ||
+						adj_full(cadj, !n_ce && n_u)) {
+				ren_br(0);
+				ren_fillreq = 0;
+			}
 		}
 		if (c == '\n' || ren_nl)	/* end or start of input line */
 			n_lb = f_hpos();
--- a/roff.c
+++ b/roff.c
@@ -8,6 +8,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include "roff.h"
 
 static void g_init(void)
@@ -26,6 +27,12 @@
 	va_end(ap);
 }
 
+void errdie(char *msg)
+{
+	fprintf(stderr, msg);
+	exit(1);
+}
+
 static char *usage =
 	"Usage: neatcc [options] input\n"
 	"Options:\n"
@@ -79,7 +86,7 @@
 		in_queue(NULL);	/* reading from standard input */
 	for (; i < argc; i++)
 		in_queue(!strcmp("-", argv[i]) ? NULL : argv[i]);
-	str_set(REG('.', 'P'), macrodir);
+	str_set(map(".P"), macrodir);
 	out("s%d\n", n_s);
 	out("f%d\n", n_f);
 	ret = render();
--- a/roff.h
+++ b/roff.h
@@ -325,6 +325,7 @@
 
 /* helpers */
 void errmsg(char *msg, ...);
+void errdie(char *msg);
 int utf8len(int c);
 int utf8next(char *s, int (*next)(void));
 int utf8read(char **s, char *d);
@@ -347,13 +348,12 @@
 #define TR_DIVEND	"\07>"	/* diversion ends */
 #define TR_EJECT	"\07P"	/* page eject */
 
-/* mapping register, macro and environment names to numbers */
-#define NREGS		(1 << 16)
-#define NREGS2		(NREGS * 2)
-#define REG(c1, c2)	((c1) * 256 + (c2))
+/* mapping register, macro and environment names to indices */
+#define NREGS		4096	/* maximum number of mapped names */
+#define DOTMAP(c2)	(c2)	/* optimized mapping for ".x" names */
 
-int map(char *s);
-char *map_name(int id);
+int map(char *s);		/* map name s to an index */
+char *map_name(int id);		/* return the name mapped to id */
 
 /* colors */
 #define CLR_R(c)		(((c) >> 16) & 0xff)
@@ -365,59 +365,59 @@
 int clr_get(char *s);
 
 /* 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')))
-#define n_i		(*nreg(REG('.', 'i')))
+#define n_a		(*nreg(DOTMAP('a')))
+#define n_cp		(*nreg(DOTMAP('C')))
+#define n_d		(*nreg(DOTMAP('d')))
+#define n_f		(*nreg(DOTMAP('f')))
+#define n_h		(*nreg(DOTMAP('h')))
+#define n_i		(*nreg(DOTMAP('i')))
 #define n_it		(*nreg(map(".it")))	/* .it trap macro */
 #define n_itn		(*nreg(map(".itn")))	/* .it lines left */
-#define n_j		(*nreg(REG('.', 'j')))
-#define n_l		(*nreg(REG('.', 'l')))
-#define n_L		(*nreg(REG('.', 'L')))
-#define n_n		(*nreg(REG('.', 'n')))
+#define n_j		(*nreg(DOTMAP('j')))
+#define n_l		(*nreg(DOTMAP('l')))
+#define n_L		(*nreg(DOTMAP('L')))
+#define n_n		(*nreg(DOTMAP('n')))
 #define n_nI		(*nreg(map(".nI")))	/* i for .nm */
 #define n_nm		(*nreg(map(".nm")))	/* .nm enabled */
 #define n_nM		(*nreg(map(".nM")))	/* m for .nm */
 #define n_nn		(*nreg(map(".nn")))	/* remaining .nn */
 #define n_nS		(*nreg(map(".nS")))	/* s for .nm */
-#define n_m		(*nreg(REG('.', 'm')))
+#define n_m		(*nreg(DOTMAP('m')))
 #define n_mc		(*nreg(map(".mc")))	/* .mc enabled */
 #define n_mcn		(*nreg(map(".mcn")))	/* .mc distance */
-#define n_o		(*nreg(REG('.', 'o')))
-#define n_p		(*nreg(REG('.', 'p')))
-#define n_s		(*nreg(REG('.', 's')))
-#define n_u		(*nreg(REG('.', 'u')))
-#define n_v		(*nreg(REG('.', 'v')))
-#define n_ct		(*nreg(REG('c', 't')))
-#define n_dl		(*nreg(REG('d', 'l')))
-#define n_dn		(*nreg(REG('d', 'n')))
-#define n_ln		(*nreg(REG('l', 'n')))
-#define n_nl		(*nreg(REG('n', 'l')))
-#define n_sb		(*nreg(REG('s', 'b')))
-#define n_st		(*nreg(REG('s', 't')))
-#define n_pg		(*nreg(REG('%', '\0')))	/* % */
-#define n_lb		(*nreg(REG(0, 'b')))	/* input line beg */
-#define n_ce		(*nreg(REG(0, 'c')))	/* .ce remaining */
-#define n_f0		(*nreg(REG(0, 'f')))	/* last .f */
-#define n_lg		(*nreg(REG(0, 'g')))	/* .lg mode */
-#define n_hy		(*nreg(REG(0, 'h')))	/* .hy mode */
-#define n_i0		(*nreg(REG(0, 'i')))	/* last .i */
-#define n_kn		(*nreg(REG(0, 'k')))	/* .kn mode */
-#define n_l0		(*nreg(REG(0, 'l')))	/* last .l */
-#define n_L0		(*nreg(REG(0, 'L')))	/* last .L */
-#define n_m0		(*nreg(REG(0, 'm')))	/* last .m */
-#define n_mk		(*nreg(REG(0, 'M')))	/* .mk internal register */
-#define n_na		(*nreg(REG(0, 'n')))	/* .na mode */
-#define n_ns		(*nreg(REG(0, 'N')))	/* .ns mode */
-#define n_o0		(*nreg(REG(0, 'o')))	/* last .o */
-#define n_ss		(*nreg(REG(0, 'p')))	/* .ss value */
-#define n_s0		(*nreg(REG(0, 's')))	/* last .s */
-#define n_sv		(*nreg(REG(0, 'S')))	/* .sv value */
-#define n_lt		(*nreg(REG(0, 't')))	/* .lt value */
-#define n_t0		(*nreg(REG(0, 'T')))	/* previous .lt value */
-#define n_v0		(*nreg(REG(0, 'v')))	/* last .v */
+#define n_o		(*nreg(DOTMAP('o')))
+#define n_p		(*nreg(DOTMAP('p')))
+#define n_s		(*nreg(DOTMAP('s')))
+#define n_u		(*nreg(DOTMAP('u')))
+#define n_v		(*nreg(DOTMAP('v')))
+#define n_ct		(*nreg(map("ct")))
+#define n_dl		(*nreg(map("dl")))
+#define n_dn		(*nreg(map("dn")))
+#define n_ln		(*nreg(map("ln")))
+#define n_nl		(*nreg(map("nl")))
+#define n_sb		(*nreg(map("sb")))
+#define n_st		(*nreg(map("st")))
+#define n_pg		(*nreg(map("%")))	/* % */
+#define n_lb		(*nreg(map(".b0")))	/* input line beg */
+#define n_ce		(*nreg(map(".ce")))	/* .ce remaining */
+#define n_f0		(*nreg(map(".f0")))	/* last .f */
+#define n_lg		(*nreg(map(".lg")))	/* .lg mode */
+#define n_hy		(*nreg(map(".hy")))	/* .hy mode */
+#define n_i0		(*nreg(map(".i0")))	/* last .i */
+#define n_kn		(*nreg(map(".kern")))	/* .kn mode */
+#define n_l0		(*nreg(map(".l0")))	/* last .l */
+#define n_L0		(*nreg(map(".L0")))	/* last .L */
+#define n_m0		(*nreg(map(".m0")))	/* last .m */
+#define n_mk		(*nreg(map(".mk")))	/* .mk internal register */
+#define n_na		(*nreg(map(".na")))	/* .na mode */
+#define n_ns		(*nreg(map(".ns")))	/* .ns mode */
+#define n_o0		(*nreg(map(".o0")))	/* last .o */
+#define n_ss		(*nreg(map(".ss")))	/* .ss value */
+#define n_s0		(*nreg(map(".s0")))	/* last .s */
+#define n_sv		(*nreg(map(".sv")))	/* .sv value */
+#define n_lt		(*nreg(map(".lt")))	/* .lt value */
+#define n_t0		(*nreg(map(".lt0")))	/* previous .lt value */
+#define n_v0		(*nreg(map(".v0")))	/* last .v */
 
 /* functions for implementing read-only registers */
 int f_nexttrap(void);	/* .t */
--- a/tr.c
+++ b/tr.c
@@ -336,7 +336,7 @@
 {
 	int c = cp_next();
 	if (c >= 0 && c == c_pc) {
-		in_push(num_str(REG('%', '\0')), NULL);
+		in_push(num_str(map("%")), NULL);
 		c = cp_next();
 	}
 	return c;