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