shithub: neatroff

Download patch

ref: e8ccdf0b751754aae72e4765e556e9a1760443a9
parent: 02e2d40bd555472b4a58290814f1082f56d0a0ca
author: Ali Gholami Rudi <ali@rudi.ir>
date: Mon Feb 18 15:23:43 EST 2013

adj: import the text filling logic

--- a/adj.c
+++ b/adj.c
@@ -1,10 +1,62 @@
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include "xroff.h"
 
-static void adj_nf(struct adj *a, int n, char *s)
+struct word {
+	int beg;	/* word beginning offset */
+	int end;	/* word ending offset */
+	int wid;	/* word width */
+	int blanks;	/* blanks before word */
+};
+
+struct adj {
+	char buf[LNLEN];		/* line buffer */
+	int len;
+	struct word words[NWORDS];	/* words in buf  */
+	int nwords;
+	int wid;			/* total width of buffer */
+	struct word *word;		/* current word */
+	int swid;			/* current space width */
+	int spaces;			/* spaces before the next word */
+	int nl_cnt;			/* newlines before the next word */
+	int nl_pre;			/* previous newlines; for "\n\n" */
+	int nl_ins;			/* indented line after newline */
+};
+
+/* does the adjustment buffer need to be flushed without filling? */
+static int adj_fullnf(struct adj *a)
 {
+	return a->nl_ins || a->nl_pre + a->nl_cnt > 1 ||
+		(a->nl_cnt > 0 && !a->nwords);
+}
+
+/* does the adjustment buffer need to be flushed? */
+int adj_full(struct adj *a, int mode, int linelen)
+{
+	if (mode == ADJ_N)
+		return a->nl_cnt;
+	if (adj_fullnf(a))
+		return 1;
+	return !a->word && a->wid > linelen;
+}
+
+/* is the adjustment buffer empty? */
+int adj_empty(struct adj *a, int mode)
+{
+	return mode == ADJ_N ? !a->nl_cnt : !a->nwords && !adj_fullnf(a);
+}
+
+/* set space width */
+void adj_swid(struct adj *adj, int swid)
+{
+	adj->swid = swid;
+}
+
+/* move n words from the adjustment buffer to the s buffer */
+static void adj_move(struct adj *a, int n, char *s)
+{
 	struct word *cur;
 	int lendiff;
 	int w = 0;
@@ -17,6 +69,8 @@
 		w += cur->wid + cur->blanks;
 	}
 	*s = '\0';
+	if (!n)
+		return;
 	lendiff = n < a->nwords ? a->words[n].beg : a->len;
 	memmove(a->buf, a->buf + lendiff, a->len - lendiff);
 	a->len -= lendiff;
@@ -29,13 +83,17 @@
 	}
 }
 
-void adj_fi(struct adj *a, int mode, int ll, char *s)
+/* fill and copy a line into s */
+void adj_fill(struct adj *a, int mode, int ll, char *s)
 {
 	int adj_div, adj_rem;
 	int w = 0;
 	int i, n;
-	if (mode == ADJ_N) {
-		adj_nf(a, a->nwords, s);
+	if (mode == ADJ_N || adj_fullnf(a)) {
+		a->nl_pre = 1;
+		a->nl_cnt--;
+		a->nl_ins = 0;
+		adj_move(a, a->nwords, s);
 		return;
 	}
 	for (n = 0; n < a->nwords; n++) {
@@ -50,13 +108,13 @@
 		for (i = 0; i < n - 1; i++)
 			a->words[i + 1].blanks += adj_div + (i < adj_rem);
 	}
-	adj_nf(a, n, s);
+	adj_move(a, n, s);
 	if (a->nwords)
 		a->wid -= a->words[0].blanks;
 	a->words[0].blanks = 0;
 }
 
-void adj_wordbeg(struct adj *adj, int blanks)
+static void adj_wordbeg(struct adj *adj, int blanks)
 {
 	adj->word = &adj->words[adj->nwords++];
 	adj->word->beg = adj->len;
@@ -65,34 +123,57 @@
 	adj->wid += blanks;
 }
 
-void adj_wordend(struct adj *adj)
+static void adj_wordend(struct adj *adj)
 {
-	adj->word->end = adj->len;
+	if (adj->word)
+		adj->word->end = adj->len;
 	adj->word = NULL;
 }
 
-void adj_putcmd(struct adj *adj, char *fmt, ...)
+/* insert s into the adjustment buffer */
+void adj_put(struct adj *adj, int wid, char *s, ...)
 {
 	va_list ap;
-	va_start(ap, fmt);
-	adj->len += vsprintf(adj->buf + adj->len, fmt, ap);
+	if (!strcmp(s, " ")) {
+		adj_wordend(adj);
+		adj->spaces += wid;
+		adj->swid = wid;
+		if (adj->nl_cnt)
+			adj->nl_ins = 1;
+		return;
+	}
+	if (!strcmp(s, "\n")) {
+		adj_wordend(adj);
+		adj->nl_cnt++;
+		adj->spaces = 0;
+		adj->nl_ins = 0;
+		adj->swid = wid;
+		return;
+	}
+	if (!adj->word) {
+		if (adj->nl_cnt && !adj->spaces && adj->nwords >= 1)
+			adj->spaces = adj->swid;
+		adj_wordbeg(adj, adj->spaces);
+		adj->nl_cnt = 0;
+		adj->spaces = 0;
+		adj->nl_ins = 0;
+		adj->nl_pre = 0;
+	}
+	va_start(ap, s);
+	adj->len += vsprintf(adj->buf + adj->len, s, ap);
 	va_end(ap);
-}
-
-void adj_putchar(struct adj *adj, int wid, char *s)
-{
-	strcpy(adj->buf + adj->len, s);
-	adj->len += strlen(s);
 	adj->word->wid += wid;
 	adj->wid += wid;
 }
 
-int adj_inword(struct adj *adj)
+struct adj *adj_alloc(void)
 {
-	return adj->word != NULL;
+	struct adj *adj = malloc(sizeof(*adj));
+	memset(adj, 0, sizeof(*adj));
+	return adj;
 }
 
-int adj_inbreak(struct adj *adj, int ll)
+void adj_free(struct adj *adj)
 {
-	return !adj_inword(adj) && adj->wid > ll;
+	free(adj);
 }
--- a/ren.c
+++ b/ren.c
@@ -4,7 +4,8 @@
 #include <string.h>
 #include "xroff.h"
 
-#define LL		(n_l - n_i)	/* effective line length */
+#define ADJ_LL		(n_l - n_i)	/* effective line length */
+#define ADJ_MODE	(n_u ? n_ad : ADJ_N)
 
 /* diversion */
 struct div {
@@ -11,7 +12,7 @@
 	int f, s, f0, s0;		/* backup variables */
 };
 
-static struct adj adj;			/* line buffer */
+static struct adj *adj;			/* line buffer */
 static int ren_backed = -1;		/* pushed back character */
 static int ren_div;			/* current diversion */
 static struct sbuf out_div;		/* current diversion output */
@@ -116,11 +117,11 @@
 	}
 }
 
-static void ren_br(int sp)
+static void ren_br(int sp, int force)
 {
 	char out[LNLEN];
-	if (adj.nwords) {
-		adj_fi(&adj, n_u ? n_ad : ADJ_N, LL, out);
+	if (!adj_empty(adj, ADJ_MODE)) {
+		adj_fill(adj, force ? ADJ_N : ADJ_MODE, ADJ_LL, out);
 		ren_ne(n_v);
 		out_line(out);
 		ren_ne(n_v);
@@ -131,7 +132,7 @@
 
 void tr_br(char **args)
 {
-	ren_br(0);
+	ren_br(0, 1);
 }
 
 void tr_sp(char **args)
@@ -139,7 +140,7 @@
 	int sp = 0;
 	if (args[1])
 		sp = tr_int(args[1], 0, 'v');
-	ren_br(sp);
+	ren_br(sp, 1);
 }
 
 void ren_page(int pg)
@@ -154,7 +155,7 @@
 void tr_bp(char **args)
 {
 	if (!ren_div) {
-		ren_br(0);
+		ren_br(0, 1);
 		ren_page(args[1] ? tr_int(args[1], n_pg, 'v') : n_pg + 1);
 	}
 }
@@ -174,7 +175,7 @@
 
 void tr_in(char **args)
 {
-	ren_br(0);
+	ren_br(0, 1);
 	if (args[1])
 		n_i = tr_int(args[1], n_i, 'm');
 }
@@ -204,7 +205,7 @@
 
 void tr_nf(char **args)
 {
-	ren_br(0);
+	ren_br(0, 1);
 	n_u = 0;
 }
 
@@ -250,37 +251,18 @@
 	char c[GNLEN * 2];
 	char arg[ILNLEN];
 	struct glyph *g;
-	int blanks = 0;
-	int newline = 0;
 	int r_s = n_s;
 	int r_f = n_f;
 	int esc = 0;
-	int space_br = 0;	/* .br caused by indented lines */
-	ren_br(0);
+	adj = adj_alloc();
+	ren_br(0, 1);
 	while (nextchar(c) > 0) {
-		g = NULL;
-		if (n_u && adj_inbreak(&adj, LL))
-			ren_br(0);
-		if (c[0] == ' ' || c[0] == '\n') {
-			if (adj_inword(&adj))
-				adj_wordend(&adj);
-			if (!n_u && c[0] == '\n')
-				ren_br(0);
-			if (n_u && newline && c[0] == '\n')
-				ren_br(n_v);
-			if (n_u && newline && c[0] == ' ' && !space_br) {
-				space_br = 1;
-				ren_br(0);
-			}
-			if (c[0] == '\n') {
-				blanks = 0;
-				newline = 1;
-				space_br = 0;
-			}
-			if (c[0] == ' ')
-				blanks += charwid(dev_spacewid(), n_s);
+		if (c[0] == ' ' || c[0] == '\n')
+			adj_put(adj, charwid(dev_spacewid(), n_s), c);
+		while (adj_full(adj, ADJ_MODE, ADJ_LL))
+			ren_br(0, 0);
+		if (c[0] == ' ' || c[0] == '\n')
 			continue;
-		}
 		esc = 0;
 		if (c[0] == '\\') {
 			esc = 1;
@@ -307,19 +289,13 @@
 				continue;
 			}
 		}
-		if (!adj_inword(&adj)) {
-			if (newline && !blanks && adj.nwords >= 1)
-				blanks = charwid(dev_spacewid(), n_s);
-			adj_wordbeg(&adj, blanks);
-			newline = 0;
-			blanks = 0;
-		}
 		if (r_s != n_s) {
-			adj_putcmd(&adj, "\\s(%02d", n_s);
+			adj_swid(adj, charwid(dev_spacewid(), n_s));
+			adj_put(adj, 0, "\\s(%02d", n_s);
 			r_s = n_s;
 		}
 		if (r_f != n_f) {
-			adj_putcmd(&adj, "\\f(%02d", n_f);
+			adj_put(adj, 0, "\\f(%02d", n_f);
 			r_f = n_f;
 		}
 		if (utf8len(c[0]) == strlen(c))
@@ -327,9 +303,8 @@
 		else
 			sprintf(arg, "\\(%s", c);
 		g = dev_glyph(c, n_f);
-		adj_putchar(&adj, charwid(g ? g->wid : dev_spacewid(), n_s), arg);
+		adj_put(adj, charwid(g ? g->wid : dev_spacewid(), n_s), arg);
 	}
-	if (n_u)
-		ren_br(0);
-	ren_br(0);
+	ren_br(0, 1);
+	adj_free(adj);
 }
--- a/xroff.c
+++ b/xroff.c
@@ -1,7 +1,7 @@
 /*
  * neatroff troff clone
  *
- * Copyright (C) 2012 Ali Gholami Rudi <ali at rudi dot ir>
+ * Copyright (C) 2012-2013 Ali Gholami Rudi <ali at rudi dot ir>
  *
  * This program is released under the modified BSD license.
  */
--- a/xroff.h
+++ b/xroff.h
@@ -147,26 +147,10 @@
 #define ADJ_B		1
 #define ADJ_N		2		/* no adjustment (.nf) */
 
-struct word {
-	int beg;	/* word beginning offset */
-	int end;	/* word ending offset */
-	int wid;	/* word width */
-	int blanks;	/* blanks before word */
-};
-
-struct adj {
-	char buf[LNLEN];		/* line buffer */
-	int len;
-	struct word words[NWORDS];	/* words in buf  */
-	int nwords;
-	int wid;			/* total width of buffer */
-	struct word *word;		/* current word */
-};
-
-void adj_fi(struct adj *adj, int mode, int linelen, char *dst);
-void adj_wordbeg(struct adj *adj, int blanks);
-void adj_wordend(struct adj *adj);
-void adj_putcmd(struct adj *adj, char *s, ...);
-void adj_putchar(struct adj *adj, int wid, char *s);
-int adj_inword(struct adj *adj);
-int adj_inbreak(struct adj *adj, int linelen);
+struct adj *adj_alloc(void);
+void adj_free(struct adj *adj);
+void adj_fill(struct adj *adj, int mode, int linelen, char *dst);
+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 mode, int linelen);
+int adj_empty(struct adj *adj, int mode);