shithub: neatroff

Download patch

ref: 07e35081b3f754c61e9a081f320db0e942f72e4a
parent: 03ef6990eb2f07e46b801914363ad43412d4da3d
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat Jun 22 15:25:59 EDT 2013

wb: ligature support

--- a/dev.c
+++ b/dev.c
@@ -144,11 +144,6 @@
 	return font_glyph(fn_font[fn], id);
 }
 
-struct glyph *dev_ligature(char **s, int n)
-{
-	return NULL;
-}
-
 int dev_kernpair(char *c1, char *c2)
 {
 	return 0;
@@ -182,4 +177,15 @@
 {
 	/* the original troff rounds the widths up */
 	return (wid * sz + dev_uwid / 2) / dev_uwid;
+}
+
+/* return 1 if lig is a ligature in the font mounted at f */
+int dev_lig(int f, char *lig)
+{
+	struct font *fn = fn_font[f];
+	int i;
+	for (i = 0; i < fn->nlig; i++)
+		if (!strcmp(lig, fn->lig[i]))
+			return 1;
+	return 0;
 }
--- a/font.c
+++ b/font.c
@@ -93,9 +93,12 @@
 			continue;
 		}
 		if (!strcmp("ligatures", tok)) {
-			while (fscanf(fin, "%s", tok) == 1)
+			while (fscanf(fin, "%s", tok) == 1) {
 				if (!strcmp("0", tok))
 					break;
+				if (fn->nlig < NLIGS)
+					strcpy(fn->lig[fn->nlig++], tok);
+			}
 			skipline(fin);
 			continue;
 		}
--- a/ren.c
+++ b/ren.c
@@ -670,7 +670,8 @@
 	}
 	if (c[0] == c_ni)
 		nextchar(c + 1, next);
-	wb_put(wb, c);
+	if (!n_lg || wb_lig(wb, c))
+		wb_put(wb, c);
 }
 
 /* read the argument of \w and push its width */
--- a/roff.c
+++ b/roff.c
@@ -14,6 +14,7 @@
 {
 	n_o = SC_IN;
 	n_p = SC_IN * 11;
+	n_lg = 1;
 }
 
 static void compile(void)
--- a/roff.h
+++ b/roff.h
@@ -9,6 +9,7 @@
 #define PATHLEN		1024	/* path length */
 #define NFILES		16	/* number of input files */
 #define NFONTS		32	/* number of fonts */
+#define NLIGS		32	/* number of font ligatures */
 #define FNLEN		32	/* font name length */
 #define NGLYPHS		512	/* glyphs in fonts */
 #define GNLEN		32	/* glyph name length */
@@ -92,6 +93,8 @@
 	char c[NGLYPHS][GNLEN];		/* character names in charset */
 	struct glyph *g[NGLYPHS];	/* character glyphs in charset */
 	int n;				/* number of characters in charset */
+	char lig[NLIGS][GNLEN * 4];	/* font ligatures */
+	int nlig;			/* number of font ligatures */
 };
 
 /* output device functions */
@@ -100,6 +103,7 @@
 int dev_mnt(int pos, char *id, char *name);
 int dev_font(char *id);
 int charwid(int wid, int sz);
+int dev_lig(int f, char *c);
 
 /* font-related functions */
 struct font *font_open(char *path);
@@ -139,6 +143,7 @@
 	char *s;
 	int sz;
 	int n;
+	int prev_n;		/* n before the last sbuf_append() */
 };
 
 void sbuf_init(struct sbuf *sbuf);
@@ -149,6 +154,8 @@
 void sbuf_printf(struct sbuf *sbuf, char *s, ...);
 void sbuf_putnl(struct sbuf *sbuf);
 int sbuf_empty(struct sbuf *sbuf);
+char *sbuf_last(struct sbuf *sbuf);
+void sbuf_pop(struct sbuf *sbuf);
 
 /* word buffer */
 struct wb {
@@ -159,6 +166,7 @@
 	int els_neg, els_pos;	/* extra line spacing */
 	int h, v;		/* buffer vertical and horizontal positions */
 	int ct, sb, st;		/* \w registers */
+	int prev_h;		/* previous value of h */
 };
 
 void wb_init(struct wb *wb);
@@ -182,6 +190,7 @@
 int wb_wid(struct wb *wb);
 int wb_empty(struct wb *wb);
 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb);
+int wb_lig(struct wb *wb, char *c);
 
 /* hyphenation flags */
 #define HY_MASK		0x0f	/* enable hyphenation */
@@ -302,6 +311,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_lg		(*nreg(REG(0, 'g')))	/* .lg mode */
 #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 */
--- a/sbuf.c
+++ b/sbuf.c
@@ -35,6 +35,7 @@
 	if (sbuf->n + len + 1 >= sbuf->sz)
 		sbuf_extend(sbuf, sbuf->n + len + 1);
 	memcpy(sbuf->s + sbuf->n, s, len);
+	sbuf->prev_n = sbuf->n;
 	sbuf->n += len;
 }
 
@@ -63,6 +64,17 @@
 {
 	sbuf->s[sbuf->n] = '\0';
 	return sbuf->s;
+}
+
+char *sbuf_last(struct sbuf *sbuf)
+{
+	return sbuf->prev_n < sbuf->n ? sbuf_buf(sbuf) + sbuf->prev_n : NULL;
+}
+
+void sbuf_pop(struct sbuf *sbuf)
+{
+	if (sbuf->prev_n < sbuf->n)
+		sbuf->n = sbuf->prev_n;
 }
 
 void sbuf_done(struct sbuf *sbuf)
--- a/tr.c
+++ b/tr.c
@@ -411,6 +411,12 @@
 	n_hy = args[1] ? atoi(args[1]) : 1;
 }
 
+static void tr_lg(char **args)
+{
+	if (args[1])
+		n_lg = atoi(args[1]);
+}
+
 static char *arg_regname(char *s, int len)
 {
 	char *e = s + 2;
@@ -612,6 +618,7 @@
 	{"if", tr_if, mkargs_null},
 	{"ig", tr_ig},
 	{"in", tr_in},
+	{"lg", tr_lg},
 	{"ll", tr_ll},
 	{"ls", tr_ls},
 	{"lt", tr_lt},
--- a/wb.c
+++ b/wb.c
@@ -103,6 +103,25 @@
 	}
 }
 
+/* return zero if c formed a ligature with its previous character */
+int wb_lig(struct wb *wb, char *c)
+{
+	char *p = sbuf_last(&wb->sbuf);
+	char lig[GNLEN];
+	if (!p || strlen(p) + strlen(c) + 4 > GNLEN)
+		return 1;
+	if (p[0] == c_ec && p[1] == '(')
+		p += 2;
+	sprintf(lig, "%s%s", p, c);
+	if (dev_lig(R_F(wb), lig)) {
+		wb->h = wb->prev_h;
+		sbuf_pop(&wb->sbuf);
+		wb_put(wb, lig);
+		return 0;
+	}
+	return 1;
+}
+
 int wb_part(struct wb *wb)
 {
 	return wb->part;