uvtd: vt: implement VT_GETMODE/SETMODE ioctl state-tracking
[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-2013 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_unifont_glyph(FILE *out, const struct unifont_glyph *g)
62 {
63         size_t i;
64         uint8_t val;
65
66         switch (g->len) {
67         case 32:
68         case 64:
69                 break;
70         default:
71                 fprintf(stderr, "genunifont: invalid data size %d for %x",
72                         g->len, g->codepoint);
73                 return;
74         }
75
76         fprintf(out, "%c", g->len / 2);
77         for (i = 0; i < g->len; i += 2) {
78                 val = hex_val(g->data[i]) << 4;
79                 val |= hex_val(g->data[i + 1]);
80                 fprintf(out, "%c", val);
81         }
82         for ( ; i < 64; i += 2)
83                 fprintf(out, "%c", 0);
84 }
85
86 static int build_unifont_glyph(struct unifont_glyph *g, const char *buf)
87 {
88         int val;
89         const char *orig = buf;
90
91         val = 0;
92         while (*buf && *buf != ':') {
93                 val <<= 4;
94                 val += hex_val(*buf++);
95         }
96
97         if (*buf++ != ':') {
98                 fprintf(stderr, "genunifont: invalid file format: %s\n", orig);
99                 return -EFAULT;
100         }
101
102         g->codepoint = val;
103         g->len = 0;
104         while (*buf && *buf != '\n' && g->len < MAX_DATA_SIZE) {
105                 g->data[g->len] = *buf++;
106                 ++g->len;
107         }
108
109         return 0;
110 }
111
112 static int parse_single_file(FILE *out, FILE *in)
113 {
114         static const struct unifont_glyph replacement = {
115                 .codepoint = 0,
116                 .len = 32,
117                 .data = "0000007E665A5A7A76767E76767E0000"
118         };
119         char buf[MAX_DATA_SIZE];
120         struct unifont_glyph *g, **iter, *list, *last;
121         int ret, num;
122         unsigned long status_max, status_cur;
123         unsigned long perc_prev, perc_now;
124
125         if (fseek(in, 0, SEEK_END) != 0) {
126                 fprintf(stderr, "genunifont: cannot seek: %m\n");
127                 return -EFAULT;
128         }
129
130         status_max = ftell(in);
131         if (status_max < 0) {
132                 fprintf(stderr, "genunifont: cannot ftell: %m\n");
133                 return -EFAULT;
134         }
135
136         if (status_max < 1) {
137                 fprintf(stderr, "genunifont: empty file\n");
138                 return -EFAULT;
139         }
140
141         rewind(in);
142         list = NULL;
143         last = NULL;
144         status_cur = 0;
145         perc_prev = 0;
146         perc_now = 0;
147
148         fprintf(stderr, "Finished: %3ld%%", perc_now);
149
150         while (fgets(buf, sizeof(buf) - 1, in) != NULL) {
151                 /* print status update in percent */
152                 perc_now = status_cur * 100 / status_max;
153                 if (perc_now > perc_prev) {
154                         perc_prev = perc_now;
155                         fprintf(stderr, "\b\b\b\b%3ld%%", perc_now);
156                         fflush(stderr);
157                 }
158                 status_cur += strlen(buf);
159
160                 /* ignore comments */
161                 if (buf[0] == '#')
162                         continue;
163
164                 /* allocate new glyph */
165                 g = malloc(sizeof(*g));
166                 if (!g) {
167                         fprintf(stderr, "genunifont: out of memory\n");
168                         return -ENOMEM;
169                 }
170                 memset(g, 0, sizeof(*g));
171
172                 /* read glyph data */
173                 ret = build_unifont_glyph(g, buf);
174                 if (ret) {
175                         free(g);
176                         return ret;
177                 }
178
179                 /* find glyph position */
180                 if (last && last->codepoint < g->codepoint) {
181                         iter = &last->next;
182                 } else {
183                         iter = &list;
184                         while (*iter && (*iter)->codepoint < g->codepoint)
185                                 iter = &(*iter)->next;
186
187                         if (*iter && (*iter)->codepoint == g->codepoint) {
188                                 fprintf(stderr, "glyph %d used twice\n",
189                                         g->codepoint);
190                                 free(g);
191                                 return -EFAULT;
192                         }
193                 }
194
195                 /* insert glyph into single-linked list */
196                 g->next = *iter;
197                 if (!*iter)
198                         last = g;
199                 *iter = g;
200         }
201
202         fprintf(stderr, "\b\b\b\b%3d%%\n", 100);
203
204         /* print all glyph-data to output file */
205         num = 0;
206         while (list) {
207                 g = list;
208                 list = g->next;
209
210                 /* print replacements if glyphs are missing */
211                 while (num++ < g->codepoint)
212                         print_unifont_glyph(out, &replacement);
213
214                 print_unifont_glyph(out, g);
215                 free(g);
216         }
217
218         return 0;
219 }
220
221 int main(int argc, char **argv)
222 {
223         FILE *out, *in;
224         int ret;
225
226         if (argc < 3) {
227                 fprintf(stderr, "genunifont: use ./genunifont <outputfile> <inputfiles>\n");
228                 ret = EXIT_FAILURE;
229                 goto err_out;
230         }
231
232         out = fopen(argv[1], "wb");
233         if (!out) {
234                 fprintf(stderr, "genunifont: cannot open output %s: %m\n",
235                         argv[1]);
236                 ret = EXIT_FAILURE;
237                 goto err_out;
238         }
239
240         fprintf(stderr, "genunifont: parsing input %s\n", argv[2]);
241         in = fopen(argv[2], "rb");
242         if (!in) {
243                 fprintf(stderr, "genunifont: cannot open %s: %m\n",
244                         argv[2]);
245                 ret = EXIT_FAILURE;
246         } else {
247                 ret = parse_single_file(out, in);
248                 if (ret) {
249                         fprintf(stderr, "genunifont: parsing input %s failed",
250                                 argv[2]);
251                         ret = EXIT_FAILURE;
252                 } else {
253                         ret = EXIT_SUCCESS;
254                 }
255                 fclose(in);
256         }
257
258
259         fclose(out);
260 err_out:
261         return ret;
262 }