[comp.sources.misc] v20i033: hp2pk - HP font conversion tool, Part03/04

steve@txsil.sil.org (Steve McConnel) (06/03/91)

Submitted-by: Steve McConnel <steve@txsil.sil.org>
Posting-number: Volume 20, Issue 33
Archive-name: hp2pk/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 4)."
# Contents:  hp2pk.c writepk.c
# Wrapped by steve@txsil on Thu May 30 10:36:56 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'hp2pk.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hp2pk.c'\"
else
echo shar: Extracting \"'hp2pk.c'\" \(26111 characters\)
sed "s/^X//" >'hp2pk.c' <<'END_OF_FILE'
X/*  HP2PK.C - Convert HP soft font files to TeX PK and TFM (or PL) files
X ***************************************************************************
X *
X *	Sources of information for HP Soft Fonts:
X *
X *		LaserJet Printer Family Technical Reference Manual,
X *		Hewlett-Packard, January 1986.
X *
X *		LaserJet series II Printer Technical Reference Manual,
X *		Hewlett-Packard, May 1987.
X *
X *		LaserJet III Technical Reference Manual, Hewlett-Packard,
X *		March 1990.
X *
X *		HP DeskJet Printer Family Software Developer's Guide,
X *		Hewlett-Packard, August 1990.  (only to interpret values
X *		of some font header fields--font format is much different
X *		in general)
X *
X *	Sources of information for TeX font files:
X *
X *		The METAFONTbook by Donald E. Knuth (appendix F)
X *
X *		PLtoTF.WEB by Donald E. Knuth, Leo Guibas, et al.
X *
X *		GFtoPK.WEB by Tomas Rokicki
X *
X ***************************************************************************
X *	EDIT HISTORY
X *	 4-Oct-90	SRMc - convert Pascal code left here by Jonathan Kew
X *				into C, start debugging and adding comments
X *	 5-Oct-90	SRMc - first successful translation of .SFP file to
X *				.PK and .PL files
X *	 6-Oct-90	SRMc - add more comments, convert to dynamic memory
X *				allocation
X *	 9-Oct-90	SRMc - add direct output of .TFM file in addition
X *				to .PL file
X *	16-Oct-90	SRMc - fiddle with the user interface
X *	19-Oct-90	SRMc - rewrite code for greater modularity and fewer
X *				global variables (allows for future reuse in
X *				other "Font A to Font B" conversion programs)
X *	20-Oct-90	SRMc - move ctime() call from init_pl_file() to main()
X *			SRMc - add -b command line option
X *	22-Oct-90	SRMc - fight MSDOS cross-compiler code generation bugs
X *				(or are they obscure features of the C language
X *				definition? -- some seem to be definite bugs)
X *	14-Jan-91	SRMc - add TURBO C patches from Thomas B. Ridgeway
X *				(ridgeway@blackbox.hacc.washington.edu)
X *	15-Jan-91	SRMc - fix for Macintosh Lightspeed THINK C
X *	17-Jan-91	SRMc - move version information into PATCHLEVEL.H
X *	28-Jan-91	SRMc - add -s option for specifying the width of space,
X *				as suggested by Chris Paris (cap@cs.cmu.edu)
X *	30-Jan-91	SRMc - add -r option for restricting to 7-bit character
X *				codes in the output file (to support antique
X *				DVI drivers), as suggested by Kevin A. Streater
X *				(ba124@uk.ac.city.cs in JANET syntax)
X *	31-Jan-91	SRMc - add -h option for getting help
X ***************************************************************************
X * Copyright 1990, 1991 by the Summer Institute of Linguistics, Inc.
X * All rights reserved.
X */
X/*#define TURBO_C*/		/* uncomment if using MSDOS TURBO C */
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef BSD
X#include <sys/time.h>
Xtypedef long time_t;
Xextern time_t time();
Xextern char *memset(), *memcpy();
Xextern int memcmp();
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#else
X#include <time.h>
X#ifdef TURBO_C
X#include <mem.h>
X#define MSDOS
X#else
X#ifndef THINK_C		/* THINK C includes memxxx() functions in <string.h> */
X#include <memory.h>
X#endif
X#endif
X#include <string.h>
X#endif
X#ifdef THINK_C
X#include <console.h>
X#define signed		/* keyword not recognized by this compiler */
X#define MACINTOSH
X#endif
X
X#include "patchlevel.h"
X#include "sfp.h"
X#include "tfm.h"
X#include "pk.h"
X#include "bitmap.h"
X
X#ifdef MSDOS
X#define DIRSEPCHAR '\\'
X#endif
X#ifdef UNIX
X#define DIRSEPCHAR '/'
X#endif
X#ifdef MACINTOSH
X#define DIRSEPCHAR ':'
X#endif
X
X#define NUL '\0'
X
X/************************************************************************/
X/*			   EXTERN DECLARATIONS				*/
X/************************************************************************/
Xextern void exit();
Xextern long strtol();
Xextern int getopt(), optind;
Xextern char *optarg;
X
X/* from READSFP.C */
Xextern void read_sfp_font_descriptor();
Xextern int read_sfp_character();
X
X/* from WRITEPK.C */
Xextern void init_pk_file(), write_pk_character(), end_pk_file();
X
X/* from WRITEPL.C */
Xextern void init_pl_file(), write_pl_entry(), end_pl_file();
X
X/* from WRITETFM.C */
Xextern void write_tfm_data();
X
X/* from MYALLOC.C */
Xextern char *myalloc(), *myrealloc();
Xextern void myfree();
X
X/* from FIXNUM.C */
Xextern fixnum str_to_fixnum();
X
X/************************************************************************/
X/*			    GLOBAL VARIABLES				*/
X/************************************************************************/
X/*
X *  data from input HP Soft Font (.SFP) file
X */
Xstruct hp_font_descriptor hp_font;	/* font descriptor */
Xstruct hp_character_descriptor hp_char;	/* current character descriptor */
Xstruct character_bitmap bitmap;		/* current character bitmap */
Xchar *symbol_set_string = NULL;		/* hp_font.symbol_set in English */
X/*
X *  data for the PK font file
X */
Xstruct pk_preamble pk_header;		/* font preamble */
Xstruct pk_chardata pk_char;		/* current character descriptor */
X/*
X *  data for the TFM and PL files
X */
Xstruct tfm_top      top_fm;		/* TFM file top information */
Xstruct tfm_header   header_fm;		/* font descriptor */
Xstruct tfm_param    param_fm;		/* font parameters */
Xstruct tfm_chardata char_fm[256];	/* array of character metrics */
X/*
X *  global variables set by the command line options
X */
Xfixnum designsize    = 0L;	/* -d = font design size */
Xfixnum spacewidth    = 0L;	/* -s = width of basic space in font */
Xlong   magnification = 0L;	/* -m = font magnification */
Xint    verbose       = 0;	/* -v = program talkativity flag */
Xint    density       = 0;	/* -d = dots per inch of SFP font */
Xshort restrict_7bit = 0;	/* -r = restrict to 128 chars, lower/upper */
X#ifdef MACINTOSH
Xchar *fileCreator = NULL;	/* -z = Macintosh file type  */
X#endif
Xchar *sfp_filename = NULL;	/* <infile> = input SFP font file's name */
Xchar *pk_filename  = NULL;	/* -p = output PK font file's name */
Xchar *pl_filename  = NULL;	/* -l = output PL font metric file's name */
Xchar *tfm_filename = NULL;	/* -t = output TFM font metric file's name */
X/*
X *  conversion factor for SFP dimensions to TFM dimensions
X *  double precision floating point is occasionally useful...
X */
Xdouble dot_scale;		/* ratio: SFP font dots -> (2**-20) points */
X
X/****************************************************************************
X * NAME
X *    myputs
X * ARGUMENTS
X *    msg - message string
X * DESCRIPTION
X *    Write a string to stdout, inserting linebreaks automatically as needed.
X *    Also, if the verbose flag is zero, don't print anything.
X * RETURN VALUE
X *    none
X */
Xvoid myputs(msg)
Xchar *msg;
X{
Xstatic int screen_col=0; /* screen column (for linewrap of progress report) */
X
Xif (verbose == 0)
X    return;
X
Xif (strcmp(msg,"\n")==0)
X    {
X    fputs(msg,stdout);
X    screen_col = 0;
X    return;
X    }
Xif ((strlen(msg)+screen_col) >= 79)
X    {
X    putchar('\n');
X    screen_col = 0;
X    }
Xfputs(msg,stdout);
Xfflush(stdout);
Xscreen_col += strlen(msg);
X}
X
X/****************************************************************************
X * NAME
X *    change_filetype
X * ARGUMENTS
X *    name - pointer to a filename
X *    type - pointer to replacement filetype (includes '.')
X * DESCRIPTION
X *    Create a new filename based on the old name and new type.
X * RETURN VALUE
X *    pointer to new filename (allocated with malloc())
X */
Xchar *change_filetype(name, type)
Xchar *name;
Xchar *type;
X{
Xchar *p;
Xchar *newname;	/* pointer to dynamically allocated buffer for result */
X
Xnewname = strcpy( myalloc((unsigned)(strlen(name)+strlen(type)+1)), name);
Xp = strchr(newname, DIRSEPCHAR);
Xif (p == (char *)NULL)
X    p = newname;
Xp = strrchr(p, '.');
Xif (p == (char *)NULL)
X    strcat(newname, type);
Xelse
X    strcpy(p, type);
Xreturn(newname);
X}
X
X/****************************************************************************
X * NAME
X *    fix_filename
X * ARGUMENTS
X *    name - filename
X *    type - default filename type extension
X *    mode - mode string for fopen()
X * DESCRIPTION
X *    Fix up a filename based on the name and possibly the type.
X *    Input files may or may not have have a type extension.
X *    Output files must have a filetype.
X * RETURN VALUE
X *    FILE pointer to open file
X */
Xchar *fix_filename(name, type, mode)
Xchar *name;
Xchar *type;
Xchar *mode;
X{
Xchar *p;
XFILE *fp;
X
Xif (*mode == 'r')
X    {
X    fp = fopen(name, mode);
X    if (fp == (FILE *)NULL)
X	{
X	/*
X	 * see if the user was lazy and omitted the filetype
X	 */
X	p = strrchr(name, DIRSEPCHAR);
X	if (p == (char *)NULL)
X	p = name;
X	if (strchr(p, '.') == (char *)NULL)
X	    name = change_filetype(name, type);
X	}
X    else
X	fclose(fp);
X    return( name );
X    }
X/*
X * see if the user was lazy and omitted the filetype
X */
Xp = strrchr(name, DIRSEPCHAR);
Xif (p == (char *)NULL)
Xp = name;
Xif (strchr(p, '.') == (char *)NULL)
X    name = change_filetype(name, type);
Xreturn( name );
X}
X
X/****************************************************************************
X * NAME
X *    sfp_to_tfm_header
X * ARGUMENTS
X *    hpf     - pointer to SFP font descriptor structure
X *    sym_set - font symbol set string
X *    dsize   - font design size (fixed-point, 20-bit fraction)
X *    tp      - pointer to TeX font metric header structure
X * DESCRIPTION
X *    Fill in the TeX font metric header information, using the SFP font
X *    information already known.
X * RETURN VALUE
X *    none
X */
Xvoid sfp_to_tfm_header( hpf, sym_set, dsize, tp )
Xstruct hp_font_descriptor *hpf;
Xchar *sym_set;
Xfixnum dsize;
Xstruct tfm_header *tp;
X{
Xint i;
X
Xtp->tfm_checksum = 0L;
Xtp->tfm_design_size = dsize;
Xi = strlen(sym_set);
Xif (i > 39)
X    i = 39;
Xtp->tfm_coding[0] = i;
Xmemcpy( &tp->tfm_coding[1], sym_set, i );
X/*
X *  find the actual length of the stored font name
X *  if nonzero, store it; otherwise store a default name
X */
Xfor (	i = 15 ;
X	(i >= 0) && isascii(hpf->font_name[i]) && isspace(hpf->font_name[i]) ;
X	--i )
X    ;
Xif (i >= 0)
X    {
X    tp->tfm_fontid[0] = i+1;
X    memcpy( &tp->tfm_fontid[1], hpf->font_name, i+1 );
X    }
Xelse
X    {
X    tp->tfm_fontid[0] = 12;
X    memcpy( &tp->tfm_fontid[1], "HP SOFT FONT", 12 );
X    }
X
Xtp->tfm_7bitsafe = 0;
Xtp->tfm_unused[0] = 0;
Xtp->tfm_unused[1] = 0;
X
Xtp->tfm_face = 0;
Xif (hp_font.width_type < 0)
X    tp->tfm_face += CONDENSED;
Xelse if (hp_font.width_type > 0)
X    tp->tfm_face += EXTENDED;
Xif (hp_font.style == 1)
X    tp->tfm_face += ITALIC;
Xif (hp_font.stroke_weight < -1)
X    tp->tfm_face += LIGHT;
Xelse if (hp_font.stroke_weight > 1)
X    tp->tfm_face += BOLD;
X}
X
X/****************************************************************************
X * NAME
X *    sfp_to_pk
X * ARGUMENTS
X *    cc  - current character code
X *    hpf - pointer to SFP font descriptor structure
X *    hpc - pointer to SFP font character descriptor structure
X *    pkc - pointer to PK font character data structure
X * DESCRIPTION
X *    Compute the TeX character information for this SFP character.
X * RETURN VALUE
X *    none
X */
Xvoid sfp_to_pk(cc, hpf, hpc, pkc)
Xint cc;
Xstruct hp_font_descriptor *hpf;
Xstruct hp_character_descriptor *hpc;
Xstruct pk_chardata *pkc;
X{
Xlong qdot_width;
Xdouble d_wd;
X
Xpkc->char_code = cc;
X/*
X *  some compilers need to have these computations split out this way
X */
Xif (hpf->spacing == 1)
X    qdot_width = hpc->delta_x;
Xelse
X    qdot_width = hpf->pitch;
Xd_wd = ((dot_scale * qdot_width) / 4.0) * TWO_20th;
Xpkc->tfm_width = d_wd;
Xpkc->dx = hpc->delta_x;
Xpkc->dx <<= 16;			/* need separate for 16-bit int systems */
Xpkc->dy = 0L;
Xpkc->pixel_width  = hpc->character_width;
Xpkc->pixel_height = hpc->character_height;
Xpkc->hoff = -hpc->left_offset;
Xpkc->voff = hpc->top_offset;
X}
X
X/****************************************************************************
X * NAME
X *    sfp_to_tfm
X * ARGUMENTS
X *    hpf - pointer to SFP font descriptor structure
X *    hpc - pointer to SFP font character descriptor structure
X *    pkc - pointer to PK character data structure
X *    tfc - pointer to TFM character data structure
X *    tft - pointer to TFM file top information structure
X * DESCRIPTION
X *    Compute the TeX font metric information for this SFP character.
X * RETURN VALUE
X *    none
X */
Xvoid sfp_to_tfm(hpf, hpc, pkc, tfc, tft)
Xstruct hp_font_descriptor *hpf;
Xstruct hp_character_descriptor *hpc;
Xstruct pk_chardata *pkc;
Xstruct tfm_chardata *tfc;
Xstruct tfm_top *tft;
X{
Xlong qdot_width;	/* width of character in quarter-dots */
Xlong x;
Xdouble d_wd, d_ht, d_dp, d_ic;
X
Xif (hpf->spacing == 1)
X    qdot_width = hpc->delta_x;
Xelse
X    qdot_width = hpf->pitch;
X/*
X *  some compilers need to have these computations split out this way
X */
Xd_wd = ((dot_scale * qdot_width) / 4.0) * TWO_20th;
Xd_ht = dot_scale * hpc->top_offset * TWO_20th;
X/*
X *   be extremely careful on conversions involving signed and unsigned short
X *   (this may look paranoid, but some compilers botch the conversions)
X */
Xx = hpc->character_height;
Xx -= hpc->top_offset;
Xif (x > 0L)
X    d_dp = dot_scale * x * TWO_20th;
Xelse
X    d_dp = 0.0;
Xx = hpc->character_width;
Xx *= 4;
Xx -= qdot_width;
Xif (x > 0L)
X    d_ic = dot_scale * (x / 4.0) * TWO_20th;
Xelse
X    d_ic = 0.0;
X
Xtfc->charwd = d_wd;
Xtfc->charht = d_ht;
Xtfc->chardp = d_dp;
Xtfc->charic = d_ic;
X
Xif ((tfc->charic != 0L) && (hpf->style != 1))
X    {
X    myputs(
X	 "Warning:  character in upright font has nonzero italic correction.");
X    myputs("\n");
X    }
X/*
X *  save the smallest and largest character codes encountered
X */
Xif (pkc->char_code < tft->tfm_bc)
X    tft->tfm_bc = pkc->char_code;
Xif (pkc->char_code > tft->tfm_ec)
X    tft->tfm_ec = pkc->char_code;
X}
X
X/****************************************************************************
X * NAME
X *    sfp_to_tfm_param
X * ARGUMENTS
X *    tfp - pointer to TFM font parameter structure
X *    hpf - pointer to SFP font descriptor structure
X *    tfc - pointer to array of TFM character data structures
X *    tft - pointer to TFM file top information structure
X * DESCRIPTION
X *    Compute the TFM font spacing parameter values.
X * RETURN VALUE
X *    none
X */
Xvoid sfp_to_tfm_param(tfp, hpf, tfc, tft)
Xstruct tfm_param *tfp;
Xstruct hp_font_descriptor *hpf;
Xstruct tfm_chardata *tfc;
Xstruct tfm_top *tft;
X{
Xdouble d;
X/*
X *  first, compute the space parameters
X */
Xif (hpf->spacing == 1)
X    {
X    if ((tft->tfm_bc <= ' ')&&(tft->tfm_ec >= ' ')&&(tfc[' '].charwd != 0L))
X	{
X	/*
X	 *  use space character's width for font spacing parameters
X	 */
X	tfp->tfm_space = tfc[' '].charwd;
X	}
X    else if (spacewidth != 0L)
X	{
X	d = spacewidth;
X	d /= designsize;
X	tfp->tfm_space = d * TWO_20th;
X	}
X    else if ((tft->tfm_bc <= 'x')&&(tft->tfm_ec >= 'x')&&(tfc['x'].charwd!=0L))
X	{
X	/*
X	 *  if no space character, use 'x' character's width for spacing
X	 */
X	printf("\
XFont contains no space; using width of x character for font space.\n");
X	tfp->tfm_space = tfc['x'].charwd;
X	}
X    else
X	{
X	/*
X	 *  Neither space nor x was available, so we arbitrarily use
X	 *  values based on the design size.
X	 */
X	printf("\
XFont contains no space or x; using 1/2 design size for font space.\n");
X	tfp->tfm_space = 0x00080000;		/* == 0.5 as fixnum */
X	}
X    tfp->tfm_space_stretch = tfp->tfm_space / 2;
X    tfp->tfm_space_shrink  = tfp->tfm_space / 3;
X    tfp->tfm_extra_space   = tfp->tfm_space / 3;
X    }
Xelse
X    {
X    /*
X     *  mono-space font
X     */
X    d = ((dot_scale * hpf->pitch) / 4.0) * TWO_20th;
X    tfp->tfm_space = d;
X    tfp->tfm_space_stretch = 0L;
X    tfp->tfm_space_shrink = 0L;
X    tfp->tfm_extra_space = tfp->tfm_space;
X    }
X/*
X *  we always set the quad value to twice the basic space value
X */
Xtfp->tfm_quad = tfp->tfm_space * 2;		/* em-space */
X/*
X *  set the x height (used for accent placement)
X */
Xif ((tft->tfm_bc <= 'x') && (tft->tfm_ec >= 'x') && (tfc['x'].charwd != 0L))
X    param_fm.tfm_x_height = tfc['x'].charht + tfc['x'].chardp;
Xelse
X    {
X    printf("Font contains no x; using 1/2 design size for x-height.\n");
X    tfp->tfm_x_height = 0x00080000;		/* == 0.5 as fixnum */
X    }
X}
X
X#ifdef MACINTOSH
X/***************************************************************************
X * NAME
X *    setMacFileType
X * ARGUMENTS
X *    fname   - filename string
X *    type    - file type string (4 chars, allcaps)
X *    creator - file creator string (4 chars, allcaps)
X * DESCRIPTION
X *    For the Macintosh, call the toolbox functions to set the file type and
X *    creator to the desired values.
X * RETURN VALUE
X *    none
X */
Xvoid setMacFileType(fname, type, creator)
Xchar *fname;
Xchar *type;
Xchar *creator;
X{
Xchar filename[256];
Xlong err;
Xlong refnum;
Xstruct FInfo {
X    char fdType[4];
X    char fdCreator[4];
X    long fdFlags;
X    struct { long x; long y; } fdLocation;
X    long fdFldr;
X    } finderInfo;
Xint i;
X
Xstrcpy(filename+1,fname);
Xfilename[0] = strlen(fname);
Xrefnum = 0;
Xerr = GetFInfo( filename, refnum, &finderInfo );
Xfor ( i = 0 ; i < 4 ; ++i )
X    {
X    finderInfo.fdType[i] = ' ';
X    finderInfo.fdCreator[i] = ' ';
X    }
Xfor ( i = 0 ; i < 4 ; ++i )
X    {
X    if (type[i] == NUL)
X	break;
X    finderInfo.fdType[i] = type[i];
X    }
Xfor ( i = 0 ; i < 4 ; ++i )
X    {
X    if (creator[i] == NUL)
X	break;
X    finderInfo.fdCreator[i] = creator[i];
X    }
X#ifdef THINK_C
Xerr = SetFInfo( filename, refnum, &finderInfo );
X#endif
X}
X#endif
X
X/****************************************************************************
X * NAME
X *    main
X * ARGUMENTS
X *    argc - number of command line arguments
X *    argv - pointer to array of command line arguments
X * DESCRIPTION
X *    main procedure for the HP2PK program
X * RETURN VALUE
X *    0 to indicate success
X */
Xint main(argc,argv)
Xint argc;
Xchar **argv;
X{
Xint c;
XFILE *sfp_fp = NULL;	/* SFP input FILE pointer */
XFILE *pk_fp = NULL;	/* PK  output FILE pointer */
XFILE *pl_fp = NULL;	/* PL  output FILE pointer */
XFILE *tfm_fp = NULL;	/* TFM output FILE pointer */
Xdouble d;		/* used in computing design size */
Xint errflag;		/* flag errors in command line parsing */
Xchar buffer[80];	/* scratch buffer for sprintf() output */
Xtime_t job_time;	/* time that this job was run, in seconds */
Xstruct tm *tp;		/* decoded time that this job was run */
Xchar *date;		/* time string for when this job was run */
Xstruct tfm_chardata *cfmp;	/* hack for MSDOS compiler bug */
X
Xfprintf(stderr, "This is HP2PK, Version %d.%d.%d (%s)\n%s\n",
X	VERSION, REVISION, PATCHLEVEL, PATCHDATE, COPYRIGHT );
X
X#ifdef THINK_C		/* this MUST follow the fprintf() for some reason */
X    SetWTitle( FrontWindow(), "\pHP2PK" );
X    argc = ccommand( &argv );
X#endif
X
Xtime( &job_time );
Xtp = localtime( &job_time );
X/*
X *  parse the command line
X */
Xerrflag = 0;
Xwhile ((c = getopt(argc,argv,"b:d:hl:m:p:r:s:t:vz:")) != EOF)
X    {
X    switch (c)
X	{
X	case 'b':			/* pixel density (bits per inch) */
X	    density = (int)strtol(optarg, (char **)NULL, 10);
X	    break;
X	case 'd':			/* design size (in points) */
X	    designsize = str_to_fixnum(optarg);
X	    break;
X	case 's':			/* width of space char (in points) */
X	    spacewidth = str_to_fixnum(optarg);
X	    break;
X	case 'm':			/* magnification * 1000 */
X	    magnification = strtol(optarg, (char **)NULL, 10);
X	    break;
X	case 'r':			/* restrict to lower/upper 128 chars */
X	    if ((*optarg == 'l') || (*optarg == 'u'))
X		restrict_7bit = *optarg;
X	    else
X		{
X		fprintf(stderr,
X		     "The -r option requires either l or u as an argument.\n");
X		++errflag;
X		}
X	    break;
X	case 'p':
X	    pk_filename = optarg;
X	    break;
X	case 'l':
X	    pl_filename = optarg;
X	    break;
X	case 't':
X	    tfm_filename = optarg;
X	    break;
X	case 'v':
X	    verbose = 1;
X	    break;
X	case 'z':
X#ifdef MACINTOSH
X	    fileCreator = optarg;
X	    break;
X#else
X	    fprintf(stderr,"The -z option is valid only for the Macintosh.\n");
X	    /* fall through */
X#endif
X	case 'h':		/* fall through */
X	default:
X	    ++errflag;
X	    break;
X	}
X    }
Xif (errflag || (optind >= argc))
X    {
X    fputs("\
XUsage: hp2pk [options] file.sfp\n\
X    -b density   specify pixel density (dots/inch) of the font\n\
X    -d size      specify the design size (in points) of the font\n\
X    -h           ask for help (this display)\n\
X    -l file.pl   specify the output Property List (PL) file\n\
X    -m mag       specify the magnification (* 1000) of the font\n\
X", stderr); fputs("\
X    -p file.pk   specify the output PacKed font (PK) file\n\
X    -r {l|u}     ask for only lower 128 or only upper 128 characters\n\
X    -s sp_width  specify the width of a space character (in points)\n\
X    -t file.tfm  specify the output TeX Font Metric (TFM) file\n\
X    -v           request verbose progress report output\n\
X", stderr);
X#ifdef MACINTOSH
X    fputs("\
X    -z CREA      set the hidden Macintosh Creator type for output files.\n\
X                 This is usually four letters.\n\
X", stderr);
X#endif
X    fputs("\
Xfile.sfp is the input HP Soft Font/Portrait (SFP) file.\n\
X\n\
XIf not specified, hp2pk creates a PK file with the same base name as the\n\
Xinput file, but with a .pk filename extension.\n\
XIf neither a PL nor a TFM file is specified, hp2pk creates a TFM file with\n\
Xthe same base name as the input file, but with a .tfm filename extension.\n\
X", stderr);
X    fputs("\
XThe default design size is calculated from the font data.\n\
XThe default magnification is 1000.  The default pixel density is 300 dpi.\n\
XIf the font contains a space character, its width is always used.  Otherwise,\n\
Xthe default width of a space is the width of the 'x' character.\n\
X", stderr);
X    exit(1);
X    }
X/*
X *  Open the .SFP file
X */
Xsfp_filename = fix_filename( argv[optind], ".sfp", "rb");
Xsfp_fp = fopen(sfp_filename, "rb");
Xif (sfp_fp == (FILE *)NULL)
X    {
X    fprintf(stderr, "Cannot open HP soft font file %s\n", sfp_filename);
X    exit(1);
X    }
Xread_sfp_font_descriptor(sfp_fp, &hp_font, &symbol_set_string, verbose );
Xif (symbol_set_string == (char *)NULL)
X    symbol_set_string = "UNSPECIFIED";
Xif (magnification == 0L)
X    magnification = 1000L;
Xif (density == 0)
X    density = 300;		/* assume 300 dots per inch */
Xif (designsize == 0L)
X    {
X    /*
X     *  Estimate TeX design size based on font height
X     *  Note:  18.0675 = (72.27 points/inch) / 4 quarter-dots/dot
X     *	       and hp_font.height is measured in quarter-dots
X     */
X    d = ((18.0675 / density) * hp_font.height) * (1000.0 / magnification) *
X								     TWO_20th;
X    designsize = d;
X    printf("Estimated font design size is %.2f pt.\n", d/TWO_20th );
X    }
X/*
X *  dot_scale is used to translate dots (pixels) to (2**-20) points
X */
Xdot_scale = (72.27 / density) * (1000.0 / magnification) *
X						(TWO_20th / designsize);
Xsfp_to_tfm_header( &hp_font, symbol_set_string, designsize, &header_fm );
Xtop_fm.tfm_bc = 256;	/* larger than any possible value */
Xtop_fm.tfm_ec = -1;	/* smaller than any possible value */
X/*
X *  Open the new .PK file
X */
Xif (pk_filename == (char *)NULL)
X    pk_filename = change_filetype(sfp_filename, ".pk");
Xpk_filename = fix_filename( pk_filename, ".pk", "wb");
Xpk_fp = fopen(pk_filename, "wb");
Xif (pk_fp == (FILE *)NULL)
X    {
X    fprintf(stderr, "Cannot open output PK font file %s\n", pk_filename );
X    exit(1);
X    }
X/*
X *  if wanted, open the new .PL file
X */
Xif (pl_filename != (char *)NULL)
X    {
X    pl_filename = fix_filename(pl_filename, ".pl", "w");
X    pl_fp = fopen(pl_filename, "w");
X    if (pl_fp == (FILE *)NULL)
X	{
X	fprintf(stderr, "Cannot open output PL font metric file %s\n",
X							pl_filename );
X	exit(1);
X	}
X    }
Xelse
X    pl_fp = (FILE *)NULL;		/* signals that we don't output PL */
X/*
X *  if wanted, open the new .TFM file
X */
Xif ((tfm_filename == (char *)NULL) && (pl_filename == (char *)NULL))
X    tfm_filename = change_filetype(sfp_filename, ".tfm");
Xif (tfm_filename != (char *)NULL)
X    {
X    tfm_filename = fix_filename(tfm_filename, ".tfm", "wb");
X    tfm_fp = fopen(tfm_filename, "wb");
X    if (tfm_fp == (FILE *)NULL)
X	{
X	fprintf(stderr, "Cannot open output TFM font metric file %s\n",
X							tfm_filename );
X	exit(1);
X	}
X    }
Xsprintf(buffer, "HP2PK %d.%d.%d (%s) output  %4d.%02d.%02d  %2d:%02d:%02d",
X	VERSION, REVISION, PATCHLEVEL, PATCHDATE,
X	tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday,
X	tp->tm_hour, tp->tm_min, tp->tm_sec );
Xinit_pk_file(pk_fp, buffer, designsize, density, &pk_header);
Xif (pl_fp != (FILE *)NULL)
X    {
X    date = ctime(&job_time);
X    date[24] = '\0';
X    init_pl_file(pl_fp, "HP2PK", date, &header_fm );
X    }
X/*
X *  Process the sfp file to produce the pk file and the pl file
X */
Xfor (;;)
X    {
X    /*
X     *  process the data for one character
X     */
X    c = read_sfp_character(sfp_fp, &hp_font, &hp_char, &bitmap );
X    if (c == -1)
X	{
X	if (!feof(sfp_fp))
X	    puts("\nIgnoring junk at the end of the Soft Font/Portrait file.");
X	break;
X	}
X    if (    ((restrict_7bit == 'l') && (c >= 128)) ||
X	    ((restrict_7bit == 'u') && (c <  128)) )
X	continue;
X
X    sprintf(buffer, " [%d]", c);
X    myputs(buffer);		/* print the character code on the screen */
X
X    if ((restrict_7bit == 'u') && (c >= 128))
X	c -= 128;		/* fix character code for 7-bit output file */
X
X    sfp_to_pk(c, &hp_font, &hp_char, &pk_char);
X    write_pk_character(pk_fp, &pk_char, &bitmap);
X
X    cfmp = &char_fm[c];	/* need this to get around MSDOS compiler bug */
X    sfp_to_tfm(&hp_font, &hp_char, &pk_char, cfmp, &top_fm);
X    if (pl_fp != (FILE *)NULL)
X	write_pl_entry(pl_fp, c, cfmp);
X    }
Xend_pk_file(pk_fp);
Xif (verbose)
X    {
X    putchar('\n');
X    printf( "%6ld bytes read from HP soft font file.\n", ftell(sfp_fp) );
X    printf( "%6ld bytes written to packed font file.\n", ftell(pk_fp) );
X    }
Xfclose(sfp_fp);
Xfclose(pk_fp);
X#ifdef MACINTOSH	/* set Macintosh file type for PK file */
Xif (fileCreator != (char *)NULL)
X    setMacFileType(pk_filename, "BINA", fileCreator );
X#endif
Xsfp_to_tfm_param(&param_fm, &hp_font, char_fm, &top_fm );
Xif (pl_fp != (FILE *)NULL)
X    {
X    end_pl_file(pl_fp, &param_fm);
X    fclose(pl_fp);
X#ifdef MACINTOSH	/* set Macintosh file type for PL file */
X    if (fileCreator != (char *)NULL)
X	setMacFileType(pl_filename, "TEXT", fileCreator );
X#endif
X    }
X/*
X *  if wanted, write the .TFM file
X */
Xif (tfm_fp != (FILE *)NULL)
X    {
X    write_tfm_data(tfm_fp,&top_fm,&header_fm, char_fm,&param_fm, designsize);
X    fclose(tfm_fp);
X#ifdef MACINTOSH	/* set Macintosh file type for TFM file */
X    if (fileCreator != (char *)NULL)
X	setMacFileType(tfm_filename, "BINA", fileCreator );
X#endif
X    }
X
Xreturn(0);		/* successful execution */
X}
END_OF_FILE
if test 26111 -ne `wc -c <'hp2pk.c'`; then
    echo shar: \"'hp2pk.c'\" unpacked with wrong size!
fi
# end of 'hp2pk.c'
fi
if test -f 'writepk.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'writepk.c'\"
else
echo shar: Extracting \"'writepk.c'\" \(19349 characters\)
sed "s/^X//" >'writepk.c' <<'END_OF_FILE'
X/*  WRITEPK.C - Write data to a TeX PK font file
X ***************************************************************************
X *
X *	void init_pk_file(fp, comment, dsize, density, pkp)
X *	FILE *fp;
X *	char *comment;
X *	fixnum dsize;
X *	int density;
X *	struct pk_preamble *pkp;
X *
X *	void write_pk_character(fp, pkc, bmp)
X *	FILE *fp;
X *	struct pk_chardata *pkc;
X *	struct character_bitmap *bmp;
X *
X *	void end_pk_file(fp)
X *	FILE *fp;
X *
X ***************************************************************************
X *
X *	Source of information for TeX PK font files:
X *
X *		GFtoPK.WEB by Tomas Rokicki
X *
X ***************************************************************************
X *	EDIT HISTORY
X *	19-Oct-90	SRMc - split out from HP2PK.C to improve modularity
X *	14-Jan-91	SRMc - add TURBO C patches from Thomas B. Ridgeway
X *				(ridgeway@blackbox.hacc.washington.edu)
X ***************************************************************************
X * Copyright 1990, 1991 by the Summer Institute of Linguistics, Inc.
X * All rights reserved.
X */
X/*#define TURBO_C*/		/* uncomment if using MSDOS TURBO C */
X#include <stdio.h>
X#ifdef BSD
Xextern int memcmp();
Xextern char *memset(), *memcpy();
X#include <strings.h>
X#else
X#ifdef TURBO_C
X#include <mem.h>
X#define MSDOS
X#else
X#ifndef THINK_C		/* THINK C includes memxxx() functions in <string.h> */
X#include <memory.h>
X#endif
X#endif
X#include <string.h>
X#endif
X#include "pk.h"
X#include "bitmap.h"
X
X#define END_OF_BITMAP	2	/* used in write_pk_character() */
X
X/************************************************************************/
X/*			   EXTERN DECLARATIONS				*/
X/************************************************************************/
X
Xextern void exit();
X
X/* from MYALLOC.C */
Xextern char *myalloc(), *myrealloc();
Xextern void myfree();
X
X/* from BIGENDIO.C */
Xextern void put_halfword(), put_3_bytes(), put_fullword();
X
X/************************************************************************/
X/*			STATIC GLOBAL VARIABLES				*/
X/************************************************************************/
X/*
X *  powers of two (used in various computations)
X */
Xstatic unsigned long power[32] = {
X    0x00000001L, 0x00000002L, 0x00000004L, 0x00000008L,
X    0x00000010L, 0x00000020L, 0x00000040L, 0x00000080L,
X    0x00000100L, 0x00000200L, 0x00000400L, 0x00000800L,
X    0x00001000L, 0x00002000L, 0x00004000L, 0x00008000L, 
X    0x00010000L, 0x00020000L, 0x00040000L, 0x00080000L,
X    0x00100000L, 0x00200000L, 0x00400000L, 0x00800000L,
X    0x01000000L, 0x02000000L, 0x04000000L, 0x08000000L,
X    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L
X    };
X/*
X *  globals for pk_nyb() output
X */
Xstatic short bit_weight;		/* either 1 or 16 */
Xstatic unsigned char output_byte;	/* current stored value */
X
X/****************************************************************************
X * NAME
X *    init_pk_file
X * ARGUMENTS
X *    fp      - output PK FILE pointer
X *    comment - comment string for PK file
X *    dsize   - font design size (fixed-point, 20-bit fraction)
X *    density - dots per inch of the font bitmap
X *    pkp     - pointer to PK file preamble structure
X * DESCRIPTION
X *    Fill in and write the header information for a .PK file.
X * RETURN VALUE
X *    none
X */
Xvoid init_pk_file(fp, comment, dsize, density, pkp)
XFILE *fp;
Xchar *comment;
Xfixnum dsize;
Xint density;
Xstruct pk_preamble *pkp;
X{
Xint i;
Xdouble d;
X/*
X *  fill in the preamble
X */
Xpkp->preamble     = PK_PRE;
Xpkp->ident        = PK_ID;
Xpkp->comment_size = strlen(comment);
Xmemcpy( pkp->comment, comment, pkp->comment_size );
Xpkp->designsize   = dsize;
Xpkp->checksum     = 0L;
Xd = (density / 72.27) * 65536.0;
Xpkp->hppp         = d;
Xpkp->vppp         = pkp->hppp;		/* assumes square pixels */
X/*
X *  write the preamble
X */
Xputc(pkp->preamble, fp);
Xputc(pkp->ident,    fp);
Xputc(pkp->comment_size, fp);
Xfor ( i = 0 ; i < pkp->comment_size ; ++i )	/* one byte at a time */
X    putc( pkp->comment[i], fp);		 /* ensures proper byte order */
Xput_fullword(pkp->designsize, fp);
Xput_fullword(pkp->checksum,   fp);
Xput_fullword(pkp->hppp, fp);
Xput_fullword(pkp->vppp, fp);
X}
X
X/****************************************************************************
X * MACRO NAME
X *    ADD_BIT_COUNT
X * ARGUMENTS
X *    x - value to store in the bit_counts array
X * DESCRIPTION
X *    Add a value to the bit_counts array, increasing the array size if
X *    necessary.
X */
X#define ADD_BIT_COUNT(x) \
Xif (current_bit_count == last_bit_count)\
X    { \
X    bit_counts = (int *)myrealloc((char *)bit_counts,\
X	(unsigned)((max_bit_counts_size+(pkc->pixel_height)) * sizeof(int)));\
X    current_bit_count = &bit_counts[max_bit_counts_size];\
X    max_bit_counts_size += (pkc->pixel_height);\
X    last_bit_count = &bit_counts[max_bit_counts_size];\
X    } \
X*current_bit_count++ = (x)
X
X/****************************************************************************
X * NAME
X *    static pk_nyb
X * ARGUMENTS
X *    a  - 4-bit "nybble" for output
X *    fp - output PK FILE pointer
X * DESCRIPTION
X *    Write a 4-bit "nybble" to the PK file, storing intermediate values in
X *    output_byte and using bit_weight as a flag.
X * RETURN VALUE
X *    none
X */
Xstatic void pk_nyb(a,fp)
Xunsigned char a;
XFILE *fp;
X{
Xif (bit_weight == 16)
X    {
X    output_byte = (a << 4) & 0xF0;
X    bit_weight = 1;
X    }
Xelse
X    {
X    putc( (output_byte + (a & 0xF)) & 0xFF, fp);;
X    bit_weight = 16;
X    }
X}
X
X/****************************************************************************
X * NAME
X *    write_pk_character
X * ARGUMENTS
X *    fp  - output PK FILE pointer
X *    pkc - pointer to PK character data structure
X *    bmp - pointer to character bitmap data
X * DESCRIPTION
X *    Write one character's info to the PK file.
X *    This function converts a raw bitmap into the dense format used by PK
X *    files.  (algorithms courtesy of PXtoPK and GFtoPK)
X * RETURN VALUE
X *    none
X */
Xvoid write_pk_character(fp, pkc, bmp)
XFILE *fp;
Xstruct pk_chardata *pkc;
Xstruct character_bitmap *bmp;
X{
X/* (this is largely translated borrowed code from GFtoPK, which is why
X *  there aren't too many comments at times */
Xlong best_packet_length;
Xint i, j, k;
Xint count;
Xint bit, oldbit;
Xlong  curr_word = 0L;
Xint bit_ptr;
Xint bit_mod_32 = 0;
Xlong *prast;
Xlong *end_raster;
Xint dyn_f;
Xlong deriv[13+1];		/* array[1..13] of integer */
Xint first_on;
Xint state;
Xint on;
Xint h_bit;
Xint p_bit;
Xint r_on, s_on;
Xint r_count, s_count;
Xint max_2;
Xlong  pred_pk_loc;
Xint buff;
X
Xstatic long *zero_row = NULL;
Xstatic long *ones_row = NULL;
Xstatic int max_row_size = 0;
X
Xstatic int *row_repeats = NULL;
Xstatic int max_column_size = 0;
Xint *cur_repeat;
Xint repeat_flag;
X
Xstatic int *bit_counts = NULL;
Xstatic int max_bit_counts_size = 0;
Xint *current_bit_count, *first_bit_count, *last_bit_count;
Xint *r_bit_count, *s_bit_count;
X/*
X *  set up an all-zeros row and an all-ones row
X */
Xif (bmp->raster_width > max_row_size)
X    {
X    max_row_size = bmp->raster_width;
X    if (zero_row)
X	myfree(zero_row);
X    zero_row = (long *)myalloc( (unsigned)(4 * max_row_size) );
X    memset( zero_row, 0x00, 4 * max_row_size );
X    if (ones_row)
X	myfree(ones_row);
X    ones_row = (long *)myalloc( (unsigned)(4 * max_row_size) );
X    }
Xmemset( ones_row, 0xFF, 4 * bmp->raster_width );
Xi = pkc->pixel_width % 32;
Xif (i == 1)
X    ones_row[bmp->raster_width - 1] = power[31];	/* MAXLONGINT */
Xelse if (i > 1)
X    ones_row[bmp->raster_width - 1] = -power[32-i];
X/*
X *  set markers for runs of identical rows of bits
X */
Xif (((pkc->pixel_height)+1) > max_column_size)
X    {
X    if (row_repeats)
X	myfree(row_repeats);
X    max_column_size = (pkc->pixel_height) + 1;
X    row_repeats = (int *)myalloc( (unsigned)(max_column_size * sizeof(int)) );
X    }
Xfor (	prast = bmp->raster, i = 0 ;
X	i < (pkc->pixel_height)-1 ;
X	++i, prast += bmp->raster_width )
X    {
X    if (memcmp( prast, zero_row, bmp->raster_width * 4) == 0)
X	row_repeats[i] = 0;		/* skip all-zero rows */
X    else if (memcmp( prast, ones_row, bmp->raster_width * 4) == 0)
X	row_repeats[i] = 0;		/* skip all-one rows */
X    else if (memcmp(prast, prast+bmp->raster_width, bmp->raster_width * 4)==0)
X	row_repeats[i] = 1;		/* mark this equal to next row */
X    else
X	row_repeats[i] = 0;		/* not equal to next row... */
X    }
Xrow_repeats[(pkc->pixel_height)-1] = 0;	/* last row can't equal "next" */
X/*
X *  convert boolean markers of repeated rows into repeat counts
X */
Xfor ( i = 0 ; i < (pkc->pixel_height) ; i = k + 1 )
X    {
X    k = i;
X    while ((row_repeats[k] == 1) && (k < (pkc->pixel_height)))
X	++k;
X    row_repeats[i] = k - i;
X    }
Xrow_repeats[(pkc->pixel_height)] = 0;		/* to simplify bookkeepping */
X/*
X *  create the bit counts for each row
X */
Xif (((pkc->pixel_height) * 5) > max_bit_counts_size)
X    {
X    if (bit_counts)
X	myfree(bit_counts);
X    max_bit_counts_size = (pkc->pixel_height) * 5;
X    bit_counts = (int *)myalloc((unsigned)(max_bit_counts_size * sizeof(int)));
X    }
Xlast_bit_count = &bit_counts[max_bit_counts_size];
Xprast = bmp->raster;
Xcur_repeat = row_repeats;
Xcurrent_bit_count = bit_counts;
Xrepeat_flag = 0;
Xend_raster = &(bmp->raster[(pkc->pixel_height) * bmp->raster_width]);
Xcount = 0;
Xfor ( bit_ptr = pkc->pixel_width, oldbit = 0 ; oldbit != END_OF_BITMAP ; ++bit_ptr )
X    {
X    if (bit_ptr == pkc->pixel_width)
X	{
X	/*
X	 *  time to try the next row of this bitmap
X	 */
X	if (*cur_repeat > 0)
X	    {
X	    /*
X	     *  skip over rows that are repeated
X	     */
X	    repeat_flag = *cur_repeat;
X	    cur_repeat += repeat_flag;
X	    prast += bmp->raster_width * repeat_flag;
X	    }
X	++cur_repeat;
X	bit_mod_32 = 0;
X	bit_ptr = 0;
X	}
X    --bit_mod_32;
X    if (bit_mod_32 == -1)
X	{
X	/*
X	 *  time to get the next longword of this row
X	 */
X	bit_mod_32 = 31;
X	curr_word = *prast++;
X	}
X    if (prast > end_raster)
X	bit = END_OF_BITMAP;		/* at end of character bitmap */
X    else if (curr_word & power[bit_mod_32])
X	{
X	bit = 1;
X	curr_word ^= power[bit_mod_32];
X	}
X    else
X	bit = 0;
X    if (bit == oldbit)
X	++count;
X    else
X	{
X	ADD_BIT_COUNT( count );
X	count = 1;
X	oldbit = bit;
X	if (repeat_flag > 0)
X	    {
X	    ADD_BIT_COUNT( -repeat_flag );
X	    repeat_flag = 0;
X	    }
X	}
X    }
XADD_BIT_COUNT( 0 );
XADD_BIT_COUNT( 0 );
X/*
X *  Quoting from GFTOPK.WEB, from which the following code was adapted:
X *
X *	Here is another piece of rather intricate code.  Here we determine the
X *	smallest size in which we can pack the data, calculating |dyn_f| in
X *	the process.  To do this, we calculate the size required if |dyn_f| is
X *	0, and put this in |pkc->packet_length|.  Then, we calculate the changes in the
X *	size for each increment of |dyn_f|, and stick these values in the
X *	|deriv| array.  Finally, we scan through this array, and find the
X *	final minimum value, which we then use to send the character data.
X */
Xfor ( i = 0 ; i <= 13 ; ++i )
X    deriv[i] = 0;
Xfirst_on = (bit_counts[0] == 0);
Xif (first_on)
X    first_bit_count = &bit_counts[1];
Xelse
X    first_bit_count = &bit_counts[0];
Xpkc->packet_length = 0L;
Xfor (	current_bit_count = first_bit_count ; *current_bit_count != 0 ; )
X    {
X    /*  Quoting again from GFTOPK.WEB, except for changes in variable names:
X     *
X     *		When we enter this module, we have a count, at
X     *		|*current_bit_count|.  First, we add to the |pkc->packet_length| the
X     *		number of nybbles that this count would require, assuming
X     *		|dyn_f| to be zero.  Since when |dyn_f| is zero, there are no
X     *		one nybble counts, we simply check the two-nybble counts, and
X     *		then the extensible counts.
X     *
X     *		Next, we take the count value and determine the value of
X     *		|dyn_f| (if any) that would cause this count to take either
X     *		more or less nybbles.  If a valid value for |dyn_f| exists in
X     *		this range, we accumulate this change in the |deriv| array.
X     *
X     *		We know that a repeat count of one will not change the length
X     *		of the raster representation, no matter what |dyn_f| is,
X     *		because it is always represented by the nybble 15, so we do
X     *		that as a special case.
X     */
X    j = *current_bit_count++;
X    if (j == -1)
X	++pkc->packet_length;			/* we have a row repeat count of 1 */
X    else
X	{
X	if (j < 0)
X	    {
X	    ++pkc->packet_length;
X	    j = -j;			/* get positive row count */
X	    }
X	if (j < 209)			/* 208 = 13 * 16 (13 is max dyn_f) */
X	    pkc->packet_length += 2;
X	else
X	    {
X	    k = j - 193;		/* 192 = 12 * 16 */
X	    while (k >= 16)
X		{
X		k = k / 16;
X		pkc->packet_length += 2;
X		}
X	    ++pkc->packet_length;
X            }
X	if (j < 14)
X	    --deriv[j];
X	else if (j < 209)
X	    ++deriv[(223-j)/15];
X	else
X	    {
X	    k = 16;
X	    while ((k * 16) < (j + 3))
X		k = k * 16;
X	    if ((j - k) <= 192)
X		deriv[(207-j+k)/15] += 2;
X	    }
X	}
X    }
X/*
X *  set best_packet_length to the best size for the given value of dyn_f
X */
Xbest_packet_length = pkc->packet_length;
Xdyn_f = 0;
Xfor ( i = 1 ; i <= 13 ; ++i )
X    {
X    pkc->packet_length += deriv[i];
X    if (pkc->packet_length <= best_packet_length)
X	{
X	best_packet_length = pkc->packet_length;
X	dyn_f = i;
X	}
X    }
Xpkc->packet_length = (best_packet_length + 1) / 2;	/* convert from nybble to byte size */
Xif (	(pkc->packet_length > (((pkc->pixel_height) * pkc->pixel_width + 7) / 8)) ||
X	(((pkc->pixel_height) * pkc->pixel_width) == 0) )
X    {
X    /*
X     *  raw bitmap is the best we can do -- no compression possible
X     */
X    pkc->packet_length = ((pkc->pixel_height) * pkc->pixel_width + 7) / 8;
X    dyn_f = 14;
X    }
X/*
X * write character preamble
X */
Xpkc->flag_byte = dyn_f << 4;
Xif (first_on)
X    pkc->flag_byte |= 0x08;
Xif (	(pkc->tfm_width > 0xFFFFFFL) || (pkc->tfm_width < 0L)          ||
X	(pkc->dx < 0L)               || (pkc->packet_length > 196579L) ||
X	(pkc->pixel_width > 0xFFFFL) || (pkc->pixel_height > 0xFFFFL)  ||
X	(pkc->hoff > 32767L)         || (pkc->hoff < -32768L)          ||
X	(pkc->voff > 32767L)         || (pkc->voff < -32768L) )
X    {
X    pkc->packet_length += 28L;
X    pkc->flag_byte |= 0x07;
X    /*
X     * write long character preamble
X     */
X    putc(pkc->flag_byte & 0xFF, fp);
X    put_fullword(pkc->packet_length, fp);
X    put_fullword(pkc->char_code, fp);
X    pred_pk_loc = ftell(fp) + pkc->packet_length;
X    put_fullword(pkc->tfm_width, fp);
X    put_fullword(pkc->dx, fp);
X    put_fullword(pkc->dy, fp);
X    put_fullword((long)pkc->pixel_width, fp);
X    put_fullword((long)(pkc->pixel_height), fp);
X    put_fullword(pkc->hoff, fp);
X    put_fullword(pkc->voff, fp);
X    }
Xelse if ((pkc->dx > 0xFF0000L)    || (pkc->packet_length > 1016) ||
X	 (pkc->pixel_width > 255) || (pkc->pixel_height > 255)   ||
X	 (pkc->hoff > 127)        || (pkc->hoff < -128)          ||
X	 (pkc->voff > 127)        || (pkc->voff < -128) )
X    {
X    pkc->packet_length += 13L;
X    pkc->flag_byte |= (pkc->packet_length >> 16) | 4;
X    /*
X     *  write two-byte short character preamble
X     */
X    putc(pkc->flag_byte & 0xFF, fp);
X    put_halfword((unsigned short)(pkc->packet_length & 0xFFFF), fp);
X    putc((unsigned short)pkc->char_code & 0xFF, fp);
X    pred_pk_loc = ftell(fp) + pkc->packet_length;
X    put_3_bytes(pkc->tfm_width, fp);
X    put_halfword((unsigned short)(pkc->dx >> 16), fp);
X    put_halfword((unsigned short)pkc->pixel_width, fp);
X    put_halfword((unsigned short)(pkc->pixel_height), fp);
X    put_halfword((unsigned short)pkc->hoff, fp);
X    put_halfword((unsigned short)pkc->voff, fp);
X    }
Xelse
X    {
X    pkc->packet_length += 8L;
X    pkc->flag_byte |= pkc->packet_length >> 8;
X    /*
X     * write one-byte short character preamble
X     */
X    putc(pkc->flag_byte & 0xFF, fp);
X    putc((unsigned char)(pkc->packet_length & 0xFF), fp);
X    putc((unsigned char)pkc->char_code & 0xFF, fp);
X    pred_pk_loc = ftell(fp) + pkc->packet_length;
X    put_3_bytes(pkc->tfm_width, fp);
X    putc((unsigned char)(pkc->dx >> 16) & 0xFF, fp);
X    putc((unsigned char)pkc->pixel_width & 0xFF, fp);
X    putc((unsigned char)(pkc->pixel_height) & 0xFF, fp);
X    putc((unsigned char)pkc->hoff & 0xFF, fp);
X    putc((unsigned char)pkc->voff & 0xFF, fp);
X    }
Xif (dyn_f != 14)
X    {
X    /*
X     * send compressed format
X     */
X    bit_weight = 16;
X    max_2 = 208 - 15 * dyn_f;		/* set max value for two nybbles */
X    current_bit_count = first_bit_count;
X    while (*current_bit_count != 0)
X	{
X	j = *current_bit_count++;
X	if (j == -1)
X	    pk_nyb(15,fp);		/* send special row repeat count = 1 */
X	else 
X	    {
X	    if (j < 0)
X		{
X		pk_nyb(14,fp);		/* send row repeat flag */
X		j = -j;			/* convert to positive count */
X                }
X	    if (j <= dyn_f)
X		pk_nyb(j,fp);		/* small, one-nybble value */
X	    else if (j <= max_2)
X		{			/* two-nybble value */
X		j = j - dyn_f - 1;
X		pk_nyb(j / 16 + dyn_f + 1, fp);
X		pk_nyb(j % 16, fp);
X		}
X	    else
X		{			/* multi-nybble value */
X		j = j - max_2 + 15;
X		k = 16;
X		while (k <= j)
X		    {
X		    k = k * 16;
X		    pk_nyb(0,fp);
X		    }
X		while (k > 1)
X		    {
X		    k = k / 16;
X		    pk_nyb(j / k, fp);
X		    j = j % k;
X		    }
X		}
X	    }
X	}
X    if (bit_weight != 16)
X	putc(output_byte & 0xFF, fp);	/* pad to byte boundary */
X    }
Xelse
X    {
X    /*
X     *  send raw bit map
X     */
X    buff = 0;
X    p_bit = 8;
X    current_bit_count = first_bit_count;
X    r_bit_count = s_bit_count = bit_counts;
X    h_bit = pkc->pixel_width;
X    on = !first_on;
X    state = r_on = s_on = 0;
X    count = r_count = s_count = 0;
X    repeat_flag = 0;
X    while ((*current_bit_count != 0) || state || (count > 0))
X	{
X	if (state)
X	    {
X	    count = r_count;
X	    current_bit_count = r_bit_count;
X	    on = r_on;
X	    --repeat_flag;
X	    }
X	else
X	    {
X	    r_count = count;
X	    r_bit_count = current_bit_count;
X	    r_on = on;
X	    }
X	/*
X	 * send one row by bits
X	 */
X	do  {
X	    if (count == 0)
X		{
X		if (*current_bit_count < 0)
X		    {
X		    if (!state)
X			repeat_flag = -(*current_bit_count);
X		    ++current_bit_count;
X		    }
X		count = *current_bit_count++;
X		on = !on;
X		}
X	    if ((count >= p_bit) && (p_bit < h_bit))
X		{
X		if (on)
X		    buff = buff + power[p_bit] - 1;
X		putc(buff & 0xFF, fp);
X		buff = 0;
X		h_bit = h_bit - p_bit;
X		count = count - p_bit;
X		p_bit = 8;
X                }
X	    else if ((count < p_bit) && (count < h_bit))
X		{
X		if (on)
X		    buff = buff + power[p_bit] - power[p_bit-count];
X		p_bit = p_bit - count;
X		h_bit = h_bit - count;
X		count = 0;
X                }
X	    else
X		{
X		if (on)
X		    buff = buff + power[p_bit] - power[p_bit-h_bit];
X		count = count - h_bit;
X		p_bit = p_bit - h_bit;
X		h_bit = pkc->pixel_width;
X		if (p_bit == 0)
X		    {
X		    putc(buff & 0xFF, fp);
X		    buff = 0;
X		    p_bit = 8;
X		    }
X		}
X	    } while (h_bit != pkc->pixel_width);
X	if (state && (repeat_flag == 0))
X	    {
X	    count = s_count;
X	    current_bit_count = s_bit_count;
X	    on = s_on;
X	    state = 0;
X	    }
X	else if (!state && (repeat_flag > 0))
X	    {
X	    s_count = count;
X	    s_bit_count = current_bit_count;
X	    s_on = on;
X	    state = 1;
X	    }
X	}
X    if (p_bit != 8)
X	putc(buff & 0xFF, fp);
X    }
Xif (pred_pk_loc != ftell(fp))
X    {
X    fflush(stdout);
X    fprintf(stderr, "\nERROR: Bad predicted character length.\n");
X    exit(1);
X    }
X}
X
X/****************************************************************************
X * NAME
X *    end_pk_file
X * ARGUMENTS
X *    fp - output PK FILE pointer
X * DESCRIPTION
X *    Write the postamble for the .PK file.
X * RETURN VALUE
X *    none
X */
Xvoid end_pk_file(fp)
XFILE *fp;
X{
Xputc(PK_POST & 0xFF, fp);
Xwhile (ftell(fp) % 4 != 0)
X    putc(PK_NO_OP & 0xFF, fp);
X}
END_OF_FILE
if test 19349 -ne `wc -c <'writepk.c'`; then
    echo shar: \"'writepk.c'\" unpacked with wrong size!
fi
# end of 'writepk.c'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.