shithub: neatroff

Download patch

ref: 3c5e855b56948641dc46927cd50870c80412593a
parent: f148a9d90d6581768c5197dc4e777edc0f6baf0d
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat May 11 14:42:32 EDT 2013

wb: hyphenation at dashes and hyphenation marks

--- a/adj.c
+++ b/adj.c
@@ -128,7 +128,7 @@
 	struct wb w1, w2;
 	wb_init(&w1);
 	wb_init(&w2);
-	if (wb_hyph(&a->wbs[n], w, &w1, &w2)) {
+	if (wb_hyph(&a->wbs[n], w, &w1, &w2, n == 0 ? HY_ANY : 0)) {
 		wb_done(&w1);
 		wb_done(&w2);
 		return;
--- a/out.c
+++ b/out.c
@@ -199,7 +199,7 @@
 			c[1] = '\0';
 		}
 		if (!t) {
-			if (c[0] == '\t' || c[0] == '')
+			if (c[0] == '\t' || c[0] == '' || !strcmp(c_hc, c))
 				continue;
 			g = dev_glyph(c, o_f);
 			if (utf8len(c[0]) == strlen(c))
--- a/reg.c
+++ b/reg.c
@@ -11,6 +11,7 @@
 	int eregs[NENVS];	/* environment-specific number registers */
 	int tabs[NTABS];	/* tab stops */
 	struct adj *adj;	/* per environment line buffer */
+	char hc[GNLEN];		/* hyphenation character */
 };
 
 static int nregs[NREGS];	/* global number registers */
@@ -32,6 +33,7 @@
 	REG('.', 'v'),
 	REG(0, 'c'),
 	REG(0, 'f'),
+	REG(0, 'h'),
 	REG(0, 'i'),
 	REG(0, 'l'),
 	REG(0, 'L'),
@@ -168,6 +170,8 @@
 		n_f0 = n_f;
 		n_na = 0;
 		n_lt = SC_IN * 65 / 10;
+		n_hy = 1;
+		strcpy(env->hc, "\\%");
 		adj_ll(env->adj, n_l);
 		adj_in(env->adj, n_i);
 		for (i = 0; i < NTABS; i++)
@@ -209,6 +213,11 @@
 struct adj *env_adj(void)
 {
 	return env->adj;
+}
+
+char *env_hc(void)
+{
+	return env->hc;
 }
 
 /* saving and restoring registers around diverted lines */
--- a/tr.c
+++ b/tr.c
@@ -394,6 +394,21 @@
 	c_ec = -1;
 }
 
+static void tr_hc(char **args)
+{
+	strcpy(c_hc, args[1] ? args[1] : "\\%");
+}
+
+static void tr_nh(char **args)
+{
+	n_hy = 0;
+}
+
+static void tr_hy(char **args)
+{
+	n_hy = args[1] ? atoi(args[1]) : 1;
+}
+
 static char *arg_regname(char *s, int len)
 {
 	char *e = s + 2;
@@ -586,6 +601,8 @@
 	{"fi", tr_fi},
 	{"fp", tr_fp},
 	{"ft", tr_ft},
+	{"hc", tr_hc},
+	{"hy", tr_hy},
 	{"ie", tr_if, mkargs_null},
 	{"if", tr_if, mkargs_null},
 	{"ig", tr_ig},
@@ -597,6 +614,7 @@
 	{"na", tr_na},
 	{"ne", tr_ne},
 	{"nf", tr_nf},
+	{"nh", tr_nh},
 	{"nr", tr_nr, mkargs_reg1},
 	{"ns", tr_ns},
 	{"nx", tr_nx},
--- a/wb.c
+++ b/wb.c
@@ -88,9 +88,11 @@
 	g = dev_glyph(c, R_F(wb));
 	wb_font(wb);
 	sbuf_append(&wb->sbuf, c);
-	wb->h += charwid(g ? g->wid : SC_DW, R_S(wb));
-	wb->ct |= g ? g->type : 0;
-	wb_stsb(wb);
+	if (strcmp(c_hc, c)) {
+		wb->h += charwid(g ? g->wid : SC_DW, R_S(wb));
+		wb->ct |= g ? g->type : 0;
+		wb_stsb(wb);
+	}
 }
 
 int wb_part(struct wb *wb)
@@ -221,8 +223,87 @@
 	*sb = -wb->sb;
 }
 
+/* skip troff requests; return 1 if read c_hc */
+static int skipreqs(char **s, struct wb *w1)
+{
+	char d[ILNLEN];
+	char *r = *s;
+	int c;
+	wb_reset(w1);
+	while ((c = out_readc(s, d)) > 0) {
+		wb_putc(w1, c, d);
+		r = *s;
+	}
+	if (c < 0 || !strcmp(c_hc, d))
+		return 1;
+	*s = r;
+	return 0;
+}
+
+static char *dashpos(char *s, int w, struct wb *w1, int any)
+{
+	char d[ILNLEN];
+	char *r = NULL;
+	int c;
+	skipreqs(&s, w1);
+	while ((c = out_readc(&s, d)) == 0) {
+		wb_putc(w1, c, d);
+		if (wb_wid(w1) > w && (!any || r))
+			break;
+		if (!strcmp("-", d) || (d[0] == c_ec && (!strcmp("(em", d + 1) ||
+							!strcmp("(hy", d + 1))))
+			r = s;
+	}
+	return r;
+}
+
+static char *hyphpos(char *s, int w, struct wb *w1, int any)
+{
+	char hy[GNLEN] = {c_ec, '(', 'h', 'y'};
+	char d[ILNLEN];
+	char *r = NULL;
+	struct glyph *g;
+	int c;
+	skipreqs(&s, w1);
+	while ((c = out_readc(&s, d)) == 0) {
+		wb_putc(w1, c, d);
+		g = dev_glyph(hy, R_F(w1));
+		if (!g || (wb_wid(w1) + charwid(g->wid, R_S(w1)) > w && (!any || r)))
+			break;
+		if (!strcmp(c_hc, d))
+			r = s;
+	}
+	return r;
+}
+
+static void dohyph(char *s, char *pos, int dash, struct wb *w1, struct wb *w2)
+{
+	char d[ILNLEN];
+	char hy[GNLEN] = {c_ec, '(', 'h', 'y'};
+	int c = -1;
+	wb_reset(w1);
+	wb_reset(w2);
+	while (s != pos && (c = out_readc(&s, d)) >= 0)
+		wb_putc(w1, c, d);
+	if (dash)
+		wb_putc(w1, 0, hy);
+	w2->r_s = w1->r_s;
+	w2->r_f = w1->r_f;
+	while ((c = out_readc(&s, d)) >= 0)
+		wb_putc(w2, c, d);
+}
+
 /* hyphenate wb into w1 and w2; return zero on success */
-int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2)
+int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2, int flags)
 {
-	return 1;
+	char *s = sbuf_buf(&wb->sbuf);
+	char *dp, *hp, *p;
+	if (skipreqs(&s, w1))
+		return 1;
+	dp = dashpos(sbuf_buf(&wb->sbuf), w, w1, flags & HY_ANY);
+	hp = hyphpos(sbuf_buf(&wb->sbuf), w, w1, flags & HY_ANY);
+	p = flags & HY_ANY ? MIN(dp, hp) : MAX(dp, hp);
+	if (p)
+		dohyph(sbuf_buf(&wb->sbuf), p, p != dp, w1, w2);
+	return !p;
 }
--- a/xroff.h
+++ b/xroff.h
@@ -37,6 +37,7 @@
 extern int c_cc;	/* basic control character (.) */
 extern int c_c2;	/* no-break control character (') */
 #define c_ni	4	/* non-interpreted copy mode escape */
+#define c_hc	env_hc()/* hyphenation character */
 
 /* number registers */
 int num_get(int id, int inc);
@@ -65,6 +66,7 @@
 void env_init(void);
 void env_free(void);
 struct adj *env_adj(void);
+char *env_hc(void);
 int tab_next(int pos);
 
 /* device related variables */
@@ -176,11 +178,14 @@
 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_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2);
+int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2, int flags);
 int wb_wid(struct wb *wb);
 int wb_empty(struct wb *wb);
 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb);
 
+/* hyphenation flags */
+#define HY_ANY		1	/* break at any possible position */
+
 /* adjustment */
 #define AD_L		0
 #define AD_B		1
@@ -286,6 +291,7 @@
 #define n_lb		(*nreg(REG(0, 'b')))	/* input line beg */
 #define n_ce		(*nreg(REG(0, 'c')))	/* .ce remaining */
 #define n_f0		(*nreg(REG(0, 'f')))	/* last .f */
+#define n_hy		(*nreg(REG(0, 'h')))	/* .hy mode */
 #define n_i0		(*nreg(REG(0, 'i')))	/* last .i */
 #define n_l0		(*nreg(REG(0, 'l')))	/* last .l */
 #define n_L0		(*nreg(REG(0, 'L')))	/* last .L */