File:  [MW Coherent from dump] / coherent / b / bin / troff / fwt_TFM.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * fwt_TFM.c
 * 3/30/93
 * Build troff font width table from HP TFM file.
 * Reference: Hewlett Packard, "Tagged Font Metric Specification".
 * However, as of 6/7/91, steve has not seen the official spec,
 * so this code is based on the braindamaged source code for HP TFM reader.
 * Prints useful debugging output to stderr if compiled with DEBUG true.
 * INCOMPLETE.
 */

#include <stdio.h>
#include "fwtable.h"

/* Manifest constants. */
#define	INTEL_ORDER	0x4949
#define	MOTOROLA_ORDER	0x4D4D
#define	N_SYMBOL_SET	14		/* bytes per symbol set entry */

/* Tag values; this list does not include unused tags. */
#define	T_SYMBOL_SET	404
#define	T_POINT		406
#define	T_NOMINAL_PT	407
#define	T_DESIGN_UNITS	408
#define	T_TYPE_STRUCT	410
#define	T_STROKE_WT	411
#define	T_SPACING	412
#define	T_SLANT		413
#define	T_APPEAR_WIDTH	414
#define	T_TYPEFACE	417
#define	T_HORIZ_ESC	433
#define	T_SELECT_STR	442

/* Type. */
typedef	struct	rational {
	long	r_mul;		/* multiplier */
	long	r_div;		/* divisor */
} RATIONAL;

/* Data type lengths. */
#define	MAXTYPE	18		/* Max data type */
int type_size[MAXTYPE+1] = {
	0,			/* 0  == unused		*/
	1,			/* 1  == BYTE		*/
	1,			/* 2  == ASCII		*/
	2,			/* 3  == SHORT		*/
	4,			/* 4  == LONG		*/
	8,			/* 5  == RATIONAL	*/
	0,0,0,0,0,0,0,0,0,0,	/* 6 to 15 == unused	*/
	1,			/* 16 == SIGNEDBYTE	*/
	2,			/* 17 == SIGNEDSHORT	*/
	4			/* 18 == SIGNEDLONG	*/
};

/* Global. */
int	appear_width;		/* Width.			*/
RATIONAL design_units;		/* Design units.		*/
int	Intel_order;		/* Use Intel i8086 byte order.	*/
RATIONAL nominal_point;		/* Nominal pointsize.		*/
RATIONAL point;			/* Point size.			*/
int	selector;		/* Selector.			*/
int	slant;			/* Slant.			*/
int	spacing;		/* Spacing.			*/
int	stroke_weight;		/* Stroke weight.		*/
short	*symbol_horiz;		/* Symbol map horizontal esc.	*/
short	*symbol_set;		/* Symbol set indices.		*/
int	symbol_set_size;	/* Symbol set size.		*/
int	symset_val;		/* Encoded symbol set value.	*/
char	*typeface;		/* Typeface name.		*/
int	type_structure;		/* Type structure.		*/

/*
 * Return the GCD of two longs.
 * Euclid's algorithm.
 */
long
gcd(m, n) long m, n;
{
	long r;

	while ((r = m % n) != 0) {
		m = n;
		n = r;
	}
	return n;
}

/*
 * Read and return a long, observing specified byte order.
 */
long
getlong()
{
	register int c;

	c = getword();
	if (Intel_order)
		return (((long)getword()) << 16) | c;
	else
		return (((long)c) << 16) | getword();
}

/*
 * Read a rational and store it through the supplied pointer.
 */
void
getrational(rp) RATIONAL *rp;
{
	rp->r_mul = getlong();
	rp->r_div = getlong();
}

/*
 * Read a NUL-terminated string into buf[] and return a pointer to it.
 * No overflow check, for shame...
 */
char *
getstring()
{
	register char *cp;

	for (cp = buf; *cp++ = getuchar(); )
		;
	return buf;
}

/*
 * Read and return a short (2 bytes), observing specified byte order.
 */
int
getword()
{
	register int c;

	c = getuchar();
	if (Intel_order)
		return (getuchar() << 8) | c;
	else
		return (c << 8) | getuchar();
}

/*
 * Read TFM file.
 */
void
inputTFM()
{
	register int i, ntags;
	int tag, type;
	long size, length, curpos, offset;

	/* Read byte order word. */
	if ((i = getword()) == INTEL_ORDER)
		++Intel_order;
	else if (i != MOTOROLA_ORDER)
		fatal("unknown byte order 0x%x in TFM header", i);

	/* Skip TFM version number. */
	getword();

	/* Read typeface offset, warn if not equal to current position. */
	if ((offset = getlong()) != 8L) {
		nonfatal("warning: TFM file contains multiple typefaces; using first");
		xseek(offset);
	}

	/* Read tag count and process tags. */
	ntags = getword();
	dbprintf((stderr, "ntags=%d\n", ntags));
	for (i = 1; i <= ntags; i++) {

		/* Read tag, type, size; compute length. */
		tag = getword();
		type = getword();
		size = getlong();
		length = size * type_size[type];
		dbprintf((stderr, "tag=%d type=%d size=%ld length=%ld\n", tag, type, size, length));

		/* Save current position, seek to data position if required. */
		curpos = xtell();
		if (length > 4) {
			offset = getlong();
			dbprintf((stderr, "length=%ld, data at offset %ld\n", length, offset));
			xseek(offset);
		}
		
		/* Process the tag. */
		switch(tag) {

		case T_SYMBOL_SET:	read_symbol_set((int)size / N_SYMBOL_SET);
					break;
		case T_POINT:		getrational(&point);		break;
		case T_NOMINAL_PT:	getrational(&nominal_point);	break;
		case T_DESIGN_UNITS:	getrational(&design_units);	break;
		case T_TYPE_STRUCT:	type_structure = getuchar();	break;
		case T_STROKE_WT:	stroke_weight = getuchar();	break;
		case T_SPACING:		spacing = getword();		break;
		case T_SLANT:		slant = getword();		break;
		case T_APPEAR_WIDTH:	appear_width = PCL_width(getuchar());
					break;
		case T_TYPEFACE:	typeface = newstring(getstring());
					break;
		case T_HORIZ_ESC:	symbol_horiz = read_array((int)size);
					break;
		case T_SELECT_STR:	selector = atoi(getstring());	break;
		default:
			dbprintf((stderr, "tag %d IGNORED\n", tag));
			break;			/* Ignore other tags. */
		}

		/* Restore position for next tag. */
		xseek(curpos+4);
	}
}

/*
 * Write font width table output from TFM.
 */
void
outputTFM()
{
	register int i, j, width, max, mul;
	long g, lmul, ldiv;

	/* Calculate maximum width of characters in character set. */
	for (max = i = 0; i < NWIDTH && i < symbol_set_size; i++) {
		j = symbol_set[i];
		width = (j == -1) ? 0 : symbol_horiz[j];
		dbprintf((stderr, "i=%d j=%d width=%d\n", i, j, width));
		if (width > max)
			max = width;		
	}
	mul = (max / 256) + 1;
	dbprintf((stderr, "max=%d\n", max));
	dbprintf((stderr, "mul=%d\n", mul));
	dbprintf((stderr, "design_unit: %ld/%ld\n", design_units.r_mul, design_units.r_div));
	dbprintf((stderr, "nominal pt:  %ld/%ld\n", nominal_point.r_mul, nominal_point.r_div));
	dbprintf((stderr, "point:       %ld/%ld\n", point.r_mul, point.r_div));

	/* A little fuss to convert tag values to PCL values; thanks, HP. */
	if (vflag)
		fprintf(stderr, "%s %s\n", typeface, symset);
	fprintf(ofp, "%s %s", typeface, symset);	/* descriptor string */
	fputc('\0', ofp);		/* NUL-terminated */
	fputc('\0', ofp);		/* PS name */
	putshort(FLAG_PCL);		/* flags */
	putshort(0);			/* fonttype */
	putshort(0);			/* orientation */
	putshort(spacing == 0);		/* spacing */
	putshort(symset_val);		/* symbol set */
	if (spacing == 0)
		putshort(0);		/* pitch, proportional */
	else {
		/* UNTESTED, is this right? */
		i = (point.r_div * nominal_point.r_div * design_units.r_mul) /
		    (point.r_mul * nominal_point.r_mul * design_units.r_div * spacing);
		putshort(i);		/* pitch, fixed spacing */
	}
	i = 10 * nominal_point.r_mul / nominal_point.r_div;
	putshort(i);			/* 10 * pointsize */
	i = ((type_structure/8) << 5) | (appear_width << 2) | (slant != 0);
	putshort(i);			/* style */
	i = (stroke_weight == 0) ? -7 : (stroke_weight-1)/17 - 7;
	putshort(i);			/* weight */
	putshort(selector);		/* face */

	/* Compute multiplier and divisor. */
#if	0
	/*
	 * I think this is philosophically right,
	 * but the factors get too big when point==100/7231;
	 * just assume a point is 1/72" instead.
	 */
	if (point.r_mul == 1 && point.r_div == 72) {
		lmul = design_units.r_div * mul;
		ldiv = design_units.r_mul;
	} else {
		lmul = design_units.r_div * point.r_mul * 72 * mul;
		ldiv = design_units.r_mul * point.r_div;
	}
#else
	lmul = design_units.r_div * mul;
	ldiv = design_units.r_mul;
#endif
	dbprintf((stderr, "lmul=%ld ldiv=%ld\n", lmul, ldiv));
	if ((g = gcd(lmul, ldiv)) != 1) {
		lmul /= g;
		ldiv /= g;
	}
	dbprintf((stderr, "g=%ld lmul=%ld ldiv=%ld\n", g, lmul, ldiv));
	putshort((int)lmul);		/* mul */
	putshort((int)ldiv);		/* div */

	/* Write width table. */
	for (i = 0; i < 256; i++) {
		j = (i < symbol_set_size) ? symbol_set[i] : -1;
		width = (j == -1) ? 0 : symbol_horiz[j];
		fputc(width/mul, ofp);
		dbprintf((stderr, "i=%d width=%d\n", i, width/mul));
	}
}

/*
 * Convert appearance width tag value to PCL value.
 * Cf. "LJ III Printer Developer's Guide", p. 6-37.
 */
int
PCL_width(n) int n;
{
	if (n <= 20)	   return 4;
	else if (n <= 47)  return 3;
	else if (n <= 74)  return 2;
	else if (n <= 101) return 1;
	else if (n <= 182) return 0;
	else if (n <= 209) return 6;
	else		   return 7;
}

/*
 * Allocate space for n integer words.
 * Read the array of integers and return a pointer to the array.
 */
int *
read_array(n) int n;
{
	register int i;
	register short *ip, *p;

	p = ip = alloc(n * sizeof(short));
	for (i = 0; i < n; i++, ip++) {
		*ip = getword();
#if	0
		dbprintf((stderr, "index=%d val=%d\n", i, *ip));
#endif
	}
	return p;
}

/*
 * Read the symbol set directory.
 */
void
read_symbol_set(n) int n;
{
	register int i, found;
	long curpos, offset, symset_seek, symsel_seek;
	char *s;

	dbprintf((stderr, "n_symbol_sets=%d\n", n));
	for (found = i = 0; i < n && !found; i++) {
		dbprintf((stderr, "symbol set %d: ", i));
		symset_seek = getlong();
		symsel_seek = getlong();
		offset = getlong();
		symbol_set_size = getword();
		curpos = xtell();
		xseek(symset_seek);
		s = getstring();		/* symbol set */
		xseek(curpos);
		dbprintf((stderr, "symset=%s ", s));
		dbprintf((stderr, "index offset=%ld ", offset));
		dbprintf((stderr, "index length=%d\n", symbol_set_size));
		if (symset == NULL) {
			symset = newstring(s);	/* no -s option, take first */
			++found;
		} else if (strcmp(symset, s) == 0)
			++found;
	}
	if (!found)
		fatal("symbol set %s not found", symset);
	dbprintf((stderr, "found symset %s\n", symset));
	xseek(symsel_seek);
	s = getstring();		/* read symbol set selector */
	dbprintf((stderr, "selector=%s ", s));
	symset_val = atoi(s) * 32 + s[strlen(s)-1] - 64;
	dbprintf((stderr, "symset_val=%d\n", i));
	xseek(offset);
	symbol_set = read_array(symbol_set_size);
}

/*
 * Seek to given offset, die on error.
 */
void
xseek(offset) long offset;
{
	if (fseek(ifp, offset, SEEK_SET) == -1L)
		fatal("fseek failed");
}

/*
 * Return current seek position, die on error.
 */
long
xtell()
{
	register long offset;

	if ((offset = ftell(ifp)) == -1L)
		fatal("ftell failed");
	return offset;
}

/* end of fwt_TFM.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.