ref: 73e0f630cdbbeb348edeb7eada032b368968b624
parent: ab56322f71018914577c058d2454e2b2d6177b5d
author: Ali Gholami Rudi <[email protected]>
date: Thu May 8 10:01:57 EDT 2014
fmt: import the handling of HY_LAST and \p from ren.c
--- a/fmt.c
+++ b/fmt.c
@@ -2,15 +2,13 @@
* line formatting buffer for line adjustment and hyphenation
*
* The line formatting buffer does two main functions: breaking
- * words into lines (possibly after hyphenating some of them), and, if
- * requested, adjusting the space between words in a line. In this
- * file the first step is referred to as filling.
+ * words into lines (possibly after hyphenating some of them),
+ * and, if requested, adjusting the space between words in a line.
+ * In this file the first step is referred to as filling.
*
- * Inputs are specified via these functions:
- * + fmt_word(): for appending space-separated words.
- * + fmt_space(): for appending spaces.
- * + fmt_newline(): for appending new lines.
- *
+ * Functions like fmt_word() return nonzero on failure, which
+ * means the call should be repeated after fetching previously
+ * formatted lines via fmt_nextline().
*/
#include <stdio.h>
#include <stdlib.h>
@@ -28,7 +26,7 @@
int elsn, elsp; /* els_neg and els_pos */
int gap; /* the space before this word */
int hy; /* hyphen width if inserted after this word */
- int str; /* does the spece before it stretch */
+ int str; /* does the space before it stretch */
};
struct line {
@@ -54,6 +52,7 @@
int li, ll; /* current line indentation and length */
int filled; /* filled all words in the last fmt_fill() */
int eos; /* last word ends a sentence */
+ int fillreq; /* fill after the last word (\p) */
};
/* .ll, .in and .ti are delayed until the partial line is output */
@@ -164,7 +163,8 @@
static int fmt_sp(struct fmt *f)
{
struct line *l;
- fmt_fill(f, 0, 0);
+ if (fmt_fill(f))
+ return 1;
l = fmt_mkline(f);
if (!l)
return 1;
@@ -172,15 +172,18 @@
f->nls--;
l->wid = fmt_wordscopy(f, 0, f->nwords, &l->sbuf, &l->elsn, &l->elsp);
f->nwords = 0;
+ f->fillreq = 0;
return 0;
}
-void fmt_br(struct fmt *f)
+int fmt_br(struct fmt *f)
{
- fmt_fill(f, 0, 0);
+ if (fmt_fill(f))
+ return 1;
f->filled = 0;
if (f->nwords)
fmt_sp(f);
+ return 0;
}
void fmt_space(struct fmt *fmt)
@@ -188,23 +191,33 @@
fmt->gap += FMT_SWID(fmt);
}
-void fmt_newline(struct fmt *f)
+int fmt_newline(struct fmt *f)
{
- f->nls++;
f->gap = 0;
if (!FMT_FILL(f)) {
+ f->nls++;
fmt_sp(f);
- return;
+ return 0;
}
- if (f->nls == 1 && !f->filled && !f->nwords)
+ if (f->nls >= 1)
+ if (fmt_sp(f))
+ return 1;
+ if (f->nls == 0 && !f->filled && !f->nwords)
fmt_sp(f);
- if (f->nls > 1) {
- if (!f->filled)
- fmt_sp(f);
- fmt_sp(f);
- }
+ f->nls++;
+ return 0;
}
+/* format the paragraph after the next word (\p) */
+int fmt_fillreq(struct fmt *f)
+{
+ if (f->fillreq > 0)
+ if (fmt_fill(f))
+ return 1;
+ f->fillreq = f->nwords + 1;
+ return 0;
+}
+
static void fmt_wb2word(struct fmt *f, struct word *word, struct wb *wb,
int hy, int str, int gap)
{
@@ -253,12 +266,13 @@
}
/* insert wb into fmt */
-void fmt_word(struct fmt *f, struct wb *wb)
+int fmt_word(struct fmt *f, struct wb *wb)
{
- if (f->nwords == NWORDS || fmt_confchanged(f))
- fmt_fill(f, 0, 0);
- if (wb_empty(wb) || f->nwords == NWORDS)
- return;
+ if (f->nwords + NHYPHS >= NWORDS || fmt_confchanged(f))
+ if (fmt_fill(f))
+ return 1;
+ if (wb_empty(wb))
+ return 0;
if (FMT_FILL(f) && f->nls && f->gap)
fmt_sp(f);
if (!f->nwords) /* apply the new .l and .i */
@@ -270,6 +284,7 @@
f->filled = 0;
f->nls = 0;
f->gap = 0;
+ return 0;
}
/* assuming an empty line has cost 10000; take care of integer overflow */
@@ -317,13 +332,17 @@
}
/* return the last filled word */
-static int fmt_breakparagraph(struct fmt *f, int pos, int all)
+static int fmt_breakparagraph(struct fmt *f, int pos)
{
int i;
int best = -1;
int llen = FMT_LLEN(f);
int lwid = 0;
- if (all || (pos > 0 && f->words[pos - 1].wid >= llen)) {
+ if (f->fillreq > 0 && f->fillreq <= f->nwords) {
+ fmt_findcost(f, f->fillreq);
+ return f->fillreq;
+ }
+ if (pos > 0 && f->words[pos - 1].wid >= llen) {
fmt_findcost(f, pos);
return pos;
}
@@ -335,7 +354,7 @@
lwid += f->words[i].wid;
if (i + 1 < pos)
lwid += f->words[i + 1].gap;
- if (lwid > llen && pos - i > 1)
+ if (lwid > llen && i + 1 < pos)
break;
if (best < 0 || fmt_findcost(f, i) < fmt_findcost(f, best))
best = i;
@@ -344,6 +363,7 @@
return best;
}
+/* extract the first nreq formatted lines before the word at pos */
static int fmt_head(struct fmt *f, int nreq, int pos)
{
int best = -1;
@@ -350,7 +370,7 @@
int i;
if (nreq <= 0 || f->best_dep[pos] < nreq)
return pos;
- for (i = 1; i < pos && f->best_dep[i] <= nreq; i++) {
+ for (i = 1; i <= pos && f->best_dep[i] <= nreq; i++) {
fmt_findcost(f, i);
if (f->best_dep[i] == nreq && !f->words[i - 1].hy)
best = i;
@@ -388,19 +408,17 @@
return ret + (end - beg);
}
-/*
- * fill the words collected in the buffer
- *
- * The argument nreq, when nonzero, limits the number of lines
- * to format. It also tells fmt_fill() not to hyphenate the
- * last word of nreq-th line. This is used in ren.c to prevent
- * hyphenating last lines of pages.
- *
- * The all argument forces fmt_fill() to fill all of the words.
- * This is used for the \p escape sequence.
- */
-int fmt_fill(struct fmt *f, int nreq, int all)
+/* estimated number of lines until traps or the end of a page */
+static int fmt_safelines(void)
{
+ int lnht = MAX(1, n_L) * n_v;
+ return (f_nexttrap() + lnht - 1) / lnht;
+}
+
+/* fill the words collected in the buffer */
+int fmt_fill(struct fmt *f)
+{
+ int nreq; /* the number of lines until a trap */
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 */
@@ -408,14 +426,16 @@
if (!FMT_FILL(f))
return 0;
/* not enough words to fill */
- if (!all && fmt_wordslen(f, 0, f->nwords) <= FMT_LLEN(f))
+ if ((f->fillreq <= 0 || f->nwords < f->fillreq) &&
+ fmt_wordslen(f, 0, f->nwords) <= FMT_LLEN(f))
return 0;
+ nreq = (n_hy & HY_LAST) ? fmt_safelines() : 0;
if (nreq > 0 && nreq <= fmt_nlines(f))
- return 0;
+ return 1;
/* resetting positions */
for (i = 0; i < f->nwords + 1; i++)
f->best_pos[i] = -1;
- end = fmt_breakparagraph(f, f->nwords, all);
+ end = fmt_breakparagraph(f, f->nwords);
if (nreq > 0) {
end_head = fmt_head(f, nreq - fmt_nlines(f), end);
head = end_head < end;
@@ -424,6 +444,7 @@
/* recursively add lines */
n = fmt_break(f, end);
f->nwords -= n;
+ f->fillreq -= n;
fmt_movewords(f, 0, n, f->nwords);
f->filled = n && !f->nwords;
if (f->nwords)
--- a/ren.c
+++ b/ren.c
@@ -30,7 +30,6 @@
static int ren_cnl; /* current char is a newline */
static int ren_unbuf[8]; /* ren_back() buffer */
static int ren_un;
-static int ren_fillreq; /* \p request */
static int ren_aborted; /* .ab executed */
static int bp_first = 1; /* prior to the first page */
@@ -369,28 +368,27 @@
return ret;
}
-/* estimated number of lines until traps or the end of a page */
-static int ren_safelines(void)
+/* output formatted lines in fmt */
+static void ren_fmtpop(struct fmt *fmt)
{
- return f_nexttrap() / (MAX(1, n_L) * n_v);
+ while (fmt_morelines(fmt))
+ ren_passline(fmt);
}
-/* call fmt_fill() for all pending lines */
-static void ren_fmtfill(struct fmt *fmt, int all)
+/* format and output all lines in fmt */
+static void ren_fmtpopall(struct fmt *fmt)
{
- int n;
- do { /* do not hyphenate lines preceding traps or new pages */
- n = fmt_fill(fmt, (n_hy & HY_LAST) ? ren_safelines() : 0, all);
- while (fmt_morelines(fmt))
- ren_passline(fmt);
- } while (n);
+ while (fmt_fill(fmt))
+ ren_fmtpop(fmt);
+ ren_fmtpop(fmt);
}
/* output current line; returns 1 if triggered a trap */
static int ren_br(void)
{
- ren_fmtfill(cfmt, 0);
- fmt_br(cfmt);
+ ren_fmtpopall(cfmt);
+ while (fmt_br(cfmt))
+ ren_fmtpop(cfmt);
return ren_passline(cfmt);
}
@@ -643,7 +641,8 @@
break;
case 'p':
if (RENWB(wb))
- ren_fillreq = 1;
+ while (fmt_fillreq(cfmt))
+ ren_fmtpop(cfmt);
break;
case 'r':
wb_vmov(wb, -SC_EM);
@@ -947,7 +946,7 @@
break;
if (bp_final == 0) {
bp_final = 1;
- ren_fmtfill(cfmt, 0);
+ ren_fmtpopall(cfmt);
if (trap_em >= 0)
trap_exec(trap_em);
} else {
@@ -960,24 +959,21 @@
/* add wb (the current word) to cfmt */
if (c == ' ' || c == '\n') {
if (!wb_part(wb)) { /* not after a \c */
- fmt_word(cfmt, wb);
+ while (fmt_word(cfmt, wb))
+ ren_fmtpop(cfmt);
if (c == '\n')
- fmt_newline(cfmt);
- else
+ while (fmt_newline(cfmt))
+ ren_fmtpop(cfmt);
+ if (c == ' ')
fmt_space(cfmt);
wb_reset(wb);
if (!(n_j & AD_P))
- ren_fmtfill(cfmt, 0);
+ ren_fmtpopall(cfmt);
}
}
/* flush the line if necessary */
- if (c == ' ' || c == '\n' || c < 0) {
- if (ren_fillreq && !wb_part(wb))
- ren_fmtfill(cfmt, 1);
- while (fmt_morelines(cfmt))
- ren_passline(cfmt);
- ren_fillreq = 0;
- }
+ if (c == ' ' || c == '\n' || c < 0)
+ ren_fmtpop(cfmt);
if (c == '\n' || ren_nl) /* end or start of input line */
n_lb = f_hpos();
if (c == '\n' && n_it && --n_itn == 0)
--- a/roff.h
+++ b/roff.h
@@ -308,11 +308,12 @@
struct fmt *fmt_alloc(void);
void fmt_free(struct fmt *fmt);
int fmt_wid(struct fmt *fmt);
-void fmt_word(struct fmt *fmt, struct wb *wb);
-void fmt_newline(struct fmt *fmt);
void fmt_space(struct fmt *fmt);
-void fmt_br(struct fmt *fmt);
-int fmt_fill(struct fmt *fmt, int nreq, int all);
+int fmt_word(struct fmt *fmt, struct wb *wb);
+int fmt_newline(struct fmt *fmt);
+int fmt_fillreq(struct fmt *f);
+int fmt_br(struct fmt *fmt);
+int fmt_fill(struct fmt *fmt);
int fmt_morelines(struct fmt *fmt);
int fmt_morewords(struct fmt *fmt);
int fmt_nextline(struct fmt *fmt, struct sbuf *sbuf, int *w,