ref: 2f5ccbee8981330d8e872a6b505c9aae647d6320
parent: f8bbe8ac5392ff8948a3e735b1e3e35422e746e4
author: Ali Gholami Rudi <ali@rudi.ir>
date: Tue Jan 15 17:33:59 EST 2013
basic diversion support Also the line adjustment functions were moved to adj.c.
--- 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
+xroff: xroff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o
$(CC) -o $@ $^ $(LDFLAGS)
clean:
rm -f *.o xroff
--- /dev/null
+++ b/adj.c
@@ -1,0 +1,98 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include "xroff.h"
+
+static void adj_nf(struct adj *a, int n, char *s)
+{
+ struct word *cur;
+ int lendiff;
+ int w = 0;
+ int i;
+ for (i = 0; i < n; i++) {
+ cur = &a->words[i];
+ s += sprintf(s, "\\h'%du'", cur->blanks);
+ memcpy(s, a->buf + cur->beg, cur->end - cur->beg);
+ s += cur->end - cur->beg;
+ w += cur->wid + cur->blanks;
+ }
+ *s = '\0';
+ lendiff = n < a->nwords ? a->words[n].beg : a->len;
+ memmove(a->buf, a->buf + lendiff, a->len - lendiff);
+ 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;
+ }
+}
+
+void adj_fi(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);
+ return;
+ }
+ for (n = 0; n < a->nwords; n++) {
+ if (n && w + a->words[n].wid + a->words[n].blanks > ll)
+ break;
+ w += a->words[n].wid + a->words[n].blanks;
+ }
+ if (mode == ADJ_B && n > 1 && n < a->nwords) {
+ adj_div = (ll - w) / (n - 1);
+ adj_rem = ll - w - adj_div * (n - 1);
+ a->wid += ll - w;
+ for (i = 0; i < n - 1; i++)
+ a->words[i + 1].blanks += adj_div + (i < adj_rem);
+ }
+ adj_nf(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)
+{
+ adj->word = &adj->words[adj->nwords++];
+ adj->word->beg = adj->len;
+ adj->word->wid = 0;
+ adj->word->blanks = blanks;
+ adj->wid += blanks;
+}
+
+void adj_wordend(struct adj *adj)
+{
+ adj->word->end = adj->len;
+ adj->word = NULL;
+}
+
+void adj_putcmd(struct adj *adj, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ adj->len += vsprintf(adj->buf + adj->len, fmt, 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)
+{
+ return adj->word != NULL;
+}
+
+int adj_inbreak(struct adj *adj, int ll)
+{
+ return !adj_inword(adj) && adj->wid > ll;
+}
--- a/ren.c
+++ b/ren.c
@@ -4,22 +4,18 @@
#include <string.h>
#include "xroff.h"
-#define LL (n_l - n_i) /* effective line length */
+#define LL (n_l - n_i) /* effective line length */
-struct word {
- int beg; /* word beginning offset in buf */
- int end; /* word ending offset in buf */
- int wid; /* word width */
- int blanks; /* blanks before word */
+/* diversion */
+struct div {
+ int f, s, f0, s0; /* backup variables */
};
-static char buf[LNLEN]; /* output buffer */
-static int buflen;
-static struct word words[NWORDS]; /* words in the buffer */
-static int nwords;
-static int wid; /* total width of the buffer */
-static struct word *word; /* current word */
+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 */
+static struct div cur_div;
static int ren_next(void)
{
@@ -47,84 +43,87 @@
return l;
}
-static void adjust_nf(char *s, int n)
+static void ren_ne(int n)
{
- struct word *cur;
- int lendiff;
- int w = 0;
- int i;
- for (i = 0; i < n; i++) {
- cur = &words[i];
- s += sprintf(s, "\\h'%du'", cur->blanks);
- memcpy(s, buf + cur->beg, cur->end - cur->beg);
- s += cur->end - cur->beg;
- w += cur->wid + cur->blanks;
- }
- *s = '\0';
- lendiff = n < nwords ? words[n].beg : buflen;
- memmove(buf, buf + lendiff, buflen - lendiff);
- buflen -= lendiff;
- nwords -= n;
- memmove(words, words + n, nwords * sizeof(words[0]));
- wid -= w;
- for (i = 0; i < nwords; i++) {
- words[i].beg -= lendiff;
- words[i].end -= lendiff;
- }
+ if (n_nl + n > n_p && !ren_div)
+ ren_page(n_pg + 1);
}
-static void adjust_fi(char *s, int adj)
+void tr_di(char **args)
{
- int adj_div, adj_rem;
- int w = 0;
- int i, n;
- for (n = 0; n < nwords; n++) {
- if (n && w + words[n].wid + words[n].blanks > LL)
- break;
- w += words[n].wid + words[n].blanks;
+ if (args[1]) {
+ sbuf_init(&out_div);
+ ren_div = REG(args[1][0], args[1][1]);
+ n_d = 0;
+ } else if (ren_div) {
+ sbuf_putnl(&out_div);
+ str_set(ren_div, sbuf_buf(&out_div));
+ sbuf_done(&out_div);
+ ren_div = 0;
}
- if (adj == ADJ_B && n > 1 && n < nwords) {
- adj_div = (LL - w) / (n - 1);
- adj_rem = LL - w - adj_div * (n - 1);
- wid += LL - w;
- for (i = 0; i < n - 1; i++)
- words[i + 1].blanks += adj_div + (i < adj_rem);
- }
- adjust_nf(s, n);
- if (nwords)
- wid -= words[0].blanks;
- words[0].blanks = 0;
}
-static void ren_ne(int n)
+/* begin outputting diverted line */
+static void div_beg(void)
{
- if (n_nl + n > n_p)
- ren_page(n_pg + 1);
+ cur_div.f = n_f;
+ cur_div.s = n_s;
+ cur_div.f0 = n_f0;
+ cur_div.s0 = n_s0;
}
+/* end outputting diverted line */
+static void div_end(void)
+{
+ n_f = cur_div.f;
+ n_s = cur_div.s;
+ n_f0 = cur_div.f0;
+ n_s0 = cur_div.s0;
+}
+
+/* vertical motion before rendering lines */
static void down(int n)
{
+ char cmd[32];
n_d += n;
- n_nl = n_d;
- if (n_nl <= n_p)
- OUT("v%d\n", n);
+ if (ren_div) {
+ sbuf_putnl(&out_div);
+ sprintf(cmd, ".sp %du\n", n);
+ sbuf_append(&out_div, cmd);
+ } else {
+ n_nl = n_d;
+ if (n_nl <= n_p)
+ OUT("v%d\n", n);
+ }
ren_ne(0);
}
-static void ren_br(int sp)
+static void out_line(char *out)
{
- char out[LNLEN];
- buf[buflen] = '\0';
- if (nwords) {
- if (n_u)
- adjust_fi(out, n_ad);
- else
- adjust_nf(out, nwords);
- ren_ne(n_v);
+ char cmd[32];
+ if (ren_div) {
+ if (!sbuf_empty(&out_div))
+ down(n_v);
+ sprintf(cmd, "\\h'%d'", n_i);
+ sbuf_append(&out_div, DIV_BEG);
+ sbuf_append(&out_div, cmd);
+ sbuf_append(&out_div, out);
+ sbuf_append(&out_div, DIV_END);
+ } else {
down(n_v);
OUT("H%d\n", n_o + n_i);
output(out);
+ }
+}
+
+static void ren_br(int sp)
+{
+ char out[LNLEN];
+ if (adj.nwords) {
+ adj_fi(&adj, n_u ? n_ad : ADJ_N, LL, out);
ren_ne(n_v);
+ out_line(out);
+ ren_ne(n_v);
}
if (sp)
down(sp);
@@ -154,8 +153,10 @@
void tr_bp(char **args)
{
- ren_br(0);
- ren_page(args[1] ? tr_int(args[1], n_pg, 'v') : n_pg + 1);
+ if (!ren_div) {
+ ren_br(0);
+ ren_page(args[1] ? tr_int(args[1], n_pg, 'v') : n_pg + 1);
+ }
}
static void ren_ps(char *s)
@@ -249,7 +250,6 @@
char c[GNLEN * 2];
char arg[ILNLEN];
struct glyph *g;
- int g_wid;
int blanks = 0;
int newline = 0;
int r_s = n_s;
@@ -259,13 +259,11 @@
ren_br(0);
while (nextchar(c) > 0) {
g = NULL;
- if (n_u && !word && wid > LL)
+ if (n_u && adj_inbreak(&adj, LL))
ren_br(0);
if (c[0] == ' ' || c[0] == '\n') {
- if (word) {
- word->end = buflen;
- word = NULL;
- }
+ if (adj_inword(&adj))
+ adj_wordend(&adj);
if (!n_u && c[0] == '\n')
ren_br(0);
if (n_u && newline && c[0] == '\n')
@@ -287,6 +285,15 @@
if (c[0] == '\\') {
esc = 1;
nextchar(c);
+ /* rendered lines inside diversions */
+ if (c[0] == DIV_BEG[1]) {
+ nextchar(c);
+ if (c[0] == DIV_BEG[2])
+ div_beg();
+ if (c[0] == DIV_END[2])
+ div_end();
+ continue;
+ }
if (c[0] == '(') {
int l = nextchar(c);
l += nextchar(c + l);
@@ -300,34 +307,27 @@
continue;
}
}
- if (!word) {
- word = &words[nwords++];
- word->beg = buflen;
- word->wid = 0;
- if (newline && !blanks && nwords > 1)
- word->blanks = charwid(dev_spacewid(), n_s);
- else
- word->blanks = blanks;
- wid += word->blanks;
+ 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) {
- buflen += sprintf(buf + buflen, "\\s(%02d", n_s);
+ adj_putcmd(&adj, "\\s(%02d", n_s);
r_s = n_s;
}
if (r_f != n_f) {
- buflen += sprintf(buf + buflen, "\\f(%02d", n_f);
+ adj_putcmd(&adj, "\\f(%02d", n_f);
r_f = n_f;
}
if (utf8len(c[0]) == strlen(c))
- buflen += sprintf(buf + buflen, "%s%s", esc ? "\\" : "", c);
+ sprintf(arg, "%s%s", esc ? "\\" : "", c);
else
- buflen += sprintf(buf + buflen, "\\(%s", c);
+ sprintf(arg, "\\(%s", c);
g = dev_glyph(c, n_f);
- g_wid = charwid(g ? g->wid : dev_spacewid(), n_s);
- word->wid += g_wid;
- wid += g_wid;
+ adj_putchar(&adj, charwid(g ? g->wid : dev_spacewid(), n_s), arg);
}
if (n_u)
ren_br(0);
--- a/sbuf.c
+++ b/sbuf.c
@@ -35,6 +35,17 @@
sbuf->n += len;
}
+void sbuf_putnl(struct sbuf *sbuf)
+{
+ if (sbuf->n && sbuf->s[sbuf->n - 1] != '\n')
+ sbuf_add(sbuf, '\n');
+}
+
+int sbuf_empty(struct sbuf *sbuf)
+{
+ return !sbuf->n;
+}
+
char *sbuf_buf(struct sbuf *sbuf)
{
sbuf->s[sbuf->n] = '\0';
--- a/tr.c
+++ b/tr.c
@@ -263,6 +263,7 @@
{"bp", tr_bp},
{"br", tr_br},
{"de", tr_de, mkargs_reg1},
+ {"di", tr_di},
{"ds", tr_ds, mkargs_ds},
{"fp", tr_fp},
{"ft", tr_ft},
--- a/xroff.h
+++ b/xroff.h
@@ -14,10 +14,6 @@
#define NARGS 9 /* number of macro arguments */
#define RLEN 4 /* register/macro name */
-/* adjustment modes */
-#define ADJ_L 0
-#define ADJ_B 1
-
/* escape sequences */
#define ESC_Q "bCDhHlLNoSvwxX" /* quoted escape sequences */
#define ESC_P "*fgkns" /* 1 or 2-char escape sequences */
@@ -114,6 +110,7 @@
/* troff commands */
void tr_bp(char **args);
void tr_br(char **args);
+void tr_di(char **args);
void tr_fp(char **args);
void tr_ft(char **args);
void tr_in(char **args);
@@ -138,3 +135,38 @@
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 "\\I<"
+#define DIV_END "\\I>"
+
+/* adjustment */
+#define ADJ_L 0
+#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);