1219888Sed/*- 2267123Semaste * Copyright (c) 2009, 2014 The FreeBSD Foundation 3219888Sed * All rights reserved. 4219888Sed * 5219888Sed * This software was developed by Ed Schouten under sponsorship from the 6219888Sed * FreeBSD Foundation. 7219888Sed * 8219888Sed * Redistribution and use in source and binary forms, with or without 9219888Sed * modification, are permitted provided that the following conditions 10219888Sed * are met: 11219888Sed * 1. Redistributions of source code must retain the above copyright 12219888Sed * notice, this list of conditions and the following disclaimer. 13219888Sed * 2. Redistributions in binary form must reproduce the above copyright 14219888Sed * notice, this list of conditions and the following disclaimer in the 15219888Sed * documentation and/or other materials provided with the distribution. 16219888Sed * 17219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219888Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219888Sed * SUCH DAMAGE. 28219888Sed */ 29219888Sed 30219888Sed#include <sys/cdefs.h> 31219888Sed__FBSDID("$FreeBSD: releng/10.3/usr.bin/vtfontcvt/vtfontcvt.c 288174 2015-09-24 13:06:19Z emaste $"); 32219888Sed 33267035Semaste#include <sys/types.h> 34267035Semaste#include <sys/fnv_hash.h> 35219888Sed#include <sys/endian.h> 36219888Sed#include <sys/param.h> 37219888Sed#include <sys/queue.h> 38219888Sed 39219888Sed#include <assert.h> 40267301Semaste#include <err.h> 41219888Sed#include <stdint.h> 42219888Sed#include <stdio.h> 43219888Sed#include <stdlib.h> 44219888Sed#include <string.h> 45267011Semaste#include <unistd.h> 46219888Sed 47259680Semaste#define VFNT_MAPS 4 48259680Semaste#define VFNT_MAP_NORMAL 0 49267301Semaste#define VFNT_MAP_NORMAL_RH 1 50259680Semaste#define VFNT_MAP_BOLD 2 51267301Semaste#define VFNT_MAP_BOLD_RH 3 52259680Semaste 53267011Semastestatic unsigned int width = 8, wbytes, height = 16; 54219888Sed 55219888Sedstruct glyph { 56219888Sed TAILQ_ENTRY(glyph) g_list; 57267035Semaste SLIST_ENTRY(glyph) g_hash; 58219888Sed uint8_t *g_data; 59219888Sed unsigned int g_index; 60219888Sed}; 61219888Sed 62267035Semaste#define FONTCVT_NHASH 4096 63259680SemasteTAILQ_HEAD(glyph_list, glyph); 64267035Semastestatic SLIST_HEAD(, glyph) glyph_hash[FONTCVT_NHASH]; 65259680Semastestatic struct glyph_list glyphs[VFNT_MAPS] = { 66259680Semaste TAILQ_HEAD_INITIALIZER(glyphs[0]), 67259680Semaste TAILQ_HEAD_INITIALIZER(glyphs[1]), 68259680Semaste TAILQ_HEAD_INITIALIZER(glyphs[2]), 69259680Semaste TAILQ_HEAD_INITIALIZER(glyphs[3]), 70259680Semaste}; 71259680Semastestatic unsigned int glyph_total, glyph_count[4], glyph_unique, glyph_dupe; 72219888Sed 73219888Sedstruct mapping { 74219888Sed TAILQ_ENTRY(mapping) m_list; 75219888Sed unsigned int m_char; 76219888Sed unsigned int m_length; 77219888Sed struct glyph *m_glyph; 78219888Sed}; 79219888Sed 80219888SedTAILQ_HEAD(mapping_list, mapping); 81259680Semastestatic struct mapping_list maps[VFNT_MAPS] = { 82259680Semaste TAILQ_HEAD_INITIALIZER(maps[0]), 83259680Semaste TAILQ_HEAD_INITIALIZER(maps[1]), 84259680Semaste TAILQ_HEAD_INITIALIZER(maps[2]), 85259680Semaste TAILQ_HEAD_INITIALIZER(maps[3]), 86259680Semaste}; 87259680Semastestatic unsigned int mapping_total, map_count[4], map_folded_count[4], 88259680Semaste mapping_unique, mapping_dupe; 89219888Sed 90219888Sedstatic void 91219888Sedusage(void) 92219888Sed{ 93219888Sed 94269041Semaste (void)fprintf(stderr, 95267337Semaste"usage: vtfontcvt [-w width] [-h height] [-v] normal.bdf [bold.bdf] out.fnt\n"); 96219888Sed exit(1); 97219888Sed} 98219888Sed 99288174Semastestatic void * 100288174Semastexmalloc(size_t size) 101288174Semaste{ 102288174Semaste void *m; 103288174Semaste 104288174Semaste if ((m = malloc(size)) == NULL) 105288174Semaste errx(1, "memory allocation failure"); 106288174Semaste return (m); 107288174Semaste} 108288174Semaste 109219888Sedstatic int 110259680Semasteadd_mapping(struct glyph *gl, unsigned int c, unsigned int map_idx) 111219888Sed{ 112219888Sed struct mapping *mp; 113219888Sed struct mapping_list *ml; 114219888Sed 115219888Sed mapping_total++; 116219888Sed 117288174Semaste mp = xmalloc(sizeof *mp); 118219888Sed mp->m_char = c; 119219888Sed mp->m_glyph = gl; 120219888Sed mp->m_length = 0; 121219888Sed 122259680Semaste ml = &maps[map_idx]; 123219888Sed if (TAILQ_LAST(ml, mapping_list) != NULL && 124269041Semaste TAILQ_LAST(ml, mapping_list)->m_char >= c) 125267298Semaste errx(1, "Bad ordering at character %u\n", c); 126219888Sed TAILQ_INSERT_TAIL(ml, mp, m_list); 127219888Sed 128259680Semaste map_count[map_idx]++; 129219888Sed mapping_unique++; 130219888Sed 131219888Sed return (0); 132219888Sed} 133219888Sed 134267301Semastestatic int 135267301Semastededup_mapping(unsigned int map_idx) 136267301Semaste{ 137267301Semaste struct mapping *mp_bold, *mp_normal, *mp_temp; 138267301Semaste unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD; 139267301Semaste 140267301Semaste assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RH); 141267301Semaste mp_normal = TAILQ_FIRST(&maps[normal_map_idx]); 142267301Semaste TAILQ_FOREACH_SAFE(mp_bold, &maps[map_idx], m_list, mp_temp) { 143267301Semaste while (mp_normal->m_char < mp_bold->m_char) 144267301Semaste mp_normal = TAILQ_NEXT(mp_normal, m_list); 145269041Semaste if (mp_bold->m_char != mp_normal->m_char) 146267301Semaste errx(1, "Character %u not in normal font!\n", 147267301Semaste mp_bold->m_char); 148267301Semaste if (mp_bold->m_glyph != mp_normal->m_glyph) 149267301Semaste continue; 150267301Semaste 151267301Semaste /* No mapping is needed if it's equal to the normal mapping. */ 152267301Semaste TAILQ_REMOVE(&maps[map_idx], mp_bold, m_list); 153267301Semaste free(mp_bold); 154267301Semaste mapping_dupe++; 155267301Semaste } 156267301Semaste return (0); 157267301Semaste} 158267301Semaste 159219888Sedstatic struct glyph * 160259680Semasteadd_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback) 161219888Sed{ 162219888Sed struct glyph *gl; 163267035Semaste int hash; 164219888Sed 165219888Sed glyph_total++; 166259680Semaste glyph_count[map_idx]++; 167219888Sed 168267035Semaste hash = fnv_32_buf(bytes, wbytes * height, FNV1_32_INIT) % FONTCVT_NHASH; 169267035Semaste SLIST_FOREACH(gl, &glyph_hash[hash], g_hash) { 170267035Semaste if (memcmp(gl->g_data, bytes, wbytes * height) == 0) { 171267035Semaste glyph_dupe++; 172267035Semaste return (gl); 173219888Sed } 174219888Sed } 175219888Sed 176288174Semaste gl = xmalloc(sizeof *gl); 177288174Semaste gl->g_data = xmalloc(wbytes * height); 178219888Sed memcpy(gl->g_data, bytes, wbytes * height); 179219888Sed if (fallback) 180259680Semaste TAILQ_INSERT_HEAD(&glyphs[map_idx], gl, g_list); 181219888Sed else 182259680Semaste TAILQ_INSERT_TAIL(&glyphs[map_idx], gl, g_list); 183267035Semaste SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash); 184219888Sed 185219888Sed glyph_unique++; 186219888Sed return (gl); 187219888Sed} 188219888Sed 189219888Sedstatic int 190267123Semasteadd_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r) 191267123Semaste{ 192267123Semaste struct glyph *gl; 193267123Semaste 194267123Semaste /* Prevent adding two glyphs for 0xFFFD */ 195267123Semaste if (curchar == 0xFFFD) { 196267123Semaste if (map_idx < VFNT_MAP_BOLD) 197267123Semaste gl = add_glyph(bytes, 0, 1); 198267123Semaste } else if (curchar >= 0x20) { 199267123Semaste gl = add_glyph(bytes, map_idx, 0); 200267123Semaste if (add_mapping(gl, curchar, map_idx) != 0) 201267123Semaste return (1); 202267123Semaste if (bytes_r != NULL) { 203267123Semaste gl = add_glyph(bytes_r, map_idx + 1, 0); 204267123Semaste if (add_mapping(gl, curchar, 205267123Semaste map_idx + 1) != 0) 206267123Semaste return (1); 207267123Semaste } 208267123Semaste } 209267123Semaste return (0); 210267123Semaste} 211267123Semaste 212267123Semaste 213267123Semastestatic int 214259680Semasteparse_bitmap_line(uint8_t *left, uint8_t *right, unsigned int line, 215259680Semaste unsigned int dwidth) 216219888Sed{ 217259680Semaste uint8_t *p; 218259680Semaste unsigned int i, subline; 219259680Semaste 220269041Semaste if (dwidth != width && dwidth != width * 2) 221269041Semaste errx(1, "Bitmap with unsupported width %u!\n", dwidth); 222259680Semaste 223259680Semaste /* Move pixel data right to simplify splitting double characters. */ 224259680Semaste line >>= (howmany(dwidth, 8) * 8) - dwidth; 225259680Semaste 226259680Semaste for (i = dwidth / width; i > 0; i--) { 227259680Semaste p = (i == 2) ? right : left; 228259680Semaste 229259680Semaste subline = line & ((1 << width) - 1); 230259680Semaste subline <<= (howmany(width, 8) * 8) - width; 231259680Semaste 232259680Semaste if (wbytes == 1) { 233259680Semaste *p = subline; 234259680Semaste } else if (wbytes == 2) { 235259680Semaste *p++ = subline >> 8; 236259680Semaste *p = subline; 237259680Semaste } else { 238269041Semaste errx(1, "Unsupported wbytes %u!\n", wbytes); 239259680Semaste } 240259680Semaste 241259680Semaste line >>= width; 242259680Semaste } 243267337Semaste 244259680Semaste return (0); 245259680Semaste} 246259680Semaste 247259680Semastestatic int 248267123Semasteparse_bdf(FILE *fp, unsigned int map_idx) 249259680Semaste{ 250219888Sed char *ln; 251219888Sed size_t length; 252259680Semaste uint8_t bytes[wbytes * height], bytes_r[wbytes * height]; 253259680Semaste unsigned int curchar = 0, dwidth = 0, i, line; 254219888Sed 255219888Sed while ((ln = fgetln(fp, &length)) != NULL) { 256219888Sed ln[length - 1] = '\0'; 257219888Sed 258219888Sed if (strncmp(ln, "ENCODING ", 9) == 0) { 259219888Sed curchar = atoi(ln + 9); 260219888Sed } 261219888Sed 262259680Semaste if (strncmp(ln, "DWIDTH ", 7) == 0) { 263259680Semaste dwidth = atoi(ln + 7); 264259680Semaste } 265259680Semaste 266267126Semaste if (strncmp(ln, "BITMAP", 6) == 0 && 267267126Semaste (ln[6] == ' ' || ln[6] == '\0')) { 268219888Sed for (i = 0; i < height; i++) { 269269041Semaste if ((ln = fgetln(fp, &length)) == NULL) 270267298Semaste errx(1, "Unexpected EOF!\n"); 271219888Sed ln[length - 1] = '\0'; 272219888Sed sscanf(ln, "%x", &line); 273259680Semaste if (parse_bitmap_line(bytes + i * wbytes, 274259680Semaste bytes_r + i * wbytes, line, dwidth) != 0) 275219888Sed return (1); 276219888Sed } 277219888Sed 278267123Semaste if (add_char(curchar, map_idx, bytes, 279267123Semaste dwidth == width * 2 ? bytes_r : NULL) != 0) 280267123Semaste return (1); 281267123Semaste } 282267123Semaste } 283267123Semaste 284267123Semaste return (0); 285267123Semaste} 286267123Semaste 287269041Semastestatic void 288269041Semasteset_width(int w) 289269041Semaste{ 290269041Semaste 291269041Semaste if (w <= 0 || w > 128) 292269041Semaste errx(1, "invalid width %d", w); 293269041Semaste width = w; 294269041Semaste wbytes = howmany(width, 8); 295269041Semaste} 296269041Semaste 297267123Semastestatic int 298267123Semasteparse_hex(FILE *fp, unsigned int map_idx) 299267123Semaste{ 300267123Semaste char *ln, *p; 301267123Semaste char fmt_str[8]; 302267123Semaste size_t length; 303288174Semaste uint8_t *bytes = NULL, *bytes_r = NULL; 304267123Semaste unsigned curchar = 0, i, line, chars_per_row, dwidth; 305288174Semaste int rv = 0; 306267123Semaste 307267123Semaste while ((ln = fgetln(fp, &length)) != NULL) { 308267123Semaste ln[length - 1] = '\0'; 309267123Semaste 310267123Semaste if (strncmp(ln, "# Height: ", 10) == 0) { 311288174Semaste if (bytes != NULL) 312288174Semaste errx(1, "malformed input: Height tag after font data"); 313267123Semaste height = atoi(ln + 10); 314267123Semaste } else if (strncmp(ln, "# Width: ", 9) == 0) { 315288174Semaste if (bytes != NULL) 316288174Semaste errx(1, "malformed input: Width tag after font data"); 317269041Semaste set_width(atoi(ln + 9)); 318267123Semaste } else if (sscanf(ln, "%4x:", &curchar)) { 319288174Semaste if (bytes == NULL) { 320288174Semaste bytes = xmalloc(wbytes * height); 321288174Semaste bytes_r = xmalloc(wbytes * height); 322288174Semaste } 323267123Semaste p = ln + 5; 324267123Semaste chars_per_row = strlen(p) / height; 325267123Semaste dwidth = width; 326269041Semaste if (chars_per_row / 2 > (width + 7) / 8) 327267123Semaste dwidth *= 2; /* Double-width character. */ 328267123Semaste snprintf(fmt_str, sizeof(fmt_str), "%%%ux", 329267123Semaste chars_per_row); 330267337Semaste 331267123Semaste for (i = 0; i < height; i++) { 332267123Semaste sscanf(p, fmt_str, &line); 333267123Semaste p += chars_per_row; 334267123Semaste if (parse_bitmap_line(bytes + i * wbytes, 335288174Semaste bytes_r + i * wbytes, line, dwidth) != 0) { 336288174Semaste rv = 1; 337288174Semaste goto out; 338288174Semaste } 339219888Sed } 340267123Semaste 341267123Semaste if (add_char(curchar, map_idx, bytes, 342288174Semaste dwidth == width * 2 ? bytes_r : NULL) != 0) { 343288174Semaste rv = 1; 344288174Semaste goto out; 345288174Semaste } 346219888Sed } 347219888Sed } 348288174Semasteout: 349288174Semaste free(bytes); 350288174Semaste free(bytes_r); 351288174Semaste return (rv); 352219888Sed} 353219888Sed 354267123Semastestatic int 355267123Semasteparse_file(const char *filename, unsigned int map_idx) 356267123Semaste{ 357267123Semaste FILE *fp; 358267123Semaste size_t len; 359269041Semaste int rv; 360267123Semaste 361267123Semaste fp = fopen(filename, "r"); 362267123Semaste if (fp == NULL) { 363267123Semaste perror(filename); 364267123Semaste return (1); 365267123Semaste } 366267123Semaste len = strlen(filename); 367267123Semaste if (len > 4 && strcasecmp(filename + len - 4, ".hex") == 0) 368269041Semaste rv = parse_hex(fp, map_idx); 369269041Semaste else 370269041Semaste rv = parse_bdf(fp, map_idx); 371269041Semaste fclose(fp); 372269041Semaste return (rv); 373267123Semaste} 374267123Semaste 375219888Sedstatic void 376219888Sednumber_glyphs(void) 377219888Sed{ 378219888Sed struct glyph *gl; 379259680Semaste unsigned int i, idx = 0; 380219888Sed 381259680Semaste for (i = 0; i < VFNT_MAPS; i++) 382259680Semaste TAILQ_FOREACH(gl, &glyphs[i], g_list) 383259680Semaste gl->g_index = idx++; 384219888Sed} 385219888Sed 386267324Semastestatic int 387219888Sedwrite_glyphs(FILE *fp) 388219888Sed{ 389219888Sed struct glyph *gl; 390259680Semaste unsigned int i; 391219888Sed 392259680Semaste for (i = 0; i < VFNT_MAPS; i++) { 393259680Semaste TAILQ_FOREACH(gl, &glyphs[i], g_list) 394267324Semaste if (fwrite(gl->g_data, wbytes * height, 1, fp) != 1) 395267324Semaste return (1); 396259680Semaste } 397267324Semaste return (0); 398219888Sed} 399219888Sed 400219888Sedstatic void 401259680Semastefold_mappings(unsigned int map_idx) 402219888Sed{ 403259680Semaste struct mapping_list *ml = &maps[map_idx]; 404219888Sed struct mapping *mn, *mp, *mbase; 405219888Sed 406219888Sed mp = mbase = TAILQ_FIRST(ml); 407219888Sed for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) { 408219888Sed mn = TAILQ_NEXT(mp, m_list); 409219888Sed if (mn != NULL && mn->m_char == mp->m_char + 1 && 410219888Sed mn->m_glyph->g_index == mp->m_glyph->g_index + 1) 411219888Sed continue; 412219888Sed mbase->m_length = mp->m_char - mbase->m_char + 1; 413219888Sed mbase = mp = mn; 414259680Semaste map_folded_count[map_idx]++; 415219888Sed } 416219888Sed} 417219888Sed 418219888Sedstruct file_mapping { 419219888Sed uint32_t source; 420219888Sed uint16_t destination; 421219888Sed uint16_t length; 422219888Sed} __packed; 423219888Sed 424267324Semastestatic int 425259680Semastewrite_mappings(FILE *fp, unsigned int map_idx) 426219888Sed{ 427259680Semaste struct mapping_list *ml = &maps[map_idx]; 428219888Sed struct mapping *mp; 429219888Sed struct file_mapping fm; 430219888Sed unsigned int i = 0, j = 0; 431219888Sed 432219888Sed TAILQ_FOREACH(mp, ml, m_list) { 433219888Sed j++; 434219888Sed if (mp->m_length > 0) { 435219888Sed i += mp->m_length; 436219888Sed fm.source = htobe32(mp->m_char); 437219888Sed fm.destination = htobe16(mp->m_glyph->g_index); 438219888Sed fm.length = htobe16(mp->m_length - 1); 439267324Semaste if (fwrite(&fm, sizeof fm, 1, fp) != 1) 440267324Semaste return (1); 441219888Sed } 442219888Sed } 443219888Sed assert(i == j); 444267324Semaste return (0); 445219888Sed} 446219888Sed 447219888Sedstruct file_header { 448219888Sed uint8_t magic[8]; 449219888Sed uint8_t width; 450219888Sed uint8_t height; 451259680Semaste uint16_t pad; 452259680Semaste uint32_t glyph_count; 453259680Semaste uint32_t map_count[4]; 454219888Sed} __packed; 455219888Sed 456219888Sedstatic int 457219888Sedwrite_fnt(const char *filename) 458219888Sed{ 459219888Sed FILE *fp; 460219888Sed struct file_header fh = { 461259680Semaste .magic = "VFNT0002", 462219888Sed }; 463219888Sed 464219888Sed fp = fopen(filename, "wb"); 465219888Sed if (fp == NULL) { 466219888Sed perror(filename); 467219888Sed return (1); 468219888Sed } 469219888Sed 470219888Sed fh.width = width; 471219888Sed fh.height = height; 472259680Semaste fh.glyph_count = htobe32(glyph_unique); 473259680Semaste fh.map_count[0] = htobe32(map_folded_count[0]); 474259680Semaste fh.map_count[1] = htobe32(map_folded_count[1]); 475259680Semaste fh.map_count[2] = htobe32(map_folded_count[2]); 476259680Semaste fh.map_count[3] = htobe32(map_folded_count[3]); 477267324Semaste if (fwrite(&fh, sizeof fh, 1, fp) != 1) { 478267324Semaste perror(filename); 479269041Semaste fclose(fp); 480267324Semaste return (1); 481267324Semaste } 482267337Semaste 483267324Semaste if (write_glyphs(fp) != 0 || 484267324Semaste write_mappings(fp, VFNT_MAP_NORMAL) != 0 || 485267324Semaste write_mappings(fp, 1) != 0 || 486267324Semaste write_mappings(fp, VFNT_MAP_BOLD) != 0 || 487267324Semaste write_mappings(fp, 3) != 0) { 488267324Semaste perror(filename); 489269041Semaste fclose(fp); 490267324Semaste return (1); 491267324Semaste } 492219888Sed 493269041Semaste fclose(fp); 494219888Sed return (0); 495219888Sed} 496219888Sed 497267298Semastestatic void 498267298Semasteprint_font_info(void) 499267298Semaste{ 500267298Semaste printf( 501267298Semaste"Statistics:\n" 502267298Semaste"- glyph_total: %5u\n" 503267298Semaste"- glyph_normal: %5u\n" 504267298Semaste"- glyph_normal_right: %5u\n" 505267298Semaste"- glyph_bold: %5u\n" 506267298Semaste"- glyph_bold_right: %5u\n" 507267298Semaste"- glyph_unique: %5u\n" 508267298Semaste"- glyph_dupe: %5u\n" 509267298Semaste"- mapping_total: %5u\n" 510267298Semaste"- mapping_normal: %5u\n" 511267298Semaste"- mapping_normal_folded: %5u\n" 512267298Semaste"- mapping_normal_right: %5u\n" 513267298Semaste"- mapping_normal_right_folded: %5u\n" 514267298Semaste"- mapping_bold: %5u\n" 515267298Semaste"- mapping_bold_folded: %5u\n" 516267298Semaste"- mapping_bold_right: %5u\n" 517267298Semaste"- mapping_bold_right_folded: %5u\n" 518267298Semaste"- mapping_unique: %5u\n" 519267298Semaste"- mapping_dupe: %5u\n", 520267298Semaste glyph_total, 521267298Semaste glyph_count[0], 522267298Semaste glyph_count[1], 523267298Semaste glyph_count[2], 524267298Semaste glyph_count[3], 525267298Semaste glyph_unique, glyph_dupe, 526267298Semaste mapping_total, 527267298Semaste map_count[0], map_folded_count[0], 528267298Semaste map_count[1], map_folded_count[1], 529267298Semaste map_count[2], map_folded_count[2], 530267298Semaste map_count[3], map_folded_count[3], 531267298Semaste mapping_unique, mapping_dupe); 532267298Semaste} 533267298Semaste 534219888Sedint 535219888Sedmain(int argc, char *argv[]) 536219888Sed{ 537267298Semaste int ch, val, verbose = 0; 538219888Sed 539259680Semaste assert(sizeof(struct file_header) == 32); 540219888Sed assert(sizeof(struct file_mapping) == 8); 541219888Sed 542267337Semaste while ((ch = getopt(argc, argv, "h:vw:")) != -1) { 543267011Semaste switch (ch) { 544267011Semaste case 'h': 545267298Semaste val = atoi(optarg); 546269041Semaste if (val <= 0 || val > 128) 547267298Semaste errx(1, "Invalid height %d", val); 548267298Semaste height = val; 549267011Semaste break; 550267298Semaste case 'v': 551267298Semaste verbose = 1; 552267298Semaste break; 553267011Semaste case 'w': 554269041Semaste set_width(atoi(optarg)); 555267011Semaste break; 556267011Semaste case '?': 557267011Semaste default: 558267011Semaste usage(); 559267011Semaste } 560267011Semaste } 561267011Semaste argc -= optind; 562267011Semaste argv += optind; 563267011Semaste 564267012Semaste if (argc < 2 || argc > 3) 565219888Sed usage(); 566267011Semaste 567219888Sed wbytes = howmany(width, 8); 568219888Sed 569267123Semaste if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) 570219888Sed return (1); 571267012Semaste argc--; 572267012Semaste argv++; 573267012Semaste if (argc == 2) { 574267123Semaste if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) 575267012Semaste return (1); 576267012Semaste argc--; 577267012Semaste argv++; 578267012Semaste } 579219888Sed number_glyphs(); 580267301Semaste dedup_mapping(VFNT_MAP_BOLD); 581267301Semaste dedup_mapping(VFNT_MAP_BOLD_RH); 582219888Sed fold_mappings(0); 583219888Sed fold_mappings(1); 584259680Semaste fold_mappings(2); 585259680Semaste fold_mappings(3); 586267012Semaste if (write_fnt(argv[0]) != 0) 587219888Sed return (1); 588267298Semaste 589267298Semaste if (verbose) 590267298Semaste print_font_info(); 591267298Semaste 592219888Sed return (0); 593219888Sed} 594