2 /* Copyright (C) 1994, 2000, 2001 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 put human readable font name in device file
24 devise new names for useful characters
25 use --- for unnamed characters
26 option to specify symbol sets to look in
27 make it work with TrueType fonts
28 put filename in error messages (or fix lib)
43 extern "C" const char *Version_string;
45 #define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
47 const int MULTIPLIER = 3;
52 return n * MULTIPLIER;
62 inches_per_point_tag = 406,
63 design_units_per_em_tag = 408,
65 stroke_weight_tag = 411,
68 appearance_width_tag = 414,
69 word_spacing_tag = 421,
71 lower_ascent_tag = 427,
72 lower_descent_tag = 428,
74 left_extent_tag = 435,
75 right_extent_tag = 436,
90 SIGNED_SHORT_TYPE = 17
94 typedef unsigned char byte;
95 typedef unsigned short uint16;
97 typedef unsigned int uint32;
109 const unsigned char *ptr_;
110 const unsigned char *end_;
118 entry() : present(0) { }
132 const uint16 NO_SYMBOL_SET = 0;
137 name_list(const char *s, name_list *p) : name(strsave(s)), next(p) { }
138 ~name_list() { a_delete name; }
146 #define SYMBOL_SET(n, c) ((n) * 32 + ((c) - 64))
148 uint16 text_symbol_sets[] = {
149 SYMBOL_SET(0, 'N'), // Latin 1
150 SYMBOL_SET(6, 'J'), // Microsoft Publishing
151 SYMBOL_SET(2, 'N'), // Latin 2
155 uint16 special_symbol_sets[] = {
162 entry tags[max_tag + 1 - min_tag];
164 char_info *char_table;
167 unsigned int msl_name_table_size = 0;
168 name_list **msl_name_table = 0;
170 unsigned int n_symbol_sets;
171 symbol_set *symbol_set_table;
173 static int special_flag = 0;
174 static int italic_flag = 0;
175 static int italic_sep;
177 static void usage(FILE *stream);
179 static const char *xbasename(const char *);
180 static void read_tags(File &);
181 static void check_type();
182 static void check_units(File &);
183 static int read_map(const char *);
184 static void require_tag(tag_type);
185 static void dump_tags(File &f);
186 static void output_spacewidth();
187 static void output_pclweight();
188 static void output_pclproportional();
189 static void read_and_output_pcltypeface(File &);
190 static void output_pclstyle();
191 static void output_slant();
192 static void output_ligatures();
193 static void read_symbol_sets(File &);
194 static void read_and_output_kernpairs(File &);
195 static void output_charset();
196 static void read_char_table(File &f);
199 entry &tag_info(tag_type t)
201 return tags[t - min_tag];
204 int main(int argc, char **argv)
206 program_name = argv[0];
211 static const struct option long_options[] = {
212 { "help", no_argument, 0, CHAR_MAX + 1 },
213 { "version", no_argument, 0, 'v' },
216 while ((opt = getopt_long(argc, argv, "dsvi:", long_options, NULL)) != EOF) {
226 italic_sep = atoi(optarg);
230 printf("GNU hpftodit (groff) version %s\n", Version_string);
234 case CHAR_MAX + 1: // --help
245 if (argc - optind != 3)
247 File f(argv[optind]);
248 if (!read_map(argv[optind + 1]))
250 current_filename = 0;
251 current_lineno = -1; // no line numbers
252 if (freopen(argv[optind + 2], "w", stdout) == 0)
253 fatal("cannot open `%1': %2", argv[optind + 2], strerror(errno));
254 current_filename = argv[optind];
255 printf("name %s\n", xbasename(argv[optind + 2]));
266 read_and_output_pcltypeface(f);
267 output_pclproportional();
272 read_and_output_kernpairs(f);
278 void usage(FILE *stream)
280 fprintf(stream, "usage: %s [-s] [-i n] tfm_file map_file output_font\n",
290 File::File(const char *s)
292 // We need to read the file in binary mode because hpftodit relies
294 int fd = open(s, O_RDONLY | O_BINARY);
296 fatal("cannot open `%1': %2", s, strerror(errno));
297 current_filename = s;
299 if (fstat(fd, &sb) < 0)
300 fatal("cannot stat: %1", strerror(errno));
301 if (!S_ISREG(sb.st_mode))
302 fatal("not a regular file");
303 buf_ = new unsigned char[sb.st_size];
304 long nread = read(fd, buf_, sb.st_size);
306 fatal("read error: %1", strerror(errno));
307 if (nread != sb.st_size)
308 fatal("read unexpected number of bytes");
310 end_ = buf_ + sb.st_size;
313 void File::skip(int n)
316 fatal("unexpected end of file");
320 void File::seek(uint32 n)
322 if ((uint32)(end_ - buf_) < n)
323 fatal("unexpected end of file");
327 byte File::get_byte()
330 fatal("unexpected end of file");
334 uint16 File::get_uint16()
337 fatal("unexpected end of file");
339 return n + (*ptr_++ << 8);
342 uint32 File::get_uint32()
345 fatal("unexpected end of file");
347 for (int i = 0; i < 3; i++)
348 n += *ptr_++ << (i + 1)*8;
353 void read_tags(File &f)
355 if (f.get_byte() != 'I' || f.get_byte() != 'I')
356 fatal("not an Intel format TFM file");
358 uint16 ntags = f.get_uint16();
360 for (uint16 i = 0; i < ntags; i++) {
361 uint16 tag = f.get_uint16();
363 if (min_tag <= tag && tag <= max_tag)
364 p = tags + (tag - min_tag);
368 p->type = f.get_uint16();
369 p->count = f.get_uint32();
370 p->value = f.get_uint32();
377 require_tag(type_tag);
378 if (tag_info(type_tag).value != 0) {
379 if (tag_info(type_tag).value == 2)
380 fatal("cannot handle TrueType tfm files");
381 fatal("unknown type tag %1", int(tag_info(type_tag).value));
386 void check_units(File &f)
388 require_tag(design_units_per_em_tag);
389 f.seek(tag_info(design_units_per_em_tag).value);
390 uint32 num = f.get_uint32();
391 uint32 den = f.get_uint32();
392 if (num != 8782 || den != 1)
393 fatal("design units per em != 8782/1");
394 require_tag(inches_per_point_tag);
395 f.seek(tag_info(inches_per_point_tag).value);
396 num = f.get_uint32();
397 den = f.get_uint32();
398 if (num != 100 || den != 7231)
399 fatal("inches per point not 100/7231");
403 void require_tag(tag_type t)
405 if (!tag_info(t).present)
406 fatal("tag %1 missing", int(t));
410 void output_spacewidth()
412 require_tag(word_spacing_tag);
413 printf("spacewidth %d\n", scale(tag_info(word_spacing_tag).value));
417 void read_symbol_sets(File &f)
419 uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count;
420 n_symbol_sets = symbol_set_dir_length/14;
421 symbol_set_table = new symbol_set[n_symbol_sets];
423 for (i = 0; i < n_symbol_sets; i++) {
424 f.seek(tag_info(symbol_set_tag).value + i*14);
425 (void)f.get_uint32();
426 uint32 off1 = f.get_uint32();
427 uint32 off2 = f.get_uint32();
428 (void)f.get_uint16(); // what's this for?
432 for (j = 0; j < off2 - off1; j++) {
433 unsigned char c = f.get_byte();
434 if ('0' <= c && c <= '9')
435 kind = kind*10 + (c - '0');
436 else if ('A' <= c && c <= 'Z')
437 kind = kind*32 + (c - 64);
439 symbol_set_table[i].select = kind;
440 for (j = 0; j < 256; j++)
441 symbol_set_table[i].index[j] = f.get_uint16();
443 for (i = 0; i < nchars; i++)
444 char_table[i].symbol_set = NO_SYMBOL_SET;
446 uint16 *symbol_set_selectors = (special_flag
447 ? special_symbol_sets
449 for (i = 0; symbol_set_selectors[i] != 0; i++) {
451 for (j = 0; j < n_symbol_sets; j++)
452 if (symbol_set_table[j].select == symbol_set_selectors[i])
454 if (j < n_symbol_sets) {
455 for (int k = 0; k < 256; k++) {
456 uint16 index = symbol_set_table[j].index[k];
458 && char_table[index].symbol_set == NO_SYMBOL_SET) {
459 char_table[index].symbol_set = symbol_set_table[j].select;
460 char_table[index].code = k;
468 void read_char_table(File &f)
470 require_tag(msl_tag);
471 nchars = tag_info(msl_tag).count;
472 char_table = new char_info[nchars];
474 f.seek(tag_info(msl_tag).value);
476 for (i = 0; i < nchars; i++)
477 char_table[i].msl = f.get_uint16();
479 require_tag(width_tag);
480 f.seek(tag_info(width_tag).value);
481 for (i = 0; i < nchars; i++)
482 char_table[i].width = f.get_uint16();
484 require_tag(ascent_tag);
485 f.seek(tag_info(ascent_tag).value);
486 for (i = 0; i < nchars; i++) {
487 char_table[i].ascent = f.get_uint16();
490 require_tag(descent_tag);
491 f.seek(tag_info(descent_tag).value);
492 for (i = 0; i < nchars; i++) {
493 char_table[i].descent = f.get_uint16();
494 if (char_table[i].descent > 0)
495 char_table[i].descent = 0;
498 require_tag(left_extent_tag);
499 f.seek(tag_info(left_extent_tag).value);
500 for (i = 0; i < nchars; i++)
501 char_table[i].left_extent = int16(f.get_uint16());
503 require_tag(right_extent_tag);
504 f.seek(tag_info(right_extent_tag).value);
505 for (i = 0; i < nchars; i++)
506 char_table[i].right_extent = f.get_uint16();
510 void output_pclweight()
512 require_tag(stroke_weight_tag);
513 int stroke_weight = tag_info(stroke_weight_tag).value;
514 int pcl_stroke_weight;
515 if (stroke_weight < 128)
516 pcl_stroke_weight = -3;
517 else if (stroke_weight == 128)
518 pcl_stroke_weight = 0;
519 else if (stroke_weight <= 145)
520 pcl_stroke_weight = 1;
521 else if (stroke_weight <= 179)
522 pcl_stroke_weight = 3;
524 pcl_stroke_weight = 4;
525 printf("pclweight %d\n", pcl_stroke_weight);
529 void output_pclproportional()
531 require_tag(spacing_tag);
532 printf("pclproportional %d\n", tag_info(spacing_tag).value == 0);
536 void read_and_output_pcltypeface(File &f)
538 printf("pcltypeface ");
539 require_tag(typeface_tag);
540 f.seek(tag_info(typeface_tag).value);
541 for (uint32 i = 0; i < tag_info(typeface_tag).count; i++) {
542 unsigned char c = f.get_byte();
551 void output_pclstyle()
553 unsigned pcl_style = 0;
554 // older tfms don't have the posture tag
555 if (tag_info(posture_tag).present) {
556 if (tag_info(posture_tag).value)
560 require_tag(slant_tag);
561 if (tag_info(slant_tag).value != 0)
564 require_tag(appearance_width_tag);
565 if (tag_info(appearance_width_tag).value < 100) // guess
567 printf("pclstyle %d\n", pcl_style);
573 require_tag(slant_tag);
574 int slant = int16(tag_info(slant_tag).value);
576 printf("slant %f\n", slant/100.0);
580 void output_ligatures()
582 // don't use ligatures for fixed space font
583 require_tag(spacing_tag);
584 if (tag_info(spacing_tag).value != 0)
586 static const char *ligature_names[] = {
587 "fi", "fl", "ff", "ffi", "ffl"
590 static const char *ligature_chars[] = {
591 "fi", "fl", "ff", "Fi", "Fl"
594 unsigned ligature_mask = 0;
596 for (i = 0; i < nchars; i++) {
597 uint16 msl = char_table[i].msl;
598 if (msl < msl_name_table_size
599 && char_table[i].symbol_set != NO_SYMBOL_SET) {
600 for (name_list *p = msl_name_table[msl]; p; p = p->next)
601 for (unsigned int j = 0; j < SIZEOF(ligature_chars); j++)
602 if (strcmp(p->name, ligature_chars[j]) == 0) {
603 ligature_mask |= 1 << j;
610 for (i = 0; i < SIZEOF(ligature_names); i++)
611 if (ligature_mask & (1 << i))
612 printf(" %s", ligature_names[i]);
618 void read_and_output_kernpairs(File &f)
620 if (tag_info(pair_kern_tag).present) {
621 printf("kernpairs\n");
622 f.seek(tag_info(pair_kern_tag).value);
623 uint16 n_pairs = f.get_uint16();
624 for (int i = 0; i < n_pairs; i++) {
625 uint16 i1 = f.get_uint16();
626 uint16 i2 = f.get_uint16();
627 int16 val = int16(f.get_uint16());
628 if (char_table[i1].symbol_set != NO_SYMBOL_SET
629 && char_table[i2].symbol_set != NO_SYMBOL_SET
630 && char_table[i1].msl < msl_name_table_size
631 && char_table[i2].msl < msl_name_table_size) {
632 for (name_list *p = msl_name_table[char_table[i1].msl];
635 for (name_list *q = msl_name_table[char_table[i2].msl];
638 printf("%s %s %d\n", p->name, q->name, scale(val));
645 void output_charset()
647 require_tag(slant_tag);
648 double slant_angle = int16(tag_info(slant_tag).value)*PI/18000.0;
649 double slant = sin(slant_angle)/cos(slant_angle);
651 require_tag(x_height_tag);
652 require_tag(lower_ascent_tag);
653 require_tag(lower_descent_tag);
657 for (i = 0; i < nchars; i++) {
658 uint16 msl = char_table[i].msl;
659 if (msl < msl_name_table_size
660 && msl_name_table[msl]) {
661 if (char_table[i].symbol_set != NO_SYMBOL_SET) {
663 msl_name_table[msl]->name,
664 scale(char_table[i].width),
665 scale(char_table[i].ascent));
666 int depth = scale(- char_table[i].descent);
669 int italic_correction = 0;
670 int left_italic_correction = 0;
671 int subscript_correction = 0;
673 italic_correction = scale(char_table[i].right_extent
674 - char_table[i].width
676 if (italic_correction < 0)
677 italic_correction = 0;
678 subscript_correction = int((tag_info(x_height_tag).value
680 if (subscript_correction > italic_correction)
681 subscript_correction = italic_correction;
682 left_italic_correction = scale(italic_sep
683 - char_table[i].left_extent);
685 if (subscript_correction != 0)
686 printf(",%d,%d,%d,%d",
687 depth, italic_correction, left_italic_correction,
688 subscript_correction);
689 else if (left_italic_correction != 0)
690 printf(",%d,%d,%d", depth, italic_correction, left_italic_correction);
691 else if (italic_correction != 0)
692 printf(",%d,%d", depth, italic_correction);
694 printf(",%d", depth);
695 // This is fairly arbitrary. Fortunately it doesn't much matter.
697 if (char_table[i].ascent > (tag_info(lower_ascent_tag).value*9)/10)
699 if (char_table[i].descent < (int16(tag_info(lower_descent_tag).value)*9)/10)
703 char_table[i].symbol_set*256 + char_table[i].code);
704 for (name_list *p = msl_name_table[msl]->next; p; p = p->next)
705 printf("%s\t\"\n", p->name);
708 warning("MSL %1 not in any of the searched symbol sets", msl);
714 void dump_tags(File &f)
717 for (i = min_tag; i <= max_tag; i++) {
718 enum tag_type t = tag_type(i);
719 if (tag_info(t).present) {
721 "%d %d %d %d\n", i, tag_info(t).type, tag_info(t).count,
723 if (tag_info(t).type == FLOAT_TYPE
724 && tag_info(t).count == 1) {
725 f.seek(tag_info(t).value);
726 uint32 num = f.get_uint32();
727 uint32 den = f.get_uint32();
728 fprintf(stderr, "(%u/%u = %g)\n", num, den, (double)num/den);
735 int read_map(const char *file)
738 FILE *fp = fopen(file, "r");
740 error("can't open `%1': %2", file, strerror(errno));
743 current_filename = file;
746 while (fgets(buf, int(sizeof(buf)), fp)) {
749 while (csspace(*ptr))
751 if (*ptr == '\0' || *ptr == '#')
753 ptr = strtok(ptr, " \n\t");
757 if (sscanf(ptr, "%d", &n) != 1) {
758 error("bad map file");
763 error("negative code");
767 if ((size_t)n >= msl_name_table_size) {
768 size_t old_size = msl_name_table_size;
769 name_list **old_table = msl_name_table;
770 msl_name_table_size = n + 256;
771 msl_name_table = new name_list *[msl_name_table_size];
773 memcpy(msl_name_table, old_table, old_size*sizeof(name_list *));
776 for (size_t i = old_size; i < msl_name_table_size; i++)
777 msl_name_table[i] = 0;
779 ptr = strtok(0, " \n\t");
781 error("missing names");
785 for (; ptr; ptr = strtok(0, " \n\t"))
786 msl_name_table[n] = new name_list(ptr, msl_name_table[n]);
793 const char *xbasename(const char *s)
795 // DIR_SEPS[] are possible directory separator characters, see
796 // nonposix.h. We want the rightmost separator of all possible
797 // ones. Example: d:/foo\\bar.
798 const char *b = strrchr(s, DIR_SEPS[0]), *b1;
799 const char *sep = &DIR_SEPS[1];
803 b1 = strrchr(s, *sep);
804 if (b1 && (!b || b1 > b))
808 return b ? b + 1 : s;