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