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