205 lines
5.7 KiB
C
205 lines
5.7 KiB
C
#include "mkfont_bdf.h"
|
|
#include "../conf.h"
|
|
#include "util.h"
|
|
#include "bdf.h"
|
|
|
|
/* mkfont_bdf functions */
|
|
bool map_glyph(struct glyph_t *font[],
|
|
struct glyph_list_t *glist_head, struct glyph_t *default_glyph)
|
|
{
|
|
int width, cell_width = 0, cell_height = 0;
|
|
struct glyph_t *glyph;
|
|
struct glyph_list_t *listp;
|
|
|
|
if (default_glyph->width == 0 || default_glyph->height == 0) {
|
|
logging(ERROR, "default glyph(U+%.4X) not found\n", DEFAULT_CHAR);
|
|
return false;
|
|
}
|
|
|
|
cell_width = default_glyph->width;
|
|
cell_height = default_glyph->height;
|
|
logging(DEBUG, "default glyph width:%d height:%d\n",
|
|
default_glyph->width, default_glyph->height);
|
|
|
|
for (listp = glist_head; listp != NULL; listp = listp->next) {
|
|
if (listp->code >= UCS2_CHARS)
|
|
continue;
|
|
|
|
width = wcwidth(listp->code);
|
|
glyph = listp->glyph;
|
|
if ((width <= 0) /* not printable */
|
|
|| (glyph->height != cell_height) /* invalid font height */
|
|
|| (glyph->width != (cell_width * width))) /* invalid font width */
|
|
continue;
|
|
|
|
font[listp->code] = glyph;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool load_alias(struct glyph_t *font[], char *alias)
|
|
{
|
|
unsigned int dst, src;
|
|
char buf[BUFSIZE];
|
|
FILE *fp;
|
|
|
|
if ((fp = efopen(alias, "r")) == NULL)
|
|
return false;
|
|
|
|
while (fgets(buf, BUFSIZE, fp) != NULL) {
|
|
if (strlen(buf) == 0 || buf[0] == '#')
|
|
continue;
|
|
|
|
sscanf(buf, "%X %X", &dst, &src);
|
|
if ((dst >= UCS2_CHARS) || (src >= UCS2_CHARS))
|
|
continue;
|
|
|
|
//if (font[src] != NULL && font[dst] != NULL) {
|
|
if (font[src] != NULL) {
|
|
logging(DEBUG, "swapped: use U+%.4X for U+%.4X\n", src, dst);
|
|
font[dst] = font[src];
|
|
|
|
//free(font[dst]->bitmap);
|
|
//font[dst]->width = font[src]->width;
|
|
//font[dst]->height = font[src]->height;
|
|
//font[dst]->bitmap = font[src]->bitmap;
|
|
//memcpy(font[dst]->bitmap, font[src]->bitmap, sizeof(bitmap_width_t) * font[src]->height);
|
|
}
|
|
}
|
|
efclose(fp);
|
|
return true;
|
|
}
|
|
|
|
bool check_font(struct glyph_t **font, struct glyph_t *empty_half, struct glyph_t *empty_wide)
|
|
{
|
|
empty_half->bitmap = (bitmap_width_t *) ecalloc(font[DEFAULT_CHAR]->height, sizeof(bitmap_width_t));
|
|
empty_wide->bitmap = (bitmap_width_t *) ecalloc(font[DEFAULT_CHAR]->height, sizeof(bitmap_width_t));
|
|
|
|
if (!empty_half->bitmap || !empty_wide->bitmap)
|
|
return false;
|
|
|
|
empty_half->width = font[DEFAULT_CHAR]->width;
|
|
empty_wide->width = font[DEFAULT_CHAR]->width * WIDE;
|
|
empty_half->height = font[DEFAULT_CHAR]->height;
|
|
empty_wide->height = font[DEFAULT_CHAR]->height;
|
|
|
|
if (font[SUBSTITUTE_HALF] == NULL) {
|
|
logging(WARN, "half substitute glyph(U+%.4X) not found, use empty glyph\n", SUBSTITUTE_HALF);
|
|
font[SUBSTITUTE_HALF] = empty_half;
|
|
}
|
|
if (font[SUBSTITUTE_WIDE] == NULL) {
|
|
logging(WARN, "wide substitute glyph(U+%.4X) not found, use empty glyph\n", SUBSTITUTE_WIDE);
|
|
font[SUBSTITUTE_WIDE] = empty_wide;
|
|
}
|
|
if (font[REPLACEMENT_CHAR] == NULL) {
|
|
logging(WARN, "replacement glyph(U+%.4X) not found, use empty glyph\n", REPLACEMENT_CHAR);
|
|
font[REPLACEMENT_CHAR] = empty_half;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool dump_font(struct glyph_t *font[])
|
|
{
|
|
int i, j, width, int_type;
|
|
uint8_t cell_width, cell_height;
|
|
|
|
cell_width = font[DEFAULT_CHAR]->width;
|
|
cell_height = font[DEFAULT_CHAR]->height;
|
|
|
|
int_type = my_ceil(cell_width, BITS_PER_BYTE) /* minimum byte for containing half glyph */
|
|
* 2 /* minimum byte for containing wide glyph */
|
|
* BITS_PER_BYTE; /* minimum bits for containing wide glyph */
|
|
|
|
/* int_type: 16, 32, 48, 64, 80... */
|
|
if (int_type == 48) { /* uint48_t does not exist */
|
|
int_type = 64;
|
|
} else if (int_type >= 80) {
|
|
logging(ERROR, "BDF width too large (uint%d_t does not exist)\n", int_type);
|
|
return false;
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"struct glyph_t {\n"
|
|
"\tuint32_t code;\n"
|
|
"\tuint8_t width;\n"
|
|
"\tuint%d_t bitmap[%d];\n"
|
|
"};\n\n", int_type, cell_height);
|
|
|
|
fprintf(stdout, "enum {\n\tCELL_WIDTH = %d,\n\tCELL_HEIGHT = %d\n};\n\n",
|
|
cell_width, cell_height);
|
|
|
|
fprintf(stdout, "static const struct glyph_t glyphs[] = {\n");
|
|
for (i = 0; i < UCS2_CHARS; i++) {
|
|
width = wcwidth(i);
|
|
|
|
if (font[i] == NULL) /* glyph not found */
|
|
continue;
|
|
|
|
fprintf(stdout, "\t{%d, %d, {", i, width);
|
|
for (j = 0; j < cell_height; j++)
|
|
fprintf(stdout, "0x%X%s", (unsigned int) font[i]->bitmap[j], (j == (cell_height - 1)) ? "": ", ");
|
|
fprintf(stdout, "}},\n");
|
|
}
|
|
fprintf(stdout, "};\n");
|
|
return true;
|
|
}
|
|
|
|
void cleanup(struct glyph_list_t *glist_head, struct glyph_t *empty_half, struct glyph_t *empty_wide)
|
|
{
|
|
struct glyph_list_t *listp, *next;
|
|
|
|
for (listp = glist_head; listp != NULL; listp = next) {
|
|
next = listp->next;
|
|
|
|
free(listp->glyph->bitmap);
|
|
free(listp->glyph);
|
|
free(listp);
|
|
}
|
|
free(empty_half->bitmap);
|
|
free(empty_wide->bitmap);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct glyph_list_t *glist_head = NULL;
|
|
struct glyph_t *font[UCS2_CHARS], default_glyph, empty_wide, empty_half;
|
|
|
|
if (!setlocale(LC_ALL, "")) /* set current locale for wcwidth() */
|
|
logging(WARN, "setlocale() failed\n");
|
|
|
|
if (argc < 3) {
|
|
logging(FATAL, "usage: ./mkfont ALIAS BDF1 [BDF2] [BDF3] ...\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
for (int i = 0; i < UCS2_CHARS; i++)
|
|
font[i] = NULL;
|
|
|
|
for (int i = 2; i < argc; i++)
|
|
load_bdf_glyph(&glist_head, &default_glyph, argv[i]);
|
|
|
|
if (!map_glyph(font, glist_head, &default_glyph)) {
|
|
logging(FATAL, "map_glyph() failed\n");
|
|
goto err_occurred;
|
|
}
|
|
|
|
if (!load_alias(font, argv[1]))
|
|
logging(WARN, "font alias does not work\n");
|
|
|
|
if (!check_font(font, &empty_half, &empty_wide)) {
|
|
logging(FATAL, "check_font() failed\n");
|
|
goto err_occurred;
|
|
}
|
|
|
|
if (!dump_font(font)) {
|
|
logging(FATAL, "dump_font() failed\n");
|
|
goto err_occurred;
|
|
}
|
|
|
|
cleanup(glist_head, &empty_half, &empty_wide);
|
|
return EXIT_SUCCESS;
|
|
|
|
err_occurred:
|
|
cleanup(glist_head, &empty_half, &empty_wide);
|
|
return EXIT_FAILURE;
|
|
}
|