ref: e69b19f1a9b2abb086d2c3e0483a77268689c638
parent: 845970d2c992db3356cc2eae0b4e678b44a577af
author: Ali Gholami Rudi <ali@rudi.ir>
date: Wed May 1 15:01:23 EDT 2013
wb: add wb struct as a word buffer Now words are collected in wb structs and then added to the adjustment buffer. ren_char() now requires a wb struct and can be called recursively.
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
all: xroff
%.o: %.c xroff.h
$(CC) -c $(CFLAGS) $<
-xroff: xroff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o line.o
+xroff: xroff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o line.o wb.o
$(CC) -o $@ $^ $(LDFLAGS)
clean:
rm -f *.o xroff
--- a/adj.c
+++ b/adj.c
@@ -1,4 +1,3 @@
-#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -7,8 +6,7 @@
#define ADJ_LLEN(a) MAX(0, (a)->ll - ((a)->lt >= 0 ? (a)->lt : (a)->li))
struct word {
- int beg; /* word beginning offset */
- int end; /* word ending offset */
+ struct sbuf s;
int wid; /* word width */
int gap; /* the space before this word */
int els_neg; /* pre-extra line space */
@@ -16,12 +14,9 @@
};
struct adj {
- char buf[LNLEN]; /* line buffer */
- int len;
struct word words[NWORDS]; /* words in buf */
int nwords;
int wid; /* total width of buf */
- struct word *word; /* current word */
int swid; /* current space width */
int gap; /* space before the next word */
int nls; /* newlines before the next word */
@@ -67,7 +62,7 @@
return a->nls;
if (adj_fullnf(a))
return 1;
- return !a->word && a->wid > ADJ_LLEN(a);
+ return a->wid > ADJ_LLEN(a);
}
/* is the adjustment buffer empty? */
@@ -83,10 +78,9 @@
}
/* move n words from the adjustment buffer to s */
-static int adj_move(struct adj *a, int n, char *s, int *els_neg, int *els_pos)
+static int adj_move(struct adj *a, int n, struct sbuf *s, int *els_neg, int *els_pos)
{
struct word *cur;
- int lendiff;
int w = 0;
int i;
*els_neg = 0;
@@ -93,9 +87,9 @@
*els_pos = 0;
for (i = 0; i < n; i++) {
cur = &a->words[i];
- s += sprintf(s, "\\h'%du'", cur->gap);
- memcpy(s, a->buf + cur->beg, cur->end - cur->beg);
- s += cur->end - cur->beg;
+ sbuf_printf(s, "\\h'%du'", cur->gap);
+ sbuf_append(s, sbuf_buf(&cur->s));
+ sbuf_done(&cur->s);
w += cur->wid + cur->gap;
if (cur->els_neg < *els_neg)
*els_neg = cur->els_neg;
@@ -102,19 +96,11 @@
if (cur->els_pos > *els_pos)
*els_pos = cur->els_pos;
}
- *s = '\0';
if (!n)
return 0;
- lendiff = n < a->nwords ? a->words[n].beg : a->len;
- memmove(a->buf, a->buf + lendiff, a->len - lendiff + 1);
- a->len -= lendiff;
a->nwords -= n;
memmove(a->words, a->words + n, a->nwords * sizeof(a->words[0]));
a->wid -= w;
- for (i = 0; i < a->nwords; i++) {
- a->words[i].beg -= lendiff;
- a->words[i].end -= lendiff;
- }
if (a->nwords) /* apply the new .l and .i */
adj_confupdate(a);
return w;
@@ -121,7 +107,7 @@
}
/* fill and copy a line into s */
-int adj_fill(struct adj *a, int ad_b, int fill, char *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)
{
int adj_div, adj_rem;
@@ -154,66 +140,41 @@
return w;
}
-static void adj_wordbeg(struct adj *adj, int gap)
+void adj_sp(struct adj *adj)
{
- adj->word = &adj->words[adj->nwords++];
- adj->word->beg = adj->len;
- adj->word->wid = 0;
- adj->word->gap = gap;
- adj->wid += gap;
- adj->word->els_neg = 0;
- adj->word->els_pos = 0;
+ adj->gap += adj->swid;
}
-static void adj_wordend(struct adj *adj)
+void adj_nl(struct adj *adj)
{
- if (adj->word)
- adj->word->end = adj->len;
- adj->word = NULL;
+ adj->nls++;
+ adj->gap = 0;
}
-/* insert s into the adjustment buffer */
-void adj_put(struct adj *adj, int wid, char *s, ...)
+static void adj_word(struct adj *adj, struct wb *wb)
{
- va_list ap;
- if (!strcmp(s, " ")) {
- adj_wordend(adj);
- adj->gap += wid;
- adj->swid = wid;
- return;
- }
- if (!strcmp(s, "\n")) {
- adj_wordend(adj);
- adj->nls++;
- adj->gap = 0;
- adj->swid = wid;
- return;
- }
- if (!adj->nwords) /* apply the new .l and .i */
- adj_confupdate(adj);
- if (!adj->word) {
- if (adj->nls && !adj->gap && adj->nwords >= 1)
- adj->gap = adj->swid;
- adj_wordbeg(adj, adj->gap);
- adj->nls = 0;
- adj->gap = 0;
- }
- va_start(ap, s);
- adj->len += vsprintf(adj->buf + adj->len, s, ap);
- va_end(ap);
- adj->word->wid += wid;
- adj->wid += wid;
+ 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);
}
-/* extra line-space requests */
-void adj_els(struct adj *adj, int els)
+/* insert wb into the adjustment buffer */
+void adj_wb(struct adj *adj, struct wb *wb)
{
- if (!adj->word)
- adj_put(adj, 0, "");
- if (els < adj->word->els_neg)
- adj->word->els_neg = els;
- if (els > adj->word->els_pos)
- adj->word->els_pos = els;
+ if (wb_empty(wb) || adj->nwords == NWORDS)
+ return;
+ if (!adj->nwords) /* apply the new .l and .i */
+ adj_confupdate(adj);
+ if (adj->nls && !adj->gap && adj->nwords >= 1)
+ adj->gap = adj->swid;
+ adj_word(adj, wb);
+ adj->nls = 0;
+ adj->gap = 0;
}
struct adj *adj_alloc(void)
--- a/line.c
+++ b/line.c
@@ -1,11 +1,32 @@
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "xroff.h"
-/* horizontal and vertical line characters */
-static char *hs[] = {"_", "\\_", "\\-", "\\(ru", "\\(ul", "\\(rn", NULL};
-static char *vs[] = {"\\(bv", "\\(br", "|", NULL};
+static char *ln_s;
+static int ln_next(void)
+{
+ return *ln_s ? (unsigned char) *ln_s++ : -1;
+}
+
+static void ln_back(int c)
+{
+ ln_s--;
+}
+
+static char *ln_push(char *s)
+{
+ char *old_s = ln_s;
+ ln_s = s;
+ return old_s;
+}
+
+static void ln_pop(char *s)
+{
+ ln_s = s;
+}
+
static int cwid(char *c)
{
struct glyph *g = dev_glyph(c, n_f);
@@ -12,6 +33,10 @@
return charwid(g ? g->wid : SC_DW, n_s);
}
+/* horizontal and vertical line characters */
+static char *hs[] = {"_", "\\_", "\\-", "\\(ru", "\\(ul", "\\(rn", NULL};
+static char *vs[] = {"\\(bv", "\\(br", "|", NULL};
+
static int lchar(char *c, char **cs)
{
while (*cs)
@@ -20,18 +45,8 @@
return 0;
}
-static void vmov(struct adj *adj, int w)
+void ren_hline(struct wb *wb, char *arg)
{
- adj_put(adj, w, "\\v'%du'", w);
-}
-
-static void hmov(struct adj *adj, int w)
-{
- adj_put(adj, w, "\\h'%du'", w);
-}
-
-void ren_hline(struct adj *adj, char *arg)
-{
char *lc = "\\(ru";
int w, l, n, i, rem;
l = eval_up(&arg, 'm');
@@ -44,7 +59,7 @@
w = cwid(lc);
/* negative length; moving backwards */
if (l < 0) {
- hmov(adj, l);
+ wb_hmov(wb, l);
l = -l;
}
n = l / w;
@@ -53,25 +68,25 @@
if (l < w) {
n = 1;
rem = 0;
- hmov(adj, -(w - l) / 2);
+ wb_hmov(wb, -(w - l) / 2);
}
/* the initial gap */
if (rem) {
if (lchar(lc, hs)) {
- adj_put(adj, w, "%s", lc);
- hmov(adj, rem - w);
+ wb_put(wb, lc);
+ wb_hmov(wb, rem - w);
} else {
- hmov(adj, rem);
+ wb_hmov(wb, rem);
}
}
for (i = 0; i < n; i++)
- adj_put(adj, w, lc);
+ wb_put(wb, lc);
/* moving back */
if (l < w)
- hmov(adj, -(w - l + 1) / 2);
+ wb_hmov(wb, -(w - l + 1) / 2);
}
-void ren_vline(struct adj *adj, char *arg)
+void ren_vline(struct wb *wb, char *arg)
{
char *lc = "\\(br";
int w, l, n, i, rem, hw, neg;
@@ -87,7 +102,7 @@
hw = cwid(lc); /* character width */
/* negative length; moving backwards */
if (l < 0) {
- vmov(adj, l);
+ wb_vmov(wb, l);
l = -l;
}
n = l / w;
@@ -96,98 +111,132 @@
if (l < w) {
n = 1;
rem = 0;
- vmov(adj, -w + l / 2);
+ wb_vmov(wb, -w + l / 2);
}
/* the initial gap */
if (rem) {
if (lchar(lc, vs)) {
- vmov(adj, w);
- adj_put(adj, hw, "%s", lc);
- hmov(adj, -hw);
- vmov(adj, rem - w);
+ wb_vmov(wb, w);
+ wb_put(wb, lc);
+ wb_hmov(wb, -hw);
+ wb_vmov(wb, rem - w);
} else {
- vmov(adj, rem);
+ wb_vmov(wb, rem);
}
}
for (i = 0; i < n; i++) {
- vmov(adj, w);
- adj_put(adj, hw, lc);
- hmov(adj, -hw);
+ wb_vmov(wb, w);
+ wb_put(wb, lc);
+ wb_hmov(wb, -hw);
}
/* moving back */
if (l < w)
- vmov(adj, l / 2);
+ wb_vmov(wb, l / 2);
if (neg)
- vmov(adj, -l);
- hmov(adj, hw);
+ wb_vmov(wb, -l);
+ wb_hmov(wb, hw);
}
-static char *cutchar(char *d, char *s)
+void ren_bracket(struct wb *wb, char *arg)
{
- s = utf8get(d, s);
- if (d[0] == '\\') {
- s = utf8get(d + 1, s);
- if (d[1] == '(') {
- s = utf8get(d + 2, s);
- s = utf8get(d + strlen(d), s);
- }
+ struct wb wb2;
+ int n = 0, w = 0;
+ int c, center;
+ char *ln_prev = ln_push(arg);
+ wb_init(&wb2);
+ c = ln_next();
+ while (c >= 0) {
+ ln_back(c);
+ ren_char(&wb2, ln_next, ln_back);
+ if (wb_wid(&wb2) > w)
+ w = wb_wid(&wb2);
+ wb_hmov(&wb2, -wb_wid(&wb2));
+ wb_vmov(&wb2, SC_HT);
+ n++;
+ c = ln_next();
}
- return s;
+ ln_pop(ln_prev);
+ center = -(n * SC_HT + SC_EM) / 2;
+ wb_vmov(wb, center + SC_HT);
+ wb_cat(wb, &wb2);
+ wb_done(&wb2);
+ wb_vmov(wb, center);
+ wb_hmov(wb, w);
}
-static int maxwid(char *s)
+void ren_over(struct wb *wb, char *arg)
{
- char c[GNLEN * 4];
- int w = 0;
- while (*s) {
- s = cutchar(c, s);
- if (cwid(c) > w)
- w = cwid(c);
+ struct wb wb2, wb3;
+ int w = 0, wc;
+ int c;
+ char *ln_prev = ln_push(arg);
+ wb_init(&wb2);
+ wb_init(&wb3);
+ c = ln_next();
+ while (c >= 0) {
+ ln_back(c);
+ ren_char(&wb3, ln_next, ln_back);
+ wc = wb_wid(&wb3);
+ if (wc > w)
+ w = wc;
+ wb_hmov(&wb2, -wc / 2);
+ wb_cat(&wb2, &wb3);
+ wb_hmov(&wb2, -wc / 2);
+ c = ln_next();
}
- return w;
+ ln_pop(ln_prev);
+ wb_hmov(wb, w / 2);
+ wb_cat(wb, &wb2);
+ wb_hmov(wb, w / 2);
+ wb_done(&wb3);
+ wb_done(&wb2);
}
-static int nchars(char *s)
+static int tok_num(char **s, int scale)
{
- char c[GNLEN * 4];
- int n = 0;
- while (*s) {
- s = cutchar(c, s);
- n++;
- }
- return n;
+ char tok[ILNLEN];
+ char *d = tok;
+ while (isspace(**s))
+ (*s)++;
+ while (**s && !isspace(**s))
+ *d++ = *(*s)++;
+ *d = '\0';
+ return eval(tok, scale);
}
-void ren_bracket(struct adj *adj, char *arg)
+void ren_draw(struct wb *wb, char *s)
{
- char c[GNLEN * 4];
- int ht, hc;
- int w = maxwid(arg);
- int n = nchars(arg);
- ht = n * SC_HT;
- hc = -(ht + SC_EM) / 2;
- vmov(adj, hc + SC_HT);
- while (*arg) {
- arg = cutchar(c, arg);
- adj_put(adj, cwid(arg), c);
- hmov(adj, -cwid(c));
- vmov(adj, SC_HT);
+ int h1, h2, v1, v2;
+ int c = *s++;
+ switch (c) {
+ case 'l':
+ h1 = tok_num(&s, 'm');
+ v1 = tok_num(&s, 'v');
+ wb_drawl(wb, h1, v1);
+ break;
+ case 'c':
+ h1 = tok_num(&s, 'm');
+ wb_drawc(wb, h1);
+ break;
+ case 'e':
+ h1 = tok_num(&s, 'm');
+ v1 = tok_num(&s, 'v');
+ wb_drawe(wb, h1, v1);
+ break;
+ case 'a':
+ h1 = tok_num(&s, 'm');
+ v1 = tok_num(&s, 'v');
+ h2 = tok_num(&s, 'm');
+ v2 = tok_num(&s, 'v');
+ wb_drawa(wb, h1, v1, h2, v2);
+ break;
+ default:
+ wb_drawxbeg(wb, c);
+ while (*s) {
+ h1 = tok_num(&s, 'm');
+ v1 = tok_num(&s, 'v');
+ wb_drawxdot(wb, h1, v1);
+ }
+ wb_drawxend(wb);
}
- hmov(adj, w);
- vmov(adj, hc);
-}
-
-void ren_over(struct adj *adj, char *arg)
-{
- char c[GNLEN * 4];
- int a;
- int w = maxwid(arg);
- while (*arg) {
- arg = cutchar(c, arg);
- a = (w - cwid(c) + 1) / 2;
- hmov(adj, a);
- adj_put(adj, cwid(arg), c);
- hmov(adj, -cwid(c) - a);
- }
- hmov(adj, w);
}
--- a/out.c
+++ b/out.c
@@ -110,84 +110,51 @@
return s;
}
-static char *tok_str(char *d, char *s)
+static int tok_num(char **s, int scale)
{
- while (isspace(*s))
- s++;
- while (*s && !isspace(*s))
- *d++ = *s++;
+ char tok[ILNLEN];
+ char *d = tok;
+ while (isspace(**s))
+ (*s)++;
+ while (**s && !isspace(**s))
+ *d++ = *(*s)++;
*d = '\0';
- return s;
+ return eval(tok, scale);
}
-static char *tok_num(int *d, char *s, char **cc, int scale)
+static void out_draw(char *s)
{
- char tok[ILNLEN];
- s = tok_str(tok, s);
- *d = eval(tok, scale);
- if (*cc)
- *cc += sprintf(*cc, " %du", *d);
- else
- outnn(" %d", *d);
- return s;
-}
-
-/* parse \D arguments and copy them into cc; return the width */
-int out_draw(char *s, char *cc)
-{
- int h1, h2, v1, v2;
- int hd = 0, vd = 0;
int c = *s++;
- if (cc)
- *cc++ = c;
- else
- out("D%c", c);
+ out("D%c", c);
switch (c) {
case 'l':
- s = tok_num(&h1, s, &cc, 'm');
- s = tok_num(&v1, s, &cc, 'v');
- if (!cc) /* dpost requires this */
- outnn(" .");
- hd = h1;
- vd = v1;
+ outnn(" %d", tok_num(&s, 'm'));
+ outnn(" %d", tok_num(&s, 'v'));
+ outnn(" ."); /* dpost requires this */
break;
case 'c':
- s = tok_num(&h1, s, &cc, 'm');
- hd = h1;
- vd = 0;
+ outnn(" %d", tok_num(&s, 'm'));
break;
case 'e':
- s = tok_num(&h1, s, &cc, 'm');
- s = tok_num(&v1, s, &cc, 'v');
- hd = h1;
- vd = 0;
+ outnn(" %d", tok_num(&s, 'm'));
+ outnn(" %d", tok_num(&s, 'v'));
break;
case 'a':
- s = tok_num(&h1, s, &cc, 'm');
- s = tok_num(&v1, s, &cc, 'v');
- s = tok_num(&h2, s, &cc, 'm');
- s = tok_num(&v2, s, &cc, 'v');
- hd = h1 + h2;
- vd = v1 + v2;
+ outnn(" %d", tok_num(&s, 'm'));
+ outnn(" %d", tok_num(&s, 'v'));
+ outnn(" %d", tok_num(&s, 'm'));
+ outnn(" %d", tok_num(&s, 'v'));
break;
default:
- s = tok_num(&h1, s, &cc, 'm');
- s = tok_num(&v1, s, &cc, 'v');
- hd = h1;
- vd = v1;
+ outnn(" %d", tok_num(&s, 'm'));
+ outnn(" %d", tok_num(&s, 'v'));
while (*s) {
- s = tok_num(&h2, s, &cc, 'm');
- s = tok_num(&v2, s, &cc, 'v');
- hd += h2;
- vd += v2;
+ outnn(" %d", tok_num(&s, 'm'));
+ outnn(" %d", tok_num(&s, 'v'));
}
break;
}
- if (cc)
- *cc = '\0';
- else
- outnn("\n");
- return hd;
+ outnn("\n");
}
void out_line(char *s)
@@ -207,7 +174,7 @@
} else if (strchr("DfhsvX", c[1])) {
s = escarg(s, arg, c[1]);
if (c[1] == 'D') {
- out_draw(arg, NULL);
+ out_draw(arg);
continue;
}
if (c[1] == 'f') {
--- a/ren.c
+++ b/ren.c
@@ -20,12 +20,10 @@
};
static struct div divs[NPREV]; /* diversion stack */
static struct div *cdiv; /* current diversion */
-static int ren_f = -1; /* last rendered n_f */
-static int ren_s = -1; /* last rendered n_s */
static int ren_div; /* rendering a diversion */
-static int ren_part; /* partial line (\c) */
static int ren_backed = -1; /* pushed back character */
+static struct wb ren_wb; /* the main ren.c word buffer */
static int bp_first = 1; /* prior to the first page */
static int bp_next = 1; /* next page number */
@@ -54,8 +52,6 @@
if (args[0][2] == 'a' && str_get(cdiv->reg)) /* .da */
sbuf_append(&cdiv->sbuf, str_get(cdiv->reg));
sbuf_append(&cdiv->sbuf, DIV_BEG "\n");
- ren_f = -1;
- ren_s = -1;
cdiv->prev_d = n_d;
cdiv->prev_h = n_h;
cdiv->prev_mk = n_mk;
@@ -76,8 +72,6 @@
n_mk = cdiv->prev_mk;
n_ns = cdiv->prev_ns;
cdiv = cdiv > divs ? cdiv - 1 : NULL;
- ren_f = -1;
- ren_s = -1;
}
}
@@ -88,7 +82,7 @@
int f_hpos(void)
{
- return adj_wid(cadj);
+ return adj_wid(cadj) + wb_wid(&ren_wb);
}
void tr_divbeg(char **args)
@@ -223,12 +217,13 @@
/* return 1 if triggered a trap */
static int ren_bradj(struct adj *adj, int fill, int ad)
{
- char buf[LNLEN];
+ struct sbuf sbuf;
int ll, li, lt, els_neg, els_pos;
int w, prev_d;
ren_first();
if (!adj_empty(adj, fill)) {
- w = adj_fill(adj, ad == AD_B, fill, buf,
+ sbuf_init(&sbuf);
+ w = adj_fill(adj, ad == AD_B, fill, &sbuf,
&ll, &li, <, &els_neg, &els_pos);
prev_d = n_d;
if (els_neg)
@@ -235,9 +230,10 @@
ren_sp(-els_neg);
if (!n_ns || w || els_neg || els_pos) {
ren_sp(0);
- ren_line(buf, w, ad, ll, li, lt);
+ ren_line(sbuf_buf(&sbuf), w, ad, ll, li, lt);
n_ns = 0;
}
+ sbuf_done(&sbuf);
if (els_pos)
ren_sp(els_pos);
n_a = els_pos;
@@ -477,75 +473,70 @@
return l;
}
-static void ren_cmd(struct adj *adj, int c, char *arg)
+static void ren_cmd(struct wb *wb, int c, char *arg)
{
- char draw_arg[ILNLEN];
struct glyph *g;
- int n, w;
switch (c) {
case ' ':
- w = charwid(dev_spacewid(), n_s);
- adj_put(adj, w, "\\h'%du'", w);
+ wb_hmov(wb, charwid(dev_spacewid(), n_s));
break;
case 'b':
- ren_bracket(adj, arg);
+ ren_bracket(wb, arg);
break;
+ case 'c':
+ wb_setpart(wb);
+ break;
case 'D':
- w = out_draw(arg, draw_arg);
- adj_put(adj, w, "\\D'%s'", draw_arg);
+ ren_draw(wb, arg);
break;
case 'd':
- adj_put(adj, 0, "\\v'%du'", eval(".5m", 0));
+ wb_vmov(wb, SC_EM / 2);
break;
case 'f':
ren_ft(arg);
break;
case 'h':
- n = eval(arg, 'm');
- adj_put(adj, n, "\\h'%du'", n);
+ wb_hmov(wb, eval(arg, 'm'));
break;
case 'k':
num_set(REG(arg[0], arg[1]), f_hpos() - n_lb);
break;
case 'L':
- ren_vline(adj, arg);
+ ren_vline(wb, arg);
break;
case 'l':
- ren_hline(adj, arg);
+ ren_hline(wb, arg);
break;
case 'o':
- ren_over(adj, arg);
+ ren_over(wb, arg);
break;
case 'r':
- adj_put(adj, 0, "\\v'%du'", eval("-1m", 0));
+ wb_vmov(wb, -SC_EM);
break;
case 's':
ren_ps(arg);
break;
case 'u':
- adj_put(adj, 0, "\\v'%du'", eval("-.5m", 0));
+ wb_vmov(wb, -SC_EM / 2);
break;
case 'v':
- adj_put(adj, 0, "\\v'%du'", eval(arg, 'v'));
+ wb_vmov(wb, eval(arg, 'v'));
break;
case 'X':
- adj_put(adj, 0, "\\X'%s'", arg);
+ wb_etc(wb, arg);
break;
case 'x':
- adj_els(adj, eval(arg, 'v'));
+ wb_els(wb, eval(arg, 'v'));
break;
case '0':
g = dev_glyph("0", n_f);
- w = charwid(g ? g->wid : SC_DW, n_s);
- adj_put(adj, w, "\\h'%du'", w);
+ wb_hmov(wb, charwid(g ? g->wid : SC_DW, n_s));
break;
case '|':
- w = eval("1m/6", 0);
- adj_put(adj, w, "\\h'%du'", w);
+ wb_hmov(wb, SC_EM / 6);
break;
case '^':
- w = eval("1m/12", 0);
- adj_put(adj, w, "\\h'%du'", w);
+ wb_hmov(wb, SC_EM / 12);
break;
case '{':
case '}':
@@ -553,18 +544,16 @@
}
}
-/* read one character and place it inside adj buffer */
-static int ren_char(struct adj *adj, int (*next)(void), void (*back)(int))
+/* read one character and place it inside wb buffer */
+void ren_char(struct wb *wb, int (*next)(void), void (*back)(int))
{
char c[GNLEN * 4];
char arg[ILNLEN];
- struct glyph *g;
- int zerowid = 0;
int w;
nextchar(c, next);
if (c[0] == ' ' || c[0] == '\n') {
- adj_put(adj, charwid(dev_spacewid(), n_s), c);
- return 0;
+ wb_put(wb, c);
+ return;
}
if (c[0] == '\\') {
nextchar(c + 1, next);
@@ -573,40 +562,17 @@
l += nextchar(c + 2 + l, next);
c[2 + l] = '\0';
} else if (c[1] == 'z') {
- zerowid = 1;
- nextchar(c, next);
- if (c[0] == '\\') {
- nextchar(c + 1, next);
- if (c[1] == '(') {
- nextchar(c + 2, next);
- nextchar(c + strlen(c), next);
- }
- }
- } else if (c[1] == 'c') {
- if (adj == cadj)
- ren_part = 1;
- return 0;
- } else if (strchr(" bDdfhkLlorsuvXxz0^|{}&", c[1])) {
+ w = wb_wid(wb);
+ ren_char(wb, next, back);
+ wb_hmov(wb, w - wb_wid(wb));
+ return;
+ } else if (strchr(" bcDdfhkLlorsuvXxz0^|{}&", c[1])) {
escarg_ren(arg, c[1], next, back);
- ren_cmd(adj, c[1], arg);
- return 0;
+ ren_cmd(wb, c[1], arg);
+ return;
}
}
- if (ren_s != n_s) {
- adj_swid(adj, charwid(dev_spacewid(), n_s));
- adj_put(adj, 0, "\\s(%02d", n_s);
- ren_s = n_s;
- }
- if (ren_f != n_f) {
- adj_put(adj, 0, "\\f(%02d", n_f);
- ren_f = n_f;
- }
- g = dev_glyph(c, n_f);
- w = charwid(g ? g->wid : SC_DW, n_s);
- adj_put(adj, w, "%s", c);
- if (zerowid)
- adj_put(adj, -w, "\\h'%du'", -w);
- return g ? g->type : 0;
+ wb_put(wb, c);
}
/* read the argument of \w and push its width */
@@ -613,11 +579,10 @@
int ren_wid(int (*next)(void), void (*back)(int))
{
char delim[GNLEN];
- struct adj *adj = adj_alloc();
int c, n;
- int type = 0;
+ struct wb wb;
+ wb_init(&wb);
schar_read(delim, next);
- adj_ll(adj, n_l);
odiv_beg();
c = next();
while (c >= 0 && c != '\n') {
@@ -624,19 +589,17 @@
back(c);
if (!schar_jump(delim, next, back))
break;
- type |= ren_char(adj, next, back);
+ ren_char(&wb, next, back);
c = next();
}
odiv_end();
- ren_f = -1;
- ren_s = -1;
- n = adj_wid(adj);
- n_ct = type;
- adj_free(adj);
+ n = wb_wid(&wb);
+ wb_wconf(&wb, &n_ct, &n_st, &n_sb);
+ wb_done(&wb);
return n;
}
-static void ren_until(struct adj *adj, char *delim, int (*next)(void), void (*back)(int))
+static void ren_until(struct wb *wb, char *delim, int (*next)(void), void (*back)(int))
{
int c;
c = next();
@@ -644,7 +607,7 @@
back(c);
if (!schar_jump(delim, next, back))
break;
- ren_char(adj, next, back);
+ ren_char(wb, next, back);
c = next();
}
if (c == '\n')
@@ -651,67 +614,71 @@
back(c);
}
-static void adj_cpy(struct adj *dst, struct adj *src, int left)
+static void wb_cpy(struct wb *dst, struct wb *src, int left)
{
- char buf[LNLEN];
- int ll, li, lt, els_neg, els_pos;
- int w;
- adj_put(src, 0, "\n");
- w = adj_fill(src, 0, 0, buf, &ll, &li, <, &els_neg, &els_pos);
- adj_put(dst, left - adj_wid(dst), "\\h'%du'", left - adj_wid(dst));
- adj_put(dst, w, "%s", buf);
- adj_els(dst, els_neg);
- adj_els(dst, els_pos);
+ wb_hmov(dst, left - wb_wid(dst));
+ wb_cat(dst, src);
}
void ren_tl(int (*next)(void), void (*back)(int))
{
- struct adj *adj = adj_alloc();
- struct adj *tmp = adj_alloc();
+ struct adj *adj;
+ struct wb wb, wb2;
char delim[GNLEN];
- adj_ll(tmp, n_lt);
- adj_ll(adj, n_lt);
+ adj = adj_alloc();
+ wb_init(&wb);
+ wb_init(&wb2);
schar_read(delim, next);
/* the left-adjusted string */
- ren_until(adj, delim, next, back);
+ ren_until(&wb2, delim, next, back);
+ wb_cpy(&wb, &wb2, 0);
/* the centered string */
- ren_until(tmp, delim, next, back);
- adj_cpy(adj, tmp, (n_lt - adj_wid(tmp)) / 2);
+ ren_until(&wb2, delim, next, back);
+ wb_cpy(&wb, &wb2, (n_lt - wb_wid(&wb2)) / 2);
/* the right-adjusted string */
- ren_until(tmp, delim, next, back);
- adj_cpy(adj, tmp, n_lt - adj_wid(tmp));
+ ren_until(&wb2, delim, next, back);
+ wb_cpy(&wb, &wb2, n_lt - wb_wid(&wb2));
/* flushing the line */
- adj_put(adj, 0, "\n");
+ adj_ll(adj, n_lt);
+ adj_wb(adj, &wb);
+ adj_nl(adj);
ren_bradj(adj, 0, AD_L);
- adj_free(tmp);
adj_free(adj);
+ wb_done(&wb2);
+ wb_done(&wb);
}
/* read characters from in.c and pass rendered lines to out.c */
void render(void)
{
+ struct wb *wb = &ren_wb;
int c;
n_nl = -1;
tr_first();
ren_first(); /* transition to the first page */
c = ren_next();
+ wb_init(wb);
while (c >= 0) {
- if (!ren_part && (c == ' ' || c == '\n')) {
- ren_back(c);
- ren_char(cadj, ren_next, ren_back);
+ if (c == ' ' || c == '\n') {
+ adj_swid(cadj, charwid(dev_spacewid(), n_s));
+ adj_wb(cadj, wb);
+ if (!wb_part(wb)) {
+ if (c == '\n')
+ adj_nl(cadj);
+ else
+ adj_sp(cadj);
+ }
}
while (adj_full(cadj, !n_ce && n_u))
ren_br(0);
if (c == '\n') /* end of input line */
n_lb = adj_wid(cadj);
- if (c == '\n' && !ren_part)
+ if (c == '\n' && !wb_part(wb))
n_ce = MAX(0, n_ce - 1);
- if (!ren_part && (c != ' ' && c != '\n')) {
+ if (c != ' ') {
ren_back(c);
- ren_char(cadj, ren_next, ren_back);
+ ren_char(wb, ren_next, ren_back);
}
- if (ren_part && c == '\n')
- ren_part = 0;
c = ren_next();
}
ren_br(1);
--- a/sbuf.c
+++ b/sbuf.c
@@ -1,3 +1,5 @@
+#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xroff.h"
@@ -33,6 +35,16 @@
sbuf_extend(sbuf, sbuf->n + len + 1);
memcpy(sbuf->s + sbuf->n, s, len);
sbuf->n += len;
+}
+
+void sbuf_printf(struct sbuf *sbuf, char *s, ...)
+{
+ char buf[ILNLEN];
+ va_list ap;
+ va_start(ap, s);
+ vsprintf(buf, s, ap);
+ va_end(ap);
+ sbuf_append(sbuf, buf);
}
void sbuf_putnl(struct sbuf *sbuf)
--- /dev/null
+++ b/wb.c
@@ -1,0 +1,201 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "xroff.h"
+
+void wb_init(struct wb *wb)
+{
+ memset(wb, 0, sizeof(*wb));
+ sbuf_init(&wb->sbuf);
+ wb->f = -1;
+ wb->s = -1;
+}
+
+void wb_done(struct wb *wb)
+{
+ sbuf_done(&wb->sbuf);
+}
+
+/* update wb->st and wb->sb */
+static void wb_stsb(struct wb *wb)
+{
+ wb->st = MIN(wb->st, wb->v - SC_HT);
+ wb->sb = MAX(wb->sb, wb->v);
+}
+
+/* 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, "\\f(%02d", n_f);
+ wb->f = n_f;
+ }
+ if (wb->s != n_s) {
+ sbuf_printf(&wb->sbuf, "\\s(%02d", n_s);
+ wb->s = n_s;
+ }
+ wb_stsb(wb);
+}
+
+void wb_hmov(struct wb *wb, int n)
+{
+ wb->h += n;
+ sbuf_printf(&wb->sbuf, "\\h'%du'", n);
+}
+
+void wb_vmov(struct wb *wb, int n)
+{
+ wb->v += n;
+ sbuf_printf(&wb->sbuf, "\\v'%du'", n);
+}
+
+void wb_els(struct wb *wb, int els)
+{
+ if (els > wb->els_pos)
+ wb->els_pos = els;
+ if (els < wb->els_neg)
+ wb->els_neg = els;
+}
+
+void wb_etc(struct wb *wb, char *x)
+{
+ wb_font(wb);
+ sbuf_printf(&wb->sbuf, "\\X%s", x);
+}
+
+void wb_put(struct wb *wb, char *c)
+{
+ struct glyph *g;
+ if (c[0] == '\n') {
+ wb->part = 0;
+ return;
+ }
+ if (c[0] == ' ') {
+ wb_hmov(wb, charwid(dev_spacewid(), n_s));
+ return;
+ }
+ g = dev_glyph(c, n_f);
+ wb_font(wb);
+ sbuf_append(&wb->sbuf, c);
+ wb->h += charwid(g ? g->wid : SC_DW, n_s);
+ wb->ct |= g ? g->type : 0;
+ wb_stsb(wb);
+}
+
+int wb_part(struct wb *wb)
+{
+ return wb->part;
+}
+
+void wb_setpart(struct wb *wb)
+{
+ wb->part = 1;
+}
+
+void wb_drawl(struct wb *wb, int h, int v)
+{
+ wb_font(wb);
+ sbuf_printf(&wb->sbuf, "\\D'l %du %du'", h, v);
+ wb->h += h;
+ wb->v += v;
+ wb_stsb(wb);
+}
+
+void wb_drawc(struct wb *wb, int r)
+{
+ wb_font(wb);
+ sbuf_printf(&wb->sbuf, "\\D'c %du'", r);
+ wb->h += r;
+}
+
+void wb_drawe(struct wb *wb, int h, int v)
+{
+ wb_font(wb);
+ sbuf_printf(&wb->sbuf, "\\D'e %du %du'", h, v);
+ wb->h += h;
+}
+
+void wb_drawa(struct wb *wb, int h1, int v1, int h2, int v2)
+{
+ wb_font(wb);
+ sbuf_printf(&wb->sbuf, "\\D'a %du %du %du %du'", h1, v1, h2, v2);
+ wb->h += h1 + h2;
+ wb->v += v1 + v2;
+ wb_stsb(wb);
+}
+
+void wb_drawxbeg(struct wb *wb, int c)
+{
+ wb_font(wb);
+ sbuf_printf(&wb->sbuf, "\\D'%c", c);
+}
+
+void wb_drawxdot(struct wb *wb, int h, int v)
+{
+ sbuf_printf(&wb->sbuf, " %du %du", h, v);
+ wb->h += h;
+ wb->v += v;
+ wb_stsb(wb);
+}
+
+void wb_drawxend(struct wb *wb)
+{
+ sbuf_printf(&wb->sbuf, "'");
+}
+
+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;
+}
+
+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;
+ wb_reset(src);
+}
+
+int wb_wid(struct wb *wb)
+{
+ return wb->h;
+}
+
+int wb_empty(struct wb *wb)
+{
+ 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;
+}
--- a/xroff.h
+++ b/xroff.h
@@ -14,7 +14,7 @@
#define GNLEN 32 /* glyph name length */
#define ILNLEN 256 /* line limit of input files */
#define LNLEN 4000 /* line buffer length (ren.c/out.c) */
-#define NWORDS 1000 /* number of words in line buffer */
+#define NWORDS 256 /* number of words in line buffer */
#define NARGS 9 /* number of macro arguments */
#define RLEN 4 /* register/macro name */
#define NPREV 16 /* environment stack depth */
@@ -25,7 +25,8 @@
#define ESC_Q "bCDhHlLNoSvwxX" /* quoted escape sequences */
#define ESC_P "*fgkns" /* 1 or 2-char escape sequences */
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define LEN(a) (sizeof(a) / sizeof((a)[0]))
/* number registers */
@@ -121,17 +122,88 @@
#define cp_back in_back /* cp.c is stateless */
void tr_first(void); /* read until the first non-command line */
+/* variable length string buffer */
+struct sbuf {
+ char *s;
+ int sz;
+ int n;
+};
+
+void sbuf_init(struct sbuf *sbuf);
+void sbuf_done(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);
+void sbuf_printf(struct sbuf *sbuf, char *s, ...);
+void sbuf_putnl(struct sbuf *sbuf);
+int sbuf_empty(struct sbuf *sbuf);
+
+/* word buffer */
+struct wb {
+ struct sbuf sbuf;
+ int f, s; /* the last output font and size */
+ int part; /* partial input (\c) */
+ int els_neg, els_pos; /* extra line spacing */
+ int h, v; /* current 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);
+void wb_etc(struct wb *wb, char *x);
+void wb_put(struct wb *wb, char *c);
+int wb_part(struct wb *wb);
+void wb_setpart(struct wb *wb);
+void wb_drawl(struct wb *wb, int h, int v);
+void wb_drawc(struct wb *wb, int r);
+void wb_drawe(struct wb *wb, int h, int v);
+void wb_drawa(struct wb *wb, int h1, int v1, int h2, int v2);
+void wb_drawxbeg(struct wb *wb, int c);
+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_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 */
+#define AD_L 0
+#define AD_B 1
+#define AD_C 3
+#define AD_R 5
+
+struct adj *adj_alloc(void);
+void adj_free(struct adj *adj);
+int adj_fill(struct adj *adj, int ad_b, int fill, struct sbuf *dst,
+ int *ll, int *in, int *ti, int *els_neg, int *els_pos);
+int adj_full(struct adj *adj, int fill);
+int adj_empty(struct adj *adj, int fill);
+int adj_wid(struct adj *adj);
+void adj_swid(struct adj *adj, int swid);
+void adj_ll(struct adj *adj, int ll);
+void adj_in(struct adj *adj, int in);
+void adj_ti(struct adj *adj, int ti);
+void adj_wb(struct adj *adj, struct wb *wb);
+void adj_nl(struct adj *adj);
+void adj_sp(struct adj *adj);
+
/* rendering */
void render(void); /* read from in.c and print the output */
+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 */
-int out_draw(char *s, char *cc);
void out(char *s, ...); /* output troff cmd */
-void ren_hline(struct adj *adj, char *arg); /* horizontal line */
-void ren_vline(struct adj *adj, char *arg); /* vertical line */
-void ren_bracket(struct adj *adj, char *arg); /* \b */
-void ren_over(struct adj *adj, char *arg); /* \o */
+void ren_hline(struct wb *wb, char *arg); /* horizontal line */
+void ren_vline(struct wb *wb, char *arg); /* vertical line */
+void ren_bracket(struct wb *wb, char *arg); /* \b */
+void ren_over(struct wb *wb, char *arg); /* \o */
+void ren_draw(struct wb *wb, char *arg); /* \D */
/* troff commands */
void tr_bp(char **args);
@@ -171,46 +243,10 @@
void schar_read(char *d, int (*next)(void));
int schar_jump(char *d, int (*next)(void), void (*back)(int));
-/* variable length string buffer */
-struct sbuf {
- char *s;
- int sz;
- int n;
-};
-
-void sbuf_init(struct sbuf *sbuf);
-void sbuf_done(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);
-void sbuf_putnl(struct sbuf *sbuf);
-int sbuf_empty(struct sbuf *sbuf);
-
/* diversions */
#define DIV_BEG ".&<"
#define DIV_END ".&>"
-/* adjustment */
-#define AD_L 0
-#define AD_B 1
-#define AD_C 3
-#define AD_R 5
-
-struct adj *adj_alloc(void);
-void adj_free(struct adj *adj);
-int adj_fill(struct adj *adj, int ad_b, int fill, char *dst,
- int *ll, int *in, int *ti, int *els_neg, int *els_pos);
-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 fill);
-int adj_empty(struct adj *adj, int fill);
-int adj_wid(struct adj *adj);
-void adj_ll(struct adj *adj, int ll);
-void adj_in(struct adj *adj, int in);
-void adj_ti(struct adj *adj, int ti);
-void adj_els(struct adj *adj, int els);
-void adj_conf(struct adj *adj, int *ll, int *in, int *ti);
-
/* builtin number registers; n_X for .X register */
#define REG(c1, c2) ((c1) * 256 + (c2))
#define n_a (*nreg(REG('.', 'a')))
@@ -231,6 +267,8 @@
#define n_dl (*nreg(REG('d', 'l')))
#define n_dn (*nreg(REG('d', 'n')))
#define n_nl (*nreg(REG('n', 'l')))
+#define n_sb (*nreg(REG('s', 'b')))
+#define n_st (*nreg(REG('s', 't')))
#define n_pg (*nreg(REG('%', '\0'))) /* % */
#define n_lb (*nreg(REG(0, 'b'))) /* input line beg */
#define n_ce (*nreg(REG(0, 'c'))) /* .ce remaining */