shithub: neatroff

Download patch

ref: 2da706eb682dd4906578d99521bc3e58467c10b1
parent: f53206e184d2bd1d4b234a52b43ac9234880325e
author: Ali Gholami Rudi <ali@rudi.ir>
date: Thu May 7 20:19:06 EDT 2015

fmt: allocate words and lines dynamically

This removes NLINES and NWORDS.
Suggested by Dirk-Wilhelm Peters <peters@schwertfisch.de>.

--- a/fmt.c
+++ b/fmt.c
@@ -40,15 +40,15 @@
 
 struct fmt {
 	/* queued words */
-	struct word words[NWORDS];
-	int nwords;
+	struct word *words;
+	int words_n, words_sz;
 	/* queued lines */
-	struct line lines[NLINES];
-	int l_head, l_tail;
+	struct line *lines;
+	int lines_head, lines_tail, lines_sz;
 	/* for paragraph adjustment */
-	long best[NWORDS];
-	int best_pos[NWORDS];
-	int best_dep[NWORDS];
+	long *best;
+	int *best_pos;
+	int *best_dep;
 	/* current line */
 	int gap;		/* space before the next word */
 	int nls;		/* newlines before the next word */
@@ -109,9 +109,7 @@
 
 static int fmt_nlines(struct fmt *f)
 {
-	if (f->l_tail <= f->l_head)
-		return f->l_head - f->l_tail;
-	return NLINES - f->l_tail + f->l_head;
+	return f->lines_head - f->lines_tail;
 }
 
 /* the total width of the specified words in f->words[] */
@@ -144,30 +142,34 @@
 }
 
 /* return the next line in the buffer */
-int fmt_nextline(struct fmt *f, struct sbuf *sbuf, int *w,
+char *fmt_nextline(struct fmt *f, int *w,
 		int *li, int *ll, int *els_neg, int *els_pos)
 {
 	struct line *l;
-	l = &f->lines[f->l_tail];
-	if (f->l_head == f->l_tail)
-		return 1;
+	if (f->lines_head == f->lines_tail)
+		return NULL;
+	l = &f->lines[f->lines_tail++];
 	*li = l->li;
 	*ll = l->ll;
 	*w = l->wid;
 	*els_neg = l->elsn;
 	*els_pos = l->elsp;
-	sbuf_append(sbuf, sbuf_buf(&l->sbuf));
-	sbuf_done(&l->sbuf);
-	f->l_tail = (f->l_tail + 1) % NLINES;
-	return 0;
+	return sbuf_out(&l->sbuf);
 }
 
 static struct line *fmt_mkline(struct fmt *f)
 {
-	struct line *l = &f->lines[f->l_head];
-	if ((f->l_head + 1) % NLINES == f->l_tail)
-		return NULL;
-	f->l_head = (f->l_head + 1) % NLINES;
+	struct line *l;
+	if (f->lines_head == f->lines_tail) {
+		f->lines_head = 0;
+		f->lines_tail = 0;
+	}
+	if (f->lines_head == f->lines_sz) {
+		f->lines_sz += 256;
+		f->lines = mextend(f->lines, f->lines_head,
+			f->lines_sz, sizeof(f->lines[0]));
+	}
+	l = &f->lines[f->lines_head++];
 	l->li = f->li;
 	l->ll = f->ll;
 	sbuf_init(&l->sbuf);
@@ -203,12 +205,12 @@
 {
 	if (fmt_fillwords(f, 1))
 		return 1;
-	if (fmt_extractline(f, 0, f->nwords, 0))
+	if (fmt_extractline(f, 0, f->words_n, 0))
 		return 1;
 	f->filled = 0;
 	f->nls--;
 	f->nls_sup = 0;
-	f->nwords = 0;
+	f->words_n = 0;
 	f->fillreq = 0;
 	return 0;
 }
@@ -220,7 +222,7 @@
 		return 1;
 	if (br) {
 		f->filled = 0;
-		if (f->nwords)
+		if (f->words_n)
 			if (fmt_sp(f))
 				return 1;
 	}
@@ -243,7 +245,7 @@
 	if (f->nls >= 1)
 		if (fmt_sp(f))
 			return 1;
-	if (f->nls == 0 && !f->filled && !f->nwords)
+	if (f->nls == 0 && !f->filled && !f->words_n)
 		fmt_sp(f);
 	f->nls++;
 	return 0;
@@ -255,7 +257,7 @@
 	if (f->fillreq > 0)
 		if (fmt_fillwords(f, 0))
 			return 1;
-	f->fillreq = f->nwords + 1;
+	f->fillreq = f->words_n + 1;
 	return 0;
 }
 
@@ -297,6 +299,16 @@
 	return n;
 }
 
+static struct word *fmt_mkword(struct fmt *f)
+{
+	if (f->words_n == f->words_sz) {
+		f->words_sz += 256;
+		f->words = mextend(f->words, f->words_n,
+			f->words_sz, sizeof(f->words[0]));
+	}
+	return &f->words[f->words_n++];
+}
+
 static void fmt_insertword(struct fmt *f, struct wb *wb, int gap)
 {
 	int hyidx[NHYPHSWORD];
@@ -309,11 +321,11 @@
 	int cf, cs, cm;
 	n = fmt_hyphmarks(src, hyidx, hyins);
 	if (n <= 0) {
-		fmt_wb2word(f, &f->words[f->nwords++], wb, 0, 1, gap, 1);
+		fmt_wb2word(f, fmt_mkword(f), wb, 0, 1, gap, 1);
 		return;
 	}
 	/* update f->fillreq considering the new sub-words */
-	if (f->fillreq == f->nwords + 1)
+	if (f->fillreq == f->words_n + 1)
 		f->fillreq += n;
 	wb_init(&wbc);
 	for (i = 0; i <= n; i++) {
@@ -320,7 +332,7 @@
 		beg = src + (i > 0 ? hyidx[i - 1] : 0);
 		end = src + (i < n ? hyidx[i] : strlen(src));
 		wb_catstr(&wbc, beg, end);
-		fmt_wb2word(f, &f->words[f->nwords++], &wbc,
+		fmt_wb2word(f, fmt_mkword(f), &wbc,
 			i < n && hyins[i], i == 0, i == 0 ? gap : 0, i == n);
 		/* restoring wbc */
 		wb_fnszget(&wbc, &cs, &cf, &cm);
@@ -335,10 +347,10 @@
 {
 	int nls = f->nls || f->nls_sup;
 	int swid = font_swid(dev_font(n_f), n_s, n_ss);
-	if (f->eos && f->nwords)
+	if (f->eos && f->words_n)
 		if ((nls && !f->gap) || (!nls && f->gap == 2 * swid))
 			return swid + font_swid(dev_font(n_f), n_s, n_sss);
-	return (nls && !f->gap && f->nwords) ? swid : f->gap;
+	return (nls && !f->gap && f->words_n) ? swid : f->gap;
 }
 
 /* insert wb into fmt */
@@ -346,13 +358,13 @@
 {
 	if (wb_empty(wb))
 		return 0;
-	if (f->nwords + NHYPHSWORD >= NWORDS || fmt_confchanged(f))
+	if (fmt_confchanged(f))
 		if (fmt_fillwords(f, 0))
 			return 1;
 	if (FMT_FILL(f) && f->nls && f->gap)
 		if (fmt_sp(f))
 			return 1;
-	if (!f->nwords)		/* apply the new .l and .i */
+	if (!f->words_n)		/* apply the new .l and .i */
 		fmt_confupdate(f);
 	f->gap = fmt_wordgap(f);
 	f->eos = wb_eos(wb);
@@ -467,7 +479,7 @@
 	int lwid = 0;		/* current line length */
 	int swid = 0;		/* amount of stretchable spaces */
 	int nspc = 0;		/* number of stretchable spaces */
-	if (f->fillreq > 0 && f->fillreq <= f->nwords) {
+	if (f->fillreq > 0 && f->fillreq <= f->words_n) {
 		fmt_findcost(f, f->fillreq);
 		return f->fillreq;
 	}
@@ -566,18 +578,23 @@
 	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;
+	llen = fmt_wordslen(f, 0, f->words_n) -
+		fmt_spacessum(f, 0, f->words_n) * n_ssh / 100;
 	/* not enough words to fill */
-	if ((f->fillreq <= 0 || f->nwords < f->fillreq) && llen <= FMT_LLEN(f))
+	if ((f->fillreq <= 0 || f->words_n < f->fillreq) && llen <= FMT_LLEN(f))
 		return 0;
 	nreq = (n_hy & HY_LAST) ? fmt_safelines() : 0;
 	if (nreq > 0 && nreq <= fmt_nlines(f))
 		return 1;
 	/* resetting positions */
-	for (i = 0; i < f->nwords + 1; i++)
+	f->best = malloc((f->words_n + 1) * sizeof(f->best[0]));
+	f->best_pos = malloc((f->words_n + 1) * sizeof(f->best_pos[0]));
+	f->best_dep = malloc((f->words_n + 1) * sizeof(f->best_dep[0]));
+	memset(f->best, 0, (f->words_n + 1) * sizeof(f->best[0]));
+	memset(f->best_dep, 0, (f->words_n + 1) * sizeof(f->best_dep[0]));
+	for (i = 0; i < f->words_n + 1; i++)
 		f->best_pos[i] = -1;
-	end = fmt_breakparagraph(f, f->nwords, br);
+	end = fmt_breakparagraph(f, f->words_n, br);
 	if (nreq > 0) {
 		end_head = fmt_head(f, nreq - fmt_nlines(f), end);
 		head = end_head < end;
@@ -585,14 +602,20 @@
 	}
 	/* recursively add lines */
 	n = end > 0 ? fmt_break(f, end) : 0;
-	f->nwords -= n;
+	f->words_n -= n;
 	f->fillreq -= n;
-	fmt_movewords(f, 0, n, f->nwords);
-	f->filled = n && !f->nwords;
-	if (f->nwords)
+	fmt_movewords(f, 0, n, f->words_n);
+	f->filled = n && !f->words_n;
+	if (f->words_n)
 		f->words[0].gap = 0;
-	if (f->nwords)		/* apply the new .l and .i */
+	if (f->words_n)		/* apply the new .l and .i */
 		fmt_confupdate(f);
+	free(f->best);
+	free(f->best_pos);
+	free(f->best_dep);
+	f->best = NULL;
+	f->best_pos = NULL;
+	f->best_dep = NULL;
 	return head || n != end;
 }
 
@@ -605,22 +628,24 @@
 
 void fmt_free(struct fmt *fmt)
 {
+	free(fmt->lines);
+	free(fmt->words);
 	free(fmt);
 }
 
 int fmt_wid(struct fmt *fmt)
 {
-	return fmt_wordslen(fmt, 0, fmt->nwords) + fmt_wordgap(fmt);
+	return fmt_wordslen(fmt, 0, fmt->words_n) + fmt_wordgap(fmt);
 }
 
 int fmt_morewords(struct fmt *fmt)
 {
-	return fmt_morelines(fmt) || fmt->nwords;
+	return fmt_morelines(fmt) || fmt->words_n;
 }
 
 int fmt_morelines(struct fmt *fmt)
 {
-	return fmt->l_head != fmt->l_tail;
+	return fmt->lines_head != fmt->lines_tail;
 }
 
 /* suppress the last newline */
--- a/ren.c
+++ b/ren.c
@@ -356,20 +356,19 @@
 /* read a line from fmt and send it to ren_line() */
 static int ren_passline(struct fmt *fmt)
 {
-	struct sbuf sbuf;
+	char *buf;
 	int ll, li, els_neg, els_pos, w, ret;
 	int ad = n_j;
 	ren_first();
 	if (!fmt_morewords(fmt))
 		return 0;
-	sbuf_init(&sbuf);
-	fmt_nextline(fmt, &sbuf, &w, &li, &ll, &els_neg, &els_pos);
+	buf = fmt_nextline(fmt, &w, &li, &ll, &els_neg, &els_pos);
 	if ((n_cp && !n_u) || n_na)
 		ad = AD_L;
 	if (n_ce)
 		ad = AD_C;
-	ret = ren_line(sbuf_buf(&sbuf), w, ad, 1, li, ll, els_neg, els_pos);
-	sbuf_done(&sbuf);
+	ret = ren_line(buf, w, ad, 1, li, ll, els_neg, els_pos);
+	free(buf);
 	return ret;
 }
 
--- a/roff.h
+++ b/roff.h
@@ -32,9 +32,6 @@
 #define RNLEN		NMLEN	/* register/macro name */
 #define NREGS		8192	/* number of mapped names */
 #define ILNLEN		1000	/* line limit of input files */
-#define LNLEN		4000	/* line buffer length (ren.c/out.c) */
-#define NWORDS		1024	/* number of queued words in formatting buffer */
-#define NLINES		32	/* number of queued lines in formatting buffer */
 #define NARGS		16	/* number of macro arguments */
 #define NPREV		16	/* environment stack depth */
 #define NTRAPS		1024	/* number of traps per page */
@@ -211,6 +208,7 @@
 
 void sbuf_init(struct sbuf *sbuf);
 void sbuf_done(struct sbuf *sbuf);
+char *sbuf_out(struct sbuf *sbuf);
 char *sbuf_buf(struct sbuf *sbuf);
 void sbuf_add(struct sbuf *sbuf, int c);
 void sbuf_append(struct sbuf *sbuf, char *s);
@@ -315,7 +313,7 @@
 int fmt_fill(struct fmt *fmt, int br);
 int fmt_morelines(struct fmt *fmt);
 int fmt_morewords(struct fmt *fmt);
-int fmt_nextline(struct fmt *fmt, struct sbuf *sbuf, int *w,
+char *fmt_nextline(struct fmt *fmt, int *w,
 		int *li, int *ll, int *els_neg, int *els_pos);
 
 /* rendering */
--- a/sbuf.c
+++ b/sbuf.c
@@ -73,3 +73,10 @@
 {
 	free(sbuf->s);
 }
+
+char *sbuf_out(struct sbuf *sbuf)
+{
+	char *s = sbuf->s;
+	memset(sbuf, 0, sizeof(*sbuf));
+	return s;
+}