shithub: neatroff

Download patch

ref: c96d5ac9e6e6d97f85052f9cb7ceb998fb13d11d
parent: e09893889703797eb671aa56f59e109da1caa569
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sun Oct 13 14:40:06 EDT 2013

tr: basic .char implementation for glyph definitions

This is not compatible with Groff: nested defined characters in
.char definitions are not expanded, defined characters are ignored
when they are used in .tr character translations, and the
expansion does not happen in a separate environment.

--- a/draw.c
+++ b/draw.c
@@ -5,8 +5,13 @@
 
 static int cwid(char *c)
 {
-	struct glyph *g = dev_glyph(c, n_f);
-	return charwid(n_f, n_s, g ? g->wid : SC_DW);
+	struct wb wb;
+	int w;
+	wb_init(&wb);
+	wb_putexpand(&wb, c);
+	w = wb_wid(&wb);
+	wb_done(&wb);
+	return w;
 }
 
 static int hchar(char *c)
@@ -46,7 +51,7 @@
 	/* the initial gap */
 	if (rem) {
 		if (hchar(c)) {
-			wb_put(wb, c);
+			wb_putexpand(wb, c);
 			wb_hmov(wb, rem - w);
 		} else {
 			wb_hmov(wb, rem);
@@ -53,7 +58,7 @@
 		}
 	}
 	for (i = 0; i < n; i++)
-		wb_put(wb, c);
+		wb_putexpand(wb, c);
 	/* moving back */
 	if (l < w)
 		wb_hmov(wb, -(w - l + 1) / 2);
@@ -82,7 +87,7 @@
 	if (rem) {
 		if (vchar(c)) {
 			wb_vmov(wb, w);
-			wb_put(wb, c);
+			wb_putexpand(wb, c);
 			wb_hmov(wb, -hw);
 			wb_vmov(wb, rem - w);
 		} else {
@@ -91,7 +96,7 @@
 	}
 	for (i = 0; i < n; i++) {
 		wb_vmov(wb, w);
-		wb_put(wb, c);
+		wb_putexpand(wb, c);
 		wb_hmov(wb, -hw);
 	}
 	/* moving back */
--- a/ren.c
+++ b/ren.c
@@ -301,7 +301,7 @@
 	wb_init(&wb);
 	if (w + ljust < n_l + n_mcn)
 		wb_hmov(&wb, n_l + n_mcn - w - ljust);
-	wb_put(&wb, c_mc);
+	wb_putexpand(&wb, c_mc);
 	sbuf_append(sbuf, sbuf_buf(&wb.sbuf));
 	wb_done(&wb);
 }
@@ -733,7 +733,7 @@
 	if (!n_lg || ren_div || wb_lig(wb, c)) {
 		if (n_kn && !ren_div)
 			wb_kern(wb, c);
-		wb_put(wb, c);
+		wb_putexpand(wb, c);
 	}
 }
 
@@ -894,6 +894,31 @@
 		ren_hline(wb, ins - pos, tc);
 	wb_cat(wb, &t);
 	wb_done(&t);
+}
+
+static int ren_expanding;	/* expanding the definition of a character */
+
+/* expand the given defined character */
+int ren_expand(struct wb *wb, char *n)
+{
+	char *s = chdef_map(n);
+	int c;
+	if (!s || ren_expanding)
+		return 1;
+	ren_expanding = 1;
+	odiv_beg();
+	sstr_push(s);
+	c = sstr_next();
+	while (c >= 0) {
+		sstr_back(c);
+		if (ren_chardel(wb, sstr_next, sstr_back, NULL, NULL))
+			break;
+		c = sstr_next();
+	}
+	sstr_pop();
+	odiv_end();
+	ren_expanding = 0;
+	return 0;
 }
 
 /* read characters from in.c and pass rendered lines to out.c */
--- a/roff.h
+++ b/roff.h
@@ -29,6 +29,7 @@
 #define NFIELDS		32	/* number of fields */
 #define MAXFRAC		100000	/* maximum value of the fractional part */
 #define LIGLEN		4	/* length of ligatures */
+#define NCHDEF		128	/* number of character definitions (.char) */
 
 /* escape sequences */
 #define ESC_Q	"bCDhHlLNoSvwxX"	/* \X'ccc' quoted escape sequences */
@@ -177,6 +178,8 @@
 /* character translation (.tr) */
 void tr_add(char *c1, char *c2);
 char *tr_map(char *c);
+/* character definition (.char) */
+char *chdef_map(char *c);
 
 /* variable length string buffer */
 struct sbuf {
@@ -220,6 +223,7 @@
 void wb_els(struct wb *wb, int els);
 void wb_etc(struct wb *wb, char *x);
 void wb_put(struct wb *wb, char *c);
+void wb_putexpand(struct wb *wb, char *c);
 int wb_part(struct wb *wb);
 void wb_setpart(struct wb *wb);
 void wb_drawl(struct wb *wb, int c, int h, int v);
@@ -280,6 +284,7 @@
 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 */
+int ren_expand(struct wb *wb, char *c);		/* .char expansion */
 
 /* out.c */
 void out_line(char *s);				/* output rendered line */
--- a/tr.c
+++ b/tr.c
@@ -535,6 +535,60 @@
 	}
 }
 
+/* character definitions */
+static char chdef_src[NCHDEF][GNLEN];
+static char *chdef_dst[NCHDEF];
+static int chdef_n;
+
+static int chdef_find(char *c)
+{
+	int i;
+	for (i = 0; i < chdef_n; i++)
+		if (!strcmp(chdef_src[i], c))
+			return i;
+	return -1;
+}
+
+/* return the definition of the given character */
+char *chdef_map(char *c)
+{
+	int i = chdef_find(c);
+	return i >= 0 ? chdef_dst[i] : NULL;
+}
+
+static void tr_char(char **args)
+{
+	char c[GNLEN];
+	char *s = args[1];
+	int i;
+	if (!args[2] || charread(&s, c) < 0)
+		return;
+	i = chdef_find(c);
+	if (i < 0 && chdef_n < NCHDEF)
+		i = chdef_n++;
+	if (i >= 0) {
+		strncpy(chdef_src[i], c, sizeof(chdef_src[i]) - 1);
+		chdef_dst[i] = malloc(strlen(args[2]) + 1);
+		strcpy(chdef_dst[i], args[2]);
+	}
+}
+
+static void tr_rchar(char **args)
+{
+	char c[GNLEN];
+	char *s;
+	int i;
+	for (i = 1; i <= NARGS; i++) {
+		s = args[i];
+		if (s && charread(&s, c) >= 0) {
+			if (chdef_find(c) >= 0) {
+				free(chdef_dst[chdef_find(c)]);
+				chdef_dst[chdef_find(c)] = NULL;
+			}
+		}
+	}
+}
+
 static char *arg_regname(char *s, int len)
 {
 	char *e = n_cp ? s + 2 : s + len;
@@ -717,6 +771,7 @@
 	{"cc", tr_cc},
 	{"ce", tr_ce},
 	{"ch", tr_ch},
+	{"char", tr_char, mkargs_ds},
 	{"cl", tr_cl},
 	{"cp", tr_cp},
 	{"cs", tr_cs},
@@ -767,6 +822,7 @@
 	{"pn", tr_pn},
 	{"po", tr_po},
 	{"ps", tr_ps},
+	{"rchar", tr_rchar, mkargs_ds},
 	{"rm", tr_rm},
 	{"rn", tr_rn},
 	{"rr", tr_rr},
--- a/wb.c
+++ b/wb.c
@@ -164,6 +164,13 @@
 	}
 }
 
+/* just like wb_put(), but call chdef_expand() if c is defined */
+void wb_putexpand(struct wb *wb, char *c)
+{
+	if (ren_expand(wb, c))
+		wb_put(wb, c);
+}
+
 /* return zero if c formed a ligature with its previous character */
 int wb_lig(struct wb *wb, char *c)
 {