otf: clean up
[neatmkfn.git] / trfn.c
blob6d420aec8721031e3f786e1c968f4361a477c1cf
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 */
17 static struct sbuf sbuf_char; /* characters */
18 static struct sbuf sbuf_kern; /* kerning pairs */
19 static int trfn_div; /* divisor of widths */
20 static int trfn_swid; /* space width */
21 static int trfn_special; /* special flag */
22 static int trfn_kmin; /* minimum kerning value */
23 static int trfn_bbox; /* include bounding box */
24 static char trfn_ligs[8192]; /* font ligatures */
25 static char trfn_trname[256]; /* font troff name */
26 static char trfn_psname[256]; /* font ps name */
27 /* character type */
28 static int trfn_asc; /* minimum height of glyphs with ascender */
29 static int trfn_desc; /* minimum depth of glyphs with descender */
31 /* adobe glyphlist mapping */
32 static char agl_key[AGLLEN][GNLEN];
33 static char agl_val[AGLLEN][GNLEN];
34 static int agl_n;
36 /* lookup tables */
37 static struct tab *tab_agl;
38 static struct tab *tab_alts;
40 static int utf8len(int c)
42 if (c > 0 && c <= 0x7f)
43 return 1;
44 if (c >= 0xfc)
45 return 6;
46 if (c >= 0xf8)
47 return 5;
48 if (c >= 0xf0)
49 return 4;
50 if (c >= 0xe0)
51 return 3;
52 if (c >= 0xc0)
53 return 2;
54 return c != 0;
57 static int utf8get(char **src)
59 int result;
60 int l = 1;
61 char *s = *src;
62 if (~((unsigned char) **src) & 0xc0)
63 return (unsigned char) *(*src)++;
64 while (l < 6 && (unsigned char) *s & (0x40 >> l))
65 l++;
66 result = (0x3f >> l) & (unsigned char) *s++;
67 while (l--)
68 result = (result << 6) | ((unsigned char) *s++ & 0x3f);
69 *src = s;
70 return result;
73 static void utf8put(char **d, int c)
75 int l;
76 if (c > 0xffff) {
77 *(*d)++ = 0xf0 | (c >> 18);
78 l = 3;
79 } else if (c > 0x7ff) {
80 *(*d)++ = 0xe0 | (c >> 12);
81 l = 2;
82 } else if (c > 0x7f) {
83 *(*d)++ = 0xc0 | (c >> 6);
84 l = 1;
85 } else {
86 *(*d)++ = c > 0 ? c : ' ';
87 l = 0;
89 while (l--)
90 *(*d)++ = 0x80 | ((c >> (l * 6)) & 0x3f);
91 **d = '\0';
94 static int hexval(char *s, int len)
96 char *digs = HEXDIGS;
97 int n = 0;
98 int i;
99 for (i = 0; i < len; i++) {
100 if (s[i] && strchr(digs, tolower(s[i])))
101 n = n * 16 + (strchr(digs, tolower(s[i])) - digs);
102 else
103 break;
105 return len == 1 ? n << 4 : n;
108 static int agl_read(char *path)
110 FILE *fin = fopen(path, "r");
111 char ln[GNLEN];
112 char val[GNLEN];
113 char *s, *d;
114 int i;
115 if (!fin)
116 return 1;
117 while (fgets(ln, sizeof(ln), fin)) {
118 s = strchr(ln, ';');
119 if (ln[0] == '#' || !s)
120 continue;
121 *s++ = '\0';
122 d = val;
123 while (s && *s) {
124 while (*s == ' ')
125 s++;
126 utf8put(&d, hexval(s, 6));
127 s = strchr(s, ' ');
129 *d = '\0';
130 strcpy(agl_key[agl_n], ln);
131 strcpy(agl_val[agl_n], val);
132 agl_n++;
134 fclose(fin);
135 tab_agl = tab_alloc(agl_n);
136 for (i = 0; i < agl_n; i++)
137 tab_put(tab_agl, agl_key[i], agl_val[i]);
138 return 0;
141 static char *agl_map(char *s)
143 return tab_get(tab_agl, s);
146 static int achar_map(char *name)
148 int i;
149 for (i = 0; i < LEN(achars); i++) {
150 struct achar *a = &achars[i];
151 if (!strncmp(a->name, name, strlen(a->name))) {
152 char *postfix = name + strlen(a->name);
153 if (!*postfix)
154 return a->c;
155 if (!strcmp("isolated", postfix))
156 return a->s ? a->s : a->c;
157 if (!strcmp("initial", postfix))
158 return a->i ? a->i : a->c;
159 if (!strcmp("medial", postfix))
160 return a->m ? a->m : a->c;
161 if (!strcmp("final", postfix))
162 return a->f ? a->f : a->c;
165 return 0;
168 static int achar_shape(int c, int pjoin, int njoin)
170 int i;
171 for (i = 0; i < LEN(achars); i++) {
172 struct achar *a = &achars[i];
173 if (a->c == c) {
174 if (!pjoin && !njoin)
175 return a->c;
176 if (!pjoin && njoin)
177 return a->i ? a->i : a->c;
178 if (pjoin && njoin)
179 return a->m ? a->m : a->c;
180 if (pjoin && !njoin)
181 return a->f ? a->f : a->c;
184 return c;
187 static void ashape(char *str, char *ext)
189 int s[NCHAR];
190 char *src = str;
191 int i, l;
192 int bjoin = !strcmp(".medi", ext) || !strcmp(".fina", ext);
193 int ejoin = !strcmp(".medi", ext) || !strcmp(".init", ext);
194 for (l = 0; l < NCHAR && *src; l++)
195 s[l] = utf8get(&src);
196 for (i = 0; i < l; i++)
197 s[i] = achar_shape(s[i], i > 0 || bjoin, i < l - 1 || ejoin);
198 for (i = 0; i < l; i++)
199 utf8put(&str, s[i]);
202 /* find the utf-8 name of src with the given unicode codepoint */
203 static int trfn_name(char *dst, char *src, int codepoint)
205 char ch[GNLEN];
206 char *d = dst;
207 char *s;
208 int i;
209 if (codepoint) {
210 utf8put(&dst, codepoint);
211 return 0;
213 if (!src || src[0] == '.')
214 return 1;
215 while (*src && *src != '.') {
216 s = ch;
217 if (src[0] == '_')
218 src++;
219 while (*src && *src != '_' && *src != '.')
220 *s++ = *src++;
221 *s = '\0';
222 if (agl_map(ch)) {
223 strcpy(d, agl_map(ch));
224 for (i = 0; i < LEN(agl_exceptions); i++) {
225 if (!strcmp(agl_exceptions[i][0], d)) {
226 strcpy(d, agl_exceptions[i][1]);
227 break;
230 d = strchr(d, '\0');
231 } else if (ch[0] == 'u' && ch[1] == 'n' && ch[2] == 'i') {
232 for (i = 0; strlen(ch + 3 + 4 * i) >= 4; i++)
233 utf8put(&d, hexval(ch + 3 + 4 * i, 4));
234 } else if (ch[0] == 'u' && ch[1] && strchr(HEXDIGS, tolower(ch[1]))) {
235 utf8put(&d, hexval(ch + 1, 6));
236 } else if (achar_map(ch)) {
237 utf8put(&d, achar_map(ch));
238 } else {
239 return 1;
242 ashape(dst, src);
243 return 0;
246 static void trfn_lig(char *c)
248 int i;
249 for (i = 0; i < LEN(ligs_exceptions); i++)
250 if (!strcmp(ligs_exceptions[i], c))
251 return;
252 if (c[0] && c[1] && strlen(c) > utf8len((unsigned char) c[0])) {
253 sprintf(strchr(trfn_ligs, '\0'), "%s ", c);
254 } else {
255 for (i = 0; i < LEN(ligs_utf8); i++)
256 if (!strcmp(ligs_utf8[i][0], c))
257 sprintf(strchr(trfn_ligs, '\0'),
258 "%s ", ligs_utf8[i][1]);
262 static int trfn_type(char *s, int lly, int ury)
264 int typ = 0;
265 int c = !s[0] || s[1] ? 0 : (unsigned char) *s;
266 if (c == 't' && !trfn_asc)
267 trfn_asc = ury;
268 if ((c == 'g' || c == 'j' || c == 'p' || c == 'q' || c == 'y') &&
269 (!trfn_desc || trfn_desc < lly))
270 trfn_desc = lly;
271 if (!trfn_desc || !trfn_asc) {
272 if (c > 0 && c < 128)
273 return ctype_ascii[c];
274 return 3;
276 if (!trfn_desc || lly <= trfn_desc)
277 typ |= 1;
278 if (!trfn_asc || ury >= trfn_asc)
279 typ |= 2;
280 return typ;
283 /* n is the position and u is the unicode codepoint */
284 void trfn_char(char *psname, int n, int u, int wid,
285 int llx, int lly, int urx, int ury)
287 char uc[GNLEN]; /* mapping unicode character */
288 char **a_tr; /* troff character names */
289 char pos[GNLEN] = ""; /* postscript character position/name */
290 int typ; /* character type */
291 /* initializing character attributes */
292 if (trfn_name(uc, psname, u))
293 strcpy(uc, "---");
294 if (n >= 0 && n < 256)
295 sprintf(pos, "%d", n);
296 if (n < 0 && !uc[1] && uc[0] >= 32 && uc[0] <= 125)
297 if (!strchr(psname, '.'))
298 sprintf(pos, "%d", uc[0]);
299 typ = trfn_type(!strchr(psname, '.') ? uc : "", lly, ury);
300 /* printing troff charset */
301 if (strchr(uc, ' ')) { /* space not allowed in char names */
302 if (!trfn_swid && !strcmp(" ", uc))
303 trfn_swid = WX(wid);
304 return;
306 if (strcmp("---", uc))
307 trfn_lig(uc);
308 sbuf_printf(&sbuf_char, "char %s\t%d", uc, WX(wid));
309 if (trfn_bbox && (llx || lly || urx || ury))
310 sbuf_printf(&sbuf_char, ",%d,%d,%d,%d",
311 WX(llx), WX(lly), WX(urx), WX(ury));
312 sbuf_printf(&sbuf_char, "\t%d\t%s\t%s\n", typ, psname, pos);
313 a_tr = tab_get(tab_alts, uc);
314 while (a_tr && *a_tr)
315 sbuf_printf(&sbuf_char, "char %s\t\"\n", *a_tr++);
318 void trfn_kern(char *c1, char *c2, int x)
320 if (WX(x) && abs(WX(x)) >= trfn_kmin)
321 sbuf_printf(&sbuf_kern, "kern %s\t%s\t%d\n", c1, c2, WX(x));
324 void trfn_trfont(char *name)
326 if (!trfn_trname[0])
327 strcpy(trfn_trname, name);
330 void trfn_psfont(char *name)
332 if (!trfn_psname[0])
333 strcpy(trfn_psname, name);
336 void trfn_print(void)
338 if (trfn_trname[0])
339 printf("name %s\n", trfn_trname);
340 if (trfn_psname[0])
341 printf("fontname %s\n", trfn_psname);
342 printf("spacewidth %d\n", trfn_swid);
343 printf("ligatures %s0\n", trfn_ligs);
344 if (trfn_special)
345 printf("special\n");
346 printf("%s", sbuf_buf(&sbuf_char));
347 printf("%s", sbuf_buf(&sbuf_kern));
350 void trfn_init(int res, int spc, int kmin, int bbox)
352 int i;
353 trfn_div = 7200 / res;
354 trfn_special = spc;
355 trfn_kmin = kmin;
356 trfn_bbox = bbox;
357 if (agl_read("glyphlist.txt"))
358 fprintf(stderr, "mktrfn: could not open glyphlist.txt\n");
359 sbuf_init(&sbuf_char);
360 sbuf_init(&sbuf_kern);
361 tab_alts = tab_alloc(LEN(alts));
362 for (i = 0; i < LEN(alts); i++)
363 tab_put(tab_alts, alts[i][0], alts[i] + 1);
366 void trfn_done(void)
368 sbuf_done(&sbuf_char);
369 sbuf_done(&sbuf_kern);
370 tab_free(tab_alts);
371 if (tab_agl)
372 tab_free(tab_agl);