bdfload.c revision 53a12b5f
153a12b5fSmacallan/*	$NetBSD: bdfload.c,v 1.21 2024/01/08 18:09:33 macallan Exp $	*/
2d5f9d0dbSmacallan
3d5f9d0dbSmacallan/*
4d5f9d0dbSmacallan * Copyright (c) 2018 Michael Lorenz
5d5f9d0dbSmacallan * All rights reserved.
6d5f9d0dbSmacallan *
7d5f9d0dbSmacallan * Redistribution and use in source and binary forms, with or without
8d5f9d0dbSmacallan * modification, are permitted provided that the following conditions
9d5f9d0dbSmacallan * are met:
10d5f9d0dbSmacallan * 1. Redistributions of source code must retain the above copyright
11d5f9d0dbSmacallan *    notice, this list of conditions and the following disclaimer.
12d5f9d0dbSmacallan * 2. Redistributions in binary form must reproduce the above copyright
13d5f9d0dbSmacallan *    notice, this list of conditions and the following disclaimer in the
14d5f9d0dbSmacallan *    documentation and/or other materials provided with the distribution.
15d5f9d0dbSmacallan *
16d5f9d0dbSmacallan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17d5f9d0dbSmacallan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18d5f9d0dbSmacallan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19d5f9d0dbSmacallan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20d5f9d0dbSmacallan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21d5f9d0dbSmacallan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22d5f9d0dbSmacallan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23d5f9d0dbSmacallan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24d5f9d0dbSmacallan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25d5f9d0dbSmacallan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26d5f9d0dbSmacallan */
27d5f9d0dbSmacallan
28d5f9d0dbSmacallan/*
29d5f9d0dbSmacallan * a crude BDF loader for wsdisplay
30d5f9d0dbSmacallan */
31d5f9d0dbSmacallan
32d5f9d0dbSmacallan#include <stdlib.h>
33d5f9d0dbSmacallan#include <stdio.h>
34d5f9d0dbSmacallan#include <fcntl.h>
35d5f9d0dbSmacallan#include <unistd.h>
36d5f9d0dbSmacallan#include <string.h>
37d5f9d0dbSmacallan#include <errno.h>
38d5f9d0dbSmacallan#include <ctype.h>
39d5f9d0dbSmacallan#include <sys/ioctl.h>
40d5f9d0dbSmacallan#include <err.h>
41d5f9d0dbSmacallan
42d5f9d0dbSmacallan#include <dev/wscons/wsconsio.h>
43d5f9d0dbSmacallan
442b154882Suwe/*
452b154882Suwe * wsdisplay_font but with strings embedded and integer fields in
462b154882Suwe * little endian
472b154882Suwe */
482b154882Suwestruct wsfthdr {
492b154882Suwe	char magic[4];		/* "WSFT" */
502b154882Suwe	char name[64];
512b154882Suwe	uint32_t firstchar;
522b154882Suwe	uint32_t numchars;
532b154882Suwe	uint32_t encoding;
542b154882Suwe	uint32_t fontwidth;
552b154882Suwe	uint32_t fontheight;
562b154882Suwe	uint32_t stride;
572b154882Suwe	uint32_t bitorder;
582b154882Suwe	uint32_t byteorder;
592b154882Suwe};
602b154882Suwe
612b154882Suwe
622b154882Suweconst struct encmap {
632b154882Suwe	const char *name;
642b154882Suwe	int encoding;
652b154882Suwe} encmap[] = {
662b154882Suwe	{ "cp437",	WSDISPLAY_FONTENC_IBM },
672b154882Suwe	{ "ibm",	WSDISPLAY_FONTENC_IBM },
682b154882Suwe	{ "iso",	WSDISPLAY_FONTENC_ISO },
69a5a7ac3fSmacallan	{ "iso8859",	WSDISPLAY_FONTENC_ISO },
70a5a7ac3fSmacallan	{ "iso10646",	WSDISPLAY_FONTENC_ISO },
712b154882Suwe	{ "iso-8859-1",	WSDISPLAY_FONTENC_ISO },
722b154882Suwe	{ "iso-8859-2",	WSDISPLAY_FONTENC_ISO2 },
732b154882Suwe	{ "iso-8859-7",	WSDISPLAY_FONTENC_ISO7 },
742b154882Suwe	{ "iso2",	WSDISPLAY_FONTENC_ISO2 },
752b154882Suwe	{ "iso7",	WSDISPLAY_FONTENC_ISO7 },
762b154882Suwe	{ "iso8859-1",	WSDISPLAY_FONTENC_ISO },
772b154882Suwe	{ "iso8859-2",	WSDISPLAY_FONTENC_ISO2 },
782b154882Suwe	{ "iso8859-7",	WSDISPLAY_FONTENC_ISO7 },
792b154882Suwe	{ "koi8-r",	WSDISPLAY_FONTENC_KOI8_R },
802b154882Suwe	{ "koi8r",	WSDISPLAY_FONTENC_KOI8_R },
812b154882Suwe	{ "latin-1",	WSDISPLAY_FONTENC_ISO },
822b154882Suwe	{ "latin-2",	WSDISPLAY_FONTENC_ISO2 },
832b154882Suwe	{ "latin1",	WSDISPLAY_FONTENC_ISO },
842b154882Suwe	{ "latin2",	WSDISPLAY_FONTENC_ISO2 },
852b154882Suwe	{ "pcvt",	WSDISPLAY_FONTENC_PCVT },
862b154882Suwe	{ NULL, -1 }
872b154882Suwe};
882b154882Suwe
892b154882Suweconst char * const encname[] = {
902b154882Suwe#define _ENC(_e) [_e] = #_e
912b154882Suwe	_ENC(WSDISPLAY_FONTENC_ISO),
922b154882Suwe	_ENC(WSDISPLAY_FONTENC_IBM),
932b154882Suwe	_ENC(WSDISPLAY_FONTENC_PCVT),
942b154882Suwe	_ENC(WSDISPLAY_FONTENC_ISO7),
952b154882Suwe	_ENC(WSDISPLAY_FONTENC_ISO2),
962b154882Suwe	_ENC(WSDISPLAY_FONTENC_KOI8_R),
972b154882Suwe};
982b154882Suwe
992b154882Suwe
1002b154882Suweconst char *ofile = NULL;
1012b154882Suweint encoding = -1;
10261348eb3Smacallanint verbose = 0;
103554a5d78Smacallanint dump = 0;
1042d60533cSmacallanint header = 0;
105a5a7ac3fSmacallanint force = 0;
10653a12b5fSmacallanint scale = 0;
10753a12b5fSmacallanint smoothe = 0;
1087d6aaba4Smacallanchar commentbuf[2048] = "";
1097d6aaba4Smacallanint commentptr = 0;
11051bbcd86Smacallanchar fontname[64] = "";
11116ae1398Smacallanchar *names[256];
1122b154882Suwe
113554a5d78Smacallanvoid
114554a5d78Smacallandump_line(char *gptr, int stride)
115554a5d78Smacallan{
116554a5d78Smacallan	int i, j, msk, c;
117554a5d78Smacallan
118554a5d78Smacallan	for (i = 0; i < stride; i++) {
119554a5d78Smacallan		c = gptr[i];
120554a5d78Smacallan		msk = 0x80;
121554a5d78Smacallan		for (j = 0; j < 8; j++) {
122554a5d78Smacallan			putchar((c & msk) != 0 ? '#' : ' ');
123554a5d78Smacallan			msk = msk >> 1;
124554a5d78Smacallan		}
125554a5d78Smacallan	}
126ec211365Smacallan	printf("\n");
127554a5d78Smacallan}
128554a5d78Smacallan
1292d60533cSmacallanvoid
13053a12b5fSmacallanwrite_wsf(const char *oname, struct wsdisplay_font *f)
1312d60533cSmacallan{
1322d60533cSmacallan	struct wsfthdr h;
13353a12b5fSmacallan	uint8_t *buffer = f->data;
13453a12b5fSmacallan	int buflen = f->numchars * f->stride * f->fontheight;
1352d60533cSmacallan
1362d60533cSmacallan	memset(&h, 0, sizeof(h));
1372d60533cSmacallan	strncpy(h.magic, "WSFT", sizeof(h.magic));
1382d60533cSmacallan	strncpy(h.name, f->name, sizeof(h.name));
1392d60533cSmacallan	h.firstchar = htole32(f->firstchar);
1402d60533cSmacallan	h.numchars = htole32(f->numchars);
1412d60533cSmacallan	h.encoding = htole32(f->encoding);
1422d60533cSmacallan	h.fontwidth = htole32(f->fontwidth);
1432d60533cSmacallan	h.fontheight = htole32(f->fontheight);
1442d60533cSmacallan	h.stride = htole32(f->stride);
1452d60533cSmacallan	h.bitorder = htole32(f->bitorder);
1462d60533cSmacallan	h.byteorder = htole32(f->byteorder);
1472d60533cSmacallan
1482d60533cSmacallan	int wsfd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1492d60533cSmacallan	if (wsfd < 0)
1502d60533cSmacallan		err(EXIT_FAILURE, "%s", ofile);
1512d60533cSmacallan
1522d60533cSmacallan	ssize_t nwritten;
1532d60533cSmacallan	nwritten = write(wsfd, &h, sizeof(h));
1542d60533cSmacallan	if (nwritten < 0)
1552d60533cSmacallan		err(EXIT_FAILURE, "%s", ofile);
1562d60533cSmacallan	if (nwritten != sizeof(h))
1572d60533cSmacallan		errx(EXIT_FAILURE, "%s: partial write", ofile);
1582d60533cSmacallan
1592d60533cSmacallan	nwritten = write(wsfd, buffer, buflen);
1602d60533cSmacallan	if (nwritten < 0)
1612d60533cSmacallan		err(EXIT_FAILURE, "%s", ofile);
1622d60533cSmacallan	if (nwritten != buflen)
1632d60533cSmacallan		errx(EXIT_FAILURE, "%s: partial write", ofile);
1642d60533cSmacallan	close(wsfd);
1652d60533cSmacallan}
1662d60533cSmacallan
1672d60533cSmacallanint
16853a12b5fSmacallanwrite_header(const char *filename, struct wsdisplay_font *f)
1692d60533cSmacallan{
1702d60533cSmacallan	FILE *output;
17153a12b5fSmacallan	char *buffer = f->data;
1727dd7205fSmacallan	int i, j, x, y, idx, pxls, left;
17343d302b1Smacallan	char name[64], c, msk;
1742d60533cSmacallan
1752d60533cSmacallan	/* now output as a header file */
17643d302b1Smacallan	snprintf(name, sizeof(name), "%s_%dx%d", f->name,
1772d60533cSmacallan	    f->fontwidth, f->fontheight);
17843d302b1Smacallan	for (i = 0; i < strlen(name); i++) {
1796c735b96Schristos		if (isblank((unsigned char)name[i]))
1806c735b96Schristos			name[i] = '_';
1812d60533cSmacallan	}
1822d60533cSmacallan	if ((output = fopen(filename, "w")) == NULL) {
1836c735b96Schristos		warn("Can't open output file `%s'", filename);
1842d60533cSmacallan		return -1;
1852d60533cSmacallan	}
1867d6aaba4Smacallan	if (commentptr > 0) {
1877d6aaba4Smacallan		fprintf(output, "/*\n");
1887d6aaba4Smacallan		fputs(commentbuf, output);
1897d6aaba4Smacallan		fprintf(output, "*/\n\n");
1907d6aaba4Smacallan	}
1917d6aaba4Smacallan
19243d302b1Smacallan	fprintf(output, "static u_char %s_data[];\n", name);
1932d60533cSmacallan	fprintf(output, "\n");
19443d302b1Smacallan	fprintf(output, "static struct wsdisplay_font %s = {\n", name);
19551bbcd86Smacallan	fprintf(output, "\t\"%s\",\t\t\t/* typeface name */\n", f->name);
1962d60533cSmacallan	fprintf(output, "\t%d,\t\t\t\t/* firstchar */\n", f->firstchar);
1972d60533cSmacallan	fprintf(output, "\t%d,\t\t\t\t/* numchars */\n", f->numchars);
1982d60533cSmacallan	fprintf(output, "\t%d,\t\t\t\t/* encoding */\n", f->encoding);
1992d60533cSmacallan	fprintf(output, "\t%d,\t\t\t\t/* fontwidth */\n", f->fontwidth);
2002d60533cSmacallan	fprintf(output, "\t%d,\t\t\t\t/* fontheight */\n", f->fontheight);
2012d60533cSmacallan	fprintf(output, "\t%d,\t\t\t\t/* stride */\n", f->stride);
2022d60533cSmacallan	fprintf(output, "\tWSDISPLAY_FONTORDER_L2R,\t/* bit order */\n");
2032d60533cSmacallan	fprintf(output, "\tWSDISPLAY_FONTORDER_L2R,\t/* byte order */\n");
20443d302b1Smacallan	fprintf(output, "\t%s_data\t\t/* data */\n", name);
2052d60533cSmacallan	fprintf(output, "};\n\n");
20643d302b1Smacallan	fprintf(output, "static u_char %s_data[] = {\n", name);
20753a12b5fSmacallan	for (i = 0; i < f->numchars; i++) {
20816ae1398Smacallan		if (names[i] != NULL) {
20953a12b5fSmacallan			fprintf(output, "\t/* %d %s */\n", i + f->firstchar, names[i]);
21016ae1398Smacallan		} else
21153a12b5fSmacallan			fprintf(output, "\t/* %d */\n", i + f->firstchar);
2122d60533cSmacallan		idx = i * f->stride * f->fontheight;
2132d60533cSmacallan		for (y = 0; y < f->fontheight; y++) {
2142d60533cSmacallan			for (x = 0; x < f->stride; x++) {
2152d60533cSmacallan				fprintf(output, "0x%02x, ",buffer[idx + x]);
2162d60533cSmacallan			}
2172d60533cSmacallan			fprintf(output, "/* ");
2187dd7205fSmacallan			pxls = f->fontwidth;
2192d60533cSmacallan			for (x = 0; x < f->stride; x++) {
2202d60533cSmacallan				c = buffer[idx + x];
2212d60533cSmacallan				msk = 0x80;
2227dd7205fSmacallan				left = pxls > 8 ? 8 : pxls;
2237dd7205fSmacallan				for (j = 0; j < left; j++) {
224426ebb7fSmacallan					fprintf(output, "%s",
225426ebb7fSmacallan					    (c & msk) != 0 ? "[]" : ". ");
2262d60533cSmacallan					msk = msk >> 1;
2272d60533cSmacallan				}
2287dd7205fSmacallan				pxls -= 8;
2292d60533cSmacallan			}
2302d60533cSmacallan			fprintf(output, " */\n");
2312d60533cSmacallan
2322d60533cSmacallan			idx += f->stride;
2332d60533cSmacallan		}
2342d60533cSmacallan	}
2352d60533cSmacallan	fprintf(output, "};\n");
2362d60533cSmacallan	fclose(output);
2372d60533cSmacallan	return 0;
2382d60533cSmacallan}
2392d60533cSmacallan
24053a12b5fSmacallanvoid
24153a12b5fSmacallandouble_pixels(uint8_t *inbuf, uint16_t *outbuf, int bytes)
24253a12b5fSmacallan{
24353a12b5fSmacallan	int i, j;
24453a12b5fSmacallan	uint16_t outmask, out;
24553a12b5fSmacallan	uint8_t in, inmask;
24653a12b5fSmacallan
24753a12b5fSmacallan	for (i = 0; i < bytes; i++) {
24853a12b5fSmacallan		inmask = 0x80;
24953a12b5fSmacallan		outmask = 0xc000;
25053a12b5fSmacallan		out = 0;
25153a12b5fSmacallan		in = inbuf[i];
25253a12b5fSmacallan		for (j = 0; j < 8; j++) {
25353a12b5fSmacallan			if (in & inmask) {
25453a12b5fSmacallan				out |= outmask;
25553a12b5fSmacallan			}
25653a12b5fSmacallan			inmask = inmask >> 1;
25753a12b5fSmacallan			outmask = outmask >> 2;
25853a12b5fSmacallan		}
25953a12b5fSmacallan		outbuf[i * 2] = htobe16(out);
26053a12b5fSmacallan	}
26153a12b5fSmacallan}
26253a12b5fSmacallan
26353a12b5fSmacallanvoid fill_dup(uint16_t *buf, int lines)
26453a12b5fSmacallan{
26553a12b5fSmacallan	int i;
26653a12b5fSmacallan	for (i = 0; i < lines; i++) {
26753a12b5fSmacallan		buf[2 * i + 1] = buf[2 * i];
26853a12b5fSmacallan	}
26953a12b5fSmacallan}
27053a12b5fSmacallan
27153a12b5fSmacallanvoid smoothe_pixels(uint16_t *buf, int lines)
27253a12b5fSmacallan{
27353a12b5fSmacallan	int i, j, topright, topleft, botright, botleft;
27453a12b5fSmacallan	uint16_t pmask, in, prev, next, out;
27553a12b5fSmacallan	for (i = 0; i < lines; i++) {
27653a12b5fSmacallan		pmask = 0xc000;
27753a12b5fSmacallan		in = be16toh(buf[i]);
27853a12b5fSmacallan		out = in;
27953a12b5fSmacallan		prev = next = 0;
28053a12b5fSmacallan		if (i > 1) prev = be16toh(buf[i - 2]);
28153a12b5fSmacallan		if (i < (lines - 2)) next = be16toh(buf[i + 2]);
28253a12b5fSmacallan		for (j = 0; j < 8; j++) {
28353a12b5fSmacallan			if ((in & pmask) == 0) {
28453a12b5fSmacallan				/* empty pixel, check surroundings */
28553a12b5fSmacallan				topright = topleft = botright = botleft = 0;
28653a12b5fSmacallan				if (((i & 1) == 0) && (j < 6))
28753a12b5fSmacallan					topright = (((prev & pmask) == pmask) &&
28853a12b5fSmacallan						    ((prev & (pmask >> 2)) != 0) &&
28953a12b5fSmacallan						    ((in & (pmask >> 2)) != 0));
29053a12b5fSmacallan				if (((i & 1) == 0) && (j > 0))
29153a12b5fSmacallan					topleft = (((prev & pmask) == pmask) &&
29253a12b5fSmacallan						    ((prev & (pmask << 2)) != 0) &&
29353a12b5fSmacallan						    ((in & (pmask << 2)) != 0));
29453a12b5fSmacallan				if ((i & 1) && (j < 6))
29553a12b5fSmacallan					botright = (((next & pmask) == pmask) &&
29653a12b5fSmacallan						    ((next & (pmask >> 2)) != 0) &&
29753a12b5fSmacallan						    ((in & (pmask >> 2)) != 0));
29853a12b5fSmacallan				if ((i & 1) && (j > 0))
29953a12b5fSmacallan					botleft = (((next & pmask) == pmask) &&
30053a12b5fSmacallan						    ((next & (pmask << 2)) != 0) &&
30153a12b5fSmacallan						    ((in & (pmask << 2)) != 0));
30253a12b5fSmacallan				if ((topright + topleft + botright + botleft) == 1) {
30353a12b5fSmacallan					if (topleft || botleft) out |= pmask << 1;
30453a12b5fSmacallan					if (topright || botright) out |= pmask >> 1;
30553a12b5fSmacallan				}
30653a12b5fSmacallan			}
30753a12b5fSmacallan			pmask = pmask >> 2;
30853a12b5fSmacallan		}
30953a12b5fSmacallan		buf[i] = htobe16(out);
31053a12b5fSmacallan	}
31153a12b5fSmacallan}
31253a12b5fSmacallan
313d5f9d0dbSmacallanvoid
314d5f9d0dbSmacallaninterpret(FILE *foo)
315d5f9d0dbSmacallan{
316999c8572Smacallan	char line[128], *arg, name[64] = "foo", *buffer, *cbitmap;
31716ae1398Smacallan	char charname[65], *charnamebuf;
31816ae1398Smacallan	int buflen = -1, charnamebufptr = 0, j;
3196c735b96Schristos	int in_char = 0, current = -1, stride = 0, charsize = 0;
320d5f9d0dbSmacallan	int width, height, x, y, num;
321d5f9d0dbSmacallan	int first = 255, last = 0;
322d5f9d0dbSmacallan	int left, top, lines;
323d5f9d0dbSmacallan	int bl = 255, bt = 255, br = -1, bb = -1;
324d5f9d0dbSmacallan	struct wsdisplay_font f;
3252b154882Suwe	int status;
326d5f9d0dbSmacallan
32716ae1398Smacallan	charnamebuf = malloc(64 * 256);
32816ae1398Smacallan	if (charnamebuf == 0) err(EXIT_FAILURE, "failed to allocate memory\n");
32916ae1398Smacallan	memset(charnamebuf, 0, 64 * 256);
33016ae1398Smacallan	for (j = 0; j < 256; j++) names[j] = NULL;
33116ae1398Smacallan
332d5f9d0dbSmacallan	while (fgets(line, sizeof(line), foo) != NULL) {
3336c735b96Schristos		size_t i = 0, len;
334d5f9d0dbSmacallan		/* separate keyword from parameters */
335d5f9d0dbSmacallan		len = strlen(line);
3366c735b96Schristos		while (!isspace((unsigned char)line[i]) && i < len) i++;
337d5f9d0dbSmacallan		line[i] = 0;
338d5f9d0dbSmacallan		arg = &line[i + 1];
339d5f9d0dbSmacallan		i = 0;
340d5f9d0dbSmacallan		len = strlen(arg);
341d5f9d0dbSmacallan		/* get rid of garbage */
3426c735b96Schristos		while ((!iscntrl((unsigned char)arg[i])) && (arg[i] != 0)) {
343d5f9d0dbSmacallan			i++;
344d5f9d0dbSmacallan		}
345d5f9d0dbSmacallan		arg[i] = 0;
346d5f9d0dbSmacallan		if (strcmp(line, "FAMILY_NAME") == 0) {
347682eda17Smacallan			char *q;
348d5f9d0dbSmacallan			/* cut off quotation marks */
3496c735b96Schristos			strlcpy(name, arg + 1, 64);
350682eda17Smacallan			/* remove trailing " */
351682eda17Smacallan			if ((q = strnstr(name, "\"", 64)) != NULL)
352682eda17Smacallan				*q = 0;
35361348eb3Smacallan			if (verbose) printf("name: %s\n", name);
3547d6aaba4Smacallan		} else if (strcmp(line, "COMMENT") == 0) {
3557d6aaba4Smacallan			commentptr += snprintf(&commentbuf[commentptr],
3566c735b96Schristos			    sizeof(commentbuf) - commentptr, "%s\n", arg);
357a5a7ac3fSmacallan		} else if (strcmp(line, "SPACING") == 0) {
358a5a7ac3fSmacallan			char spc[16];
359a5a7ac3fSmacallan			int res;
360a5a7ac3fSmacallan			res = sscanf(arg, "%s", spc);
361a5a7ac3fSmacallan			if (res > 0) {
362a5a7ac3fSmacallan				if (verbose) printf("spacing %s\n", spc);
363a5a7ac3fSmacallan				if ((spc[1] == 'P') && (force == 0)) {
3646c735b96Schristos					warnx("This is a proportional font, "
3656c735b96Schristos					   "results are probably not suitable "
3666c735b96Schristos					   "for console use.");
3676c735b96Schristos					errx(EXIT_FAILURE, "Use -f to override "
3686c735b96Schristos					    "if you want to try it anyway.");
369a5a7ac3fSmacallan				}
370a5a7ac3fSmacallan			}
371d5f9d0dbSmacallan		} else if (strcmp(line, "FONTBOUNDINGBOX") == 0) {
372d5f9d0dbSmacallan			int res;
373d5f9d0dbSmacallan			res = sscanf(arg, "%d %d %d %d",
374d5f9d0dbSmacallan					  &width, &height, &x, &y);
375d5f9d0dbSmacallan			stride = (width + 7) >> 3;
37661348eb3Smacallan			if (verbose) printf("box %d x %d\n", width, height);
377d5f9d0dbSmacallan			if (stride > 2) {
3786c735b96Schristos				errx(EXIT_FAILURE,
37961348eb3Smacallan				    "no fonts wider than 16 work for now\n");
380d5f9d0dbSmacallan			}
381d5f9d0dbSmacallan			charsize = height * stride;
382999c8572Smacallan			buflen = 257 * charsize;
3832b154882Suwe			buffer = calloc(1, buflen);
384d5f9d0dbSmacallan			if (buffer == NULL) {
38561348eb3Smacallan				err(EXIT_FAILURE,
38661348eb3Smacallan				    "failed to allocate %dKB for glyphs\n",
387d5f9d0dbSmacallan				    buflen);
388ce18d260Suwe			}
389999c8572Smacallan			cbitmap = buffer + 256 * charsize;
390d5f9d0dbSmacallan		} else if (strcmp(line, "CHARS") == 0) {
391d5f9d0dbSmacallan			if (sscanf(arg, "%d", &num) == 1)
39261348eb3Smacallan				if (verbose)
39361348eb3Smacallan				    printf("number of characters: %d\n", num);
394d5f9d0dbSmacallan		} else if (strcmp(line, "STARTCHAR") == 0) {
395d5f9d0dbSmacallan			in_char = 1;
396999c8572Smacallan			if (charsize <= 1) err(EXIT_FAILURE,
397999c8572Smacallan			    "syntax error - no valid FONTBOUNDINGBOX\n");
398999c8572Smacallan			memset(cbitmap, 0, charsize);
39916ae1398Smacallan			strlcpy(charname, arg, 64);
4004ffa922fSmacallan			if (dump && (strlen(charname) > 0))
4014ffa922fSmacallan				printf("name: %s\n", charname);
4024ffa922fSmacallan
403d5f9d0dbSmacallan		} else if (strcmp(line, "ENDCHAR") == 0) {
404d5f9d0dbSmacallan			in_char = 0;
405999c8572Smacallan			/* only commit the glyph if it's in range */
406999c8572Smacallan			if ((current >= 0) && (current < 256)) {
407999c8572Smacallan				memcpy(&buffer[charsize * current],
408999c8572Smacallan				    cbitmap, charsize);
40916ae1398Smacallan				if ((strlen(charname) > 0) &&
41016ae1398Smacallan				    (charnamebufptr < 255 * 64)) {
41116ae1398Smacallan				    	char *cur;
41216ae1398Smacallan					int len;
41316ae1398Smacallan					/* copy name into buffer, keep a
41416ae1398Smacallan					 * pointer to it for later */
41516ae1398Smacallan					cur = &charnamebuf[charnamebufptr];
41616ae1398Smacallan					len = strlcpy(cur, charname, 64);
41716ae1398Smacallan					charnamebufptr += len + 1;
41816ae1398Smacallan					names[current] = cur;
41916ae1398Smacallan				}
420999c8572Smacallan			}
421d5f9d0dbSmacallan			current = -1;
422d5f9d0dbSmacallan		} else if (strcmp(line, "ENCODING") == 0) {
423d5f9d0dbSmacallan			if (sscanf(arg, "%d", &current) == 1) {
424d5f9d0dbSmacallan				if (current >= 0 && current < 256) {
425d5f9d0dbSmacallan					if (current < first) first = current;
426d5f9d0dbSmacallan					if (current > last) last = current;
427554a5d78Smacallan					if (dump) printf("glyph %d\n", current);
428d5f9d0dbSmacallan				}
429d5f9d0dbSmacallan			}
430d5f9d0dbSmacallan		} else if (strcmp(line, "BBX") == 0) {
431d5f9d0dbSmacallan			int cx, cy, cwi, che;
432d5f9d0dbSmacallan			if (sscanf(arg, "%d %d %d %d", &cwi, &che, &cx, &cy)
433d5f9d0dbSmacallan			     == 4) {
434d5f9d0dbSmacallan				left = cx;
435d5f9d0dbSmacallan				lines = che;
436d5f9d0dbSmacallan				top = height + y - che - cy;
437d5f9d0dbSmacallan				if (left < bl) bl = left;
438d5f9d0dbSmacallan				if (top < bt) bt = top;
439d5f9d0dbSmacallan				if ((left + cwi) > br) br = left + cwi;
440d5f9d0dbSmacallan				if ((top + che) > bb) bb = top + che;
4416c735b96Schristos				if (dump && verbose)
4426c735b96Schristos					printf("top %d left %d\n", top, left);
443d5f9d0dbSmacallan			}
444d5f9d0dbSmacallan		} else if (strcmp(line, "BITMAP") == 0) {
445d5f9d0dbSmacallan			int i, j, k, l;
446d5f9d0dbSmacallan			char num[32];
447999c8572Smacallan			char *gptr = cbitmap;
448d5f9d0dbSmacallan			char *bptr = gptr + top;
449d5f9d0dbSmacallan			uint16_t *bptr16 = (uint16_t *)gptr;
450d5f9d0dbSmacallan			bptr16 += top;
451d5f9d0dbSmacallan			/* see if the character is in range */
452d5f9d0dbSmacallan			if ((current < 0) || (current > 255)) continue;
453d5f9d0dbSmacallan			/* now we read & render the character */
454d5f9d0dbSmacallan			for (i = 0; i < lines; i++) {
455d5f9d0dbSmacallan				fgets(num, 32, foo);
456d5f9d0dbSmacallan				sscanf(num, "%x", &l);
457d5f9d0dbSmacallan				if ((stride) == 2 && (strlen(num) < 4))
458d5f9d0dbSmacallan					l = l << 8;
459d5f9d0dbSmacallan				l = l >> left;
460d5f9d0dbSmacallan				if (stride == 1) {
461b9e0dc8cSmacallan					*bptr = l;
462b9e0dc8cSmacallan					bptr++;
463d5f9d0dbSmacallan				} else {
464d5f9d0dbSmacallan					*bptr16 = htobe16(l);
465d5f9d0dbSmacallan					bptr16++;
466ce18d260Suwe				}
467d5f9d0dbSmacallan			}
468554a5d78Smacallan			if (dump) {
469999c8572Smacallan				gptr = cbitmap;
470554a5d78Smacallan				for (i = 0; i < height; i++) {
471554a5d78Smacallan					dump_line(gptr, stride);
472554a5d78Smacallan					gptr += stride;
473554a5d78Smacallan				}
474554a5d78Smacallan			}
475d5f9d0dbSmacallan		}
476d5f9d0dbSmacallan	}
47761348eb3Smacallan	if (verbose) {
47861348eb3Smacallan		printf("range %d to %d\n", first, last);
47961348eb3Smacallan		printf("encoding: %s\n", encname[encoding]);
48061348eb3Smacallan		printf("actual box: %d %d %d %d\n", bl, bt, br, bb);
48161348eb3Smacallan	}
4822b154882Suwe
483d5f9d0dbSmacallan	/* now stuff it into a something wsfont understands */
484d5f9d0dbSmacallan	f.firstchar = first;
4852b154882Suwe	f.numchars = last - first + 1;
4862b154882Suwe	f.encoding = encoding;
48751bbcd86Smacallan	if (fontname[0] == 0) {
48851bbcd86Smacallan		f.name = name;
48951bbcd86Smacallan	} else f.name = fontname;
490d5f9d0dbSmacallan	f.bitorder = WSDISPLAY_FONTORDER_L2R;
491d5f9d0dbSmacallan	f.byteorder = WSDISPLAY_FONTORDER_L2R;
49253a12b5fSmacallan
49353a12b5fSmacallan	if (scale) {
49453a12b5fSmacallan		uint16_t *outbuf;
49553a12b5fSmacallan		uint8_t *inbuf;
49653a12b5fSmacallan		int i;
49753a12b5fSmacallan
49853a12b5fSmacallan		if (stride != 1) err(EXIT_FAILURE,
49953a12b5fSmacallan		    "scaling works only on fonts up to 8 pixels wide\n");
50053a12b5fSmacallan		f.fontwidth = width * 2 /*(width + 3) & ~3*/;
50153a12b5fSmacallan		f.fontheight = height * 2;
50253a12b5fSmacallan		f.stride = stride * 2;
50353a12b5fSmacallan		outbuf = calloc(1, f.numchars * charsize * 4);
50453a12b5fSmacallan		if (outbuf == NULL) err(EXIT_FAILURE,
50553a12b5fSmacallan		    "failed to allocete memory for scale buffer\n");
50653a12b5fSmacallan		f.data = outbuf;
50753a12b5fSmacallan		inbuf = &buffer[first * charsize];
50853a12b5fSmacallan		for (i = 0; i < f.numchars; i++) {
50953a12b5fSmacallan			double_pixels(inbuf, outbuf, charsize);
51053a12b5fSmacallan			fill_dup(outbuf, charsize);
51153a12b5fSmacallan			if (smoothe) smoothe_pixels(outbuf, charsize * 2);
51253a12b5fSmacallan			inbuf += charsize;
51353a12b5fSmacallan			outbuf += charsize * 2;
51453a12b5fSmacallan		}
51553a12b5fSmacallan
51653a12b5fSmacallan	} else {
51753a12b5fSmacallan		f.fontwidth = width /*(width + 3) & ~3*/;
51853a12b5fSmacallan		f.fontheight = height;
51953a12b5fSmacallan		f.stride = stride;
52053a12b5fSmacallan		f.data = &buffer[first * charsize];
52153a12b5fSmacallan	}
52253a12b5fSmacallanif (0) {
52353a12b5fSmacallan	int i;
52453a12b5fSmacallan	uint16_t pixbuf[16];
52553a12b5fSmacallan	double_pixels(&buffer[charsize * 'Q'], pixbuf, charsize);
52653a12b5fSmacallan	fill_dup(pixbuf, charsize);
52753a12b5fSmacallan	for (i = 0; i < charsize * 2; i++) {
52853a12b5fSmacallan		printf("%2d: ", i);
52953a12b5fSmacallan		dump_line((char *)&pixbuf[i], 2);
53053a12b5fSmacallan	}
53153a12b5fSmacallan	smoothe_pixels(pixbuf, charsize * 2);
53253a12b5fSmacallan	for (i = 0; i < charsize * 2; i++) {
53353a12b5fSmacallan		printf("%2d: ", i);
53453a12b5fSmacallan		dump_line((char *)&pixbuf[i], 2);
53553a12b5fSmacallan	}
53653a12b5fSmacallan}
537d5f9d0dbSmacallan
5382b154882Suwe	if (ofile == NULL) {
5392b154882Suwe		int fdev = open("/dev/wsfont", O_RDWR, 0);
5402b154882Suwe		if (fdev < 0)
5412b154882Suwe			err(EXIT_FAILURE, "/dev/wsfont");
5422b154882Suwe		status = ioctl(fdev, WSDISPLAYIO_LDFONT, &f);
5432b154882Suwe		if (status != 0)
5442b154882Suwe			err(EXIT_FAILURE, "WSDISPLAYIO_LDFONT");
5452b154882Suwe		close(fdev);
5462b154882Suwe	}
5472b154882Suwe	else {
5486c735b96Schristos		if (header == 0)
54953a12b5fSmacallan			write_wsf(ofile, &f);
5506c735b96Schristos		else
55153a12b5fSmacallan			write_header(ofile, &f);
5522b154882Suwe	}
553d5f9d0dbSmacallan}
554d5f9d0dbSmacallan
5552b154882Suwe__dead void
5562b154882Suweusage()
5572b154882Suwe{
55853a12b5fSmacallan	fprintf(stderr, "Usage: %s [-vdhf2s] [-e encoding] [-N name] "
5596c735b96Schristos	    "[-o ofile.wsf] font.bdf\n", getprogname());
5602b154882Suwe	exit(EXIT_FAILURE);
5612b154882Suwe}
5622b154882Suwe
5632b154882Suweint
564d5f9d0dbSmacallanmain(int argc, char *argv[])
565d5f9d0dbSmacallan{
566d5f9d0dbSmacallan	FILE *foo;
5672b154882Suwe	const char *encname = NULL;
5682b154882Suwe
5692b154882Suwe	int c;
57053a12b5fSmacallan	while ((c = getopt(argc, argv, "e:o:N:vdhf2s")) != -1) {
5712b154882Suwe		switch (c) {
5722b154882Suwe
5732b154882Suwe		/* font encoding */
5742b154882Suwe		case 'e':
5752b154882Suwe			if (encname != NULL)
5762b154882Suwe				usage();
5772b154882Suwe			encname = optarg;
5782b154882Suwe			break;
5792b154882Suwe
5802b154882Suwe		/* output file name */
5812b154882Suwe		case 'o':
5822b154882Suwe			if (ofile != NULL)
5832b154882Suwe				usage();
5842b154882Suwe			ofile = optarg;
5852b154882Suwe			break;
5862b154882Suwe
58761348eb3Smacallan		case 'v':
58861348eb3Smacallan			verbose = 1;
58961348eb3Smacallan			break;
59061348eb3Smacallan
591554a5d78Smacallan		case 'd':
592554a5d78Smacallan			dump = 1;
593554a5d78Smacallan			break;
594554a5d78Smacallan
5952d60533cSmacallan		case 'h':
5962d60533cSmacallan			header = 1;
5972d60533cSmacallan			break;
598a5a7ac3fSmacallan		case 'f':
599a5a7ac3fSmacallan			force = 1;
600a5a7ac3fSmacallan			break;
60153a12b5fSmacallan		case '2':
60253a12b5fSmacallan			scale = 1;
60353a12b5fSmacallan			break;
60453a12b5fSmacallan		case 's':
60553a12b5fSmacallan			smoothe = 1;
60653a12b5fSmacallan			break;
60751bbcd86Smacallan		case 'N':
60851bbcd86Smacallan			strncpy(fontname, optarg, 64);
60951bbcd86Smacallan			break;
6102b154882Suwe		case '?':	/* FALLTHROUGH */
6112b154882Suwe		default:
6122b154882Suwe			usage();
613d5f9d0dbSmacallan		}
614d5f9d0dbSmacallan	}
6152b154882Suwe
6162b154882Suwe	argc -= optind;
6172b154882Suwe	argv += optind;
6182b154882Suwe
6192b154882Suwe	if (encname == NULL) {
6202b154882Suwe		encoding = WSDISPLAY_FONTENC_ISO;
6212b154882Suwe	}
6222b154882Suwe	else {
6232b154882Suwe		for (const struct encmap *e = encmap; e->name; ++e) {
6242b154882Suwe			if (strcmp(e->name, encname) == 0) {
6252b154882Suwe				encoding = e->encoding;
6262b154882Suwe				break;
6272b154882Suwe			}
6282b154882Suwe		}
6292b154882Suwe	}
6302b154882Suwe
6312b154882Suwe	/* get encoding from the bdf file? */
6322b154882Suwe	if (encoding == -1)
6332b154882Suwe		encoding = WSDISPLAY_FONTENC_ISO;
6342b154882Suwe
6352b154882Suwe	if (argc == 0)
6362b154882Suwe		usage();
6372b154882Suwe
6382b154882Suwe	const char *bdfname = argv[0];
6392b154882Suwe	foo = fopen(bdfname, "r");
6402b154882Suwe	if (foo == NULL)
6412b154882Suwe		err(EXIT_FAILURE, "%s", bdfname);
6422b154882Suwe
6432b154882Suwe	interpret(foo);
6442b154882Suwe	return EXIT_SUCCESS;
645d5f9d0dbSmacallan}
646