1/*- 2 * Copyright (c) 2003 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Ben Collver <collver1@attbi.com>. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * This utility allows you to generate from an ISO10646-1 encoded 31 * BDF font other BDF fonts in any possible encoding. This way, you can 32 * derive from a single ISO10646-1 master font a whole set of 8-bit 33 * fonts in all ISO 8859 and various other encodings. (Hopefully 34 * a future XFree86 release will have a similar facility built into 35 * the server, which can re-encode ISO10646-1 on the fly, because 36 * storing the same fonts in many different encodings is clearly 37 * a waste of storage capacity). 38*/ 39 40#include <ctype.h> 41#include <errno.h> 42#include <fcntl.h> 43#if !defined(NEED_BASENAME) && !defined(Lynx) 44#include <libgen.h> 45#endif 46#include <limits.h> 47#include <stdarg.h> 48#include <stdint.h> 49#include <stdio.h> 50#include <stdlib.h> 51#include <string.h> 52#include <unistd.h> 53 54/* global variable for argv[0] */ 55static const char *my_name = NULL; 56 57#ifdef NEED_BASENAME 58static char * 59basename(char *pathname) 60{ 61 char *ptr; 62 63 ptr = strrchr(pathname, '/'); 64 return ((ptr == NULL) ? pathname : &ptr[1]); 65} 66#endif 67 68/* "CLASS" "z" string and memory manipulation */ 69 70static void * 71zmalloc(size_t size) 72{ 73 void *r; 74 r = malloc(size); 75 if (r == NULL) { 76 perror(my_name); 77 exit(errno); 78 } 79 memset(r, 0, size); 80 return r; 81} 82 83static void * 84zrealloc(void *ptr, size_t size) 85{ 86 void *temp; 87 temp = realloc(ptr, size); 88 if (temp == NULL) { 89 perror(my_name); 90 exit(errno); 91 } 92 return temp; 93} 94 95static char * 96zstrdup(const char *str) 97{ 98 char *retval; 99 100 if (str == NULL) { 101 fprintf(stderr, "%s: zstrdup(NULL)\n", my_name); 102 exit(1); 103 } 104 retval = strdup(str); 105 if (retval == NULL) { 106 perror(my_name); 107 exit(errno); 108 } 109 return retval; 110} 111 112static void 113zstrcpy(char **dest, const char *source) 114{ 115 if (*dest != NULL) 116 free(*dest); 117 *dest = zstrdup(source); 118} 119 120static void 121zquotedcpy(char **dest, const char *source) 122{ 123 const char *start, *end; 124 125 if (*dest != NULL) 126 free(*dest); 127 *dest = NULL; 128 start = source; 129 if (*start == '"') { 130 start = source+1; 131 end = strrchr(start, '"'); 132 if (!end) return; 133 *dest = zmalloc(end-start+1); 134 strncpy(*dest, start, end-start); 135 (*dest)[end-start] = '\0'; 136 } else { 137 *dest = zstrdup(source); 138 } 139} 140 141static void 142zstrcat(char **dest, const char *source) 143{ 144 size_t dest_size = 1; 145 size_t source_size; 146 147 if (*dest != NULL) 148 dest_size = strlen(*dest) + 1; 149 source_size = strlen(source); 150 *dest = zrealloc(*dest, dest_size + source_size); 151 strcpy(*dest + dest_size - 1, source); 152} 153 154static void 155zstrtoupper(char *s) 156{ 157 char *t; 158 159 for (t = s; *t != '\000'; t++) 160 *t = (char) toupper(*t); 161} 162 163#define zs_true(x) (x != NULL && strcmp(x, "0") != 0) 164#define zi_true(x) (x == 1) 165 166/* "CLASS" "dynamic array" */ 167 168typedef struct { 169 char *name; 170 int size; 171 int count; 172 void **values; 173 void *nv; 174} da_t; 175 176static da_t * 177da_new(const char *name) 178{ 179 da_t *da; 180 181 da = zmalloc(sizeof(da_t)); 182 da->size = 0; 183 da->count = 0; 184 da->values = NULL; 185 da->nv = NULL; 186 da->name = NULL; 187 zstrcpy(&(da->name), name); 188 return da; 189} 190 191static void * 192da_fetch(da_t *da, int key) 193{ 194 void *r = NULL; 195 196 if (key >= 0 && key < da->size && da->values[key] != NULL) 197 r = da->values[key]; 198 else 199 if (key == -1 && da->nv != NULL) 200 r = da->nv; 201 202 return r; 203} 204 205static int 206da_fetch_int(da_t *da, int key) 207{ 208 int *t; 209 int r = -1; 210 t = da_fetch(da, key); 211 if (t != NULL) 212 r = *t; 213 return r; 214} 215 216#define da_fetch_str(a,k) \ 217 (char *)da_fetch(a,k) 218 219static void 220da_add(da_t *da, int key, void *value) 221{ 222 int i = da->size; 223 if (key >= 0) { 224 if ((size_t)key >= SIZE_MAX / sizeof(void *)) { 225 fprintf(stderr, "%s: Illegal key '%d' encountered!\n", 226 my_name, key); 227 exit(1); 228 } 229 if (key >= da->size) { 230 da->size = key + 1; 231 da->values = zrealloc(da->values, 232 da->size * sizeof(void *)); 233 for (; i < da->size; i++) 234 da->values[i] = NULL; 235 } 236 if (da->values[key] != NULL) { 237 free(da->values[key]); 238 } else { 239 if (value == NULL) { 240 if (da->count > 0) 241 da->count--; 242 } else { 243 da->count++; 244 } 245 } 246 da->values[key] = value; 247 } else if (key == -1) { 248 if (da->nv != NULL) 249 free(da->nv); 250 da->nv = value; 251 } 252} 253 254static void 255da_add_str(da_t *da, int key, const char *value) 256{ 257 da_add(da, key, value?zstrdup(value):NULL); 258} 259 260static void 261da_add_int(da_t *da, int key, int value) 262{ 263 int *v; 264 265 v = zmalloc(sizeof(int)); 266 *v = value; 267 da_add(da, key, v); 268} 269 270#define da_count(da) (da->count) 271#define da_size(da) (da->size) 272 273static void 274da_clear(da_t *da) 275{ 276 int i; 277 278 for (i = da->size; i; i--) 279 free(da->values[i]); 280 if (da->values != NULL) 281 free(da->values); 282 da->size = 0; 283 da->count = 0; 284 da->values = NULL; 285} 286 287/* "CLASS" file input */ 288 289#define TYPICAL_LINE_SIZE (80) 290 291/* read a line and strip trailing whitespace */ 292static int 293read_line(FILE *fp, char **buffer) 294{ 295 int buffer_size = TYPICAL_LINE_SIZE; 296 int eof = 0; 297 int position = 0; 298 int c; 299 300 *buffer = zmalloc(TYPICAL_LINE_SIZE); 301 (*buffer)[0] = '\0'; 302 303 if ((c = getc(fp)) == EOF) 304 eof = 1; 305 306 while (c != '\n' && !eof) { 307 if (position + 1 >= buffer_size) { 308 buffer_size = buffer_size * 2 + 1; 309 *buffer = zrealloc(*buffer, buffer_size); 310 } 311 (*buffer)[position++] = (char) c; 312 (*buffer)[position] = '\0'; 313 c = getc(fp); 314 if (c == EOF) 315 eof = 1; 316 } 317 318 if (eof) { 319 free(*buffer); 320 *buffer = NULL; 321 return 0; 322 } 323 324 while (position > 1) { 325 position--; 326 if (!isspace((*buffer)[position])) 327 break; 328 (*buffer)[position] = '\0'; 329 } 330 331 return 1; 332} 333 334/* BEGIN */ 335 336/* 337DEC VT100 graphics characters in the range 1-31 (as expected by 338some old xterm versions and a few other applications) 339*/ 340#define decmap_size 31 341static int decmap[decmap_size] = { 342 0x25C6, /* BLACK DIAMOND */ 343 0x2592, /* MEDIUM SHADE */ 344 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */ 345 0x240C, /* SYMBOL FOR FORM FEED */ 346 0x240D, /* SYMBOL FOR CARRIAGE RETURN */ 347 0x240A, /* SYMBOL FOR LINE FEED */ 348 0x00B0, /* DEGREE SIGN */ 349 0x00B1, /* PLUS-MINUS SIGN */ 350 0x2424, /* SYMBOL FOR NEWLINE */ 351 0x240B, /* SYMBOL FOR VERTICAL TABULATION */ 352 0x2518, /* BOX DRAWINGS LIGHT UP AND LEFT */ 353 0x2510, /* BOX DRAWINGS LIGHT DOWN AND LEFT */ 354 0x250C, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ 355 0x2514, /* BOX DRAWINGS LIGHT UP AND RIGHT */ 356 0x253C, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ 357 0x23BA, /* HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ 358 0x23BB, /* HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ 359 0x2500, /* BOX DRAWINGS LIGHT HORIZONTAL */ 360 0x23BC, /* HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ 361 0x23BD, /* HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ 362 0x251C, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ 363 0x2524, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ 364 0x2534, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ 365 0x252C, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ 366 0x2502, /* BOX DRAWINGS LIGHT VERTICAL */ 367 0x2264, /* LESS-THAN OR EQUAL TO */ 368 0x2265, /* GREATER-THAN OR EQUAL TO */ 369 0x03C0, /* GREEK SMALL LETTER PI */ 370 0x2260, /* NOT EQUAL TO */ 371 0x00A3, /* POUND SIGN */ 372 0x00B7 /* MIDDLE DOT */ 373}; 374 375static int 376is_control(int ucs) 377{ 378 return ((ucs >= 0x00 && ucs <= 0x1f) || 379 (ucs >= 0x7f && ucs <= 0x9f)); 380} 381 382static int 383is_blockgraphics(int ucs) 384{ 385 return ucs >= 0x2500 && ucs <= 0x25FF; 386} 387 388/* calculate the bounding box that covers both provided bounding boxes */ 389typedef struct { 390 int cwidth; 391 int cheight; 392 int cxoff; 393 int cyoff; 394} bbx_t; 395 396static bbx_t * 397combine_bbx(int awidth, int aheight, int axoff, int ayoff, 398 int cwidth, int cheight, int cxoff, int cyoff, bbx_t *r) 399{ 400 r->cwidth = cwidth; 401 r->cheight = cheight; 402 r->cxoff = cxoff; 403 r->cyoff = cyoff; 404 405 if (axoff < r->cxoff) { 406 r->cwidth += r->cxoff - axoff; 407 r->cxoff = axoff; 408 } 409 if (ayoff < r->cyoff) { 410 r->cheight += r->cyoff - ayoff; 411 r->cyoff = ayoff; 412 } 413 if (awidth + axoff > r->cwidth + r->cxoff) { 414 r->cwidth = awidth + axoff - r->cxoff; 415 } 416 if (aheight + ayoff > r->cheight + r->cyoff) { 417 r->cheight = aheight + ayoff - r->cyoff; 418 } 419 420 return r; 421} 422 423static void 424usage(void) { 425 printf("%s", "\n" 426"Usage: ucs2any [+d|-d] <source-name> { <mapping-file> <registry-encoding> }\n" 427"\n" 428"where\n" 429"\n" 430" +d put DEC VT100 graphics characters in the C0 range\n" 431" (default for upright charcell fonts)\n" 432"\n" 433" -d do not put DEC VT100 graphics characters in the\n" 434" C0 range (default for all other font types)\n" 435"\n" 436" <source-name> is the name of an ISO10646-1 encoded BDF file\n" 437"\n" 438" <mapping-file> is the name of a character set table like those on\n" 439" <ftp://ftp.unicode.org/Public/MAPPINGS/>\n" 440"\n" 441" <registry-encoding> are the CHARSET_REGISTRY and CHARSET_ENCODING\n" 442" field values for the font name (XLFD) of the\n" 443" target font, separated by a hyphen\n" 444"\n" 445"Example:\n" 446"\n" 447" ucs2any 6x13.bdf 8859-1.TXT iso8859-1 8859-2.TXT iso8859-2\n" 448"\n" 449"will generate the files 6x13-iso8859-1.bdf and 6x13-iso8859-2.bdf\n" 450"\n"); 451} 452 453static int 454chars_compare(const void *aa, const void *bb) 455{ 456 int a = *(const int *)aa; 457 int b = *(const int *)bb; 458 459 return a - b; 460} 461 462/* 463 * Return != 0 if "string" starts with "pattern" followed by whitespace. 464 * If it does, return a pointer to the first non space char. 465 */ 466static const char * 467startswith(const char *string, const char *pattern) 468{ 469 size_t l = strlen(pattern); 470 471 if (strlen(string) <= l) return NULL; 472 if (strncmp(string, pattern, l) != 0) return NULL; 473 string += l; 474 if (!isspace(*string)) return NULL; 475 while (isspace(*string)) 476 string++; 477 return string; 478} 479 480int 481main(int argc, char *argv[]) 482{ 483 int ai = 1; 484 int dec_chars = -1; 485 char *fsource = NULL; 486 FILE *fsource_fp; 487 int properties; 488 int default_char; 489 char *l = NULL; 490 char *t = NULL; 491 const char *nextc = NULL; 492 char *startfont = NULL; 493 char *slant = NULL; 494 char *spacing = NULL; 495 char *sc = NULL; 496 int code = -1; 497 da_t *startchar; 498 da_t *my_char; 499 char *fmap = NULL; 500 char *registry = NULL; 501 char *encoding = NULL; 502 char *fontname = NULL; 503 FILE *fmap_fp; 504 da_t *map; 505 da_t *headers; 506 int nextheader = -1; 507 int default_char_index = -1; 508 int startproperties_index = -1; 509 int fontname_index = -1; 510 int charset_registry_index = -1; 511 int slant_index = -1; 512 int spacing_index = -1; 513 int charset_encoding_index = -1; 514 int fontboundingbox_index = -1; 515 int target; 516 int ucs; 517 int i; 518 int j; 519 int *chars = NULL; 520 bbx_t bbx; 521 char *fout = NULL; 522 FILE *fout_fp; 523 int k; 524 char *registry_encoding = NULL; 525 526 my_name = argv[0]; 527 bbx.cheight = bbx.cxoff = bbx.cyoff = -1; 528 529 startchar = da_new("startchar"); 530 my_char = da_new("my_char"); 531 map = da_new("map"); 532 headers = da_new("headers"); 533 534 if (argc < 2) { 535 usage(); 536 exit(0); 537 } 538 539 /* check options */ 540 if (strcmp(argv[ai], "+d") == 0) { 541 ai++; 542 dec_chars = 1; 543 } else if (strcmp(argv[ai], "-d") == 0) { 544 ai++; 545 dec_chars = 0; 546 } 547 if (ai >= argc) { 548 usage(); 549 exit(0); 550 } 551 552 /* open and read source file */ 553 fsource = argv[ai]; 554 fsource_fp = fopen(fsource, "r"); 555 if (fsource_fp == NULL) { 556 fprintf(stderr, "%s: Can't read file '%s': %s!\n", my_name, 557 fsource, strerror(errno)); 558 exit(1); 559 } 560 561 /* read header */ 562 properties = 0; 563 default_char = 0; 564 while (read_line(fsource_fp, &l)) { 565 if (startswith(l, "CHARS")) 566 break; 567 if (startswith(l, "STARTFONT")) { 568 zstrcpy(&startfont, l); 569 } else if (startswith(l, "_XMBDFED_INFO") || 570 startswith(l, "XFREE86_GLYPH_RANGES")) 571 { 572 properties--; 573 } else if ((nextc = startswith(l, "DEFAULT_CHAR")) != NULL) 574 { 575 default_char = atoi(nextc); 576 default_char_index = ++nextheader; 577 da_add_str(headers, default_char_index, NULL); 578 } else { 579 if ((nextc = startswith(l, "STARTPROPERTIES")) != NULL) 580 { 581 properties = atoi(nextc); 582 startproperties_index = ++nextheader; 583 da_add_str(headers, startproperties_index, NULL); 584 } else if ((nextc = startswith(l, "FONT")) != NULL) 585 { 586 char * term; 587 /* slightly simplistic check ... */ 588 zquotedcpy(&fontname, nextc); 589 if (fontname == NULL) { 590 fprintf(stderr, 591 "%s: FONT name in '%s' is invalid string '%s'!\n", 592 my_name, fsource, nextc); 593 exit(1); 594 } 595 if ((term = strstr(fontname, "-ISO10646-1")) == NULL) { 596 fprintf(stderr, 597 "%s: FONT name in '%s' is '%s' and not '*-ISO10646-1'!\n", 598 my_name, fsource, fontname); 599 exit(1); 600 } 601 *term = '\0'; 602 fontname_index = ++nextheader; 603 da_add_str(headers, fontname_index, NULL); 604 } else if ((nextc = startswith(l, "CHARSET_REGISTRY")) != NULL) 605 { 606 if (strcmp(nextc, "\"ISO10646\"") != 0) { 607 fprintf(stderr, 608 "%s: CHARSET_REGISTRY in '%s' is '%s' and not 'ISO10646'!\n", 609 my_name, fsource, nextc); 610 exit(1); 611 } 612 charset_registry_index = ++nextheader; 613 da_add_str(headers, charset_registry_index, NULL); 614 } else if ((nextc = startswith(l, "CHARSET_ENCODING")) != NULL) 615 { 616 if (strcmp(nextc, "\"1\"") != 0) { 617 fprintf(stderr, 618 "%s: CHARSET_ENCODING in '%s' is '%s' and not '1'!\n", 619 my_name, fsource, nextc); 620 exit(1); 621 } 622 charset_encoding_index = ++nextheader; 623 da_add_str(headers, charset_encoding_index, NULL); 624 } else if (startswith(l, "FONTBOUNDINGBOX")) { 625 fontboundingbox_index = ++nextheader; 626 da_add_str(headers, fontboundingbox_index, NULL); 627 } else if ((nextc = startswith(l, "SLANT")) != NULL) 628 { 629 zquotedcpy(&slant, nextc); 630 if (slant == NULL) { 631 fprintf(stderr, 632 "%s: SLANT property in '%s' is invalid string '%s'!\n", 633 my_name, fsource, nextc); 634 exit(1); 635 } 636 slant_index = ++nextheader; 637 da_add_str(headers, slant_index, NULL); 638 } else if ((nextc = startswith(l, "SPACING")) != NULL) 639 { 640 zquotedcpy(&spacing, nextc); 641 if (spacing == NULL) { 642 fprintf(stderr, 643 "%s: SPACING property in '%s' is invalid string '%s'!\n", 644 my_name, fsource, nextc); 645 exit(1); 646 } 647 zstrtoupper(spacing); 648 spacing_index = ++nextheader; 649 da_add_str(headers, spacing_index, NULL); 650 } else if ((nextc = startswith(l, "COMMENT")) != NULL) { 651 if (strncmp(nextc, "$Id: ", 5)==0) { 652 char *header = NULL; 653 char *id = NULL, *end = NULL; 654 id = zstrdup(nextc + 5); 655 end = strrchr(id, '$'); 656 if (end) *end = '\0'; 657 zstrcpy(&header, "COMMENT Derived from "); 658 zstrcat(&header, id); 659 zstrcat(&header, "\n"); 660 free(id); 661 da_add_str(headers, ++nextheader, header); 662 free(header); 663 } else { 664 da_add_str(headers, ++nextheader, l); 665 } 666 } else { 667 da_add_str(headers, ++nextheader, l); 668 } 669 } 670 free(l); 671 } 672 673 if (startfont == NULL) { 674 fprintf(stderr, "%s: No STARTFONT line found in '%s'!\n", 675 my_name, fsource); 676 exit(1); 677 } 678 679 /* read characters */ 680 while (read_line(fsource_fp, &l)) { 681 if (startswith(l, "STARTCHAR")) { 682 zstrcpy(&sc, l); 683 zstrcat(&sc, "\n"); 684 code = -1; 685 } else if ((nextc = startswith(l, "ENCODING")) != NULL) { 686 code = atoi(nextc); 687 da_add_str(startchar, code, sc); 688 da_add_str(my_char, code, ""); 689 } else if (strcmp(l, "ENDFONT")==0) { 690 code = -1; 691 zstrcpy(&sc, "STARTCHAR ???\n"); 692 } else { 693 zstrcpy(&t, da_fetch_str(my_char, code)); 694 zstrcat(&t, l); 695 zstrcat(&t, "\n"); 696 da_add_str(my_char, code, t); 697 if (strcmp(l, "ENDCHAR")==0) { 698 code = -1; 699 zstrcpy(&sc, "STARTCHAR ???\n"); 700 } 701 } 702 free(l); 703 } 704 705 fclose(fsource_fp); 706 707 ai++; 708 while (ai < argc) { 709 zstrcpy(&fmap, argv[ai]); 710 i = ai + 1; 711 if (i < argc) { 712 char *temp = NULL; 713 char * hyphen = strchr(argv[i], '-'); 714 if (!hyphen || strchr(hyphen+1, '-') != NULL) { 715 fprintf(stderr, 716 "%s: Argument registry-encoding '%s' not in expected format!\n", 717 my_name, i < argc ? fmap : ""); 718 exit(1); 719 } 720 temp = zstrdup(argv[i]); 721 hyphen = strchr(temp, '-'); 722 if (hyphen) *hyphen = 0; 723 zstrcpy(®istry, temp); 724 zstrcpy(&encoding, hyphen+1); 725 free(temp); 726 } else { 727 fprintf(stderr, "map file argument \"%s\" needs a " 728 "corresponding registry-encoding argument\n", fmap); 729 exit(0); 730 } 731 732 ai++; 733 ai++; 734 735 /* open and read source file */ 736 fmap_fp = fopen(fmap, "r"); 737 if (fmap_fp == NULL) { 738 fprintf(stderr, 739 "%s: Can't read mapping file '%s': %s!\n", 740 my_name, fmap, strerror(errno)); 741 exit(1); 742 } 743 744 da_clear(map); 745 746 for (;read_line(fmap_fp, &l); free(l)) { 747 char *p, *endp; 748 749 for (p = l; isspace(p[0]); p++) 750 ; 751 if (p[0] == '\0' || p[0] == '#') 752 continue; 753 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 754 target = (int) strtol(p+2, &endp, 16); 755 if (*endp == '\0') goto bad; 756 p = endp; 757 } else 758 goto bad; 759 for (; isspace(p[0]); p++) 760 ; 761 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 762 ucs = (int) strtol(p+2, &endp, 16); 763 if (*endp == '\0') goto bad; 764 } else 765 goto bad; 766 767 if (!is_control(ucs)) { 768 if (zs_true(da_fetch_str(startchar, ucs))) 769 { 770 da_add_int(map, target, ucs); 771 } else { 772 if (!((is_blockgraphics(ucs) && 773 slant != NULL && 774 strcmp(slant, "R") != 0) || 775 (ucs >= 0x200e && 776 ucs <= 0x200f))) 777 { 778 fprintf(stderr, 779 "No glyph for character U+%04X (0x%02x) available.\n", 780 ucs, target); 781 } 782 } 783 } 784 continue; 785 bad: 786 fprintf(stderr, "Unrecognized line in '%s':\n%s\n", fmap, l); 787 } 788 fclose(fmap_fp); 789 790 /* add default character */ 791 if (!zi_true(da_fetch_int(map, 0))) { 792 if (zs_true(da_fetch_str(startchar, default_char))) { 793 da_add_int(map, 0, default_char); 794 da_add_str(startchar, default_char, 795 "STARTCHAR defaultchar\n"); 796 } else { 797 fprintf(stderr, "%s", 798 "No default character defined.\n"); 799 } 800 } 801 802 if (dec_chars == 1 || 803 (dec_chars == -1 && 804 (slant != NULL && strcmp(slant, "R") == 0) && 805 (spacing != NULL && strcmp(spacing, "C") == 0))) 806 { 807 /* add DEC VT100 graphics characters in the range 1-31 808 (as expected by some old xterm versions) */ 809 for (i = 0; i < decmap_size; i++) { 810 if (zs_true(da_fetch_str(startchar, decmap[i]))) 811 { 812 da_add_int(map, i + 1, decmap[i]); 813 } 814 } 815 } 816 817 /* list of characters that will be written out */ 818 j = da_count(map); 819 if (j < 0) { 820 fprintf(stderr, 821 "No characters found for %s-%s.\n", 822 registry, encoding); 823 continue; 824 } 825 if (chars != NULL) 826 free(chars); 827 chars = zmalloc(j * sizeof(int)); 828 memset(chars, 0, j * sizeof(int)); 829 for (k = 0, i = 0; k < da_count(map) && i < da_size(map); i++) { 830 if (da_fetch(map, i) != NULL) 831 chars[k++] = i; 832 } 833 qsort(chars, j, sizeof(int), chars_compare); 834 835 /* find overall font bounding box */ 836 bbx.cwidth = -1; 837 for (i = 0; i < j; i++) { 838 ucs = da_fetch_int(map, chars[i]); 839 zstrcpy(&t, da_fetch_str(my_char, ucs)); 840 if ((nextc = startswith(t, "BBX")) != NULL 841 || (nextc = strstr(t, "\nBBX")) != NULL) 842 { 843 char *endp; 844 int w, h, x, y; 845 846 if (*nextc == '\n') { 847 nextc += 4; 848 while (isspace(*nextc)) 849 nextc++; 850 } 851 for (;isspace(*nextc);) 852 nextc++; 853 w = (int) strtol(nextc, &endp, 10); 854 nextc = endp; 855 if (*nextc == '\0') goto bbxbad; 856 for (;isspace(*nextc);) 857 nextc++; 858 h = (int) strtol(nextc, &endp, 10); 859 nextc = endp; 860 if (*nextc == '\0') goto bbxbad; 861 for (;isspace(*nextc);) 862 nextc++; 863 x = (int) strtol(nextc, &endp, 10); 864 nextc = endp; 865 if (*nextc == '\0') goto bbxbad; 866 for (;isspace(*nextc);) 867 nextc++; 868 y = (int) strtol(nextc, &endp, 10); 869 if (bbx.cwidth == -1) { 870 bbx.cwidth = w; 871 bbx.cheight = h; 872 bbx.cxoff = x; 873 bbx.cyoff = y; 874 } else { 875 combine_bbx(bbx.cwidth, bbx.cheight, 876 bbx.cxoff, bbx.cyoff, 877 w, h, x, y, &bbx); 878 } 879 continue; 880 bbxbad: 881 fprintf(stderr, "Unparsable BBX found for U+%04x!\n", ucs); 882 } else { 883 fprintf(stderr, 884 "Warning: No BBX found for U+%04X!\n", 885 ucs); 886 } 887 } 888 889 if (!registry) registry = zstrdup(""); 890 if (!encoding) encoding = zstrdup(""); 891 892 /* generate output file name */ 893 zstrcpy(®istry_encoding, "-"); 894 zstrcat(®istry_encoding, registry); 895 zstrcat(®istry_encoding, "-"); 896 zstrcat(®istry_encoding, encoding); 897 898 { 899 char * p = strstr(fsource, ".bdf"); 900 if (p) { 901 zstrcpy(&fout, fsource); 902 p = strstr(fout, ".bdf"); 903 *p = 0; 904 zstrcat(&fout, registry_encoding); 905 zstrcat(&fout, ".bdf"); 906 } else { 907 zstrcpy(&fout, fsource); 908 zstrcat(&fout, registry_encoding); 909 } 910 } 911 912 /* remove path prefix */ 913 zstrcpy(&t, basename(fout)); 914 zstrcpy(&fout, t); 915 916 /* write new BDF file */ 917 fprintf(stderr, "Writing %d characters into file '%s'.\n", 918 j, fout); 919 fout_fp = fopen(fout, "w"); 920 if (fout_fp == NULL) { 921 fprintf(stderr, "%s: Can't write file '%s': %s!\n", 922 my_name, fout, strerror(errno)); 923 exit(1); 924 } 925 926 fprintf(fout_fp, "%s\n", startfont); 927 fprintf(fout_fp, "%s", 928 "COMMENT AUTOMATICALLY GENERATED FILE. DO NOT EDIT!\n"); 929 fprintf(fout_fp, 930 "COMMENT Generated with 'ucs2any %s %s %s-%s'\n", 931 fsource, fmap, registry, encoding); 932 fprintf(fout_fp, "%s", 933 "COMMENT from an ISO10646-1 encoded source BDF font.\n"); 934 fprintf(fout_fp, "%s", 935 "COMMENT ucs2any by Ben Collver <collver1@attbi.com>, 2003, based on\n"); 936 fprintf(fout_fp, "%s", 937 "COMMENT ucs2any.pl by Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/>, 2000.\n"); 938 939 for (i = 0; i <= nextheader; i++) { 940 if (i == default_char_index) 941 fprintf(fout_fp, "DEFAULT_CHAR %d\n", default_char); 942 else if (i == startproperties_index) 943 fprintf(fout_fp, "STARTPROPERTIES %d\n", properties); 944 else if (i == fontname_index) { 945 fprintf(fout_fp, "FONT %s%s\n", fontname, registry_encoding); 946 } 947 else if (i == charset_registry_index) 948 fprintf(fout_fp, "CHARSET_REGISTRY \"%s\"\n", registry); 949 else if (i == slant_index) 950 fprintf(fout_fp, "SLANT \"%s\"\n", slant); 951 else if (i == charset_encoding_index) 952 fprintf(fout_fp, "CHARSET_ENCODING \"%s\"\n", encoding); 953 else if (i == fontboundingbox_index) 954 fprintf(fout_fp, "FONTBOUNDINGBOX %d %d %d %d\n", bbx.cwidth, bbx.cheight, bbx.cxoff, bbx.cyoff); 955 else if (i == spacing_index) 956 fprintf(fout_fp, "SPACING \"%s\"\n", spacing); 957 else 958 fprintf(fout_fp, "%s\n", da_fetch_str(headers, i)); 959 } 960 961 fprintf(fout_fp, "CHARS %d\n", j); 962 963 /* Write characters */ 964 for (i = 0; i < j; i++) { 965 ucs = da_fetch_int(map, chars[i]); 966 fprintf(fout_fp, "%s", da_fetch_str(startchar, 967 ucs)); 968 fprintf(fout_fp, "ENCODING %d\n", chars[i]); 969 fprintf(fout_fp, "%s", da_fetch_str(my_char, 970 ucs)); 971 } 972 fprintf(fout_fp, "%s", "ENDFONT\n"); 973 fclose(fout_fp); 974 } 975 976 exit(0); 977} 978