#ifndef lint
static char *rcs = "$Header: tfm2ofont.c,v 1.1 88/01/15 13:05:54 simpson Rel $";
#endif
/*
$Log:	tfm2ofont.c,v $
 * Revision 1.1  88/01/15  13:05:54  simpson
 * initial release
 * 
 * Revision 0.1  87/12/11  18:31:26  simpson
 * beta test
 * 
*/
#include <stdio.h>
#include <ctype.h>
#include <local/standard.h>
#include "constants.h"

extern char	RegularOrder[], SpecialOrder[]; /* Order we want to output */

char OutputFile[81];
char TfmName[81];	/* Only used in error routine */
char *WhoAmI;		/* Argv[0] */
char *Usage = "Usage: %s [-s] file...\n";
Boolean Special = FALSE;	/* Designates whether font is special */
int  ExitStatus = SUCCEED;

main(argc, argv)
int	argc;
char	*argv[];
{
    extern int	optind;
    extern char	*optarg;
    int		c;
    FILE	*infile, *outfile;
    void	seteoffunction(), tfmeofsoexit(), convert();
    char	*strcpy(), *strcat(), *strncat();

    WhoAmI = argv[0];
    while ((c = getopt(argc, argv, "s")) != EOF)
        switch (c) {
	case 's':
	    Special = TRUE;
	    break;
	case '?':
	    fprintf(stderr, Usage, WhoAmI);
	    exit(FAIL);
	}
    seteoffunction(tfmeofsoexit);
    for (; optind < argc; optind++) {
	if (strlen(argv[optind]) < 5 || !EQ(".tfm", &argv[optind][strlen(
	argv[optind])-4])) {
	    fprintf(stderr, "%s: invalid input file name %s\n", WhoAmI,
	    argv[optind]);
	    ExitStatus = FAIL;
	    continue;
	}
	if (!(infile = fopen(argv[optind], "r"))) {
	    fprintf(stderr, "%s: cannot open input file %s\n", WhoAmI, 
	    argv[optind]);
	    ExitStatus = FAIL;
	    continue;
	}
	(void)strcpy(TfmName, argv[optind]);
	(void)strcpy(OutputFile, "ft");
	(void)strncat(OutputFile, argv[optind], strlen(argv[optind])-4);
	(void)strcat(OutputFile, ".c");
	if (!(outfile = fopen(OutputFile, "w"))) {
	    fprintf(stderr, "%s: cannot open output file %s\n", WhoAmI,
	    OutputFile);
	    ExitStatus = FAIL;
	    continue;
	}
	convert(infile, outfile, argv[optind]);
	(void)fclose(infile), (void)fclose(outfile);
    }
    exit(ExitStatus);
}

/* The main routine which converts a tfm file to an otroff width table file.
 */
void convert(infile, outfile, inname)
FILE *infile, *outfile;
char *inname;
{
    long	aheight, i, j, widthindex, heightanddepth, zero, height,
    		depth, charpos;
    long	widths[256][2]; /* Width of char in FIX/designsize & kern */
    unsigned long uinteger(), lh, bc, ec, nw, nh, designsize;
    long	integer(), getaheight();

    fprintf(outfile, "char font[256-32] = {\n");
    if ((aheight = getaheight(infile)) == MAX_INTEGER) {
	fprintf(stderr, "%s: no letter 'a' in file %s\n", WhoAmI, inname);
	fprintf(stderr, "\tsetting height to zero\n");
	aheight = 0;
    }
    rewind(infile);
    bzero((char *)widths, sizeof(widths));
    (void)uinteger(infile, 2);	/* lf */
    lh = uinteger(infile, 2);
    bc = uinteger(infile, 2);
    ec = uinteger(infile, 2);
    nw = uinteger(infile, 2);
    nh = uinteger(infile, 2);
    (void)uinteger(infile, 2);  /* nd */
    (void)uinteger(infile, 2);	/* ni */
    (void)uinteger(infile, 2);	/* nl */
    (void)uinteger(infile, 2);	/* nk */
    (void)uinteger(infile, 2);	/* ne */
    (void)uinteger(infile, 2);	/* np */
    (void)uinteger(infile, 4);	/* Skip checksum */
    designsize = uinteger(infile, 4) / FIX;
    for (i = bc; i <= ec; i++) {
	(void)fseek(infile, 24L + 4 * lh + (i - bc) * 4, 0);
	widthindex = uinteger(infile, 1);
	heightanddepth = uinteger(infile, 1);
	if (widthindex == 0)
	    continue;
	(void)fseek(infile, 24L + 4 * lh + (ec - bc + 1) * 4 + widthindex
	* 4, 0);
	widths[i][0] = integer(infile, 4);
	(void)fseek(infile, 24L + 4 * lh + (ec - bc + 1) * 4 + nw * 4 +
	(heightanddepth >> 4) * 4, 0);
	height = uinteger(infile, 4);
	(void)fseek(infile, 24L + 4 * lh + (ec - bc + 1) * 4 + nw * 4 +
	nh * 4 + (heightanddepth & 0xF) * 4, 0);
	depth = uinteger(infile, 4);
	if (!Special && isalnum(i) || Special && (0101 <= i && i <= 0130
	|| 0141 <= i && i <= 0170 || i == 014 || i == 050)) {
	    if (height > aheight)     /* Letters taller than 'a' get 0200 */
	        widths[i][1] |= 0200; /* turned on. */
	    if (depth > 0)	      /* Letters below baseline get 0100 */
	        widths[i][1] |= 0100; /* turned on. */
	}
    }
    for (i = 040, zero = 0; i < 256; i++) {
	if (i == 0177 && !Special) { /* 1/16em is always 6 units */
	    if (zero) {
		zero = 0;
		putc('\n', outfile);
	    }
	    fprintf(outfile, "6,\n");
	    continue;
	}
	if (i == 0226 && !Special) { /* 1/12em is always 3 units */
	    if (zero) {
		zero = 0;
		putc('\n', outfile);
	    }
	    fprintf(outfile, "3,\n");
	    continue;
	}
	if (i == ' ' && !Special) {  /* Space is always 12 units */
	    if (zero) {
		zero = 0;
		putc('\n', outfile);
	    }
	    fprintf(outfile, "12,\n");
	    continue;
	}
	charpos = (Special ? SpecialOrder[i - 32] : RegularOrder[i - 32]);
	if (charpos == 0 || widths[charpos][0] == 0) {
	    fprintf(outfile, "0,");
	    zero++;
	    if (!((i+1)%8)) {
		putc('\n', outfile);
		zero = 0;
	    }
	} else {
	    if (zero) {
		zero = 0;
		putc('\n', outfile);
	    }
	    j = ROUND((widths[charpos][0] / (double)FIX * designsize) / PPI
	    * 254.6457);
	    /* Don't ask where the 254.6457 came from.  I haven't the faintest
	     * notion why troff uses this constant, but it works, and that
	     * is fine enough with me.  Otroff can't handle widths over
	     * 63 (2^6).  If you give it something greater, it take the
	     * lower six bits.  This screws up the TRW logo which is 79 but
	     * there is nothing we can do.
	     */
	    fprintf(outfile, "%d", j > 63 ? 63 : j);
	    if (widths[charpos][1])
	        fprintf(outfile, "+0%o,\n", widths[charpos][1]);
	    else
	        fprintf(outfile, ",\n");
	}
    }
    fprintf(outfile, "};\n");
}

/* Returns the height of the letter 'a' in the font passed as a parameter.
 * The height is returned in FIXes/designsize.  If the letter 'a' is not 
 * found, MAX_INTEGER is returned.
 */
long getaheight(in)
FILE	*in;
{
    unsigned long lh, bc, ec, nw, uinteger();

    (void)fseek(in, 0L, 0);
    (void)uinteger(in, 2);	/* lf */
    lh = uinteger(in, 2);
    bc = uinteger(in, 2);
    ec = uinteger(in, 2);
    nw = uinteger(in, 2);
    (void)uinteger(in, 2);	/* nh */
    (void)uinteger(in, 2);	/* nd */
    (void)uinteger(in, 2);	/* ni */
    (void)uinteger(in, 2);	/* nl */
    (void)uinteger(in, 2);	/* nk */
    (void)uinteger(in, 2);	/* ne */
    (void)uinteger(in, 2);	/* np */
    if (bc > 'a' || ec < 'a')
	return MAX_INTEGER;
    (void)uinteger(in, 4);		    /* Skip checksum */
    (void)uinteger(in, 4);    		    /* Width */
    (void)fseek(in, 24L + lh*4 + ('a'-bc)*4, 0);
    if (uinteger(in, 1) == 0)
	return MAX_INTEGER;
    (void)fseek(in, 24L + lh*4 + (ec-bc+1)*4 + nw*4 + (uinteger(in,1) >> 4)*4,
    0);
    return uinteger(in, 4);
}

void tfmeofsoexit()
{
    fprintf(stderr, "%s: unexpected end of tfm file %s\n", WhoAmI, TfmName);
    exit(FAIL);
}