#include #include "util.h" #include "font.h" int font_compare(const node_t *a, const node_t *b) { const font_t *x = (const font_t *)a->data; const font_t *y = (const font_t *)b->data; return strcmp(x->name, y->name); } node_t *load_fonts(toml_table_t *table, const char *base_path) { node_t *root = NULL; // vast majority of projects should have only 1-2 fonts, but let's offer // some room in case there's more. for (int i = 0; i < 32; i++) { const char *key = toml_key_in(table, i); if (!key) break; char fullname[200]; font_t font; toml_datum_t filename = toml_string_in(table, key); if (!filename.ok) { error("couldn't load font ", key); } snprintf(fullname, 200, "%s/%s", base_path, filename.u.s); font = font_create(key, fullname); root = node_insert(root, &font, font_compare); } return root; } font_t *font_find(node_t *root, const char *key) { font_t search = {.name = key}; node_t *node = node_search(root, &search, font_compare); font_t *font = (font_t *)node->data; if (font == NULL) { error("couldn't find requested font ", key); } return font; } font_t font_create(const char *font_name, const char *filename) { FILE *fp; font_t font; char errbuf[200]; map_t *map; printf(" Processing %s...\n", font_name); fp = fopen(filename, "r"); if (!fp) { char str[200]; snprintf(str, 200, "can't open %s: ", filename); error(str, strerror(errno)); } toml_table_t *table = toml_parse_file(fp, errbuf, 200); fclose(fp); #define TOML_GET_KEY(var, key, func) toml_datum_t (var) = func(table, (key));\ if (!(var).ok) {\ char str[200];\ snprintf(str, 200, "key '%s' missing from", (key)); \ error(str, filename); \ } TOML_GET_KEY(name, "name", toml_string_in) TOML_GET_KEY(image_filename, "filename", toml_string_in) TOML_GET_KEY(bpp, "bits_per_pixel", toml_int_in) TOML_GET_KEY(width, "width", toml_int_in) TOML_GET_KEY(height, "height", toml_int_in) #undef TOML_GET_KEY toml_table_t *mapping = toml_table_in(table, "map"); font.name = name.u.s; font.image_filename = image_filename.u.s; font.bits_per_pixel = bpp.u.i; font.width = width.u.i; font.height = height.u.i; font.map_entries = map_create(mapping, &map); font.map = map; return font; } void font_destroy(font_t font) { map_destroy(font.map); free(font.name); free(font.image_filename); } unsigned int map_create(toml_table_t *table, map_t **map) { map_t *node; map_t *next; unsigned int nodes; map_t *root = malloc(sizeof(map_t*)); toml_array_t *space = toml_array_in(table, " "); toml_datum_t spcidx = toml_int_at(space, 0); toml_datum_t spcwid = toml_int_at(space, 1); if (!spcidx.ok) { error("missing or inappropriate index for glyph: ' '", ""); } if (!spcwid.ok) { error("missing or inappropriate index for glyph: ' '", ""); } node = root; for (nodes = 1; ; nodes++) { const char *key = toml_key_in(table, nodes); if (!key) break; toml_array_t *val = toml_array_in(table, key); toml_datum_t index = toml_int_at(val, 0); toml_datum_t width = toml_int_at(val, 1); if (!index.ok) { error("missing or inappropriate index for glyph: ", key); } if (!width.ok) { error("missing or inappropriate width for glyph: ", key); } next = malloc(sizeof(map_t *)); next->glyph = key; next->index = index.u.i; next->width = width.u.i; node->next = next; node = next; } node->next = NULL; *map = root; return nodes; } void map_destroy(map_t *map) { map_t *node = map; map_t *next; while ((next = node->next) != NULL) { free(node); node = next; } }