Changeset View
Changeset View
Standalone View
Standalone View
head/usr.bin/vtfontcvt/vtfontcvt.c
Show All 29 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/fnv_hash.h> | #include <sys/fnv_hash.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/font.h> | |||||
#include <assert.h> | #include <assert.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdbool.h> | |||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <lz4.h> | |||||
#define VFNT_MAPS 4 | |||||
#define VFNT_MAP_NORMAL 0 | |||||
#define VFNT_MAP_NORMAL_RH 1 | |||||
#define VFNT_MAP_BOLD 2 | |||||
#define VFNT_MAP_BOLD_RH 3 | |||||
#define VFNT_MAXGLYPHS 131072 | #define VFNT_MAXGLYPHS 131072 | ||||
#define VFNT_MAXDIMENSION 128 | #define VFNT_MAXDIMENSION 128 | ||||
static unsigned int width = 8, wbytes, height = 16; | static unsigned int width = 8, wbytes, height = 16; | ||||
struct glyph { | struct glyph { | ||||
TAILQ_ENTRY(glyph) g_list; | TAILQ_ENTRY(glyph) g_list; | ||||
SLIST_ENTRY(glyph) g_hash; | SLIST_ENTRY(glyph) g_hash; | ||||
Show All 24 Lines | static struct mapping_list maps[VFNT_MAPS] = { | ||||
TAILQ_HEAD_INITIALIZER(maps[0]), | TAILQ_HEAD_INITIALIZER(maps[0]), | ||||
TAILQ_HEAD_INITIALIZER(maps[1]), | TAILQ_HEAD_INITIALIZER(maps[1]), | ||||
TAILQ_HEAD_INITIALIZER(maps[2]), | TAILQ_HEAD_INITIALIZER(maps[2]), | ||||
TAILQ_HEAD_INITIALIZER(maps[3]), | TAILQ_HEAD_INITIALIZER(maps[3]), | ||||
}; | }; | ||||
static unsigned int mapping_total, map_count[4], map_folded_count[4], | static unsigned int mapping_total, map_count[4], map_folded_count[4], | ||||
mapping_unique, mapping_dupe; | mapping_unique, mapping_dupe; | ||||
enum output_format { | |||||
VT_FONT, /* default */ | |||||
VT_C_SOURCE, /* C source for built in fonts */ | |||||
VT_C_COMPRESSED /* C source with compressed font data */ | |||||
}; | |||||
struct whitelist { | |||||
uint32_t c; | |||||
uint32_t len; | |||||
}; | |||||
/* | |||||
* Compressed font glyph list. To be used with boot loader, we need to have | |||||
* ascii set and box drawing chars. | |||||
*/ | |||||
static struct whitelist c_list[] = { | |||||
{ .c = 0, .len = 0 }, /* deault char */ | |||||
{ .c = 0x20, .len = 0x5f }, | |||||
{ .c = 0x2500, .len = 0 }, /* single frame */ | |||||
{ .c = 0x2502, .len = 0 }, | |||||
{ .c = 0x250c, .len = 0 }, | |||||
{ .c = 0x2510, .len = 0 }, | |||||
{ .c = 0x2514, .len = 0 }, | |||||
{ .c = 0x2518, .len = 0 }, | |||||
{ .c = 0x2550, .len = 1 }, /* double frame */ | |||||
{ .c = 0x2554, .len = 0 }, | |||||
{ .c = 0x2557, .len = 0 }, | |||||
{ .c = 0x255a, .len = 0 }, | |||||
{ .c = 0x255d, .len = 0 }, | |||||
}; | |||||
/* | |||||
* Uncompressed source. For x86 we need cp437 so the vga text mode | |||||
* can program font into the vga card. | |||||
*/ | |||||
static struct whitelist s_list[] = { | |||||
{ .c = 0, .len = 0 }, /* deault char */ | |||||
{ .c = 0x20, .len = 0x5f }, /* ascii set */ | |||||
{ .c = 0xA0, .len = 0x5f }, /* latin 1 */ | |||||
{ .c = 0x0192, .len = 0 }, | |||||
{ .c = 0x0332, .len = 0 }, /* composing lower line */ | |||||
{ .c = 0x0393, .len = 0 }, | |||||
{ .c = 0x0398, .len = 0 }, | |||||
{ .c = 0x03A3, .len = 0 }, | |||||
{ .c = 0x03A6, .len = 0 }, | |||||
{ .c = 0x03A9, .len = 0 }, | |||||
{ .c = 0x03B1, .len = 1 }, | |||||
{ .c = 0x03B4, .len = 0 }, | |||||
{ .c = 0x03C0, .len = 0 }, | |||||
{ .c = 0x03C3, .len = 0 }, | |||||
{ .c = 0x03C4, .len = 0 }, | |||||
{ .c = 0x207F, .len = 0 }, | |||||
{ .c = 0x20A7, .len = 0 }, | |||||
{ .c = 0x2205, .len = 0 }, | |||||
{ .c = 0x220A, .len = 0 }, | |||||
{ .c = 0x2219, .len = 1 }, | |||||
{ .c = 0x221E, .len = 0 }, | |||||
{ .c = 0x2229, .len = 0 }, | |||||
{ .c = 0x2248, .len = 0 }, | |||||
{ .c = 0x2261, .len = 0 }, | |||||
{ .c = 0x2264, .len = 1 }, | |||||
{ .c = 0x2310, .len = 0 }, | |||||
{ .c = 0x2320, .len = 1 }, | |||||
{ .c = 0x2500, .len = 0 }, | |||||
{ .c = 0x2502, .len = 0 }, | |||||
{ .c = 0x250C, .len = 0 }, | |||||
{ .c = 0x2510, .len = 0 }, | |||||
{ .c = 0x2514, .len = 0 }, | |||||
{ .c = 0x2518, .len = 0 }, | |||||
{ .c = 0x251C, .len = 0 }, | |||||
{ .c = 0x2524, .len = 0 }, | |||||
{ .c = 0x252C, .len = 0 }, | |||||
{ .c = 0x2534, .len = 0 }, | |||||
{ .c = 0x253C, .len = 0 }, | |||||
{ .c = 0x2550, .len = 0x1c }, | |||||
{ .c = 0x2580, .len = 0 }, | |||||
{ .c = 0x2584, .len = 0 }, | |||||
{ .c = 0x2588, .len = 0 }, | |||||
{ .c = 0x258C, .len = 0 }, | |||||
{ .c = 0x2590, .len = 3 }, | |||||
{ .c = 0x25A0, .len = 0 }, | |||||
}; | |||||
static bool filter = true; | |||||
static enum output_format format = VT_FONT; | |||||
/* Type for write callback. */ | |||||
typedef size_t (*vt_write)(const void *, size_t, size_t, FILE *); | |||||
static uint8_t *uncompressed; | |||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
(void)fprintf(stderr, | (void)fprintf(stderr, "usage: vtfontcvt " | ||||
"usage: vtfontcvt [-w width] [-h height] [-v] normal.bdf [bold.bdf] out.fnt\n"); | "[-n] [-f font|source|compressed-source] [-w width] " | ||||
"[-h height]\n\t[-v] normal.bdf [bold.bdf] out.fnt\n"); | |||||
emaste: This misses the new -o handling | |||||
emasteUnsubmitted Not Done Inline ActionsUpdated in df777aeb9813cc37883fb6d4e1a4d502254b3193 emaste: Updated in df777aeb9813cc37883fb6d4e1a4d502254b3193 | |||||
exit(1); | exit(1); | ||||
} | } | ||||
static void * | static void * | ||||
xmalloc(size_t size) | xmalloc(size_t size) | ||||
{ | { | ||||
void *m; | void *m; | ||||
Show All 37 Lines | |||||
} | } | ||||
static int | static int | ||||
dedup_mapping(unsigned int map_idx) | dedup_mapping(unsigned int map_idx) | ||||
{ | { | ||||
struct mapping *mp_bold, *mp_normal, *mp_temp; | struct mapping *mp_bold, *mp_normal, *mp_temp; | ||||
unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD; | unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD; | ||||
assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RH); | assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RIGHT); | ||||
mp_normal = TAILQ_FIRST(&maps[normal_map_idx]); | mp_normal = TAILQ_FIRST(&maps[normal_map_idx]); | ||||
TAILQ_FOREACH_SAFE(mp_bold, &maps[map_idx], m_list, mp_temp) { | TAILQ_FOREACH_SAFE(mp_bold, &maps[map_idx], m_list, mp_temp) { | ||||
while (mp_normal->m_char < mp_bold->m_char) | while (mp_normal->m_char < mp_bold->m_char) | ||||
mp_normal = TAILQ_NEXT(mp_normal, m_list); | mp_normal = TAILQ_NEXT(mp_normal, m_list); | ||||
if (mp_bold->m_char != mp_normal->m_char) | if (mp_bold->m_char != mp_normal->m_char) | ||||
errx(1, "Character %u not in normal font!", | errx(1, "Character %u not in normal font!", | ||||
mp_bold->m_char); | mp_bold->m_char); | ||||
if (mp_bold->m_glyph != mp_normal->m_glyph) | if (mp_bold->m_glyph != mp_normal->m_glyph) | ||||
Show All 36 Lines | add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback) | ||||
SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash); | SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash); | ||||
glyph_unique++; | glyph_unique++; | ||||
if (glyph_unique > VFNT_MAXGLYPHS) | if (glyph_unique > VFNT_MAXGLYPHS) | ||||
errx(1, "too many glyphs (%u)", glyph_unique); | errx(1, "too many glyphs (%u)", glyph_unique); | ||||
return (gl); | return (gl); | ||||
} | } | ||||
static bool | |||||
check_whitelist(unsigned c) | |||||
{ | |||||
struct whitelist *w = NULL; | |||||
int i, n = 0; | |||||
if (filter == false) | |||||
return (true); | |||||
if (format == VT_C_SOURCE) { | |||||
w = s_list; | |||||
n = sizeof (s_list) / sizeof (s_list[0]); | |||||
} | |||||
if (format == VT_C_COMPRESSED) { | |||||
w = c_list; | |||||
n = sizeof (c_list) / sizeof (c_list[0]); | |||||
} | |||||
if (w == NULL) | |||||
return (true); | |||||
for (i = 0; i < n; i++) { | |||||
if (c >= w[i].c && c <= w[i].c + w[i].len) | |||||
return (true); | |||||
} | |||||
return (false); | |||||
} | |||||
static int | static int | ||||
add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r) | add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r) | ||||
{ | { | ||||
struct glyph *gl; | struct glyph *gl; | ||||
/* Prevent adding two glyphs for 0xFFFD */ | /* Prevent adding two glyphs for 0xFFFD */ | ||||
if (curchar == 0xFFFD) { | if (curchar == 0xFFFD) { | ||||
if (map_idx < VFNT_MAP_BOLD) | if (map_idx < VFNT_MAP_BOLD) | ||||
gl = add_glyph(bytes, 0, 1); | gl = add_glyph(bytes, 0, 1); | ||||
} else if (curchar >= 0x20) { | } else if (filter == false || curchar >= 0x20) { | ||||
gl = add_glyph(bytes, map_idx, 0); | gl = add_glyph(bytes, map_idx, 0); | ||||
if (add_mapping(gl, curchar, map_idx) != 0) | if (add_mapping(gl, curchar, map_idx) != 0) | ||||
return (1); | return (1); | ||||
if (bytes_r != NULL) { | if (bytes_r != NULL) { | ||||
gl = add_glyph(bytes_r, map_idx + 1, 0); | gl = add_glyph(bytes_r, map_idx + 1, 0); | ||||
if (add_mapping(gl, curchar, map_idx + 1) != 0) | if (add_mapping(gl, curchar, map_idx + 1) != 0) | ||||
return (1); | return (1); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if (w <= 0 || w > VFNT_MAXDIMENSION) | ||||
errx(1, "invalid width %d", w); | errx(1, "invalid width %d", w); | ||||
width = w; | width = w; | ||||
wbytes = howmany(width, 8); | wbytes = howmany(width, 8); | ||||
} | } | ||||
static int | static int | ||||
parse_bdf(FILE *fp, unsigned int map_idx) | parse_bdf(FILE *fp, unsigned int map_idx) | ||||
{ | { | ||||
char *line, *ln, *p; | char *ln, *p; | ||||
size_t length; | size_t length; | ||||
uint8_t *bytes, *bytes_r; | uint8_t *line, *bytes, *bytes_r; | ||||
unsigned int curchar = 0, i, j, linenum = 0, bbwbytes; | unsigned int curchar = 0, i, j, linenum = 0, bbwbytes; | ||||
int bbw, bbh, bbox, bboy; /* Glyph bounding box. */ | int bbw, bbh, bbox, bboy; /* Glyph bounding box. */ | ||||
int fbbw = 0, fbbh, fbbox, fbboy; /* Font bounding box. */ | int fbbw = 0, fbbh, fbbox, fbboy; /* Font bounding box. */ | ||||
int dwidth = 0, dwy = 0; | int dwidth = 0, dwy = 0; | ||||
int rv = -1; | int rv = -1; | ||||
char spc = '\0'; | char spc = '\0'; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | if (strncmp(ln, "ENCODING ", 9) == 0) { | ||||
rshift_row(line, wbytes * 2, bbox - fbbox); | rshift_row(line, wbytes * 2, bbox - fbbox); | ||||
rv = split_row(bytes + i * wbytes, | rv = split_row(bytes + i * wbytes, | ||||
bytes_r + i * wbytes, line, dwidth); | bytes_r + i * wbytes, line, dwidth); | ||||
if (rv != 0) | if (rv != 0) | ||||
goto out; | goto out; | ||||
} | } | ||||
if (check_whitelist(curchar) == true) { | |||||
rv = add_char(curchar, map_idx, bytes, | rv = add_char(curchar, map_idx, bytes, | ||||
dwidth > (int)width ? bytes_r : NULL); | dwidth > (int)width ? bytes_r : NULL); | ||||
if (rv != 0) | if (rv != 0) | ||||
goto out; | goto out; | ||||
} | |||||
dwidth = bbw = bbh = 0; | dwidth = bbw = bbh = 0; | ||||
} | } | ||||
} | } | ||||
out: | out: | ||||
free(bytes); | free(bytes); | ||||
free(bytes_r); | free(bytes_r); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (strncmp(ln, "# Height: ", 10) == 0) { | ||||
} | } | ||||
rv = split_row(bytes + i * wbytes, | rv = split_row(bytes + i * wbytes, | ||||
bytes_r + i * wbytes, line, gwidth); | bytes_r + i * wbytes, line, gwidth); | ||||
if (rv != 0) | if (rv != 0) | ||||
goto out; | goto out; | ||||
p += gwbytes * 2; | p += gwbytes * 2; | ||||
} | } | ||||
if (check_whitelist(curchar) == true) { | |||||
rv = add_char(curchar, map_idx, bytes, | rv = add_char(curchar, map_idx, bytes, | ||||
gwidth != width ? bytes_r : NULL); | gwidth != width ? bytes_r : NULL); | ||||
if (rv != 0) | if (rv != 0) | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
} | |||||
out: | out: | ||||
free(bytes); | free(bytes); | ||||
free(bytes_r); | free(bytes_r); | ||||
free(line); | free(line); | ||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static int | ||||
Show All 23 Lines | number_glyphs(void) | ||||
struct glyph *gl; | struct glyph *gl; | ||||
unsigned int i, idx = 0; | unsigned int i, idx = 0; | ||||
for (i = 0; i < VFNT_MAPS; i++) | for (i = 0; i < VFNT_MAPS; i++) | ||||
TAILQ_FOREACH(gl, &glyphs[i], g_list) | TAILQ_FOREACH(gl, &glyphs[i], g_list) | ||||
gl->g_index = idx++; | gl->g_index = idx++; | ||||
} | } | ||||
/* Note we only deal with byte stream here. */ | |||||
static size_t | |||||
write_glyph_source(const void *ptr, size_t size, size_t nitems, FILE *stream) | |||||
{ | |||||
const uint8_t *data = ptr; | |||||
size_t i; | |||||
size *= nitems; | |||||
for (i = 0; i < size; i++) { | |||||
if ((i % wbytes) == 0) { | |||||
if (fprintf(stream, "\n") < 0) | |||||
return (0); | |||||
} | |||||
if (fprintf(stream, "0x%02x, ", data[i]) < 0) | |||||
return (0); | |||||
} | |||||
if (fprintf(stream, "\n") < 0) | |||||
nitems = 0; | |||||
return (nitems); | |||||
} | |||||
/* Write to buffer */ | |||||
static size_t | |||||
write_glyph_buf(const void *ptr, size_t size, size_t nitems, | |||||
FILE *stream __unused) | |||||
{ | |||||
static size_t index = 0; | |||||
size *= nitems; | |||||
(void) memmove(uncompressed + index, ptr, size); | |||||
index += size; | |||||
return (nitems); | |||||
} | |||||
static int | static int | ||||
write_glyphs(FILE *fp) | write_glyphs(FILE *fp, vt_write cb) | ||||
{ | { | ||||
struct glyph *gl; | struct glyph *gl; | ||||
unsigned int i; | unsigned int i; | ||||
for (i = 0; i < VFNT_MAPS; i++) { | for (i = 0; i < VFNT_MAPS; i++) { | ||||
TAILQ_FOREACH(gl, &glyphs[i], g_list) | TAILQ_FOREACH(gl, &glyphs[i], g_list) | ||||
if (fwrite(gl->g_data, wbytes * height, 1, fp) != 1) | if (cb(gl->g_data, wbytes * height, 1, fp) != 1) | ||||
return (1); | return (1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
fold_mappings(unsigned int map_idx) | fold_mappings(unsigned int map_idx) | ||||
{ | { | ||||
struct mapping_list *ml = &maps[map_idx]; | struct mapping_list *ml = &maps[map_idx]; | ||||
struct mapping *mn, *mp, *mbase; | struct mapping *mn, *mp, *mbase; | ||||
mp = mbase = TAILQ_FIRST(ml); | mp = mbase = TAILQ_FIRST(ml); | ||||
for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) { | for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) { | ||||
mn = TAILQ_NEXT(mp, m_list); | mn = TAILQ_NEXT(mp, m_list); | ||||
if (mn != NULL && mn->m_char == mp->m_char + 1 && | if (mn != NULL && mn->m_char == mp->m_char + 1 && | ||||
mn->m_glyph->g_index == mp->m_glyph->g_index + 1) | mn->m_glyph->g_index == mp->m_glyph->g_index + 1) | ||||
continue; | continue; | ||||
mbase->m_length = mp->m_char - mbase->m_char + 1; | mbase->m_length = mp->m_char - mbase->m_char + 1; | ||||
mbase = mp = mn; | mbase = mp = mn; | ||||
map_folded_count[map_idx]++; | map_folded_count[map_idx]++; | ||||
} | } | ||||
} | } | ||||
struct file_mapping { | |||||
uint32_t source; | |||||
uint16_t destination; | |||||
uint16_t length; | |||||
} __packed; | |||||
static int | static int | ||||
write_mappings(FILE *fp, unsigned int map_idx) | write_mappings(FILE *fp, unsigned int map_idx) | ||||
{ | { | ||||
struct mapping_list *ml = &maps[map_idx]; | struct mapping_list *ml = &maps[map_idx]; | ||||
struct mapping *mp; | struct mapping *mp; | ||||
struct file_mapping fm; | vfnt_map_t fm; | ||||
unsigned int i = 0, j = 0; | unsigned int i = 0, j = 0; | ||||
TAILQ_FOREACH(mp, ml, m_list) { | TAILQ_FOREACH(mp, ml, m_list) { | ||||
j++; | j++; | ||||
if (mp->m_length > 0) { | if (mp->m_length > 0) { | ||||
i += mp->m_length; | i += mp->m_length; | ||||
fm.source = htobe32(mp->m_char); | fm.vfm_src = htobe32(mp->m_char); | ||||
fm.destination = htobe16(mp->m_glyph->g_index); | fm.vfm_dst = htobe16(mp->m_glyph->g_index); | ||||
fm.length = htobe16(mp->m_length - 1); | fm.vfm_len = htobe16(mp->m_length - 1); | ||||
if (fwrite(&fm, sizeof fm, 1, fp) != 1) | if (fwrite(&fm, sizeof fm, 1, fp) != 1) | ||||
return (1); | return (1); | ||||
} | } | ||||
} | } | ||||
assert(i == j); | assert(i == j); | ||||
return (0); | return (0); | ||||
} | } | ||||
struct file_header { | static int | ||||
uint8_t magic[8]; | write_source_mappings(FILE *fp, unsigned int map_idx) | ||||
uint8_t width; | { | ||||
uint8_t height; | struct mapping_list *ml = &maps[map_idx]; | ||||
uint16_t pad; | struct mapping *mp; | ||||
uint32_t glyph_count; | unsigned int i = 0, j = 0; | ||||
uint32_t map_count[4]; | |||||
} __packed; | |||||
TAILQ_FOREACH(mp, ml, m_list) { | |||||
j++; | |||||
if (mp->m_length > 0) { | |||||
i += mp->m_length; | |||||
if (fprintf(fp, "\t{ 0x%08x, 0x%04x, 0x%04x },\n", | |||||
mp->m_char, mp->m_glyph->g_index, | |||||
mp->m_length - 1) < 0) | |||||
return (1); | |||||
} | |||||
} | |||||
assert(i == j); | |||||
return (0); | |||||
} | |||||
static int | static int | ||||
write_fnt(const char *filename) | write_fnt(const char *filename) | ||||
{ | { | ||||
FILE *fp; | FILE *fp; | ||||
struct file_header fh = { | struct font_header fh = { | ||||
.magic = "VFNT0002", | .fh_magic = FONT_HEADER_MAGIC, | ||||
}; | }; | ||||
fp = fopen(filename, "wb"); | fp = fopen(filename, "wb"); | ||||
if (fp == NULL) { | if (fp == NULL) { | ||||
perror(filename); | perror(filename); | ||||
return (1); | return (1); | ||||
} | } | ||||
fh.width = width; | fh.fh_width = width; | ||||
fh.height = height; | fh.fh_height = height; | ||||
fh.glyph_count = htobe32(glyph_unique); | fh.fh_glyph_count = htobe32(glyph_unique); | ||||
fh.map_count[0] = htobe32(map_folded_count[0]); | fh.fh_map_count[0] = htobe32(map_folded_count[0]); | ||||
fh.map_count[1] = htobe32(map_folded_count[1]); | fh.fh_map_count[1] = htobe32(map_folded_count[1]); | ||||
fh.map_count[2] = htobe32(map_folded_count[2]); | fh.fh_map_count[2] = htobe32(map_folded_count[2]); | ||||
fh.map_count[3] = htobe32(map_folded_count[3]); | fh.fh_map_count[3] = htobe32(map_folded_count[3]); | ||||
if (fwrite(&fh, sizeof fh, 1, fp) != 1) { | if (fwrite(&fh, sizeof(fh), 1, fp) != 1) { | ||||
perror(filename); | perror(filename); | ||||
fclose(fp); | fclose(fp); | ||||
return (1); | return (1); | ||||
} | } | ||||
if (write_glyphs(fp) != 0 || | if (write_glyphs(fp, &fwrite) != 0 || | ||||
write_mappings(fp, VFNT_MAP_NORMAL) != 0 || | write_mappings(fp, VFNT_MAP_NORMAL) != 0 || | ||||
write_mappings(fp, VFNT_MAP_NORMAL_RH) != 0 || | write_mappings(fp, VFNT_MAP_NORMAL_RIGHT) != 0 || | ||||
write_mappings(fp, VFNT_MAP_BOLD) != 0 || | write_mappings(fp, VFNT_MAP_BOLD) != 0 || | ||||
write_mappings(fp, VFNT_MAP_BOLD_RH) != 0) { | write_mappings(fp, VFNT_MAP_BOLD_RIGHT) != 0) { | ||||
perror(filename); | perror(filename); | ||||
fclose(fp); | fclose(fp); | ||||
return (1); | return (1); | ||||
} | } | ||||
fclose(fp); | fclose(fp); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | |||||
write_fnt_source(bool lz4, const char *filename) | |||||
{ | |||||
FILE *fp; | |||||
int rv = 1; | |||||
size_t uncompressed_size = wbytes * height * glyph_unique; | |||||
size_t compressed_size = uncompressed_size; | |||||
uint8_t *compressed = NULL; | |||||
fp = fopen(filename, "w"); | |||||
if (fp == NULL) { | |||||
perror(filename); | |||||
return (1); | |||||
} | |||||
if (lz4 == true) { | |||||
uncompressed = xmalloc(uncompressed_size); | |||||
compressed = xmalloc(uncompressed_size); | |||||
} | |||||
if (fprintf(fp, "/* Generated %ux%u console font source. */\n\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
if (fprintf(fp, "#include <sys/types.h>\n") < 0) | |||||
goto done; | |||||
if (fprintf(fp, "#include <sys/param.h>\n") < 0) | |||||
goto done; | |||||
if (fprintf(fp, "#include <sys/font.h>\n\n") < 0) | |||||
goto done; | |||||
/* Write font bytes. */ | |||||
if (fprintf(fp, "static uint8_t FONTDATA_%ux%u[] = {\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
if (lz4 == true) { | |||||
if (write_glyphs(fp, &write_glyph_buf) != 0) | |||||
goto done; | |||||
compressed_size = lz4_compress(uncompressed, compressed, | |||||
uncompressed_size, compressed_size, 0); | |||||
if (write_glyph_source(compressed, compressed_size, 1, fp) != 1) | |||||
goto done; | |||||
free(uncompressed); | |||||
free(compressed); | |||||
} else { | |||||
if (write_glyphs(fp, &write_glyph_source) != 0) | |||||
goto done; | |||||
} | |||||
if (fprintf(fp, "};\n\n") < 0) | |||||
goto done; | |||||
/* Write font maps. */ | |||||
if (!TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL])) { | |||||
if (fprintf(fp, "static vfnt_map_t " | |||||
"FONTMAP_NORMAL_%ux%u[] = {\n", width, height) < 0) | |||||
goto done; | |||||
if (write_source_mappings(fp, VFNT_MAP_NORMAL) != 0) | |||||
goto done; | |||||
if (fprintf(fp, "};\n\n") < 0) | |||||
goto done; | |||||
} | |||||
if (!TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL_RIGHT])) { | |||||
if (fprintf(fp, "static vfnt_map_t " | |||||
"FONTMAP_NORMAL_RH_%ux%u[] = {\n", width, height) < 0) | |||||
goto done; | |||||
if (write_source_mappings(fp, VFNT_MAP_NORMAL_RIGHT) != 0) | |||||
goto done; | |||||
if (fprintf(fp, "};\n\n") < 0) | |||||
goto done; | |||||
} | |||||
if (!TAILQ_EMPTY(&maps[VFNT_MAP_BOLD])) { | |||||
if (fprintf(fp, "static vfnt_map_t " | |||||
"FONTMAP_BOLD_%ux%u[] = {\n", width, height) < 0) | |||||
goto done; | |||||
if (write_source_mappings(fp, VFNT_MAP_BOLD) != 0) | |||||
goto done; | |||||
if (fprintf(fp, "};\n\n") < 0) | |||||
goto done; | |||||
} | |||||
if (!TAILQ_EMPTY(&maps[VFNT_MAP_BOLD_RIGHT])) { | |||||
if (fprintf(fp, "static vfnt_map_t " | |||||
"FONTMAP_BOLD_RH_%ux%u[] = {\n", width, height) < 0) | |||||
goto done; | |||||
if (write_source_mappings(fp, VFNT_MAP_BOLD_RIGHT) != 0) | |||||
goto done; | |||||
if (fprintf(fp, "};\n\n") < 0) | |||||
goto done; | |||||
} | |||||
/* Write struct font. */ | |||||
if (fprintf(fp, "struct vt_font font_%ux%u = {\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
if (fprintf(fp, "\t.vf_map\t= {\n") < 0) | |||||
goto done; | |||||
if (TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL])) { | |||||
if (fprintf(fp, "\t\t\tNULL,\n") < 0) | |||||
goto done; | |||||
} else { | |||||
if (fprintf(fp, "\t\t\tFONTMAP_NORMAL_%ux%u,\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
} | |||||
if (TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL_RIGHT])) { | |||||
if (fprintf(fp, "\t\t\tNULL,\n") < 0) | |||||
goto done; | |||||
} else { | |||||
if (fprintf(fp, "\t\t\tFONTMAP_NORMAL_RH_%ux%u,\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
} | |||||
if (TAILQ_EMPTY(&maps[VFNT_MAP_BOLD])) { | |||||
if (fprintf(fp, "\t\t\tNULL,\n") < 0) | |||||
goto done; | |||||
} else { | |||||
if (fprintf(fp, "\t\t\tFONTMAP_BOLD_%ux%u,\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
} | |||||
if (TAILQ_EMPTY(&maps[VFNT_MAP_BOLD_RIGHT])) { | |||||
if (fprintf(fp, "\t\t\tNULL\n") < 0) | |||||
goto done; | |||||
} else { | |||||
if (fprintf(fp, "\t\t\tFONTMAP_BOLD_RH_%ux%u\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
} | |||||
if (fprintf(fp, "\t\t},\n") < 0) | |||||
goto done; | |||||
if (lz4 == true) { | |||||
if (fprintf(fp, "\t.vf_bytes\t= NULL,\n") < 0) | |||||
goto done; | |||||
} else { | |||||
if (fprintf(fp, "\t.vf_bytes\t= FONTDATA_%ux%u,\n", | |||||
width, height) < 0) { | |||||
goto done; | |||||
} | |||||
} | |||||
if (fprintf(fp, "\t.vf_width\t= %u,\n", width) < 0) | |||||
goto done; | |||||
if (fprintf(fp, "\t.vf_height\t= %u,\n", height) < 0) | |||||
goto done; | |||||
if (fprintf(fp, "\t.vf_map_count\t= { %u, %u, %u, %u }\n", | |||||
map_folded_count[0], map_folded_count[1], map_folded_count[2], | |||||
map_folded_count[3]) < 0) { | |||||
goto done; | |||||
} | |||||
if (fprintf(fp, "};\n\n") < 0) | |||||
goto done; | |||||
/* Write bitmap data. */ | |||||
if (fprintf(fp, "vt_font_bitmap_data_t font_data_%ux%u = {\n", | |||||
width, height) < 0) | |||||
goto done; | |||||
if (fprintf(fp, "\t.vfbd_width\t= %u,\n", width) < 0) | |||||
goto done; | |||||
if (fprintf(fp, "\t.vfbd_height\t= %u,\n", height) < 0) | |||||
goto done; | |||||
if (lz4 == true) { | |||||
if (fprintf(fp, "\t.vfbd_compressed_size\t= %zu,\n", | |||||
compressed_size) < 0) { | |||||
goto done; | |||||
} | |||||
if (fprintf(fp, "\t.vfbd_uncompressed_size\t= %zu,\n", | |||||
uncompressed_size) < 0) { | |||||
goto done; | |||||
} | |||||
if (fprintf(fp, "\t.vfbd_compressed_data\t= FONTDATA_%ux%u,\n", | |||||
width, height) < 0) { | |||||
goto done; | |||||
} | |||||
} else { | |||||
if (fprintf(fp, "\t.vfbd_compressed_size\t= 0,\n") < 0) | |||||
goto done; | |||||
if (fprintf(fp, "\t.vfbd_uncompressed_size\t= %zu,\n", | |||||
uncompressed_size) < 0) { | |||||
goto done; | |||||
} | |||||
if (fprintf(fp, "\t.vfbd_compressed_data\t= NULL,\n") < 0) | |||||
goto done; | |||||
} | |||||
if (fprintf(fp, "\t.vfbd_font = &font_%ux%u\n", width, height) < 0) | |||||
goto done; | |||||
if (fprintf(fp, "};\n") < 0) | |||||
goto done; | |||||
rv = 0; | |||||
done: | |||||
if (rv != 0) | |||||
perror(filename); | |||||
fclose(fp); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
print_font_info(void) | print_font_info(void) | ||||
{ | { | ||||
printf( | printf( | ||||
"Statistics:\n" | "Statistics:\n" | ||||
"- width: %6u\n" | "- width: %6u\n" | ||||
"- height: %6u\n" | "- height: %6u\n" | ||||
"- glyph_total: %6u\n" | "- glyph_total: %6u\n" | ||||
Show All 27 Lines | "- mapping_dupe: %6u\n", | ||||
map_count[2], map_folded_count[2], | map_count[2], map_folded_count[2], | ||||
map_count[3], map_folded_count[3], | map_count[3], map_folded_count[3], | ||||
mapping_unique, mapping_dupe); | mapping_unique, mapping_dupe); | ||||
} | } | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
int ch, verbose = 0; | int ch, verbose = 0, rv = 0; | ||||
char *outfile = NULL; | |||||
assert(sizeof(struct file_header) == 32); | assert(sizeof(struct font_header) == 32); | ||||
assert(sizeof(struct file_mapping) == 8); | assert(sizeof(vfnt_map_t) == 8); | ||||
while ((ch = getopt(argc, argv, "h:vw:")) != -1) { | while ((ch = getopt(argc, argv, "nf:h:vw:o:")) != -1) { | ||||
switch (ch) { | switch (ch) { | ||||
case 'f': | |||||
if (strcmp(optarg, "font") == 0) | |||||
format = VT_FONT; | |||||
else if (strcmp(optarg, "source") == 0) | |||||
format = VT_C_SOURCE; | |||||
else if (strcmp(optarg, "compressed-source") == 0) | |||||
format = VT_C_COMPRESSED; | |||||
else | |||||
errx(1, "Invalid format: %s", optarg); | |||||
break; | |||||
case 'h': | case 'h': | ||||
height = atoi(optarg); | height = atoi(optarg); | ||||
break; | break; | ||||
case 'n': | |||||
filter = false; | |||||
break; | |||||
case 'o': | |||||
outfile = optarg; | |||||
break; | |||||
case 'v': | case 'v': | ||||
verbose = 1; | verbose = 1; | ||||
break; | break; | ||||
case 'w': | case 'w': | ||||
width = atoi(optarg); | width = atoi(optarg); | ||||
break; | break; | ||||
case '?': | case '?': | ||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (argc < 2 || argc > 3) | if (outfile == NULL && (argc < 2 || argc > 3)) | ||||
usage(); | usage(); | ||||
if (outfile == NULL) { | |||||
outfile = argv[argc - 1]; | |||||
argc--; | |||||
} | |||||
set_width(width); | set_width(width); | ||||
set_height(height); | set_height(height); | ||||
if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) | if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) | ||||
return (1); | return (1); | ||||
argc--; | argc--; | ||||
argv++; | argv++; | ||||
if (argc == 2) { | if (argc == 1) { | ||||
if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) | if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) | ||||
return (1); | return (1); | ||||
argc--; | argc--; | ||||
argv++; | argv++; | ||||
} | } | ||||
number_glyphs(); | number_glyphs(); | ||||
dedup_mapping(VFNT_MAP_BOLD); | dedup_mapping(VFNT_MAP_BOLD); | ||||
dedup_mapping(VFNT_MAP_BOLD_RH); | dedup_mapping(VFNT_MAP_BOLD_RIGHT); | ||||
fold_mappings(0); | fold_mappings(0); | ||||
fold_mappings(1); | fold_mappings(1); | ||||
fold_mappings(2); | fold_mappings(2); | ||||
fold_mappings(3); | fold_mappings(3); | ||||
if (write_fnt(argv[0]) != 0) | |||||
return (1); | |||||
switch (format) { | |||||
case VT_FONT: | |||||
rv = write_fnt(outfile); | |||||
break; | |||||
case VT_C_SOURCE: | |||||
rv = write_fnt_source(false, outfile); | |||||
break; | |||||
case VT_C_COMPRESSED: | |||||
rv = write_fnt_source(true, outfile); | |||||
break; | |||||
} | |||||
if (verbose) | if (verbose) | ||||
print_font_info(); | print_font_info(); | ||||
return (0); | return (rv); | ||||
} | } |
This misses the new -o handling