ref: c96d5ac9e6e6d97f85052f9cb7ceb998fb13d11d
parent: e09893889703797eb671aa56f59e109da1caa569
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sun Oct 13 14:40:06 EDT 2013
tr: basic .char implementation for glyph definitions This is not compatible with Groff: nested defined characters in .char definitions are not expanded, defined characters are ignored when they are used in .tr character translations, and the expansion does not happen in a separate environment.
--- a/draw.c
+++ b/draw.c
@@ -5,8 +5,13 @@
static int cwid(char *c)
{
- struct glyph *g = dev_glyph(c, n_f);
- return charwid(n_f, n_s, g ? g->wid : SC_DW);
+ struct wb wb;
+ int w;
+ wb_init(&wb);
+ wb_putexpand(&wb, c);
+ w = wb_wid(&wb);
+ wb_done(&wb);
+ return w;
}
static int hchar(char *c)
@@ -46,7 +51,7 @@
/* the initial gap */
if (rem) {
if (hchar(c)) {
- wb_put(wb, c);
+ wb_putexpand(wb, c);
wb_hmov(wb, rem - w);
} else {
wb_hmov(wb, rem);
@@ -53,7 +58,7 @@
}
}
for (i = 0; i < n; i++)
- wb_put(wb, c);
+ wb_putexpand(wb, c);
/* moving back */
if (l < w)
wb_hmov(wb, -(w - l + 1) / 2);
@@ -82,7 +87,7 @@
if (rem) {
if (vchar(c)) {
wb_vmov(wb, w);
- wb_put(wb, c);
+ wb_putexpand(wb, c);
wb_hmov(wb, -hw);
wb_vmov(wb, rem - w);
} else {
@@ -91,7 +96,7 @@
}
for (i = 0; i < n; i++) {
wb_vmov(wb, w);
- wb_put(wb, c);
+ wb_putexpand(wb, c);
wb_hmov(wb, -hw);
}
/* moving back */
--- a/ren.c
+++ b/ren.c
@@ -301,7 +301,7 @@
wb_init(&wb);
if (w + ljust < n_l + n_mcn)
wb_hmov(&wb, n_l + n_mcn - w - ljust);
- wb_put(&wb, c_mc);
+ wb_putexpand(&wb, c_mc);
sbuf_append(sbuf, sbuf_buf(&wb.sbuf));
wb_done(&wb);
}
@@ -733,7 +733,7 @@
if (!n_lg || ren_div || wb_lig(wb, c)) {
if (n_kn && !ren_div)
wb_kern(wb, c);
- wb_put(wb, c);
+ wb_putexpand(wb, c);
}
}
@@ -894,6 +894,31 @@
ren_hline(wb, ins - pos, tc);
wb_cat(wb, &t);
wb_done(&t);
+}
+
+static int ren_expanding; /* expanding the definition of a character */
+
+/* expand the given defined character */
+int ren_expand(struct wb *wb, char *n)
+{
+ char *s = chdef_map(n);
+ int c;
+ if (!s || ren_expanding)
+ return 1;
+ ren_expanding = 1;
+ odiv_beg();
+ sstr_push(s);
+ c = sstr_next();
+ while (c >= 0) {
+ sstr_back(c);
+ if (ren_chardel(wb, sstr_next, sstr_back, NULL, NULL))
+ break;
+ c = sstr_next();
+ }
+ sstr_pop();
+ odiv_end();
+ ren_expanding = 0;
+ return 0;
}
/* read characters from in.c and pass rendered lines to out.c */
--- a/roff.h
+++ b/roff.h
@@ -29,6 +29,7 @@
#define NFIELDS 32 /* number of fields */
#define MAXFRAC 100000 /* maximum value of the fractional part */
#define LIGLEN 4 /* length of ligatures */
+#define NCHDEF 128 /* number of character definitions (.char) */
/* escape sequences */
#define ESC_Q "bCDhHlLNoSvwxX" /* \X'ccc' quoted escape sequences */
@@ -177,6 +178,8 @@
/* character translation (.tr) */
void tr_add(char *c1, char *c2);
char *tr_map(char *c);
+/* character definition (.char) */
+char *chdef_map(char *c);
/* variable length string buffer */
struct sbuf {
@@ -220,6 +223,7 @@
void wb_els(struct wb *wb, int els);
void wb_etc(struct wb *wb, char *x);
void wb_put(struct wb *wb, char *c);
+void wb_putexpand(struct wb *wb, char *c);
int wb_part(struct wb *wb);
void wb_setpart(struct wb *wb);
void wb_drawl(struct wb *wb, int c, int h, int v);
@@ -280,6 +284,7 @@
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 */
+int ren_expand(struct wb *wb, char *c); /* .char expansion */
/* out.c */
void out_line(char *s); /* output rendered line */
--- a/tr.c
+++ b/tr.c
@@ -535,6 +535,60 @@
}
}
+/* character definitions */
+static char chdef_src[NCHDEF][GNLEN];
+static char *chdef_dst[NCHDEF];
+static int chdef_n;
+
+static int chdef_find(char *c)
+{
+ int i;
+ for (i = 0; i < chdef_n; i++)
+ if (!strcmp(chdef_src[i], c))
+ return i;
+ return -1;
+}
+
+/* return the definition of the given character */
+char *chdef_map(char *c)
+{
+ int i = chdef_find(c);
+ return i >= 0 ? chdef_dst[i] : NULL;
+}
+
+static void tr_char(char **args)
+{
+ char c[GNLEN];
+ char *s = args[1];
+ int i;
+ if (!args[2] || charread(&s, c) < 0)
+ return;
+ i = chdef_find(c);
+ if (i < 0 && chdef_n < NCHDEF)
+ i = chdef_n++;
+ if (i >= 0) {
+ strncpy(chdef_src[i], c, sizeof(chdef_src[i]) - 1);
+ chdef_dst[i] = malloc(strlen(args[2]) + 1);
+ strcpy(chdef_dst[i], args[2]);
+ }
+}
+
+static void tr_rchar(char **args)
+{
+ char c[GNLEN];
+ char *s;
+ int i;
+ for (i = 1; i <= NARGS; i++) {
+ s = args[i];
+ if (s && charread(&s, c) >= 0) {
+ if (chdef_find(c) >= 0) {
+ free(chdef_dst[chdef_find(c)]);
+ chdef_dst[chdef_find(c)] = NULL;
+ }
+ }
+ }
+}
+
static char *arg_regname(char *s, int len)
{
char *e = n_cp ? s + 2 : s + len;
@@ -717,6 +771,7 @@
{"cc", tr_cc},
{"ce", tr_ce},
{"ch", tr_ch},
+ {"char", tr_char, mkargs_ds},
{"cl", tr_cl},
{"cp", tr_cp},
{"cs", tr_cs},
@@ -767,6 +822,7 @@
{"pn", tr_pn},
{"po", tr_po},
{"ps", tr_ps},
+ {"rchar", tr_rchar, mkargs_ds},
{"rm", tr_rm},
{"rn", tr_rn},
{"rr", tr_rr},
--- a/wb.c
+++ b/wb.c
@@ -164,6 +164,13 @@
}
}
+/* just like wb_put(), but call chdef_expand() if c is defined */
+void wb_putexpand(struct wb *wb, char *c)
+{
+ if (ren_expand(wb, c))
+ wb_put(wb, c);
+}
+
/* return zero if c formed a ligature with its previous character */
int wb_lig(struct wb *wb, char *c)
{