bdfload.c revision 51bbcd86
1/* $NetBSD: bdfload.c,v 1.12 2022/08/29 14:54:04 macallan Exp $ */ 2 3/* 4 * Copyright (c) 2018 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28/* 29 * a crude BDF loader for wsdisplay 30 */ 31 32#include <stdlib.h> 33#include <stdio.h> 34#include <fcntl.h> 35#include <unistd.h> 36#include <string.h> 37#include <errno.h> 38#include <ctype.h> 39#include <sys/ioctl.h> 40#include <err.h> 41 42#include <dev/wscons/wsconsio.h> 43 44/* 45 * wsdisplay_font but with strings embedded and integer fields in 46 * little endian 47 */ 48struct wsfthdr { 49 char magic[4]; /* "WSFT" */ 50 char name[64]; 51 uint32_t firstchar; 52 uint32_t numchars; 53 uint32_t encoding; 54 uint32_t fontwidth; 55 uint32_t fontheight; 56 uint32_t stride; 57 uint32_t bitorder; 58 uint32_t byteorder; 59}; 60 61 62const struct encmap { 63 const char *name; 64 int encoding; 65} encmap[] = { 66 { "cp437", WSDISPLAY_FONTENC_IBM }, 67 { "ibm", WSDISPLAY_FONTENC_IBM }, 68 { "iso", WSDISPLAY_FONTENC_ISO }, 69 { "iso-8859-1", WSDISPLAY_FONTENC_ISO }, 70 { "iso-8859-2", WSDISPLAY_FONTENC_ISO2 }, 71 { "iso-8859-7", WSDISPLAY_FONTENC_ISO7 }, 72 { "iso2", WSDISPLAY_FONTENC_ISO2 }, 73 { "iso7", WSDISPLAY_FONTENC_ISO7 }, 74 { "iso8859-1", WSDISPLAY_FONTENC_ISO }, 75 { "iso8859-2", WSDISPLAY_FONTENC_ISO2 }, 76 { "iso8859-7", WSDISPLAY_FONTENC_ISO7 }, 77 { "koi8-r", WSDISPLAY_FONTENC_KOI8_R }, 78 { "koi8r", WSDISPLAY_FONTENC_KOI8_R }, 79 { "latin-1", WSDISPLAY_FONTENC_ISO }, 80 { "latin-2", WSDISPLAY_FONTENC_ISO2 }, 81 { "latin1", WSDISPLAY_FONTENC_ISO }, 82 { "latin2", WSDISPLAY_FONTENC_ISO2 }, 83 { "pcvt", WSDISPLAY_FONTENC_PCVT }, 84 { NULL, -1 } 85}; 86 87const char * const encname[] = { 88#define _ENC(_e) [_e] = #_e 89 _ENC(WSDISPLAY_FONTENC_ISO), 90 _ENC(WSDISPLAY_FONTENC_IBM), 91 _ENC(WSDISPLAY_FONTENC_PCVT), 92 _ENC(WSDISPLAY_FONTENC_ISO7), 93 _ENC(WSDISPLAY_FONTENC_ISO2), 94 _ENC(WSDISPLAY_FONTENC_KOI8_R), 95}; 96 97 98const char *ofile = NULL; 99int encoding = -1; 100int verbose = 0; 101int dump = 0; 102int header = 0; 103char commentbuf[2048] = ""; 104int commentptr = 0; 105char fontname[64] = ""; 106 107void 108dump_line(char *gptr, int stride) 109{ 110 int i, j, msk, c; 111 112 for (i = 0; i < stride; i++) { 113 c = gptr[i]; 114 msk = 0x80; 115 for (j = 0; j < 8; j++) { 116 putchar((c & msk) != 0 ? '#' : ' '); 117 msk = msk >> 1; 118 } 119 } 120 printf("\n"); 121} 122 123void 124write_wsf(const char *oname, struct wsdisplay_font *f, char *buffer, int buflen) 125{ 126 struct wsfthdr h; 127 128 memset(&h, 0, sizeof(h)); 129 strncpy(h.magic, "WSFT", sizeof(h.magic)); 130 strncpy(h.name, f->name, sizeof(h.name)); 131 h.firstchar = htole32(f->firstchar); 132 h.numchars = htole32(f->numchars); 133 h.encoding = htole32(f->encoding); 134 h.fontwidth = htole32(f->fontwidth); 135 h.fontheight = htole32(f->fontheight); 136 h.stride = htole32(f->stride); 137 h.bitorder = htole32(f->bitorder); 138 h.byteorder = htole32(f->byteorder); 139 140 int wsfd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0644); 141 if (wsfd < 0) 142 err(EXIT_FAILURE, "%s", ofile); 143 144 ssize_t nwritten; 145 nwritten = write(wsfd, &h, sizeof(h)); 146 if (nwritten < 0) 147 err(EXIT_FAILURE, "%s", ofile); 148 if (nwritten != sizeof(h)) 149 errx(EXIT_FAILURE, "%s: partial write", ofile); 150 151 nwritten = write(wsfd, buffer, buflen); 152 if (nwritten < 0) 153 err(EXIT_FAILURE, "%s", ofile); 154 if (nwritten != buflen) 155 errx(EXIT_FAILURE, "%s: partial write", ofile); 156 close(wsfd); 157} 158 159int 160write_header(const char *filename, struct wsdisplay_font *f, 161 char *buffer, int buflen) 162{ 163 FILE *output; 164 int i, j, x, y, idx, pxls, left; 165 char fontname[64], c, msk; 166 167 /* now output as a header file */ 168 snprintf(fontname, sizeof(fontname), "%s_%dx%d", f->name, 169 f->fontwidth, f->fontheight); 170 for (i = 0; i < strlen(fontname); i++) { 171 if (isblank((int)fontname[i])) 172 fontname[i]='_'; 173 } 174 if ((output = fopen(filename, "w")) == NULL) { 175 fprintf(stderr, "Can't open output file %s\n", filename); 176 return -1; 177 } 178 if (commentptr > 0) { 179 fprintf(output, "/*\n"); 180 fputs(commentbuf, output); 181 fprintf(output, "*/\n\n"); 182 } 183 184 fprintf(output, "static u_char %s_data[];\n", fontname); 185 fprintf(output, "\n"); 186 fprintf(output, "static struct wsdisplay_font %s = {\n", fontname); 187 fprintf(output, "\t\"%s\",\t\t\t/* typeface name */\n", f->name); 188 fprintf(output, "\t%d,\t\t\t\t/* firstchar */\n", f->firstchar); 189 fprintf(output, "\t%d,\t\t\t\t/* numchars */\n", f->numchars); 190 fprintf(output, "\t%d,\t\t\t\t/* encoding */\n", f->encoding); 191 fprintf(output, "\t%d,\t\t\t\t/* fontwidth */\n", f->fontwidth); 192 fprintf(output, "\t%d,\t\t\t\t/* fontheight */\n", f->fontheight); 193 fprintf(output, "\t%d,\t\t\t\t/* stride */\n", f->stride); 194 fprintf(output, "\tWSDISPLAY_FONTORDER_L2R,\t/* bit order */\n"); 195 fprintf(output, "\tWSDISPLAY_FONTORDER_L2R,\t/* byte order */\n"); 196 fprintf(output, "\t%s_data\t\t/* data */\n", fontname); 197 fprintf(output, "};\n\n"); 198 fprintf(output, "static u_char %s_data[] = {\n", fontname); 199 for (i = f->firstchar; i < f->firstchar + f->numchars; i++) { 200 fprintf(output, "\t/* %d */\n", i); 201 idx = i * f->stride * f->fontheight; 202 for (y = 0; y < f->fontheight; y++) { 203 for (x = 0; x < f->stride; x++) { 204 fprintf(output, "0x%02x, ",buffer[idx + x]); 205 } 206 fprintf(output, "/* "); 207 pxls = f->fontwidth; 208 for (x = 0; x < f->stride; x++) { 209 c = buffer[idx + x]; 210 msk = 0x80; 211 left = pxls > 8 ? 8 : pxls; 212 for (j = 0; j < left; j++) { 213 fprintf(output, "%s", 214 (c & msk) != 0 ? "[]" : ". "); 215 msk = msk >> 1; 216 } 217 pxls -= 8; 218 } 219 fprintf(output, " */\n"); 220 221 idx += f->stride; 222 } 223 } 224 fprintf(output, "};\n"); 225 fclose(output); 226 return 0; 227} 228 229void 230interpret(FILE *foo) 231{ 232 char line[128], *arg, name[64] = "foo", *buffer; 233 int buflen = -1; 234 int len, in_char = 0, current = -1, stride = 0, charsize = 0; 235 int width, height, x, y, num; 236 int first = 255, last = 0; 237 int left, top, lines; 238 int bl = 255, bt = 255, br = -1, bb = -1; 239 struct wsdisplay_font f; 240 int status; 241 242 while (fgets(line, sizeof(line), foo) != NULL) { 243 int i = 0; 244 /* separate keyword from parameters */ 245 len = strlen(line); 246 while (!isspace(line[i]) && (i < len)) i++; 247 line[i] = 0; 248 arg = &line[i + 1]; 249 i = 0; 250 len = strlen(arg); 251 /* get rid of garbage */ 252 while ((!iscntrl(arg[i])) && (arg[i] != 0)) { 253 i++; 254 } 255 arg[i] = 0; 256 if (strcmp(line, "FAMILY_NAME") == 0) { 257 /* cut off quotation marks */ 258 strncpy(name, arg + 1, 64); 259 name[strlen(name) - 1] = 0; 260 if (verbose) printf("name: %s\n", name); 261 } else if (strcmp(line, "COMMENT") == 0) { 262 commentptr += snprintf(&commentbuf[commentptr], 263 2048 - commentptr, 264 "%s\n", arg); 265 } else if (strcmp(line, "FONTBOUNDINGBOX") == 0) { 266 int res; 267 res = sscanf(arg, "%d %d %d %d", 268 &width, &height, &x, &y); 269 stride = (width + 7) >> 3; 270 if (verbose) printf("box %d x %d\n", width, height); 271 if (stride > 2) { 272 err(EXIT_FAILURE, 273 "no fonts wider than 16 work for now\n"); 274 } 275 charsize = height * stride; 276 buflen = 256 * charsize; 277 buffer = calloc(1, buflen); 278 if (buffer == NULL) { 279 err(EXIT_FAILURE, 280 "failed to allocate %dKB for glyphs\n", 281 buflen); 282 } 283 } else if (strcmp(line, "CHARS") == 0) { 284 if (sscanf(arg, "%d", &num) == 1) 285 if (verbose) 286 printf("number of characters: %d\n", num); 287 } else if (strcmp(line, "STARTCHAR") == 0) { 288 in_char = 1; 289 } else if (strcmp(line, "ENDCHAR") == 0) { 290 in_char = 0; 291 current = -1; 292 } else if (strcmp(line, "ENCODING") == 0) { 293 if (sscanf(arg, "%d", ¤t) == 1) { 294 if (current >= 0 && current < 256) { 295 if (current < first) first = current; 296 if (current > last) last = current; 297 if (dump) printf("glyph %d\n", current); 298 } 299 } 300 } else if (strcmp(line, "BBX") == 0) { 301 int cx, cy, cwi, che; 302 if (sscanf(arg, "%d %d %d %d", &cwi, &che, &cx, &cy) 303 == 4) { 304 left = cx; 305 lines = che; 306 top = height + y - che - cy; 307 if (left < bl) bl = left; 308 if (top < bt) bt = top; 309 if ((left + cwi) > br) br = left + cwi; 310 if ((top + che) > bb) bb = top + che; 311 if(dump && verbose) printf("top %d left %d\n", top, left); 312 } 313 } else if (strcmp(line, "BITMAP") == 0) { 314 int i, j, k, l; 315 char num[32]; 316 char *gptr = &buffer[charsize * current]; 317 char *bptr = gptr + top; 318 uint16_t *bptr16 = (uint16_t *)gptr; 319 bptr16 += top; 320 /* see if the character is in range */ 321 if ((current < 0) || (current > 255)) continue; 322 /* now we read & render the character */ 323 for (i = 0; i < lines; i++) { 324 fgets(num, 32, foo); 325 sscanf(num, "%x", &l); 326 if ((stride) == 2 && (strlen(num) < 4)) 327 l = l << 8; 328 l = l >> left; 329 if (stride == 1) { 330 *bptr = l; 331 bptr++; 332 } else { 333 *bptr16 = htobe16(l); 334 bptr16++; 335 } 336 } 337 if (dump) { 338 gptr = &buffer[charsize * current]; 339 for (i = 0; i < height; i++) { 340 dump_line(gptr, stride); 341 gptr += stride; 342 } 343 } 344 } 345 } 346 if (verbose) { 347 printf("range %d to %d\n", first, last); 348 printf("encoding: %s\n", encname[encoding]); 349 printf("actual box: %d %d %d %d\n", bl, bt, br, bb); 350 } 351 352 /* now stuff it into a something wsfont understands */ 353 f.fontwidth = width /*(width + 3) & ~3*/; 354 f.fontheight = height; 355 f.firstchar = first; 356 f.numchars = last - first + 1; 357 f.stride = stride; 358 f.encoding = encoding; 359 if (fontname[0] == 0) { 360 f.name = name; 361 } else f.name = fontname; 362 f.bitorder = WSDISPLAY_FONTORDER_L2R; 363 f.byteorder = WSDISPLAY_FONTORDER_L2R; 364 f.data = &buffer[first * charsize]; 365 366 if (ofile == NULL) { 367 int fdev = open("/dev/wsfont", O_RDWR, 0); 368 if (fdev < 0) 369 err(EXIT_FAILURE, "/dev/wsfont"); 370 status = ioctl(fdev, WSDISPLAYIO_LDFONT, &f); 371 if (status != 0) 372 err(EXIT_FAILURE, "WSDISPLAYIO_LDFONT"); 373 close(fdev); 374 } 375 else { 376 if (header == 0) { 377 write_wsf(ofile, &f, buffer, buflen); 378 } else 379 write_header(ofile, &f, buffer, buflen); 380 } 381} 382 383__dead void 384usage() 385{ 386 fprintf(stderr, "usage: bdfload [-vdh] [-e encoding] [-N name] [-o ofile.wsf] font.bdf\n"); 387 exit(EXIT_FAILURE); 388} 389 390int 391main(int argc, char *argv[]) 392{ 393 FILE *foo; 394 const char *encname = NULL; 395 396 int c; 397 while ((c = getopt(argc, argv, "e:o:N:vdh")) != -1) { 398 switch (c) { 399 400 /* font encoding */ 401 case 'e': 402 if (encname != NULL) 403 usage(); 404 encname = optarg; 405 break; 406 407 /* output file name */ 408 case 'o': 409 if (ofile != NULL) 410 usage(); 411 ofile = optarg; 412 break; 413 414 case 'v': 415 verbose = 1; 416 break; 417 418 case 'd': 419 dump = 1; 420 break; 421 422 case 'h': 423 header = 1; 424 break; 425 case 'N': 426 strncpy(fontname, optarg, 64); 427 printf("given name: %s\n", fontname); 428 break; 429 case '?': /* FALLTHROUGH */ 430 default: 431 usage(); 432 } 433 } 434 435 argc -= optind; 436 argv += optind; 437 438 if (encname == NULL) { 439 encoding = WSDISPLAY_FONTENC_ISO; 440 } 441 else { 442 for (const struct encmap *e = encmap; e->name; ++e) { 443 if (strcmp(e->name, encname) == 0) { 444 encoding = e->encoding; 445 break; 446 } 447 } 448 } 449 450 /* get encoding from the bdf file? */ 451 if (encoding == -1) 452 encoding = WSDISPLAY_FONTENC_ISO; 453 454 if (argc == 0) 455 usage(); 456 457 const char *bdfname = argv[0]; 458 foo = fopen(bdfname, "r"); 459 if (foo == NULL) 460 err(EXIT_FAILURE, "%s", bdfname); 461 462 interpret(foo); 463 return EXIT_SUCCESS; 464} 465