Home | History | Annotate | Line # | Download | only in bdfload
      1 /*	$NetBSD: bdfload.c,v 1.24 2026/06/06 17:58:53 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  */
     48 struct 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 
     62 const 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 	{ "iso8859",	WSDISPLAY_FONTENC_ISO },
     70 	{ "iso10646",	WSDISPLAY_FONTENC_ISO },
     71 	{ "iso-8859-1",	WSDISPLAY_FONTENC_ISO },
     72 	{ "iso-8859-2",	WSDISPLAY_FONTENC_ISO2 },
     73 	{ "iso-8859-7",	WSDISPLAY_FONTENC_ISO7 },
     74 	{ "iso2",	WSDISPLAY_FONTENC_ISO2 },
     75 	{ "iso7",	WSDISPLAY_FONTENC_ISO7 },
     76 	{ "iso8859-1",	WSDISPLAY_FONTENC_ISO },
     77 	{ "iso8859-2",	WSDISPLAY_FONTENC_ISO2 },
     78 	{ "iso8859-7",	WSDISPLAY_FONTENC_ISO7 },
     79 	{ "koi8-r",	WSDISPLAY_FONTENC_KOI8_R },
     80 	{ "koi8r",	WSDISPLAY_FONTENC_KOI8_R },
     81 	{ "latin-1",	WSDISPLAY_FONTENC_ISO },
     82 	{ "latin-2",	WSDISPLAY_FONTENC_ISO2 },
     83 	{ "latin1",	WSDISPLAY_FONTENC_ISO },
     84 	{ "latin2",	WSDISPLAY_FONTENC_ISO2 },
     85 	{ "pcvt",	WSDISPLAY_FONTENC_PCVT },
     86 	{ NULL, -1 }
     87 };
     88 
     89 const char * const encname[] = {
     90 #define _ENC(_e) [_e] = #_e
     91 	_ENC(WSDISPLAY_FONTENC_ISO),
     92 	_ENC(WSDISPLAY_FONTENC_IBM),
     93 	_ENC(WSDISPLAY_FONTENC_PCVT),
     94 	_ENC(WSDISPLAY_FONTENC_ISO7),
     95 	_ENC(WSDISPLAY_FONTENC_ISO2),
     96 	_ENC(WSDISPLAY_FONTENC_KOI8_R),
     97 };
     98 
     99 
    100 const char *ofile = NULL;
    101 int encoding = -1;
    102 int verbose = 0;
    103 int dump = 0;
    104 int header = 0;
    105 int force = 0;
    106 int scale = 0;
    107 int dub = 0;
    108 int smoothe = 0;
    109 char commentbuf[2048] = "";
    110 int commentptr = 0;
    111 char fontname[64] = "";
    112 char *names[256];
    113 
    114 void
    115 dump_line(char *gptr, int stride)
    116 {
    117 	int i, j, msk, c;
    118 
    119 	for (i = 0; i < stride; i++) {
    120 		c = gptr[i];
    121 		msk = 0x80;
    122 		for (j = 0; j < 8; j++) {
    123 			putchar((c & msk) != 0 ? '#' : ' ');
    124 			msk = msk >> 1;
    125 		}
    126 	}
    127 	printf("\n");
    128 }
    129 
    130 void
    131 write_wsf(const char *oname, struct wsdisplay_font *f)
    132 {
    133 	struct wsfthdr h;
    134 	uint8_t *buffer = f->data;
    135 	int buflen = f->numchars * f->stride * f->fontheight;
    136 
    137 	memset(&h, 0, sizeof(h));
    138 	strncpy(h.magic, "WSFT", sizeof(h.magic));
    139 	strncpy(h.name, f->name, sizeof(h.name));
    140 	h.firstchar = htole32(f->firstchar);
    141 	h.numchars = htole32(f->numchars);
    142 	h.encoding = htole32(f->encoding);
    143 	h.fontwidth = htole32(f->fontwidth);
    144 	h.fontheight = htole32(f->fontheight);
    145 	h.stride = htole32(f->stride);
    146 	h.bitorder = htole32(f->bitorder);
    147 	h.byteorder = htole32(f->byteorder);
    148 
    149 	int wsfd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    150 	if (wsfd < 0)
    151 		err(EXIT_FAILURE, "%s", ofile);
    152 
    153 	ssize_t nwritten;
    154 	nwritten = write(wsfd, &h, sizeof(h));
    155 	if (nwritten < 0)
    156 		err(EXIT_FAILURE, "%s", ofile);
    157 	if (nwritten != sizeof(h))
    158 		errx(EXIT_FAILURE, "%s: partial write", ofile);
    159 
    160 	nwritten = write(wsfd, buffer, buflen);
    161 	if (nwritten < 0)
    162 		err(EXIT_FAILURE, "%s", ofile);
    163 	if (nwritten != buflen)
    164 		errx(EXIT_FAILURE, "%s: partial write", ofile);
    165 	close(wsfd);
    166 }
    167 
    168 int
    169 write_header(const char *filename, struct wsdisplay_font *f)
    170 {
    171 	FILE *output;
    172 	uint8_t *buffer = f->data;
    173 	uint8_t c, msk;
    174 	int i, j, x, y, idx, pxls, left;
    175 	char name[64];
    176 
    177 	/* now output as a header file */
    178 	snprintf(name, sizeof(name), "%s_%dx%d", f->name,
    179 	    f->fontwidth, f->fontheight);
    180 	for (i = 0; i < strlen(name); i++) {
    181 		if (isblank((unsigned char)name[i]))
    182 			name[i] = '_';
    183 	}
    184 	if ((output = fopen(filename, "w")) == NULL) {
    185 		warn("Can't open output file `%s'", filename);
    186 		return -1;
    187 	}
    188 	if (commentptr > 0) {
    189 		fprintf(output, "/*\n");
    190 		fputs(commentbuf, output);
    191 		fprintf(output, "*/\n\n");
    192 	}
    193 
    194 	fprintf(output, "static u_char %s_data[];\n", name);
    195 	fprintf(output, "\n");
    196 	fprintf(output, "static struct wsdisplay_font %s = {\n", name);
    197 	fprintf(output, "\t\"%s\",\t\t\t/* typeface name */\n", f->name);
    198 	fprintf(output, "\t%d,\t\t\t\t/* firstchar */\n", f->firstchar);
    199 	fprintf(output, "\t%d,\t\t\t\t/* numchars */\n", f->numchars);
    200 	fprintf(output, "\t%d,\t\t\t\t/* encoding */\n", f->encoding);
    201 	fprintf(output, "\t%d,\t\t\t\t/* fontwidth */\n", f->fontwidth);
    202 	fprintf(output, "\t%d,\t\t\t\t/* fontheight */\n", f->fontheight);
    203 	fprintf(output, "\t%d,\t\t\t\t/* stride */\n", f->stride);
    204 	fprintf(output, "\tWSDISPLAY_FONTORDER_L2R,\t/* bit order */\n");
    205 	fprintf(output, "\tWSDISPLAY_FONTORDER_L2R,\t/* byte order */\n");
    206 	fprintf(output, "\t%s_data\t\t/* data */\n", name);
    207 	fprintf(output, "};\n\n");
    208 	fprintf(output, "static u_char %s_data[] = {\n", name);
    209 	for (i = 0; i < f->numchars; i++) {
    210 		if (names[i] != NULL) {
    211 			fprintf(output, "\t/* %d %s */\n", i + f->firstchar, names[i]);
    212 		} else
    213 			fprintf(output, "\t/* %d */\n", i + f->firstchar);
    214 		idx = i * f->stride * f->fontheight;
    215 		for (y = 0; y < f->fontheight; y++) {
    216 			for (x = 0; x < f->stride; x++) {
    217 				fprintf(output, "0x%02x, ",buffer[idx + x]);
    218 			}
    219 			fprintf(output, "/* ");
    220 			pxls = f->fontwidth;
    221 			for (x = 0; x < f->stride; x++) {
    222 				c = buffer[idx + x];
    223 				msk = 0x80;
    224 				left = pxls > 8 ? 8 : pxls;
    225 				for (j = 0; j < left; j++) {
    226 					fprintf(output, "%s",
    227 					    (c & msk) != 0 ? "[]" : ". ");
    228 					msk = msk >> 1;
    229 				}
    230 				pxls -= 8;
    231 			}
    232 			fprintf(output, " */\n");
    233 
    234 			idx += f->stride;
    235 		}
    236 	}
    237 	fprintf(output, "};\n");
    238 	fclose(output);
    239 	return 0;
    240 }
    241 
    242 void
    243 double_pixels(uint8_t *inbuf, uint16_t *outbuf, int bytes)
    244 {
    245 	int i, j;
    246 	uint16_t outmask, out;
    247 	uint8_t in, inmask;
    248 
    249 	for (i = 0; i < bytes; i++) {
    250 		inmask = 0x80;
    251 		outmask = 0xc000;
    252 		out = 0;
    253 		in = inbuf[i];
    254 		for (j = 0; j < 8; j++) {
    255 			if (in & inmask) {
    256 				out |= outmask;
    257 			}
    258 			inmask = inmask >> 1;
    259 			outmask = outmask >> 2;
    260 		}
    261 		outbuf[i * 2] = htobe16(out);
    262 	}
    263 }
    264 
    265 void fill_dup(uint16_t *buf, int lines)
    266 {
    267 	int i;
    268 	for (i = 0; i < lines; i++) {
    269 		buf[2 * i + 1] = buf[2 * i];
    270 	}
    271 }
    272 
    273 void smoothe_pixels(uint16_t *buf, int lines)
    274 {
    275 	int i, j, topright, topleft, botright, botleft;
    276 	uint16_t pmask, in, prev, next, out;
    277 	for (i = 0; i < lines; i++) {
    278 		pmask = 0xc000;
    279 		in = be16toh(buf[i]);
    280 		out = in;
    281 		prev = next = 0;
    282 		if (i > 1) prev = be16toh(buf[i - 2]);
    283 		if (i < (lines - 2)) next = be16toh(buf[i + 2]);
    284 		for (j = 0; j < 8; j++) {
    285 			if ((in & pmask) == 0) {
    286 				/* empty pixel, check surroundings */
    287 				topright = topleft = botright = botleft = 0;
    288 				if (((i & 1) == 0) && (j < 6))
    289 					topright = (((prev & pmask) == pmask) &&
    290 						    ((prev & (pmask >> 2)) != 0) &&
    291 						    ((in & (pmask >> 2)) != 0));
    292 				if (((i & 1) == 0) && (j > 0))
    293 					topleft = (((prev & pmask) == pmask) &&
    294 						    ((prev & (pmask << 2)) != 0) &&
    295 						    ((in & (pmask << 2)) != 0));
    296 				if ((i & 1) && (j < 6))
    297 					botright = (((next & pmask) == pmask) &&
    298 						    ((next & (pmask >> 2)) != 0) &&
    299 						    ((in & (pmask >> 2)) != 0));
    300 				if ((i & 1) && (j > 0))
    301 					botleft = (((next & pmask) == pmask) &&
    302 						    ((next & (pmask << 2)) != 0) &&
    303 						    ((in & (pmask << 2)) != 0));
    304 				if ((topright + topleft + botright + botleft) == 1) {
    305 					if (topleft || botleft) out |= pmask << 1;
    306 					if (topright || botright) out |= pmask >> 1;
    307 				}
    308 			}
    309 			pmask = pmask >> 2;
    310 		}
    311 		buf[i] = htobe16(out);
    312 	}
    313 }
    314 
    315 void
    316 interpret(FILE *foo)
    317 {
    318 	char line[128], *arg, name[64] = "foo", *buffer, *cbitmap;
    319 	char charname[65], *charnamebuf;
    320 	int buflen = -1, charnamebufptr = 0, j;
    321 	int in_char = 0, current = -1, stride = 0, charsize = 0;
    322 	int width, height, x, y, num;
    323 	int first = 255, last = 0;
    324 	int left, top, lines;
    325 	int bl = 255, bt = 255, br = -1, bb = -1;
    326 	struct wsdisplay_font f;
    327 	int status;
    328 
    329 	charnamebuf = malloc(64 * 256);
    330 	if (charnamebuf == 0) err(EXIT_FAILURE, "failed to allocate memory\n");
    331 	memset(charnamebuf, 0, 64 * 256);
    332 	for (j = 0; j < 256; j++) names[j] = NULL;
    333 
    334 	while (fgets(line, sizeof(line), foo) != NULL) {
    335 		size_t i = 0, len;
    336 		/* separate keyword from parameters */
    337 		len = strlen(line);
    338 		while (!isspace((unsigned char)line[i]) && i < len) i++;
    339 		line[i] = 0;
    340 		arg = &line[i + 1];
    341 		i = 0;
    342 		len = strlen(arg);
    343 		/* get rid of garbage */
    344 		while ((!iscntrl((unsigned char)arg[i])) && (arg[i] != 0)) {
    345 			i++;
    346 		}
    347 		arg[i] = 0;
    348 		if (strcmp(line, "FAMILY_NAME") == 0) {
    349 			char *q;
    350 			/* cut off quotation marks */
    351 			strlcpy(name, arg + 1, 64);
    352 			/* remove trailing " */
    353 			if ((q = strnstr(name, "\"", 64)) != NULL)
    354 				*q = 0;
    355 			if (verbose) printf("name: %s\n", name);
    356 		} else if (strcmp(line, "COMMENT") == 0) {
    357 			commentptr += snprintf(&commentbuf[commentptr],
    358 			    sizeof(commentbuf) - commentptr, "%s\n", arg);
    359 		} else if (strcmp(line, "SPACING") == 0) {
    360 			char spc[16];
    361 			int res;
    362 			res = sscanf(arg, "%s", spc);
    363 			if (res > 0) {
    364 				if (verbose) printf("spacing %s\n", spc);
    365 				if ((spc[1] == 'P') && (force == 0)) {
    366 					warnx("This is a proportional font, "
    367 					   "results are probably not suitable "
    368 					   "for console use.");
    369 					errx(EXIT_FAILURE, "Use -f to override "
    370 					    "if you want to try it anyway.");
    371 				}
    372 			}
    373 		} else if (strcmp(line, "FONTBOUNDINGBOX") == 0) {
    374 			int res;
    375 			res = sscanf(arg, "%d %d %d %d",
    376 					  &width, &height, &x, &y);
    377 			stride = (width + 7) >> 3;
    378 			if (verbose) printf("box %d x %d\n", width, height);
    379 			if (stride > 2) {
    380 				errx(EXIT_FAILURE,
    381 				    "no fonts wider than 16 work for now\n");
    382 			}
    383 			charsize = height * stride;
    384 			buflen = 257 * charsize;
    385 			buffer = calloc(1, buflen);
    386 			if (buffer == NULL) {
    387 				err(EXIT_FAILURE,
    388 				    "failed to allocate %dKB for glyphs\n",
    389 				    buflen);
    390 			}
    391 			cbitmap = buffer + 256 * charsize;
    392 		} else if (strcmp(line, "CHARS") == 0) {
    393 			if (sscanf(arg, "%d", &num) == 1)
    394 				if (verbose)
    395 				    printf("number of characters: %d\n", num);
    396 		} else if (strcmp(line, "STARTCHAR") == 0) {
    397 			in_char = 1;
    398 			if (charsize <= 1) err(EXIT_FAILURE,
    399 			    "syntax error - no valid FONTBOUNDINGBOX\n");
    400 			memset(cbitmap, 0, charsize);
    401 			strlcpy(charname, arg, 64);
    402 			if (dump && (strlen(charname) > 0))
    403 				printf("name: %s\n", charname);
    404 
    405 		} else if (strcmp(line, "ENDCHAR") == 0) {
    406 			in_char = 0;
    407 			/* only commit the glyph if it's in range */
    408 			if ((current >= 0) && (current < 256)) {
    409 				memcpy(&buffer[charsize * current],
    410 				    cbitmap, charsize);
    411 				if ((strlen(charname) > 0) &&
    412 				    (charnamebufptr < 255 * 64)) {
    413 				    	char *cur;
    414 					int len;
    415 					/* copy name into buffer, keep a
    416 					 * pointer to it for later */
    417 					cur = &charnamebuf[charnamebufptr];
    418 					len = strlcpy(cur, charname, 64);
    419 					charnamebufptr += len + 1;
    420 					names[current] = cur;
    421 				}
    422 			}
    423 			current = -1;
    424 		} else if (strcmp(line, "ENCODING") == 0) {
    425 			if (sscanf(arg, "%d", &current) == 1) {
    426 				if (current >= 0 && current < 256) {
    427 					if (current < first) first = current;
    428 					if (current > last) last = current;
    429 					if (dump) printf("glyph %d\n", current);
    430 				}
    431 			}
    432 		} else if (strcmp(line, "BBX") == 0) {
    433 			int cx, cy, cwi, che;
    434 			if (sscanf(arg, "%d %d %d %d", &cwi, &che, &cx, &cy)
    435 			     == 4) {
    436 				left = cx;
    437 				lines = che;
    438 				top = height + y - che - cy;
    439 				if (left < bl) bl = left;
    440 				if (top < bt) bt = top;
    441 				if ((left + cwi) > br) br = left + cwi;
    442 				if ((top + che) > bb) bb = top + che;
    443 				if (dump && verbose)
    444 					printf("top %d left %d\n", top, left);
    445 			}
    446 		} else if (strcmp(line, "BITMAP") == 0) {
    447 			int i, j, k, l;
    448 			char num[32];
    449 			char *gptr = cbitmap;
    450 			char *bptr = gptr + top;
    451 			uint16_t *bptr16 = (uint16_t *)gptr;
    452 			bptr16 += top;
    453 			/* see if the character is in range */
    454 			if ((current < 0) || (current > 255)) continue;
    455 			/* now we read & render the character */
    456 			for (i = 0; i < lines; i++) {
    457 				fgets(num, 32, foo);
    458 				sscanf(num, "%x", &l);
    459 				if ((stride) == 2 && (strlen(num) < 4))
    460 					l = l << 8;
    461 				l = l >> left;
    462 				if (stride == 1) {
    463 					*bptr = l;
    464 					bptr++;
    465 				} else {
    466 					*bptr16 = htobe16(l);
    467 					bptr16++;
    468 				}
    469 			}
    470 			if (dump) {
    471 				gptr = cbitmap;
    472 				for (i = 0; i < height; i++) {
    473 					dump_line(gptr, stride);
    474 					gptr += stride;
    475 				}
    476 			}
    477 		}
    478 	}
    479 	if (verbose) {
    480 		printf("range %d to %d\n", first, last);
    481 		printf("encoding: %s\n", encname[encoding]);
    482 		printf("actual box: %d %d %d %d\n", bl, bt, br, bb);
    483 	}
    484 
    485 	/* now stuff it into a something wsfont understands */
    486 	f.firstchar = first;
    487 	f.numchars = last - first + 1;
    488 	f.encoding = encoding;
    489 	if (fontname[0] == 0) {
    490 		f.name = name;
    491 	} else f.name = fontname;
    492 	f.bitorder = WSDISPLAY_FONTORDER_L2R;
    493 	f.byteorder = WSDISPLAY_FONTORDER_L2R;
    494 
    495 	if (scale) {
    496 		uint16_t *outbuf;
    497 		uint8_t *inbuf;
    498 		int i;
    499 
    500 		if (stride != 1) err(EXIT_FAILURE,
    501 		    "scaling works only on fonts up to 8 pixels wide\n");
    502 		f.fontwidth = width * 2 /*(width + 3) & ~3*/;
    503 		f.fontheight = height * 2;
    504 		f.stride = stride * 2;
    505 		outbuf = calloc(1, f.numchars * charsize * 4);
    506 		if (outbuf == NULL) err(EXIT_FAILURE,
    507 		    "failed to allocate memory for scale buffer\n");
    508 		f.data = outbuf;
    509 		inbuf = &buffer[first * charsize];
    510 		for (i = 0; i < f.numchars; i++) {
    511 			double_pixels(inbuf, outbuf, charsize);
    512 			fill_dup(outbuf, charsize);
    513 			if (smoothe) smoothe_pixels(outbuf, charsize * 2);
    514 			inbuf += charsize;
    515 			outbuf += charsize * 2;
    516 		}
    517 	} else if (dub) {
    518 		uint8_t *outbuf;
    519 		uint8_t *inbuf;
    520 		int i, j;
    521 
    522 		if (stride != 1) err(EXIT_FAILURE,
    523 		    "scaling works only on fonts up to 8 pixels wide\n");
    524 		f.fontwidth = width;
    525 		f.fontheight = height * 2;
    526 		f.stride = stride;
    527 		outbuf = calloc(1, f.numchars * charsize * 2);
    528 		if (outbuf == NULL) err(EXIT_FAILURE,
    529 		    "failed to allocate memory for scale buffer\n");
    530 		f.data = outbuf;
    531 		inbuf = &buffer[first * charsize];
    532 		for (i = 0; i < f.numchars; i++) {
    533 			for (j = 0; j < height; j++) {
    534 				outbuf[2 * j] = inbuf[j];
    535 				outbuf[2 * j + 1] = inbuf[j];
    536 			}
    537 			inbuf += charsize;
    538 			outbuf += charsize * 2;
    539 		}
    540 
    541 	} else{
    542 		f.fontwidth = width /*(width + 3) & ~3*/;
    543 		f.fontheight = height;
    544 		f.stride = stride;
    545 		f.data = &buffer[first * charsize];
    546 	}
    547 
    548 	if (ofile == NULL) {
    549 		int fdev = open("/dev/wsfont", O_RDWR, 0);
    550 		if (fdev < 0)
    551 			err(EXIT_FAILURE, "/dev/wsfont");
    552 		status = ioctl(fdev, WSDISPLAYIO_LDFONT, &f);
    553 		if (status != 0)
    554 			err(EXIT_FAILURE, "WSDISPLAYIO_LDFONT");
    555 		close(fdev);
    556 	}
    557 	else {
    558 		if (header == 0)
    559 			write_wsf(ofile, &f);
    560 		else
    561 			write_header(ofile, &f);
    562 	}
    563 }
    564 
    565 __dead void
    566 usage()
    567 {
    568 	fprintf(stderr, "Usage: %s [-vdhf2st] [-e encoding] [-N name] "
    569 	    "[-o ofile.wsf] font.bdf\n", getprogname());
    570 	exit(EXIT_FAILURE);
    571 }
    572 
    573 int
    574 main(int argc, char *argv[])
    575 {
    576 	FILE *foo;
    577 	const char *encname = NULL;
    578 
    579 	int c;
    580 	while ((c = getopt(argc, argv, "e:o:N:vdhf2st")) != -1) {
    581 		switch (c) {
    582 
    583 		/* font encoding */
    584 		case 'e':
    585 			if (encname != NULL)
    586 				usage();
    587 			encname = optarg;
    588 			break;
    589 
    590 		/* output file name */
    591 		case 'o':
    592 			if (ofile != NULL)
    593 				usage();
    594 			ofile = optarg;
    595 			break;
    596 
    597 		case 'v':
    598 			verbose = 1;
    599 			break;
    600 
    601 		case 'd':
    602 			dump = 1;
    603 			break;
    604 
    605 		case 'h':
    606 			header = 1;
    607 			break;
    608 		case 'f':
    609 			force = 1;
    610 			break;
    611 		case '2':
    612 			scale = 1;
    613 			break;
    614 		case 't':
    615 			dub = 1;
    616 			break;
    617 		case 's':
    618 			smoothe = 1;
    619 			break;
    620 		case 'N':
    621 			strncpy(fontname, optarg, 64);
    622 			break;
    623 		case '?':	/* FALLTHROUGH */
    624 		default:
    625 			usage();
    626 		}
    627 	}
    628 
    629 	argc -= optind;
    630 	argv += optind;
    631 
    632 	if (encname == NULL) {
    633 		encoding = WSDISPLAY_FONTENC_ISO;
    634 	}
    635 	else {
    636 		for (const struct encmap *e = encmap; e->name; ++e) {
    637 			if (strcmp(e->name, encname) == 0) {
    638 				encoding = e->encoding;
    639 				break;
    640 			}
    641 		}
    642 	}
    643 
    644 	/* get encoding from the bdf file? */
    645 	if (encoding == -1)
    646 		encoding = WSDISPLAY_FONTENC_ISO;
    647 
    648 	if (argc == 0)
    649 		usage();
    650 
    651 	const char *bdfname = argv[0];
    652 	foo = fopen(bdfname, "r");
    653 	if (foo == NULL)
    654 		err(EXIT_FAILURE, "%s", bdfname);
    655 
    656 	interpret(foo);
    657 	return EXIT_SUCCESS;
    658 }
    659