bdfload.c revision ec211365
1/* $NetBSD: bdfload.c,v 1.7 2022/08/16 21:52:00 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; 102 103void 104dump_line(char *gptr, int stride) 105{ 106 int i, j, msk, c; 107 108 for (i = 0; i < stride; i++) { 109 c = gptr[i]; 110 msk = 0x80; 111 for (j = 0; j < 8; j++) { 112 putchar((c & msk) != 0 ? '#' : ' '); 113 msk = msk >> 1; 114 } 115 } 116 printf("\n"); 117} 118 119void 120interpret(FILE *foo) 121{ 122 char line[128], *arg, name[64] = "foop", *buffer; 123 int buflen = -1; 124 int len, in_char = 0, current = -1, stride = 0, charsize = 0; 125 int width, height, x, y, num; 126 int first = 255, last = 0; 127 int left, top, lines; 128 int bl = 255, bt = 255, br = -1, bb = -1; 129 struct wsdisplay_font f; 130 int status; 131 132 while (fgets(line, sizeof(line), foo) != NULL) { 133 int i = 0; 134 /* separate keyword from parameters */ 135 len = strlen(line); 136 while (!isspace(line[i]) && (i < len)) i++; 137 line[i] = 0; 138 arg = &line[i + 1]; 139 i = 0; 140 len = strlen(arg); 141 /* get rid of garbage */ 142 while ((!iscntrl(arg[i])) && (arg[i] != 0)) { 143 i++; 144 } 145 arg[i] = 0; 146 if (strcmp(line, "FAMILY_NAME") == 0) { 147 /* cut off quotation marks */ 148 strncpy(name, arg + 1, 64); 149 name[strlen(name) - 1] = 0; 150 if (verbose) printf("name: %s\n", name); 151 } else if (strcmp(line, "FONTBOUNDINGBOX") == 0) { 152 int res; 153 res = sscanf(arg, "%d %d %d %d", 154 &width, &height, &x, &y); 155 stride = (width + 7) >> 3; 156 if (verbose) printf("box %d x %d\n", width, height); 157 if (stride > 2) { 158 err(EXIT_FAILURE, 159 "no fonts wider than 16 work for now\n"); 160 } 161 charsize = height * stride; 162 buflen = 256 * charsize; 163 buffer = calloc(1, buflen); 164 if (buffer == NULL) { 165 err(EXIT_FAILURE, 166 "failed to allocate %dKB for glyphs\n", 167 buflen); 168 } 169 } else if (strcmp(line, "CHARS") == 0) { 170 if (sscanf(arg, "%d", &num) == 1) 171 if (verbose) 172 printf("number of characters: %d\n", num); 173 } else if (strcmp(line, "STARTCHAR") == 0) { 174 in_char = 1; 175 } else if (strcmp(line, "ENDCHAR") == 0) { 176 in_char = 0; 177 current = -1; 178 } else if (strcmp(line, "ENCODING") == 0) { 179 if (sscanf(arg, "%d", ¤t) == 1) { 180 if (current >= 0 && current < 256) { 181 if (current < first) first = current; 182 if (current > last) last = current; 183 if (dump) printf("glyph %d\n", current); 184 } 185 } 186 } else if (strcmp(line, "BBX") == 0) { 187 int cx, cy, cwi, che; 188 if (sscanf(arg, "%d %d %d %d", &cwi, &che, &cx, &cy) 189 == 4) { 190 left = cx; 191 lines = che; 192 top = height + y - che - cy; 193 if (left < bl) bl = left; 194 if (top < bt) bt = top; 195 if ((left + cwi) > br) br = left + cwi; 196 if ((top + che) > bb) bb = top + che; 197 if(dump && verbose) printf("top %d left %d\n", top, left); 198 } 199 } else if (strcmp(line, "BITMAP") == 0) { 200 int i, j, k, l; 201 char num[32]; 202 char *gptr = &buffer[charsize * current]; 203 char *bptr = gptr + top; 204 uint16_t *bptr16 = (uint16_t *)gptr; 205 bptr16 += top; 206 /* see if the character is in range */ 207 if ((current < 0) || (current > 255)) continue; 208 /* now we read & render the character */ 209 for (i = 0; i < lines; i++) { 210 fgets(num, 32, foo); 211 sscanf(num, "%x", &l); 212 if ((stride) == 2 && (strlen(num) < 4)) 213 l = l << 8; 214 l = l >> left; 215 if (stride == 1) { 216 *bptr = l; 217 bptr++; 218 } else { 219 *bptr16 = htobe16(l); 220 bptr16++; 221 } 222 } 223 if (dump) { 224 gptr = &buffer[charsize * current]; 225 for (i = 0; i < height; i++) { 226 dump_line(gptr, stride); 227 gptr += stride; 228 } 229 } 230 } 231 } 232 if (verbose) { 233 printf("range %d to %d\n", first, last); 234 printf("encoding: %s\n", encname[encoding]); 235 printf("actual box: %d %d %d %d\n", bl, bt, br, bb); 236 } 237 238 /* now stuff it into a something wsfont understands */ 239 f.fontwidth = width /*(width + 3) & ~3*/; 240 f.fontheight = height; 241 f.firstchar = first; 242 f.numchars = last - first + 1; 243 f.stride = stride; 244 f.encoding = encoding; 245 f.name = name; 246 f.bitorder = WSDISPLAY_FONTORDER_L2R; 247 f.byteorder = WSDISPLAY_FONTORDER_L2R; 248 f.data = &buffer[first * charsize]; 249 250 if (ofile == NULL) { 251 int fdev = open("/dev/wsfont", O_RDWR, 0); 252 if (fdev < 0) 253 err(EXIT_FAILURE, "/dev/wsfont"); 254 status = ioctl(fdev, WSDISPLAYIO_LDFONT, &f); 255 if (status != 0) 256 err(EXIT_FAILURE, "WSDISPLAYIO_LDFONT"); 257 close(fdev); 258 } 259 else { 260 struct wsfthdr h; 261 262 memset(&h, 0, sizeof(h)); 263 strncpy(h.magic, "WSFT", sizeof(h.magic)); 264 strncpy(h.name, f.name, sizeof(h.name)); 265 h.firstchar = htole32(f.firstchar); 266 h.numchars = htole32(f.numchars); 267 h.encoding = htole32(f.encoding); 268 h.fontwidth = htole32(f.fontwidth); 269 h.fontheight = htole32(f.fontheight); 270 h.stride = htole32(f.stride); 271 h.bitorder = htole32(f.bitorder); 272 h.byteorder = htole32(f.byteorder); 273 274 int wsfd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0644); 275 if (wsfd < 0) 276 err(EXIT_FAILURE, "%s", ofile); 277 278 ssize_t nwritten; 279 nwritten = write(wsfd, &h, sizeof(h)); 280 if (nwritten < 0) 281 err(EXIT_FAILURE, "%s", ofile); 282 if (nwritten != sizeof(h)) 283 errx(EXIT_FAILURE, "%s: partial write", ofile); 284 285 nwritten = write(wsfd, buffer, buflen); 286 if (nwritten < 0) 287 err(EXIT_FAILURE, "%s", ofile); 288 if (nwritten != buflen) 289 errx(EXIT_FAILURE, "%s: partial write", ofile); 290 close(wsfd); 291 } 292} 293 294 295__dead void 296usage() 297{ 298 fprintf(stderr, "usage: bdfload [-vd] [-e encoding] [-o ofile.wsf] font.bdf\n"); 299 exit(EXIT_FAILURE); 300} 301 302int 303main(int argc, char *argv[]) 304{ 305 FILE *foo; 306 const char *encname = NULL; 307 308 int c; 309 while ((c = getopt(argc, argv, "e:o:vd")) != -1) { 310 switch (c) { 311 312 /* font encoding */ 313 case 'e': 314 if (encname != NULL) 315 usage(); 316 encname = optarg; 317 break; 318 319 /* output file name */ 320 case 'o': 321 if (ofile != NULL) 322 usage(); 323 ofile = optarg; 324 break; 325 326 case 'v': 327 verbose = 1; 328 break; 329 330 case 'd': 331 dump = 1; 332 break; 333 334 case '?': /* FALLTHROUGH */ 335 default: 336 usage(); 337 } 338 } 339 340 argc -= optind; 341 argv += optind; 342 343 if (encname == NULL) { 344 encoding = WSDISPLAY_FONTENC_ISO; 345 } 346 else { 347 for (const struct encmap *e = encmap; e->name; ++e) { 348 if (strcmp(e->name, encname) == 0) { 349 encoding = e->encoding; 350 break; 351 } 352 } 353 } 354 355 /* get encoding from the bdf file? */ 356 if (encoding == -1) 357 encoding = WSDISPLAY_FONTENC_ISO; 358 359 if (argc == 0) 360 usage(); 361 362 const char *bdfname = argv[0]; 363 foo = fopen(bdfname, "r"); 364 if (foo == NULL) 365 err(EXIT_FAILURE, "%s", bdfname); 366 367 interpret(foo); 368 return EXIT_SUCCESS; 369} 370