/contrib/groff/src/utils/hpftodit/hpftodit.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 1454 lines · 1283 code · 116 blank · 55 comment · 298 complexity · 4f4ef3ff663ff3fffbb477da89f29abe MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1994, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
  3. Written by James Clark (jjc@jclark.com)
  4. This file is part of groff.
  5. groff is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation; either version 2, or (at your option) any later
  8. version.
  9. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. You should have received a copy of the GNU General Public License along
  14. with groff; see the file COPYING. If not, write to the Free Software
  15. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  16. /*
  17. TODO
  18. devise new names for useful characters
  19. option to specify symbol sets to look in
  20. put filename in error messages (or fix lib)
  21. */
  22. #include "lib.h"
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27. #include <math.h>
  28. #include <errno.h>
  29. #include "assert.h"
  30. #include "posix.h"
  31. #include "errarg.h"
  32. #include "error.h"
  33. #include "cset.h"
  34. #include "nonposix.h"
  35. #include "unicode.h"
  36. extern "C" const char *Version_string;
  37. extern const char *hp_msl_to_unicode_code(const char *);
  38. #define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
  39. #define equal(a, b) (strcmp(a, b) == 0)
  40. // only valid if is_uname(c) has returned true
  41. #define is_decomposed(c) strchr(c, '_')
  42. #define NO 0
  43. #define YES 1
  44. #define MSL 0
  45. #define SYMSET 1
  46. #define UNICODE 2
  47. #define UNNAMED "---"
  48. static double multiplier = 3.0; // make Agfa-based unitwidth an integer
  49. inline
  50. int scale(int n)
  51. {
  52. return int(n * multiplier + 0.5);
  53. }
  54. // tags in TFM file
  55. enum tag_type {
  56. min_tag = 400,
  57. type_tag = 400,
  58. copyright_tag = 401,
  59. comment_tag = 402,
  60. charcode_tag = 403, // MSL for Intellifont, Unicode for TrueType
  61. symbol_set_tag = 404,
  62. unique_identifier_tag = 405,
  63. inches_per_point_tag = 406,
  64. nominal_point_size_tag = 407,
  65. design_units_per_em_tag = 408,
  66. posture_tag = 409,
  67. type_structure_tag = 410,
  68. stroke_weight_tag = 411,
  69. spacing_tag = 412,
  70. slant_tag = 413,
  71. appearance_width_tag = 414,
  72. serif_style_tag = 415,
  73. font_name_tag = 417,
  74. typeface_source_tag = 418,
  75. average_width_tag = 419,
  76. max_width_tag = 420,
  77. word_spacing_tag = 421,
  78. recommended_line_spacing_tag = 422,
  79. cap_height_tag = 423,
  80. x_height_tag = 424,
  81. max_ascent_tag = 425,
  82. max_descent_tag = 426,
  83. lower_ascent_tag = 427,
  84. lower_descent_tag = 428,
  85. underscore_depth_tag = 429,
  86. underscore_thickness_tag = 430,
  87. uppercase_accent_height_tag = 431,
  88. lowercase_accent_height_tag = 432,
  89. width_tag = 433,
  90. vertical_escapement_tag = 434,
  91. left_extent_tag = 435,
  92. right_extent_tag = 436,
  93. ascent_tag = 437,
  94. descent_tag = 438,
  95. pair_kern_tag = 439,
  96. sector_kern_tag = 440,
  97. track_kern_tag = 441,
  98. typeface_tag = 442,
  99. panose_tag = 443,
  100. max_tag = 443
  101. };
  102. const char *tag_name[] = {
  103. "Symbol Set",
  104. "Font Type" // MSL for Intellifont, Unicode for TrueType
  105. };
  106. // types in TFM file
  107. enum {
  108. BYTE_TYPE = 1,
  109. ASCII_TYPE = 2, // NUL-terminated string
  110. USHORT_TYPE = 3,
  111. LONG_TYPE = 4, // unused
  112. RATIONAL_TYPE = 5, // 8-byte numerator + 8-byte denominator
  113. SIGNED_BYTE_TYPE = 16, // unused
  114. SIGNED_SHORT_TYPE = 17,
  115. SIGNED_LONG_TYPE = 18 // unused
  116. };
  117. typedef unsigned char byte;
  118. typedef unsigned short uint16;
  119. typedef short int16;
  120. typedef unsigned int uint32;
  121. class File {
  122. public:
  123. File(const char *);
  124. void skip(int n);
  125. byte get_byte();
  126. uint16 get_uint16();
  127. uint32 get_uint32();
  128. uint32 get_uint32(char *orig);
  129. void seek(uint32 n);
  130. private:
  131. unsigned char *buf_;
  132. const unsigned char *ptr_;
  133. const unsigned char *end_;
  134. };
  135. struct entry {
  136. char present;
  137. uint16 type;
  138. uint32 count;
  139. uint32 value;
  140. char orig_value[4];
  141. entry() : present(0) { }
  142. };
  143. struct char_info {
  144. uint16 charcode;
  145. uint16 width;
  146. int16 ascent;
  147. int16 descent;
  148. int16 left_extent;
  149. uint16 right_extent;
  150. uint16 symbol_set;
  151. unsigned char code;
  152. };
  153. const uint16 NO_GLYPH = 0xffff;
  154. const uint16 NO_SYMBOL_SET = 0;
  155. struct name_list {
  156. char *name;
  157. name_list *next;
  158. name_list(const char *s, name_list *p) : name(strsave(s)), next(p) { }
  159. ~name_list() { a_delete name; }
  160. };
  161. struct symbol_set {
  162. uint16 select;
  163. uint16 index[256];
  164. };
  165. #define SYMBOL_SET(n, c) ((n) * 32 + ((c) - 64))
  166. uint16 text_symbol_sets[] = {
  167. SYMBOL_SET(19, 'U'), // Windows Latin 1 ("ANSI", code page 1252)
  168. SYMBOL_SET(9, 'E'), // Windows Latin 2, Code Page 1250
  169. SYMBOL_SET(5, 'T'), // Code Page 1254
  170. SYMBOL_SET(7, 'J'), // Desktop
  171. SYMBOL_SET(6, 'J'), // Microsoft Publishing
  172. SYMBOL_SET(0, 'N'), // Latin 1 (subset of 19U,
  173. // so we should never get here)
  174. SYMBOL_SET(2, 'N'), // Latin 2 (subset of 9E,
  175. // so we should never get here)
  176. SYMBOL_SET(8, 'U'), // HP Roman 8
  177. SYMBOL_SET(10, 'J'), // PS Standard
  178. SYMBOL_SET(9, 'U'), // Windows 3.0 "ANSI"
  179. SYMBOL_SET(1, 'U'), // U.S. Legal
  180. SYMBOL_SET(12, 'J'), // MC Text
  181. SYMBOL_SET(10, 'U'), // PC Code Page 437
  182. SYMBOL_SET(11, 'U'), // PC Code Page 437N
  183. SYMBOL_SET(17, 'U'), // PC Code Page 852
  184. SYMBOL_SET(12, 'U'), // PC Code Page 850
  185. SYMBOL_SET(9, 'T'), // PC Code Page 437T
  186. 0
  187. };
  188. uint16 special_symbol_sets[] = {
  189. SYMBOL_SET(8, 'M'), // Math 8
  190. SYMBOL_SET(5, 'M'), // PS Math
  191. SYMBOL_SET(15, 'U'), // Pi font
  192. SYMBOL_SET(13, 'J'), // Ventura International
  193. SYMBOL_SET(19, 'M'), // Symbol font
  194. SYMBOL_SET(579, 'L'), // Wingdings
  195. 0
  196. };
  197. entry tags[max_tag + 1 - min_tag];
  198. char_info *char_table;
  199. uint32 nchars = 0;
  200. unsigned int charcode_name_table_size = 0;
  201. name_list **charcode_name_table = NULL;
  202. symbol_set *symbol_set_table;
  203. unsigned int n_symbol_sets;
  204. static int debug_flag = NO;
  205. static int special_flag = NO; // not a special font
  206. static int italic_flag = NO; // don't add italic correction
  207. static int italic_sep;
  208. static int all_flag = NO; // don't include glyphs not in mapfile
  209. static int quiet_flag = NO; // don't suppress warnings about symbols not found
  210. static char *hp_msl_to_ucode_name(int);
  211. static char *unicode_to_ucode_name(int);
  212. static int is_uname(char *);
  213. static char *show_symset(unsigned int);
  214. static void usage(FILE *);
  215. static void usage();
  216. static const char *xbasename(const char *);
  217. static void read_tags(File &);
  218. static int check_type();
  219. static void check_units(File &, const int, double *, double *);
  220. static int read_map(const char *, const int);
  221. static void require_tag(tag_type);
  222. static void dump_ascii(File &, tag_type);
  223. static void dump_tags(File &);
  224. static void dump_symbol_sets(File &);
  225. static void dump_symbols(int);
  226. static void output_font_name(File &);
  227. static void output_spacewidth();
  228. static void output_pclweight();
  229. static void output_pclproportional();
  230. static void read_and_output_pcltypeface(File &);
  231. static void output_pclstyle();
  232. static void output_slant();
  233. static void output_ligatures();
  234. static void read_symbol_sets(File &);
  235. static void read_and_output_kernpairs(File &);
  236. static void output_charset(const int);
  237. static void read_char_table(File &);
  238. inline
  239. entry &tag_info(tag_type t)
  240. {
  241. return tags[t - min_tag];
  242. }
  243. int
  244. main(int argc, char **argv)
  245. {
  246. program_name = argv[0];
  247. int opt;
  248. int res = 1200; // PCL unit of measure for cursor moves
  249. int scalesize = 4; // LaserJet 4 only allows 1/4 point increments
  250. int unitwidth = 6350;
  251. double ppi; // points per inch
  252. double upem; // design units per em
  253. static const struct option long_options[] = {
  254. { "help", no_argument, 0, CHAR_MAX + 1 },
  255. { "version", no_argument, 0, 'v' },
  256. { NULL, 0, 0, 0 }
  257. };
  258. while ((opt = getopt_long(argc, argv, "adsqvi:", long_options, NULL)) != EOF) {
  259. switch (opt) {
  260. case 'a':
  261. all_flag = YES;
  262. break;
  263. case 'd':
  264. debug_flag = YES;
  265. break;
  266. case 's':
  267. special_flag = YES;
  268. break;
  269. case 'i':
  270. italic_flag = YES;
  271. italic_sep = atoi(optarg); // design units
  272. break;
  273. case 'q':
  274. quiet_flag = YES; // suppress warnings about symbols not found
  275. break;
  276. case 'v':
  277. printf("GNU hpftodit (groff) version %s\n", Version_string);
  278. exit(0);
  279. break;
  280. case CHAR_MAX + 1: // --help
  281. usage(stdout);
  282. exit(0);
  283. break;
  284. case '?':
  285. usage();
  286. break;
  287. default:
  288. assert(0);
  289. }
  290. }
  291. if (debug_flag && argc - optind < 1)
  292. usage();
  293. else if (!debug_flag && argc - optind != 3)
  294. usage();
  295. File f(argv[optind]);
  296. read_tags(f);
  297. int tfm_type = check_type();
  298. if (debug_flag)
  299. dump_tags(f);
  300. if (!debug_flag && !read_map(argv[optind + 1], tfm_type))
  301. exit(1);
  302. else if (debug_flag && argc - optind > 1)
  303. read_map(argv[optind + 1], tfm_type);
  304. current_filename = NULL;
  305. current_lineno = -1; // no line numbers
  306. if (!debug_flag && !equal(argv[optind + 2], "-"))
  307. if (freopen(argv[optind + 2], "w", stdout) == NULL)
  308. fatal("cannot open `%1': %2", argv[optind + 2], strerror(errno));
  309. current_filename = argv[optind];
  310. check_units(f, tfm_type, &ppi, &upem);
  311. if (tfm_type == UNICODE) // don't calculate for Intellifont TFMs
  312. multiplier = double(res) / upem / ppi * unitwidth / scalesize;
  313. if (italic_flag)
  314. // convert from thousandths of an em to design units
  315. italic_sep = int(italic_sep * upem / 1000 + 0.5);
  316. read_char_table(f);
  317. if (nchars == 0)
  318. fatal("no characters");
  319. if (!debug_flag) {
  320. output_font_name(f);
  321. printf("name %s\n", xbasename(argv[optind + 2]));
  322. if (special_flag)
  323. printf("special\n");
  324. output_spacewidth();
  325. output_slant();
  326. read_and_output_pcltypeface(f);
  327. output_pclproportional();
  328. output_pclweight();
  329. output_pclstyle();
  330. }
  331. read_symbol_sets(f);
  332. if (debug_flag)
  333. dump_symbols(tfm_type);
  334. else {
  335. output_ligatures();
  336. read_and_output_kernpairs(f);
  337. output_charset(tfm_type);
  338. }
  339. return 0;
  340. }
  341. static void
  342. usage(FILE *stream)
  343. {
  344. fprintf(stream,
  345. "usage: %s [-s] [-a] [-q] [-i n] tfm_file map_file output_font\n"
  346. " %s -d tfm_file [map_file]\n",
  347. program_name, program_name);
  348. }
  349. static void
  350. usage()
  351. {
  352. usage(stderr);
  353. exit(1);
  354. }
  355. File::File(const char *s)
  356. {
  357. // We need to read the file in binary mode because hpftodit relies
  358. // on byte counts.
  359. int fd = open(s, O_RDONLY | O_BINARY);
  360. if (fd < 0)
  361. fatal("cannot open `%1': %2", s, strerror(errno));
  362. current_filename = s;
  363. struct stat sb;
  364. if (fstat(fd, &sb) < 0)
  365. fatal("cannot stat: %1", strerror(errno));
  366. if (!S_ISREG(sb.st_mode))
  367. fatal("not a regular file");
  368. buf_ = new unsigned char[sb.st_size];
  369. long nread = read(fd, buf_, sb.st_size);
  370. if (nread < 0)
  371. fatal("read error: %1", strerror(errno));
  372. if (nread != sb.st_size)
  373. fatal("read unexpected number of bytes");
  374. ptr_ = buf_;
  375. end_ = buf_ + sb.st_size;
  376. }
  377. void
  378. File::skip(int n)
  379. {
  380. if (end_ - ptr_ < n)
  381. fatal("unexpected end of file");
  382. ptr_ += n;
  383. }
  384. void
  385. File::seek(uint32 n)
  386. {
  387. if (uint32(end_ - buf_) < n)
  388. fatal("unexpected end of file");
  389. ptr_ = buf_ + n;
  390. }
  391. byte
  392. File::get_byte()
  393. {
  394. if (ptr_ >= end_)
  395. fatal("unexpected end of file");
  396. return *ptr_++;
  397. }
  398. uint16
  399. File::get_uint16()
  400. {
  401. if (end_ - ptr_ < 2)
  402. fatal("unexpected end of file");
  403. uint16 n = *ptr_++;
  404. return n + (*ptr_++ << 8);
  405. }
  406. uint32
  407. File::get_uint32()
  408. {
  409. if (end_ - ptr_ < 4)
  410. fatal("unexpected end of file");
  411. uint32 n = *ptr_++;
  412. for (int i = 0; i < 3; i++)
  413. n += *ptr_++ << (i + 1)*8;
  414. return n;
  415. }
  416. uint32
  417. File::get_uint32(char *orig)
  418. {
  419. if (end_ - ptr_ < 4)
  420. fatal("unexpected end of file");
  421. unsigned char v = *ptr_++;
  422. uint32 n = v;
  423. orig[0] = v;
  424. for (int i = 1; i < 4; i++) {
  425. v = *ptr_++;
  426. orig[i] = v;
  427. n += v << i*8;
  428. }
  429. return n;
  430. }
  431. static void
  432. read_tags(File &f)
  433. {
  434. if (f.get_byte() != 'I' || f.get_byte() != 'I')
  435. fatal("not an Intel format TFM file");
  436. f.skip(6);
  437. uint16 ntags = f.get_uint16();
  438. entry dummy;
  439. for (uint16 i = 0; i < ntags; i++) {
  440. uint16 tag = f.get_uint16();
  441. entry *p;
  442. if (min_tag <= tag && tag <= max_tag)
  443. p = tags + (tag - min_tag);
  444. else
  445. p = &dummy;
  446. p->present = 1;
  447. p->type = f.get_uint16();
  448. p->count = f.get_uint32();
  449. p->value = f.get_uint32(p->orig_value);
  450. }
  451. }
  452. static int
  453. check_type()
  454. {
  455. require_tag(type_tag);
  456. int tfm_type = tag_info(type_tag).value;
  457. switch (tfm_type) {
  458. case MSL:
  459. case UNICODE:
  460. break;
  461. case SYMSET:
  462. fatal("cannot handle Symbol Set TFM files");
  463. break;
  464. default:
  465. fatal("unknown type tag %1", tfm_type);
  466. }
  467. return tfm_type;
  468. }
  469. static void
  470. check_units(File &f, const int tfm_type, double *ppi, double *upem)
  471. {
  472. require_tag(design_units_per_em_tag);
  473. f.seek(tag_info(design_units_per_em_tag).value);
  474. uint32 num = f.get_uint32();
  475. uint32 den = f.get_uint32();
  476. if (tfm_type == MSL && (num != 8782 || den != 1))
  477. fatal("design units per em != 8782/1");
  478. *upem = double(num) / den;
  479. require_tag(inches_per_point_tag);
  480. f.seek(tag_info(inches_per_point_tag).value);
  481. num = f.get_uint32();
  482. den = f.get_uint32();
  483. if (tfm_type == MSL && (num != 100 || den != 7231))
  484. fatal("inches per point not 100/7231");
  485. *ppi = double(den) / num;
  486. }
  487. static void
  488. require_tag(tag_type t)
  489. {
  490. if (!tag_info(t).present)
  491. fatal("tag %1 missing", int(t));
  492. }
  493. // put a human-readable font name in the file
  494. static void
  495. output_font_name(File &f)
  496. {
  497. char *p;
  498. if (!tag_info(font_name_tag).present)
  499. return;
  500. int count = tag_info(font_name_tag).count;
  501. char *font_name = new char[count];
  502. if (count > 4) { // value is a file offset to the string
  503. f.seek(tag_info(font_name_tag).value);
  504. int n = count;
  505. p = font_name;
  506. while (--n)
  507. *p++ = f.get_byte();
  508. }
  509. else // orig_value contains the string
  510. sprintf(font_name, "%.*s",
  511. count, tag_info(font_name_tag).orig_value);
  512. // remove any trailing space
  513. p = font_name + count - 1;
  514. while (csspace(*--p))
  515. ;
  516. *(p + 1) = '\0';
  517. printf("# %s\n", font_name);
  518. delete font_name;
  519. }
  520. static void
  521. output_spacewidth()
  522. {
  523. require_tag(word_spacing_tag);
  524. printf("spacewidth %d\n", scale(tag_info(word_spacing_tag).value));
  525. }
  526. static void
  527. read_symbol_sets(File &f)
  528. {
  529. uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count;
  530. uint16 *symbol_set_selectors;
  531. n_symbol_sets = symbol_set_dir_length/14;
  532. symbol_set_table = new symbol_set[n_symbol_sets];
  533. unsigned int i;
  534. for (i = 0; i < nchars; i++)
  535. char_table[i].symbol_set = NO_SYMBOL_SET;
  536. for (i = 0; i < n_symbol_sets; i++) {
  537. f.seek(tag_info(symbol_set_tag).value + i*14);
  538. (void)f.get_uint32(); // offset to symbol set name
  539. uint32 off1 = f.get_uint32(); // offset to selection string
  540. uint32 off2 = f.get_uint32(); // offset to symbol set index array
  541. f.seek(off1);
  542. uint16 kind = 0; // HP-GL "Kind 1" symbol set value
  543. unsigned int j;
  544. for (j = 0; j < off2 - off1; j++) {
  545. unsigned char c = f.get_byte();
  546. if ('0' <= c && c <= '9') // value
  547. kind = kind*10 + (c - '0');
  548. else if ('A' <= c && c <= 'Z') // terminator
  549. kind = kind*32 + (c - 64);
  550. }
  551. symbol_set_table[i].select = kind;
  552. for (j = 0; j < 256; j++)
  553. symbol_set_table[i].index[j] = f.get_uint16();
  554. }
  555. symbol_set_selectors = (special_flag ? special_symbol_sets
  556. : text_symbol_sets);
  557. for (i = 0; symbol_set_selectors[i] != 0; i++) {
  558. unsigned int j;
  559. for (j = 0; j < n_symbol_sets; j++)
  560. if (symbol_set_table[j].select == symbol_set_selectors[i])
  561. break;
  562. if (j < n_symbol_sets) {
  563. for (int k = 0; k < 256; k++) {
  564. uint16 idx = symbol_set_table[j].index[k];
  565. if (idx != NO_GLYPH
  566. && char_table[idx].symbol_set == NO_SYMBOL_SET) {
  567. char_table[idx].symbol_set = symbol_set_table[j].select;
  568. char_table[idx].code = k;
  569. }
  570. }
  571. }
  572. }
  573. if (all_flag)
  574. return;
  575. symbol_set_selectors = (special_flag ? text_symbol_sets
  576. : special_symbol_sets);
  577. for (i = 0; symbol_set_selectors[i] != 0; i++) {
  578. unsigned int j;
  579. for (j = 0; j < n_symbol_sets; j++)
  580. if (symbol_set_table[j].select == symbol_set_selectors[i])
  581. break;
  582. if (j < n_symbol_sets) {
  583. for (int k = 0; k < 256; k++) {
  584. uint16 idx = symbol_set_table[j].index[k];
  585. if (idx != NO_GLYPH
  586. && char_table[idx].symbol_set == NO_SYMBOL_SET) {
  587. char_table[idx].symbol_set = symbol_set_table[j].select;
  588. char_table[idx].code = k;
  589. }
  590. }
  591. }
  592. }
  593. return;
  594. }
  595. static void
  596. read_char_table(File &f)
  597. {
  598. require_tag(charcode_tag);
  599. nchars = tag_info(charcode_tag).count;
  600. char_table = new char_info[nchars];
  601. f.seek(tag_info(charcode_tag).value);
  602. uint32 i;
  603. for (i = 0; i < nchars; i++)
  604. char_table[i].charcode = f.get_uint16();
  605. require_tag(width_tag);
  606. f.seek(tag_info(width_tag).value);
  607. for (i = 0; i < nchars; i++)
  608. char_table[i].width = f.get_uint16();
  609. require_tag(ascent_tag);
  610. f.seek(tag_info(ascent_tag).value);
  611. for (i = 0; i < nchars; i++) {
  612. char_table[i].ascent = f.get_uint16();
  613. if (char_table[i].ascent < 0)
  614. char_table[i].ascent = 0;
  615. }
  616. require_tag(descent_tag);
  617. f.seek(tag_info(descent_tag).value);
  618. for (i = 0; i < nchars; i++) {
  619. char_table[i].descent = f.get_uint16();
  620. if (char_table[i].descent > 0)
  621. char_table[i].descent = 0;
  622. }
  623. require_tag(left_extent_tag);
  624. f.seek(tag_info(left_extent_tag).value);
  625. for (i = 0; i < nchars; i++)
  626. char_table[i].left_extent = int16(f.get_uint16());
  627. require_tag(right_extent_tag);
  628. f.seek(tag_info(right_extent_tag).value);
  629. for (i = 0; i < nchars; i++)
  630. char_table[i].right_extent = f.get_uint16();
  631. }
  632. static void
  633. output_pclweight()
  634. {
  635. require_tag(stroke_weight_tag);
  636. int stroke_weight = tag_info(stroke_weight_tag).value;
  637. int pcl_stroke_weight;
  638. if (stroke_weight < 128)
  639. pcl_stroke_weight = -3;
  640. else if (stroke_weight == 128)
  641. pcl_stroke_weight = 0;
  642. else if (stroke_weight <= 145)
  643. pcl_stroke_weight = 1;
  644. else if (stroke_weight <= 179)
  645. pcl_stroke_weight = 3;
  646. else
  647. pcl_stroke_weight = 4;
  648. printf("pclweight %d\n", pcl_stroke_weight);
  649. }
  650. static void
  651. output_pclproportional()
  652. {
  653. require_tag(spacing_tag);
  654. printf("pclproportional %d\n", tag_info(spacing_tag).value == 0);
  655. }
  656. static void
  657. read_and_output_pcltypeface(File &f)
  658. {
  659. printf("pcltypeface ");
  660. require_tag(typeface_tag);
  661. if (tag_info(typeface_tag).count > 4) {
  662. f.seek(tag_info(typeface_tag).value);
  663. for (uint32 i = 0; i < tag_info(typeface_tag).count; i++) {
  664. unsigned char c = f.get_byte();
  665. if (c == '\0')
  666. break;
  667. putchar(c);
  668. }
  669. }
  670. else
  671. printf("%.4s", tag_info(typeface_tag).orig_value);
  672. printf("\n");
  673. }
  674. static void
  675. output_pclstyle()
  676. {
  677. unsigned pcl_style = 0;
  678. // older tfms don't have the posture tag
  679. if (tag_info(posture_tag).present) {
  680. if (tag_info(posture_tag).value)
  681. pcl_style |= 1;
  682. }
  683. else {
  684. require_tag(slant_tag);
  685. if (tag_info(slant_tag).value != 0)
  686. pcl_style |= 1;
  687. }
  688. require_tag(appearance_width_tag);
  689. if (tag_info(appearance_width_tag).value < 100) // guess
  690. pcl_style |= 4;
  691. printf("pclstyle %d\n", pcl_style);
  692. }
  693. static void
  694. output_slant()
  695. {
  696. require_tag(slant_tag);
  697. int slant = int16(tag_info(slant_tag).value);
  698. if (slant != 0)
  699. printf("slant %f\n", slant/100.0);
  700. }
  701. static void
  702. output_ligatures()
  703. {
  704. // don't use ligatures for fixed space font
  705. require_tag(spacing_tag);
  706. if (tag_info(spacing_tag).value != 0)
  707. return;
  708. static const char *ligature_names[] = {
  709. "fi", "fl", "ff", "ffi", "ffl"
  710. };
  711. static const char *ligature_chars[] = {
  712. "fi", "fl", "ff", "Fi", "Fl"
  713. };
  714. unsigned ligature_mask = 0;
  715. unsigned int i;
  716. for (i = 0; i < nchars; i++) {
  717. uint16 charcode = char_table[i].charcode;
  718. if (charcode < charcode_name_table_size
  719. && char_table[i].symbol_set != NO_SYMBOL_SET) {
  720. for (name_list *p = charcode_name_table[charcode]; p; p = p->next)
  721. for (unsigned int j = 0; j < SIZEOF(ligature_chars); j++)
  722. if (strcmp(p->name, ligature_chars[j]) == 0) {
  723. ligature_mask |= 1 << j;
  724. break;
  725. }
  726. }
  727. }
  728. if (ligature_mask) {
  729. printf("ligatures");
  730. for (i = 0; i < SIZEOF(ligature_names); i++)
  731. if (ligature_mask & (1 << i))
  732. printf(" %s", ligature_names[i]);
  733. printf(" 0\n");
  734. }
  735. }
  736. static void
  737. read_and_output_kernpairs(File &f)
  738. {
  739. if (tag_info(pair_kern_tag).present) {
  740. printf("kernpairs\n");
  741. f.seek(tag_info(pair_kern_tag).value);
  742. uint16 n_pairs = f.get_uint16();
  743. for (int i = 0; i < n_pairs; i++) {
  744. uint16 i1 = f.get_uint16();
  745. uint16 i2 = f.get_uint16();
  746. int16 val = int16(f.get_uint16());
  747. if (char_table[i1].symbol_set != NO_SYMBOL_SET
  748. && char_table[i2].symbol_set != NO_SYMBOL_SET
  749. && char_table[i1].charcode < charcode_name_table_size
  750. && char_table[i2].charcode < charcode_name_table_size) {
  751. for (name_list *p = charcode_name_table[char_table[i1].charcode];
  752. p;
  753. p = p->next)
  754. for (name_list *q = charcode_name_table[char_table[i2].charcode];
  755. q;
  756. q = q->next)
  757. if (!equal(p->name, UNNAMED) && !equal(q->name, UNNAMED))
  758. printf("%s %s %d\n", p->name, q->name, scale(val));
  759. }
  760. }
  761. }
  762. }
  763. static void
  764. output_charset(const int tfm_type)
  765. {
  766. require_tag(slant_tag);
  767. double slant_angle = int16(tag_info(slant_tag).value)*PI/18000.0;
  768. double slant = sin(slant_angle)/cos(slant_angle);
  769. if (italic_flag)
  770. require_tag(x_height_tag);
  771. require_tag(lower_ascent_tag);
  772. require_tag(lower_descent_tag);
  773. printf("charset\n");
  774. unsigned int i;
  775. for (i = 0; i < nchars; i++) {
  776. uint16 charcode = char_table[i].charcode;
  777. // the glyph is bound to one of the searched symbol sets
  778. if (char_table[i].symbol_set != NO_SYMBOL_SET) {
  779. // the character was in the map file
  780. if (charcode < charcode_name_table_size && charcode_name_table[charcode])
  781. printf("%s", charcode_name_table[charcode]->name);
  782. else if (!all_flag)
  783. continue;
  784. else if (tfm_type == MSL)
  785. fputs(hp_msl_to_ucode_name(charcode), stdout);
  786. else
  787. fputs(unicode_to_ucode_name(charcode), stdout);
  788. printf("\t%d,%d",
  789. scale(char_table[i].width), scale(char_table[i].ascent));
  790. int depth = scale(-char_table[i].descent);
  791. if (depth < 0)
  792. depth = 0;
  793. int italic_correction = 0;
  794. int left_italic_correction = 0;
  795. int subscript_correction = 0;
  796. if (italic_flag) {
  797. italic_correction = scale(char_table[i].right_extent
  798. - char_table[i].width
  799. + italic_sep);
  800. if (italic_correction < 0)
  801. italic_correction = 0;
  802. subscript_correction = int((tag_info(x_height_tag).value
  803. * slant * .8) + .5);
  804. if (subscript_correction > italic_correction)
  805. subscript_correction = italic_correction;
  806. left_italic_correction = scale(italic_sep
  807. - char_table[i].left_extent);
  808. }
  809. if (subscript_correction != 0)
  810. printf(",%d,%d,%d,%d",
  811. depth, italic_correction, left_italic_correction,
  812. subscript_correction);
  813. else if (left_italic_correction != 0)
  814. printf(",%d,%d,%d", depth, italic_correction, left_italic_correction);
  815. else if (italic_correction != 0)
  816. printf(",%d,%d", depth, italic_correction);
  817. else if (depth != 0)
  818. printf(",%d", depth);
  819. // This is fairly arbitrary. Fortunately it doesn't much matter.
  820. unsigned type = 0;
  821. if (char_table[i].ascent > int16(tag_info(lower_ascent_tag).value)*9/10)
  822. type |= 2;
  823. if (char_table[i].descent < int16(tag_info(lower_descent_tag).value)*9/10)
  824. type |= 1;
  825. printf("\t%d\t%d", type,
  826. char_table[i].symbol_set*256 + char_table[i].code);
  827. if (tfm_type == UNICODE) {
  828. if (charcode >= 0xE000 && charcode <= 0xF8FF)
  829. printf("\t-- HP PUA U+%04X", charcode);
  830. else
  831. printf("\t-- U+%04X", charcode);
  832. }
  833. else
  834. printf("\t-- MSL %4d", charcode);
  835. printf(" (%3s %3d)\n",
  836. show_symset(char_table[i].symbol_set), char_table[i].code);
  837. if (charcode < charcode_name_table_size
  838. && charcode_name_table[charcode])
  839. for (name_list *p = charcode_name_table[charcode]->next;
  840. p; p = p->next)
  841. printf("%s\t\"\n", p->name);
  842. }
  843. // warnings about characters in mapfile not found in TFM
  844. else if (charcode < charcode_name_table_size
  845. && charcode_name_table[charcode]) {
  846. char *name = charcode_name_table[charcode]->name;
  847. // don't warn about Unicode or unnamed glyphs
  848. // that aren't in the the TFM file
  849. if (tfm_type == UNICODE && !quiet_flag && !equal(name, UNNAMED)
  850. && !is_uname(name)) {
  851. fprintf(stderr, "%s: warning: symbol U+%04X (%s",
  852. program_name, charcode, name);
  853. for (name_list *p = charcode_name_table[charcode]->next;
  854. p; p = p->next)
  855. fprintf(stderr, ", %s", p->name);
  856. fprintf(stderr, ") not in any searched symbol set\n");
  857. }
  858. else if (!quiet_flag && !equal(name, UNNAMED) && !is_uname(name)) {
  859. fprintf(stderr, "%s: warning: symbol MSL %d (%s",
  860. program_name, charcode, name);
  861. for (name_list *p = charcode_name_table[charcode]->next;
  862. p; p = p->next)
  863. fprintf(stderr, ", %s", p->name);
  864. fprintf(stderr, ") not in any searched symbol set\n");
  865. }
  866. }
  867. }
  868. }
  869. #define em_fract(a) (upem >= 0 ? double(a)/upem : 0)
  870. static void
  871. dump_tags(File &f)
  872. {
  873. double upem = -1.0;
  874. printf("TFM tags\n"
  875. "\n"
  876. "tag# type count value\n"
  877. "---------------------\n");
  878. for (int i = min_tag; i <= max_tag; i++) {
  879. enum tag_type t = tag_type(i);
  880. if (tag_info(t).present) {
  881. printf("%4d %4d %5d", i, tag_info(t).type, tag_info(t).count);
  882. switch (tag_info(t).type) {
  883. case BYTE_TYPE:
  884. case USHORT_TYPE:
  885. printf(" %5u", tag_info(t).value);
  886. switch (i) {
  887. case type_tag:
  888. printf(" Font Type ");
  889. switch (tag_info(t).value) {
  890. case MSL:
  891. case SYMSET:
  892. printf("(Intellifont)");
  893. break;
  894. case UNICODE:
  895. printf("(TrueType)");
  896. }
  897. break;
  898. case charcode_tag:
  899. printf(" Number of Symbols (%u)", tag_info(t).count);
  900. break;
  901. case symbol_set_tag:
  902. printf(" Symbol Sets (%u): ",
  903. tag_info(symbol_set_tag).count / 14);
  904. dump_symbol_sets(f);
  905. break;
  906. case type_structure_tag:
  907. printf(" Type Structure (%u)", tag_info(t).value);
  908. break;
  909. case stroke_weight_tag:
  910. printf(" Stroke Weight (%u)", tag_info(t).value);
  911. break;
  912. case spacing_tag:
  913. printf(" Spacing ");
  914. switch (tag_info(t).value) {
  915. case 0:
  916. printf("(Proportional)");
  917. break;
  918. case 1:
  919. printf("(Fixed Pitch: %u DU: %.2f em)", tag_info(t).value,
  920. em_fract(tag_info(t).value));
  921. break;
  922. }
  923. break;
  924. case appearance_width_tag:
  925. printf(" Appearance Width (%u)", tag_info(t).value);
  926. break;
  927. case serif_style_tag:
  928. printf(" Serif Style (%u)", tag_info(t).value);
  929. break;
  930. case posture_tag:
  931. printf(" Posture (%s)", tag_info(t).value == 0
  932. ? "Upright"
  933. : tag_info(t).value == 1
  934. ? "Italic"
  935. : "Alternate Italic");
  936. break;
  937. case max_width_tag:
  938. printf(" Maximum Width (%u DU: %.2f em)", tag_info(t).value,
  939. em_fract(tag_info(t).value));
  940. break;
  941. case word_spacing_tag:
  942. printf(" Interword Spacing (%u DU: %.2f em)", tag_info(t).value,
  943. em_fract(tag_info(t).value));
  944. break;
  945. case recommended_line_spacing_tag:
  946. printf(" Recommended Line Spacing (%u DU: %.2f em)", tag_info(t).value,
  947. em_fract(tag_info(t).value));
  948. break;
  949. case x_height_tag:
  950. printf(" x-Height (%u DU: %.2f em)", tag_info(t).value,
  951. em_fract(tag_info(t).value));
  952. break;
  953. case cap_height_tag:
  954. printf(" Cap Height (%u DU: %.2f em)", tag_info(t).value,
  955. em_fract(tag_info(t).value));
  956. break;
  957. case max_ascent_tag:
  958. printf(" Maximum Ascent (%u DU: %.2f em)", tag_info(t).value,
  959. em_fract(tag_info(t).value));
  960. break;
  961. case lower_ascent_tag:
  962. printf(" Lowercase Ascent (%u DU: %.2f em)", tag_info(t).value,
  963. em_fract(tag_info(t).value));
  964. break;
  965. case underscore_thickness_tag:
  966. printf(" Underscore Thickness (%u DU: %.2f em)", tag_info(t).value,
  967. em_fract(tag_info(t).value));
  968. break;
  969. case uppercase_accent_height_tag:
  970. printf(" Uppercase Accent Height (%u DU: %.2f em)", tag_info(t).value,
  971. em_fract(tag_info(t).value));
  972. break;
  973. case lowercase_accent_height_tag:
  974. printf(" Lowercase Accent Height (%u DU: %.2f em)", tag_info(t).value,
  975. em_fract(tag_info(t).value));
  976. break;
  977. case width_tag:
  978. printf(" Horizontal Escapement array");
  979. break;
  980. case vertical_escapement_tag:
  981. printf(" Vertical Escapement array");
  982. break;
  983. case right_extent_tag:
  984. printf(" Right Extent array");
  985. break;
  986. case ascent_tag:
  987. printf(" Character Ascent array");
  988. break;
  989. case pair_kern_tag:
  990. f.seek(tag_info(t).value);
  991. printf(" Kern Pairs (%u)", f.get_uint16());
  992. break;
  993. case panose_tag:
  994. printf(" PANOSE Classification array");
  995. break;
  996. }
  997. break;
  998. case SIGNED_SHORT_TYPE:
  999. printf(" %5d", int16(tag_info(t).value));
  1000. switch (i) {
  1001. case slant_tag:
  1002. printf(" Slant (%.2f degrees)", double(tag_info(t).value) / 100);
  1003. break;
  1004. case max_descent_tag:
  1005. printf(" Maximum Descent (%d DU: %.2f em)", int16(tag_info(t).value),
  1006. em_fract(int16(tag_info(t).value)));
  1007. break;
  1008. case lower_descent_tag:
  1009. printf(" Lowercase Descent (%d DU: %.2f em)", int16(tag_info(t).value),
  1010. em_fract(int16(tag_info(t).value)));
  1011. break;
  1012. case underscore_depth_tag:
  1013. printf(" Underscore Depth (%d DU: %.2f em)", int16(tag_info(t).value),
  1014. em_fract(int16(tag_info(t).value)));
  1015. break;
  1016. case left_extent_tag:
  1017. printf(" Left Extent array");
  1018. break;
  1019. // The type of this tag has changed from SHORT to SIGNED SHORT
  1020. // in TFM version 1.3.0.
  1021. case ascent_tag:
  1022. printf(" Character Ascent array");
  1023. break;
  1024. case descent_tag:
  1025. printf(" Character Descent array");
  1026. break;
  1027. }
  1028. break;
  1029. case RATIONAL_TYPE:
  1030. printf(" %5u", tag_info(t).value);
  1031. switch (i) {
  1032. case inches_per_point_tag:
  1033. printf(" Inches per Point");
  1034. break;
  1035. case nominal_point_size_tag:
  1036. printf(" Nominal Point Size");
  1037. break;
  1038. case design_units_per_em_tag:
  1039. printf(" Design Units per Em");
  1040. break;
  1041. case average_width_tag:
  1042. printf(" Average Width");
  1043. break;
  1044. }
  1045. if (tag_info(t).count == 1) {
  1046. f.seek(tag_info(t).value);
  1047. uint32 num = f.get_uint32();
  1048. uint32 den = f.get_uint32();
  1049. if (i == design_units_per_em_tag)
  1050. upem = double(num) / den;
  1051. printf(" (%u/%u = %g)", num, den, double(num)/den);
  1052. }
  1053. break;
  1054. case ASCII_TYPE:
  1055. printf(" %5u ", tag_info(t).value);
  1056. switch (i) {
  1057. case comment_tag:
  1058. printf("Comment ");
  1059. break;
  1060. case copyright_tag:
  1061. printf("Copyright ");
  1062. break;
  1063. case unique_identifier_tag:
  1064. printf("Unique ID ");
  1065. break;
  1066. case font_name_tag:
  1067. printf("Typeface Name ");
  1068. break;
  1069. case typeface_source_tag:
  1070. printf("Typeface Source ");
  1071. break;
  1072. case typeface_tag:
  1073. printf("PCL Typeface ");
  1074. break;
  1075. }
  1076. dump_ascii(f, t);
  1077. }
  1078. putchar('\n');
  1079. }
  1080. }
  1081. putchar('\n');
  1082. }
  1083. #undef em_fract
  1084. static void
  1085. dump_ascii(File &f, tag_type t)
  1086. {
  1087. putchar('"');
  1088. if (tag_info(t).count > 4) {
  1089. int count = tag_info(t).count;
  1090. f.seek(tag_info(t).value);
  1091. while (--count)
  1092. printf("%c", f.get_byte());
  1093. }
  1094. else
  1095. printf("%.4s", tag_info(t).orig_value);
  1096. putchar('"');
  1097. }
  1098. static void
  1099. dump_symbol_sets(File &f)
  1100. {
  1101. uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count;
  1102. uint32 num_symbol_sets = symbol_set_dir_length / 14;
  1103. for (uint32 i = 0; i < num_symbol_sets; i++) {
  1104. f.seek(tag_info(symbol_set_tag).value + i * 14);
  1105. (void)f.get_uint32(); // offset to symbol set name
  1106. uint32 off1 = f.get_uint32(); // offset to selection string
  1107. uint32 off2 = f.get_uint32(); // offset to symbol set index array
  1108. f.seek(off1);
  1109. for (uint32 j = 0; j < off2 - off1; j++) {
  1110. unsigned char c = f.get_byte();
  1111. if ('0' <= c && c <= '9')
  1112. putchar(c);
  1113. else if ('A' <= c && c <= 'Z')
  1114. printf(i < num_symbol_sets - 1 ? "%c," : "%c", c);
  1115. }
  1116. }
  1117. }
  1118. static void
  1119. dump_symbols(int tfm_type)
  1120. {
  1121. printf("Symbols:\n"
  1122. "\n"
  1123. " glyph id# symbol set name(s)\n"
  1124. "----------------------------------\n");
  1125. for (uint32 i = 0; i < nchars; i++) {
  1126. uint16 charcode = char_table[i].charcode;
  1127. if (charcode < charcode_name_table_size
  1128. && charcode_name_table[charcode]) {
  1129. if (char_table[i].symbol_set != NO_SYMBOL_SET) {
  1130. printf(tfm_type == UNICODE ? "%4d (U+%04X) (%3s %3d) %s"
  1131. : "%4d (MSL %4d) (%3s %3d) %s",
  1132. i, charcode,
  1133. show_symset(char_table[i].symbol_set),
  1134. char_table[i].code,
  1135. charcode_name_table[charcode]->name);
  1136. for (name_list *p = charcode_name_table[charcode]->next;
  1137. p; p = p->next)
  1138. printf(", %s", p->name);
  1139. putchar('\n');
  1140. }
  1141. }
  1142. else {
  1143. printf(tfm_type == UNICODE ? "%4d (U+%04X) "
  1144. : "%4d (MSL %4d) ",
  1145. i, charcode);
  1146. if (char_table[i].symbol_set != NO_SYMBOL_SET)
  1147. printf("(%3s %3d)",
  1148. show_symset(char_table[i].symbol_set), char_table[i].code);
  1149. putchar('\n');
  1150. }
  1151. }
  1152. putchar('\n');
  1153. }
  1154. static char *
  1155. show_symset(unsigned int symset)
  1156. {
  1157. static char symset_str[8];
  1158. sprintf(symset_str, "%d%c", symset / 32, (symset & 31) + 64);
  1159. return symset_str;
  1160. }
  1161. static char *
  1162. hp_msl_to_ucode_name(int msl)
  1163. {
  1164. char codestr[8];
  1165. sprintf(codestr, "%d", msl);
  1166. const char *ustr = hp_msl_to_unicode_code(codestr);
  1167. if (ustr == NULL)
  1168. ustr = UNNAMED;
  1169. else {
  1170. char *nonum;
  1171. int ucode = int(strtol(ustr, &nonum, 16));
  1172. // don't allow PUA code points as Unicode names
  1173. if (ucode >= 0xE000 && ucode <= 0xF8FF)
  1174. ustr = UNNAMED;
  1175. }
  1176. if (!equal(ustr, UNNAMED)) {
  1177. const char *uname_decomposed = decompose_unicode(ustr);
  1178. if (uname_decomposed)
  1179. // 1st char is the number of components
  1180. ustr = uname_decomposed + 1;
  1181. }
  1182. char *value = new char[strlen(ustr) + 1];
  1183. sprintf(value, equal(ustr, UNNAMED) ? ustr : "u%s", ustr);
  1184. return value;
  1185. }
  1186. static char *
  1187. unicode_to_ucode_name(int ucode)
  1188. {
  1189. const char *ustr;
  1190. char codestr[8];
  1191. // don't allow PUA code points as Unicode names
  1192. if (ucode >= 0xE000 && ucode <= 0xF8FF)
  1193. ustr = UNNAMED;
  1194. else {
  1195. sprintf(codestr, "%04X", ucode);
  1196. ustr = codestr;
  1197. }
  1198. if (!equal(ustr, UNNAMED)) {
  1199. const char *uname_decomposed = decompose_unicode(ustr);
  1200. if (uname_decomposed)
  1201. // 1st char is the number of components
  1202. ustr = uname_decomposed + 1;
  1203. }
  1204. char *value = new char[strlen(ustr) + 1];
  1205. sprintf(value, equal(ustr, UNNAMED) ? ustr : "u%s", ustr);
  1206. return value;
  1207. }
  1208. static int
  1209. is_uname(char *name)
  1210. {
  1211. size_t i;
  1212. size_t len = strlen(name);
  1213. if (len % 5)
  1214. return 0;
  1215. if (name[0] != 'u')
  1216. return 0;
  1217. for (i = 1; i < 4; i++)
  1218. if (!csxdigit(name[i]))
  1219. return 0;
  1220. for (i = 5; i < len; i++)
  1221. if (i % 5 ? !csxdigit(name[i]) : name[i] != '_')
  1222. return 0;
  1223. return 1;
  1224. }
  1225. static int
  1226. read_map(const char *file, const int tfm_type)
  1227. {
  1228. errno = 0;
  1229. FILE *fp = fopen(file, "r");
  1230. if (!fp) {
  1231. error("can't open `%1': %2", file, strerror(errno));
  1232. return 0;
  1233. }
  1234. current_filename = file;
  1235. char buf[512];
  1236. current_lineno = 0;
  1237. char *nonum;
  1238. while (fgets(buf, int(sizeof(buf)), fp)) {
  1239. current_lineno++;
  1240. char *ptr = buf;
  1241. while (csspace(*ptr))
  1242. ptr++;
  1243. if (*ptr == '\0' || *ptr == '#')
  1244. continue;
  1245. ptr = strtok(ptr, " \n\t");
  1246. if (!ptr)
  1247. continue;
  1248. int msl_code = int(strtol(ptr, &nonum, 10));
  1249. if (*nonum != '\0') {
  1250. if (csxdigit(*nonum))
  1251. error("bad MSL map: got hex code (%1)", ptr);
  1252. else if (ptr == nonum)
  1253. error("bad MSL map: bad MSL code (%1)", ptr);
  1254. else
  1255. error("bad MSL map");
  1256. fclose(fp);
  1257. return 0;
  1258. }
  1259. ptr = strtok(NULL, " \n\t");
  1260. if (!ptr)
  1261. continue;
  1262. int unicode = int(strtol(ptr, &nonum, 16));
  1263. if (*nonum != '\0') {
  1264. if (ptr == nonum)
  1265. error("bad Unicode value (%1)", ptr);
  1266. else
  1267. error("bad Unicode map");
  1268. fclose(fp);
  1269. return 0;
  1270. }
  1271. if (strlen(ptr) != 4) {
  1272. error("bad Unicode value (%1)", ptr);
  1273. return 0;
  1274. }
  1275. int n = tfm_type == MSL ? msl_code : unicode;
  1276. if (tfm_type == UNICODE && n > 0xFFFF) {
  1277. // greatest value supported by TFM files
  1278. error("bad Unicode value (%1): greatest value is 0xFFFF", ptr);
  1279. fclose(fp);
  1280. return 0;
  1281. }
  1282. else if (n < 0) {
  1283. error("negative code value (%1)", ptr);
  1284. fclose(fp);
  1285. return 0;
  1286. }
  1287. ptr = strtok(NULL, " \n\t");
  1288. if (!ptr) { // groff name
  1289. error("missing name(s)");
  1290. fclose(fp);
  1291. return 0;
  1292. }
  1293. // leave decomposed Unicode values alone
  1294. else if (is_uname(ptr) && !is_decomposed(ptr))
  1295. ptr = unicode_to_ucode_name(strtol(ptr + 1, &nonum, 16));
  1296. if (size_t(n) >= charcode_name_table_size) {
  1297. size_t old_size = charcode_name_table_size;
  1298. name_list **old_table = charcode_name_table;
  1299. charcode_name_table_size = n + 256;
  1300. charcode_name_table = new name_list *[charcode_name_table_size];
  1301. if (old_table) {
  1302. memcpy(charcode_name_table, old_table, old_size*sizeof(name_list *));
  1303. a_delete old_table;
  1304. }
  1305. for (size_t i = old_size; i < charcode_name_table_size; i++)
  1306. charcode_name_table[i] = NULL;
  1307. }
  1308. // a '#' that isn't the first groff name begins a comment
  1309. for (int names = 1; ptr; ptr = strtok(NULL, " \n\t")) {
  1310. if (names++ > 1 && *ptr == '#')
  1311. break;
  1312. charcode_name_table[n] = new name_list(ptr, charcode_name_table[n]);
  1313. }
  1314. }
  1315. fclose(fp);
  1316. return 1;
  1317. }
  1318. static const char *
  1319. xbasename(const char *s)
  1320. {
  1321. // DIR_SEPS[] are possible directory separator characters, see
  1322. // nonposix.h. We want the rightmost separator of all possible
  1323. // ones. Example: d:/foo\\bar.
  1324. const char *b = strrchr(s, DIR_SEPS[0]), *b1;
  1325. const char *sep = &DIR_SEPS[1];
  1326. while (*sep)
  1327. {
  1328. b1 = strrchr(s, *sep);
  1329. if (b1 && (!b || b1 > b))
  1330. b = b1;
  1331. sep++;
  1332. }
  1333. return b ? b + 1 : s;
  1334. }