#ifndef lint
static char *sccsid = "@(#)fontotext.c	1.2 (UKC) 16/9/86";
#endif  lint
/*
 *	fontotext.c
 *	read a font file and output it as text
 */

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include "font.h"

extern char	*calloc();
static u_short	get16();
static u_long	get32();

static	char	*progname = "fontotext";
static u_short	nchars;
static u_long	raster_size;		/* note: this is u_short in font */
static charac	*characters;		/* block of character structures */
static u_long	*rasters;		/* start of the block of rasters */

char	white = '.';	/* the default grid characters */
char	black = '@';
char	whiteref = '+';
char	blackref = '*';

main(argc, argv)
int	argc;
char	**argv;
{
	FILE	*ifp = stdin, *ofp = stdout;	/* default i/o streams */
	u_long	n_rasters;			/* for checking purposes */
	int	i;

	if (argc > 3) {
		fprintf(stderr, "Usage: %s [fontfile] [textfile]\n", progname);
		exit(1);
	}
	if (argc >= 2) 
		if ((ifp = fopen(argv[1], "r")) == NULL) {
			fprintf(stderr, "%s: can't read %s\n",
				progname, argv[1]);
			exit(1);
		}
	if (argc == 3)
		if ((ofp = fopen(argv[2], "w")) == NULL) {
			fprintf(stderr, "%s: can't write to %s\n",
				progname, argv[2]);
			exit(1);
		}

	nchars = get16(ifp);
	raster_size = (u_long) get16(ifp);
	fprintf(ofp, "# Number of characters: %u Raster size: %u\n",
		nchars, raster_size);
	characters = (charac *) calloc (nchars, sizeof(charac));
	if (characters == NULL) {
		fprintf(stderr, "%s: not enough memory for %d chars\n",
			progname, nchars);
		exit(1);
	}

	n_rasters = 0;

	/* read in all the characters */
	for (i = 0; i < nchars; i++) {
		characters[i].width = get16(ifp);
		characters[i].height = get16(ifp);
		characters[i].xoffs = (short) get16(ifp);
		characters[i].yoffs = (short) get16(ifp);
		characters[i].raster_index = get32(ifp);
		characters[i].effective_width = get32(ifp);
		n_rasters += (characters[i].width+31)/32 * characters[i].height;
	}

	if (n_rasters < raster_size)
		fprintf(stderr, "%s: only %d of the %d rasters are used\n",
			progname, n_rasters, raster_size);

	/* allocate some memory for the rasters */
	rasters = (u_long *) calloc ((unsigned) raster_size, sizeof(u_long));
	if (rasters == NULL) {
		fprintf(stderr, "%s: not enough memory for %d rasters\n",
			progname, raster_size);
		exit(1);
	}

	/* read in all the rasters */
	for (i = 0; i < raster_size; i++)
		rasters[i] = get32(ifp);

	/* print all the characters */
	for (i = 0; i < nchars; i++)
		printchar(ofp, i);
	exit(0);
}

#define max(a, b)	((a) > (b) ? (a) : (b))
#define min(a, b)	((a) < (b) ? (a) : (b))

/*
 *	write the pattern of character[i] to the output stream fp
 */
printchar(fp, i)
FILE	*fp;
{
	int	x, xmin, xmax;
	int	y, ymin, ymax;
	int	isref;
	u_long	*r;		/* pointer into rasters */
	u_long	bit;

	short	width	= characters[i].width;
	short	height	= characters[i].height;
	short	xoffs	= characters[i].xoffs;
	short	yoffs	= characters[i].yoffs;
	u_long	index	= characters[i].raster_index;
	u_long	ew	= characters[i].effective_width;
 
 	/* if this character is unused, there is nothing to print */
 	if (width == 0 || height == 0)
 		return;

	/* check that the character indexes the rasters correctly */
	if (index + (width+31)/32 * height > raster_size) {
		fprintf(stderr,
			"%s: character %d has invalid index (%d+%u*%d > %u)\n",
			progname, i, index, (width+31)/32, height, raster_size);
		return;
	}

	fprintf(fp, "# %d ", i);
	if (isprint(i)) fprintf(fp, "'%c' ", i);
	fprintf(fp, "width=%d height=%d xoffset=%d yoffset=%d\n",
		width, height, xoffs, yoffs); 
	fprintf(fp, "ch=%d ewidth=%ld\n", i, ew);

	r = rasters + index;	/* our first raster */

	/*
	 *	Now print the character grid showing two reference points;
	 *	the second one illustrates the effective width
	 */
	ymin = min(yoffs, 0);			/* find y-boundaries for grid */
	ymax = max(yoffs, height-1);
	for (y = ymin; y <= ymax; y++) {
		bit = 1 << 31;			/* scanning bit */
		xmin = min(xoffs, 0);		/* x-boundaries for this line */
		xmax = max(xoffs, width-1);
		if (xmax < ew+xoffs) xmax = ew+xoffs;
		for (x = xmin; x <= xmax; x++) {
			isref = ((x == xoffs || x == ew+xoffs) && y == yoffs);
			if (x >= 0 && x < width && y >= 0 && y < height) {
				if (bit == 0) {
					bit = 1 << 31;
					r++;
				}
				if (*r&bit) /* bit is set */
					putc(isref ? blackref : black, fp);
				else putc(isref ? whiteref : white, fp);
				bit >>= 1;
			} else putc(isref ? whiteref : white, fp);
		}
		putc('\n', fp);
		if (y >= 0 && y < height)	/* move on to next raster */
			r++;
	}
	putc('\n', fp);	/* a blank line terminates the character */
}

#define cget(ifp) ((ch = getc(ifp))==EOF ? preof() : (ch&255))

/* get a 16 bit quantity from stream fp */
static u_short
get16(fp)
FILE *fp;
{
	register u_short i;
	register int ch;

	i = (u_short) cget(fp) << 8;
	i += (u_short) cget(fp);
	return(i);
}
	
/* get a 32 bit quantity from stream fp */
static u_long
get32(fp)
FILE *fp;
{
	register u_long i;
	register int ch;

	i = (u_long) cget(fp) << 24;
	i += (u_long) cget(fp) << 16;
	i += (u_long) cget(fp) << 8;
	i += (u_long) cget(fp);
	return(i);
}

preof()
{
	fprintf(stderr, "%s: premature EOF\n", progname);
	exit(1);
}
