2 * Copyright (c) 2009, 2014 The FreeBSD Foundation
5 * This software was developed by Ed Schouten under sponsorship from the
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/queue.h>
46 #define VFNT_MAP_NORMAL 0
47 #define VFNT_MAP_NORMAL_RH 1
48 #define VFNT_MAP_BOLD 2
49 #define VFNT_MAP_BOLD_RH 3
51 extern size_t lz4_compress(void *, void *, size_t, size_t, int);
53 static unsigned int width
= 8, wbytes
, height
= 16;
56 unsigned int width
; /* pixels */
58 int x
; /* lower left corner x */
59 int y
; /* lower left corner y */
62 static struct bbox bbox
; /* font bounding box */
63 static int font_ascent
; /* pixels above baseline */
64 static int font_descent
; /* pixels below baseline */
65 static unsigned int default_char
= 0xFFFD;
68 TAILQ_ENTRY(glyph
) g_list
;
69 SLIST_ENTRY(glyph
) g_hash
;
74 #define FONTCVT_NHASH 4096
75 TAILQ_HEAD(glyph_list
, glyph
);
76 static SLIST_HEAD(, glyph
) glyph_hash
[FONTCVT_NHASH
];
77 static struct glyph_list glyphs
[VFNT_MAPS
] = {
78 TAILQ_HEAD_INITIALIZER(glyphs
[0]),
79 TAILQ_HEAD_INITIALIZER(glyphs
[1]),
80 TAILQ_HEAD_INITIALIZER(glyphs
[2]),
81 TAILQ_HEAD_INITIALIZER(glyphs
[3]),
83 static unsigned int glyph_total
, glyph_count
[4], glyph_unique
, glyph_dupe
;
86 TAILQ_ENTRY(mapping
) m_list
;
88 unsigned int m_length
;
89 struct glyph
*m_glyph
;
92 TAILQ_HEAD(mapping_list
, mapping
);
93 static struct mapping_list maps
[VFNT_MAPS
] = {
94 TAILQ_HEAD_INITIALIZER(maps
[0]),
95 TAILQ_HEAD_INITIALIZER(maps
[1]),
96 TAILQ_HEAD_INITIALIZER(maps
[2]),
97 TAILQ_HEAD_INITIALIZER(maps
[3]),
99 static unsigned int mapping_total
, map_count
[4], map_folded_count
[4],
100 mapping_unique
, mapping_dupe
;
103 VT_FONT
, /* default */
104 VT_C_SOURCE
, /* C source for built in fonts */
105 VT_C_COMPRESSED
/* C source with compressed font data */
114 * Compressed font glyph list. To be used with boot loader, we need to have
115 * ascii set and box drawing chars.
117 static struct whitelist c_list
[] = {
118 { .c
= 0, .len
= 0 }, /* deault char */
119 { .c
= 0x20, .len
= 0x5f },
120 { .c
= 0x2500, .len
= 0 }, /* single frame */
121 { .c
= 0x2502, .len
= 0 },
122 { .c
= 0x250c, .len
= 0 },
123 { .c
= 0x2510, .len
= 0 },
124 { .c
= 0x2514, .len
= 0 },
125 { .c
= 0x2518, .len
= 0 },
126 { .c
= 0x2550, .len
= 1 }, /* double frame */
127 { .c
= 0x2554, .len
= 0 },
128 { .c
= 0x2557, .len
= 0 },
129 { .c
= 0x255a, .len
= 0 },
130 { .c
= 0x255d, .len
= 0 },
134 * Uncompressed source. For x86 we need cp437 so the vga text mode
135 * can program font into the vga card.
137 static struct whitelist s_list
[] = {
138 { .c
= 0, .len
= 0 }, /* deault char */
139 { .c
= 0x20, .len
= 0x5f }, /* ascii set */
140 { .c
= 0xA0, .len
= 0x5f }, /* latin 1 */
141 { .c
= 0x0192, .len
= 0 },
142 { .c
= 0x0332, .len
= 0 }, /* composing lower line */
143 { .c
= 0x0393, .len
= 0 },
144 { .c
= 0x0398, .len
= 0 },
145 { .c
= 0x03A3, .len
= 0 },
146 { .c
= 0x03A6, .len
= 0 },
147 { .c
= 0x03A9, .len
= 0 },
148 { .c
= 0x03B1, .len
= 1 },
149 { .c
= 0x03B4, .len
= 0 },
150 { .c
= 0x03C0, .len
= 0 },
151 { .c
= 0x03C3, .len
= 0 },
152 { .c
= 0x03C4, .len
= 0 },
153 { .c
= 0x207F, .len
= 0 },
154 { .c
= 0x20A7, .len
= 0 },
155 { .c
= 0x2205, .len
= 0 },
156 { .c
= 0x220A, .len
= 0 },
157 { .c
= 0x2219, .len
= 1 },
158 { .c
= 0x221E, .len
= 0 },
159 { .c
= 0x2229, .len
= 0 },
160 { .c
= 0x2248, .len
= 0 },
161 { .c
= 0x2261, .len
= 0 },
162 { .c
= 0x2264, .len
= 1 },
163 { .c
= 0x2310, .len
= 0 },
164 { .c
= 0x2320, .len
= 1 },
165 { .c
= 0x2500, .len
= 0 },
166 { .c
= 0x2502, .len
= 0 },
167 { .c
= 0x250C, .len
= 0 },
168 { .c
= 0x2510, .len
= 0 },
169 { .c
= 0x2514, .len
= 0 },
170 { .c
= 0x2518, .len
= 0 },
171 { .c
= 0x251C, .len
= 0 },
172 { .c
= 0x2524, .len
= 0 },
173 { .c
= 0x252C, .len
= 0 },
174 { .c
= 0x2534, .len
= 0 },
175 { .c
= 0x253C, .len
= 0 },
176 { .c
= 0x2550, .len
= 0x1c },
177 { .c
= 0x2580, .len
= 0 },
178 { .c
= 0x2584, .len
= 0 },
179 { .c
= 0x2588, .len
= 0 },
180 { .c
= 0x258C, .len
= 0 },
181 { .c
= 0x2590, .len
= 3 },
182 { .c
= 0x25A0, .len
= 0 },
186 enum output_format format
= VT_FONT
;
187 /* Type for write callback. */
188 typedef size_t (*vt_write
)(const void *, size_t, size_t, FILE *);
189 uint8_t *uncompressed
;
195 (void) fprintf(stderr
, "usage:\tvtfontcvt "
196 "[-n] [-f font|source|compressed-source] [-w width] "
197 "[-h height]\n\t[-v] -o outfile normal.bdf [bold.bdf]\n");
206 if ((m
= malloc(size
)) == NULL
)
207 errx(1, "memory allocation failure");
212 add_mapping(struct glyph
*gl
, unsigned int c
, unsigned int map_idx
)
214 struct mapping
*mp
, *v
;
215 struct mapping_list
*ml
;
219 mp
= xmalloc(sizeof (*mp
));
225 if (TAILQ_LAST(ml
, mapping_list
) != NULL
&&
226 TAILQ_LAST(ml
, mapping_list
)->m_char
>= c
) {
227 TAILQ_FOREACH_REVERSE(v
, ml
, mapping_list
, m_list
) {
229 TAILQ_INSERT_AFTER(ml
, v
, mp
, m_list
);
231 } else if (v
->m_char
== c
)
232 errx(1, "Bad ordering at character %u", c
);
235 TAILQ_INSERT_TAIL(ml
, mp
, m_list
);
237 map_count
[map_idx
]++;
244 dedup_mapping(unsigned int map_idx
)
246 struct mapping
*mp_bold
, *mp_normal
;
247 unsigned normal_map_idx
= map_idx
- VFNT_MAP_BOLD
;
249 assert(map_idx
== VFNT_MAP_BOLD
|| map_idx
== VFNT_MAP_BOLD_RH
);
250 mp_normal
= TAILQ_FIRST(&maps
[normal_map_idx
]);
251 TAILQ_FOREACH(mp_bold
, &maps
[map_idx
], m_list
) {
252 while (mp_normal
->m_char
< mp_bold
->m_char
)
253 mp_normal
= TAILQ_NEXT(mp_normal
, m_list
);
254 if (mp_bold
->m_char
!= mp_normal
->m_char
)
255 errx(1, "Character %u not in normal font!",
257 if (mp_bold
->m_glyph
!= mp_normal
->m_glyph
)
260 /* No mapping is needed if it's equal to the normal mapping. */
261 TAILQ_REMOVE(&maps
[map_idx
], mp_bold
, m_list
);
268 static struct glyph
*
269 add_glyph(const uint8_t *bytes
, unsigned int map_idx
, int fallback
)
275 glyph_count
[map_idx
]++;
277 hash
= fnv_32_buf(bytes
, wbytes
* height
, FNV1_32_INIT
) % FONTCVT_NHASH
;
278 SLIST_FOREACH(gl
, &glyph_hash
[hash
], g_hash
) {
279 if (memcmp(gl
->g_data
, bytes
, wbytes
* height
) == 0) {
285 gl
= xmalloc(sizeof (*gl
));
286 gl
->g_data
= xmalloc(wbytes
* height
);
287 memcpy(gl
->g_data
, bytes
, wbytes
* height
);
289 TAILQ_INSERT_HEAD(&glyphs
[map_idx
], gl
, g_list
);
291 TAILQ_INSERT_TAIL(&glyphs
[map_idx
], gl
, g_list
);
292 SLIST_INSERT_HEAD(&glyph_hash
[hash
], gl
, g_hash
);
299 check_whitelist(unsigned c
)
301 struct whitelist
*w
= NULL
;
307 if (format
== VT_C_SOURCE
) {
309 n
= sizeof (s_list
) / sizeof (s_list
[0]);
311 if (format
== VT_C_COMPRESSED
) {
313 n
= sizeof (c_list
) / sizeof (c_list
[0]);
317 for (i
= 0; i
< n
; i
++) {
318 if (c
>= w
[i
].c
&& c
<= w
[i
].c
+ w
[i
].len
)
325 add_char(unsigned curchar
, unsigned map_idx
, uint8_t *bytes
, uint8_t *bytes_r
)
329 /* Prevent adding two glyphs for default_char */
330 if (curchar
== default_char
) {
331 if (map_idx
< VFNT_MAP_BOLD
)
332 gl
= add_glyph(bytes
, 0, 1);
333 } else if (filter
== false || curchar
>= 0x20) {
334 gl
= add_glyph(bytes
, map_idx
, 0);
335 if (add_mapping(gl
, curchar
, map_idx
) != 0)
337 if (bytes_r
!= NULL
) {
338 gl
= add_glyph(bytes_r
, map_idx
+ 1, 0);
339 if (add_mapping(gl
, curchar
,
349 parse_bitmap_line(uint8_t *left
, uint8_t *right
, unsigned int line
,
353 unsigned int i
, subline
;
355 if (dwidth
!= width
&& dwidth
!= width
* 2)
356 errx(1, "Bitmap with unsupported width %u!", dwidth
);
358 /* Move pixel data right to simplify splitting double characters. */
359 line
>>= (howmany(dwidth
, 8) * 8) - dwidth
;
361 for (i
= dwidth
/ width
; i
> 0; i
--) {
362 p
= (i
== 2) ? right
: left
;
364 subline
= line
& ((1 << width
) - 1);
365 subline
<<= (howmany(width
, 8) * 8) - width
;
369 } else if (wbytes
== 2) {
373 errx(1, "Unsupported wbytes %u!", wbytes
);
383 parse_bdf(FILE *fp
, unsigned int map_idx
)
386 uint8_t bytes
[wbytes
* height
], bytes_r
[wbytes
* height
];
387 unsigned int curchar
= 0, dwidth
= 0, i
, line
;
389 memset(bytes
, 0, sizeof (bytes
));
390 memset(bytes_r
, 0, sizeof (bytes_r
));
392 while (fgets(ln
, sizeof (ln
), fp
) != NULL
) {
393 if (sscanf(ln
, "ENCODING %u", &curchar
) == 1)
396 if (sscanf(ln
, "DWIDTH %u", &dwidth
) == 1)
399 if (strncmp(ln
, "BITMAP", 6) == 0) {
400 for (i
= 0; i
< height
; i
++) {
401 if (fgets(ln
, sizeof (ln
), fp
) == NULL
)
402 errx(1, "Unexpected EOF!");
403 sscanf(ln
, "%x", &line
);
404 if (parse_bitmap_line(bytes
+ i
* wbytes
,
405 bytes_r
+ i
* wbytes
, line
, dwidth
) != 0)
409 if (check_whitelist(curchar
) == true) {
410 if (add_char(curchar
, map_idx
, bytes
,
411 dwidth
== width
* 2 ? bytes_r
: NULL
) != 0)
424 if (w
<= 0 || w
> 128)
425 errx(1, "invalid width %d", w
);
427 wbytes
= howmany(width
, 8);
431 parse_hex(FILE *fp
, unsigned int map_idx
)
435 uint8_t *bytes
= NULL
, *bytes_r
= NULL
;
436 unsigned curchar
= 0, i
, line
, chars_per_row
, dwidth
;
439 while (fgets(ln
, sizeof (ln
), fp
) != NULL
) {
440 if (strncmp(ln
, "# Height: ", 10) == 0) {
442 errx(1, "malformed input: Height tag after "
445 height
= atoi(ln
+ 10);
446 } else if (strncmp(ln
, "# Width: ", 9) == 0) {
448 errx(1, "malformed input: Width tag after "
451 set_width(atoi(ln
+ 9));
452 } else if (sscanf(ln
, "%6x:", &curchar
)) {
454 bytes
= xmalloc(wbytes
* height
);
455 bytes_r
= xmalloc(wbytes
* height
);
457 /* ln is guaranteed to have a colon here. */
458 p
= strchr(ln
, ':') + 1;
459 chars_per_row
= strlen(p
) / height
;
461 if (chars_per_row
/ 2 > (width
+ 7) / 8)
462 dwidth
*= 2; /* Double-width character. */
463 snprintf(fmt_str
, sizeof (fmt_str
), "%%%ux",
466 for (i
= 0; i
< height
; i
++) {
467 sscanf(p
, fmt_str
, &line
);
469 if (parse_bitmap_line(bytes
+ i
* wbytes
,
470 bytes_r
+ i
* wbytes
, line
, dwidth
) != 0) {
476 if (add_char(curchar
, map_idx
, bytes
,
477 dwidth
== width
* 2 ? bytes_r
: NULL
) != 0) {
489 /* Read BDF header and set the font data. */
491 parse_bdf_header(FILE *fp
)
494 char spacing
= '\0'; /* Should we assume C if not specified? */
497 while (fgets(ln
, sizeof (ln
), fp
) != NULL
) {
498 ret
= sscanf(ln
, "FONTBOUNDINGBOX %u %u %d %d",
499 &bbox
.width
, &bbox
.height
, &bbox
.x
, &bbox
.y
);
502 ret
= sscanf(ln
, "FONT_ASCENT %u", &font_ascent
);
505 ret
= sscanf(ln
, "FONT_DESCENT %u", &font_descent
);
508 ret
= sscanf(ln
, "DEFAULT_CHAR %u", &default_char
);
510 c_list
[0].c
= default_char
;
511 s_list
[0].c
= default_char
;
514 ret
= sscanf(ln
, "SPACING \"%c\"", &spacing
);
517 if (strncmp("ENDPROPERTIES", ln
, 13) == 0)
520 if (spacing
!= 'C') {
521 printf("Spacing '%c' is not supported\n", spacing
);
526 set_width(bbox
.width
);
528 if (bbox
.height
== 0)
529 bbox
.height
= height
;
530 height
= bbox
.height
;
535 parse_file(const char *filename
, unsigned int map_idx
)
541 fp
= fopen(filename
, "r");
546 len
= strlen(filename
);
547 if (len
> 4 && strcasecmp(filename
+ len
- 4, ".hex") == 0) {
548 rv
= parse_hex(fp
, map_idx
);
550 if ((rv
= parse_bdf_header(fp
)) == 0)
551 rv
= parse_bdf(fp
, map_idx
);
561 unsigned int i
, idx
= 0;
563 for (i
= 0; i
< VFNT_MAPS
; i
++)
564 TAILQ_FOREACH(gl
, &glyphs
[i
], g_list
)
568 /* Note we only deal with byte stream here. */
570 write_glyph_source(const void *ptr
, size_t size
, size_t nitems
, FILE *stream
)
572 const uint8_t *data
= ptr
;
576 for (i
= 0; i
< size
; i
++) {
577 if ((i
% wbytes
) == 0) {
578 if (fprintf(stream
, "\n") < 0)
581 if (fprintf(stream
, "0x%02x, ", data
[i
]) < 0)
584 if (fprintf(stream
, "\n") < 0)
590 /* Write to buffer */
592 write_glyph_buf(const void *ptr
, size_t size
, size_t nitems
, FILE *stream
)
594 static size_t index
= 0;
597 (void) memmove(uncompressed
+ index
, ptr
, size
);
604 write_glyphs(FILE *fp
, vt_write cb
)
609 for (i
= 0; i
< VFNT_MAPS
; i
++) {
610 TAILQ_FOREACH(gl
, &glyphs
[i
], g_list
)
611 if (cb(gl
->g_data
, wbytes
* height
, 1, fp
) != 1)
618 fold_mappings(unsigned int map_idx
)
620 struct mapping_list
*ml
= &maps
[map_idx
];
621 struct mapping
*mn
, *mp
, *mbase
;
623 mp
= mbase
= TAILQ_FIRST(ml
);
624 for (mp
= mbase
= TAILQ_FIRST(ml
); mp
!= NULL
; mp
= mn
) {
625 mn
= TAILQ_NEXT(mp
, m_list
);
626 if (mn
!= NULL
&& mn
->m_char
== mp
->m_char
+ 1 &&
627 mn
->m_glyph
->g_index
== mp
->m_glyph
->g_index
+ 1)
629 mbase
->m_length
= mp
->m_char
- mbase
->m_char
+ 1;
631 map_folded_count
[map_idx
]++;
635 struct file_mapping
{
637 uint16_t destination
;
639 } __attribute__((packed
));
642 write_mappings(FILE *fp
, unsigned int map_idx
)
644 struct mapping_list
*ml
= &maps
[map_idx
];
646 struct file_mapping fm
;
647 unsigned int i
= 0, j
= 0;
649 TAILQ_FOREACH(mp
, ml
, m_list
) {
651 if (mp
->m_length
> 0) {
653 fm
.source
= htobe32(mp
->m_char
);
654 fm
.destination
= htobe16(mp
->m_glyph
->g_index
);
655 fm
.length
= htobe16(mp
->m_length
- 1);
656 if (fwrite(&fm
, sizeof (fm
), 1, fp
) != 1)
665 write_source_mappings(FILE *fp
, unsigned int map_idx
)
667 struct mapping_list
*ml
= &maps
[map_idx
];
669 unsigned int i
= 0, j
= 0;
671 TAILQ_FOREACH(mp
, ml
, m_list
) {
673 if (mp
->m_length
> 0) {
675 if (fprintf(fp
, "\t{ 0x%08x, 0x%04x, 0x%04x },\n",
676 mp
->m_char
, mp
->m_glyph
->g_index
,
677 mp
->m_length
- 1) < 0)
690 uint32_t glyph_count
;
691 uint32_t map_count
[4];
692 } __attribute__((packed
));
695 write_fnt(const char *filename
)
698 struct file_header fh
= {
702 fp
= fopen(filename
, "wb");
710 fh
.glyph_count
= htobe32(glyph_unique
);
711 fh
.map_count
[0] = htobe32(map_folded_count
[0]);
712 fh
.map_count
[1] = htobe32(map_folded_count
[1]);
713 fh
.map_count
[2] = htobe32(map_folded_count
[2]);
714 fh
.map_count
[3] = htobe32(map_folded_count
[3]);
715 if (fwrite(&fh
, sizeof (fh
), 1, fp
) != 1) {
721 if (write_glyphs(fp
, &fwrite
) != 0 ||
722 write_mappings(fp
, VFNT_MAP_NORMAL
) != 0 ||
723 write_mappings(fp
, 1) != 0 ||
724 write_mappings(fp
, VFNT_MAP_BOLD
) != 0 ||
725 write_mappings(fp
, 3) != 0) {
736 write_fnt_source(bool lz4
, const char *filename
)
740 size_t uncompressed_size
= wbytes
* height
* glyph_unique
;
741 size_t compressed_size
= uncompressed_size
;
742 uint8_t *compressed
= NULL
;
744 fp
= fopen(filename
, "w");
751 uncompressed
= xmalloc(uncompressed_size
);
752 compressed
= xmalloc(uncompressed_size
);
754 if (fprintf(fp
, "/* Generated %ux%u console font source. */\n\n",
757 if (fprintf(fp
, "#include <sys/types.h>\n") < 0)
759 if (fprintf(fp
, "#include <sys/param.h>\n") < 0)
761 if (fprintf(fp
, "#include <sys/font.h>\n\n") < 0)
764 /* Write font bytes. */
765 if (fprintf(fp
, "static uint8_t FONTDATA_%ux%u[] = {\n",
769 if (write_glyphs(fp
, &write_glyph_buf
) != 0)
771 compressed_size
= lz4_compress(uncompressed
, compressed
,
772 uncompressed_size
, compressed_size
, 0);
773 if (write_glyph_source(compressed
, compressed_size
, 1, fp
) != 1)
778 if (write_glyphs(fp
, &write_glyph_source
) != 0)
781 if (fprintf(fp
, "};\n\n") < 0)
784 /* Write font maps. */
785 if (!TAILQ_EMPTY(&maps
[VFNT_MAP_NORMAL
])) {
786 if (fprintf(fp
, "static struct font_map "
787 "FONTMAP_NORMAL_%ux%u[] = {\n", width
, height
) < 0)
789 if (write_source_mappings(fp
, VFNT_MAP_NORMAL
) != 0)
791 if (fprintf(fp
, "};\n\n") < 0)
794 if (!TAILQ_EMPTY(&maps
[VFNT_MAP_NORMAL_RH
])) {
795 if (fprintf(fp
, "static struct font_map "
796 "FONTMAP_NORMAL_RH_%ux%u[] = {\n", width
, height
) < 0)
798 if (write_source_mappings(fp
, VFNT_MAP_NORMAL_RH
) != 0)
800 if (fprintf(fp
, "};\n\n") < 0)
803 if (!TAILQ_EMPTY(&maps
[VFNT_MAP_BOLD
])) {
804 if (fprintf(fp
, "static struct font_map "
805 "FONTMAP_BOLD_%ux%u[] = {\n", width
, height
) < 0)
807 if (write_source_mappings(fp
, VFNT_MAP_BOLD
) != 0)
809 if (fprintf(fp
, "};\n\n") < 0)
812 if (!TAILQ_EMPTY(&maps
[VFNT_MAP_BOLD_RH
])) {
813 if (fprintf(fp
, "static struct font_map "
814 "FONTMAP_BOLD_RH_%ux%u[] = {\n", width
, height
) < 0)
816 if (write_source_mappings(fp
, VFNT_MAP_BOLD_RH
) != 0)
818 if (fprintf(fp
, "};\n\n") < 0)
822 /* Write struct font. */
823 if (fprintf(fp
, "struct font font_%ux%u = {\n",
826 if (fprintf(fp
, "\t.vf_map\t= {\n") < 0)
828 if (TAILQ_EMPTY(&maps
[VFNT_MAP_NORMAL
])) {
829 if (fprintf(fp
, "\t\t\tNULL,\n") < 0)
832 if (fprintf(fp
, "\t\t\tFONTMAP_NORMAL_%ux%u,\n",
836 if (TAILQ_EMPTY(&maps
[VFNT_MAP_NORMAL_RH
])) {
837 if (fprintf(fp
, "\t\t\tNULL,\n") < 0)
840 if (fprintf(fp
, "\t\t\tFONTMAP_NORMAL_RH_%ux%u,\n",
844 if (TAILQ_EMPTY(&maps
[VFNT_MAP_BOLD
])) {
845 if (fprintf(fp
, "\t\t\tNULL,\n") < 0)
848 if (fprintf(fp
, "\t\t\tFONTMAP_BOLD_%ux%u,\n",
852 if (TAILQ_EMPTY(&maps
[VFNT_MAP_BOLD_RH
])) {
853 if (fprintf(fp
, "\t\t\tNULL\n") < 0)
856 if (fprintf(fp
, "\t\t\tFONTMAP_BOLD_RH_%ux%u\n",
860 if (fprintf(fp
, "\t\t},\n") < 0)
863 if (fprintf(fp
, "\t.vf_bytes\t= NULL,\n") < 0)
866 if (fprintf(fp
, "\t.vf_bytes\t= FONTDATA_%ux%u,\n",
867 width
, height
) < 0) {
871 if (fprintf(fp
, "\t.vf_width\t= %u,\n", width
) < 0)
873 if (fprintf(fp
, "\t.vf_height\t= %u,\n", height
) < 0)
875 if (fprintf(fp
, "\t.vf_map_count\t= { %u, %u, %u, %u }\n",
876 map_folded_count
[0], map_folded_count
[1], map_folded_count
[2],
877 map_folded_count
[3]) < 0) {
880 if (fprintf(fp
, "};\n\n") < 0)
883 /* Write bitmap data. */
884 if (fprintf(fp
, "bitmap_data_t font_data_%ux%u = {\n",
887 if (fprintf(fp
, "\t.width\t= %u,\n", width
) < 0)
889 if (fprintf(fp
, "\t.height\t= %u,\n", height
) < 0)
892 if (fprintf(fp
, "\t.compressed_size\t= %u,\n",
893 compressed_size
) < 0) {
896 if (fprintf(fp
, "\t.uncompressed_size\t= %u,\n",
897 uncompressed_size
) < 0) {
900 if (fprintf(fp
, "\t.compressed_data\t= FONTDATA_%ux%u,\n",
901 width
, height
) < 0) {
905 if (fprintf(fp
, "\t.compressed_size\t= 0,\n") < 0)
907 if (fprintf(fp
, "\t.uncompressed_size\t= %u,\n",
908 uncompressed_size
) < 0) {
911 if (fprintf(fp
, "\t.compressed_data\t= NULL,\n") < 0)
914 if (fprintf(fp
, "\t.font = &font_%ux%u\n", width
, height
) < 0)
916 if (fprintf(fp
, "};\n") < 0)
928 print_font_info(void)
932 "- glyph_total: %6u\n"
933 "- glyph_normal: %6u\n"
934 "- glyph_normal_right: %6u\n"
935 "- glyph_bold: %6u\n"
936 "- glyph_bold_right: %6u\n"
937 "- glyph_unique: %6u\n"
938 "- glyph_dupe: %6u\n"
939 "- mapping_total: %6u\n"
940 "- mapping_normal: %6u\n"
941 "- mapping_normal_folded: %6u\n"
942 "- mapping_normal_right: %6u\n"
943 "- mapping_normal_right_folded: %6u\n"
944 "- mapping_bold: %6u\n"
945 "- mapping_bold_folded: %6u\n"
946 "- mapping_bold_right: %6u\n"
947 "- mapping_bold_right_folded: %6u\n"
948 "- mapping_unique: %6u\n"
949 "- mapping_dupe: %6u\n",
955 glyph_unique
, glyph_dupe
,
957 map_count
[0], map_folded_count
[0],
958 map_count
[1], map_folded_count
[1],
959 map_count
[2], map_folded_count
[2],
960 map_count
[3], map_folded_count
[3],
961 mapping_unique
, mapping_dupe
);
965 main(int argc
, char *argv
[])
967 int ch
, val
, verbose
= 0, rv
= 0;
968 char *outfile
= NULL
;
970 assert(sizeof (struct file_header
) == 32);
971 assert(sizeof (struct file_mapping
) == 8);
973 while ((ch
= getopt(argc
, argv
, "nf:h:vw:o:")) != -1) {
976 if (strcmp(optarg
, "font") == 0)
978 else if (strcmp(optarg
, "source") == 0)
979 format
= VT_C_SOURCE
;
980 else if (strcmp(optarg
, "compressed-source") == 0)
981 format
= VT_C_COMPRESSED
;
983 errx(1, "Invalid format: %s", optarg
);
987 if (val
<= 0 || val
> 128)
988 errx(1, "Invalid height %d", val
);
1001 set_width(atoi(optarg
));
1011 if (outfile
== NULL
|| argc
< 1 || argc
> 2)
1014 wbytes
= howmany(width
, 8);
1016 if (parse_file(argv
[0], VFNT_MAP_NORMAL
) != 0)
1021 if (parse_file(argv
[0], VFNT_MAP_BOLD
) != 0)
1027 dedup_mapping(VFNT_MAP_BOLD
);
1028 dedup_mapping(VFNT_MAP_BOLD_RH
);
1036 rv
= write_fnt(outfile
);
1039 rv
= write_fnt_source(false, outfile
);
1041 case VT_C_COMPRESSED
:
1042 rv
= write_fnt_source(true, outfile
);