trfn_ch.h: fix ws digraph mapping
[neatmkfn.git] / mkfn.c
blob892a12cd71e7e3bce6730599becf8e9e04c70d02
1 /*
2 * NEATMKFN - GENERATE NEATROFF FONT DESCRIPTIONS
4 * Copyright (C) 2012-2018 Ali Gholami Rudi <ali at rudi dot ir>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include "mkfn.h"
24 #define LEN(a) ((sizeof(a) / sizeof((a)[0])))
26 static char *mkfn_scripts; /* filtered scripts */
27 static char *mkfn_langs; /* filtered languages */
28 static char *mkfn_subfont; /* filtered font */
29 static char *mkfn_trname; /* font troff name */
30 static char *mkfn_psname; /* font ps name */
31 static char *mkfn_path; /* font path */
32 int mkfn_res = 720; /* device resolution */
33 int mkfn_warn; /* warn about unsupported features */
34 int mkfn_kmin; /* minimum kerning value */
35 int mkfn_swid; /* space width */
36 int mkfn_special; /* special flag */
37 int mkfn_bbox; /* include bounding box */
38 int mkfn_noligs; /* suppress ligatures */
39 int mkfn_pos = 1; /* include glyph positions */
40 int mkfn_dry; /* generate no output */
42 /* OpenType specifies a specific feature order for different scripts */
43 static char *scriptorder[][2] = {
44 {"latn", "ccmp,liga,clig,dist,kern,mark,mkmk"},
45 {"cyrl", "ccmp,liga,clig,dist,kern,mark,mkmk"},
46 {"grek", "ccmp,liga,clig,dist,kern,mark,mkmk"},
47 {"armn", "ccmp,liga,clig,dist,kern,mark,mkmk"},
48 {"geor", "ccmp,liga,clig,dist,kern,mark,mkmk"},
49 {"runr", "ccmp,liga,clig,dist,kern,mark,mkmk"},
50 {"ogam", "ccmp,liga,clig,dist,kern,mark,mkmk"},
51 {"arab", "ccmp,isol,fina,medi,init,rlig,calt,liga,dlig,cswh,mset,curs,kern,mark,mkmk"},
52 {"bugi", "locl,ccmp,rlig,liga,clig,calt,kern,dist,mark,mkmk"},
53 {"hang", "ccmp,ljmo,vjmo,tjmo"},
54 {"hebr", "ccmp,dlig,kern,mark"},
55 {"bng2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
56 {"dev2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
57 {"gjr2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
58 {"gur2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
59 {"knd2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
60 {"mlym", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
61 {"ory2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
62 {"tml2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
63 {"tml2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
64 {"telu", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
65 {"java", "locl,pref,abvf,blwf,pstf,pres,abvs,blws,psts,ccmp,rlig,liga,clig,calt,kern,dist,mark,mkmk"},
66 {"khmr", "pref,blwf,abvf,pstf,pres,blws,abvs,psts,clig,dist,blwm,abvm,mkmk"},
67 {"lao ", "ccmp,kern,mark,mkmk"},
68 {"mym2", "locl,rphf,pref,blwf,pstf,pres,abvs,blws,psts,kern,dist,mark,mkmk"},
69 {"sinh", "locl,ccmp,akhn,rphf,vatu,pstf,pres,abvs,blws,psts,kern,dist,abvm,blwm"},
70 {"syrc", "stch,ccmp,isol,fina,fin2,fin3,medi,med2,init,rlig,calt,liga,dlig,kern,mark,mkmk"},
71 {"thaa", "kern,mark"},
72 {"thai", "ccmp,kern,mark,mkmk"},
73 {"tibt", "ccmp,abvs,blws,calt,liga,kern,abvm,blwm,mkmk"},
76 /* return 1 if the given script is to be included */
77 int mkfn_script(char *script, int nscripts)
79 /* fill mkfn_scripts (if unspecified) in the first call */
80 if (!mkfn_scripts) {
81 if (nscripts == 1 || !script)
82 return 1;
83 if (!strcmp("DFLT", script))
84 mkfn_scripts = "DFLT";
85 else
86 mkfn_scripts = "latn";
88 if (!strcmp("list", mkfn_scripts))
89 printf("%s\n", script ? script : "");
90 if (strchr(script, ' '))
91 *strchr(script, ' ') = '\0';
92 return !!strstr(mkfn_scripts, script);
95 /* return 1 if the given language is to be included */
96 int mkfn_lang(char *lang, int nlangs)
98 if (!mkfn_langs)
99 return 1;
100 if (!lang)
101 lang = "";
102 if (!strcmp("list", mkfn_langs))
103 printf("%s\n", lang);
104 if (strchr(lang, ' '))
105 *strchr(lang, ' ') = '\0';
106 return !!strstr(mkfn_langs, lang);
109 /* return 1 if the given font is to be included */
110 int mkfn_font(char *font)
112 static int idx; /* font index */
113 idx++;
114 if (!mkfn_subfont)
115 return idx == 1;
116 if (!strcmp("list", mkfn_subfont))
117 printf("%s\n", font);
118 if (mkfn_subfont[0] && isdigit((unsigned char) mkfn_subfont[0]))
119 if (atoi(mkfn_subfont) == idx)
120 return 1;
121 return !strcmp(mkfn_subfont, font);
124 /* return the rank of the given feature, for the current script */
125 int mkfn_featrank(char *scrp, char *feat)
127 static char **order;
128 int i;
129 if (!order || strcmp(scrp, order[0])) {
130 order = NULL;
131 for (i = 0; i < LEN(scriptorder); i++)
132 if (!strcmp(scrp, scriptorder[i][0]))
133 order = scriptorder[i];
135 if (order && strstr(order[1], feat))
136 return strstr(order[1], feat) - order[1];
137 return 1000;
140 void mkfn_header(char *fontname)
142 if (mkfn_dry)
143 return;
144 if (mkfn_trname)
145 printf("name %s\n", mkfn_trname);
146 if (mkfn_psname)
147 printf("fontname %s\n", mkfn_psname);
148 if (!mkfn_psname && fontname && fontname[0])
149 printf("fontname %s\n", fontname);
150 if (mkfn_path)
151 printf("fontpath %s\n", mkfn_path);
152 trfn_header();
153 if (mkfn_special)
154 printf("special\n");
155 trfn_cdefs();
158 int otf_read(void);
159 int afm_read(void);
161 static char *usage =
162 "Usage: mktrfn [options] <input >output\n"
163 "Options:\n"
164 " -a \tread an AFM file (default)\n"
165 " -o \tread a TTF or an OTF file\n"
166 " -s \tspecial font\n"
167 " -p name \toverride font postscript name\n"
168 " -t name \tset font troff name\n"
169 " -f path \tset font path\n"
170 " -r res \tset device resolution (720)\n"
171 " -k kmin \tspecify the minimum amount of kerning (0)\n"
172 " -b \tinclude glyph bounding boxes\n"
173 " -l \tsuppress the ligatures line\n"
174 " -n \tsuppress glyph positions\n"
175 " -S scrs \tcomma-separated list of scripts to include (list to list)\n"
176 " -L langs\tcomma-separated list of languages to include (list to list)\n"
177 " -F font \tfont name or index in a font collection (list to list)\n"
178 " -w \twarn about unsupported font features\n";
180 int main(int argc, char *argv[])
182 int afm = 1;
183 int i;
184 for (i = 1; i < argc && argv[i][0] == '-'; i++) {
185 switch (argv[i][1]) {
186 case 'a':
187 afm = 1;
188 break;
189 case 'b':
190 mkfn_bbox = 1;
191 break;
192 case 'f':
193 mkfn_path = argv[i][2] ? argv[i] + 2 : argv[++i];
194 break;
195 case 'F':
196 mkfn_subfont = argv[i][2] ? argv[i] + 2 : argv[++i];
197 mkfn_dry = !strcmp("list", mkfn_subfont);
198 break;
199 case 'k':
200 mkfn_kmin = atoi(argv[i][2] ? argv[i] + 2 : argv[++i]);
201 break;
202 case 'l':
203 mkfn_noligs = 1;
204 break;
205 case 'L':
206 mkfn_langs = argv[i][2] ? argv[i] + 2 : argv[++i];
207 mkfn_dry = !strcmp("list", mkfn_langs);
208 break;
209 case 'n':
210 mkfn_pos = 0;
211 break;
212 case 'o':
213 afm = 0;
214 break;
215 case 'p':
216 mkfn_psname = argv[i][2] ? argv[i] + 2 : argv[++i];
217 break;
218 case 'r':
219 mkfn_res = atoi(argv[i][2] ? argv[i] + 2 : argv[++i]);
220 break;
221 case 's':
222 mkfn_special = 1;
223 break;
224 case 'S':
225 mkfn_scripts = argv[i][2] ? argv[i] + 2 : argv[++i];
226 mkfn_dry = !strcmp("list", mkfn_scripts);
227 break;
228 case 't':
229 mkfn_trname = argv[i][2] ? argv[i] + 2 : argv[++i];
230 break;
231 case 'w':
232 mkfn_warn = 1;
233 break;
234 default:
235 fprintf(stderr, "%s", usage);
236 return 1;
239 trfn_init();
240 if ((afm ? afm_read() : otf_read())) {
241 fprintf(stderr, "neatmkfn: cannot parse the font\n");
242 trfn_done();
243 return 1;
245 trfn_done();
246 return 0;