ref: f08ca5dc1ee4183db88463bcf4c8e39071d1ef46
parent: 7a5b33eb77e544f5a6c814c40c9a8ae2787b5c96
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri May 10 06:50:16 EDT 2013
wb: changes before hyphenation support This changes neatroff to prepare for the hyphenation support: * adj struct now holds an array of wb structs * out_readc() is extracted to read troff output requests or glyph names * wb_cat() rereads wb struct buffers
--- a/adj.c
+++ b/adj.c
@@ -5,16 +5,9 @@
#define ADJ_LLEN(a) MAX(0, (a)->ll - ((a)->lt >= 0 ? (a)->lt : (a)->li))
-struct word {
- struct sbuf s;
- int wid; /* word width */
- int gap; /* the space before this word */
- int els_neg; /* pre-extra line space */
- int els_pos; /* post-extra line space */
-};
-
struct adj {
- struct word words[NWORDS]; /* words in buf */
+ struct wb wbs[NWORDS]; /* words in buf */
+ int gaps[NWORDS]; /* gaps before words */
int nwords;
int wid; /* total width of buf */
int swid; /* current space width */
@@ -77,20 +70,43 @@
adj->swid = swid;
}
+/* move words inside an adj struct */
+static void adj_movewords(struct adj *a, int dst, int src, int len)
+{
+ memmove(a->wbs + dst, a->wbs + src, len * sizeof(a->wbs[0]));
+ memmove(a->gaps + dst, a->gaps + src, len * sizeof(a->gaps[0]));
+}
+
+static int adj_linewid(struct adj *a, int n)
+{
+ int i, w = 0;
+ for (i = 0; i < n; i++)
+ w += wb_wid(&a->wbs[i]) + a->gaps[i];
+ return w;
+}
+
+static int adj_linefit(struct adj *a, int llen)
+{
+ int i, w = 0;
+ for (i = 0; i < a->nwords && w <= llen; i++)
+ w += wb_wid(&a->wbs[i]) + a->gaps[i];
+ return i - 1;
+}
+
/* move n words from the adjustment buffer to s */
static int adj_move(struct adj *a, int n, struct sbuf *s, int *els_neg, int *els_pos)
{
- struct word *cur;
+ struct wb *cur;
int w = 0;
int i;
*els_neg = 0;
*els_pos = 0;
for (i = 0; i < n; i++) {
- cur = &a->words[i];
- sbuf_printf(s, "%ch'%du'", c_ec, cur->gap);
- sbuf_append(s, sbuf_buf(&cur->s));
- sbuf_done(&cur->s);
- w += cur->wid + cur->gap;
+ cur = &a->wbs[i];
+ sbuf_printf(s, "%ch'%du'", c_ec, a->gaps[i]);
+ sbuf_append(s, sbuf_buf(&cur->sbuf));
+ w += wb_wid(cur) + a->gaps[i];
+ wb_done(cur);
if (cur->els_neg < *els_neg)
*els_neg = cur->els_neg;
if (cur->els_pos > *els_pos)
@@ -99,13 +115,33 @@
if (!n)
return 0;
a->nwords -= n;
- memmove(a->words, a->words + n, a->nwords * sizeof(a->words[0]));
- a->wid -= w;
+ adj_movewords(a, 0, n, a->nwords);
+ a->wid = adj_linewid(a, a->nwords);
if (a->nwords) /* apply the new .l and .i */
adj_confupdate(a);
return w;
}
+/* try to hyphenate the n-th word */
+static void adj_hyph(struct adj *a, int n, int w)
+{
+ struct wb w1, w2;
+ wb_init(&w1);
+ wb_init(&w2);
+ if (wb_hyph(&a->wbs[n], w, &w1, &w2)) {
+ wb_done(&w1);
+ wb_done(&w2);
+ return;
+ }
+ adj_movewords(a, n + 2, n + 1, a->nwords - n);
+ wb_done(&a->wbs[n]);
+ memcpy(&a->wbs[n], &w1, sizeof(w1));
+ memcpy(&a->wbs[n + 1], &w2, sizeof(w2));
+ a->nwords++;
+ a->gaps[n + 1] = 0;
+ a->wid = adj_linewid(a, a->nwords);
+}
+
/* fill and copy a line into s */
int adj_fill(struct adj *a, int ad_b, int fill, struct sbuf *s,
int *ll, int *in, int *ti, int *els_neg, int *els_pos)
@@ -121,22 +157,23 @@
a->nls--;
return adj_move(a, a->nwords, s, els_neg, els_pos);
}
- for (n = 0; n < a->nwords; n++) {
- if (n && w + a->words[n].wid + a->words[n].gap > llen)
- break;
- w += a->words[n].wid + a->words[n].gap;
- }
+ n = adj_linefit(a, llen);
+ if (n < a->nwords)
+ adj_hyph(a, n, llen - adj_linewid(a, n) - a->gaps[n]);
+ n = adj_linefit(a, llen);
+ if (!n && a->nwords)
+ n = 1;
+ w = adj_linewid(a, n);
if (ad_b && n > 1 && n < a->nwords) {
adj_div = (llen - w) / (n - 1);
- adj_rem = llen - w - adj_div * (n - 1);
- a->wid += llen - w;
+ adj_rem = (llen - w) % (n - 1);
for (i = 0; i < n - 1; i++)
- a->words[i + 1].gap += adj_div + (i < adj_rem);
+ a->gaps[i + 1] += adj_div + (i < adj_rem);
}
w = adj_move(a, n, s, els_neg, els_pos);
if (a->nwords)
- a->wid -= a->words[0].gap;
- a->words[0].gap = 0;
+ a->wid -= a->gaps[0];
+ a->gaps[0] = 0;
return w;
}
@@ -161,14 +198,11 @@
static void adj_word(struct adj *adj, struct wb *wb)
{
- struct word *cur = &adj->words[adj->nwords++];
- cur->wid = wb_wid(wb);
- cur->gap = adj->gap;
- adj->wid += cur->wid + adj->gap;
- wb_getels(wb, &cur->els_neg, &cur->els_pos);
- sbuf_init(&cur->s);
- sbuf_append(&cur->s, sbuf_buf(&wb->sbuf));
- wb_reset(wb);
+ int i = adj->nwords++;
+ wb_init(&adj->wbs[i]);
+ adj->gaps[i] = adj->gap;
+ adj->wid += wb_wid(wb) + adj->gap;
+ wb_cat(&adj->wbs[i], wb);
}
/* insert wb into the adjustment buffer */
--- a/out.c
+++ b/out.c
@@ -48,17 +48,17 @@
return 3;
if (c >= 0xc0)
return 2;
- return 1;
+ return c != 0;
}
-char *utf8get(char *d, char *s)
+static void utf8get(char **s, char *d)
{
- int l = utf8len((unsigned char) *s);
+ int l = utf8len((unsigned char) **s);
int i;
for (i = 0; i < l; i++)
- d[i] = s[i];
+ d[i] = (*s)[i];
d[l] = '\0';
- return s + l;
+ *s += l;
}
static int o_s = 10;
@@ -80,8 +80,9 @@
}
}
-static char *escarg(char *s, char *d, int cmd)
+static void escarg(char **sp, char *d, int cmd)
{
+ char *s = *sp;
int q;
if (strchr(ESC_P, cmd)) {
if (cmd == 's' && (*s == '-' || *s == '+'))
@@ -107,7 +108,7 @@
if (cmd == 'z')
*d++ = *s++;
*d = '\0';
- return s;
+ *sp = s;
}
static int tok_num(char **s, int scale)
@@ -157,57 +158,76 @@
outnn("\n");
}
+/*
+ * read a glyph or output troff request
+ *
+ * This functions reads from s either an output troff request
+ * (only the ones emitted by wb.c) or a glyph name and updates
+ * s. The return value is the name of the troff request (the
+ * argument is copied into d) or zero for glyph names (it is
+ * copied into d). Returns -1 when the end of s is reached.
+ */
+int out_readc(char **s, char *d)
+{
+ if (!**s)
+ return -1;
+ utf8get(s, d);
+ if (d[0] == c_ec) {
+ utf8get(s, d + 1);
+ if (d[1] == '(') {
+ utf8get(s, d + 2);
+ utf8get(s, d + strlen(d));
+ } else if (strchr("DfhsvXx", d[1])) {
+ int c = d[1];
+ escarg(s, d, d[1]);
+ return c;
+ }
+ }
+ if (d[0] == c_ni)
+ utf8get(s, d + 1);
+ return 0;
+}
+
void out_line(char *s)
{
struct glyph *g;
- char c[GNLEN * 4];
- char arg[ILNLEN];
- while (*s) {
- s = utf8get(c, s);
- if (c[0] == c_ec) {
- s = utf8get(c + 1, s);
- if (c[1] == '(') {
- s = utf8get(c + 2, s);
- s = utf8get(c + strlen(c), s);
- } else if (c[1] == c_ec) {
- c[1] = '\0';
- } else if (strchr("DfhsvX", c[1])) {
- s = escarg(s, arg, c[1]);
- if (c[1] == 'D') {
- out_draw(arg);
- continue;
- }
- if (c[1] == 'f') {
- out_ft(dev_font(arg));
- continue;
- }
- if (c[1] == 'h') {
- outnn("h%d", eval(arg, 'm'));
- continue;
- }
- if (c[1] == 's') {
- out_ps(eval_re(arg, o_s, '\0'));
- continue;
- }
- if (c[1] == 'v') {
- outnn("v%d", eval(arg, 'v'));
- continue;
- }
- if (c[1] == 'X') {
- out("x X %s\n", arg);
- continue;
- }
- }
+ char c[ILNLEN + GNLEN * 4];
+ int t;
+ while ((t = out_readc(&s, c)) >= 0) {
+ if (c[0] == c_ni) {
+ c[0] = c[1];
+ c[1] = '\0';
}
- if (c[0] == c_ni)
- s = utf8get(c, s);
- if (c[0] == '\t' || c[0] == '')
+ if (!t) {
+ if (c[0] == '\t' || c[0] == '')
+ continue;
+ g = dev_glyph(c, o_f);
+ if (utf8len(c[0]) == strlen(c))
+ outnn("c%s%s", c, c[1] ? "\n" : "");
+ else
+ out("C%s\n", c[0] == c_ec && c[1] == '(' ? c + 2 : c);
+ outnn("h%d", charwid(g ? g->wid : SC_DW, o_s));
continue;
- g = dev_glyph(c, o_f);
- if (utf8len(c[0]) == strlen(c))
- outnn("c%s%s", c, c[1] ? "\n" : "");
- else
- out("C%s\n", c[0] == c_ec && c[1] == '(' ? c + 2 : c);
- outnn("h%d", charwid(g ? g->wid : SC_DW, o_s));
+ }
+ switch (t) {
+ case 'D':
+ out_draw(c);
+ break;
+ case 'f':
+ out_ft(dev_font(c));
+ break;
+ case 'h':
+ outnn("h%d", eval(c, 'm'));
+ break;
+ case 's':
+ out_ps(eval_re(c, o_s, '\0'));
+ break;
+ case 'v':
+ outnn("v%d", eval(c, 'v'));
+ break;
+ case 'X':
+ out("x X %s\n", c);
+ break;
+ }
}
}
--- a/wb.c
+++ b/wb.c
@@ -3,6 +3,9 @@
#include <string.h>
#include "xroff.h"
+#define R_F(wb) ((wb)->r_f >= 0 ? (wb)->r_f : n_f) /* current font */
+#define R_S(wb) ((wb)->r_s >= 0 ? (wb)->r_s : n_s) /* current size */
+
void wb_init(struct wb *wb)
{
memset(wb, 0, sizeof(*wb));
@@ -9,6 +12,8 @@
sbuf_init(&wb->sbuf);
wb->f = -1;
wb->s = -1;
+ wb->r_f = -1;
+ wb->r_s = -1;
}
void wb_done(struct wb *wb)
@@ -26,13 +31,13 @@
/* append font and size to the buffer if needed */
static void wb_font(struct wb *wb)
{
- if (wb->f != n_f) {
- sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, n_f);
- wb->f = n_f;
+ if (wb->f != R_F(wb)) {
+ sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, R_F(wb));
+ wb->f = R_F(wb);
}
- if (wb->s != n_s) {
- sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, n_s);
- wb->s = n_s;
+ if (wb->s != R_S(wb)) {
+ sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, R_S(wb));
+ wb->s = R_S(wb);
}
wb_stsb(wb);
}
@@ -55,6 +60,7 @@
wb->els_pos = els;
if (els < wb->els_neg)
wb->els_neg = els;
+ sbuf_printf(&wb->sbuf, "%cx'%du'", c_ec, els);
}
void wb_etc(struct wb *wb, char *x)
@@ -71,7 +77,7 @@
return;
}
if (c[0] == ' ') {
- wb_hmov(wb, charwid(dev_spacewid(), n_s));
+ wb_hmov(wb, charwid(dev_spacewid(), R_S(wb)));
return;
}
if (c[0] == '\t' || c[0] == '' ||
@@ -79,10 +85,10 @@
sbuf_append(&wb->sbuf, c);
return;
}
- g = dev_glyph(c, n_f);
+ g = dev_glyph(c, R_F(wb));
wb_font(wb);
sbuf_append(&wb->sbuf, c);
- wb->h += charwid(g ? g->wid : SC_DW, n_s);
+ wb->h += charwid(g ? g->wid : SC_DW, R_S(wb));
wb->ct |= g ? g->type : 0;
wb_stsb(wb);
}
@@ -148,38 +154,54 @@
sbuf_printf(&wb->sbuf, "'");
}
-void wb_reset(struct wb *wb)
+static void wb_reset(struct wb *wb)
{
- sbuf_done(&wb->sbuf);
- sbuf_init(&wb->sbuf);
- wb->els_pos = 0;
- wb->els_neg = 0;
- wb->ct = 0;
- wb->sb = 0;
- wb->st = 0;
- wb->h = 0;
- wb->v = 0;
- wb->f = -1;
- wb->s = -1;
+ wb_done(wb);
+ wb_init(wb);
}
+static void wb_putc(struct wb *wb, int t, char *s)
+{
+ switch (t) {
+ case 0:
+ wb_put(wb, s);
+ break;
+ case 'D':
+ ren_draw(wb, s);
+ break;
+ case 'f':
+ wb->r_f = atoi(s);
+ break;
+ case 'h':
+ wb_hmov(wb, atoi(s));
+ break;
+ case 's':
+ wb->r_s = atoi(s);
+ break;
+ case 'v':
+ wb_vmov(wb, atoi(s));
+ break;
+ case 'x':
+ wb_els(wb, atoi(s));
+ break;
+ case 'X':
+ wb_etc(wb, s);
+ break;
+ }
+}
+
void wb_cat(struct wb *wb, struct wb *src)
{
- sbuf_append(&wb->sbuf, sbuf_buf(&src->sbuf));
- if (src->f >= 0)
- wb->f = src->f;
- if (src->s >= 0)
- wb->s = src->s;
- wb_els(wb, src->els_neg);
- wb_els(wb, src->els_pos);
- if (src->part)
- wb->part = src->part;
- wb->ct |= src->ct;
- wb->st = MIN(wb->st, wb->v + src->st);
- wb->sb = MAX(wb->sb, wb->v + src->sb);
- wb->h += src->h;
- wb->v += src->v;
+ char *s = sbuf_buf(&src->sbuf);
+ char d[ILNLEN];
+ int c, part;
+ while ((c = out_readc(&s, d)) >= 0)
+ wb_putc(wb, c, d);
+ part = src->part;
+ wb->r_s = -1;
+ wb->r_f = -1;
wb_reset(src);
+ src->part = part;
}
int wb_wid(struct wb *wb)
@@ -192,15 +214,15 @@
return sbuf_empty(&wb->sbuf);
}
-void wb_getels(struct wb *wb, int *els_neg, int *els_pos)
-{
- *els_neg = wb->els_neg;
- *els_pos = wb->els_pos;
-}
-
void wb_wconf(struct wb *wb, int *ct, int *st, int *sb)
{
*ct = wb->ct;
*st = -wb->st;
*sb = -wb->sb;
+}
+
+/* hyphenate wb into w1 and w2; return zero on success */
+int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2)
+{
+ return 1;
}
--- a/xroff.h
+++ b/xroff.h
@@ -152,15 +152,15 @@
struct wb {
struct sbuf sbuf;
int f, s; /* the last output font and size */
+ int r_f, r_s; /* current font and size; use n_f and n_s if -1 */
int part; /* partial input (\c) */
int els_neg, els_pos; /* extra line spacing */
- int h, v; /* current buffer vertical and horizontal positions */
+ int h, v; /* buffer vertical and horizontal positions */
int ct, sb, st; /* \w registers */
};
void wb_init(struct wb *wb);
void wb_done(struct wb *wb);
-void wb_reset(struct wb *wb);
void wb_hmov(struct wb *wb, int n);
void wb_vmov(struct wb *wb, int n);
void wb_els(struct wb *wb, int els);
@@ -176,9 +176,9 @@
void wb_drawxdot(struct wb *wb, int h, int v);
void wb_drawxend(struct wb *wb);
void wb_cat(struct wb *wb, struct wb *src);
+int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2);
int wb_wid(struct wb *wb);
int wb_empty(struct wb *wb);
-void wb_getels(struct wb *wb, int *els_neg, int *els_pos);
void wb_wconf(struct wb *wb, int *ct, int *st, int *sb);
/* adjustment */
@@ -204,11 +204,12 @@
void adj_nonl(struct adj *adj);
/* rendering */
-void render(void); /* read from in.c and print the output */
+void render(void); /* the main loop */
void ren_char(struct wb *wb, int (*next)(void), void (*back)(int));
int ren_wid(int (*next)(void), void (*back)(int));
void ren_tl(int (*next)(void), void (*back)(int));
-void out_line(char *s); /* output the given rendered line */
+void out_line(char *s); /* output rendered line */
+int out_readc(char **s, char *d); /* read request or glyph */
void out(char *s, ...); /* output troff cmd */
void ren_hline(struct wb *wb, char *arg); /* horizontal line */
void ren_vline(struct wb *wb, char *arg); /* vertical line */
@@ -252,7 +253,6 @@
/* helpers */
void errmsg(char *msg, ...);
int utf8len(int c);
-char *utf8get(char *d, char *s);
void schar_read(char *d, int (*next)(void));
int schar_jump(char *d, int (*next)(void), void (*back)(int));