bdfload.c revision 2b154882
12b154882Suwe/*	$NetBSD: bdfload.c,v 1.3 2022/06/08 19:19:42 uwe 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 },
692b154882Suwe	{ "iso-8859-1",	WSDISPLAY_FONTENC_ISO },
702b154882Suwe	{ "iso-8859-2",	WSDISPLAY_FONTENC_ISO2 },
712b154882Suwe	{ "iso-8859-7",	WSDISPLAY_FONTENC_ISO7 },
722b154882Suwe	{ "iso2",	WSDISPLAY_FONTENC_ISO2 },
732b154882Suwe	{ "iso7",	WSDISPLAY_FONTENC_ISO7 },
742b154882Suwe	{ "iso8859-1",	WSDISPLAY_FONTENC_ISO },
752b154882Suwe	{ "iso8859-2",	WSDISPLAY_FONTENC_ISO2 },
762b154882Suwe	{ "iso8859-7",	WSDISPLAY_FONTENC_ISO7 },
772b154882Suwe	{ "koi8-r",	WSDISPLAY_FONTENC_KOI8_R },
782b154882Suwe	{ "koi8r",	WSDISPLAY_FONTENC_KOI8_R },
792b154882Suwe	{ "latin-1",	WSDISPLAY_FONTENC_ISO },
802b154882Suwe	{ "latin-2",	WSDISPLAY_FONTENC_ISO2 },
812b154882Suwe	{ "latin1",	WSDISPLAY_FONTENC_ISO },
822b154882Suwe	{ "latin2",	WSDISPLAY_FONTENC_ISO2 },
832b154882Suwe	{ "pcvt",	WSDISPLAY_FONTENC_PCVT },
842b154882Suwe	{ NULL, -1 }
852b154882Suwe};
862b154882Suwe
872b154882Suweconst char * const encname[] = {
882b154882Suwe#define _ENC(_e) [_e] = #_e
892b154882Suwe	_ENC(WSDISPLAY_FONTENC_ISO),
902b154882Suwe	_ENC(WSDISPLAY_FONTENC_IBM),
912b154882Suwe	_ENC(WSDISPLAY_FONTENC_PCVT),
922b154882Suwe	_ENC(WSDISPLAY_FONTENC_ISO7),
932b154882Suwe	_ENC(WSDISPLAY_FONTENC_ISO2),
942b154882Suwe	_ENC(WSDISPLAY_FONTENC_KOI8_R),
952b154882Suwe};
962b154882Suwe
972b154882Suwe
982b154882Suweconst char *ofile = NULL;
992b154882Suweint encoding = -1;
1002b154882Suwe
1012b154882Suwe
102d5f9d0dbSmacallanvoid
103d5f9d0dbSmacallaninterpret(FILE *foo)
104d5f9d0dbSmacallan{
1052b154882Suwe	char line[128], *arg, name[64] = "foop", *buffer;
1062b154882Suwe	int buflen = -1;
107d5f9d0dbSmacallan	int len, in_char = 0, current = -1, stride = 0, charsize = 0;
108d5f9d0dbSmacallan	int width, height, x, y, num;
109d5f9d0dbSmacallan	int first = 255, last = 0;
110d5f9d0dbSmacallan	int left, top, lines;
111d5f9d0dbSmacallan	int bl = 255, bt = 255, br = -1, bb = -1;
112d5f9d0dbSmacallan	struct wsdisplay_font f;
1132b154882Suwe	int status;
114d5f9d0dbSmacallan
115d5f9d0dbSmacallan	while (fgets(line, sizeof(line), foo) != NULL) {
116d5f9d0dbSmacallan		int i = 0;
117d5f9d0dbSmacallan		/* separate keyword from parameters */
118d5f9d0dbSmacallan		len = strlen(line);
119d5f9d0dbSmacallan		while (!isspace(line[i]) && (i < len)) i++;
120d5f9d0dbSmacallan		line[i] = 0;
121d5f9d0dbSmacallan		arg = &line[i + 1];
122d5f9d0dbSmacallan		i = 0;
123d5f9d0dbSmacallan		len = strlen(arg);
124d5f9d0dbSmacallan		/* get rid of garbage */
125d5f9d0dbSmacallan		while ((!iscntrl(arg[i])) && (arg[i] != 0)) {
126d5f9d0dbSmacallan			i++;
127d5f9d0dbSmacallan		}
128d5f9d0dbSmacallan		arg[i] = 0;
129d5f9d0dbSmacallan		if (strcmp(line, "FAMILY_NAME") == 0) {
130d5f9d0dbSmacallan			/* cut off quotation marks */
131d5f9d0dbSmacallan			strncpy(name, arg + 1, 64);
132d5f9d0dbSmacallan			name[strlen(name) - 1] = 0;
133d5f9d0dbSmacallan			printf("name: %s\n", name);
134d5f9d0dbSmacallan		} else if (strcmp(line, "FONTBOUNDINGBOX") == 0) {
135d5f9d0dbSmacallan			int res;
136d5f9d0dbSmacallan			res = sscanf(arg, "%d %d %d %d",
137d5f9d0dbSmacallan					  &width, &height, &x, &y);
138d5f9d0dbSmacallan			stride = (width + 7) >> 3;
139d5f9d0dbSmacallan			printf("box %d x %d\n", width, height);
140d5f9d0dbSmacallan			if (stride > 2) {
141d5f9d0dbSmacallan				printf("no fonts wider than 16 work for now\n");
142d5f9d0dbSmacallan				exit(1);
143d5f9d0dbSmacallan			}
144d5f9d0dbSmacallan			charsize = height * stride;
145d5f9d0dbSmacallan			buflen = 256 * charsize;
1462b154882Suwe			buffer = calloc(1, buflen);
147d5f9d0dbSmacallan			if (buffer == NULL) {
148d5f9d0dbSmacallan				printf("failed to allocate %dKB for glyphs\n",
149d5f9d0dbSmacallan				    buflen);
150d5f9d0dbSmacallan				exit(1);
151ce18d260Suwe			}
152d5f9d0dbSmacallan		} else if (strcmp(line, "CHARS") == 0) {
153d5f9d0dbSmacallan			if (sscanf(arg, "%d", &num) == 1)
154d5f9d0dbSmacallan				printf("number of characters: %d\n", num);
155d5f9d0dbSmacallan		} else if (strcmp(line, "STARTCHAR") == 0) {
156d5f9d0dbSmacallan			in_char = 1;
157d5f9d0dbSmacallan		} else if (strcmp(line, "ENDCHAR") == 0) {
158d5f9d0dbSmacallan			in_char = 0;
159d5f9d0dbSmacallan			current = -1;
160d5f9d0dbSmacallan		} else if (strcmp(line, "ENCODING") == 0) {
161d5f9d0dbSmacallan			if (sscanf(arg, "%d", &current) == 1) {
162d5f9d0dbSmacallan				if (current >= 0 && current < 256) {
163d5f9d0dbSmacallan					if (current < first) first = current;
164d5f9d0dbSmacallan					if (current > last) last = current;
165d5f9d0dbSmacallan				}
166d5f9d0dbSmacallan			}
167d5f9d0dbSmacallan		} else if (strcmp(line, "BBX") == 0) {
168d5f9d0dbSmacallan			int cx, cy, cwi, che;
169d5f9d0dbSmacallan			if (sscanf(arg, "%d %d %d %d", &cwi, &che, &cx, &cy)
170d5f9d0dbSmacallan			     == 4) {
171d5f9d0dbSmacallan				left = cx;
172d5f9d0dbSmacallan				lines = che;
173d5f9d0dbSmacallan				top = height + y - che - cy;
174d5f9d0dbSmacallan				if (left < bl) bl = left;
175d5f9d0dbSmacallan				if (top < bt) bt = top;
176d5f9d0dbSmacallan				if ((left + cwi) > br) br = left + cwi;
177d5f9d0dbSmacallan				if ((top + che) > bb) bb = top + che;
178d5f9d0dbSmacallan			}
179d5f9d0dbSmacallan		} else if (strcmp(line, "BITMAP") == 0) {
180d5f9d0dbSmacallan			int i, j, k, l;
181d5f9d0dbSmacallan			char num[32];
182d5f9d0dbSmacallan			char *gptr = &buffer[charsize * current];
183d5f9d0dbSmacallan			char *bptr = gptr + top;
184d5f9d0dbSmacallan			uint16_t *bptr16 = (uint16_t *)gptr;
185d5f9d0dbSmacallan			bptr16 += top;
186d5f9d0dbSmacallan			/* see if the character is in range */
187d5f9d0dbSmacallan			if ((current < 0) || (current > 255)) continue;
188d5f9d0dbSmacallan			/* now we read & render the character */
189d5f9d0dbSmacallan			for (i = 0; i < lines; i++) {
190d5f9d0dbSmacallan				fgets(num, 32, foo);
191d5f9d0dbSmacallan				sscanf(num, "%x", &l);
192d5f9d0dbSmacallan				if ((stride) == 2 && (strlen(num) < 4))
193d5f9d0dbSmacallan					l = l << 8;
194d5f9d0dbSmacallan				l = l >> left;
195d5f9d0dbSmacallan				if (stride == 1) {
196d5f9d0dbSmacallan					*gptr = l;
197d5f9d0dbSmacallan					gptr++;
198d5f9d0dbSmacallan				} else {
199d5f9d0dbSmacallan					*bptr16 = htobe16(l);
200d5f9d0dbSmacallan					bptr16++;
201ce18d260Suwe				}
202d5f9d0dbSmacallan			}
203d5f9d0dbSmacallan		}
204d5f9d0dbSmacallan	}
205d5f9d0dbSmacallan	printf("range %d to %d\n", first, last);
2062b154882Suwe	printf("encoding: %s\n", encname[encoding]);
207d5f9d0dbSmacallan	printf("actual box: %d %d %d %d\n", bl, bt, br, bb);
2082b154882Suwe
209d5f9d0dbSmacallan	/* now stuff it into a something wsfont understands */
210d5f9d0dbSmacallan	f.fontwidth = width /*(width + 3) & ~3*/;
211d5f9d0dbSmacallan	f.fontheight = height;
212d5f9d0dbSmacallan	f.firstchar = first;
2132b154882Suwe	f.numchars = last - first + 1;
214d5f9d0dbSmacallan	f.stride = stride;
2152b154882Suwe	f.encoding = encoding;
216d5f9d0dbSmacallan	f.name = name;
217d5f9d0dbSmacallan	f.bitorder = WSDISPLAY_FONTORDER_L2R;
218d5f9d0dbSmacallan	f.byteorder = WSDISPLAY_FONTORDER_L2R;
219d5f9d0dbSmacallan	f.data = &buffer[first * charsize];
220d5f9d0dbSmacallan
2212b154882Suwe	if (ofile == NULL) {
2222b154882Suwe		int fdev = open("/dev/wsfont", O_RDWR, 0);
2232b154882Suwe		if (fdev < 0)
2242b154882Suwe			err(EXIT_FAILURE, "/dev/wsfont");
2252b154882Suwe		status = ioctl(fdev, WSDISPLAYIO_LDFONT, &f);
2262b154882Suwe		if (status != 0)
2272b154882Suwe			err(EXIT_FAILURE, "WSDISPLAYIO_LDFONT");
2282b154882Suwe		close(fdev);
2292b154882Suwe	}
2302b154882Suwe	else {
2312b154882Suwe		struct wsfthdr h;
2322b154882Suwe
2332b154882Suwe		memset(&h, 0, sizeof(h));
2342b154882Suwe		strncpy(h.magic, "WSFT", sizeof(h.magic));
2352b154882Suwe		strncpy(h.name, f.name, sizeof(h.name));
2362b154882Suwe		h.firstchar = htole32(f.firstchar);
2372b154882Suwe		h.numchars = htole32(f.numchars);
2382b154882Suwe		h.encoding = htole32(f.encoding);
2392b154882Suwe		h.fontwidth = htole32(f.fontwidth);
2402b154882Suwe		h.fontheight = htole32(f.fontheight);
2412b154882Suwe		h.stride = htole32(f.stride);
2422b154882Suwe		h.bitorder = htole32(f.bitorder);
2432b154882Suwe		h.byteorder = htole32(f.byteorder);
2442b154882Suwe
2452b154882Suwe		int wsfd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
2462b154882Suwe		if (wsfd < 0)
2472b154882Suwe			err(EXIT_FAILURE, "%s", ofile);
2482b154882Suwe
2492b154882Suwe		ssize_t nwritten;
2502b154882Suwe		nwritten = write(wsfd, &h, sizeof(h));
2512b154882Suwe		if (nwritten < 0)
2522b154882Suwe			err(EXIT_FAILURE, "%s", ofile);
2532b154882Suwe		if (nwritten != sizeof(h))
2542b154882Suwe			errx(EXIT_FAILURE, "%s: partial write", ofile);
2552b154882Suwe
2562b154882Suwe		nwritten = write(wsfd, buffer, buflen);
2572b154882Suwe		if (nwritten < 0)
2582b154882Suwe			err(EXIT_FAILURE, "%s", ofile);
2592b154882Suwe		if (nwritten != buflen)
2602b154882Suwe			errx(EXIT_FAILURE, "%s: partial write", ofile);
2612b154882Suwe		close(wsfd);
2622b154882Suwe	}
263d5f9d0dbSmacallan}
264d5f9d0dbSmacallan
2652b154882Suwe
2662b154882Suwe__dead void
2672b154882Suweusage()
2682b154882Suwe{
2692b154882Suwe	fprintf(stderr, "usage: bdfload [-e encoding] [-o ofile.wsf] font.bdf\n");
2702b154882Suwe	exit(EXIT_FAILURE);
2712b154882Suwe}
2722b154882Suwe
2732b154882Suweint
274d5f9d0dbSmacallanmain(int argc, char *argv[])
275d5f9d0dbSmacallan{
276d5f9d0dbSmacallan	FILE *foo;
2772b154882Suwe	const char *encname = NULL;
2782b154882Suwe
2792b154882Suwe	int c;
2802b154882Suwe	while ((c = getopt(argc, argv, "e:o:")) != -1) {
2812b154882Suwe		switch (c) {
2822b154882Suwe
2832b154882Suwe		/* font encoding */
2842b154882Suwe		case 'e':
2852b154882Suwe			if (encname != NULL)
2862b154882Suwe				usage();
2872b154882Suwe			encname = optarg;
2882b154882Suwe			break;
2892b154882Suwe
2902b154882Suwe		/* output file name */
2912b154882Suwe		case 'o':
2922b154882Suwe			if (ofile != NULL)
2932b154882Suwe				usage();
2942b154882Suwe			ofile = optarg;
2952b154882Suwe			break;
2962b154882Suwe
2972b154882Suwe		case '?':	/* FALLTHROUGH */
2982b154882Suwe		default:
2992b154882Suwe			usage();
300d5f9d0dbSmacallan		}
301d5f9d0dbSmacallan	}
3022b154882Suwe
3032b154882Suwe	argc -= optind;
3042b154882Suwe	argv += optind;
3052b154882Suwe
3062b154882Suwe	if (encname == NULL) {
3072b154882Suwe		encoding = WSDISPLAY_FONTENC_ISO;
3082b154882Suwe	}
3092b154882Suwe	else {
3102b154882Suwe		for (const struct encmap *e = encmap; e->name; ++e) {
3112b154882Suwe			if (strcmp(e->name, encname) == 0) {
3122b154882Suwe				encoding = e->encoding;
3132b154882Suwe				break;
3142b154882Suwe			}
3152b154882Suwe		}
3162b154882Suwe	}
3172b154882Suwe
3182b154882Suwe	/* get encoding from the bdf file? */
3192b154882Suwe	if (encoding == -1)
3202b154882Suwe		encoding = WSDISPLAY_FONTENC_ISO;
3212b154882Suwe
3222b154882Suwe	if (argc == 0)
3232b154882Suwe		usage();
3242b154882Suwe
3252b154882Suwe	const char *bdfname = argv[0];
3262b154882Suwe	foo = fopen(bdfname, "r");
3272b154882Suwe	if (foo == NULL)
3282b154882Suwe		err(EXIT_FAILURE, "%s", bdfname);
3292b154882Suwe
3302b154882Suwe	interpret(foo);
3312b154882Suwe	return EXIT_SUCCESS;
332d5f9d0dbSmacallan}
333