ref: 3e4d65567e5b609fa8532915fcde566c6a40b120
parent: 0459f7fcd938752ba827be6bea9de78eb2bd137e
author: Ali Gholami Rudi <ali@rudi.ir>
date: Wed Apr 10 14:35:19 EDT 2013
ren: page and diversion trap support
--- a/reg.c
+++ b/reg.c
@@ -43,7 +43,13 @@
char *num_get(int id)
{
static char numbuf[128];
- sprintf(numbuf, "%d", *nreg(id));
+ switch (id) {
+ case REG('.', 't'):
+ sprintf(numbuf, "%d", trap_next());
+ break;
+ default:
+ sprintf(numbuf, "%d", *nreg(id));
+ }
return numbuf;
}
--- a/ren.c
+++ b/ren.c
@@ -14,6 +14,8 @@
int reg; /* diversion register */
int dl; /* diversion width */
int prev_d; /* previous \(.d value */
+ int tpos; /* diversion trap position */
+ int treg; /* diversion trap register */
};
static struct div divs[NPREV]; /* diversion stack */
static struct div *cdiv; /* current diversion */
@@ -23,6 +25,9 @@
static int ren_backed = -1; /* pushed back character */
+static int bp_next; /* next page number */
+static int bp_force; /* execute the traps until the next page */
+
static int ren_next(void)
{
int c = ren_backed >= 0 ? ren_backed : tr_next();
@@ -49,20 +54,15 @@
return l;
}
-static void ren_ne(int n)
-{
- if (n_nl + n > n_p && !cdiv)
- ren_page(n_pg + 1);
-}
-
void tr_di(char **args)
{
if (args[1]) {
cdiv = cdiv ? cdiv + 1 : divs;
+ memset(cdiv, 0, sizeof(*cdiv));
sbuf_init(&cdiv->sbuf);
cdiv->reg = REG(args[1][0], args[1][1]);
- cdiv->dl = 0;
cdiv->prev_d = n_d;
+ cdiv->treg = -1;
if (args[0][2] == 'a' && str_get(cdiv->reg)) /* .da */
sbuf_append(&cdiv->sbuf, str_get(cdiv->reg));
n_d = 0;
@@ -95,8 +95,7 @@
ren_div--;
}
-/* vertical motion before rendering lines */
-static void down(int n)
+static void ren_sp(int n)
{
char cmd[32];
if (!n && ren_div && !n_u)
@@ -111,12 +110,64 @@
if (n_nl <= n_p)
OUT("v%d\n", n ? n : n_v);
}
- ren_ne(0);
}
+static int trap_reg(int pos);
+static int trap_pos(int pos);
+
+static void push_ne(int dobr)
+{
+ char buf[32];
+ sprintf(buf, "%cne %du\n", dobr ? '.' : '\'', n_p);
+ in_push(buf, NULL);
+}
+
+static void trap_exec(int reg)
+{
+ if (bp_force)
+ push_ne(0);
+ if (str_get(reg))
+ in_push(str_get(reg), NULL);
+}
+
+/* return 1 if executed a trap */
+static int ren_traps(int beg, int end, int dosp)
+{
+ int pos = trap_pos(beg);
+ if (pos >= 0 && pos < n_p && pos <= end) {
+ if (dosp && pos > beg)
+ ren_sp(pos - beg);
+ trap_exec(trap_reg(beg));
+ return 1;
+ }
+ return 0;
+}
+
+/* start a new page if needed */
+static int ren_pagelimit(int ne)
+{
+ if (n_nl + ne >= n_p && !cdiv) {
+ ren_page(bp_next);
+ bp_force = 0;
+ if (trap_pos(-1) == 0)
+ trap_exec(trap_reg(-1));
+ return 1;
+ }
+ return 0;
+}
+
+static void down(int n)
+{
+ if (!ren_traps(n_d, n_d + (n ? n : n_v), 1)) {
+ ren_sp(n);
+ ren_pagelimit(0);
+ }
+}
+
static void out_line(char *out, int w)
{
- down(0);
+ int prev_d = n_d;
+ ren_sp(0);
n_n = w;
if (cdiv) {
if (cdiv->dl < w)
@@ -126,33 +177,31 @@
OUT("H%d\n", n_o + n_i);
output(out);
}
+ if (!ren_traps(prev_d, n_d, 0))
+ ren_pagelimit(0);
}
-static void ren_br(int sp, int force)
+static void ren_br(int force)
{
char out[LNLEN];
int w;
if (!adj_empty(adj, ADJ_MODE)) {
w = adj_fill(adj, force ? ADJ_N : ADJ_MODE, ADJ_LL, out);
- ren_ne(n_v);
out_line(out, w);
- ren_ne(n_v);
}
- if (sp)
- down(sp);
}
void tr_br(char **args)
{
- ren_br(0, 1);
+ if (args[0][0] == '.')
+ ren_br(1);
}
void tr_sp(char **args)
{
- int sp = n_v;
- if (args[1])
- sp = tr_int(args[1], 0, 'v');
- ren_br(sp, 1);
+ if (args[0][0] == '.')
+ ren_br(1);
+ down(args[1] ? tr_int(args[1], 0, 'v') : n_v);
}
void ren_page(int pg)
@@ -160,15 +209,26 @@
n_nl = -1;
n_d = 0;
n_pg = pg;
+ bp_next = n_pg + 1;
OUT("p%d\n", pg);
OUT("V%d\n", 0);
}
+void tr_ne(char **args)
+{
+ int n = args[1] ? tr_int(args[1], 0, 'v') : n_v;
+ ren_br(1);
+ if (!ren_traps(n_d, n_d + n, 1))
+ ren_pagelimit(n);
+}
+
void tr_bp(char **args)
{
if (!cdiv) {
- ren_br(0, 1);
- ren_page(args[1] ? tr_int(args[1], n_pg, 'v') : n_pg + 1);
+ bp_force = 1;
+ if (args[1])
+ bp_next = tr_int(args[1], n_pg, '\0');
+ push_ne(args[0][0] == '.');
}
}
@@ -186,7 +246,8 @@
void tr_in(char **args)
{
- ren_br(0, 1);
+ if (args[0][0] == '.')
+ ren_br(1);
if (args[1])
n_i = tr_int(args[1], n_i, 'm');
}
@@ -216,13 +277,15 @@
void tr_nf(char **args)
{
- ren_br(0, 1);
+ if (args[0][0] == '.')
+ ren_br(1);
n_u = 0;
}
void tr_fi(char **args)
{
- ren_br(0, 1);
+ if (args[0][0] == '.')
+ ren_br(1);
n_u = 1;
}
@@ -269,12 +332,12 @@
char arg[ILNLEN];
struct glyph *g;
int esc = 0;
- ren_br(0, 1);
+ ren_br(1);
while (nextchar(c) > 0) {
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);
+ ren_br(0);
if (c[0] == ' ' || c[0] == '\n')
continue;
esc = 0;
@@ -310,5 +373,114 @@
g = dev_glyph(c, n_f);
adj_put(adj, charwid(g ? g->wid : dev_spacewid(), n_s), arg);
}
- ren_br(0, 1);
+ ren_br(1);
+}
+
+static int tpos[NTRAPS]; /* trap positions */
+static int treg[NTRAPS]; /* trap registers */
+static int ntraps;
+
+static int trap_first(int pos)
+{
+ int best = -1;
+ int i;
+ for (i = 0; i < ntraps; i++)
+ if (treg[i] >= 0 && tpos[i] > pos)
+ if (best < 0 || tpos[i] <= tpos[best])
+ best = i;
+ return best;
+}
+
+static int trap_byreg(int reg)
+{
+ int i;
+ for (i = 0; i < ntraps; i++)
+ if (treg[i] == reg)
+ return i;
+ return -1;
+}
+
+static int trap_bypos(int reg, int pos)
+{
+ int i;
+ for (i = 0; i < ntraps; i++)
+ if (treg[i] >= 0 && tpos[i] == pos)
+ if (reg == -1 || treg[i] == reg)
+ return i;
+ return -1;
+}
+
+static int tpos_parse(char *s)
+{
+ int pos = tr_int(s, 0, 'v');
+ return pos >= 0 ? pos : n_p + pos;
+}
+
+void tr_wh(char **args)
+{
+ int reg, pos, id;
+ if (!args[1])
+ return;
+ pos = tpos_parse(args[1]);
+ id = trap_bypos(-1, pos);
+ if (!args[2]) {
+ if (id >= 0)
+ treg[id] = -1;
+ return;
+ }
+ reg = REG(args[2][0], args[2][1]);
+ if (id < 0)
+ id = trap_byreg(-1);
+ if (id < 0)
+ id = ntraps++;
+ tpos[id] = pos;
+ treg[id] = reg;
+}
+
+void tr_ch(char **args)
+{
+ int reg;
+ int id;
+ if (!args[1])
+ return;
+ reg = REG(args[1][0], args[1][1]);
+ id = trap_byreg(reg);
+ if (id)
+ tpos[id] = args[2] ? tpos_parse(args[2]) : -1;
+}
+
+void tr_dt(char **args)
+{
+ if (!cdiv)
+ return;
+ if (args[2]) {
+ cdiv->tpos = tr_int(args[1], 0, 'v');
+ cdiv->treg = REG(args[2][0], args[2][1]);
+ } else {
+ cdiv->treg = -1;
+ }
+}
+
+static int trap_pos(int pos)
+{
+ int ret = trap_first(pos);
+ if (cdiv)
+ return cdiv->treg && cdiv->tpos > pos ? cdiv->tpos : -1;
+ return ret >= 0 ? tpos[ret] : -1;
+}
+
+static int trap_reg(int pos)
+{
+ int ret = trap_first(pos);
+ if (cdiv)
+ return cdiv->treg && cdiv->tpos > pos ? cdiv->treg : -1;
+ return ret >= 0 ? treg[ret] : -1;
+}
+
+int trap_next(void)
+{
+ int pos = trap_pos(n_d);
+ if (cdiv)
+ return pos >= 0 ? pos : 0x7fffffff;
+ return pos >= 0 && pos < n_p ? pos : n_p - n_d;
}
--- a/tr.c
+++ b/tr.c
@@ -309,10 +309,12 @@
{"as", tr_as, mkargs_ds},
{"bp", tr_bp},
{"br", tr_br},
+ {"ch", tr_ch},
{"da", tr_di},
{"de", tr_de, mkargs_reg1},
{"di", tr_di},
{"ds", tr_ds, mkargs_ds},
+ {"dt", tr_dt},
{"ev", tr_ev},
{"fi", tr_fi},
{"fp", tr_fp},
@@ -320,6 +322,7 @@
{"in", tr_in},
{"ll", tr_ll},
{"na", tr_na},
+ {"ne", tr_ne},
{"nf", tr_nf},
{"nr", tr_nr, mkargs_reg1},
{"pl", tr_pl},
@@ -328,6 +331,7 @@
{"rn", tr_rn},
{"sp", tr_sp},
{"vs", tr_vs},
+ {"wh", tr_wh},
};
int tr_next(void)
@@ -340,6 +344,7 @@
struct cmd *req;
while (tr_nl && (c == '.' || c == '\'')) {
nl = 1;
+ memset(args, 0, sizeof(args));
args[0] = cmd;
cmd[0] = c;
req = NULL;
--- a/xroff.h
+++ b/xroff.h
@@ -14,6 +14,7 @@
#define NARGS 9 /* number of macro arguments */
#define RLEN 4 /* register/macro name */
#define NPREV 16 /* environment stack depth */
+#define NTRAPS 1024 /* number of traps per page */
/* escape sequences */
#define ESC_Q "bCDhHlLNoSvwxX" /* quoted escape sequences */
@@ -102,21 +103,27 @@
void render(void); /* read from in.c and print the output */
void output(char *s); /* output the given rendered line */
void ren_page(int pg);
+int trap_next(void);
+
/* troff commands */
void tr_bp(char **args);
void tr_br(char **args);
+void tr_ch(char **args);
void tr_di(char **args);
void tr_divbeg(char **args);
void tr_divend(char **args);
+void tr_dt(char **args);
void tr_ev(char **args);
void tr_fi(char **args);
void tr_fp(char **args);
void tr_ft(char **args);
void tr_in(char **args);
+void tr_ne(char **args);
void tr_nf(char **args);
void tr_ps(char **args);
void tr_sp(char **args);
+void tr_wh(char **args);
void tr_init(void);