home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / hpftodit / hpftodit.cc next >
C/C++ Source or Header  |  1995-06-27  |  19KB  |  780 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1994 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  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
  10. version.
  11.  
  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
  15. for more details.
  16.  
  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. */
  20.  
  21. /*
  22. TODO
  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)
  29. */
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <math.h>
  34. #include <string.h>
  35. #include <errno.h>
  36. #include "assert.h"
  37. #include "lib.h"
  38. #include "posix.h"
  39. #include "errarg.h"
  40. #include "error.h"
  41. #include "cset.h"
  42.  
  43. #define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
  44.  
  45. const int MULTIPLIER = 3;
  46.  
  47. inline
  48. int scale(int n)
  49. {
  50.   return n * MULTIPLIER;
  51. }
  52.  
  53. // tags in TFM file
  54.  
  55. enum tag_type {
  56.   min_tag = 400,
  57.   type_tag = 400,
  58.   symbol_set_tag = 404,
  59.   msl_tag = 403,
  60.   inches_per_point_tag = 406,
  61.   design_units_per_em_tag = 408,
  62.   posture_tag = 409,
  63.   stroke_weight_tag = 411,
  64.   spacing_tag = 412,
  65.   slant_tag = 413,
  66.   appearance_width_tag = 414,
  67.   word_spacing_tag = 421,
  68.   x_height_tag = 424,
  69.   lower_ascent_tag = 427,
  70.   lower_descent_tag = 428,
  71.   width_tag = 433,
  72.   left_extent_tag = 435,
  73.   right_extent_tag = 436,
  74.   ascent_tag = 437,
  75.   descent_tag = 438,
  76.   pair_kern_tag = 439,
  77.   typeface_tag = 442,
  78.   max_tag = 443
  79.   };
  80.  
  81. // types in TFM file
  82.  
  83. enum {
  84.   ENUM_TYPE = 1,
  85.   BYTE_TYPE = 2,
  86.   USHORT_TYPE = 3,
  87.   FLOAT_TYPE = 5,
  88.   SIGNED_SHORT_TYPE = 17
  89.   };
  90.  
  91.  
  92. typedef unsigned char byte;
  93. typedef unsigned short uint16;
  94. typedef short int16;
  95. typedef unsigned int uint32;
  96.  
  97. class File {
  98. public:
  99.   File(const char *);
  100.   void skip(int n);
  101.   byte get_byte();
  102.   uint16 get_uint16();
  103.   uint32 get_uint32();
  104.   void seek(uint32 n);
  105. private:
  106.   unsigned char *buf_;
  107.   const unsigned char *ptr_;
  108.   const unsigned char *end_;
  109. };
  110.  
  111. struct entry {
  112.   char present;
  113.   uint16 type;
  114.   uint32 count;
  115.   uint32 value;
  116.   entry() : present(0) { }
  117. };
  118.  
  119. struct char_info {
  120.   uint16 msl;
  121.   uint16 width;
  122.   uint16 ascent;
  123.   int16 descent;
  124.   int16 left_extent;
  125.   uint16 right_extent;
  126.   uint16 symbol_set;
  127.   unsigned char code;
  128. };
  129.  
  130. const uint16 NO_SYMBOL_SET = 0;
  131.  
  132. struct name_list {
  133.   char *name;
  134.   name_list *next;
  135.   name_list(const char *s, name_list *p) : name(strsave(s)), next(p) { }
  136.   ~name_list() { a_delete name; }
  137. };
  138.  
  139. struct symbol_set {
  140.   uint16 select;
  141.   uint16 index[256];
  142. };
  143.  
  144. #define SYMBOL_SET(n, c) ((n) * 32 + ((c) - 64))
  145.  
  146. uint16 text_symbol_sets[] = {
  147.   SYMBOL_SET(0, 'N'),        // Latin 1
  148.   SYMBOL_SET(6, 'J'),        // Microsoft Publishing
  149.   SYMBOL_SET(2, 'N'),        // Latin 2
  150.   0
  151.   };
  152.  
  153. uint16 special_symbol_sets[] = {
  154.   SYMBOL_SET(8, 'M'),
  155.   SYMBOL_SET(5, 'M'),
  156.   SYMBOL_SET(15, 'U'),
  157.   0
  158.   };
  159.  
  160. entry tags[max_tag + 1 - min_tag];
  161.  
  162. char_info *char_table;
  163. uint32 nchars;
  164.  
  165. int msl_name_table_size = 0;
  166. name_list **msl_name_table = 0;
  167.  
  168. int n_symbol_sets;
  169. symbol_set *symbol_set_table;
  170.  
  171. static int special_flag = 0;
  172. static int italic_flag = 0;
  173. static int italic_sep;
  174.  
  175. static void usage();
  176. static const char *xbasename(const char *);
  177. static void read_tags(File &);
  178. static void check_type();
  179. static void check_units(File &);
  180. static int read_map(const char *);
  181. static void require_tag(tag_type);
  182. static void dump_tags(File &f);
  183. static void output_spacewidth();
  184. static void output_pclweight();
  185. static void output_pclproportional();
  186. static void read_and_output_pcltypeface(File &);
  187. static void output_pclstyle();
  188. static void output_slant();
  189. static void output_ligatures();
  190. static void read_symbol_sets(File &);
  191. static void read_and_output_kernpairs(File &);
  192. static void output_charset();
  193. static void read_char_table(File &f);
  194.  
  195. inline
  196. entry &tag_info(tag_type t)
  197. {
  198.   return tags[t - min_tag];
  199. }
  200.  
  201. int main(int argc, char **argv)
  202. {
  203.   program_name = argv[0];
  204.  
  205.   int opt;
  206.   int debug_flag = 0;
  207.  
  208.   while ((opt = getopt(argc, argv, "dsvi:")) != EOF) {
  209.     switch (opt) {
  210.     case 'd':
  211.       debug_flag = 1;
  212.       break;
  213.     case 's':
  214.       special_flag = 1;
  215.       break;
  216.     case 'i':
  217.       italic_flag = 1;
  218.       italic_sep = atoi(optarg);
  219.       break;
  220.     case 'v':
  221.       {
  222.     extern const char *version_string;
  223.     fprintf(stderr, "hpftodit version %s\n", version_string);
  224.     fflush(stderr);
  225.     break;
  226.       }
  227.       break;
  228.     case '?':
  229.       usage();
  230.     default:
  231.       assert(0);
  232.     }
  233.   }
  234.   if (argc - optind != 3)
  235.     usage();
  236.   File f(argv[optind]);
  237.   if (!read_map(argv[optind + 1]))
  238.     exit(1);
  239.   current_filename = 0;
  240.   current_lineno = -1;        // no line numbers
  241.   if (freopen(argv[optind + 2], "w", stdout) == 0)
  242.     fatal("cannot open `%1': %2", argv[optind + 2], strerror(errno));
  243.   current_filename = argv[optind];
  244.   printf("name %s\n", xbasename(argv[optind + 2]));
  245.   if (special_flag)
  246.     printf("special\n");
  247.   read_tags(f);
  248.   check_type();
  249.   check_units(f);
  250.   if (debug_flag)
  251.     dump_tags(f);
  252.   read_char_table(f);
  253.   output_spacewidth();
  254.   output_slant();
  255.   read_and_output_pcltypeface(f);
  256.   output_pclproportional();
  257.   output_pclweight();
  258.   output_pclstyle();
  259.   read_symbol_sets(f);
  260.   output_ligatures();
  261.   read_and_output_kernpairs(f);
  262.   output_charset();
  263.   return 0;
  264. }
  265.  
  266. static
  267. void usage()
  268. {
  269.   fprintf(stderr, "usage: %s [-s] [-i n] tfm_file map_file output_font\n",
  270.       program_name);
  271.   exit(1);
  272. }
  273.  
  274. File::File(const char *s)
  275. {
  276.   int fd = open(s, O_RDONLY);
  277.   if (fd < 0)
  278.     fatal("cannot open `%1': %2", s, strerror(errno));
  279.   current_filename = s;
  280.   struct stat sb;
  281.   if (fstat(fd, &sb) < 0)
  282.     fatal("cannot stat: %1", strerror(errno));
  283.   if (!S_ISREG(sb.st_mode))
  284.     fatal("not a regular file");
  285.   buf_ = new unsigned char[sb.st_size];
  286.   long nread = read(fd, buf_, sb.st_size);
  287.   if (nread < 0)
  288.     fatal("read error: %1", strerror(errno));
  289.   if (nread != sb.st_size)
  290.     fatal("read unexpected number of bytes");
  291.   ptr_ = buf_;
  292.   end_ = buf_ + sb.st_size;
  293. }
  294.  
  295. void File::skip(int n)
  296. {
  297.   if (end_ - ptr_ < n)
  298.     fatal("unexpected end of file");
  299.   ptr_ += n;
  300. }
  301.  
  302. void File::seek(uint32 n)
  303. {
  304.   if (end_ - buf_ < n)
  305.     fatal("unexpected end of file");
  306.   ptr_ = buf_ + n;
  307. }
  308.  
  309. byte File::get_byte()
  310. {
  311.   if (ptr_ >= end_)
  312.     fatal("unexpected end of file");
  313.   return *ptr_++;
  314. }
  315.  
  316. uint16 File::get_uint16()
  317. {
  318.   if (end_ - ptr_ < 2)
  319.     fatal("unexpected end of file");
  320.   uint16 n = *ptr_++;
  321.   return n + (*ptr_++ << 8);
  322. }
  323.  
  324. uint32 File::get_uint32()
  325. {
  326.   if (end_ - ptr_ < 4)
  327.     fatal("unexpected end of file");
  328.   uint32 n = *ptr_++;
  329.   for (int i = 0; i < 3; i++)
  330.     n += *ptr_++ << (i + 1)*8;
  331.   return n;
  332. }
  333.  
  334. static
  335. void read_tags(File &f)
  336. {
  337.   if (f.get_byte() != 'I' || f.get_byte() != 'I')
  338.     fatal("not an Intel format TFM file");
  339.   f.skip(6);
  340.   uint16 ntags = f.get_uint16();
  341.   entry dummy;
  342.   for (uint16 i = 0; i < ntags; i++) {
  343.     uint16 tag = f.get_uint16();
  344.     entry *p;
  345.     if (min_tag <= tag && tag <= max_tag)
  346.       p = tags + (tag - min_tag);
  347.     else
  348.       p = &dummy;
  349.     p->present = 1;
  350.     p->type = f.get_uint16();
  351.     p->count = f.get_uint32();
  352.     p->value = f.get_uint32();
  353.   }
  354. }
  355.  
  356. static
  357. void check_type()
  358. {
  359.   require_tag(type_tag);
  360.   if (tag_info(type_tag).value != 0) {
  361.     if (tag_info(type_tag).value == 2)
  362.       fatal("cannot handle TrueType tfm files");
  363.     fatal("unknown type tag %1", int(tag_info(type_tag).value));
  364.   }
  365. }
  366.  
  367. static
  368. void check_units(File &f)
  369. {
  370.   require_tag(design_units_per_em_tag);
  371.   f.seek(tag_info(design_units_per_em_tag).value);
  372.   uint32 num = f.get_uint32();
  373.   uint32 den = f.get_uint32();
  374.   if (num != 8782 || den != 1)
  375.     fatal("design units per em != 8782/1");
  376.   require_tag(inches_per_point_tag);
  377.   f.seek(tag_info(inches_per_point_tag).value);
  378.   num = f.get_uint32();
  379.   den = f.get_uint32();
  380.   if (num != 100 || den != 7231)
  381.     fatal("inches per point not 100/7231");
  382. }
  383.  
  384. static
  385. void require_tag(tag_type t)
  386. {
  387.   if (!tag_info(t).present)
  388.     fatal("tag %1 missing", int(t));
  389. }
  390.  
  391. static
  392. void output_spacewidth()
  393. {
  394.   require_tag(word_spacing_tag);
  395.   printf("spacewidth %d\n", scale(tag_info(word_spacing_tag).value));
  396. }
  397.  
  398. static
  399. void read_symbol_sets(File &f)
  400. {
  401.   uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count;
  402.   n_symbol_sets = symbol_set_dir_length/14;
  403.   symbol_set_table = new symbol_set[n_symbol_sets];
  404.   int i;
  405.   for (i = 0; i < n_symbol_sets; i++) {
  406.     f.seek(tag_info(symbol_set_tag).value + i*14);
  407.     (void)f.get_uint32();
  408.     uint32 off1 = f.get_uint32();
  409.     uint32 off2 = f.get_uint32();
  410.     (void)f.get_uint16();        // what's this for?
  411.     f.seek(off1);
  412.     int j;
  413.     uint16 kind = 0;
  414.     for (j = 0; j < off2 - off1; j++) {
  415.       unsigned char c = f.get_byte();
  416.       if ('0' <= c && c <= '9')
  417.     kind = kind*10 + (c - '0');
  418.       else if ('A' <= c && c <= 'Z')
  419.     kind = kind*32 + (c - 64);
  420.     }
  421.     symbol_set_table[i].select = kind;
  422.     for (j = 0; j < 256; j++)
  423.       symbol_set_table[i].index[j] = f.get_uint16();
  424.   }
  425.   for (i = 0; i < nchars; i++)
  426.     char_table[i].symbol_set = NO_SYMBOL_SET;
  427.  
  428.   uint16 *symbol_set_selectors = (special_flag
  429.                   ? special_symbol_sets
  430.                   : text_symbol_sets);
  431.   for (i = 0; symbol_set_selectors[i] != 0; i++) {
  432.     int j;
  433.     for (j = 0; j < n_symbol_sets; j++)
  434.       if (symbol_set_table[j].select == symbol_set_selectors[i])
  435.     break;
  436.     if (j < n_symbol_sets) {
  437.       for (int k = 0; k < 256; k++) {
  438.     uint16 index = symbol_set_table[j].index[k];
  439.     if (index != 0xffff
  440.         && char_table[index].symbol_set == NO_SYMBOL_SET) {
  441.       char_table[index].symbol_set = symbol_set_table[j].select;
  442.       char_table[index].code = k;
  443.     }
  444.       }
  445.     }
  446.   }
  447. }
  448.  
  449. static
  450. void read_char_table(File &f)
  451. {
  452.   require_tag(msl_tag);
  453.   nchars = tag_info(msl_tag).count;
  454.   char_table = new char_info[nchars];
  455.  
  456.   f.seek(tag_info(msl_tag).value);
  457.   uint32 i;
  458.   for (i = 0; i < nchars; i++)
  459.     char_table[i].msl = f.get_uint16();
  460.   
  461.   require_tag(width_tag);
  462.   f.seek(tag_info(width_tag).value);
  463.   for (i = 0; i < nchars; i++)
  464.     char_table[i].width = f.get_uint16();
  465.  
  466.   require_tag(ascent_tag);
  467.   f.seek(tag_info(ascent_tag).value);
  468.   for (i = 0; i < nchars; i++) {
  469.     char_table[i].ascent = f.get_uint16();
  470.   }
  471.  
  472.   require_tag(descent_tag);
  473.   f.seek(tag_info(descent_tag).value);
  474.   for (i = 0; i < nchars; i++) {
  475.     char_table[i].descent = f.get_uint16();
  476.     if (char_table[i].descent > 0)
  477.       char_table[i].descent = 0;
  478.   }
  479.  
  480.   require_tag(left_extent_tag);
  481.   f.seek(tag_info(left_extent_tag).value);
  482.   for (i = 0; i < nchars; i++)
  483.     char_table[i].left_extent = int16(f.get_uint16());
  484.  
  485.   require_tag(right_extent_tag);
  486.   f.seek(tag_info(right_extent_tag).value);
  487.   for (i = 0; i < nchars; i++)
  488.     char_table[i].right_extent = f.get_uint16();
  489. }
  490.  
  491. static
  492. void output_pclweight()
  493. {
  494.   require_tag(stroke_weight_tag);
  495.   int stroke_weight = tag_info(stroke_weight_tag).value;
  496.   int pcl_stroke_weight;
  497.   if (stroke_weight < 128)
  498.     pcl_stroke_weight = -3;
  499.   else if (stroke_weight == 128)
  500.     pcl_stroke_weight = 0;
  501.   else if (stroke_weight <= 145)
  502.     pcl_stroke_weight = 1;
  503.   else if (stroke_weight <= 179)
  504.     pcl_stroke_weight = 3;
  505.   else
  506.     pcl_stroke_weight = 4;
  507.   printf("pclweight %d\n", pcl_stroke_weight);
  508. }
  509.  
  510. static
  511. void output_pclproportional()
  512. {
  513.   require_tag(spacing_tag);
  514.   printf("pclproportional %d\n", tag_info(spacing_tag).value == 0);
  515. }
  516.  
  517. static
  518. void read_and_output_pcltypeface(File &f)
  519. {
  520.   printf("pcltypeface ");
  521.   require_tag(typeface_tag);
  522.   f.seek(tag_info(typeface_tag).value);
  523.   for (uint32 i = 0; i < tag_info(typeface_tag).count; i++) {
  524.     unsigned char c = f.get_byte();
  525.     if (c == '\0')
  526.       break;
  527.     putchar(c);
  528.   }
  529.   printf("\n");
  530. }
  531.  
  532. static
  533. void output_pclstyle()
  534. {
  535.   unsigned pcl_style = 0;
  536.   // older tfms don't have the posture tag
  537.   if (tag_info(posture_tag).present) {
  538.     if (tag_info(posture_tag).value)
  539.       pcl_style |= 1;
  540.   }
  541.   else {
  542.     require_tag(slant_tag);
  543.     if (tag_info(slant_tag).value != 0)
  544.       pcl_style |= 1;
  545.   }
  546.   require_tag(appearance_width_tag);
  547.   if (tag_info(appearance_width_tag).value < 100) // guess
  548.     pcl_style |= 4;
  549.   printf("pclstyle %d\n", pcl_style);
  550. }
  551.  
  552. static
  553. void output_slant()
  554. {
  555.   require_tag(slant_tag);
  556.   int slant = int16(tag_info(slant_tag).value);
  557.   if (slant != 0)
  558.     printf("slant %f\n", slant/100.0);
  559. }
  560.  
  561. static
  562. void output_ligatures()
  563. {
  564.   // don't use ligatures for fixed space font
  565.   require_tag(spacing_tag);
  566.   if (tag_info(spacing_tag).value != 0)
  567.     return;
  568.   static const char *ligature_names[] = {
  569.     "fi", "fl", "ff", "ffi", "ffl"
  570.     };
  571.  
  572.   static const char *ligature_chars[] = {
  573.     "fi", "fl", "ff", "Fi", "Fl"
  574.     };
  575.   
  576.   unsigned ligature_mask = 0;
  577.   int i;
  578.   for (i = 0; i < nchars; i++) {
  579.     uint16 msl = char_table[i].msl;
  580.     if (msl < msl_name_table_size
  581.     && char_table[i].symbol_set != NO_SYMBOL_SET) {
  582.       for (name_list *p = msl_name_table[msl]; p; p = p->next)
  583.     for (int j = 0; j < SIZEOF(ligature_chars); j++)
  584.       if (strcmp(p->name, ligature_chars[j]) == 0) {
  585.         ligature_mask |= 1 << j;
  586.         break;
  587.       }
  588.       }
  589.     }
  590.   if (ligature_mask) {
  591.     printf("ligatures");
  592.     for (i = 0; i < SIZEOF(ligature_names); i++)
  593.       if (ligature_mask & (1 << i))
  594.     printf(" %s", ligature_names[i]);
  595.     printf(" 0\n");
  596.   }
  597. }
  598.  
  599. static
  600. void read_and_output_kernpairs(File &f)
  601. {
  602.   if (tag_info(pair_kern_tag).present) {
  603.     printf("kernpairs\n");
  604.     f.seek(tag_info(pair_kern_tag).value);
  605.     uint16 n_pairs = f.get_uint16();
  606.     for (int i = 0; i < n_pairs; i++) {
  607.       uint16 i1 = f.get_uint16();
  608.       uint16 i2 = f.get_uint16();
  609.       int16 val = int16(f.get_uint16());
  610.       if (char_table[i1].symbol_set != NO_SYMBOL_SET
  611.       && char_table[i2].symbol_set != NO_SYMBOL_SET
  612.       && char_table[i1].msl < msl_name_table_size
  613.       && char_table[i2].msl < msl_name_table_size) {
  614.     for (name_list *p = msl_name_table[char_table[i1].msl];
  615.          p;
  616.          p = p->next)
  617.       for (name_list *q = msl_name_table[char_table[i2].msl];
  618.            q;
  619.            q = q->next)
  620.         printf("%s %s %d\n", p->name, q->name, scale(val));
  621.       }
  622.     }
  623.   }
  624. }
  625.  
  626. static 
  627. void output_charset()
  628. {
  629.   require_tag(slant_tag);
  630.   double slant_angle = int16(tag_info(slant_tag).value)*PI/18000.0;
  631.   double slant = sin(slant_angle)/cos(slant_angle);
  632.  
  633.   require_tag(x_height_tag);
  634.   require_tag(lower_ascent_tag);
  635.   require_tag(lower_descent_tag);
  636.  
  637.   printf("charset\n");
  638.   int i;
  639.   for (i = 0; i < nchars; i++) {
  640.     uint16 msl = char_table[i].msl;
  641.     if (msl < msl_name_table_size
  642.     && msl_name_table[msl]) {
  643.       if (char_table[i].symbol_set != NO_SYMBOL_SET) {
  644.     printf("%s\t%d,%d",
  645.            msl_name_table[msl]->name,
  646.            scale(char_table[i].width),
  647.            scale(char_table[i].ascent));
  648.     int depth = scale(- char_table[i].descent);
  649.     if (depth < 0)
  650.       depth = 0;
  651.     int italic_correction = 0;
  652.     int left_italic_correction = 0;
  653.     int subscript_correction = 0;
  654.     if (italic_flag) {
  655.       italic_correction = scale(char_table[i].right_extent 
  656.                     - char_table[i].width
  657.                     + italic_sep);
  658.       if (italic_correction < 0)
  659.         italic_correction = 0;
  660.       subscript_correction = int((tag_info(x_height_tag).value
  661.                       * slant * .8) + .5);
  662.       if (subscript_correction > italic_correction)
  663.         subscript_correction = italic_correction;
  664.       left_italic_correction = scale(italic_sep
  665.                      - char_table[i].left_extent);
  666.     }
  667.     if (subscript_correction != 0)
  668.       printf(",%d,%d,%d,%d",
  669.          depth, italic_correction, left_italic_correction,
  670.          subscript_correction);
  671.     else if (left_italic_correction != 0)
  672.       printf(",%d,%d,%d", depth, italic_correction, left_italic_correction);
  673.     else if (italic_correction != 0)
  674.       printf(",%d,%d", depth, italic_correction);
  675.     else if (depth != 0)
  676.       printf(",%d", depth);
  677.     // This is fairly arbitrary.  Fortunately it doesn't much matter.
  678.     unsigned type = 0;
  679.     if (char_table[i].ascent > (tag_info(lower_ascent_tag).value*9)/10)
  680.       type |= 2;
  681.     if (char_table[i].descent < (int16(tag_info(lower_descent_tag).value)*9)/10)
  682.       type |= 1;
  683.     printf("\t%d\t%d\n",
  684.            type,
  685.            char_table[i].symbol_set*256 + char_table[i].code);
  686.     for (name_list *p = msl_name_table[msl]->next; p; p = p->next)
  687.       printf("%s\t\"\n", p->name);
  688.       }
  689.       else
  690.     warning("MSL %1 not in any of the searched symbol sets", msl);
  691.     }
  692.   }
  693. }
  694.  
  695. static
  696. void dump_tags(File &f)
  697. {
  698.   int i;
  699.   for (i = min_tag; i <= max_tag; i++) {
  700.     enum tag_type t = tag_type(i);
  701.     if (tag_info(t).present) {
  702.       fprintf(stderr,
  703.           "%d %d %d %d\n", i, tag_info(t).type, tag_info(t).count,
  704.           tag_info(t).value);
  705.       if (tag_info(t).type == FLOAT_TYPE
  706.       && tag_info(t).count == 1) {
  707.     f.seek(tag_info(t).value);
  708.     uint32 num = f.get_uint32();
  709.     uint32 den = f.get_uint32();
  710.     fprintf(stderr, "(%u/%u = %g)\n", num, den, (double)num/den);
  711.       }
  712.     }
  713.   }
  714. }
  715.  
  716. static
  717. int read_map(const char *file)
  718. {
  719.   errno = 0;
  720.   FILE *fp = fopen(file, "r");
  721.   if (!fp) {
  722.     error("can't open `%1': %2", file, strerror(errno));
  723.     return 0;
  724.   }
  725.   current_filename = file;
  726.   char buf[512];
  727.   current_lineno = 0;
  728.   while (fgets(buf, int(sizeof(buf)), fp)) {
  729.     current_lineno++;
  730.     char *ptr = buf;
  731.     while (csspace(*ptr))
  732.       ptr++;
  733.     if (*ptr == '\0' || *ptr == '#')
  734.       continue;
  735.     ptr = strtok(ptr, " \n\t");
  736.     if (!ptr)
  737.       continue;
  738.     int n;
  739.     if (sscanf(ptr, "%d", &n) != 1) {
  740.       error("bad map file");
  741.       fclose(fp);
  742.       return 0;
  743.     }
  744.     if (n < 0) {
  745.       error("negative code");
  746.       fclose(fp);
  747.       return 0;
  748.     }
  749.     if (n >= msl_name_table_size) {
  750.       size_t old_size = msl_name_table_size;
  751.       name_list **old_table = msl_name_table;
  752.       msl_name_table_size = n + 256;
  753.       msl_name_table = new name_list *[msl_name_table_size];
  754.       if (old_table) {
  755.     memcpy(msl_name_table, old_table, old_size*sizeof(name_list *));
  756.     a_delete old_table;
  757.       }
  758.       for (size_t i = old_size; i < msl_name_table_size; i++)
  759.     msl_name_table[i] = 0;
  760.     }
  761.     ptr = strtok(0, " \n\t");
  762.     if (!ptr) {
  763.       error("missing names");
  764.       fclose(fp);
  765.       return 0;
  766.     }
  767.     for (; ptr; ptr = strtok(0, " \n\t"))
  768.       msl_name_table[n] = new name_list(ptr, msl_name_table[n]);
  769.   }
  770.   fclose(fp);
  771.   return 1;
  772. }
  773.  
  774. static
  775. const char *xbasename(const char *s)
  776. {
  777.   const char *b = strrchr(s, '/');
  778.   return b ? b + 1 : s;
  779. }
  780.