shithub: neatroff

Download patch

ref: d173cf1cdc72519809a0e3e01165f616044b2eee
parent: d81da34389f192fee51865798fc86ff7e521617a
author: Ali Gholami Rudi <ali@rudi.ir>
date: Tue Jun 11 12:53:36 EDT 2013

fmt: keshideh justification

With ".ad k", neatroff inserts keshideh characters inside words of
filled lines, before adjusting with spaces.

--- a/fmt.c
+++ b/fmt.c
@@ -182,6 +182,8 @@
 	return l;
 }
 
+static void fmt_keshideh(struct fmt *f, int beg, int end, int wid);
+
 /* extract words from beg to end; shrink or stretch spaces if needed */
 static int fmt_extractline(struct fmt *f, int beg, int end, int str)
 {
@@ -192,6 +194,10 @@
 		return 1;
 	llen = FMT_LLEN(f);
 	w = fmt_wordslen(f, beg, end);
+	if (str && FMT_ADJ(f) && n_j & AD_K) {
+		fmt_keshideh(f, beg, end, llen - w);
+		w = fmt_wordslen(f, beg, end);
+	}
 	nspc = fmt_spaces(f, beg, end);
 	if (nspc && FMT_ADJ(f) && (llen < w || str)) {
 		fmt_div = (llen - w) / nspc;
@@ -394,6 +400,34 @@
 	f->nls_sup = 0;
 	f->gap = 0;
 	return 0;
+}
+
+/* insert keshideh characters */
+static void fmt_keshideh(struct fmt *f, int beg, int end, int wid)
+{
+	struct wb wb;
+	int kw, i = 0, c = 0;
+	struct word *w;
+	int cnt = 0;
+	do {
+		cnt = 0;
+		for (c = 0; c < 2; c++) {
+			for (i = end - 1 - c; i >= beg; i -= 2) {
+				w = &f->words[i];
+				wb_init(&wb);
+				kw = wb_keshideh(w->s, &wb, wid);
+				if (kw > 0) {
+					free(w->s);
+					w->s = xmalloc(strlen(wb_buf(&wb)) + 1);
+					strcpy(w->s, wb_buf(&wb));
+					w->wid = wb_wid(&wb);
+					wid -= kw;
+					cnt++;
+				}
+				wb_done(&wb);
+			}
+		}
+	} while (cnt);
 }
 
 /* approximate 8 * sqrt(cost) */
--- a/roff.h
+++ b/roff.h
@@ -277,6 +277,8 @@
 void wb_fnszget(struct wb *wb, int *fn, int *sz, int *m, int *cd);
 void wb_fnszset(struct wb *wb, int fn, int sz, int m, int cd);
 void wb_flushdir(struct wb *wb);
+void wb_reset(struct wb *wb);
+int wb_keshideh(char *word, struct wb *dst, int wid);
 int wb_hywid(struct wb *wb);
 int wb_swid(struct wb *wb);
 int c_eossent(char *s);
@@ -308,6 +310,7 @@
 #define AD_R		2	/* adjust right margin (flag) */
 #define AD_B		3	/* adjust both margin (mask) */
 #define AD_P		4	/* paragraph-at-once adjustment (flag) */
+#define AD_K		8	/* keshideh adjustment (flag) */
 
 /* line formatting */
 struct fmt *fmt_alloc(void);
--- a/tr.c
+++ b/tr.c
@@ -335,6 +335,8 @@
 	case 'b':
 	case 'n':
 		return AD_B;
+	case 'k':
+		return AD_B | AD_K;
 	}
 	return def;
 }
--- a/wb.c
+++ b/wb.c
@@ -568,3 +568,52 @@
 {
 	return font_swid(dev_font(R_F(wb)), R_S(wb), n_ss);
 }
+
+static char *keshideh_chars[] = {
+	"ﺒ", "ﺑ", "ﭙ", "ﭘ", "ﺘ", "ﺗ", "ﺜ", "ﺛ", "ﺴ", "ﺳ",
+	"ﺸ", "ﺷ", "ﻔ", "ﻓ", "ﻘ", "ﻗ", "ﮑ", "ﮐ", "ﮕ", "ﮔ",
+	"ﻤ", "ﻣ", "ﻨ", "ﻧ", "ﻬ", "ﻫ", "ﯿ", "ﯾ",
+};
+
+static int keshideh(char *c)
+{
+	int i;
+	for (i = 0; i < LEN(keshideh_chars); i++)
+		if (!strcmp(keshideh_chars[i], c))
+			return 1;
+	return 0;
+}
+
+/* insert keshideh */
+int wb_keshideh(char *word, struct wb *dst, int wid)
+{
+	char p[GNLEN] = "";
+	char *s, *d, *s_prev = NULL, *s_kesh = NULL;
+	int ins = 0;
+	int c;
+	/* find the last keshideh position */
+	s = word;
+	while ((c = escread(&s, &d)) >= 0) {
+		wb_putc(dst, c, d);
+		if (!c && strcmp("ـ", d) && keshideh(p)) {
+			struct glyph *g = dev_glyph("ـ", R_F(dst));
+			int kw = g ? font_gwid(g->font,
+					dev_font(R_F(dst)), R_S(dst), g->wid) : 0;
+			if (g && kw < wid) {
+				s_kesh = s_prev;
+				ins = kw;
+			}
+		}
+		s_prev = s;
+		strcpy(p, c ? "" : d);
+	}
+	/* insert the keshideh at s_kesh */
+	s = word;
+	wb_reset(dst);
+	while ((c = escread(&s, &d)) >= 0) {
+		wb_putc(dst, c, d);
+		if (s == s_kesh)
+				wb_putc(dst, 0, "ـ");
+	}
+	return ins;
+}