trfn: output only nonzero kerning values
[neatmkfn.git] / trfn.c
blobe0492cd38c58edd331ec689b2bd361dd222640b4
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "sbuf.h"
6 #include "tab.h"
7 #include "trfn.h"
8 #include "trfn_ch.h"
10 #define WX(w) (((w) < 0 ? (w) - trfn_div / 2 : (w) + trfn_div / 2) / trfn_div)
11 #define LEN(a) ((sizeof(a) / sizeof((a)[0])))
12 #define HEXDIGS "0123456789abcdef"
13 #define NCHAR 8 /* number of characters per glyph */
14 #define GNLEN 64 /* glyph name length */
15 #define AGLLEN 8192 /* adobe glyphlist length */
16 #define NSUBS 2048 /* number of substitutions */
17 #define NPSAL 32 /* number of substitutions per glyph */
19 static struct sbuf sbuf_char; /* characters */
20 static struct sbuf sbuf_kern; /* kerning pairs */
21 static int trfn_div; /* divisor of widths */
22 static int trfn_swid; /* space width */
23 static int trfn_special; /* special flag */
24 static int trfn_kmin; /* minimum kerning value */
25 static char trfn_ligs[8192]; /* font ligatures */
26 static char trfn_trname[256]; /* font troff name */
27 static char trfn_psname[256]; /* font ps name */
28 /* glyph substition */
29 static char subs_src[NSUBS][GNLEN];
30 static char subs_dst[NSUBS][GNLEN];
31 static int subs_n;
33 /* adobe glyphlist mapping */
34 static char agl_key[AGLLEN][GNLEN];
35 static char agl_val[AGLLEN][GNLEN];
36 static int agl_n;
38 /* lookup tables */
39 static struct tab *tab_agl;
40 static struct tab *tab_alts;
41 static struct tab *tab_ctyp;
43 static int utf8len(int c)
45 if (c > 0 && c <= 0x7f)
46 return 1;
47 if (c >= 0xfc)
48 return 6;
49 if (c >= 0xf8)
50 return 5;
51 if (c >= 0xf0)
52 return 4;
53 if (c >= 0xe0)
54 return 3;
55 if (c >= 0xc0)
56 return 2;
57 return c != 0;
60 static int utf8get(char **src)
62 int result;
63 int l = 1;
64 char *s = *src;
65 if (~((unsigned char) **src) & 0xc0)
66 return (unsigned char) *(*src)++;
67 while (l < 6 && (unsigned char) *s & (0x40 >> l))
68 l++;
69 result = (0x3f >> l) & (unsigned char) *s++;
70 while (l--)
71 result = (result << 6) | ((unsigned char) *s++ & 0x3f);
72 *src = s;
73 return result;
76 static void utf8put(char **d, int c)
78 int l;
79 if (c > 0xffff) {
80 *(*d)++ = 0xf0 | (c >> 18);
81 l = 3;
82 } else if (c > 0x7ff) {
83 *(*d)++ = 0xe0 | (c >> 12);
84 l = 2;
85 } else if (c > 0x7f) {
86 *(*d)++ = 0xc0 | (c >> 6);
87 l = 1;
88 } else {
89 *(*d)++ = c > 0 ? c : ' ';
90 l = 0;
92 while (l--)
93 *(*d)++ = 0x80 | ((c >> (l * 6)) & 0x3f);
94 **d = '\0';
97 static int hexval(char *s, int len)
99 char *digs = HEXDIGS;
100 int n = 0;
101 int i;
102 for (i = 0; i < len; i++) {
103 if (s[i] && strchr(digs, tolower(s[i])))
104 n = n * 16 + (strchr(digs, tolower(s[i])) - digs);
105 else
106 break;
108 return len == 1 ? n << 4 : n;
111 static int agl_read(char *path)
113 FILE *fin = fopen(path, "r");
114 char ln[GNLEN];
115 char val[GNLEN];
116 char *s, *d;
117 int i;
118 if (!fin)
119 return 1;
120 while (fgets(ln, sizeof(ln), fin)) {
121 s = strchr(ln, ';');
122 if (ln[0] == '#' || !s)
123 continue;
124 *s++ = '\0';
125 d = val;
126 while (s && *s) {
127 while (*s == ' ')
128 s++;
129 utf8put(&d, hexval(s, 6));
130 s = strchr(s, ' ');
132 *d = '\0';
133 strcpy(agl_key[agl_n], ln);
134 strcpy(agl_val[agl_n], val);
135 agl_n++;
137 fclose(fin);
138 tab_agl = tab_alloc(agl_n);
139 for (i = 0; i < agl_n; i++)
140 tab_put(tab_agl, agl_key[i], agl_val[i]);
141 return 0;
144 static char *agl_map(char *s)
146 return tab_get(tab_agl, s);
149 static int achar_map(char *name)
151 int i;
152 for (i = 0; i < LEN(achars); i++) {
153 struct achar *a = &achars[i];
154 if (!strncmp(a->name, name, strlen(a->name))) {
155 char *postfix = name + strlen(a->name);
156 if (!*postfix)
157 return a->c;
158 if (!strcmp("isolated", postfix))
159 return a->s ? a->s : a->c;
160 if (!strcmp("initial", postfix))
161 return a->i ? a->i : a->c;
162 if (!strcmp("medial", postfix))
163 return a->m ? a->m : a->c;
164 if (!strcmp("final", postfix))
165 return a->f ? a->f : a->c;
168 return 0;
171 static int achar_shape(int c, int pjoin, int njoin)
173 int i;
174 for (i = 0; i < LEN(achars); i++) {
175 struct achar *a = &achars[i];
176 if (a->c == c) {
177 if (!pjoin && !njoin)
178 return a->c;
179 if (!pjoin && njoin)
180 return a->i ? a->i : a->c;
181 if (pjoin && njoin)
182 return a->m ? a->m : a->c;
183 if (pjoin && !njoin)
184 return a->f ? a->f : a->c;
187 return c;
190 static void ashape(char *str, char *ext)
192 int s[NCHAR];
193 char *src = str;
194 int i, l;
195 int bjoin = !strcmp(".medi", ext) || !strcmp(".fina", ext);
196 int ejoin = !strcmp(".medi", ext) || !strcmp(".init", ext);
197 for (l = 0; l < NCHAR && *src; l++)
198 s[l] = utf8get(&src);
199 for (i = 0; i < l; i++)
200 s[i] = achar_shape(s[i], i > 0 || bjoin, i < l - 1 || ejoin);
201 for (i = 0; i < l; i++)
202 utf8put(&str, s[i]);
205 void trfn_sub(char *c1, char *c2)
207 if (subs_n < NSUBS && !strchr(c1, '.')) {
208 strcpy(subs_src[subs_n], c1);
209 strcpy(subs_dst[subs_n], c2);
210 subs_n++;
214 /* return the list of postscript glyph aliases of character c */
215 static void trfn_subs(char *c, char **a)
217 char *dot;
218 int i, subs = 0;
219 /* adding c itself to the list of aliases only if not substituded */
220 for (i = 0; i < subs_n; i++)
221 if (!strcmp(c, subs_src[i]))
222 subs = 1;
223 dot = strrchr(c, '.');
224 if (!subs && (!dot || !strcmp(".isol", dot) || !strcmp(".init", dot) ||
225 !strcmp(".fina", dot) || !strcmp(".medi", dot)))
226 *a++ = c;
227 /* adding aliases added via trfn_subs() */
228 for (i = 0; i < subs_n; i++)
229 if (!strcmp(c, subs_dst[i]))
230 *a++ = subs_src[i];
231 *a++ = NULL;
234 static int trfn_name(char *dst, char *src)
236 char ch[GNLEN];
237 char *d = dst;
238 char *s;
239 int i;
240 if (!src || src[0] == '.')
241 return 1;
242 while (*src && *src != '.') {
243 s = ch;
244 if (src[0] == '_')
245 src++;
246 while (*src && *src != '_' && *src != '.')
247 *s++ = *src++;
248 *s = '\0';
249 if (agl_map(ch)) {
250 strcpy(d, agl_map(ch));
251 for (i = 0; i < LEN(agl_exceptions); i++)
252 if (!strcmp(agl_exceptions[i][0], d))
253 strcpy(d, agl_exceptions[i][1]);
254 d = strchr(d, '\0');
255 } else if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'i') {
256 for (i = 0; strlen(ch + 3 + 4 * i) >= 4; i++)
257 utf8put(&d, hexval(ch + 3 + 4 * i, 4));
258 } else if (ch[0] == 'u' && ch[1] && strchr(HEXDIGS, tolower(ch[1]))) {
259 utf8put(&d, hexval(ch + 1, 6));
260 } else if (achar_map(ch)) {
261 utf8put(&d, achar_map(ch));
262 } else {
263 return 1;
266 ashape(dst, src);
267 return 0;
270 static void trfn_lig(char *c)
272 int i;
273 if (c[0] && c[1] && strlen(c) > utf8len((unsigned char) c[0])) {
274 sprintf(strchr(trfn_ligs, '\0'), "%s ", c);
275 return;
277 for (i = 0; i < LEN(ligs); i++)
278 if (!strcmp(ligs[i], c))
279 sprintf(strchr(trfn_ligs, '\0'), "%s ", c);
282 static int trfn_type(char *c)
284 struct ctype *t = tab_get(tab_ctyp, c);
285 return t ? t->type : 3;
288 void trfn_char(char *psname, char *n, int wid, int typ)
290 char uc[GNLEN]; /* mapping unicode character */
291 char *a_ps[NPSAL] = {NULL}; /* postscript glyph substitutions */
292 char **a_tr; /* troff character names */
293 char pos[GNLEN] = ""; /* postscript character position/name */
294 int i_ps = 0; /* current name in a_ps */
295 /* initializing character attributes */
296 if (trfn_name(uc, psname))
297 strcpy(uc, "---");
298 if (n && atoi(n) >= 0 && atoi(n) < 256)
299 strcpy(pos, n);
300 if (!n && !strchr(psname, '.') && !uc[1] && uc[0] >= 32 && uc[0] <= 125)
301 sprintf(pos, "%d", uc[0]);
302 if (typ < 0)
303 typ = trfn_type(!strchr(psname, '.') ? uc : "");
304 /* printing troff charset */
305 trfn_subs(psname, a_ps);
306 for (i_ps = 0; !i_ps || a_ps[i_ps]; i_ps++) {
307 if (trfn_name(uc, a_ps[i_ps]))
308 strcpy(uc, "---");
309 if (strchr(uc, ' ')) { /* space not allowed in char names */
310 if (!trfn_swid && !strcmp(" ", uc))
311 trfn_swid = WX(wid);
312 continue;
314 if (strcmp("---", uc))
315 trfn_lig(uc);
316 sbuf_printf(&sbuf_char, "char %s\t%d\t%d\t%s\t%s\n",
317 uc, WX(wid), typ, psname, pos);
318 a_tr = tab_get(tab_alts, uc);
319 while (a_tr && *a_tr)
320 sbuf_printf(&sbuf_char, "char %s\t\"\n", *a_tr++);
324 void trfn_kern(char *c1, char *c2, int x)
326 if (WX(x) && abs(WX(x)) >= WX(trfn_kmin))
327 sbuf_printf(&sbuf_kern, "kern %s\t%s\t%d\n", c1, c2, WX(x));
330 void trfn_trfont(char *name)
332 if (!trfn_trname[0])
333 strcpy(trfn_trname, name);
336 void trfn_psfont(char *name)
338 if (!trfn_psname[0])
339 strcpy(trfn_psname, name);
342 void trfn_print(void)
344 if (trfn_trname[0])
345 printf("name %s\n", trfn_trname);
346 if (trfn_psname[0])
347 printf("fontname %s\n", trfn_psname);
348 printf("spacewidth %d\n", trfn_swid);
349 printf("ligatures %s0\n", trfn_ligs);
350 if (trfn_special)
351 printf("special\n");
352 printf("%s", sbuf_buf(&sbuf_char));
353 printf("%s", sbuf_buf(&sbuf_kern));
356 void trfn_init(int res, int spc, int kmin)
358 int i;
359 trfn_div = 7200 / res;
360 trfn_special = spc;
361 trfn_kmin = kmin;
362 if (agl_read("glyphlist.txt"))
363 fprintf(stderr, "mktrfn: could not open glyphlist.txt\n");
364 sbuf_init(&sbuf_char);
365 sbuf_init(&sbuf_kern);
366 tab_alts = tab_alloc(LEN(alts));
367 tab_ctyp = tab_alloc(LEN(ctype));
368 for (i = 0; i < LEN(alts); i++)
369 tab_put(tab_alts, alts[i][0], alts[i] + 1);
370 for (i = 0; i < LEN(ctype); i++)
371 tab_put(tab_ctyp, ctype[i].ch, &ctype[i]);
374 void trfn_done(void)
376 sbuf_done(&sbuf_char);
377 sbuf_done(&sbuf_kern);
378 tab_free(tab_alts);
379 tab_free(tab_ctyp);
380 if (tab_agl)
381 tab_free(tab_agl);