shithub: neatroff

Download patch

ref: 3e4d65567e5b609fa8532915fcde566c6a40b120
parent: 0459f7fcd938752ba827be6bea9de78eb2bd137e
author: Ali Gholami Rudi <ali@rudi.ir>
date: Wed Apr 10 14:35:19 EDT 2013

ren: page and diversion trap support

--- a/reg.c
+++ b/reg.c
@@ -43,7 +43,13 @@
 char *num_get(int id)
 {
 	static char numbuf[128];
-	sprintf(numbuf, "%d", *nreg(id));
+	switch (id) {
+	case REG('.', 't'):
+		sprintf(numbuf, "%d", trap_next());
+		break;
+	default:
+		sprintf(numbuf, "%d", *nreg(id));
+	}
 	return numbuf;
 }
 
--- a/ren.c
+++ b/ren.c
@@ -14,6 +14,8 @@
 	int reg;		/* diversion register */
 	int dl;			/* diversion width */
 	int prev_d;		/* previous \(.d value */
+	int tpos;		/* diversion trap position */
+	int treg;		/* diversion trap register */
 };
 static struct div divs[NPREV];	/* diversion stack */
 static struct div *cdiv;	/* current diversion */
@@ -23,6 +25,9 @@
 
 static int ren_backed = -1;	/* pushed back character */
 
+static int bp_next;		/* next page number */
+static int bp_force;		/* execute the traps until the next page */
+
 static int ren_next(void)
 {
 	int c = ren_backed >= 0 ? ren_backed : tr_next();
@@ -49,20 +54,15 @@
 	return l;
 }
 
-static void ren_ne(int n)
-{
-	if (n_nl + n > n_p && !cdiv)
-		ren_page(n_pg + 1);
-}
-
 void tr_di(char **args)
 {
 	if (args[1]) {
 		cdiv = cdiv ? cdiv + 1 : divs;
+		memset(cdiv, 0, sizeof(*cdiv));
 		sbuf_init(&cdiv->sbuf);
 		cdiv->reg = REG(args[1][0], args[1][1]);
-		cdiv->dl = 0;
 		cdiv->prev_d = n_d;
+		cdiv->treg = -1;
 		if (args[0][2] == 'a' && str_get(cdiv->reg))	/* .da */
 			sbuf_append(&cdiv->sbuf, str_get(cdiv->reg));
 		n_d = 0;
@@ -95,8 +95,7 @@
 	ren_div--;
 }
 
-/* vertical motion before rendering lines */
-static void down(int n)
+static void ren_sp(int n)
 {
 	char cmd[32];
 	if (!n && ren_div && !n_u)
@@ -111,12 +110,64 @@
 		if (n_nl <= n_p)
 			OUT("v%d\n", n ? n : n_v);
 	}
-	ren_ne(0);
 }
 
+static int trap_reg(int pos);
+static int trap_pos(int pos);
+
+static void push_ne(int dobr)
+{
+	char buf[32];
+	sprintf(buf, "%cne %du\n", dobr ? '.' : '\'', n_p);
+	in_push(buf, NULL);
+}
+
+static void trap_exec(int reg)
+{
+	if (bp_force)
+		push_ne(0);
+	if (str_get(reg))
+		in_push(str_get(reg), NULL);
+}
+
+/* return 1 if executed a trap */
+static int ren_traps(int beg, int end, int dosp)
+{
+	int pos = trap_pos(beg);
+	if (pos >= 0 && pos < n_p && pos <= end) {
+		if (dosp && pos > beg)
+			ren_sp(pos - beg);
+		trap_exec(trap_reg(beg));
+		return 1;
+	}
+	return 0;
+}
+
+/* start a new page if needed */
+static int ren_pagelimit(int ne)
+{
+	if (n_nl + ne >= n_p && !cdiv) {
+		ren_page(bp_next);
+		bp_force = 0;
+		if (trap_pos(-1) == 0)
+			trap_exec(trap_reg(-1));
+		return 1;
+	}
+	return 0;
+}
+
+static void down(int n)
+{
+	if (!ren_traps(n_d, n_d + (n ? n : n_v), 1)) {
+		ren_sp(n);
+		ren_pagelimit(0);
+	}
+}
+
 static void out_line(char *out, int w)
 {
-	down(0);
+	int prev_d = n_d;
+	ren_sp(0);
 	n_n = w;
 	if (cdiv) {
 		if (cdiv->dl < w)
@@ -126,33 +177,31 @@
 		OUT("H%d\n", n_o + n_i);
 		output(out);
 	}
+	if (!ren_traps(prev_d, n_d, 0))
+		ren_pagelimit(0);
 }
 
-static void ren_br(int sp, int force)
+static void ren_br(int force)
 {
 	char out[LNLEN];
 	int w;
 	if (!adj_empty(adj, ADJ_MODE)) {
 		w = adj_fill(adj, force ? ADJ_N : ADJ_MODE, ADJ_LL, out);
-		ren_ne(n_v);
 		out_line(out, w);
-		ren_ne(n_v);
 	}
-	if (sp)
-		down(sp);
 }
 
 void tr_br(char **args)
 {
-	ren_br(0, 1);
+	if (args[0][0] == '.')
+		ren_br(1);
 }
 
 void tr_sp(char **args)
 {
-	int sp = n_v;
-	if (args[1])
-		sp = tr_int(args[1], 0, 'v');
-	ren_br(sp, 1);
+	if (args[0][0] == '.')
+		ren_br(1);
+	down(args[1] ? tr_int(args[1], 0, 'v') : n_v);
 }
 
 void ren_page(int pg)
@@ -160,15 +209,26 @@
 	n_nl = -1;
 	n_d = 0;
 	n_pg = pg;
+	bp_next = n_pg + 1;
 	OUT("p%d\n", pg);
 	OUT("V%d\n", 0);
 }
 
+void tr_ne(char **args)
+{
+	int n = args[1] ? tr_int(args[1], 0, 'v') : n_v;
+	ren_br(1);
+	if (!ren_traps(n_d, n_d + n, 1))
+		ren_pagelimit(n);
+}
+
 void tr_bp(char **args)
 {
 	if (!cdiv) {
-		ren_br(0, 1);
-		ren_page(args[1] ? tr_int(args[1], n_pg, 'v') : n_pg + 1);
+		bp_force = 1;
+		if (args[1])
+			bp_next = tr_int(args[1], n_pg, '\0');
+		push_ne(args[0][0] == '.');
 	}
 }
 
@@ -186,7 +246,8 @@
 
 void tr_in(char **args)
 {
-	ren_br(0, 1);
+	if (args[0][0] == '.')
+		ren_br(1);
 	if (args[1])
 		n_i = tr_int(args[1], n_i, 'm');
 }
@@ -216,13 +277,15 @@
 
 void tr_nf(char **args)
 {
-	ren_br(0, 1);
+	if (args[0][0] == '.')
+		ren_br(1);
 	n_u = 0;
 }
 
 void tr_fi(char **args)
 {
-	ren_br(0, 1);
+	if (args[0][0] == '.')
+		ren_br(1);
 	n_u = 1;
 }
 
@@ -269,12 +332,12 @@
 	char arg[ILNLEN];
 	struct glyph *g;
 	int esc = 0;
-	ren_br(0, 1);
+	ren_br(1);
 	while (nextchar(c) > 0) {
 		if (c[0] == ' ' || c[0] == '\n')
 			adj_put(adj, charwid(dev_spacewid(), n_s), c);
 		while (adj_full(adj, ADJ_MODE, ADJ_LL))
-			ren_br(0, 0);
+			ren_br(0);
 		if (c[0] == ' ' || c[0] == '\n')
 			continue;
 		esc = 0;
@@ -310,5 +373,114 @@
 		g = dev_glyph(c, n_f);
 		adj_put(adj, charwid(g ? g->wid : dev_spacewid(), n_s), arg);
 	}
-	ren_br(0, 1);
+	ren_br(1);
+}
+
+static int tpos[NTRAPS];	/* trap positions */
+static int treg[NTRAPS];	/* trap registers */
+static int ntraps;
+
+static int trap_first(int pos)
+{
+	int best = -1;
+	int i;
+	for (i = 0; i < ntraps; i++)
+		if (treg[i] >= 0 && tpos[i] > pos)
+			if (best < 0 || tpos[i] <= tpos[best])
+				best = i;
+	return best;
+}
+
+static int trap_byreg(int reg)
+{
+	int i;
+	for (i = 0; i < ntraps; i++)
+		if (treg[i] == reg)
+			return i;
+	return -1;
+}
+
+static int trap_bypos(int reg, int pos)
+{
+	int i;
+	for (i = 0; i < ntraps; i++)
+		if (treg[i] >= 0 && tpos[i] == pos)
+			if (reg == -1 || treg[i] == reg)
+				return i;
+	return -1;
+}
+
+static int tpos_parse(char *s)
+{
+	int pos = tr_int(s, 0, 'v');
+	return pos >= 0 ? pos : n_p + pos;
+}
+
+void tr_wh(char **args)
+{
+	int reg, pos, id;
+	if (!args[1])
+		return;
+	pos = tpos_parse(args[1]);
+	id = trap_bypos(-1, pos);
+	if (!args[2]) {
+		if (id >= 0)
+			treg[id] = -1;
+		return;
+	}
+	reg = REG(args[2][0], args[2][1]);
+	if (id < 0)
+		id = trap_byreg(-1);
+	if (id < 0)
+		id = ntraps++;
+	tpos[id] = pos;
+	treg[id] = reg;
+}
+
+void tr_ch(char **args)
+{
+	int reg;
+	int id;
+	if (!args[1])
+		return;
+	reg = REG(args[1][0], args[1][1]);
+	id = trap_byreg(reg);
+	if (id)
+		tpos[id] = args[2] ? tpos_parse(args[2]) : -1;
+}
+
+void tr_dt(char **args)
+{
+	if (!cdiv)
+		return;
+	if (args[2]) {
+		cdiv->tpos = tr_int(args[1], 0, 'v');
+		cdiv->treg = REG(args[2][0], args[2][1]);
+	} else {
+		cdiv->treg = -1;
+	}
+}
+
+static int trap_pos(int pos)
+{
+	int ret = trap_first(pos);
+	if (cdiv)
+		return cdiv->treg && cdiv->tpos > pos ? cdiv->tpos : -1;
+	return ret >= 0 ? tpos[ret] : -1;
+}
+
+static int trap_reg(int pos)
+{
+	int ret = trap_first(pos);
+	if (cdiv)
+		return cdiv->treg && cdiv->tpos > pos ? cdiv->treg : -1;
+	return ret >= 0 ? treg[ret] : -1;
+}
+
+int trap_next(void)
+{
+	int pos = trap_pos(n_d);
+	if (cdiv)
+		return pos >= 0 ? pos : 0x7fffffff;
+	return pos >= 0 && pos < n_p ? pos : n_p - n_d;
 }
--- a/tr.c
+++ b/tr.c
@@ -309,10 +309,12 @@
 	{"as", tr_as, mkargs_ds},
 	{"bp", tr_bp},
 	{"br", tr_br},
+	{"ch", tr_ch},
 	{"da", tr_di},
 	{"de", tr_de, mkargs_reg1},
 	{"di", tr_di},
 	{"ds", tr_ds, mkargs_ds},
+	{"dt", tr_dt},
 	{"ev", tr_ev},
 	{"fi", tr_fi},
 	{"fp", tr_fp},
@@ -320,6 +322,7 @@
 	{"in", tr_in},
 	{"ll", tr_ll},
 	{"na", tr_na},
+	{"ne", tr_ne},
 	{"nf", tr_nf},
 	{"nr", tr_nr, mkargs_reg1},
 	{"pl", tr_pl},
@@ -328,6 +331,7 @@
 	{"rn", tr_rn},
 	{"sp", tr_sp},
 	{"vs", tr_vs},
+	{"wh", tr_wh},
 };
 
 int tr_next(void)
@@ -340,6 +344,7 @@
 	struct cmd *req;
 	while (tr_nl && (c == '.' || c == '\'')) {
 		nl = 1;
+		memset(args, 0, sizeof(args));
 		args[0] = cmd;
 		cmd[0] = c;
 		req = NULL;
--- a/xroff.h
+++ b/xroff.h
@@ -14,6 +14,7 @@
 #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 */
 
 /* escape sequences */
 #define ESC_Q	"bCDhHlLNoSvwxX"	/* quoted escape sequences */
@@ -102,21 +103,27 @@
 void render(void);	/* read from in.c and print the output */
 void output(char *s);	/* output the given rendered line */
 void ren_page(int pg);
+int trap_next(void);
 
+
 /* troff commands */
 void tr_bp(char **args);
 void tr_br(char **args);
+void tr_ch(char **args);
 void tr_di(char **args);
 void tr_divbeg(char **args);
 void tr_divend(char **args);
+void tr_dt(char **args);
 void tr_ev(char **args);
 void tr_fi(char **args);
 void tr_fp(char **args);
 void tr_ft(char **args);
 void tr_in(char **args);
+void tr_ne(char **args);
 void tr_nf(char **args);
 void tr_ps(char **args);
 void tr_sp(char **args);
+void tr_wh(char **args);
 
 void tr_init(void);