shithub: neatroff

Download patch

ref: 5c7624e050d8559ee996b251fc063a5df07d9d46
parent: 4b451268a4cf9a90e01efe84cadbb5417161d568
author: Ali Gholami Rudi <ali@rudi.ir>
date: Wed Apr 24 20:59:10 EDT 2013

ren: add \o, \z and \b

--- a/line.c
+++ b/line.c
@@ -83,7 +83,7 @@
 		arg += 2;
 	if (*arg)
 		lc = arg;
-	w = n_s * SC_PT;	/* character height */
+	w = SC_HT;	/* character height */
 	hw = cwid(lc);		/* character width */
 	/* negative length; moving backwards */
 	if (l < 0) {
@@ -120,4 +120,74 @@
 	if (neg)
 		vmov(adj, -l);
 	hmov(adj, hw);
+}
+
+static char *cutchar(char *d, char *s)
+{
+	s = utf8get(d, s);
+	if (d[0] == '\\') {
+		s = utf8get(d + 1, s);
+		if (d[1] == '(') {
+			s = utf8get(d + 2, s);
+			s = utf8get(d + strlen(d), s);
+		}
+	}
+	return s;
+}
+
+static int maxwid(char *s)
+{
+	char c[GNLEN * 4];
+	int w = 0;
+	while (*s) {
+		s = cutchar(c, s);
+		if (cwid(c) > w)
+			w = cwid(c);
+	}
+	return w;
+}
+
+static int nchars(char *s)
+{
+	char c[GNLEN * 4];
+	int n = 0;
+	while (*s) {
+		s = cutchar(c, s);
+		n++;
+	}
+	return n;
+}
+
+void ren_bracket(struct adj *adj, char *arg)
+{
+	char c[GNLEN * 4];
+	int ht, hc;
+	int w = maxwid(arg);
+	int n = nchars(arg);
+	ht = n * SC_HT;
+	hc = -(ht + SC_EM) / 2;
+	vmov(adj, hc + SC_HT);
+	while (*arg) {
+		arg = cutchar(c, arg);
+		adj_put(adj, cwid(arg), c);
+		hmov(adj, -cwid(c));
+		vmov(adj, SC_HT);
+	}
+	hmov(adj, w);
+	vmov(adj, hc);
+}
+
+void ren_over(struct adj *adj, char *arg)
+{
+	char c[GNLEN * 4];
+	int a;
+	int w = maxwid(arg);
+	while (*arg) {
+		arg = cutchar(c, arg);
+		a = (w - cwid(c)) / 2;
+		hmov(adj, a);
+		adj_put(adj, cwid(arg), c);
+		hmov(adj, -cwid(c) - a);
+	}
+	hmov(adj, w);
 }
--- a/out.c
+++ b/out.c
@@ -51,7 +51,7 @@
 	return 1;
 }
 
-static char *utf8get(char *d, char *s)
+char *utf8get(char *d, char *s)
 {
 	int l = utf8len((unsigned char) *s);
 	int i;
--- a/ren.c
+++ b/ren.c
@@ -471,6 +471,9 @@
 		w = dev_spacewid();
 		adj_put(adj, w, "\\h'%du'", w);
 		break;
+	case 'b':
+		ren_bracket(adj, arg);
+		break;
 	case 'D':
 		w = out_draw(arg, draw_arg);
 		adj_put(adj, w, "\\D'%s'", draw_arg);
@@ -494,6 +497,9 @@
 	case 'l':
 		ren_hline(adj, arg);
 		break;
+	case 'o':
+		ren_over(adj, arg);
+		break;
 	case 'r':
 		adj_put(adj, 0, "\\v'%du'", eval("-1m", 0, 0));
 		break;
@@ -538,7 +544,8 @@
 	char arg[ILNLEN];
 	char widbuf[16];
 	struct glyph *g;
-	int n;
+	int zerowid = 0;
+	int n, w;
 	nextchar(c, next);
 	if (c[0] == ' ' || c[0] == '\n') {
 		adj_put(adj, charwid(dev_spacewid(), n_s), c);
@@ -550,13 +557,22 @@
 			int l = nextchar(c + 2, next);
 			l += nextchar(c + 2 + l, next);
 			c[2 + l] = '\0';
-		} else if (strchr(" DdfhkLlrsuvwXx0^|{}", c[1])) {
-			if (c[1] == 'w') {
-				n = ren_wid(next, back);
-				sprintf(widbuf, "%d", n);
-				in_push(widbuf, NULL);
-				return 0;
+		} else if (c[1] == 'z') {
+			zerowid = 1;
+			nextchar(c, next);
+			if (c[0] == '\\') {
+				nextchar(c + 1, next);
+				if (c[1] == '(') {
+					nextchar(c + 2, next);
+					nextchar(c + strlen(c), next);
+				}
 			}
+		} else if (c[1] == 'w') {
+			n = ren_wid(next, back);
+			sprintf(widbuf, "%d", n);
+			in_push(widbuf, NULL);
+			return 0;
+		} else if (strchr(" bDdfhkLlorsuvXxz0^|{}", c[1])) {
 			escarg_ren(arg, c[1], next, back);
 			ren_cmd(adj, c[1], arg);
 			return 0;
@@ -572,7 +588,10 @@
 		ren_f = n_f;
 	}
 	g = dev_glyph(c, n_f);
-	adj_put(adj, charwid(g ? g->wid : SC_DW, n_s), c);
+	w = charwid(g ? g->wid : SC_DW, n_s);
+	adj_put(adj, w, c);
+	if (zerowid)
+		adj_put(adj, -w, "\\h'%du'", -w);
 	return g ? g->type : 0;
 }
 
--- a/xroff.h
+++ b/xroff.h
@@ -1,7 +1,9 @@
 /* converting scales */
 #define SC_IN		(dev_res)	/* inch in units */
 #define SC_PT		(SC_IN / 72)	/* point in units */
-#define SC_DW		(n_s * SC_IN / 72 / 3)	/* default width */
+#define SC_EM		(n_s * SC_IN / 72)
+#define SC_DW		(SC_EM / 3)	/* default width */
+#define SC_HT		(n_s * SC_PT)	/* character height */
 
 /* predefined array limits */
 #define PATHLEN		1024	/* path length */
@@ -122,6 +124,8 @@
 void out(char *s, ...);				/* output troff cmd */
 void ren_hline(struct adj *adj, char *arg);	/* horizontal line */
 void ren_vline(struct adj *adj, char *arg);	/* vertical line */
+void ren_bracket(struct adj *adj, char *arg);	/* \b */
+void ren_over(struct adj *adj, char *arg);	/* \o */
 
 /* troff commands */
 void tr_bp(char **args);
@@ -156,6 +160,7 @@
 /* helpers */
 void errmsg(char *msg, ...);
 int utf8len(int c);
+char *utf8get(char *d, char *s);
 
 /* variable length string buffer */
 struct sbuf {