gen.sh: fix the font mapped to Helvetica and ZapfDingbats
[neatmkfn.git] / trfn.c
blobc9f2bd27fc48b3e2cf421e2dc1eabeb9aedba4af
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 int trfn_bbox; /* include bounding box */
26 static char trfn_ligs[8192]; /* font ligatures */
27 static char trfn_trname[256]; /* font troff name */
28 static char trfn_psname[256]; /* font ps name */
29 /* glyph substition */
30 static char subs_src[NSUBS][GNLEN];
31 static char subs_dst[NSUBS][GNLEN];
32 static int subs_n;
33 /* character type */
34 static int trfn_asc; /* minimum height of glyphs with ascender */
35 static int trfn_desc; /* minimum depth of glyphs with descender */
37 /* adobe glyphlist mapping */
38 static char agl_key[AGLLEN][GNLEN];
39 static char agl_val[AGLLEN][GNLEN];
40 static int agl_n;
42 /* lookup tables */
43 static struct tab *tab_agl;
44 static struct tab *tab_alts;
46 static int utf8len(int c)
48 if (c > 0 && c <= 0x7f)
49 return 1;
50 if (c >= 0xfc)
51 return 6;
52 if (c >= 0xf8)
53 return 5;
54 if (c >= 0xf0)
55 return 4;
56 if (c >= 0xe0)
57 return 3;
58 if (c >= 0xc0)
59 return 2;
60 return c != 0;
63 static int utf8get(char **src)
65 int result;
66 int l = 1;
67 char *s = *src;
68 if (~((unsigned char) **src) & 0xc0)
69 return (unsigned char) *(*src)++;
70 while (l < 6 && (unsigned char) *s & (0x40 >> l))
71 l++;
72 result = (0x3f >> l) & (unsigned char) *s++;
73 while (l--)
74 result = (result << 6) | ((unsigned char) *s++ & 0x3f);
75 *src = s;
76 return result;
79 static void utf8put(char **d, int c)
81 int l;
82 if (c > 0xffff) {
83 *(*d)++ = 0xf0 | (c >> 18);
84 l = 3;
85 } else if (c > 0x7ff) {
86 *(*d)++ = 0xe0 | (c >> 12);
87 l = 2;
88 } else if (c > 0x7f) {
89 *(*d)++ = 0xc0 | (c >> 6);
90 l = 1;
91 } else {
92 *(*d)++ = c > 0 ? c : ' ';
93 l = 0;
95 while (l--)
96 *(*d)++ = 0x80 | ((c >> (l * 6)) & 0x3f);
97 **d = '\0';
100 static int hexval(char *s, int len)
102 char *digs = HEXDIGS;
103 int n = 0;
104 int i;
105 for (i = 0; i < len; i++) {
106 if (s[i] && strchr(digs, tolower(s[i])))
107 n = n * 16 + (strchr(digs, tolower(s[i])) - digs);
108 else
109 break;
111 return len == 1 ? n << 4 : n;
114 static int agl_read(char *path)
116 FILE *fin = fopen(path, "r");
117 char ln[GNLEN];
118 char val[GNLEN];
119 char *s, *d;
120 int i;
121 if (!fin)
122 return 1;
123 while (fgets(ln, sizeof(ln), fin)) {
124 s = strchr(ln, ';');
125 if (ln[0] == '#' || !s)
126 continue;
127 *s++ = '\0';
128 d = val;
129 while (s && *s) {
130 while (*s == ' ')
131 s++;
132 utf8put(&d, hexval(s, 6));
133 s = strchr(s, ' ');
135 *d = '\0';
136 strcpy(agl_key[agl_n], ln);
137 strcpy(agl_val[agl_n], val);
138 agl_n++;
140 fclose(fin);
141 tab_agl = tab_alloc(agl_n);
142 for (i = 0; i < agl_n; i++)
143 tab_put(tab_agl, agl_key[i], agl_val[i]);
144 return 0;
147 static char *agl_map(char *s)
149 return tab_get(tab_agl, s);
152 static int achar_map(char *name)
154 int i;
155 for (i = 0; i < LEN(achars); i++) {
156 struct achar *a = &achars[i];
157 if (!strncmp(a->name, name, strlen(a->name))) {
158 char *postfix = name + strlen(a->name);
159 if (!*postfix)
160 return a->c;
161 if (!strcmp("isolated", postfix))
162 return a->s ? a->s : a->c;
163 if (!strcmp("initial", postfix))
164 return a->i ? a->i : a->c;
165 if (!strcmp("medial", postfix))
166 return a->m ? a->m : a->c;
167 if (!strcmp("final", postfix))
168 return a->f ? a->f : a->c;
171 return 0;
174 static int achar_shape(int c, int pjoin, int njoin)
176 int i;
177 for (i = 0; i < LEN(achars); i++) {
178 struct achar *a = &achars[i];
179 if (a->c == c) {
180 if (!pjoin && !njoin)
181 return a->c;
182 if (!pjoin && njoin)
183 return a->i ? a->i : a->c;
184 if (pjoin && njoin)
185 return a->m ? a->m : a->c;
186 if (pjoin && !njoin)
187 return a->f ? a->f : a->c;
190 return c;
193 static void ashape(char *str, char *ext)
195 int s[NCHAR];
196 char *src = str;
197 int i, l;
198 int bjoin = !strcmp(".medi", ext) || !strcmp(".fina", ext);
199 int ejoin = !strcmp(".medi", ext) || !strcmp(".init", ext);
200 for (l = 0; l < NCHAR && *src; l++)
201 s[l] = utf8get(&src);
202 for (i = 0; i < l; i++)
203 s[i] = achar_shape(s[i], i > 0 || bjoin, i < l - 1 || ejoin);
204 for (i = 0; i < l; i++)
205 utf8put(&str, s[i]);
208 void trfn_sub(char *c1, char *c2)
210 if (subs_n < NSUBS && !strchr(c1, '.')) {
211 strcpy(subs_src[subs_n], c1);
212 strcpy(subs_dst[subs_n], c2);
213 subs_n++;
217 /* return the list of postscript glyph aliases of character c */
218 static void trfn_subs(char *c, char **a)
220 char *dot;
221 int i, subs = 0;
222 /* adding c itself to the list of aliases only if not substituded */
223 for (i = 0; i < subs_n; i++)
224 if (!strcmp(c, subs_src[i]))
225 subs = 1;
226 dot = strrchr(c, '.');
227 if (!subs && (!dot || !strcmp(".isol", dot) || !strcmp(".init", dot) ||
228 !strcmp(".fina", dot) || !strcmp(".medi", dot)))
229 *a++ = c;
230 /* adding aliases added via trfn_subs() */
231 for (i = 0; i < subs_n; i++)
232 if (!strcmp(c, subs_dst[i]))
233 *a++ = subs_src[i];
234 *a++ = NULL;
237 static int trfn_name(char *dst, char *src)
239 char ch[GNLEN];
240 char *d = dst;
241 char *s;
242 int i;
243 if (!src || src[0] == '.')
244 return 1;
245 while (*src && *src != '.') {
246 s = ch;
247 if (src[0] == '_')
248 src++;
249 while (*src && *src != '_' && *src != '.')
250 *s++ = *src++;
251 *s = '\0';
252 if (agl_map(ch)) {
253 strcpy(d, agl_map(ch));
254 for (i = 0; i < LEN(agl_exceptions); i++) {
255 if (!strcmp(agl_exceptions[i][0], d)) {
256 strcpy(d, agl_exceptions[i][1]);
257 break;
260 d = strchr(d, '\0');
261 } else if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'i') {
262 for (i = 0; strlen(ch + 3 + 4 * i) >= 4; i++)
263 utf8put(&d, hexval(ch + 3 + 4 * i, 4));
264 } else if (ch[0] == 'u' && ch[1] && strchr(HEXDIGS, tolower(ch[1]))) {
265 utf8put(&d, hexval(ch + 1, 6));
266 } else if (achar_map(ch)) {
267 utf8put(&d, achar_map(ch));
268 } else {
269 return 1;
272 ashape(dst, src);
273 return 0;
276 static void trfn_lig(char *c)
278 int i;
279 for (i = 0; i < LEN(ligs_exceptions); i++)
280 if (!strcmp(ligs_exceptions[i], c))
281 return;
282 if (c[0] && c[1] && strlen(c) > utf8len((unsigned char) c[0])) {
283 sprintf(strchr(trfn_ligs, '\0'), "%s ", c);
284 } else {
285 for (i = 0; i < LEN(ligs_utf8); i++)
286 if (!strcmp(ligs_utf8[i][0], c))
287 sprintf(strchr(trfn_ligs, '\0'),
288 "%s ", ligs_utf8[i][1]);
292 static int trfn_type(char *s, int lly, int ury)
294 int typ = 0;
295 int c = !s[0] || s[1] ? 0 : (unsigned char) *s;
296 if (c == 't' && !trfn_asc)
297 trfn_asc = ury;
298 if ((c == 'g' || c == 'j' || c == 'p' || c == 'q' || c == 'y') &&
299 (!trfn_desc || trfn_desc < lly))
300 trfn_desc = lly;
301 if (!trfn_desc || !trfn_asc) {
302 if (c > 0 && c < 128)
303 return ctype_ascii[c];
304 return 3;
306 if (!trfn_desc || lly <= trfn_desc)
307 typ |= 1;
308 if (!trfn_asc || ury >= trfn_asc)
309 typ |= 2;
310 return typ;
313 void trfn_char(char *psname, char *n, int wid,
314 int llx, int lly, int urx, int ury)
316 char uc[GNLEN]; /* mapping unicode character */
317 char *a_ps[NPSAL] = {NULL}; /* postscript glyph substitutions */
318 char **a_tr; /* troff character names */
319 char pos[GNLEN] = ""; /* postscript character position/name */
320 int i_ps = 0; /* current name in a_ps */
321 int typ; /* character type */
322 /* initializing character attributes */
323 if (trfn_name(uc, psname))
324 strcpy(uc, "---");
325 if (n && atoi(n) >= 0 && atoi(n) < 256)
326 strcpy(pos, n);
327 if (!n && !strchr(psname, '.') && !uc[1] && uc[0] >= 32 && uc[0] <= 125)
328 sprintf(pos, "%d", uc[0]);
329 typ = trfn_type(!strchr(psname, '.') ? uc : "", lly, ury);
330 /* printing troff charset */
331 trfn_subs(psname, a_ps);
332 for (i_ps = 0; !i_ps || a_ps[i_ps]; i_ps++) {
333 if (trfn_name(uc, a_ps[i_ps]))
334 strcpy(uc, "---");
335 if (strchr(uc, ' ')) { /* space not allowed in char names */
336 if (!trfn_swid && !strcmp(" ", uc))
337 trfn_swid = WX(wid);
338 continue;
340 if (strcmp("---", uc))
341 trfn_lig(uc);
342 sbuf_printf(&sbuf_char, "char %s\t%d", uc, WX(wid));
343 if (trfn_bbox && (llx || lly || urx || ury))
344 sbuf_printf(&sbuf_char, ",%d,%d,%d,%d",
345 WX(llx), WX(lly), WX(urx), WX(ury));
346 sbuf_printf(&sbuf_char, "\t%d\t%s\t%s\n", typ, psname, pos);
347 a_tr = tab_get(tab_alts, uc);
348 while (a_tr && *a_tr)
349 sbuf_printf(&sbuf_char, "char %s\t\"\n", *a_tr++);
353 void trfn_kern(char *c1, char *c2, int x)
355 if (WX(x) && abs(WX(x)) >= WX(trfn_kmin))
356 sbuf_printf(&sbuf_kern, "kern %s\t%s\t%d\n", c1, c2, WX(x));
359 void trfn_trfont(char *name)
361 if (!trfn_trname[0])
362 strcpy(trfn_trname, name);
365 void trfn_psfont(char *name)
367 if (!trfn_psname[0])
368 strcpy(trfn_psname, name);
371 void trfn_print(void)
373 if (trfn_trname[0])
374 printf("name %s\n", trfn_trname);
375 if (trfn_psname[0])
376 printf("fontname %s\n", trfn_psname);
377 printf("spacewidth %d\n", trfn_swid);
378 printf("ligatures %s0\n", trfn_ligs);
379 if (trfn_special)
380 printf("special\n");
381 printf("%s", sbuf_buf(&sbuf_char));
382 printf("%s", sbuf_buf(&sbuf_kern));
385 void trfn_init(int res, int spc, int kmin, int bbox)
387 int i;
388 trfn_div = 7200 / res;
389 trfn_special = spc;
390 trfn_kmin = kmin;
391 trfn_bbox = bbox;
392 if (agl_read("glyphlist.txt"))
393 fprintf(stderr, "mktrfn: could not open glyphlist.txt\n");
394 sbuf_init(&sbuf_char);
395 sbuf_init(&sbuf_kern);
396 tab_alts = tab_alloc(LEN(alts));
397 for (i = 0; i < LEN(alts); i++)
398 tab_put(tab_alts, alts[i][0], alts[i] + 1);
401 void trfn_done(void)
403 sbuf_done(&sbuf_char);
404 sbuf_done(&sbuf_kern);
405 tab_free(tab_alts);
406 if (tab_agl)
407 tab_free(tab_agl);