shithub: neatroff

Download patch

ref: f08ca5dc1ee4183db88463bcf4c8e39071d1ef46
parent: 7a5b33eb77e544f5a6c814c40c9a8ae2787b5c96
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri May 10 06:50:16 EDT 2013

wb: changes before hyphenation support

This changes neatroff to prepare for the hyphenation support:

* adj struct now holds an array of wb structs
* out_readc() is extracted to read troff output requests or glyph names
* wb_cat() rereads wb struct buffers

--- a/adj.c
+++ b/adj.c
@@ -5,16 +5,9 @@
 
 #define ADJ_LLEN(a)	MAX(0, (a)->ll - ((a)->lt >= 0 ? (a)->lt : (a)->li))
 
-struct word {
-	struct sbuf s;
-	int wid;	/* word width */
-	int gap;	/* the space before this word */
-	int els_neg;	/* pre-extra line space */
-	int els_pos;	/* post-extra line space */
-};
-
 struct adj {
-	struct word words[NWORDS];	/* words in buf */
+	struct wb wbs[NWORDS];		/* words in buf */
+	int gaps[NWORDS];		/* gaps before words */
 	int nwords;
 	int wid;			/* total width of buf */
 	int swid;			/* current space width */
@@ -77,20 +70,43 @@
 	adj->swid = swid;
 }
 
+/* move words inside an adj struct */
+static void adj_movewords(struct adj *a, int dst, int src, int len)
+{
+	memmove(a->wbs + dst, a->wbs + src, len * sizeof(a->wbs[0]));
+	memmove(a->gaps + dst, a->gaps + src, len * sizeof(a->gaps[0]));
+}
+
+static int adj_linewid(struct adj *a, int n)
+{
+	int i, w = 0;
+	for (i = 0; i < n; i++)
+		w += wb_wid(&a->wbs[i]) + a->gaps[i];
+	return w;
+}
+
+static int adj_linefit(struct adj *a, int llen)
+{
+	int i, w = 0;
+	for (i = 0; i < a->nwords && w <= llen; i++)
+		w += wb_wid(&a->wbs[i]) + a->gaps[i];
+	return i - 1;
+}
+
 /* move n words from the adjustment buffer to s */
 static int adj_move(struct adj *a, int n, struct sbuf *s, int *els_neg, int *els_pos)
 {
-	struct word *cur;
+	struct wb *cur;
 	int w = 0;
 	int i;
 	*els_neg = 0;
 	*els_pos = 0;
 	for (i = 0; i < n; i++) {
-		cur = &a->words[i];
-		sbuf_printf(s, "%ch'%du'", c_ec, cur->gap);
-		sbuf_append(s, sbuf_buf(&cur->s));
-		sbuf_done(&cur->s);
-		w += cur->wid + cur->gap;
+		cur = &a->wbs[i];
+		sbuf_printf(s, "%ch'%du'", c_ec, a->gaps[i]);
+		sbuf_append(s, sbuf_buf(&cur->sbuf));
+		w += wb_wid(cur) + a->gaps[i];
+		wb_done(cur);
 		if (cur->els_neg < *els_neg)
 			*els_neg = cur->els_neg;
 		if (cur->els_pos > *els_pos)
@@ -99,13 +115,33 @@
 	if (!n)
 		return 0;
 	a->nwords -= n;
-	memmove(a->words, a->words + n, a->nwords * sizeof(a->words[0]));
-	a->wid -= w;
+	adj_movewords(a, 0, n, a->nwords);
+	a->wid = adj_linewid(a, a->nwords);
 	if (a->nwords)		/* apply the new .l and .i */
 		adj_confupdate(a);
 	return w;
 }
 
+/* try to hyphenate the n-th word */
+static void adj_hyph(struct adj *a, int n, int w)
+{
+	struct wb w1, w2;
+	wb_init(&w1);
+	wb_init(&w2);
+	if (wb_hyph(&a->wbs[n], w, &w1, &w2)) {
+		wb_done(&w1);
+		wb_done(&w2);
+		return;
+	}
+	adj_movewords(a, n + 2, n + 1, a->nwords - n);
+	wb_done(&a->wbs[n]);
+	memcpy(&a->wbs[n], &w1, sizeof(w1));
+	memcpy(&a->wbs[n + 1], &w2, sizeof(w2));
+	a->nwords++;
+	a->gaps[n + 1] = 0;
+	a->wid = adj_linewid(a, a->nwords);
+}
+
 /* fill and copy a line into s */
 int adj_fill(struct adj *a, int ad_b, int fill, struct sbuf *s,
 		int *ll, int *in, int *ti, int *els_neg, int *els_pos)
@@ -121,22 +157,23 @@
 		a->nls--;
 		return adj_move(a, a->nwords, s, els_neg, els_pos);
 	}
-	for (n = 0; n < a->nwords; n++) {
-		if (n && w + a->words[n].wid + a->words[n].gap > llen)
-			break;
-		w += a->words[n].wid + a->words[n].gap;
-	}
+	n = adj_linefit(a, llen);
+	if (n < a->nwords)
+		adj_hyph(a, n, llen - adj_linewid(a, n) - a->gaps[n]);
+	n = adj_linefit(a, llen);
+	if (!n && a->nwords)
+		n = 1;
+	w = adj_linewid(a, n);
 	if (ad_b && n > 1 && n < a->nwords) {
 		adj_div = (llen - w) / (n - 1);
-		adj_rem = llen - w - adj_div * (n - 1);
-		a->wid += llen - w;
+		adj_rem = (llen - w) % (n - 1);
 		for (i = 0; i < n - 1; i++)
-			a->words[i + 1].gap += adj_div + (i < adj_rem);
+			a->gaps[i + 1] += adj_div + (i < adj_rem);
 	}
 	w = adj_move(a, n, s, els_neg, els_pos);
 	if (a->nwords)
-		a->wid -= a->words[0].gap;
-	a->words[0].gap = 0;
+		a->wid -= a->gaps[0];
+	a->gaps[0] = 0;
 	return w;
 }
 
@@ -161,14 +198,11 @@
 
 static void adj_word(struct adj *adj, struct wb *wb)
 {
-	struct word *cur = &adj->words[adj->nwords++];
-	cur->wid = wb_wid(wb);
-	cur->gap = adj->gap;
-	adj->wid += cur->wid + adj->gap;
-	wb_getels(wb, &cur->els_neg, &cur->els_pos);
-	sbuf_init(&cur->s);
-	sbuf_append(&cur->s, sbuf_buf(&wb->sbuf));
-	wb_reset(wb);
+	int i = adj->nwords++;
+	wb_init(&adj->wbs[i]);
+	adj->gaps[i] = adj->gap;
+	adj->wid += wb_wid(wb) + adj->gap;
+	wb_cat(&adj->wbs[i], wb);
 }
 
 /* insert wb into the adjustment buffer */
--- a/out.c
+++ b/out.c
@@ -48,17 +48,17 @@
 		return 3;
 	if (c >= 0xc0)
 		return 2;
-	return 1;
+	return c != 0;
 }
 
-char *utf8get(char *d, char *s)
+static void utf8get(char **s, char *d)
 {
-	int l = utf8len((unsigned char) *s);
+	int l = utf8len((unsigned char) **s);
 	int i;
 	for (i = 0; i < l; i++)
-		d[i] = s[i];
+		d[i] = (*s)[i];
 	d[l] = '\0';
-	return s + l;
+	*s += l;
 }
 
 static int o_s = 10;
@@ -80,8 +80,9 @@
 	}
 }
 
-static char *escarg(char *s, char *d, int cmd)
+static void escarg(char **sp, char *d, int cmd)
 {
+	char *s = *sp;
 	int q;
 	if (strchr(ESC_P, cmd)) {
 		if (cmd == 's' && (*s == '-' || *s == '+'))
@@ -107,7 +108,7 @@
 	if (cmd == 'z')
 		*d++ = *s++;
 	*d = '\0';
-	return s;
+	*sp = s;
 }
 
 static int tok_num(char **s, int scale)
@@ -157,57 +158,76 @@
 	outnn("\n");
 }
 
+/*
+ * read a glyph or output troff request
+ *
+ * This functions reads from s either an output troff request
+ * (only the ones emitted by wb.c) or a glyph name and updates
+ * s.  The return value is the name of the troff request (the
+ * argument is copied into d) or zero for glyph names (it is
+ * copied into d).  Returns -1 when the end of s is reached.
+ */
+int out_readc(char **s, char *d)
+{
+	if (!**s)
+		return -1;
+	utf8get(s, d);
+	if (d[0] == c_ec) {
+		utf8get(s, d + 1);
+		if (d[1] == '(') {
+			utf8get(s, d + 2);
+			utf8get(s, d + strlen(d));
+		} else if (strchr("DfhsvXx", d[1])) {
+			int c = d[1];
+			escarg(s, d, d[1]);
+			return c;
+		}
+	}
+	if (d[0] == c_ni)
+		utf8get(s, d + 1);
+	return 0;
+}
+
 void out_line(char *s)
 {
 	struct glyph *g;
-	char c[GNLEN * 4];
-	char arg[ILNLEN];
-	while (*s) {
-		s = utf8get(c, s);
-		if (c[0] == c_ec) {
-			s = utf8get(c + 1, s);
-			if (c[1] == '(') {
-				s = utf8get(c + 2, s);
-				s = utf8get(c + strlen(c), s);
-			} else if (c[1] == c_ec) {
-				c[1] = '\0';
-			} else if (strchr("DfhsvX", c[1])) {
-				s = escarg(s, arg, c[1]);
-				if (c[1] == 'D') {
-					out_draw(arg);
-					continue;
-				}
-				if (c[1] == 'f') {
-					out_ft(dev_font(arg));
-					continue;
-				}
-				if (c[1] == 'h') {
-					outnn("h%d", eval(arg, 'm'));
-					continue;
-				}
-				if (c[1] == 's') {
-					out_ps(eval_re(arg, o_s, '\0'));
-					continue;
-				}
-				if (c[1] == 'v') {
-					outnn("v%d", eval(arg, 'v'));
-					continue;
-				}
-				if (c[1] == 'X') {
-					out("x X %s\n", arg);
-					continue;
-				}
-			}
+	char c[ILNLEN + GNLEN * 4];
+	int t;
+	while ((t = out_readc(&s, c)) >= 0) {
+		if (c[0] == c_ni) {
+			c[0] = c[1];
+			c[1] = '\0';
 		}
-		if (c[0] == c_ni)
-			s = utf8get(c, s);
-		if (c[0] == '\t' || c[0] == '')
+		if (!t) {
+			if (c[0] == '\t' || c[0] == '')
+				continue;
+			g = dev_glyph(c, o_f);
+			if (utf8len(c[0]) == strlen(c))
+				outnn("c%s%s", c, c[1] ? "\n" : "");
+			else
+				out("C%s\n", c[0] == c_ec && c[1] == '(' ? c + 2 : c);
+			outnn("h%d", charwid(g ? g->wid : SC_DW, o_s));
 			continue;
-		g = dev_glyph(c, o_f);
-		if (utf8len(c[0]) == strlen(c))
-			outnn("c%s%s", c, c[1] ? "\n" : "");
-		else
-			out("C%s\n", c[0] == c_ec && c[1] == '(' ? c + 2 : c);
-		outnn("h%d", charwid(g ? g->wid : SC_DW, o_s));
+		}
+		switch (t) {
+		case 'D':
+			out_draw(c);
+			break;
+		case 'f':
+			out_ft(dev_font(c));
+			break;
+		case 'h':
+			outnn("h%d", eval(c, 'm'));
+			break;
+		case 's':
+			out_ps(eval_re(c, o_s, '\0'));
+			break;
+		case 'v':
+			outnn("v%d", eval(c, 'v'));
+			break;
+		case 'X':
+			out("x X %s\n", c);
+			break;
+		}
 	}
 }
--- a/wb.c
+++ b/wb.c
@@ -3,6 +3,9 @@
 #include <string.h>
 #include "xroff.h"
 
+#define R_F(wb)		((wb)->r_f >= 0 ? (wb)->r_f : n_f)	/* current font */
+#define R_S(wb)		((wb)->r_s >= 0 ? (wb)->r_s : n_s)	/* current size */
+
 void wb_init(struct wb *wb)
 {
 	memset(wb, 0, sizeof(*wb));
@@ -9,6 +12,8 @@
 	sbuf_init(&wb->sbuf);
 	wb->f = -1;
 	wb->s = -1;
+	wb->r_f = -1;
+	wb->r_s = -1;
 }
 
 void wb_done(struct wb *wb)
@@ -26,13 +31,13 @@
 /* append font and size to the buffer if needed */
 static void wb_font(struct wb *wb)
 {
-	if (wb->f != n_f) {
-		sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, n_f);
-		wb->f = n_f;
+	if (wb->f != R_F(wb)) {
+		sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, R_F(wb));
+		wb->f = R_F(wb);
 	}
-	if (wb->s != n_s) {
-		sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, n_s);
-		wb->s = n_s;
+	if (wb->s != R_S(wb)) {
+		sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, R_S(wb));
+		wb->s = R_S(wb);
 	}
 	wb_stsb(wb);
 }
@@ -55,6 +60,7 @@
 		wb->els_pos = els;
 	if (els < wb->els_neg)
 		wb->els_neg = els;
+	sbuf_printf(&wb->sbuf, "%cx'%du'", c_ec, els);
 }
 
 void wb_etc(struct wb *wb, char *x)
@@ -71,7 +77,7 @@
 		return;
 	}
 	if (c[0] == ' ') {
-		wb_hmov(wb, charwid(dev_spacewid(), n_s));
+		wb_hmov(wb, charwid(dev_spacewid(), R_S(wb)));
 		return;
 	}
 	if (c[0] == '\t' || c[0] == '' ||
@@ -79,10 +85,10 @@
 		sbuf_append(&wb->sbuf, c);
 		return;
 	}
-	g = dev_glyph(c, n_f);
+	g = dev_glyph(c, R_F(wb));
 	wb_font(wb);
 	sbuf_append(&wb->sbuf, c);
-	wb->h += charwid(g ? g->wid : SC_DW, n_s);
+	wb->h += charwid(g ? g->wid : SC_DW, R_S(wb));
 	wb->ct |= g ? g->type : 0;
 	wb_stsb(wb);
 }
@@ -148,38 +154,54 @@
 	sbuf_printf(&wb->sbuf, "'");
 }
 
-void wb_reset(struct wb *wb)
+static void wb_reset(struct wb *wb)
 {
-	sbuf_done(&wb->sbuf);
-	sbuf_init(&wb->sbuf);
-	wb->els_pos = 0;
-	wb->els_neg = 0;
-	wb->ct = 0;
-	wb->sb = 0;
-	wb->st = 0;
-	wb->h = 0;
-	wb->v = 0;
-	wb->f = -1;
-	wb->s = -1;
+	wb_done(wb);
+	wb_init(wb);
 }
 
+static void wb_putc(struct wb *wb, int t, char *s)
+{
+	switch (t) {
+	case 0:
+		wb_put(wb, s);
+		break;
+	case 'D':
+		ren_draw(wb, s);
+		break;
+	case 'f':
+		wb->r_f = atoi(s);
+		break;
+	case 'h':
+		wb_hmov(wb, atoi(s));
+		break;
+	case 's':
+		wb->r_s = atoi(s);
+		break;
+	case 'v':
+		wb_vmov(wb, atoi(s));
+		break;
+	case 'x':
+		wb_els(wb, atoi(s));
+		break;
+	case 'X':
+		wb_etc(wb, s);
+		break;
+	}
+}
+
 void wb_cat(struct wb *wb, struct wb *src)
 {
-	sbuf_append(&wb->sbuf, sbuf_buf(&src->sbuf));
-	if (src->f >= 0)
-		wb->f = src->f;
-	if (src->s >= 0)
-		wb->s = src->s;
-	wb_els(wb, src->els_neg);
-	wb_els(wb, src->els_pos);
-	if (src->part)
-		wb->part = src->part;
-	wb->ct |= src->ct;
-	wb->st = MIN(wb->st, wb->v + src->st);
-	wb->sb = MAX(wb->sb, wb->v + src->sb);
-	wb->h += src->h;
-	wb->v += src->v;
+	char *s = sbuf_buf(&src->sbuf);
+	char d[ILNLEN];
+	int c, part;
+	while ((c = out_readc(&s, d)) >= 0)
+		wb_putc(wb, c, d);
+	part = src->part;
+	wb->r_s = -1;
+	wb->r_f = -1;
 	wb_reset(src);
+	src->part = part;
 }
 
 int wb_wid(struct wb *wb)
@@ -192,15 +214,15 @@
 	return sbuf_empty(&wb->sbuf);
 }
 
-void wb_getels(struct wb *wb, int *els_neg, int *els_pos)
-{
-	*els_neg = wb->els_neg;
-	*els_pos = wb->els_pos;
-}
-
 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb)
 {
 	*ct = wb->ct;
 	*st = -wb->st;
 	*sb = -wb->sb;
+}
+
+/* hyphenate wb into w1 and w2; return zero on success */
+int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2)
+{
+	return 1;
 }
--- a/xroff.h
+++ b/xroff.h
@@ -152,15 +152,15 @@
 struct wb {
 	struct sbuf sbuf;
 	int f, s;		/* the last output font and size */
+	int r_f, r_s;		/* current font and size; use n_f and n_s if -1 */
 	int part;		/* partial input (\c) */
 	int els_neg, els_pos;	/* extra line spacing */
-	int h, v;		/* current buffer vertical and horizontal positions */
+	int h, v;		/* buffer vertical and horizontal positions */
 	int ct, sb, st;		/* \w registers */
 };
 
 void wb_init(struct wb *wb);
 void wb_done(struct wb *wb);
-void wb_reset(struct wb *wb);
 void wb_hmov(struct wb *wb, int n);
 void wb_vmov(struct wb *wb, int n);
 void wb_els(struct wb *wb, int els);
@@ -176,9 +176,9 @@
 void wb_drawxdot(struct wb *wb, int h, int v);
 void wb_drawxend(struct wb *wb);
 void wb_cat(struct wb *wb, struct wb *src);
+int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2);
 int wb_wid(struct wb *wb);
 int wb_empty(struct wb *wb);
-void wb_getels(struct wb *wb, int *els_neg, int *els_pos);
 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb);
 
 /* adjustment */
@@ -204,11 +204,12 @@
 void adj_nonl(struct adj *adj);
 
 /* rendering */
-void render(void);		/* read from in.c and print the output */
+void render(void);				/* the main loop */
 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 out_line(char *s);		/* output the given rendered line */
+void out_line(char *s);				/* output rendered line */
+int out_readc(char **s, char *d);		/* read request or glyph */
 void out(char *s, ...);				/* output troff cmd */
 void ren_hline(struct wb *wb, char *arg);	/* horizontal line */
 void ren_vline(struct wb *wb, char *arg);	/* vertical line */
@@ -252,7 +253,6 @@
 /* helpers */
 void errmsg(char *msg, ...);
 int utf8len(int c);
-char *utf8get(char *d, char *s);
 void schar_read(char *d, int (*next)(void));
 int schar_jump(char *d, int (*next)(void), void (*back)(int));