ref: 1874ab5126cf9ae58f12f8b89a8da14b9ccbfbb7
parent: 93ff33b4b44f297924ecb9f2f1de84646db0cd1b
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat Jul 27 14:40:27 EDT 2013
tr: add .tc and .lc
--- a/draw.c
+++ b/draw.c
@@ -3,30 +3,6 @@
#include <string.h>
#include "roff.h"
-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);
@@ -50,18 +26,10 @@
return (c[2] == 'b' && c[3] == 'v') || (c[2] == 'b' && c[3] == 'r');
}
-void ren_hline(struct wb *wb, char *arg)
+void ren_hline(struct wb *wb, int l, char *c)
{
- char lc[GNLEN] = {c_ec, '(', 'r', 'u'};
- int w, l, n, i, rem;
- l = eval_up(&arg, 'm');
- if (!l)
- return;
- if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
- arg += 2;
- if (*arg)
- strcpy(lc, arg);
- w = cwid(lc);
+ int w, n, i, rem;
+ w = cwid(c);
/* negative length; moving backwards */
if (l < 0) {
wb_hmov(wb, l);
@@ -77,8 +45,8 @@
}
/* the initial gap */
if (rem) {
- if (hchar(lc)) {
- wb_put(wb, lc);
+ if (hchar(c)) {
+ wb_put(wb, c);
wb_hmov(wb, rem - w);
} else {
wb_hmov(wb, rem);
@@ -85,26 +53,18 @@
}
}
for (i = 0; i < n; i++)
- wb_put(wb, lc);
+ wb_put(wb, c);
/* moving back */
if (l < w)
wb_hmov(wb, -(w - l + 1) / 2);
}
-void ren_vline(struct wb *wb, char *arg)
+static void ren_vline(struct wb *wb, int l, char *c)
{
- char lc[GNLEN] = {c_ec, '(', 'b', 'r'};
- int w, l, n, i, rem, hw, neg;
- l = eval_up(&arg, 'v');
- if (!l)
- return;
+ int w, n, i, rem, hw, neg;
neg = l < 0;
- if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
- arg += 2;
- if (*arg)
- strcpy(lc, arg);
w = SC_HT; /* character height */
- hw = cwid(lc); /* character width */
+ hw = cwid(c); /* character width */
/* negative length; moving backwards */
if (l < 0) {
wb_vmov(wb, l);
@@ -120,9 +80,9 @@
}
/* the initial gap */
if (rem) {
- if (vchar(lc)) {
+ if (vchar(c)) {
wb_vmov(wb, w);
- wb_put(wb, lc);
+ wb_put(wb, c);
wb_hmov(wb, -hw);
wb_vmov(wb, rem - w);
} else {
@@ -131,7 +91,7 @@
}
for (i = 0; i < n; i++) {
wb_vmov(wb, w);
- wb_put(wb, lc);
+ wb_put(wb, c);
wb_hmov(wb, -hw);
}
/* moving back */
@@ -142,59 +102,24 @@
wb_hmov(wb, hw);
}
-void ren_bracket(struct wb *wb, char *arg)
+void ren_hlcmd(struct wb *wb, char *arg)
{
- 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();
- }
- 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);
+ char lc[GNLEN] = {c_ec, '(', 'r', 'u'};
+ int l = eval_up(&arg, 'm');
+ if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
+ arg += 2;
+ if (l)
+ ren_hline(wb, l, *arg ? arg : lc);
}
-void ren_over(struct wb *wb, char *arg)
+void ren_vlcmd(struct wb *wb, char *arg)
{
- 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();
- }
- ln_pop(ln_prev);
- wb_hmov(wb, w / 2);
- wb_cat(wb, &wb2);
- wb_hmov(wb, w / 2);
- wb_done(&wb3);
- wb_done(&wb2);
+ char lc[GNLEN] = {c_ec, '(', 'b', 'r'};
+ int l = eval_up(&arg, 'v');
+ if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
+ arg += 2;
+ if (l)
+ ren_vline(wb, l, *arg ? arg : lc);
}
static int tok_num(char **s, int scale)
@@ -209,7 +134,7 @@
return eval(tok, scale);
}
-void ren_draw(struct wb *wb, char *s)
+void ren_dcmd(struct wb *wb, char *s)
{
int h1, h2, v1, v2;
int c = *s++;
@@ -244,4 +169,92 @@
}
wb_drawxend(wb);
}
+}
+
+/*
+ * the implementation of \b and \o
+ *
+ * ren_bcmd() and ren_ocmd() call ren_char(), which requires
+ * next() and back() functions, similar to ren_next() and ren_back().
+ * ln_*() here provide such an interface for the given string,
+ * added via ln_push(). ln_*() may be called recursively to
+ * handle \o'\b"ab"c'.
+ */
+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;
+}
+
+void ren_bcmd(struct wb *wb, char *arg)
+{
+ 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();
+ }
+ 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);
+}
+
+void ren_ocmd(struct wb *wb, char *arg)
+{
+ 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();
+ }
+ ln_pop(ln_prev);
+ wb_hmov(wb, w / 2);
+ wb_cat(wb, &wb2);
+ wb_hmov(wb, w / 2);
+ wb_done(&wb3);
+ wb_done(&wb2);
}
--- a/reg.c
+++ b/reg.c
@@ -12,7 +12,9 @@
int eregs[NENVS]; /* environment-specific number registers */
int tabs[NTABS]; /* tab stops */
struct adj *adj; /* per environment line buffer */
- char hc[GNLEN]; /* hyphenation character */
+ char tc[GNLEN]; /* tab character (.tc) */
+ char lc[GNLEN]; /* leader character (.lc) */
+ char hc[GNLEN]; /* hyphenation character (.hc) */
char mc[GNLEN]; /* margin character (.mc) */
};
@@ -192,6 +194,7 @@
n_nM = 1;
n_nS = 1;
strcpy(env->hc, "\\%");
+ strcpy(env->lc, ".");
adj_ll(env->adj, n_l);
adj_in(env->adj, n_i);
for (i = 0; i < NTABS; i++)
@@ -256,6 +259,16 @@
char *env_mc(void)
{
return env->mc;
+}
+
+char *env_tc(void)
+{
+ return env->tc;
+}
+
+char *env_lc(void)
+{
+ return env->lc;
}
/* saving and restoring registers around diverted lines */
--- a/ren.c
+++ b/ren.c
@@ -645,13 +645,13 @@
wb_hmov(wb, spacewid(n_f, n_s));
break;
case 'b':
- ren_bracket(wb, arg);
+ ren_bcmd(wb, arg);
break;
case 'c':
wb_setpart(wb);
break;
case 'D':
- ren_draw(wb, arg);
+ ren_dcmd(wb, arg);
break;
case 'd':
wb_vmov(wb, SC_EM / 2);
@@ -666,16 +666,16 @@
num_set(map(arg), RENWB(wb) ? f_hpos() - n_lb : wb_wid(wb));
break;
case 'L':
- ren_vline(wb, arg);
+ ren_vlcmd(wb, arg);
break;
case 'l':
- ren_hline(wb, arg);
+ ren_hlcmd(wb, arg);
break;
case 'm':
ren_m(arg);
break;
case 'o':
- ren_over(wb, arg);
+ ren_ocmd(wb, arg);
break;
case 'p':
if (RENWB(wb))
@@ -725,7 +725,7 @@
char c[GNLEN * 4];
char arg[ILNLEN];
struct glyph *g;
- char *s;
+ char *s, *tc;
int w, n, l;
nextchar(c, next);
if (c[0] == ' ' || c[0] == '\n') {
@@ -734,7 +734,11 @@
}
if (c[0] == '\t' || c[0] == '') {
n = RENWB(wb) ? f_hpos() : wb_wid(wb);
- wb_hmov(wb, tab_next(n) - n);
+ tc = c[0] == '\t' ? c_tc : c_lc;
+ if (!tc[0])
+ wb_hmov(wb, tab_next(n) - n);
+ else
+ ren_hline(wb, tab_next(n) - n, tc);
return;
}
if (c[0] == c_fa) {
--- a/roff.h
+++ b/roff.h
@@ -43,6 +43,8 @@
#define c_ni 4 /* non-interpreted copy mode escape */
#define c_hc env_hc()/* hyphenation character */
#define c_mc env_mc()/* margin character (.mc) */
+#define c_tc env_tc()
+#define c_lc env_lc()
/* number registers */
int num_get(int id, int inc);
@@ -75,6 +77,8 @@
struct adj *env_adj(void);
char *env_hc(void);
char *env_mc(void);
+char *env_tc(void);
+char *env_lc(void);
int tab_next(int pos);
/* device related variables */
@@ -256,11 +260,12 @@
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 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 */
+void ren_hline(struct wb *wb, int l, char *c); /* horizontal line */
+void ren_hlcmd(struct wb *wb, char *arg); /* \l */
+void ren_vlcmd(struct wb *wb, char *arg); /* \L */
+void ren_bcmd(struct wb *wb, char *arg); /* \b */
+void ren_ocmd(struct wb *wb, char *arg); /* \o */
+void ren_dcmd(struct wb *wb, char *arg); /* \D */
/* out.c */
void out_line(char *s); /* output rendered line */
--- a/tr.c
+++ b/tr.c
@@ -502,6 +502,16 @@
}
}
+static void tr_tc(char **args)
+{
+ strcpy(c_tc, args[1] ? args[1] : "");
+}
+
+static void tr_lc(char **args)
+{
+ strcpy(c_lc, args[1] ? args[1] : "");
+}
+
static void tr_lf(char **args)
{
if (args[1])
@@ -716,6 +726,7 @@
{"in", tr_in},
{"it", tr_it},
{"kn", tr_kn},
+ {"lc", tr_lc},
{"lf", tr_lf},
{"lg", tr_lg},
{"ll", tr_ll},
@@ -749,6 +760,7 @@
{"sv", tr_sv},
{"sy", tr_sy, mkargs_eol},
{"ta", tr_ta},
+ {"tc", tr_tc},
{"ti", tr_ti},
{"tl", tr_tl, mkargs_null},
{"tm", tr_tm, mkargs_eol},
--- a/wb.c
+++ b/wb.c
@@ -275,7 +275,7 @@
wb_put(wb, s);
break;
case 'D':
- ren_draw(wb, s);
+ ren_dcmd(wb, s);
break;
case 'f':
wb->r_f = atoi(s);