shithub: neatroff

Download patch

ref: d7d272b68072acd84a344aa8351230c41edf311b
parent: 05ce05cf03e9a81cfa8b65f45e91739d83741fe3
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat May 10 04:47:16 EDT 2014

fmt: shrink word spaces with .ssh request

The new .ssh request specifies the amount (in percentage) by which
word spaces may be shrinked while filling.  The default value is zero.

--- a/fmt.c
+++ b/fmt.c
@@ -120,7 +120,7 @@
 	return beg < end ? w + f->words[end - 1].hy : 0;
 }
 
-/* the number stretchable spaces in f */
+/* the number of stretchable spaces in f */
 static int fmt_spaces(struct fmt *f, int beg, int end)
 {
 	int i, n = 0;
@@ -130,6 +130,16 @@
 	return n;
 }
 
+/* the amount of stretchable spaces in f */
+static int fmt_spacessum(struct fmt *f, int beg, int end)
+{
+	int i, n = 0;
+	for (i = beg + 1; i < end; i++)
+		if (f->words[i].str)
+			n += f->words[i].gap;
+	return n;
+}
+
 /* return the next line in the buffer */
 int fmt_nextline(struct fmt *f, struct sbuf *sbuf, int *w,
 		int *li, int *ll, int *els_neg, int *els_pos)
@@ -307,7 +317,8 @@
 {
 	int i, pen = 0;
 	long cur;
-	int lwid = 0;
+	int lwid = 0;			/* current line length */
+	int swid = 0;			/* amount of spaces */
 	int llen = MAX(1, FMT_LLEN(f));
 	if (pos <= 0)
 		return 0;
@@ -323,8 +334,11 @@
 		lwid += f->words[i].wid;
 		if (i + 1 < pos)
 			lwid += f->words[i + 1].gap;
-		if (lwid > llen && pos - i > 1)
-			break;
+		if (i + 1 < pos && f->words[i + 1].str)
+			swid += f->words[i + 1].gap;
+		if (lwid - (swid * n_ssh / 100) > llen)
+			if (pos - i > 1)
+				break;
 		cur = fmt_findcost(f, i) + FMT_COST(lwid, llen, pen);
 		if (f->best_pos[pos] < 0 || cur < f->best[pos]) {
 			f->best_pos[pos] = i;
@@ -409,6 +423,10 @@
 	if (FMT_ADJ(f) && nspc) {
 		fmt_div = (llen - w) / nspc;
 		fmt_rem = (llen - w) % nspc;
+		if (fmt_rem < 0) {
+			fmt_div--;
+			fmt_rem += nspc;
+		}
 		for (i = beg + 1; i < end; i++)
 			if (f->words[i].str)
 				f->words[i].gap += fmt_div + (fmt_rem-- > 0);
@@ -433,12 +451,14 @@
 	int end;	/* the final line ends before this word */
 	int end_head;	/* like end, but only the first nreq lines included */
 	int head = 0;	/* only nreq first lines have been formatted */
+	int llen;	/* line length, taking shrinkable spaces into account */
 	int n, i;
 	if (!FMT_FILL(f))
 		return 0;
+	llen = fmt_wordslen(f, 0, f->nwords) -
+		fmt_spacessum(f, 0, f->nwords) * n_ssh / 100;
 	/* not enough words to fill */
-	if ((f->fillreq <= 0 || f->nwords < f->fillreq) &&
-			fmt_wordslen(f, 0, f->nwords) <= FMT_LLEN(f))
+	if ((f->fillreq <= 0 || f->nwords < f->fillreq) && llen <= FMT_LLEN(f))
 		return 0;
 	nreq = (n_hy & HY_LAST) ? fmt_safelines() : 0;
 	if (nreq > 0 && nreq <= fmt_nlines(f))
--- a/reg.c
+++ b/reg.c
@@ -36,7 +36,7 @@
 	".nS", ".m", ".s", ".u", ".v",
 	".it", ".itn", ".mc", ".mcn",
 	".ce", ".f0", ".hy", ".hyp", ".i0", ".l0",
-	".L0", ".m0", ".n0", ".s0", ".ss",
+	".L0", ".m0", ".n0", ".s0", ".ss", ".ssh",
 	".ti", ".lt", ".lt0", ".v0",
 };
 
--- a/roff.h
+++ b/roff.h
@@ -468,6 +468,7 @@
 #define n_ns		(*nreg(map(".ns")))	/* .ns mode */
 #define n_o0		(*nreg(map(".o0")))	/* last .o */
 #define n_ss		(*nreg(map(".ss")))	/* .ss value */
+#define n_ssh		(*nreg(map(".ssh")))	/* .ssh value; word space compression */
 #define n_s0		(*nreg(map(".s0")))	/* last .s */
 #define n_sv		(*nreg(map(".sv")))	/* .sv value */
 #define n_lt		(*nreg(map(".lt")))	/* .lt value */
--- a/tr.c
+++ b/tr.c
@@ -424,6 +424,11 @@
 		n_ss = eval_re(args[1], n_ss, 0);
 }
 
+static void tr_ssh(char **args)
+{
+	n_ssh = args[1] ? eval_re(args[1], n_ssh, 0) : 0;
+}
+
 static void tr_cs(char **args)
 {
 	if (!args[1])
@@ -902,6 +907,7 @@
 	{"so", tr_so},
 	{"sp", tr_sp},
 	{"ss", tr_ss},
+	{"ssh", tr_ssh},
 	{"sv", tr_sv},
 	{"sy", tr_sy, mkargs_eol},
 	{"ta", tr_ta},