diff options
Diffstat (limited to 'tfm/tfm_output.c')
-rw-r--r-- | tfm/tfm_output.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/tfm/tfm_output.c b/tfm/tfm_output.c new file mode 100644 index 0000000..2ff7cb4 --- /dev/null +++ b/tfm/tfm_output.c @@ -0,0 +1,371 @@ +/* tfm_output.c: write property list files (a human-readable equivalent + of TFM files), and convert them to TFM format. PL format is + described in the source code to the TeX utility PLtoTF, by Donald + Knuth. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include <kpathsea/concatn.h> + +#include "file-output.h" +#include "report.h" +#include "tfm.h" + + +/* These identify the output file. (Only one may be open at a time.) */ +static FILE *pl_output_file; +static string pl_output_filename; + +/* The design size for the font is used to scale almost all numbers in + the file. It is in units of printer's points. */ +static real design_size; + + +/* Subroutines for output. */ +static void put_lig_kern_info (tfm_char_type); + + +/* Routines to actually write the properties. */ +static void start_prop_list (string); +static void finish_prop_list (void); +static void start_integer_prop_list (string, unsigned); +static void put_integer_prop (string, unsigned); +static void put_octal_prop (string, unsigned); +static void put_real_prop (string, real); +static void put_scaled_prop (string, real); +static void put_string_prop (string, string); +static void put_indentation (void); + +static void put_lig_prop (tfm_ligature_type *); +static void put_kern_prop (tfm_kern_type *); + +/* Routines to start and finish reading a file. (For the user to call.) */ + +boolean +tfm_open_pl_output_file (string filename) +{ + assert (pl_output_file == NULL); + + pl_output_filename = filename; + pl_output_file = fopen (filename, "w"); + + return pl_output_file != NULL; +} + + +void +tfm_close_pl_output_file () +{ + assert (pl_output_file != NULL); + + xfclose (pl_output_file, pl_output_filename); + + pl_output_file = NULL; + pl_output_filename = NULL; +} + + +/* An argument to allow the PL file to be deleted might be in order + here, and maybe returning the exit status. If TFM_NAME is NULL, we + replace any suffix on `pl_output_filename' with `tfm' and use that. + Otherwise, we use exactly TFM_NAME. */ + +void +tfm_convert_pl (string tfm_name, boolean verbose) +{ + string cmd; + int status; + string arg = verbose ? "" : " >/dev/null 2>&1"; + + if (pl_output_filename == NULL) + { + fprintf (stderr, "No PL output file to convert to TFM format.\n"); + fprintf (stderr, "(Perhaps you called tfm_close_pl_output_file?)\n"); + return; + } + + if (tfm_name == NULL) + tfm_name = make_suffix (pl_output_filename, "tfm"); + + cmd = concatn ("pltotf ", pl_output_filename, " ", tfm_name, arg, NULL); + + /* Make sure that all data we have written will be read. */ + if (fflush (pl_output_file) == EOF) + FATAL1 ("%s: could not flush", pl_output_filename); + + /* Convert to TFM. */ + if (verbose) + printf ("Executing `%s'.\n", cmd); + status = system (cmd); + + free (cmd); + + if (verbose && status != 0) + printf ("Exit status = %d.\n", status); +} + +/* Return an initialized structure. */ + +tfm_global_info_type +tfm_init_global_info () +{ + tfm_global_info_type info; + unsigned this_param; + + TFM_CHECKSUM (info) = 0; + TFM_DESIGN_SIZE (info) = 0.0; + TFM_CODING_SCHEME (info) = "unspecified"; + TFM_FONTDIMEN_COUNT (info) = 0; + for (this_param = 1; this_param <= TFM_MAX_FONTDIMENS; this_param++) + TFM_FONTDIMEN (info, this_param) = 0.0; + + return info; +} + + +/* Output the fontwide information in INFO. */ + +void +tfm_put_global_info (tfm_global_info_type info) +{ + unsigned this_param; + + /* Save the design size so we can scale the other reals. */ + design_size = TFM_DESIGN_SIZE (info); + + put_string_prop ("comment", now ()); + put_real_prop ("designsize", design_size); + put_string_prop ("codingscheme", TFM_CODING_SCHEME (info)); + + /* If the checksum is zero, don't output it; then PLtoTF will compute + one for us. */ + if (TFM_CHECKSUM (info) != 0) + put_octal_prop ("checksum", TFM_CHECKSUM (info)); + + start_prop_list ("fontdimen"); + + for (this_param = 1; this_param <= TFM_FONTDIMEN_COUNT (info); + this_param++) + { + real param_value = TFM_FONTDIMEN (info, this_param); + + /* Parameter #1 (the font slant) is different than all the + rest, because it's not scaled by the design size. */ + if (this_param == 1) + put_real_prop ("slant", param_value); + else + put_scaled_prop (concat ("parameter d ", utoa (this_param)), + param_value); + } + + finish_prop_list (); +} + + +/* We don't bother to keep track of the `nextlarger' and `varchar' + properties, which are used in TeX's math mode. + + TFM_CHAR should be an array of (exactly) `TFM_SIZE' elements. */ + +void +tfm_put_chars (tfm_char_type *tfm_char) +{ + unsigned this_char; + + for (this_char = 0; this_char < TFM_SIZE; this_char++, tfm_char++) + { + if (TFM_CHAR_EXISTS (*tfm_char)) + tfm_put_char (*tfm_char); + } +} + + +/* Output the single character C to the PL file. Although the width and + height are not zero often enough to matter, the depth and italic + correction are often zero, so we may as well check first. */ + +void +tfm_put_char (tfm_char_type c) +{ + /* If we're being called, the character should exist. */ + assert (TFM_CHAR_EXISTS (c)); + + start_integer_prop_list ("character", TFM_CHARCODE (c)); + + put_scaled_prop ("charwd", TFM_WIDTH (c)); + put_scaled_prop ("charht", TFM_HEIGHT (c)); + + if (!epsilon_equal (TFM_DEPTH (c), 0.0)) + put_scaled_prop ("chardp", TFM_DEPTH (c)); + + if (!epsilon_equal (TFM_ITALIC_CORRECTION (c), 0.0)) + put_scaled_prop ("charic", TFM_ITALIC_CORRECTION (c)); + + finish_prop_list (); + + put_lig_kern_info (c); +} + +/* Output any ligature/kern information in the tfm character C. */ + +static void +put_lig_kern_info (tfm_char_type c) +{ + unsigned ligature_count = LIST_SIZE (c.ligature); + unsigned kern_count = LIST_SIZE (c.kern); + + assert (TFM_CHAR_EXISTS (c)); + + /* Do nothing if there's neither ligatures nor kerns. */ + if (ligature_count > 0 || kern_count > 0) + { + unsigned step; + + start_prop_list ("ligtable"); + put_integer_prop ("label", TFM_CHARCODE (c)); + + /* We shouldn't output a lig/kern step unless all the characters + involved exist. But we don't know which characters exist until + the end, when we convert to PL. So for now, we just output + everything we get, instead of saving the information away. It + doesn't actually affect the validity of the results -- it's + just that PLtoTF might give some warnings. */ + for (step = 0; step < ligature_count; step++) + { + tfm_ligature_type *lig = LIST_ELT (c.ligature, step); +#if 0 + if (TFM_CHAR_EXISTS (tfm_char[lig->character]) + && TFM_CHAR_EXISTS (tfm_char[lig->ligature])) +#endif + put_lig_prop (lig); + } + + for (step = 0; step < kern_count; step++) + { + tfm_kern_type *k = LIST_ELT (c.kern, step); +#if 0 + if (TFM_CHAR_EXISTS (tfm_char[k->character])) +#endif + put_kern_prop (k); + } + + put_string_prop ("stop", ""); + finish_prop_list (); + } +} + +/* It makes the output more readable to make the property lists + indented. */ + +static unsigned indentation = 0; +#define INDENT_INCR 2 + + +static void +start_prop_list (string prop_list_name) +{ + put_indentation (); + fprintf (pl_output_file, "(%s\n", prop_list_name); + indentation += INDENT_INCR; +} + + +static void +start_integer_prop_list (string prop, unsigned v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s d %u\n", prop, v); + indentation += INDENT_INCR; +} + + +static void +finish_prop_list () +{ + put_indentation (); + fprintf (pl_output_file, ")\n"); + indentation -= INDENT_INCR; +} + + +static void +put_lig_prop (tfm_ligature_type *lig) +{ + put_indentation (); + fprintf (pl_output_file, "(lig d %u d %u)\n", + lig->character, lig->ligature); +} + + +static void +put_kern_prop (tfm_kern_type *kern) +{ + put_indentation (); + fprintf (pl_output_file, "(krn d %u r %f)\n", + kern->character, kern->kern / design_size); +} + + +static void +put_integer_prop (string prop_name, unsigned v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s d %u)\n", prop_name, v); +} + + +static void +put_octal_prop (string prop_name, unsigned v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s o %o)\n", prop_name, v); +} + + +static void +put_scaled_prop (string prop_name, real v) +{ + put_real_prop (prop_name, v / design_size); +} + + +static void +put_real_prop (string prop_name, real v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s r %f)\n", prop_name, v); +} + + +static void +put_string_prop (string prop_name, string v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s%s%s)\n", + prop_name, strlen (v) > 0 ? " " : "", v); +} + + +static void +put_indentation () +{ + unsigned this_space; + + for (this_space = 0; this_space < indentation; this_space++) + fprintf (pl_output_file, " "); +} |