2 * kmscon - Generate Unifont data files
4 * Copyright (c) 2012 Ted Kotz <ted@kotz.us>
5 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files
9 * (the "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 * This converts the hex-encoded Unifont data into a C-array that is used by the
30 * unifont-font-renderer.
39 #define MAX_DATA_SIZE 512
41 struct unifont_glyph {
42 struct unifont_glyph *next;
45 char data[MAX_DATA_SIZE];
48 static uint8_t hex_val(char c)
50 if (c >= '0' && c <= '9')
52 else if (c >= 'a' && c <= 'f')
54 else if (c >= 'A' && c <= 'F')
57 fprintf(stderr, "genunifont: invalid hex-code %c\n", c);
61 static void print_data_row(FILE *out, char c)
63 static const char *line_map[16] = {
64 "0x00, 0x00, 0x00, 0x00,",
65 "0x00, 0x00, 0x00, 0xff,",
66 "0x00, 0x00, 0xff, 0x00,",
67 "0x00, 0x00, 0xff, 0xff,",
68 "0x00, 0xff, 0x00, 0x00,",
69 "0x00, 0xff, 0x00, 0xff,",
70 "0x00, 0xff, 0xff, 0x00,",
71 "0x00, 0xff, 0xff, 0xff,",
72 "0xff, 0x00, 0x00, 0x00,",
73 "0xff, 0x00, 0x00, 0xff,",
74 "0xff, 0x00, 0xff, 0x00,",
75 "0xff, 0x00, 0xff, 0xff,",
76 "0xff, 0xff, 0x00, 0x00,",
77 "0xff, 0xff, 0x00, 0xff,",
78 "0xff, 0xff, 0xff, 0x00,",
79 "0xff, 0xff, 0xff, 0xff,",
85 fputs(line_map[idx], out);
87 fprintf(stderr, "genunifont: invalid value %c\n", c);
88 fputs(line_map[0], out);
92 static void print_unifont_glyph(FILE *out, const struct unifont_glyph *g)
105 fprintf(stderr, "genunifont: invalid data size");
109 fprintf(out, "\t{ /* %d 0x%x */\n"
112 "\t\t\t.width = %d,\n"
113 "\t\t\t.height = 16,\n"
114 "\t\t\t.stride = %d,\n"
115 "\t\t\t.format = UTERM_FORMAT_GREY,\n"
116 "\t\t\t.data = (uint8_t[]){\n",
117 g->codepoint, g->codepoint, 1,
118 width * 4, width * 4);
120 for (i = 0; i < g->len; ++i) {
121 fprintf(out, "\t\t\t\t");
122 print_data_row(out, g->data[i]);
126 fprintf(out, "\t\t\t},\n\t\t},\n\t},\n");
129 static int build_unifont_glyph(struct unifont_glyph *g, const char *buf)
134 while (*buf && *buf != ':') {
136 val += hex_val(*buf++);
140 fprintf(stderr, "genunifont: invalid file format\n");
146 while (*buf && *buf != '\n' && g->len < MAX_DATA_SIZE) {
147 g->data[g->len] = *buf++;
154 static void write_name(FILE *out, const char *name)
159 for (i = 0; i < len; ++i) {
160 if ((name[i] >= 'A' && name[i] <= 'Z') ||
161 (name[i] >= 'a' && name[i] <= 'z') ||
162 (name[i] >= '0' && name[i] <= '9'))
163 fwrite(&name[i], 1, 1, out);
165 fwrite("_", 1, 1, out);
169 static int parse_single_file(FILE *out, FILE *in, const char *varname)
171 struct unifont_glyph replacement = {
174 .data = "0000007E665A5A7A76767E76767E0000"
176 static const char c0[] = "const struct kmscon_glyph kmscon_";
177 static const char c1[] = "_glyphs[] = {\n";
178 static const char c2[] = "};\n\nconst size_t kmscon_";
179 static const char c3[] = "_len =\n\tsizeof(kmscon_";
180 static const char c4[] = "_glyphs) /\n\tsizeof(*kmscon_";
181 static const char c5[] = "_glyphs);\n";
182 char buf[MAX_DATA_SIZE];
183 struct unifont_glyph *g, *iter, *list, *last;
185 unsigned long status_max, status_cur;
186 unsigned long perc_prev, perc_now;
188 if (fseek(in, 0, SEEK_END) != 0) {
189 fprintf(stderr, "genunifont: cannot seek: %m\n");
193 status_max = ftell(in);
194 if (status_max < 0) {
195 fprintf(stderr, "genunifont: cannot ftell: %m\n");
199 if (status_max < 1) {
200 fprintf(stderr, "genunifont: empty file\n");
211 fprintf(stderr, "Finished: %3ld%%", perc_now);
213 while (fgets(buf, sizeof(buf) - 1, in) != NULL) {
214 perc_now = status_cur * 100 / status_max;
215 if (perc_now > perc_prev) {
216 perc_prev = perc_now;
217 fprintf(stderr, "\b\b\b\b%3ld%%", perc_now);
219 status_cur += strlen(buf);
224 g = malloc(sizeof(*g));
226 fprintf(stderr, "genunifont: out of memory\n");
229 memset(g, 0, sizeof(*g));
231 ret = build_unifont_glyph(g, buf);
237 if (!list || list->codepoint > g->codepoint) {
242 } else if (list->codepoint == g->codepoint) {
243 fprintf(stderr, "glyph %d used twice\n",
247 if (last->codepoint < g->codepoint) {
252 if (iter->next->codepoint >= g->codepoint)
259 if (iter->next->codepoint == g->codepoint) {
260 fprintf(stderr, "glyph %d used twice\n",
264 g->next = iter->next;
274 fprintf(stderr, "\n");
276 fwrite(c0, sizeof(c0) - 1, 1, out);
277 write_name(out, varname);
278 fwrite(c1, sizeof(c1) - 1, 1, out);
285 while (num++ < iter->codepoint)
286 print_unifont_glyph(out, &replacement);
288 print_unifont_glyph(out, iter);
292 fwrite(c2, sizeof(c2) - 1, 1, out);
293 write_name(out, varname);
294 fwrite(c3, sizeof(c3) - 1, 1, out);
295 write_name(out, varname);
296 fwrite(c4, sizeof(c4) - 1, 1, out);
297 write_name(out, varname);
298 fwrite(c5, sizeof(c5) - 1, 1, out);
303 static const char *get_basename(const char *path)
307 res = strrchr(path, '/');
314 int main(int argc, char **argv)
318 static const char c0[] = "/* This file was generated "
319 "by genunifont.c */\n\n"
320 "#include <stdint.h>\n"
321 "#include <stdlib.h>\n"
322 "#include \"font.h\"\n\n";
323 int ret = EXIT_FAILURE;
326 fprintf(stderr, "genunifont: use ./genunifont <outputfile> [<inputfiles> ...]\n");
330 out = fopen(argv[1], "wb");
332 fprintf(stderr, "genunifont: cannot open output %s: %m\n",
337 fwrite(c0, sizeof(c0) - 1, 1, out);
338 for (i = 2; i < argc; ++i) {
339 fprintf(stderr, "genunifont: parsing input %s\n", argv[i]);
340 in = fopen(argv[i], "rb");
342 fprintf(stderr, "genunifont: cannot open %s: %m\n",
346 ret = parse_single_file(out, in, get_basename(argv[i]));
348 fprintf(stderr, "genunifont: parsing input %s failed",