ucs2any.c revision 89d09728
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/* $XFree86$ */ 30/* 31 * This utility allows you to generate from an ISO10646-1 encoded 32 * BDF font other BDF fonts in any possible encoding. This way, you can 33 * derive from a single ISO10646-1 master font a whole set of 8-bit 34 * fonts in all ISO 8859 and various other encodings. (Hopefully 35 * a future XFree86 release will have a similar facility built into 36 * the server, which can reencode ISO10646-1 on the fly, because 37 * storing the same fonts in many different encodings is clearly 38 * a waste of storage capacity). 39*/ 40 41#include <ctype.h> 42#include <errno.h> 43#include <fcntl.h> 44#if !defined(NEED_BASENAME) && !defined(Lynx) 45#include <libgen.h> 46#endif 47#include <limits.h> 48#include <stdarg.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 int dest_size = 1; 145 int 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 = 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(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 (key >= da->size) { 225 da->size = key + 1; 226 da->values = zrealloc(da->values, 227 da->size * sizeof(void *)); 228 for (; i < da->size; i++) 229 da->values[i] = NULL; 230 } 231 if (da->values[key] != NULL) { 232 free(da->values[key]); 233 } else { 234 if (value == NULL) { 235 if (da->count > 0) 236 da->count--; 237 } else { 238 da->count++; 239 } 240 } 241 da->values[key] = value; 242 } else if (key == -1) { 243 if (da->nv != NULL) 244 free(da->nv); 245 da->nv = value; 246 } 247} 248 249static void 250da_add_str(da_t *da, int key, char *value) 251{ 252 da_add(da, key, value?zstrdup(value):NULL); 253} 254 255static void 256da_add_int(da_t *da, int key, int value) 257{ 258 int *v; 259 260 v = zmalloc(sizeof(int)); 261 *v = value; 262 da_add(da, key, v); 263} 264 265#define da_count(da) (da->count) 266#define da_size(da) (da->size) 267 268static void 269da_clear(da_t *da) 270{ 271 int i; 272 273 for (i = da->size; i; i--) 274 free(da->values[i]); 275 if (da->values != NULL) 276 free(da->values); 277 da->size = 0; 278 da->count = 0; 279 da->values = NULL; 280} 281 282/* "CLASS" file input */ 283 284#define TYPICAL_LINE_SIZE (80) 285 286/* read a line and strip trailing whitespace */ 287static int 288read_line(FILE *fp, char **buffer) 289{ 290 int buffer_size = TYPICAL_LINE_SIZE; 291 int eof = 0; 292 int position = 0; 293 int c; 294 295 *buffer = zmalloc(TYPICAL_LINE_SIZE); 296 (*buffer)[0] = '\0'; 297 298 if ((c = getc(fp)) == EOF) 299 eof = 1; 300 301 while (c != '\n' && !eof) { 302 if (position + 1 >= buffer_size) { 303 buffer_size = buffer_size * 2 + 1; 304 *buffer = zrealloc(*buffer, buffer_size); 305 } 306 (*buffer)[position++] = c; 307 (*buffer)[position] = '\0'; 308 c = getc(fp); 309 if (c == EOF) 310 eof = 1; 311 } 312 313 if (eof) { 314 free(*buffer); 315 *buffer = NULL; 316 return 0; 317 } 318 319 while (position > 1) { 320 position--; 321 if (!isspace((*buffer)[position])) 322 break; 323 (*buffer)[position] = '\0'; 324 } 325 326 return 1; 327} 328 329/* BEGIN */ 330 331/* 332DEC VT100 graphics characters in the range 1-31 (as expected by 333some old xterm versions and a few other applications) 334*/ 335#define decmap_size 31 336static int decmap[decmap_size] = { 337 0x25C6, /* BLACK DIAMOND */ 338 0x2592, /* MEDIUM SHADE */ 339 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */ 340 0x240C, /* SYMBOL FOR FORM FEED */ 341 0x240D, /* SYMBOL FOR CARRIAGE RETURN */ 342 0x240A, /* SYMBOL FOR LINE FEED */ 343 0x00B0, /* DEGREE SIGN */ 344 0x00B1, /* PLUS-MINUS SIGN */ 345 0x2424, /* SYMBOL FOR NEWLINE */ 346 0x240B, /* SYMBOL FOR VERTICAL TABULATION */ 347 0x2518, /* BOX DRAWINGS LIGHT UP AND LEFT */ 348 0x2510, /* BOX DRAWINGS LIGHT DOWN AND LEFT */ 349 0x250C, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ 350 0x2514, /* BOX DRAWINGS LIGHT UP AND RIGHT */ 351 0x253C, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ 352 0x23BA, /* HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ 353 0x23BB, /* HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ 354 0x2500, /* BOX DRAWINGS LIGHT HORIZONTAL */ 355 0x23BC, /* HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ 356 0x23BD, /* HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ 357 0x251C, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ 358 0x2524, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ 359 0x2534, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ 360 0x252C, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ 361 0x2502, /* BOX DRAWINGS LIGHT VERTICAL */ 362 0x2264, /* LESS-THAN OR EQUAL TO */ 363 0x2265, /* GREATER-THAN OR EQUAL TO */ 364 0x03C0, /* GREEK SMALL LETTER PI */ 365 0x2260, /* NOT EQUAL TO */ 366 0x00A3, /* POUND SIGN */ 367 0x00B7 /* MIDDLE DOT */ 368}; 369 370static int 371is_control(int ucs) 372{ 373 return ((ucs >= 0x00 && ucs <= 0x1f) || 374 (ucs >= 0x7f && ucs <= 0x9f)); 375} 376 377static int 378is_blockgraphics(int ucs) 379{ 380 return ucs >= 0x2500 && ucs <= 0x25FF; 381} 382 383/* calculate the bounding box that covers both provided bounding boxes */ 384typedef struct { 385 int cwidth; 386 int cheight; 387 int cxoff; 388 int cyoff; 389} bbx_t; 390 391static bbx_t * 392combine_bbx(int awidth, int aheight, int axoff, int ayoff, 393 int cwidth, int cheight, int cxoff, int cyoff, bbx_t *r) 394{ 395 r->cwidth = cwidth; 396 r->cheight = cheight; 397 r->cxoff = cxoff; 398 r->cyoff = cyoff; 399 400 if (axoff < r->cxoff) { 401 r->cwidth += r->cxoff - axoff; 402 r->cxoff = axoff; 403 } 404 if (ayoff < r->cyoff) { 405 r->cheight += r->cyoff - ayoff; 406 r->cyoff = ayoff; 407 } 408 if (awidth + axoff > r->cwidth + r->cxoff) { 409 r->cwidth = awidth + axoff - r->cxoff; 410 } 411 if (aheight + ayoff > r->cheight + r->cyoff) { 412 r->cheight = aheight + ayoff - r->cyoff; 413 } 414 415 return r; 416} 417 418static void 419usage(void) { 420 printf("%s", "\n" 421"Usage: ucs2any [+d|-d] <source-name> { <mapping-file> <registry-encoding> }\n" 422"\n" 423"where\n" 424"\n" 425" +d put DEC VT100 graphics characters in the C0 range\n" 426" (default for upright charcell fonts)\n" 427"\n" 428" -d do not put DEC VT100 graphics characters in the\n" 429" C0 range (default for all other font types)\n" 430"\n" 431" <source-name> is the name of an ISO10646-1 encoded BDF file\n" 432"\n" 433" <mapping-file> is the name of a character set table like those on\n" 434" <ftp://ftp.unicode.org/Public/MAPPINGS/>\n" 435"\n" 436" <registry-encoding> are the CHARSET_REGISTRY and CHARSET_ENCODING\n" 437" field values for the font name (XLFD) of the\n" 438" target font, separated by a hyphen\n" 439"\n" 440"Example:\n" 441"\n" 442" ucs2any 6x13.bdf 8859-1.TXT iso8859-1 8859-2.TXT iso8859-2\n" 443"\n" 444"will generate the files 6x13-iso8859-1.bdf and 6x13-iso8859-2.bdf\n" 445"\n"); 446} 447 448static int 449chars_compare(const void *aa, const void *bb) 450{ 451 int a = *(int *)aa; 452 int b = *(int *)bb; 453 454 return a - b; 455} 456 457/* 458 * Return != 0 if "string" starts with "pattern" followed by whitespace. 459 * If it does, return a pointer to the first non space char. 460 */ 461static const char * 462startswith(const char *string, const char *pattern) 463{ 464 int l = strlen(pattern); 465 466 if (strlen(string) <= l) return NULL; 467 if (strncmp(string, pattern, l) != 0) return NULL; 468 string += l; 469 if (!isspace(*string)) return NULL; 470 while (isspace(*string)) 471 string++; 472 return string; 473} 474 475int 476main(int argc, char *argv[]) 477{ 478 int ai = 1; 479 int dec_chars = -1; 480 char *fsource = NULL; 481 FILE *fsource_fp; 482 int properties; 483 int default_char; 484 char *l = NULL; 485 char *t = NULL; 486 const char *nextc = NULL; 487 char *startfont = NULL; 488 char *slant = NULL; 489 char *spacing = NULL; 490 char *sc = NULL; 491 int code = -1; 492 da_t *startchar; 493 da_t *my_char; 494 char *fmap = NULL; 495 char *registry = NULL; 496 char *encoding = NULL; 497 char *fontname = NULL; 498 FILE *fmap_fp; 499 da_t *map; 500 da_t *headers; 501 int nextheader = -1; 502 int default_char_index = -1; 503 int startproperties_index = -1; 504 int fontname_index = -1; 505 int charset_registry_index = -1; 506 int slant_index = -1; 507 int spacing_index = -1; 508 int charset_encoding_index = -1; 509 int fontboundingbox_index = -1; 510 int target; 511 int ucs; 512 int i; 513 int j; 514 int *chars = NULL; 515 bbx_t bbx; 516 char *fout = NULL; 517 FILE *fout_fp; 518 int k; 519 char *registry_encoding = NULL; 520 521 my_name = argv[0]; 522 bbx.cheight = bbx.cxoff = bbx.cyoff = -1; 523 524 startchar = da_new("startchar"); 525 my_char = da_new("my_char"); 526 map = da_new("map"); 527 headers = da_new("headers"); 528 529 if (argc < 2) { 530 usage(); 531 exit(0); 532 } 533 534 /* check options */ 535 if (strcmp(argv[ai], "+d") == 0) { 536 ai++; 537 dec_chars = 1; 538 } else if (strcmp(argv[ai], "-d") == 0) { 539 ai++; 540 dec_chars = 0; 541 } 542 if (ai >= argc) { 543 usage(); 544 exit(0); 545 } 546 547 /* open and read source file */ 548 fsource = argv[ai]; 549 fsource_fp = fopen(fsource, "r"); 550 if (fsource_fp == NULL) { 551 fprintf(stderr, "%s: Can't read file '%s': %s!\n", my_name, 552 fsource, strerror(errno)); 553 exit(1); 554 } 555 556 /* read header */ 557 properties = 0; 558 default_char = 0; 559 while (read_line(fsource_fp, &l)) { 560 if (startswith(l, "CHARS")) 561 break; 562 if (startswith(l, "STARTFONT")) { 563 zstrcpy(&startfont, l); 564 } else if (startswith(l, "_XMBDFED_INFO") || 565 startswith(l, "XFREE86_GLYPH_RANGES")) 566 { 567 properties--; 568 } else if ((nextc = startswith(l, "DEFAULT_CHAR")) != NULL) 569 { 570 default_char = atoi(nextc); 571 default_char_index = ++nextheader; 572 da_add_str(headers, default_char_index, NULL); 573 } else { 574 if ((nextc = startswith(l, "STARTPROPERTIES")) != NULL) 575 { 576 properties = atoi(nextc); 577 startproperties_index = ++nextheader; 578 da_add_str(headers, startproperties_index, NULL); 579 } else if ((nextc = startswith(l, "FONT")) != NULL) 580 { 581 char * term; 582 /* slightly simplistic check ... */ 583 zquotedcpy(&fontname, nextc); 584 if ((term = strstr(fontname, "-ISO10646-1")) == NULL) { 585 fprintf(stderr, 586 "%s: FONT name in '%s' is '%s' and not '*-ISO10646-1'!\n", 587 my_name, fsource, fontname); 588 exit(1); 589 } 590 *term = '\0'; 591 fontname_index = ++nextheader; 592 da_add_str(headers, fontname_index, NULL); 593 } else if ((nextc = startswith(l, "CHARSET_REGISTRY")) != NULL) 594 { 595 if (strcmp(nextc, "\"ISO10646\"") != 0) { 596 fprintf(stderr, 597 "%s: CHARSET_REGISTRY in '%s' is '%s' and not 'ISO10646'!\n", 598 my_name, fsource, nextc); 599 exit(1); 600 } 601 charset_registry_index = ++nextheader; 602 da_add_str(headers, charset_registry_index, NULL); 603 } else if ((nextc = startswith(l, "CHARSET_ENCODING")) != NULL) 604 { 605 if (strcmp(nextc, "\"1\"") != 0) { 606 fprintf(stderr, 607 "%s: CHARSET_ENCODING in '%s' is '%s' and not '1'!\n", 608 my_name, fsource, nextc); 609 exit(1); 610 } 611 charset_encoding_index = ++nextheader; 612 da_add_str(headers, charset_encoding_index, NULL); 613 } else if (startswith(l, "FONTBOUNDINGBOX")) { 614 fontboundingbox_index = ++nextheader; 615 da_add_str(headers, fontboundingbox_index, NULL); 616 } else if ((nextc = startswith(l, "SLANT")) != NULL) 617 { 618 zquotedcpy(&slant, nextc); 619 slant_index = ++nextheader; 620 da_add_str(headers, slant_index, NULL); 621 } else if ((nextc = startswith(l, "SPACING")) != NULL) 622 { 623 zquotedcpy(&spacing, nextc); 624 zstrtoupper(spacing); 625 spacing_index = ++nextheader; 626 da_add_str(headers, spacing_index, NULL); 627 } else if ((nextc = startswith(l, "COMMENT")) != NULL) { 628 if (strncmp(nextc, "$Id: ", 5)==0) { 629 char *header = NULL; 630 char *id = NULL, *end = NULL; 631 id = zstrdup(nextc + 5); 632 end = strrchr(id, '$'); 633 if (end) *end = '\0'; 634 zstrcpy(&header, "COMMENT Derived from "); 635 zstrcat(&header, id); 636 zstrcat(&header, "\n"); 637 free(id); 638 da_add_str(headers, ++nextheader, header); 639 free(header); 640 } else { 641 da_add_str(headers, ++nextheader, l); 642 } 643 } else { 644 da_add_str(headers, ++nextheader, l); 645 } 646 } 647 free(l); 648 } 649 650 if (startfont == NULL) { 651 fprintf(stderr, "%s: No STARTFONT line found in '%s'!\n", 652 my_name, fsource); 653 exit(1); 654 } 655 656 /* read characters */ 657 while (read_line(fsource_fp, &l)) { 658 if (startswith(l, "STARTCHAR")) { 659 zstrcpy(&sc, l); 660 zstrcat(&sc, "\n"); 661 code = -1; 662 } else if ((nextc = startswith(l, "ENCODING")) != NULL) { 663 code = atoi(nextc); 664 da_add_str(startchar, code, sc); 665 da_add_str(my_char, code, ""); 666 } else if (strcmp(l, "ENDFONT")==0) { 667 code = -1; 668 zstrcpy(&sc, "STARTCHAR ???\n"); 669 } else { 670 zstrcpy(&t, da_fetch_str(my_char, code)); 671 zstrcat(&t, l); 672 zstrcat(&t, "\n"); 673 da_add_str(my_char, code, t); 674 if (strcmp(l, "ENDCHAR")==0) { 675 code = -1; 676 zstrcpy(&sc, "STARTCHAR ???\n"); 677 } 678 } 679 free(l); 680 } 681 682 fclose(fsource_fp); 683 684 ai++; 685 while (ai < argc) { 686 zstrcpy(&fmap, argv[ai]); 687 i = ai + 1; 688 if (i < argc) { 689 char *temp = NULL; 690 char * hyphen = strchr(argv[i], '-'); 691 if (!hyphen || strchr(hyphen+1, '-') != NULL) { 692 fprintf(stderr, 693 "%s: Argument registry-encoding '%s' not in expected format!\n", 694 my_name, i < argc ? fmap : ""); 695 exit(1); 696 } 697 temp = zstrdup(argv[i]); 698 hyphen = strchr(temp, '-'); 699 if (hyphen) *hyphen = 0; 700 zstrcpy(®istry, temp); 701 zstrcpy(&encoding, hyphen+1); 702 free(temp); 703 } else { 704 fprintf(stderr, "map file argument \"%s\" needs a " 705 "coresponding registry-encoding argument\n", fmap); 706 exit(0); 707 } 708 709 ai++; 710 ai++; 711 712 /* open and read source file */ 713 fmap_fp = fopen(fmap, "r"); 714 if (fmap_fp == NULL) { 715 fprintf(stderr, 716 "%s: Can't read mapping file '%s': %s!\n", 717 my_name, fmap, strerror(errno)); 718 exit(1); 719 } 720 721 da_clear(map); 722 723 for (;read_line(fmap_fp, &l); free(l)) { 724 char *p, *endp; 725 726 for (p = l; isspace(p[0]); p++) 727 ; 728 if (p[0] == '\0' || p[0] == '#') 729 continue; 730 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 731 target = strtol(p+2, &endp, 16); 732 if (*endp == '\0') goto bad; 733 p = endp; 734 } else 735 goto bad; 736 for (; isspace(p[0]); p++) 737 ; 738 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 739 ucs = strtol(p+2, &endp, 16); 740 if (*endp == '\0') goto bad; 741 p = endp; 742 } else 743 goto bad; 744 745 if (!is_control(ucs)) { 746 if (zs_true(da_fetch_str(startchar, ucs))) 747 { 748 da_add_int(map, target, ucs); 749 } else { 750 if (!((is_blockgraphics(ucs) && 751 strcmp(slant, "R") != 0) || 752 (ucs >= 0x200e && 753 ucs <= 0x200f))) { 754 fprintf(stderr, 755 "No glyph for character U+%04X (0x%02x) available.\n", 756 ucs, target); 757 } 758 } 759 } 760 continue; 761 bad: 762 fprintf(stderr, "Unrecognized line in '%s':\n%s\n", fmap, l); 763 } 764 fclose(fmap_fp); 765 766 /* add default character */ 767 if (!zi_true(da_fetch_int(map, 0))) { 768 if (zs_true(da_fetch_str(startchar, default_char))) { 769 da_add_int(map, 0, default_char); 770 da_add_str(startchar, default_char, 771 "STARTCHAR defaultchar\n"); 772 } else { 773 fprintf(stderr, "%s", 774 "No default character defined.\n"); 775 } 776 } 777 778 if (dec_chars == 1 || 779 (dec_chars == -1 && strcmp(slant, "R") == 0 && 780 strcmp(spacing, "C") == 0)) 781 { 782 /* add DEC VT100 graphics characters in the range 1-31 783 (as expected by some old xterm versions) */ 784 for (i = 0; i < decmap_size; i++) { 785 if (zs_true(da_fetch_str(startchar, decmap[i]))) 786 { 787 da_add_int(map, i + 1, decmap[i]); 788 } 789 } 790 } 791 792 /* list of characters that will be written out */ 793 j = da_count(map); 794 if (j < 0) { 795 fprintf(stderr, 796 "No characters found for %s-%s.\n", 797 registry, encoding); 798 continue; 799 } 800 if (chars != NULL) 801 free(chars); 802 chars = zmalloc(j * sizeof(int)); 803 memset(chars, 0, j * sizeof(int)); 804 for (k = 0, i = 0; k < da_count(map) && i < da_size(map); i++) { 805 if (da_fetch(map, i) != NULL) 806 chars[k++] = i; 807 } 808 qsort(chars, j, sizeof(int), chars_compare); 809 810 /* find overall font bounding box */ 811 bbx.cwidth = -1; 812 for (i = 0; i < j; i++) { 813 ucs = da_fetch_int(map, chars[i]); 814 zstrcpy(&t, da_fetch_str(my_char, ucs)); 815 if ((nextc = startswith(t, "BBX")) != NULL 816 || (nextc = strstr(t, "\nBBX")) != NULL) 817 { 818 char *endp; 819 long w, h, x, y; 820 821 if (*nextc == '\n') { 822 nextc += 4; 823 while (isspace(*nextc)) 824 nextc++; 825 } 826 for (;isspace(*nextc);) 827 nextc++; 828 w = strtol(nextc, &endp, 10); 829 nextc = endp; 830 if (*nextc == '\0') goto bbxbad; 831 for (;isspace(*nextc);) 832 nextc++; 833 h = strtol(nextc, &endp, 10); 834 nextc = endp; 835 if (*nextc == '\0') goto bbxbad; 836 for (;isspace(*nextc);) 837 nextc++; 838 x = strtol(nextc, &endp, 10); 839 nextc = endp; 840 if (*nextc == '\0') goto bbxbad; 841 for (;isspace(*nextc);) 842 nextc++; 843 y = strtol(nextc, &endp, 10); 844 if (bbx.cwidth == -1) { 845 bbx.cwidth = w; 846 bbx.cheight = h; 847 bbx.cxoff = x; 848 bbx.cyoff = y; 849 } else { 850 combine_bbx(bbx.cwidth, bbx.cheight, 851 bbx.cxoff, bbx.cyoff, 852 w, h, x, y, &bbx); 853 } 854 continue; 855 bbxbad: 856 fprintf(stderr, "Unparsable BBX found for U+%04x!\n", ucs); 857 } else { 858 fprintf(stderr, 859 "Warning: No BBX found for U+%04X!\n", 860 ucs); 861 } 862 } 863 864 if (!registry) registry = zstrdup(""); 865 if (!encoding) encoding = zstrdup(""); 866 867 /* generate output file name */ 868 zstrcpy(®istry_encoding, "-"); 869 zstrcat(®istry_encoding, registry); 870 zstrcat(®istry_encoding, "-"); 871 zstrcat(®istry_encoding, encoding); 872 873 { 874 char * p = strstr(fsource, ".bdf"); 875 if (p) { 876 zstrcpy(&fout, fsource); 877 p = strstr(fout, ".bdf"); 878 *p = 0; 879 zstrcat(&fout, registry_encoding); 880 zstrcat(&fout, ".bdf"); 881 } else { 882 zstrcpy(&fout, fsource); 883 zstrcat(&fout, registry_encoding); 884 } 885 } 886 887 /* remove path prefix */ 888 zstrcpy(&t, basename(fout)); 889 zstrcpy(&fout, t); 890 891 /* write new BDF file */ 892 fprintf(stderr, "Writing %d characters into file '%s'.\n", 893 j, fout); 894 fout_fp = fopen(fout, "w"); 895 if (fout_fp == NULL) { 896 fprintf(stderr, "%s: Can't write file '%s': %s!\n", 897 my_name, fout, strerror(errno)); 898 exit(1); 899 } 900 901 fprintf(fout_fp, "%s\n", startfont); 902 fprintf(fout_fp, "%s", 903 "COMMENT AUTOMATICALLY GENERATED FILE. DO NOT EDIT!\n"); 904 fprintf(fout_fp, 905 "COMMENT Generated with 'ucs2any %s %s %s-%s'\n", 906 fsource, fmap, registry, encoding); 907 fprintf(fout_fp, "%s", 908 "COMMENT from an ISO10646-1 encoded source BDF font.\n"); 909 fprintf(fout_fp, "%s", 910 "COMMENT ucs2any by Ben Collver <collver1@attbi.com>, 2003, based on\n"); 911 fprintf(fout_fp, "%s", 912 "COMMENT ucs2any.pl by Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/>, 2000.\n"); 913 914 for (i = 0; i <= nextheader; i++) { 915 if (i == default_char_index) 916 fprintf(fout_fp, "DEFAULT_CHAR %d\n", default_char); 917 else if (i == startproperties_index) 918 fprintf(fout_fp, "STARTPROPERTIES %d\n", properties); 919 else if (i == fontname_index) { 920 fprintf(fout_fp, "FONT %s%s\n", fontname, registry_encoding); 921 } 922 else if (i == charset_registry_index) 923 fprintf(fout_fp, "CHARSET_REGISTRY \"%s\"\n", registry); 924 else if (i == slant_index) 925 fprintf(fout_fp, "SLANT \"%s\"\n", slant); 926 else if (i == charset_encoding_index) 927 fprintf(fout_fp, "CHARSET_ENCODING \"%s\"\n", encoding); 928 else if (i == fontboundingbox_index) 929 fprintf(fout_fp, "FONTBOUNDINGBOX %d %d %d %d\n", bbx.cwidth, bbx.cheight, bbx.cxoff, bbx.cyoff); 930 else if (i == spacing_index) 931 fprintf(fout_fp, "SPACING \"%s\"\n", spacing); 932 else 933 fprintf(fout_fp, "%s\n", da_fetch_str(headers, i)); 934 } 935 936 fprintf(fout_fp, "CHARS %d\n", j); 937 938 /* Write characters */ 939 for (i = 0; i < j; i++) { 940 ucs = da_fetch_int(map, chars[i]); 941 fprintf(fout_fp, "%s", da_fetch_str(startchar, 942 ucs)); 943 fprintf(fout_fp, "ENCODING %d\n", chars[i]); 944 fprintf(fout_fp, "%s", da_fetch_str(my_char, 945 ucs)); 946 } 947 fprintf(fout_fp, "%s", "ENDFONT\n"); 948 fclose(fout_fp); 949 } 950 951 exit(0); 952} 953