ref: e8ccdf0b751754aae72e4765e556e9a1760443a9
parent: 02e2d40bd555472b4a58290814f1082f56d0a0ca
author: Ali Gholami Rudi <[email protected]>
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);