shithub: neatroff

Download patch

ref: 85a9a58654332424c4f865e430c502416f15cdf0
parent: d4a6c339e2825fa9bd57b0c8588096aa623c3bdd
author: Ali Gholami Rudi <ali@rudi.ir>
date: Wed Apr 17 08:59:29 EDT 2013

adj: add \x

--- a/adj.c
+++ b/adj.c
@@ -4,7 +4,7 @@
 #include <string.h>
 #include "xroff.h"
 
-#define ADJ_LL(a)	((a)->ll > (a)->li + (a)->lt ? (a)->ll - (a)->li - (a)->lt : 0)
+#define ADJ_LLEN(a)	((a)->ll > (a)->li + (a)->lt ? (a)->ll - (a)->li - (a)->lt : 0)
 
 struct word {
 	int beg;	/* word beginning offset */
@@ -11,6 +11,8 @@
 	int end;	/* word ending offset */
 	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 {
@@ -42,13 +44,6 @@
 	adj->i = in;
 }
 
-void adj_conf(struct adj *adj, int *ll, int *in, int *ti)
-{
-	*ll = adj->ll;
-	*in = adj->li;
-	*ti = adj->lt;
-}
-
 /* .ll, .in and .ti are delayed until the partial line is output */
 static void adj_confupdate(struct adj *adj)
 {
@@ -72,7 +67,7 @@
 		return a->nls;
 	if (adj_fullnf(a))
 		return 1;
-	return !a->word && a->wid > ADJ_LL(a);
+	return !a->word && a->wid > ADJ_LLEN(a);
 }
 
 /* is the adjustment buffer empty? */
@@ -88,12 +83,14 @@
 }
 
 /* move n words from the adjustment buffer to s */
-static int adj_move(struct adj *a, int n, char *s)
+static int adj_move(struct adj *a, int n, char *s, int *els_neg, int *els_pos)
 {
 	struct word *cur;
 	int lendiff;
 	int w = 0;
 	int i;
+	*els_neg = 0;
+	*els_pos = 0;
 	for (i = 0; i < n; i++) {
 		cur = &a->words[i];
 		s += sprintf(s, "\\h'%du'", cur->gap);
@@ -100,6 +97,10 @@
 		memcpy(s, a->buf + cur->beg, cur->end - cur->beg);
 		s += cur->end - cur->beg;
 		w += cur->wid + cur->gap;
+		if (cur->els_neg < *els_neg)
+			*els_neg = cur->els_neg;
+		if (cur->els_pos > *els_pos)
+			*els_pos = cur->els_pos;
 	}
 	*s = '\0';
 	if (!n)
@@ -120,29 +121,33 @@
 }
 
 /* fill and copy a line into s */
-int adj_fill(struct adj *a, int ad_b, int fill, char *s)
+int adj_fill(struct adj *a, int ad_b, int fill, char *s,
+		int *ll, int *in, int *ti, int *els_neg, int *els_pos)
 {
 	int adj_div, adj_rem;
 	int w = 0;
 	int i, n;
-	int ll = ADJ_LL(a);
+	int llen = ADJ_LLEN(a);
+	*ll = a->ll;
+	*in = a->li;
+	*ti = a->lt;
 	if (!fill || adj_fullnf(a)) {
 		a->nls--;
-		return adj_move(a, a->nwords, s);
+		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 > ll)
+		if (n && w + a->words[n].wid + a->words[n].gap > llen)
 			break;
 		w += a->words[n].wid + a->words[n].gap;
 	}
 	if (ad_b && n > 1 && n < a->nwords) {
-		adj_div = (ll - w) / (n - 1);
-		adj_rem = ll - w - adj_div * (n - 1);
-		a->wid += ll - w;
+		adj_div = (llen - w) / (n - 1);
+		adj_rem = llen - w - adj_div * (n - 1);
+		a->wid += llen - w;
 		for (i = 0; i < n - 1; i++)
 			a->words[i + 1].gap += adj_div + (i < adj_rem);
 	}
-	w = adj_move(a, n, s);
+	w = adj_move(a, n, s, els_neg, els_pos);
 	if (a->nwords)
 		a->wid -= a->words[0].gap;
 	a->words[0].gap = 0;
@@ -156,6 +161,8 @@
 	adj->word->wid = 0;
 	adj->word->gap = gap;
 	adj->wid += gap;
+	adj->word->els_neg = 0;
+	adj->word->els_pos = 0;
 }
 
 static void adj_wordend(struct adj *adj)
@@ -196,6 +203,17 @@
 	va_end(ap);
 	adj->word->wid += wid;
 	adj->wid += wid;
+}
+
+/* extra line-space requests */
+void adj_els(struct adj *adj, int els)
+{
+	if (!adj->word)
+		adj_put(adj, 0, "");
+	if (els < adj->word->els_neg)
+		adj->word->els_neg = els;
+	if (els > adj->word->els_pos)
+		adj->word->els_pos = els;
 }
 
 struct adj *adj_alloc(void)
--- a/ren.c
+++ b/ren.c
@@ -193,18 +193,14 @@
 	}
 }
 
-static void out_line(char *out, int w)
+static void out_line(char *out, int w, int ll, int li, int lt)
 {
-	int prev_d = n_d;
 	int ljust = 0;
 	char cmd[32];
-	int ll, li, lt, linelen;
-	ren_sp(0);
+	int llen = ll - li - lt;
 	n_n = w;
-	adj_conf(cadj, &ll, &li, &lt);
-	linelen = ll - li - lt;
 	if (n_u && !n_na && (n_j == AD_C || n_j == AD_R))
-		ljust = n_j == AD_C ? (linelen - w) / 2 : linelen - w;
+		ljust = n_j == AD_C ? (llen - w) / 2 : llen - w;
 	if (cdiv) {
 		if (cdiv->dl < w)
 			cdiv->dl = w;
@@ -218,19 +214,27 @@
 		OUT("V%d\n", n_d);
 		output(out);
 	}
-	if (!ren_traps(prev_d, n_d, 0))
-		ren_pagelimit(0);
 }
 
 static void ren_br(int force)
 {
 	char out[LNLEN];
-	int adj_b, w;
+	int ll, li, lt, els_neg, els_pos;
+	int adj_b, w, prev_d;
 	ren_first();
 	if (!adj_empty(cadj, n_u)) {
 		adj_b = n_u && !n_na && n_j == AD_B;
-		w = adj_fill(cadj, !force && adj_b, !force && n_u, out);
-		out_line(out, w);
+		w = adj_fill(cadj, !force && adj_b, !force && n_u, out,
+				&ll, &li, &lt, &els_neg, &els_pos);
+		prev_d = n_d;
+		if (els_neg)
+			ren_sp(-els_neg);
+		ren_sp(0);
+		out_line(out, w, ll, li, lt);
+		if (els_pos)
+			ren_sp(els_pos);
+		if (!ren_traps(prev_d, n_d, 0))
+			ren_pagelimit(0);
 	}
 }
 
@@ -421,7 +425,7 @@
 			int l = nextchar(c);
 			l += nextchar(c + l);
 			c[l] = '\0';
-		} else if (strchr("Dfhsvw", c[0])) {
+		} else if (strchr("Dfhsvwx", c[0])) {
 			if (c[0] == 'w') {
 				render_wid();
 				return 0;
@@ -441,6 +445,8 @@
 				ren_ps(arg);
 			if (c[0] == 'v')
 				adj_put(adj, 0, "\\v'%du'", eval(arg, 0, 'v'));
+			if (c[0] == 'x')
+				adj_els(adj, eval(arg, 0, 'v'));
 			return 0;
 		}
 	}
--- a/xroff.h
+++ b/xroff.h
@@ -171,7 +171,8 @@
 
 struct adj *adj_alloc(void);
 void adj_free(struct adj *adj);
-int adj_fill(struct adj *adj, int ad_b, int fill, char *dst);
+int adj_fill(struct adj *adj, int ad_b, int fill, char *dst,
+		int *ll, int *in, int *ti, int *els_neg, int *els_pos);
 void adj_put(struct adj *adj, int wid, char *s, ...);
 void adj_swid(struct adj *adj, int swid);
 int adj_full(struct adj *adj, int fill);
@@ -180,6 +181,7 @@
 void adj_ll(struct adj *adj, int ll);
 void adj_in(struct adj *adj, int in);
 void adj_ti(struct adj *adj, int ti);
+void adj_els(struct adj *adj, int els);
 void adj_conf(struct adj *adj, int *ll, int *in, int *ti);
 
 /* builtin number registers; n_X for .X register */