summaryrefslogtreecommitdiff
path: root/tfm/tfm_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'tfm/tfm_output.c')
-rw-r--r--tfm/tfm_output.c371
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, " ");
+}