#ifndef lint
static char *sccsid = "@(#)cantotxt.c	1.5 (UKC) 19/9/85";
#endif  lint

/*
 *	Banner using canon font format on stdin.
 *	At UKC, get the fonts from the file server with
 *	fs from /canon/font/times.r.10 | cantotxt message
 */

#include <stdio.h>

#define debug (void)
#define MARK '@'
#define SPACE ' '

typedef unsigned short u_short;
typedef unsigned long u_long;

u_short get16();
u_long	get32();
char *calloc();
char *strcat();

struct character {
	u_short width;
	u_short height;
	short xoffs;
	short yoffs;
	u_long raster_index;
	u_long effective_width;
};

static u_short nchars;
static u_long raster_size;		/* iau bludner: is ushort in font */
static struct character *character;	/* the per-character structures */
static u_long *rasters;			/* the rasters, read from the file */

static int max_up = 0, max_down = 0;	/* The highest/lowest any character rises/falls above/below the reference point */

static int printflag = 0;	/* Debugging print of info in font file */
static int verboseflag = 0;	/* Show char data as you print them */

char message[1024];		/* the string they want bannered */

main(argc, argv)
char **argv;
{
	register FILE *ifp;
	register int i;
	u_long n_rasters;	/* for checking purposes */
	int down;
	int firststring = 1;	/* have we put anything into message[] yet? */

	for (i=1; i<argc; i++) {
		if (argv[i][0] == '-') {
			switch(argv[i][1]) {
			case 'p':
				printflag = 1;
				break;
			case 'v':
				verboseflag = 1;
				break;
			default:
				fprintf(stderr, "cantotxt: Unknown flag '%s'.\n", argv[i]);
			}
		} else {
			if (!firststring) (void) strcat(message, " ");
			else firststring = 0;
			(void) strcat(message, argv[i]);
		}
	}

	ifp = stdin;
	nchars = get16(ifp);
	raster_size = (u_long) get16(ifp);
	if (printflag) printf("nchars = %u, raster_size = %u\n", nchars, raster_size);
	character = (struct character *) calloc ( nchars, sizeof(struct character) );
	if (character == NULL) {
		fprintf(stderr, "cantotxt: Not enough memory for %d characters.\n", nchars);
		exit(1);
	}

	n_rasters = 0; max_up = max_down = 0;

	if (printflag) printf("CH# WID HEI XOF YOF INDEX EWD MXD\n");
	for (i=0; i<nchars; i++) {
		character[i].width = get16(ifp);
		character[i].height = get16(ifp);
		character[i].xoffs = (short) get16(ifp);
		character[i].yoffs = (short) get16(ifp);
		character[i].raster_index = get32(ifp);
		if (character[i].width != 0 && character[i].height != 0) {
			while(character[i].raster_index > raster_size) {
				raster_size += 65536;
				fprintf(stderr, "cantotxt: raster_size seems to be truncated. Increasing to %d for character %d.\n", raster_size, i);
			}
		}
		character[i].effective_width = get32(ifp);
		n_rasters += (character[i].width+31)/32 * character[i].height;
		if (character[i].yoffs > max_up) max_up = character[i].yoffs;
		down = (int) character[i].height - character[i].yoffs;
		if (down > max_down) max_down = down;
		if (printflag) printf("%3d %3d %3d %3d %3d %5d %3d %3d\n",
				i,
				character[i].width,
				character[i].height,
				character[i].xoffs,
				character[i].yoffs,
				character[i].raster_index,
				character[i].effective_width,
				max_down);
	}
	if (n_rasters < raster_size) {
		fprintf(stderr, "cantotxt: Hum. Only %d of the %d available rasters are used.\n", n_rasters, raster_size);
	}
	if (printflag) {
		printf("max_up = %d, max_down = %d.\n", max_up, max_down);
		exit(0);
	}

	rasters = (u_long *) calloc (raster_size, sizeof(u_long));
	if (rasters == NULL) {
		fprintf(stderr, "cantotxt: Not enough memory for %d rasters.\n", raster_size);
		exit(1);
	}
	for (i=0; i<raster_size; i++) {
		rasters[i] = get32(ifp);
	}
	if (message[0]=='\0') {
		for (i=0; i<nchars; i++) setchar(i);
	} else {
		for (i=0; message[i] != '\0'; i++) setchar(message[i]);
	}
	exit(0);
}

setchar(i)
{
	register u_long bit;
	register u_long *raster;	/* points into rasters[] */
	register int x, y;
	register int rwidth;		/* width of char in rasters */
	register u_long *r;		/* pointer into rasters[] */
	register int pendingspcs;	/* catch trailing spaces */

	u_short width	= character[i].width;
	u_short height	= character[i].height;
	short xoffs	= character[i].xoffs;
	short yoffs	= character[i].yoffs;

	int xpos = 0;	/* position in output grid */

	if (width == 0 || height == 0) {
		fprintf(stderr, "cantotxt: character %d nonexistent (height %d, width %d)\n", i, width, height);
		return;
	}
	if (character[i].raster_index + (character[i].width+31)/32*character[i].height > raster_size) {
		fprintf(stderr, "cantotxt: character %d has illegal index(%d+%d*%d/%d).\n", i, character[i].raster_index, (character[i].width+31)/32, character[i].height, raster_size);
		return;
	}
	if (verboseflag) {
		printf("CH# WID HEI XOF YOF INDEX EWD MXD\n");
		printf("%3d %3d %3d %3d %3d %5d %3d %3d",
			i,
			character[i].width,
			character[i].height,
			character[i].xoffs,
			character[i].yoffs,
			character[i].raster_index,
			character[i].effective_width);
		if (i>33 && i<127) printf(" (%c)",i);
		putchar('\n');
	}
	if (xoffs < -255 || xoffs > 0) {
		fprintf(stderr, "cantotxt: character %d has xoffset of %d.\n", i, xoffs);
	} else {
		while (xpos < xoffs) {
			putchar('\n');
			xpos++;
		}
	}
	rwidth = (width+31)/32;
	raster = rasters + character[i].raster_index;
	bit = 1<<31;
	for (x=0; x<width; x++) {
		if (bit == 0) bit = 1<<31;
		r=raster+(height-1)*rwidth + x/32;
		pendingspcs = max_down + yoffs - height;;
		for (y=height-1; y>=0; y--) {
			if (*r&bit) {
				while (pendingspcs > 0) {
					putchar(SPACE);
					pendingspcs--;
				}
				putchar(MARK);
			} else pendingspcs++;
			r -= rwidth;
		}
		bit >>= 1;
		putchar('\n');
		xpos++;
	}
	putchar('\n'); xoffs++;
	if (character[i].effective_width > 65535) {
		fprintf(stderr, "cantotxt: character %d has effective width of %d.\n", character[i].effective_width);
	} else {
		while ( xpos < character[i].effective_width) {
			putchar('\n');
			xpos++;
		}
	}
}

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

u_short
get16(ifp)
FILE *ifp;
{
	register u_short i;
	register int ch;

	i = (u_short) cget(ifp) << 8;
	i += (u_short) cget(ifp);
	debug(stderr, "get16: %d\n", i);
	return(i);
}
	
u_long
get32(ifp)
FILE *ifp;
{
	register u_long i;
	register int ch;

	i = (u_long) cget(ifp) << 24;
	i += (u_long) cget(ifp) << 16;
	i += (u_long) cget(ifp) << 8;
	i += (u_long) cget(ifp);
	debug(stderr, "get32: %d\n", i);
	return(i);
}

preof()
{
	fprintf(stderr, "Premature EOF.\n");
	exit(1);
}

debugch(i, ch)
struct character ch;
{
	fprintf(stderr, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
		i,
		ch.width,
		ch.height,
		ch.xoffs,
		ch.yoffs,
		ch.raster_index,
		ch.effective_width);
}
