ucs2any.c revision 38c51623
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 reencode 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 ((term = strstr(fontname, "-ISO10646-1")) == NULL) { 590 fprintf(stderr, 591 "%s: FONT name in '%s' is '%s' and not '*-ISO10646-1'!\n", 592 my_name, fsource, fontname); 593 exit(1); 594 } 595 *term = '\0'; 596 fontname_index = ++nextheader; 597 da_add_str(headers, fontname_index, NULL); 598 } else if ((nextc = startswith(l, "CHARSET_REGISTRY")) != NULL) 599 { 600 if (strcmp(nextc, "\"ISO10646\"") != 0) { 601 fprintf(stderr, 602 "%s: CHARSET_REGISTRY in '%s' is '%s' and not 'ISO10646'!\n", 603 my_name, fsource, nextc); 604 exit(1); 605 } 606 charset_registry_index = ++nextheader; 607 da_add_str(headers, charset_registry_index, NULL); 608 } else if ((nextc = startswith(l, "CHARSET_ENCODING")) != NULL) 609 { 610 if (strcmp(nextc, "\"1\"") != 0) { 611 fprintf(stderr, 612 "%s: CHARSET_ENCODING in '%s' is '%s' and not '1'!\n", 613 my_name, fsource, nextc); 614 exit(1); 615 } 616 charset_encoding_index = ++nextheader; 617 da_add_str(headers, charset_encoding_index, NULL); 618 } else if (startswith(l, "FONTBOUNDINGBOX")) { 619 fontboundingbox_index = ++nextheader; 620 da_add_str(headers, fontboundingbox_index, NULL); 621 } else if ((nextc = startswith(l, "SLANT")) != NULL) 622 { 623 zquotedcpy(&slant, nextc); 624 slant_index = ++nextheader; 625 da_add_str(headers, slant_index, NULL); 626 } else if ((nextc = startswith(l, "SPACING")) != NULL) 627 { 628 zquotedcpy(&spacing, nextc); 629 zstrtoupper(spacing); 630 spacing_index = ++nextheader; 631 da_add_str(headers, spacing_index, NULL); 632 } else if ((nextc = startswith(l, "COMMENT")) != NULL) { 633 if (strncmp(nextc, "$Id: ", 5)==0) { 634 char *header = NULL; 635 char *id = NULL, *end = NULL; 636 id = zstrdup(nextc + 5); 637 end = strrchr(id, '$'); 638 if (end) *end = '\0'; 639 zstrcpy(&header, "COMMENT Derived from "); 640 zstrcat(&header, id); 641 zstrcat(&header, "\n"); 642 free(id); 643 da_add_str(headers, ++nextheader, header); 644 free(header); 645 } else { 646 da_add_str(headers, ++nextheader, l); 647 } 648 } else { 649 da_add_str(headers, ++nextheader, l); 650 } 651 } 652 free(l); 653 } 654 655 if (startfont == NULL) { 656 fprintf(stderr, "%s: No STARTFONT line found in '%s'!\n", 657 my_name, fsource); 658 exit(1); 659 } 660 661 /* read characters */ 662 while (read_line(fsource_fp, &l)) { 663 if (startswith(l, "STARTCHAR")) { 664 zstrcpy(&sc, l); 665 zstrcat(&sc, "\n"); 666 code = -1; 667 } else if ((nextc = startswith(l, "ENCODING")) != NULL) { 668 code = atoi(nextc); 669 da_add_str(startchar, code, sc); 670 da_add_str(my_char, code, ""); 671 } else if (strcmp(l, "ENDFONT")==0) { 672 code = -1; 673 zstrcpy(&sc, "STARTCHAR ???\n"); 674 } else { 675 zstrcpy(&t, da_fetch_str(my_char, code)); 676 zstrcat(&t, l); 677 zstrcat(&t, "\n"); 678 da_add_str(my_char, code, t); 679 if (strcmp(l, "ENDCHAR")==0) { 680 code = -1; 681 zstrcpy(&sc, "STARTCHAR ???\n"); 682 } 683 } 684 free(l); 685 } 686 687 fclose(fsource_fp); 688 689 ai++; 690 while (ai < argc) { 691 zstrcpy(&fmap, argv[ai]); 692 i = ai + 1; 693 if (i < argc) { 694 char *temp = NULL; 695 char * hyphen = strchr(argv[i], '-'); 696 if (!hyphen || strchr(hyphen+1, '-') != NULL) { 697 fprintf(stderr, 698 "%s: Argument registry-encoding '%s' not in expected format!\n", 699 my_name, i < argc ? fmap : ""); 700 exit(1); 701 } 702 temp = zstrdup(argv[i]); 703 hyphen = strchr(temp, '-'); 704 if (hyphen) *hyphen = 0; 705 zstrcpy(®istry, temp); 706 zstrcpy(&encoding, hyphen+1); 707 free(temp); 708 } else { 709 fprintf(stderr, "map file argument \"%s\" needs a " 710 "coresponding registry-encoding argument\n", fmap); 711 exit(0); 712 } 713 714 ai++; 715 ai++; 716 717 /* open and read source file */ 718 fmap_fp = fopen(fmap, "r"); 719 if (fmap_fp == NULL) { 720 fprintf(stderr, 721 "%s: Can't read mapping file '%s': %s!\n", 722 my_name, fmap, strerror(errno)); 723 exit(1); 724 } 725 726 da_clear(map); 727 728 for (;read_line(fmap_fp, &l); free(l)) { 729 char *p, *endp; 730 731 for (p = l; isspace(p[0]); p++) 732 ; 733 if (p[0] == '\0' || p[0] == '#') 734 continue; 735 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 736 target = (int) strtol(p+2, &endp, 16); 737 if (*endp == '\0') goto bad; 738 p = endp; 739 } else 740 goto bad; 741 for (; isspace(p[0]); p++) 742 ; 743 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 744 ucs = (int) strtol(p+2, &endp, 16); 745 if (*endp == '\0') goto bad; 746 } else 747 goto bad; 748 749 if (!is_control(ucs)) { 750 if (zs_true(da_fetch_str(startchar, ucs))) 751 { 752 da_add_int(map, target, ucs); 753 } else { 754 if (!((is_blockgraphics(ucs) && 755 strcmp(slant, "R") != 0) || 756 (ucs >= 0x200e && 757 ucs <= 0x200f))) { 758 fprintf(stderr, 759 "No glyph for character U+%04X (0x%02x) available.\n", 760 ucs, target); 761 } 762 } 763 } 764 continue; 765 bad: 766 fprintf(stderr, "Unrecognized line in '%s':\n%s\n", fmap, l); 767 } 768 fclose(fmap_fp); 769 770 /* add default character */ 771 if (!zi_true(da_fetch_int(map, 0))) { 772 if (zs_true(da_fetch_str(startchar, default_char))) { 773 da_add_int(map, 0, default_char); 774 da_add_str(startchar, default_char, 775 "STARTCHAR defaultchar\n"); 776 } else { 777 fprintf(stderr, "%s", 778 "No default character defined.\n"); 779 } 780 } 781 782 if (dec_chars == 1 || 783 (dec_chars == -1 && strcmp(slant, "R") == 0 && 784 strcmp(spacing, "C") == 0)) 785 { 786 /* add DEC VT100 graphics characters in the range 1-31 787 (as expected by some old xterm versions) */ 788 for (i = 0; i < decmap_size; i++) { 789 if (zs_true(da_fetch_str(startchar, decmap[i]))) 790 { 791 da_add_int(map, i + 1, decmap[i]); 792 } 793 } 794 } 795 796 /* list of characters that will be written out */ 797 j = da_count(map); 798 if (j < 0) { 799 fprintf(stderr, 800 "No characters found for %s-%s.\n", 801 registry, encoding); 802 continue; 803 } 804 if (chars != NULL) 805 free(chars); 806 chars = zmalloc(j * sizeof(int)); 807 memset(chars, 0, j * sizeof(int)); 808 for (k = 0, i = 0; k < da_count(map) && i < da_size(map); i++) { 809 if (da_fetch(map, i) != NULL) 810 chars[k++] = i; 811 } 812 qsort(chars, j, sizeof(int), chars_compare); 813 814 /* find overall font bounding box */ 815 bbx.cwidth = -1; 816 for (i = 0; i < j; i++) { 817 ucs = da_fetch_int(map, chars[i]); 818 zstrcpy(&t, da_fetch_str(my_char, ucs)); 819 if ((nextc = startswith(t, "BBX")) != NULL 820 || (nextc = strstr(t, "\nBBX")) != NULL) 821 { 822 char *endp; 823 int w, h, x, y; 824 825 if (*nextc == '\n') { 826 nextc += 4; 827 while (isspace(*nextc)) 828 nextc++; 829 } 830 for (;isspace(*nextc);) 831 nextc++; 832 w = (int) strtol(nextc, &endp, 10); 833 nextc = endp; 834 if (*nextc == '\0') goto bbxbad; 835 for (;isspace(*nextc);) 836 nextc++; 837 h = (int) strtol(nextc, &endp, 10); 838 nextc = endp; 839 if (*nextc == '\0') goto bbxbad; 840 for (;isspace(*nextc);) 841 nextc++; 842 x = (int) strtol(nextc, &endp, 10); 843 nextc = endp; 844 if (*nextc == '\0') goto bbxbad; 845 for (;isspace(*nextc);) 846 nextc++; 847 y = (int) strtol(nextc, &endp, 10); 848 if (bbx.cwidth == -1) { 849 bbx.cwidth = w; 850 bbx.cheight = h; 851 bbx.cxoff = x; 852 bbx.cyoff = y; 853 } else { 854 combine_bbx(bbx.cwidth, bbx.cheight, 855 bbx.cxoff, bbx.cyoff, 856 w, h, x, y, &bbx); 857 } 858 continue; 859 bbxbad: 860 fprintf(stderr, "Unparsable BBX found for U+%04x!\n", ucs); 861 } else { 862 fprintf(stderr, 863 "Warning: No BBX found for U+%04X!\n", 864 ucs); 865 } 866 } 867 868 if (!registry) registry = zstrdup(""); 869 if (!encoding) encoding = zstrdup(""); 870 871 /* generate output file name */ 872 zstrcpy(®istry_encoding, "-"); 873 zstrcat(®istry_encoding, registry); 874 zstrcat(®istry_encoding, "-"); 875 zstrcat(®istry_encoding, encoding); 876 877 { 878 char * p = strstr(fsource, ".bdf"); 879 if (p) { 880 zstrcpy(&fout, fsource); 881 p = strstr(fout, ".bdf"); 882 *p = 0; 883 zstrcat(&fout, registry_encoding); 884 zstrcat(&fout, ".bdf"); 885 } else { 886 zstrcpy(&fout, fsource); 887 zstrcat(&fout, registry_encoding); 888 } 889 } 890 891 /* remove path prefix */ 892 zstrcpy(&t, basename(fout)); 893 zstrcpy(&fout, t); 894 895 /* write new BDF file */ 896 fprintf(stderr, "Writing %d characters into file '%s'.\n", 897 j, fout); 898 fout_fp = fopen(fout, "w"); 899 if (fout_fp == NULL) { 900 fprintf(stderr, "%s: Can't write file '%s': %s!\n", 901 my_name, fout, strerror(errno)); 902 exit(1); 903 } 904 905 fprintf(fout_fp, "%s\n", startfont); 906 fprintf(fout_fp, "%s", 907 "COMMENT AUTOMATICALLY GENERATED FILE. DO NOT EDIT!\n"); 908 fprintf(fout_fp, 909 "COMMENT Generated with 'ucs2any %s %s %s-%s'\n", 910 fsource, fmap, registry, encoding); 911 fprintf(fout_fp, "%s", 912 "COMMENT from an ISO10646-1 encoded source BDF font.\n"); 913 fprintf(fout_fp, "%s", 914 "COMMENT ucs2any by Ben Collver <collver1@attbi.com>, 2003, based on\n"); 915 fprintf(fout_fp, "%s", 916 "COMMENT ucs2any.pl by Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/>, 2000.\n"); 917 918 for (i = 0; i <= nextheader; i++) { 919 if (i == default_char_index) 920 fprintf(fout_fp, "DEFAULT_CHAR %d\n", default_char); 921 else if (i == startproperties_index) 922 fprintf(fout_fp, "STARTPROPERTIES %d\n", properties); 923 else if (i == fontname_index) { 924 fprintf(fout_fp, "FONT %s%s\n", fontname, registry_encoding); 925 } 926 else if (i == charset_registry_index) 927 fprintf(fout_fp, "CHARSET_REGISTRY \"%s\"\n", registry); 928 else if (i == slant_index) 929 fprintf(fout_fp, "SLANT \"%s\"\n", slant); 930 else if (i == charset_encoding_index) 931 fprintf(fout_fp, "CHARSET_ENCODING \"%s\"\n", encoding); 932 else if (i == fontboundingbox_index) 933 fprintf(fout_fp, "FONTBOUNDINGBOX %d %d %d %d\n", bbx.cwidth, bbx.cheight, bbx.cxoff, bbx.cyoff); 934 else if (i == spacing_index) 935 fprintf(fout_fp, "SPACING \"%s\"\n", spacing); 936 else 937 fprintf(fout_fp, "%s\n", da_fetch_str(headers, i)); 938 } 939 940 fprintf(fout_fp, "CHARS %d\n", j); 941 942 /* Write characters */ 943 for (i = 0; i < j; i++) { 944 ucs = da_fetch_int(map, chars[i]); 945 fprintf(fout_fp, "%s", da_fetch_str(startchar, 946 ucs)); 947 fprintf(fout_fp, "ENCODING %d\n", chars[i]); 948 fprintf(fout_fp, "%s", da_fetch_str(my_char, 949 ucs)); 950 } 951 fprintf(fout_fp, "%s", "ENDFONT\n"); 952 fclose(fout_fp); 953 } 954 955 exit(0); 956} 957