/ucs2any.c

# · C · 950 lines · 795 code · 87 blank · 68 comment · 246 complexity · 05f655fa879e6d7fc48a41a62d6f86af MD5 · raw file

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