home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / fontutils-0.6-base.tgz / fontutils-0.6-base.tar / fsf / fontutils / bzrto / main.c < prev    next >
C/C++ Source or Header  |  1992-10-20  |  19KB  |  594 lines

  1. /* bzrto -- translate a font in the binary BZR outline format to various
  2.    other formats.
  3.  
  4. Copyright (C) 1992 Free Software Foundation, Inc.
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "config.h"
  21.  
  22. #include "bzr.h"
  23. #define CMDLINE_NO_DPI /* BZR fonts are resolution-independent.  */
  24. #include "cmdline.h"
  25. #include "filename.h"
  26. #include "getopt.h"
  27. #include "lib.h"
  28. #include "list.h"
  29. #include "report.h"
  30. #include "tfm.h"
  31.  
  32. #include "input-ccc.h"
  33. #include "main.h"
  34. #include "metafont.h"
  35. #include "pstype1.h"
  36. #include "pstype3.h"
  37. #include "psutil.h"
  38. #include "text.h"
  39.  
  40. #include "ccc.h"
  41.  
  42.  
  43. /* The encoding vector.  This is not static because it's too much
  44.    trouble to pass it down to the output routines.  */
  45. encoding_info_type encoding_info;
  46.  
  47. /* Says which characters we should process.  This is independent of the
  48.    ordering in the font file.  (-range)  */
  49. charcode_type starting_char = 0;
  50. charcode_type ending_char = MAX_CHARCODE;
  51.  
  52. /* The font parameters from the main TFM file, or NULL.  */
  53. tfm_global_info_type *tfm_global_info;
  54.  
  55. /* The name of the CCC input file specified by the user.  (-ccc-file)  */
  56. static string ccc_name = NULL;
  57.  
  58. /* Possible targets for the translation.  */
  59. typedef enum
  60. { metafont, pstype1, pstype3, text, dummy_for_end
  61. } translation_targets;
  62. #define NTARGETS dummy_for_end
  63.  
  64. /* This array tells us to which forms to translate the BZR file.  */
  65. static boolean output[NTARGETS];
  66.  
  67. /* The names of BZR files to be concatenated onto the main one in the
  68.    output.  (-concat)  */
  69. static list_type bzr_name_list;
  70.  
  71. /* The name of the encoding file.  (-encoding)  */
  72. static string encoding_name = NULL;
  73.  
  74. /* The name of the output file specified by the user.  (-output-file)  */
  75. static string output_name = NULL;
  76.  
  77. /* The FontName of the PostScript font.  */
  78. static string ps_fontname;
  79.  
  80. /* This is defined in version.c.  */
  81. extern string version_string;
  82.  
  83. /* The number of characters we report per line if verbose.  */
  84. #define NCHARS_PER_LINE 13
  85.  
  86. static void append_concat_list (list_type *, string);
  87. static unsigned count_non_subr_chars
  88.   (char_type *[], bzr_char_type *[], ccc_type *[]);
  89. static void init_tfm_and_encoding_info
  90.   (string, tfm_global_info_type **, encoding_info_type *);
  91. static void output_bzr_char (bzr_char_type, char_type *[]);
  92. static void output_bzr_subr (bzr_char_type);
  93. static void output_ccc_char (ccc_type, charcode_type, char_type *[]);
  94. static void output_ccc_subr (ccc_type, charcode_type, char_type *[]);
  95. static void read_bzr_file (bzr_char_type *[], string);
  96. static bzr_char_type **read_bzr_files (list_type);
  97. static string read_command_line (int, string []);
  98.  
  99. /* Convert generic outline fonts in BZR format to a form that can
  100.    actually be used for typesetting.  */
  101.  
  102. int
  103. main (unsigned argc, string argv[])
  104. {
  105.   string bzr_name;
  106.   bzr_preamble_type preamble;
  107.   bzr_postamble_type postamble;
  108.   bzr_char_type **bzr_chars;
  109.   ccc_type **ccc_chars;
  110.   char_type **chars, **subrs;
  111.   string *first_name;
  112.   string font_name, font_rootname;
  113.   unsigned subr_count;
  114.   unsigned this_char;
  115.   boolean ccc_warning_p = true;
  116.   unsigned char_count = 0;
  117.  
  118.   /* Initialize the list of BZR filenames to have one empty element at
  119.      the beginning, which we fill in below with the main BZR name.  */
  120.   bzr_name_list = list_init ();
  121.   first_name = LIST_TAPPEND (&bzr_name_list, string);
  122.   
  123.   font_name = read_command_line (argc, argv);
  124.   font_rootname = remove_suffix (basename (font_name));
  125.  
  126.   if (output_name == NULL)
  127.     output_name = strtok (xstrdup (font_rootname), "0123456789");
  128.   else 
  129.     if (find_suffix (output_name) != NULL
  130.     && ((output[metafont] && output[pstype1])
  131.         || (output[metafont] && output[pstype3])
  132.         || (output[pstype1] && output[pstype3])))
  133.      FATAL ("You can't specify a suffix and more than one output file");
  134.  
  135.   bzr_name = extend_filename (font_name, "bzr");
  136.   if (!bzr_open_input_file (bzr_name))
  137.     FATAL_PERROR (bzr_name);
  138.  
  139.   /* The first element of the BZR name list.  */
  140.   *first_name = bzr_name;
  141.  
  142.   /* Read the global information from the BZR file and then close it, as
  143.      we open it again below when reading the characters.  */
  144.   preamble = bzr_get_preamble ();
  145.   postamble = bzr_get_postamble ();
  146.   bzr_close_input_file ();
  147.   
  148.   /* Read global TFM information, if we have it, and make sure we have
  149.      an encoding vector.  */
  150.   init_tfm_and_encoding_info (bzr_name, &tfm_global_info, &encoding_info);
  151.  
  152.   if (output[metafont])
  153.     metafont_start_output (output_name, preamble, tfm_global_info);
  154.   if (output[pstype1])
  155.     pstype1_start_output (output_name, preamble, postamble);
  156.   if (output[pstype3])
  157.     pstype3_start_output (output_name, preamble, postamble);
  158.   if (output[text])
  159.     text_start_output (font_name, preamble);
  160.  
  161.  
  162.   /* We don't know which BZR characters the CCC file might use, so just
  163.      read them all.  */
  164.   bzr_chars = read_bzr_files (bzr_name_list);
  165.  
  166.   /* Read the composite character definitions.  */
  167.   if (ccc_name == NULL)
  168.     {
  169.       ccc_name = remove_suffix (font_name);
  170.       ccc_warning_p = false;
  171.     }
  172.   ccc_chars = parse_ccc_file (ccc_name, bzr_chars, tfm_global_info,
  173.                               BZR_DESIGN_SIZE (preamble), ccc_warning_p);
  174.  
  175.  
  176.   /* We've read the input.  Figure out which characters we need as
  177.      subroutines (because they're used in the CCC characters).  */
  178.   subrs = subr_chars (bzr_chars, ccc_chars, starting_char, ending_char,
  179.                       &subr_count);
  180.  
  181.  
  182.   /* An ugly special case due to context dependence in PostScript.  */
  183.   if (output[pstype1])
  184.     pstype1_start_subrs (subr_count);
  185.  
  186.   /* Output all the characters needed as subroutines.  We cannot simply
  187.      output every character as a subroutine, because for 1200dpi
  188.      originals the result is too large to fit in even big Metafont's
  189.      260K memory.  */
  190.   REPORT ("Writing subroutines:\n");
  191.   for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
  192.     if (subrs[this_char])
  193.       { 
  194.         char_type subr = *subrs[this_char];
  195.         
  196.         char_count++;
  197.         REPORT2 ("[%d]%c", this_char,
  198.                  char_count % NCHARS_PER_LINE ? ' ' : '\n');
  199.  
  200.         /* If we have both BZR and CCC definitions for `this_char',
  201.            prefer the former.  */
  202.         if (CHAR_CLASS (subr) == bzr_char_class)
  203.           output_bzr_subr (*CHAR_BZR (subr));
  204.         else if (CHAR_CLASS (subr) == ccc_char_class)
  205.           output_ccc_subr (*CHAR_CCC (subr), this_char, subrs);
  206.         else
  207.           abort ();
  208.       }
  209.  
  210.  
  211.   /* The ugly special case continues.  */
  212.   if (output[pstype1])
  213.     pstype1_start_chars (count_non_subr_chars (subrs, bzr_chars, ccc_chars));
  214.  
  215.  
  216.   /* And finally, output the non-subroutine characters.  */
  217.   REPORT1 ("%sWriting characters:\n",
  218.            char_count % NCHARS_PER_LINE ? "\n" : "");
  219.   for (this_char = starting_char; this_char <= ending_char; this_char++)
  220.     {
  221.       if (bzr_chars[this_char] || ccc_chars[this_char])
  222.         {
  223.           char_count++;
  224.           REPORT2 ("[%d]%c", this_char,
  225.                    char_count % NCHARS_PER_LINE ? ' ' : '\n');
  226.           
  227.           if (bzr_chars[this_char])
  228.             output_bzr_char (*bzr_chars[this_char], subrs);
  229.           else if (ccc_chars[this_char])
  230.             output_ccc_char (*ccc_chars[this_char], this_char, subrs);
  231.           else
  232.             abort ();
  233.         }
  234.     }
  235.  
  236.   if (output[metafont]) metafont_finish_output (bzr_name_list, chars);
  237.   if (output[pstype1]) pstype1_finish_output ();
  238.   if (output[pstype3]) pstype3_finish_output ();
  239.   if (output[text]) text_finish_output (postamble);
  240.  
  241.   if (char_count % NCHARS_PER_LINE != 0)
  242.     REPORT ("\n");
  243.  
  244.   return 0;
  245. }
  246.  
  247. /* Read the global information from the TFM file corresponding to
  248.    BZR_NAME (if it exists) into TFM_INFO.  Also read an encoding file
  249.    specified either by `encoding_name' or the codingscheme info from the
  250.    TFM file into ENCODING_INFO.  */
  251.  
  252. static void
  253. init_tfm_and_encoding_info (string bzr_name, tfm_global_info_type **tfm_info,
  254.                             encoding_info_type *encoding_info)
  255. {
  256.   /* Open the main TFM file if it exists.  */
  257.   string tfm_root = make_suffix (bzr_name, "tfm");
  258.   string tfm_name = find_tfm_filename (tfm_root);
  259.  
  260.   if (tfm_name == NULL || !tfm_open_input_file (tfm_name))
  261.     {
  262.       *tfm_info = NULL;
  263.       if (encoding_name == NULL)
  264.         encoding_name = DEFAULT_ENCODING;
  265.     }
  266.   else
  267.     {
  268.       *tfm_info = XTALLOC1 (tfm_global_info_type);
  269.  
  270.       /* Just get the TFM global info and then close the file again, as
  271.          we will open it again later for the characters.  */
  272.       **tfm_info = tfm_get_global_info ();
  273.       tfm_close_input_file ();
  274.  
  275.       /* If the user hasn't specified an encoding name, guess from the
  276.          TFM info.  */
  277.       if (encoding_name == NULL)
  278.         encoding_name
  279.           = coding_scheme_to_filename (TFM_CODING_SCHEME (**tfm_info));
  280.     }
  281.  
  282.   /* In any case, read the encoding file.  I don't think we actually
  283.      need this in all cases, but what the heck, it's no problem to read
  284.      the default one.  */
  285.   *encoding_info = read_encoding_file (encoding_name);
  286. }
  287.  
  288. /* Read each BZR file in BZR_NAMES, merging all the characters.  We
  289.    scale all characters to the size of the first font, and oblique the
  290.    characters if `oblique_angle' is nonzero.  */
  291.  
  292. static bzr_char_type **
  293. read_bzr_files (list_type bzr_names)
  294. {
  295.   unsigned c, name;
  296.   bzr_char_type **bzr_chars = XTALLOC (MAX_CHARCODE + 1, bzr_char_type *);
  297.   
  298.   /* Assume we'll find nothing.  */
  299.   for (c = 0; c <= MAX_CHARCODE; c++)
  300.     bzr_chars[c] = NULL;
  301.  
  302.   /* Read all the files, updating the array as we go.  */
  303.   for (name = 0; name < LIST_SIZE (bzr_names); name++)
  304.     {
  305.       string *bzr_name = LIST_ELT (bzr_names, name);
  306.       
  307.       REPORT1 ("(%s", *bzr_name);
  308.       read_bzr_file (bzr_chars, *bzr_name);
  309.       REPORT (")\n");
  310.     }
  311.  
  312.   return bzr_chars;
  313. }
  314.  
  315.  
  316. /* If the BZR file BZR_NAME exists, read it and update BZR_CHARS.  We do
  317.    not overwrite existing BZR characters, since earlier files should
  318.    override later files.  (The first file is the main input file.)
  319.    Complain about missing input files, since the user specified all
  320.    these names explicitly.  We scale and oblique the characters we read
  321.    if desired.  */
  322.  
  323. static void
  324. read_bzr_file (bzr_char_type *bzr_chars[], string passed_bzr_name)
  325. {
  326.   unsigned char_count = 0;
  327.   static real output_design_size = 0.0;
  328.   string bzr_name = make_suffix (passed_bzr_name, "bzr");
  329.  
  330.   if (bzr_open_input_file (bzr_name))
  331.     {
  332.       bzr_char_type *file_char;
  333.       bzr_preamble_type pre = bzr_get_preamble ();
  334.       
  335.       /* Scale everything to the design size of the first font.  */
  336.       if (output_design_size == 0.0)
  337.         output_design_size = BZR_DESIGN_SIZE (pre);
  338.  
  339.       while (file_char = bzr_get_next_char ())
  340.         {
  341.           unsigned code = CHARCODE (*file_char);
  342.           
  343.           char_count++;
  344.           REPORT2 ("%c[%d]", char_count % NCHARS_PER_LINE ? ' ' : '\n', code);
  345.           
  346.           if (bzr_chars[code] == NULL)
  347.             {
  348.               real design_size_ratio
  349.                 = BZR_DESIGN_SIZE (pre) / output_design_size;
  350.  
  351.               BZR_SHAPE (*file_char)
  352.                 = oblique_splines (BZR_SHAPE (*file_char));
  353.               scale_char (file_char, design_size_ratio);
  354.               
  355.               bzr_chars[code] = file_char;
  356.             }
  357.           else
  358.             free (file_char);
  359.         }
  360.  
  361.       bzr_close_input_file ();
  362.     }
  363.   else
  364.     perror (bzr_name);
  365. }
  366.  
  367. /* Output BZR_CHAR as a subroutine in whatever output formats the user
  368.    has requested.  Except that PostScript Type 3 and text output don't
  369.    do subroutines, so we just output the character straight.  */
  370.  
  371. static void
  372. output_bzr_subr (bzr_char_type bzr_char)
  373. {
  374.   if (output[metafont])
  375.     metafont_output_bzr_subr (bzr_char);
  376.   
  377.   if (output[pstype1])
  378.     pstype1_output_bzr_subr (bzr_char);
  379.   
  380.   /* Don't need to do Type 3 or text, since all the subroutines will
  381.      also get output as characters.  */
  382. }
  383.  
  384.  
  385. /* Output CCC_CHAR as a subroutine.  We do nothing for the Type 3
  386.    output format here, since it doesn't deal with subroutines.  */
  387.  
  388. static void
  389. output_ccc_subr (ccc_type ccc_char, charcode_type code, char_type *subrs[])
  390. {
  391.   if (output[metafont])
  392.     metafont_output_ccc_subr (ccc_char, code, subrs);
  393.   
  394.   if (output[pstype1])
  395.     pstype1_output_ccc_subr (ccc_char, code, subrs);
  396.   
  397.   /* Don't need to do Type 3 or text, since all the subroutines will
  398.      also get output as characters.  */
  399. }
  400.  
  401.  
  402. /* Output BZR_CHAR as a character (as opposed to a subroutine).  */
  403.  
  404. static void
  405. output_bzr_char (bzr_char_type bzr_char, char_type *subrs[])
  406. {
  407.   if (output[metafont])
  408.     metafont_output_bzr_char (bzr_char, subrs);
  409.   
  410.   if (output[pstype1])
  411.     pstype1_output_bzr_char (bzr_char, subrs);
  412.   
  413.   if (output[pstype3])
  414.     pstype3_output_char (bzr_char);
  415.   
  416.   if (output[text])
  417.     text_output_bzr_char (bzr_char);
  418. }
  419.  
  420.  
  421. /* Output CCC_CHAR as a character (as opposed to a subroutine).  Again,
  422.    we do nothing for Type 3 here.  */
  423.  
  424. static void
  425. output_ccc_char (ccc_type ccc_char, charcode_type code, char_type *subrs[])
  426. {
  427.   if (output[metafont])
  428.     metafont_output_ccc_char (ccc_char, code, subrs);
  429.   
  430.   if (output[pstype1])
  431.     pstype1_output_ccc_char (ccc_char, code, subrs);
  432.   
  433.   /* if (output[pstype3])
  434.        do nothing; */
  435.   
  436.   if (output[text])
  437.     text_output_ccc_char (ccc_char);
  438. }
  439.  
  440. /* Count the number of characters (between `starting_char' and
  441.    `ending_char') that we will output, not including subroutines.  */
  442.  
  443. static unsigned
  444. count_non_subr_chars (char_type *subrs[], bzr_char_type *bzr_chars[],
  445.                       ccc_type *ccc_chars[])
  446. {
  447.   unsigned this_char;
  448.   unsigned char_count = 0;
  449.   
  450.   for (this_char = starting_char; this_char <= ending_char; this_char++)
  451.     char_count += bzr_chars[this_char] || ccc_chars[this_char];
  452.  
  453.   return char_count;
  454. }
  455.  
  456. /* Reading the options.  */
  457.  
  458. /* This is defined in version.c.  */
  459. extern string version_string;
  460.  
  461. #define USAGE "Options:
  462. <font_name> should be a filename, e.g., `cmr10'.  Any extension is ignored." \
  463.   GETOPT_USAGE                                     \
  464. "concat <bzr_name_1>,<bzr_name_2>,...: concatenate the main input bzr file with
  465.   the given <bzr_name>s; if a character code exists in more than one
  466.   bzr file, it's the first occurrence that counts.
  467. ccc-file <filename>: read the CCC file <filename> (if <filename> has a
  468.   suffix) or <filename>.ccc (if it doesn't).  Default is <font_name>.
  469. encoding <filename>: specify the encoding file; if <filename> has no
  470.   suffix, use <filename>.enc, otherwise just <filename>.  Default is to
  471.   try to guess the encoding from the coding_scheme string in the TFM
  472.   file if exists, else to use the default " DEFAULT_ENCODING ".
  473. help: print this message.
  474. metafont: translate the font to a Metafont program.
  475. mf: same as `metafont'.
  476. oblique-angle <angle-in-degrees>: angle from the vertical by which to
  477.   slant the shapes; default is 0.
  478. output-file <filename>: output to <filename> (if it has a suffix) or to
  479.   <filename>.<font format> (if it doesn't), where the <font format> is
  480.   `mf', `gsf', etc.  <filename> cannot have a suffix if more than one of
  481.   `metafont', `pstype1' and `pstype3' options are give.  Default is
  482.   <font_name> with a trailing number removed.
  483. ps-font-info <name>:<value>,...: assign each <value> to the
  484.   corresponding <name> when outputting a PostScript font.  Possible
  485.   <name>s: FontName, FamilyName, Weight, ItalicAngle, isFixedPitch,
  486.   UnderlinePosition, UnderlineThickness, UniqueID, version.  Case is
  487.   significant.  See the manual for more details.
  488. pstype1: translate the font to (unencrypted) PostScript Type 1 font format.
  489. pstype3: translate the font to PostScript Type 3 font format.
  490. range <char1>-<char2>: only work on characters between <char1> and
  491.   <char2> inclusive.
  492. text: translate the font to human-readable text; write to stdout.
  493. verbose: print brief progress reports.
  494. version: print the version number of this program.
  495. "
  496.  
  497.  
  498. /* We return the name of the font to process.  */
  499.  
  500. static string
  501. read_command_line (int argc, string argv[])
  502. {
  503.   int g;   /* `getopt' return code.  */
  504.   int option_index;
  505.   boolean printed_version = false;
  506.   struct option long_options []
  507.     = { { "ccc-file",        1, 0, 0 },
  508.         { "concat",        1, 0, 0 },
  509.         { "encoding",        1, 0, 0 },
  510.         { "fontname",        1, 0, 0 },
  511.         { "help",               0, 0, 0 },
  512.         { "metafont",        0, (int *) &output[metafont], 1 },
  513.         { "mf",            0, (int *) &output[metafont], 1 },
  514.         { "oblique-angle",    1, 0, 0 },
  515.         { "output-file",    1, 0, 0 },
  516.         { "ps-font-info",    1, 0, 0 },
  517.         { "pstype1",        0, (int *) &output[pstype1], 1 },
  518.         { "pstype3",        0, (int *) &output[pstype3], 1 },
  519.         { "range",        1, 0, 0 },
  520.         { "text",            0, (int *) &output[text], 1 },
  521.         { "verbose",            0, (int *) &verbose, 1 },
  522.         { "version",            0, (int *) &printed_version, 1 },
  523.         { 0, 0, 0, 0 } };
  524.  
  525.   while (true)
  526.     {
  527.       g = getopt_long_only (argc, argv, "", long_options, &option_index);
  528.  
  529.       if (g == EOF) break;
  530.       if (g == '?') exit (1);  /* Unknown option.  */
  531.   
  532.       assert (g == 0); /* We have no short option names.  */
  533.       
  534.       if (ARGUMENT_IS ("ccc-file"))
  535.         ccc_name = optarg;
  536.  
  537.       else if (ARGUMENT_IS ("concat"))
  538.         append_concat_list (&bzr_name_list, optarg);
  539.         
  540.       else if (ARGUMENT_IS ("encoding"))
  541.         encoding_name = optarg;
  542.         
  543.       else if (ARGUMENT_IS ("fontname"))
  544.         ps_fontname = optarg;
  545.         
  546.       else if (ARGUMENT_IS ("help"))
  547.         {
  548.           fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]);
  549.           fprintf (stderr, USAGE);
  550.           exit (0);
  551.         }
  552.  
  553.       else if (ARGUMENT_IS ("oblique-angle"))
  554.         oblique_angle = M_PI * atof (optarg) / 180.0;
  555.         
  556.       else if (ARGUMENT_IS ("output-file"))
  557.         output_name = optarg;
  558.  
  559.       else if (ARGUMENT_IS ("ps-font-info"))
  560.         ps_global_info = optarg;
  561.         
  562.       else if (ARGUMENT_IS ("range"))
  563.         GET_RANGE (optarg, starting_char, ending_char);
  564.         
  565.       else if (ARGUMENT_IS ("text"))
  566.         report_file = stderr;
  567.  
  568.       else if (ARGUMENT_IS ("version"))
  569.         printf ("%s.\n", version_string);
  570.       
  571.       /* Else it was just a flag; getopt has already done the assignment.  */
  572.     }
  573.   
  574.   FINISH_COMMAND_LINE ();
  575. }
  576.  
  577. /* The string S is a list of font names, separated by commas.  We append
  578.    each onto CONCAT_LIST.  */
  579.  
  580. static void
  581. append_concat_list (list_type *concat_list, string s)
  582. {
  583.   string name;
  584.   
  585.   /* The main routine must initialize CONCAT_LIST before we are called.  */
  586.   assert (concat_list != NULL && LIST_SIZE (*concat_list) > 0);
  587.   
  588.   for (name = strtok (s, ","); name != NULL; name = strtok (NULL, ","))
  589.     {
  590.       string *new = LIST_TAPPEND (concat_list, string);
  591.       *new = name;
  592.     }
  593. }
  594.