shithub: neatroff

Download patch

ref: 1874ab5126cf9ae58f12f8b89a8da14b9ccbfbb7
parent: 93ff33b4b44f297924ecb9f2f1de84646db0cd1b
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat Jul 27 14:40:27 EDT 2013

tr: add .tc and .lc

--- a/draw.c
+++ b/draw.c
@@ -3,30 +3,6 @@
 #include <string.h>
 #include "roff.h"
 
-static char *ln_s;
-
-static int ln_next(void)
-{
-	return *ln_s ? (unsigned char) *ln_s++ : -1;
-}
-
-static void ln_back(int c)
-{
-	ln_s--;
-}
-
-static char *ln_push(char *s)
-{
-	char *old_s = ln_s;
-	ln_s = s;
-	return old_s;
-}
-
-static void ln_pop(char *s)
-{
-	ln_s = s;
-}
-
 static int cwid(char *c)
 {
 	struct glyph *g = dev_glyph(c, n_f);
@@ -50,18 +26,10 @@
 	return (c[2] == 'b' && c[3] == 'v') || (c[2] == 'b' && c[3] == 'r');
 }
 
-void ren_hline(struct wb *wb, char *arg)
+void ren_hline(struct wb *wb, int l, char *c)
 {
-	char lc[GNLEN] = {c_ec, '(', 'r', 'u'};
-	int w, l, n, i, rem;
-	l = eval_up(&arg, 'm');
-	if (!l)
-		return;
-	if (arg[0] == c_ec && arg[1] == '&')	/* \& can be used as a separator */
-		arg += 2;
-	if (*arg)
-		strcpy(lc, arg);
-	w = cwid(lc);
+	int w, n, i, rem;
+	w = cwid(c);
 	/* negative length; moving backwards */
 	if (l < 0) {
 		wb_hmov(wb, l);
@@ -77,8 +45,8 @@
 	}
 	/* the initial gap */
 	if (rem) {
-		if (hchar(lc)) {
-			wb_put(wb, lc);
+		if (hchar(c)) {
+			wb_put(wb, c);
 			wb_hmov(wb, rem - w);
 		} else {
 			wb_hmov(wb, rem);
@@ -85,26 +53,18 @@
 		}
 	}
 	for (i = 0; i < n; i++)
-		wb_put(wb, lc);
+		wb_put(wb, c);
 	/* moving back */
 	if (l < w)
 		wb_hmov(wb, -(w - l + 1) / 2);
 }
 
-void ren_vline(struct wb *wb, char *arg)
+static void ren_vline(struct wb *wb, int l, char *c)
 {
-	char lc[GNLEN] = {c_ec, '(', 'b', 'r'};
-	int w, l, n, i, rem, hw, neg;
-	l = eval_up(&arg, 'v');
-	if (!l)
-		return;
+	int w, n, i, rem, hw, neg;
 	neg = l < 0;
-	if (arg[0] == c_ec && arg[1] == '&')	/* \& can be used as a separator */
-		arg += 2;
-	if (*arg)
-		strcpy(lc, arg);
 	w = SC_HT;	/* character height */
-	hw = cwid(lc);		/* character width */
+	hw = cwid(c);	/* character width */
 	/* negative length; moving backwards */
 	if (l < 0) {
 		wb_vmov(wb, l);
@@ -120,9 +80,9 @@
 	}
 	/* the initial gap */
 	if (rem) {
-		if (vchar(lc)) {
+		if (vchar(c)) {
 			wb_vmov(wb, w);
-			wb_put(wb, lc);
+			wb_put(wb, c);
 			wb_hmov(wb, -hw);
 			wb_vmov(wb, rem - w);
 		} else {
@@ -131,7 +91,7 @@
 	}
 	for (i = 0; i < n; i++) {
 		wb_vmov(wb, w);
-		wb_put(wb, lc);
+		wb_put(wb, c);
 		wb_hmov(wb, -hw);
 	}
 	/* moving back */
@@ -142,59 +102,24 @@
 	wb_hmov(wb, hw);
 }
 
-void ren_bracket(struct wb *wb, char *arg)
+void ren_hlcmd(struct wb *wb, char *arg)
 {
-	struct wb wb2;
-	int n = 0, w = 0;
-	int c, center;
-	char *ln_prev = ln_push(arg);
-	wb_init(&wb2);
-	c = ln_next();
-	while (c >= 0) {
-		ln_back(c);
-		ren_char(&wb2, ln_next, ln_back);
-		if (wb_wid(&wb2) > w)
-			w = wb_wid(&wb2);
-		wb_hmov(&wb2, -wb_wid(&wb2));
-		wb_vmov(&wb2, SC_HT);
-		n++;
-		c = ln_next();
-	}
-	ln_pop(ln_prev);
-	center = -(n * SC_HT + SC_EM) / 2;
-	wb_vmov(wb, center + SC_HT);
-	wb_cat(wb, &wb2);
-	wb_done(&wb2);
-	wb_vmov(wb, center);
-	wb_hmov(wb, w);
+	char lc[GNLEN] = {c_ec, '(', 'r', 'u'};
+	int l = eval_up(&arg, 'm');
+	if (arg[0] == c_ec && arg[1] == '&')	/* \& can be used as a separator */
+		arg += 2;
+	if (l)
+		ren_hline(wb, l, *arg ? arg : lc);
 }
 
-void ren_over(struct wb *wb, char *arg)
+void ren_vlcmd(struct wb *wb, char *arg)
 {
-	struct wb wb2, wb3;
-	int w = 0, wc;
-	int c;
-	char *ln_prev = ln_push(arg);
-	wb_init(&wb2);
-	wb_init(&wb3);
-	c = ln_next();
-	while (c >= 0) {
-		ln_back(c);
-		ren_char(&wb3, ln_next, ln_back);
-		wc = wb_wid(&wb3);
-		if (wc > w)
-			w = wc;
-		wb_hmov(&wb2, -wc / 2);
-		wb_cat(&wb2, &wb3);
-		wb_hmov(&wb2, -wc / 2);
-		c = ln_next();
-	}
-	ln_pop(ln_prev);
-	wb_hmov(wb, w / 2);
-	wb_cat(wb, &wb2);
-	wb_hmov(wb, w / 2);
-	wb_done(&wb3);
-	wb_done(&wb2);
+	char lc[GNLEN] = {c_ec, '(', 'b', 'r'};
+	int l = eval_up(&arg, 'v');
+	if (arg[0] == c_ec && arg[1] == '&')	/* \& can be used as a separator */
+		arg += 2;
+	if (l)
+		ren_vline(wb, l, *arg ? arg : lc);
 }
 
 static int tok_num(char **s, int scale)
@@ -209,7 +134,7 @@
 	return eval(tok, scale);
 }
 
-void ren_draw(struct wb *wb, char *s)
+void ren_dcmd(struct wb *wb, char *s)
 {
 	int h1, h2, v1, v2;
 	int c = *s++;
@@ -244,4 +169,92 @@
 		}
 		wb_drawxend(wb);
 	}
+}
+
+/*
+ * the implementation of \b and \o
+ *
+ * ren_bcmd() and ren_ocmd() call ren_char(), which requires
+ * next() and back() functions, similar to ren_next() and ren_back().
+ * ln_*() here provide such an interface for the given string,
+ * added via ln_push().  ln_*() may be called recursively to
+ * handle \o'\b"ab"c'.
+ */
+static char *ln_s;
+
+static int ln_next(void)
+{
+	return *ln_s ? (unsigned char) *ln_s++ : -1;
+}
+
+static void ln_back(int c)
+{
+	ln_s--;
+}
+
+static char *ln_push(char *s)
+{
+	char *old_s = ln_s;
+	ln_s = s;
+	return old_s;
+}
+
+static void ln_pop(char *s)
+{
+	ln_s = s;
+}
+
+void ren_bcmd(struct wb *wb, char *arg)
+{
+	struct wb wb2;
+	int n = 0, w = 0;
+	int c, center;
+	char *ln_prev = ln_push(arg);
+	wb_init(&wb2);
+	c = ln_next();
+	while (c >= 0) {
+		ln_back(c);
+		ren_char(&wb2, ln_next, ln_back);
+		if (wb_wid(&wb2) > w)
+			w = wb_wid(&wb2);
+		wb_hmov(&wb2, -wb_wid(&wb2));
+		wb_vmov(&wb2, SC_HT);
+		n++;
+		c = ln_next();
+	}
+	ln_pop(ln_prev);
+	center = -(n * SC_HT + SC_EM) / 2;
+	wb_vmov(wb, center + SC_HT);
+	wb_cat(wb, &wb2);
+	wb_done(&wb2);
+	wb_vmov(wb, center);
+	wb_hmov(wb, w);
+}
+
+void ren_ocmd(struct wb *wb, char *arg)
+{
+	struct wb wb2, wb3;
+	int w = 0, wc;
+	int c;
+	char *ln_prev = ln_push(arg);
+	wb_init(&wb2);
+	wb_init(&wb3);
+	c = ln_next();
+	while (c >= 0) {
+		ln_back(c);
+		ren_char(&wb3, ln_next, ln_back);
+		wc = wb_wid(&wb3);
+		if (wc > w)
+			w = wc;
+		wb_hmov(&wb2, -wc / 2);
+		wb_cat(&wb2, &wb3);
+		wb_hmov(&wb2, -wc / 2);
+		c = ln_next();
+	}
+	ln_pop(ln_prev);
+	wb_hmov(wb, w / 2);
+	wb_cat(wb, &wb2);
+	wb_hmov(wb, w / 2);
+	wb_done(&wb3);
+	wb_done(&wb2);
 }
--- a/reg.c
+++ b/reg.c
@@ -12,7 +12,9 @@
 	int eregs[NENVS];	/* environment-specific number registers */
 	int tabs[NTABS];	/* tab stops */
 	struct adj *adj;	/* per environment line buffer */
-	char hc[GNLEN];		/* hyphenation character */
+	char tc[GNLEN];		/* tab character (.tc) */
+	char lc[GNLEN];		/* leader character (.lc) */
+	char hc[GNLEN];		/* hyphenation character (.hc) */
 	char mc[GNLEN];		/* margin character (.mc) */
 };
 
@@ -192,6 +194,7 @@
 		n_nM = 1;
 		n_nS = 1;
 		strcpy(env->hc, "\\%");
+		strcpy(env->lc, ".");
 		adj_ll(env->adj, n_l);
 		adj_in(env->adj, n_i);
 		for (i = 0; i < NTABS; i++)
@@ -256,6 +259,16 @@
 char *env_mc(void)
 {
 	return env->mc;
+}
+
+char *env_tc(void)
+{
+	return env->tc;
+}
+
+char *env_lc(void)
+{
+	return env->lc;
 }
 
 /* saving and restoring registers around diverted lines */
--- a/ren.c
+++ b/ren.c
@@ -645,13 +645,13 @@
 		wb_hmov(wb, spacewid(n_f, n_s));
 		break;
 	case 'b':
-		ren_bracket(wb, arg);
+		ren_bcmd(wb, arg);
 		break;
 	case 'c':
 		wb_setpart(wb);
 		break;
 	case 'D':
-		ren_draw(wb, arg);
+		ren_dcmd(wb, arg);
 		break;
 	case 'd':
 		wb_vmov(wb, SC_EM / 2);
@@ -666,16 +666,16 @@
 		num_set(map(arg), RENWB(wb) ? f_hpos() - n_lb : wb_wid(wb));
 		break;
 	case 'L':
-		ren_vline(wb, arg);
+		ren_vlcmd(wb, arg);
 		break;
 	case 'l':
-		ren_hline(wb, arg);
+		ren_hlcmd(wb, arg);
 		break;
 	case 'm':
 		ren_m(arg);
 		break;
 	case 'o':
-		ren_over(wb, arg);
+		ren_ocmd(wb, arg);
 		break;
 	case 'p':
 		if (RENWB(wb))
@@ -725,7 +725,7 @@
 	char c[GNLEN * 4];
 	char arg[ILNLEN];
 	struct glyph *g;
-	char *s;
+	char *s, *tc;
 	int w, n, l;
 	nextchar(c, next);
 	if (c[0] == ' ' || c[0] == '\n') {
@@ -734,7 +734,11 @@
 	}
 	if (c[0] == '\t' || c[0] == '') {
 		n = RENWB(wb) ? f_hpos() : wb_wid(wb);
-		wb_hmov(wb, tab_next(n) - n);
+		tc = c[0] == '\t' ? c_tc : c_lc;
+		if (!tc[0])
+			wb_hmov(wb, tab_next(n) - n);
+		else
+			ren_hline(wb, tab_next(n) - n, tc);
 		return;
 	}
 	if (c[0] == c_fa) {
--- a/roff.h
+++ b/roff.h
@@ -43,6 +43,8 @@
 #define c_ni	4	/* non-interpreted copy mode escape */
 #define c_hc	env_hc()/* hyphenation character */
 #define c_mc	env_mc()/* margin character (.mc) */
+#define c_tc	env_tc()
+#define c_lc	env_lc()
 
 /* number registers */
 int num_get(int id, int inc);
@@ -75,6 +77,8 @@
 struct adj *env_adj(void);
 char *env_hc(void);
 char *env_mc(void);
+char *env_tc(void);
+char *env_lc(void);
 int tab_next(int pos);
 
 /* device related variables */
@@ -256,11 +260,12 @@
 void ren_char(struct wb *wb, int (*next)(void), void (*back)(int));
 int ren_wid(int (*next)(void), void (*back)(int));
 void ren_tl(int (*next)(void), void (*back)(int));
-void ren_hline(struct wb *wb, char *arg);	/* horizontal line */
-void ren_vline(struct wb *wb, char *arg);	/* vertical line */
-void ren_bracket(struct wb *wb, char *arg);	/* \b */
-void ren_over(struct wb *wb, char *arg);	/* \o */
-void ren_draw(struct wb *wb, char *arg);	/* \D */
+void ren_hline(struct wb *wb, int l, char *c);	/* horizontal line */
+void ren_hlcmd(struct wb *wb, char *arg);	/* \l */
+void ren_vlcmd(struct wb *wb, char *arg);	/* \L */
+void ren_bcmd(struct wb *wb, char *arg);	/* \b */
+void ren_ocmd(struct wb *wb, char *arg);	/* \o */
+void ren_dcmd(struct wb *wb, char *arg);	/* \D */
 
 /* out.c */
 void out_line(char *s);				/* output rendered line */
--- a/tr.c
+++ b/tr.c
@@ -502,6 +502,16 @@
 	}
 }
 
+static void tr_tc(char **args)
+{
+	strcpy(c_tc, args[1] ? args[1] : "");
+}
+
+static void tr_lc(char **args)
+{
+	strcpy(c_lc, args[1] ? args[1] : "");
+}
+
 static void tr_lf(char **args)
 {
 	if (args[1])
@@ -716,6 +726,7 @@
 	{"in", tr_in},
 	{"it", tr_it},
 	{"kn", tr_kn},
+	{"lc", tr_lc},
 	{"lf", tr_lf},
 	{"lg", tr_lg},
 	{"ll", tr_ll},
@@ -749,6 +760,7 @@
 	{"sv", tr_sv},
 	{"sy", tr_sy, mkargs_eol},
 	{"ta", tr_ta},
+	{"tc", tr_tc},
 	{"ti", tr_ti},
 	{"tl", tr_tl, mkargs_null},
 	{"tm", tr_tm, mkargs_eol},
--- a/wb.c
+++ b/wb.c
@@ -275,7 +275,7 @@
 		wb_put(wb, s);
 		break;
 	case 'D':
-		ren_draw(wb, s);
+		ren_dcmd(wb, s);
 		break;
 	case 'f':
 		wb->r_f = atoi(s);