189d09728Smrg/*-
289d09728Smrg * Copyright (c) 2006 Martin Husemann.
389d09728Smrg * Copyright (c) 2007 Joerg Sonnenberger.
489d09728Smrg * All rights reserved.
589d09728Smrg *
689d09728Smrg * Redistribution and use in source and binary forms, with or without
789d09728Smrg * modification, are permitted provided that the following conditions
889d09728Smrg * are met:
989d09728Smrg * 1. Redistributions of source code must retain the above copyright
1089d09728Smrg *    notice, this list of conditions and the following disclaimer.
1189d09728Smrg * 2. The name of the author may not be used to endorse or promote
1289d09728Smrg *    products derived from this software without specific prior
1389d09728Smrg *    written permission.
1489d09728Smrg *
1589d09728Smrg * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1689d09728Smrg * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1789d09728Smrg * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1889d09728Smrg * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1989d09728Smrg * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2089d09728Smrg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2189d09728Smrg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2289d09728Smrg * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2389d09728Smrg * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2489d09728Smrg * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2589d09728Smrg * POSSIBILITY OF SUCH DAMAGE.
2689d09728Smrg */
2789d09728Smrg
2889d09728Smrg/*
2989d09728Smrg * This program is derived (in a straight forward way) from
3089d09728Smrg * bdftruncate.pl -- Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/>
3189d09728Smrg *
3289d09728Smrg * This utility allows you to generate from an ISO10646-1 encoded
3389d09728Smrg * BDF font other ISO10646-1 BDF fonts in which all characters above
3489d09728Smrg * a threshold code value are stored unencoded.
3589d09728Smrg */
3689d09728Smrg
3789d09728Smrg#include <ctype.h>
3889d09728Smrg#include <errno.h>
3989d09728Smrg#include <limits.h>
4089d09728Smrg#include <stdio.h>
4189d09728Smrg#include <stdlib.h>
4289d09728Smrg#include <string.h>
4389d09728Smrg
44f931275dSmrg#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205))	\
45f931275dSmrg        || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
46f931275dSmrg# define ATTR_NORETURN __attribute((noreturn))
47f931275dSmrg#else
48f931275dSmrg# define ATTR_NORETURN
49f931275dSmrg#endif /* GNUC  */
5089d09728Smrg
51f931275dSmrgstatic int iswide(unsigned int);
52f931275dSmrgstatic void usage(void) ATTR_NORETURN;
53f931275dSmrgstatic int parse_threshold(const char *str, unsigned long *threshold);
5489d09728Smrg
5589d09728Smrgstatic int
56f931275dSmrgparse_threshold(const char *str, unsigned long *threshold)
5789d09728Smrg{
5889d09728Smrg	int base;
5989d09728Smrg	char *end_ptr;
6089d09728Smrg
6189d09728Smrg	if (!isdigit((unsigned char)*str))
6289d09728Smrg		return 1;
63a9274bcdSmrg	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
6489d09728Smrg		base = 16;
6589d09728Smrg	else
6689d09728Smrg		base = 10;
6789d09728Smrg
6889d09728Smrg	errno = 0;
69f931275dSmrg	*threshold = strtoul(str, &end_ptr, base);
70f931275dSmrg	if (errno != 0 || *threshold == 0)
7189d09728Smrg		return 1;
7289d09728Smrg	return 0;
7389d09728Smrg}
7489d09728Smrg
7589d09728Smrgstatic void
76f931275dSmrgprocess_line(const char *line, int removewide, unsigned long threshold)
7789d09728Smrg{
7889d09728Smrg	if (strncmp(line, "ENCODING", 8) == 0) {
7989d09728Smrg		unsigned long enc;
8089d09728Smrg		const char *v;
8189d09728Smrg
8289d09728Smrg		v = line + 9;
8389d09728Smrg
8489d09728Smrg		while (*v && isspace((unsigned char)(*v)))
8589d09728Smrg			++v;
8689d09728Smrg		enc = strtoul(v, NULL, 10);
8789d09728Smrg		/* XXX Check for line-ending? */
8889d09728Smrg		if (enc >= threshold || (removewide && iswide(enc))) {
8989d09728Smrg			printf("ENCODING -1\n");
9089d09728Smrg		} else {
9189d09728Smrg			fputs(line, stdout);
9289d09728Smrg		}
9389d09728Smrg		return;
9489d09728Smrg	}
9589d09728Smrg	if (strncmp(line, "STARTFONT", 9) == 0) {
9689d09728Smrg		fputs(line, stdout);
9789d09728Smrg		printf("COMMENT AUTOMATICALLY GENERATED FILE. DO NOT EDIT!\n"
9889d09728Smrg		    "COMMENT In this version of the font file, "
9989d09728Smrg		    "all characters >= U+%04lx are\n"
10089d09728Smrg		    "COMMENT not encoded to keep XFontStruct small.\n",
10189d09728Smrg		    threshold);
10289d09728Smrg		return;
10389d09728Smrg	}
10489d09728Smrg	if (strncmp(line, "COMMENT", 7) == 0) {
10589d09728Smrg		const char *v = line + 8;
10689d09728Smrg
10789d09728Smrg		while (*v && isspace((unsigned char)(*v)))
10889d09728Smrg			v++;
10989d09728Smrg		if (strncmp(v, "$id: ", 5) == 0 ||
11089d09728Smrg		    strncmp(v, "$Id: ", 5) == 0) {
11189d09728Smrg		    	const char *id = strchr(v+1, '$');
11289d09728Smrg		    	if (id) {
11389d09728Smrg		    		printf("COMMENT Derived from %.*s",
11489d09728Smrg				     (int)(id - v - 4), v + 5);
11589d09728Smrg				return;
11689d09728Smrg		    	}
11789d09728Smrg		}
11889d09728Smrg	}
11989d09728Smrg	fputs(line, stdout);
12089d09728Smrg}
12189d09728Smrg
12289d09728Smrgint
12389d09728Smrgmain(int argc, char **argv)
12489d09728Smrg{
12589d09728Smrg	int removewide;
126f931275dSmrg	unsigned long threshold;
127f931275dSmrg	int opt_minus_w = 0;
128f931275dSmrg	int opt_plus_w = 0;
12989d09728Smrg	char *line, *input_ptr;
13089d09728Smrg	size_t line_len, rest_len;
13189d09728Smrg
13289d09728Smrg	--argc;
13389d09728Smrg	++argv;
13489d09728Smrg	if (argc == 0)
13589d09728Smrg		usage();
13689d09728Smrg
13789d09728Smrg	if (strcmp(*argv, "-w") == 0 || strcmp(*argv, "+w") == 0) {
13889d09728Smrg		if (**argv == '-')
13989d09728Smrg			opt_minus_w = 1;
14089d09728Smrg		else
14189d09728Smrg			opt_plus_w = 1;
14289d09728Smrg		--argc;
14389d09728Smrg		++argv;
14489d09728Smrg	}
14589d09728Smrg
14689d09728Smrg	if (argc != 1 || (opt_plus_w && opt_minus_w))
14789d09728Smrg		usage();
148f931275dSmrg	if (parse_threshold(*argv, &threshold)) {
149a9274bcdSmrg		fprintf(stderr, "Illegal threshold %s\n", *argv);
15089d09728Smrg		usage();
15189d09728Smrg	}
15289d09728Smrg
15389d09728Smrg	if (opt_minus_w)
15489d09728Smrg		removewide = 1;
15589d09728Smrg	else if (opt_plus_w)
15689d09728Smrg		removewide = 0;
15789d09728Smrg	else
15889d09728Smrg		removewide = (threshold <= 0x3200);
15989d09728Smrg
16089d09728Smrg	line_len = 1024;
16189d09728Smrg	if ((line = malloc(line_len)) == NULL) {
16289d09728Smrg		fprintf(stderr, "malloc failed");
16389d09728Smrg		exit(EXIT_FAILURE);
16489d09728Smrg	}
16589d09728Smrg
16689d09728Smrg	for (;;) {
16789d09728Smrg		if (fgets(line, line_len, stdin) == NULL)
16889d09728Smrg		     break;
16989d09728Smrg		while (strlen(line) == line_len - 1 && !feof(stdin)) {
17089d09728Smrg			if (line_len > SSIZE_MAX) {
17189d09728Smrg				fprintf(stderr, "input line too large");
17289d09728Smrg				exit(EXIT_FAILURE);
17389d09728Smrg			}
17489d09728Smrg			line = realloc(line, line_len * 2);
17589d09728Smrg			if (line == NULL) {
17689d09728Smrg				fprintf(stderr, "realloc failed");
17789d09728Smrg				exit(EXIT_FAILURE);
17889d09728Smrg			}
17989d09728Smrg			input_ptr = line + line_len - 1;
18089d09728Smrg			rest_len = line_len + 1;
18189d09728Smrg			line_len *= 2;
18289d09728Smrg			if (fgets(input_ptr, rest_len, stdin) == NULL) {
18389d09728Smrg				/* Should not happen, but handle as EOF */
18489d09728Smrg				break;
18589d09728Smrg			}
18689d09728Smrg		}
187f931275dSmrg		process_line(line, removewide, threshold);
18889d09728Smrg	}
18989d09728Smrg
19089d09728Smrg	return EXIT_SUCCESS;
19189d09728Smrg}
19289d09728Smrg
19389d09728Smrg/*
19489d09728Smrg * Subroutine to identify whether the ISO 10646/Unicode character code
19589d09728Smrg * ucs belongs into the East Asian Wide (W) or East Asian FullWidth
19689d09728Smrg * (F) category as defined in Unicode Technical Report #11.
19789d09728Smrg */
19889d09728Smrgstatic int
19989d09728Smrgiswide(unsigned int ucs)
20089d09728Smrg{
20189d09728Smrg    return (ucs >= 0x1100 &&
20289d09728Smrg            (ucs <= 0x115f ||                   /* Hangul Jamo */
20389d09728Smrg             (ucs >= 0x2e80 && ucs <= 0xa4cf &&
20489d09728Smrg              (ucs & ~0x0011) != 0x300a && ucs != 0x303f) || /* CJK .. Yi */
20589d09728Smrg             (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
20689d09728Smrg             (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Comp. Ideographs */
20789d09728Smrg             (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Comp. Forms */
20889d09728Smrg             (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
20989d09728Smrg             (ucs >= 0xffe0 && ucs <= 0xffe6) ||
21089d09728Smrg             (ucs >= 0x20000 && ucs <= 0x2ffff)));
21189d09728Smrg}
21289d09728Smrg
21389d09728Smrgstatic void
21489d09728Smrgusage(void)
21589d09728Smrg{
21689d09728Smrg	fprintf(stderr,
21789d09728Smrg	    "Usage: bdftruncate [+w|-w] threshold <source.bdf >destination.bdf\n"
21889d09728Smrg	    "\n"
21989d09728Smrg	    "Example:\n"
22089d09728Smrg	    "\n"
22189d09728Smrg	    "  bdftruncate 0x3200 <6x13.bdf >6x13t.bdf\n"
22289d09728Smrg	    "\n"
22389d09728Smrg	    "will generate the file 6x13t.bdf in which all glyphs with codes\n"
22489d09728Smrg	    ">= 0x3200 will only be stored unencoded (i.e., ENCODING -1).\n"
22589d09728Smrg	    "Option -w removes East Asian Wide and East Asian FullWidth characters\n"
22689d09728Smrg	    "(default if threshold <= 0x3200), and option +w keeps them.\n");
22789d09728Smrg	exit(EXIT_FAILURE);
22889d09728Smrg}
229