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: stable/10/usr.bin/vtfontcvt/vtfontcvt.c 332324 2018-04-09 13:00:03Z 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')) { 268332322Semaste /* 269332322Semaste * Assume that the next _height_ lines are bitmap 270332322Semaste * data. ENDCHAR is allowed to terminate the bitmap 271332322Semaste * early but is not otherwise checked; any extra data 272332322Semaste * is ignored. 273332322Semaste */ 274219888Sed for (i = 0; i < height; i++) { 275269041Semaste if ((ln = fgetln(fp, &length)) == NULL) 276267298Semaste errx(1, "Unexpected EOF!\n"); 277219888Sed ln[length - 1] = '\0'; 278332322Semaste if (strcmp(ln, "ENDCHAR") == 0) { 279332322Semaste memset(bytes + i * wbytes, 0, 280332322Semaste (height - i) * wbytes); 281332322Semaste memset(bytes_r + i * wbytes, 0, 282332322Semaste (height - i) * wbytes); 283332322Semaste break; 284332322Semaste } 285219888Sed sscanf(ln, "%x", &line); 286259680Semaste if (parse_bitmap_line(bytes + i * wbytes, 287259680Semaste bytes_r + i * wbytes, line, dwidth) != 0) 288219888Sed return (1); 289219888Sed } 290219888Sed 291267123Semaste if (add_char(curchar, map_idx, bytes, 292267123Semaste dwidth == width * 2 ? bytes_r : NULL) != 0) 293267123Semaste return (1); 294267123Semaste } 295267123Semaste } 296267123Semaste 297267123Semaste return (0); 298267123Semaste} 299267123Semaste 300269041Semastestatic void 301269041Semasteset_width(int w) 302269041Semaste{ 303269041Semaste 304269041Semaste if (w <= 0 || w > 128) 305269041Semaste errx(1, "invalid width %d", w); 306269041Semaste width = w; 307269041Semaste wbytes = howmany(width, 8); 308269041Semaste} 309269041Semaste 310267123Semastestatic int 311267123Semasteparse_hex(FILE *fp, unsigned int map_idx) 312267123Semaste{ 313267123Semaste char *ln, *p; 314267123Semaste char fmt_str[8]; 315267123Semaste size_t length; 316288174Semaste uint8_t *bytes = NULL, *bytes_r = NULL; 317267123Semaste unsigned curchar = 0, i, line, chars_per_row, dwidth; 318288174Semaste int rv = 0; 319267123Semaste 320267123Semaste while ((ln = fgetln(fp, &length)) != NULL) { 321267123Semaste ln[length - 1] = '\0'; 322267123Semaste 323267123Semaste if (strncmp(ln, "# Height: ", 10) == 0) { 324288174Semaste if (bytes != NULL) 325288174Semaste errx(1, "malformed input: Height tag after font data"); 326267123Semaste height = atoi(ln + 10); 327267123Semaste } else if (strncmp(ln, "# Width: ", 9) == 0) { 328288174Semaste if (bytes != NULL) 329288174Semaste errx(1, "malformed input: Width tag after font data"); 330269041Semaste set_width(atoi(ln + 9)); 331332323Semaste } else if (sscanf(ln, "%6x:", &curchar)) { 332288174Semaste if (bytes == NULL) { 333288174Semaste bytes = xmalloc(wbytes * height); 334288174Semaste bytes_r = xmalloc(wbytes * height); 335288174Semaste } 336332323Semaste /* ln is guaranteed to have a colon here. */ 337332323Semaste p = strchr(ln, ':') + 1; 338267123Semaste chars_per_row = strlen(p) / height; 339267123Semaste dwidth = width; 340269041Semaste if (chars_per_row / 2 > (width + 7) / 8) 341267123Semaste dwidth *= 2; /* Double-width character. */ 342267123Semaste snprintf(fmt_str, sizeof(fmt_str), "%%%ux", 343267123Semaste chars_per_row); 344267337Semaste 345267123Semaste for (i = 0; i < height; i++) { 346267123Semaste sscanf(p, fmt_str, &line); 347267123Semaste p += chars_per_row; 348267123Semaste if (parse_bitmap_line(bytes + i * wbytes, 349288174Semaste bytes_r + i * wbytes, line, dwidth) != 0) { 350288174Semaste rv = 1; 351288174Semaste goto out; 352288174Semaste } 353219888Sed } 354267123Semaste 355267123Semaste if (add_char(curchar, map_idx, bytes, 356288174Semaste dwidth == width * 2 ? bytes_r : NULL) != 0) { 357288174Semaste rv = 1; 358288174Semaste goto out; 359288174Semaste } 360219888Sed } 361219888Sed } 362288174Semasteout: 363288174Semaste free(bytes); 364288174Semaste free(bytes_r); 365288174Semaste return (rv); 366219888Sed} 367219888Sed 368267123Semastestatic int 369267123Semasteparse_file(const char *filename, unsigned int map_idx) 370267123Semaste{ 371267123Semaste FILE *fp; 372267123Semaste size_t len; 373269041Semaste int rv; 374267123Semaste 375267123Semaste fp = fopen(filename, "r"); 376267123Semaste if (fp == NULL) { 377267123Semaste perror(filename); 378267123Semaste return (1); 379267123Semaste } 380267123Semaste len = strlen(filename); 381267123Semaste if (len > 4 && strcasecmp(filename + len - 4, ".hex") == 0) 382269041Semaste rv = parse_hex(fp, map_idx); 383269041Semaste else 384269041Semaste rv = parse_bdf(fp, map_idx); 385269041Semaste fclose(fp); 386269041Semaste return (rv); 387267123Semaste} 388267123Semaste 389219888Sedstatic void 390219888Sednumber_glyphs(void) 391219888Sed{ 392219888Sed struct glyph *gl; 393259680Semaste unsigned int i, idx = 0; 394219888Sed 395259680Semaste for (i = 0; i < VFNT_MAPS; i++) 396259680Semaste TAILQ_FOREACH(gl, &glyphs[i], g_list) 397259680Semaste gl->g_index = idx++; 398219888Sed} 399219888Sed 400267324Semastestatic int 401219888Sedwrite_glyphs(FILE *fp) 402219888Sed{ 403219888Sed struct glyph *gl; 404259680Semaste unsigned int i; 405219888Sed 406259680Semaste for (i = 0; i < VFNT_MAPS; i++) { 407259680Semaste TAILQ_FOREACH(gl, &glyphs[i], g_list) 408267324Semaste if (fwrite(gl->g_data, wbytes * height, 1, fp) != 1) 409267324Semaste return (1); 410259680Semaste } 411267324Semaste return (0); 412219888Sed} 413219888Sed 414219888Sedstatic void 415259680Semastefold_mappings(unsigned int map_idx) 416219888Sed{ 417259680Semaste struct mapping_list *ml = &maps[map_idx]; 418219888Sed struct mapping *mn, *mp, *mbase; 419219888Sed 420219888Sed mp = mbase = TAILQ_FIRST(ml); 421219888Sed for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) { 422219888Sed mn = TAILQ_NEXT(mp, m_list); 423219888Sed if (mn != NULL && mn->m_char == mp->m_char + 1 && 424219888Sed mn->m_glyph->g_index == mp->m_glyph->g_index + 1) 425219888Sed continue; 426219888Sed mbase->m_length = mp->m_char - mbase->m_char + 1; 427219888Sed mbase = mp = mn; 428259680Semaste map_folded_count[map_idx]++; 429219888Sed } 430219888Sed} 431219888Sed 432219888Sedstruct file_mapping { 433219888Sed uint32_t source; 434219888Sed uint16_t destination; 435219888Sed uint16_t length; 436219888Sed} __packed; 437219888Sed 438267324Semastestatic int 439259680Semastewrite_mappings(FILE *fp, unsigned int map_idx) 440219888Sed{ 441259680Semaste struct mapping_list *ml = &maps[map_idx]; 442219888Sed struct mapping *mp; 443219888Sed struct file_mapping fm; 444219888Sed unsigned int i = 0, j = 0; 445219888Sed 446219888Sed TAILQ_FOREACH(mp, ml, m_list) { 447219888Sed j++; 448219888Sed if (mp->m_length > 0) { 449219888Sed i += mp->m_length; 450219888Sed fm.source = htobe32(mp->m_char); 451219888Sed fm.destination = htobe16(mp->m_glyph->g_index); 452219888Sed fm.length = htobe16(mp->m_length - 1); 453267324Semaste if (fwrite(&fm, sizeof fm, 1, fp) != 1) 454267324Semaste return (1); 455219888Sed } 456219888Sed } 457219888Sed assert(i == j); 458267324Semaste return (0); 459219888Sed} 460219888Sed 461219888Sedstruct file_header { 462219888Sed uint8_t magic[8]; 463219888Sed uint8_t width; 464219888Sed uint8_t height; 465259680Semaste uint16_t pad; 466259680Semaste uint32_t glyph_count; 467259680Semaste uint32_t map_count[4]; 468219888Sed} __packed; 469219888Sed 470219888Sedstatic int 471219888Sedwrite_fnt(const char *filename) 472219888Sed{ 473219888Sed FILE *fp; 474219888Sed struct file_header fh = { 475259680Semaste .magic = "VFNT0002", 476219888Sed }; 477219888Sed 478219888Sed fp = fopen(filename, "wb"); 479219888Sed if (fp == NULL) { 480219888Sed perror(filename); 481219888Sed return (1); 482219888Sed } 483219888Sed 484219888Sed fh.width = width; 485219888Sed fh.height = height; 486259680Semaste fh.glyph_count = htobe32(glyph_unique); 487259680Semaste fh.map_count[0] = htobe32(map_folded_count[0]); 488259680Semaste fh.map_count[1] = htobe32(map_folded_count[1]); 489259680Semaste fh.map_count[2] = htobe32(map_folded_count[2]); 490259680Semaste fh.map_count[3] = htobe32(map_folded_count[3]); 491267324Semaste if (fwrite(&fh, sizeof fh, 1, fp) != 1) { 492267324Semaste perror(filename); 493269041Semaste fclose(fp); 494267324Semaste return (1); 495267324Semaste } 496267337Semaste 497267324Semaste if (write_glyphs(fp) != 0 || 498267324Semaste write_mappings(fp, VFNT_MAP_NORMAL) != 0 || 499267324Semaste write_mappings(fp, 1) != 0 || 500267324Semaste write_mappings(fp, VFNT_MAP_BOLD) != 0 || 501267324Semaste write_mappings(fp, 3) != 0) { 502267324Semaste perror(filename); 503269041Semaste fclose(fp); 504267324Semaste return (1); 505267324Semaste } 506219888Sed 507269041Semaste fclose(fp); 508219888Sed return (0); 509219888Sed} 510219888Sed 511267298Semastestatic void 512267298Semasteprint_font_info(void) 513267298Semaste{ 514267298Semaste printf( 515267298Semaste"Statistics:\n" 516332324Semaste"- glyph_total: %6u\n" 517332324Semaste"- glyph_normal: %6u\n" 518332324Semaste"- glyph_normal_right: %6u\n" 519332324Semaste"- glyph_bold: %6u\n" 520332324Semaste"- glyph_bold_right: %6u\n" 521332324Semaste"- glyph_unique: %6u\n" 522332324Semaste"- glyph_dupe: %6u\n" 523332324Semaste"- mapping_total: %6u\n" 524332324Semaste"- mapping_normal: %6u\n" 525332324Semaste"- mapping_normal_folded: %6u\n" 526332324Semaste"- mapping_normal_right: %6u\n" 527332324Semaste"- mapping_normal_right_folded: %6u\n" 528332324Semaste"- mapping_bold: %6u\n" 529332324Semaste"- mapping_bold_folded: %6u\n" 530332324Semaste"- mapping_bold_right: %6u\n" 531332324Semaste"- mapping_bold_right_folded: %6u\n" 532332324Semaste"- mapping_unique: %6u\n" 533332324Semaste"- mapping_dupe: %6u\n", 534267298Semaste glyph_total, 535267298Semaste glyph_count[0], 536267298Semaste glyph_count[1], 537267298Semaste glyph_count[2], 538267298Semaste glyph_count[3], 539267298Semaste glyph_unique, glyph_dupe, 540267298Semaste mapping_total, 541267298Semaste map_count[0], map_folded_count[0], 542267298Semaste map_count[1], map_folded_count[1], 543267298Semaste map_count[2], map_folded_count[2], 544267298Semaste map_count[3], map_folded_count[3], 545267298Semaste mapping_unique, mapping_dupe); 546267298Semaste} 547267298Semaste 548219888Sedint 549219888Sedmain(int argc, char *argv[]) 550219888Sed{ 551267298Semaste int ch, val, verbose = 0; 552219888Sed 553259680Semaste assert(sizeof(struct file_header) == 32); 554219888Sed assert(sizeof(struct file_mapping) == 8); 555219888Sed 556267337Semaste while ((ch = getopt(argc, argv, "h:vw:")) != -1) { 557267011Semaste switch (ch) { 558267011Semaste case 'h': 559267298Semaste val = atoi(optarg); 560269041Semaste if (val <= 0 || val > 128) 561267298Semaste errx(1, "Invalid height %d", val); 562267298Semaste height = val; 563267011Semaste break; 564267298Semaste case 'v': 565267298Semaste verbose = 1; 566267298Semaste break; 567267011Semaste case 'w': 568269041Semaste set_width(atoi(optarg)); 569267011Semaste break; 570267011Semaste case '?': 571267011Semaste default: 572267011Semaste usage(); 573267011Semaste } 574267011Semaste } 575267011Semaste argc -= optind; 576267011Semaste argv += optind; 577267011Semaste 578267012Semaste if (argc < 2 || argc > 3) 579219888Sed usage(); 580267011Semaste 581219888Sed wbytes = howmany(width, 8); 582219888Sed 583267123Semaste if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) 584219888Sed return (1); 585267012Semaste argc--; 586267012Semaste argv++; 587267012Semaste if (argc == 2) { 588267123Semaste if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) 589267012Semaste return (1); 590267012Semaste argc--; 591267012Semaste argv++; 592267012Semaste } 593219888Sed number_glyphs(); 594267301Semaste dedup_mapping(VFNT_MAP_BOLD); 595267301Semaste dedup_mapping(VFNT_MAP_BOLD_RH); 596219888Sed fold_mappings(0); 597219888Sed fold_mappings(1); 598259680Semaste fold_mappings(2); 599259680Semaste fold_mappings(3); 600267012Semaste if (write_fnt(argv[0]) != 0) 601219888Sed return (1); 602267298Semaste 603267298Semaste if (verbose) 604267298Semaste print_font_info(); 605267298Semaste 606219888Sed return (0); 607219888Sed} 608