wlt: fix shl_hook API changes
[platform/upstream/kmscon.git] / src / genunifont.c
1 /*
2  * kmscon - Generate Unifont data files
3  *
4  * Copyright (c) 2012 Ted Kotz <ted@kotz.us>
5  * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6  *
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:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
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.
25  */
26
27 /*
28  * Unifont Generator
29  * This converts the hex-encoded Unifont data into a C-array that is used by the
30  * unifont-font-renderer.
31  */
32
33 #include <errno.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #define MAX_DATA_SIZE 512
40
41 struct unifont_glyph {
42         struct unifont_glyph *next;
43         uint32_t codepoint;
44         uint8_t len;
45         char data[MAX_DATA_SIZE];
46 };
47
48 static uint8_t hex_val(char c)
49 {
50         if (c >= '0' && c <= '9')
51                 return c - '0';
52         else if (c >= 'a' && c <= 'f')
53                 return c - 'a' + 10;
54         else if (c >= 'A' && c <= 'F')
55                 return c - 'A' + 10;
56
57         fprintf(stderr, "genunifont: invalid hex-code %c\n", c);
58         return 0;
59 }
60
61 static void print_data_row(FILE *out, char c)
62 {
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,",
80         };
81         uint8_t idx;
82
83         idx = hex_val(c);
84         if (idx < 16) {
85                 fputs(line_map[idx], out);
86         } else {
87                 fprintf(stderr, "genunifont: invalid value %c\n", c);
88                 fputs(line_map[0], out);
89         }
90 }
91
92 static void print_unifont_glyph(FILE *out, const struct unifont_glyph *g)
93 {
94         int width;
95         size_t i;
96
97         switch (g->len) {
98         case 64:
99                 width = 4;
100                 break;
101         case 32:
102                 width = 2;
103                 break;
104         default:
105                 fprintf(stderr, "genunifont: invalid data size");
106                 return;
107         }
108
109         fprintf(out, "\t{ /* %d 0x%x */\n"
110                      "\t\t.width = %d,\n"
111                      "\t\t.buf = {\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);
119
120         for (i = 0; i < g->len; ++i) {
121                 fprintf(out, "\t\t\t\t");
122                 print_data_row(out, g->data[i]);
123                 fprintf(out, "\n");
124         }
125
126         fprintf(out, "\t\t\t},\n\t\t},\n\t},\n");
127 }
128
129 static int build_unifont_glyph(struct unifont_glyph *g, const char *buf)
130 {
131         int val;
132
133         val = 0;
134         while (*buf && *buf != ':') {
135                 val <<= 4;
136                 val += hex_val(*buf++);
137         }
138
139         if (*buf++ != ':') {
140                 fprintf(stderr, "genunifont: invalid file format\n");
141                 return -EFAULT;
142         }
143
144         g->codepoint = val;
145         g->len = 0;
146         while (*buf && *buf != '\n' && g->len < MAX_DATA_SIZE) {
147                 g->data[g->len] = *buf++;
148                 ++g->len;
149         }
150
151         return 0;
152 }
153
154 static void write_name(FILE *out, const char *name)
155 {
156         size_t i, len;
157
158         len = strlen(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);
164                 else
165                         fwrite("_", 1, 1, out);
166         }
167 }
168
169 static int parse_single_file(FILE *out, FILE *in, const char *varname)
170 {
171         struct unifont_glyph replacement = {
172                 .codepoint = 0,
173                 .len = 32,
174                 .data = "0000007E665A5A7A76767E76767E0000"
175         };
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;
184         int ret, num;
185         unsigned long status_max, status_cur;
186         unsigned long perc_prev, perc_now;
187
188         if (fseek(in, 0, SEEK_END) != 0) {
189                 fprintf(stderr, "genunifont: cannot seek: %m\n");
190                 return -EFAULT;
191         }
192
193         status_max = ftell(in);
194         if (status_max < 0) {
195                 fprintf(stderr, "genunifont: cannot ftell: %m\n");
196                 return -EFAULT;
197         }
198
199         if (status_max < 1) {
200                 fprintf(stderr, "genunifont: empty file\n");
201                 return -EFAULT;
202         }
203
204         rewind(in);
205         list = NULL;
206         last = NULL;
207         status_cur = 0;
208         perc_prev = 0;
209         perc_now = 0;
210
211         fprintf(stderr, "Finished: %3ld%%", perc_now);
212
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);
218                 }
219                 status_cur += strlen(buf);
220
221                 if (buf[0] == '#')
222                         continue;
223
224                 g = malloc(sizeof(*g));
225                 if (!g) {
226                         fprintf(stderr, "genunifont: out of memory\n");
227                         return -ENOMEM;
228                 }
229                 memset(g, 0, sizeof(*g));
230
231                 ret = build_unifont_glyph(g, buf);
232                 if (ret) {
233                         free(g);
234                         continue;
235                 }
236
237                 if (!list || list->codepoint > g->codepoint) {
238                         g->next = list;
239                         list = g;
240                         if (!last)
241                                 last = g;
242                 } else if (list->codepoint == g->codepoint) {
243                         fprintf(stderr, "glyph %d used twice\n",
244                                 g->codepoint);
245                         free(g);
246                 } else {
247                         if (last->codepoint < g->codepoint) {
248                                 iter = last;
249                         } else {
250                                 iter = list;
251                                 while (iter->next) {
252                                         if (iter->next->codepoint >= g->codepoint)
253                                                 break;
254                                         iter = iter->next;
255                                 }
256                         }
257
258                         if (iter->next) {
259                                 if (iter->next->codepoint == g->codepoint) {
260                                         fprintf(stderr, "glyph %d used twice\n",
261                                                 g->codepoint);
262                                         free(g);
263                                 } else {
264                                         g->next = iter->next;
265                                         iter->next = g;
266                                 }
267                         } else {
268                                 iter->next = g;
269                                 last = g;
270                         }
271                 }
272         }
273
274         fprintf(stderr, "\n");
275
276         fwrite(c0, sizeof(c0) - 1, 1, out);
277         write_name(out, varname);
278         fwrite(c1, sizeof(c1) - 1, 1, out);
279
280         num = 0;
281         while (list) {
282                 iter = list;
283                 list = iter->next;
284
285                 while (num++ < iter->codepoint)
286                         print_unifont_glyph(out, &replacement);
287
288                 print_unifont_glyph(out, iter);
289                 free(iter);
290         }
291
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);
299
300         return 0;
301 }
302
303 static const char *get_basename(const char *path)
304 {
305         const char *res;
306
307         res = strrchr(path, '/');
308         if (!res || !*++res)
309                 return path;
310
311         return res;
312 }
313
314 int main(int argc, char **argv)
315 {
316         FILE *out, *in;
317         size_t i;
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;
324
325         if (argc < 2) {
326                 fprintf(stderr, "genunifont: use ./genunifont <outputfile> [<inputfiles> ...]\n");
327                 goto err_out;
328         }
329
330         out = fopen(argv[1], "wb");
331         if (!out) {
332                 fprintf(stderr, "genunifont: cannot open output %s: %m\n",
333                         argv[1]);
334                 goto err_out;
335         }
336
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");
341                 if (!in) {
342                         fprintf(stderr, "genunifont: cannot open %s: %m\n",
343                                 argv[i]);
344                         continue;
345                 }
346                 ret = parse_single_file(out, in, get_basename(argv[i]));
347                 if (ret)
348                         fprintf(stderr, "genunifont: parsing input %s failed",
349                                 argv[i]);
350                 fclose(in);
351         }
352
353         ret = EXIT_SUCCESS;
354
355         fclose(out);
356 err_out:
357         return ret;
358 }