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