]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - tools/tools/vt/fontcvt/fontcvt.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / tools / tools / vt / fontcvt / fontcvt.c
1 /*-
2  * Copyright (c) 2009 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Ed Schouten under sponsorship from the
6  * FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/endian.h>
34 #include <sys/param.h>
35 #include <sys/queue.h>
36
37 #include <assert.h>
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 static unsigned int width, wbytes, height;
44
45 struct glyph {
46         TAILQ_ENTRY(glyph)       g_list;
47         uint8_t                 *g_data;
48         unsigned int             g_index;
49 };
50
51 static TAILQ_HEAD(, glyph) glyph_list = TAILQ_HEAD_INITIALIZER(glyph_list);
52 static unsigned int glyph_total, glyph_normal, glyph_bold,
53     glyph_unique, glyph_dupe;
54
55 struct mapping {
56         TAILQ_ENTRY(mapping)     m_list;
57         unsigned int             m_char;
58         unsigned int             m_length;
59         struct glyph            *m_glyph;
60 };
61
62 TAILQ_HEAD(mapping_list, mapping);
63 static struct mapping_list mapping_list_normal =
64     TAILQ_HEAD_INITIALIZER(mapping_list_normal);
65 static struct mapping_list mapping_list_bold =
66     TAILQ_HEAD_INITIALIZER(mapping_list_bold);
67 static unsigned int mapping_total, mapping_normal, mapping_normal_folded,
68     mapping_bold, mapping_bold_folded, mapping_unique, mapping_dupe;
69
70 static void
71 usage(void)
72 {
73
74         fprintf(stderr,
75 "usage: fontcvt width height normal.bdf bold.bdf out.fnt\n");
76         exit(1);
77 }
78
79 static int
80 add_mapping(struct glyph *gl, unsigned int c, int bold)
81 {
82         struct mapping *mp;
83         struct mapping_list *ml;
84
85         mapping_total++;
86
87         if (bold) {
88                 int found = 0;
89
90                 TAILQ_FOREACH(mp, &mapping_list_normal, m_list) {
91                         if (mp->m_char < c)
92                                 continue;
93                         else if (mp->m_char > c)
94                                 break;
95                         found = 1;
96
97                         /*
98                          * No mapping is needed if it's equal to the
99                          * normal mapping.
100                          */
101                         if (mp->m_glyph == gl) {
102                                 mapping_dupe++;
103                                 return (0);
104                         }
105                 }
106
107                 if (!found) {
108                         fprintf(stderr,
109                             "Character %u not in normal font!\n", c);
110                         return (1);
111                 }
112         }
113
114         mp = malloc(sizeof *mp);
115         mp->m_char = c;
116         mp->m_glyph = gl;
117         mp->m_length = 0;
118
119         ml = bold ? &mapping_list_bold : &mapping_list_normal;
120         if (TAILQ_LAST(ml, mapping_list) != NULL &&
121             TAILQ_LAST(ml, mapping_list)->m_char >= c) {
122                 fprintf(stderr, "Bad ordering at character %u\n", c);
123                 return (1);
124         }
125         TAILQ_INSERT_TAIL(ml, mp, m_list);
126
127         if (bold)
128                 mapping_bold++;
129         else
130                 mapping_normal++;
131         mapping_unique++;
132
133         return (0);
134 }
135
136 static struct glyph *
137 add_glyph(const uint8_t *bytes, int bold, int fallback)
138 {
139         struct glyph *gl;
140
141         glyph_total++;
142         if (bold)
143                 glyph_bold++;
144         else
145                 glyph_normal++;
146
147         TAILQ_FOREACH(gl, &glyph_list, g_list) {
148                 if (memcmp(gl->g_data, bytes, wbytes * height) == 0) {
149                         glyph_dupe++;
150                         return (gl);
151                 }
152         }
153
154         gl = malloc(sizeof *gl);
155         gl->g_data = malloc(wbytes * height);
156         memcpy(gl->g_data, bytes, wbytes * height);
157         if (fallback)
158                 TAILQ_INSERT_HEAD(&glyph_list, gl, g_list);
159         else
160                 TAILQ_INSERT_TAIL(&glyph_list, gl, g_list);
161
162         glyph_unique++;
163         return (gl);
164 }
165
166 static int
167 parse_bdf(const char *filename, int bold __unused)
168 {
169         FILE *fp;
170         char *ln;
171         size_t length;
172         uint8_t bytes[wbytes * height];
173         unsigned int curchar = 0, i, line;
174         struct glyph *gl;
175
176         fp = fopen(filename, "r");
177         if (fp == NULL) {
178                 perror(filename);
179                 return (1);
180         }
181
182         while ((ln = fgetln(fp, &length)) != NULL) {
183                 ln[length - 1] = '\0';
184
185                 if (strncmp(ln, "ENCODING ", 9) == 0) {
186                         curchar = atoi(ln + 9);
187                 }
188
189                 if (strcmp(ln, "BITMAP") == 0) {
190                         for (i = 0; i < height; i++) {
191                                 if ((ln = fgetln(fp, &length)) == NULL) {
192                                         fprintf(stderr, "Unexpected EOF!\n");
193                                         return (1);
194                                 }
195                                 ln[length - 1] = '\0';
196                                 sscanf(ln, "%x", &line);
197                                 if (wbytes == 1) {
198                                         bytes[i] = line;
199                                 } else if (wbytes == 2) {
200                                         bytes[i * 2 + 0] = line >> 8;
201                                         bytes[i * 2 + 1] = line;
202                                 } else {
203                                         fprintf(stderr,
204                                             "Unsupported wbytes!\n");
205                                         return (1);
206                                 }
207                         }
208
209                         /* Prevent adding two glyphs for 0xFFFD */
210                         if (curchar == 0xFFFD) {
211                                 if (!bold)
212                                         gl = add_glyph(bytes, bold, 1);
213                         } else if (curchar >= 0x20) {
214                                 gl = add_glyph(bytes, bold, 0);
215                                 if (add_mapping(gl, curchar, bold) != 0)
216                                         return (1);
217                         }
218                 }
219         }
220
221         return (0);
222 }
223
224 static void
225 number_glyphs(void)
226 {
227         struct glyph *gl;
228         unsigned int idx = 0;
229
230         TAILQ_FOREACH(gl, &glyph_list, g_list)
231                 gl->g_index = idx++;
232 }
233
234 static void
235 write_glyphs(FILE *fp)
236 {
237         struct glyph *gl;
238
239         TAILQ_FOREACH(gl, &glyph_list, g_list)
240                 fwrite(gl->g_data, wbytes * height, 1, fp);
241 }
242
243 static void
244 fold_mappings(int bold)
245 {
246         struct mapping_list *ml;
247         struct mapping *mn, *mp, *mbase;
248
249         if (bold)
250                 ml = &mapping_list_bold;
251         else
252                 ml = &mapping_list_normal;
253
254         mp = mbase = TAILQ_FIRST(ml);
255         for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) {
256                 mn = TAILQ_NEXT(mp, m_list);
257                 if (mn != NULL && mn->m_char == mp->m_char + 1 &&
258                     mn->m_glyph->g_index == mp->m_glyph->g_index + 1)
259                         continue;
260                 mbase->m_length = mp->m_char - mbase->m_char + 1;
261                 mbase = mp = mn;
262                 if (bold)
263                         mapping_bold_folded++;
264                 else
265                         mapping_normal_folded++;
266         }
267 }
268
269 struct file_mapping {
270         uint32_t        source;
271         uint16_t        destination;
272         uint16_t        length;
273 } __packed;
274
275 static void
276 write_mappings(FILE *fp, int bold)
277 {
278         struct mapping_list *ml;
279         struct mapping *mp;
280         struct file_mapping fm;
281         unsigned int i = 0, j = 0;
282
283         if (bold)
284                 ml = &mapping_list_bold;
285         else
286                 ml = &mapping_list_normal;
287
288         TAILQ_FOREACH(mp, ml, m_list) {
289                 j++;
290                 if (mp->m_length > 0) {
291                         i += mp->m_length;
292                         fm.source = htobe32(mp->m_char);
293                         fm.destination = htobe16(mp->m_glyph->g_index);
294                         fm.length = htobe16(mp->m_length - 1);
295                         fwrite(&fm, sizeof fm, 1, fp);
296                 }
297         }
298         assert(i == j);
299 }
300
301 struct file_header {
302         uint8_t         magic[8];
303         uint8_t         width;
304         uint8_t         height;
305         uint16_t        nglyphs;
306         uint16_t        nmappings_normal;
307         uint16_t        nmappings_bold;
308 } __packed;
309
310 static int
311 write_fnt(const char *filename)
312 {
313         FILE *fp;
314         struct file_header fh = {
315                 .magic = "VFNT 1.0",
316         };
317
318         fp = fopen(filename, "wb");
319         if (fp == NULL) {
320                 perror(filename);
321                 return (1);
322         }
323
324         fh.width = width;
325         fh.height = height;
326         fh.nglyphs = htobe16(glyph_unique);
327         fh.nmappings_normal = htobe16(mapping_normal_folded);
328         fh.nmappings_bold = htobe16(mapping_bold_folded);
329         fwrite(&fh, sizeof fh, 1, fp);
330         
331         write_glyphs(fp);
332         write_mappings(fp, 0);
333         write_mappings(fp, 1);
334
335         return (0);
336 }
337
338 int
339 main(int argc, char *argv[])
340 {
341
342         assert(sizeof(struct file_header) == 16);
343         assert(sizeof(struct file_mapping) == 8);
344
345         if (argc != 6)
346                 usage();
347         
348         width = atoi(argv[1]);
349         wbytes = howmany(width, 8);
350         height = atoi(argv[2]);
351
352         if (parse_bdf(argv[3], 0) != 0)
353                 return (1);
354         if (parse_bdf(argv[4], 1) != 0)
355                 return (1);
356         number_glyphs();
357         fold_mappings(0);
358         fold_mappings(1);
359         if (write_fnt(argv[5]) != 0)
360                 return (1);
361         
362         printf(
363 "Statistics:\n"
364 "- glyph_total:           %5u\n"
365 "- glyph_normal:          %5u\n"
366 "- glyph_bold:            %5u\n"
367 "- glyph_unique:          %5u\n"
368 "- glyph_dupe:            %5u\n"
369 "- mapping_total:         %5u\n"
370 "- mapping_normal:        %5u\n"
371 "- mapping_normal_folded: %5u\n"
372 "- mapping_bold:          %5u\n"
373 "- mapping_bold_folded:   %5u\n"
374 "- mapping_unique:        %5u\n"
375 "- mapping_dupe:          %5u\n",
376             glyph_total,
377             glyph_normal, glyph_bold,
378             glyph_unique, glyph_dupe,
379             mapping_total,
380             mapping_normal, mapping_normal_folded,
381             mapping_bold, mapping_bold_folded,
382             mapping_unique, mapping_dupe);
383         
384         return (0);
385 }