/*********************************************************************
 * ViewFont.C	Version 1.3       Copyright (c) 1989 Jim Bumgardner
 *
 * Second Release (Version 1.3)   8-25-89
 * First Release (Version 1.2)	11-08-88
 *
 **********************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <alloc.h>
#include <graphics.h>

/* This is the maximum character bitmap size */
#define MAXCHARSIZE	18000

/* Keyboard Definitions */
#define ESC		27
#define DOWN		0x5000
#define UP		0x4800
#define RIGHT		0x4D00
#define LEFT		0x4B00
#define PGUP		0x4900
#define PGDN		0x5100
#define HOME		0x4700
#define END		0x4F00

struct fhead_struct {
	int fil26;
	char nul1,font_type;
	int nul2,baseline,width,height;
	char orient,prop;
	int symset,pitch,points,nul3;
	char nul4,style,weight,type_face;
} font_header;

struct chead_struct {
	char fil4,nul1,fil14,cil1;
	char orient,nul2;
	int left_offset,top_offset,width,height,delta_x;
} char_header;

int g_driver = DETECT,g_mode;
int maxx,maxy;

long *char_ptrs;
int *ibuf,*bmap;

FILE *ifile;

int mbytes,maxcx,maxcy,maxcs;
int min_c = 256,max_c = 0;

char syntax[] = 
"VIEWFONT Version 1.3\t\t\t\tCopyright (c) 1989 Jim Bumgarder\n\n"
"Syntax:\n"
"\tVIEWFONT fontfile[.sfp]\n\n"
"\tUse Arrow keys or letters to view, ESC to quit.\n";

main(argc,argv)
char *argv[];
{
	int c,ch,och;
	char fname[33];

	if (argc == 1 || argv[1][0] == '?')
		erxit(syntax);

	if ((ibuf = malloc(MAXCHARSIZE)) == NULL ||
	    (char_ptrs = malloc(sizeof(long)*256)) == NULL)
		erxit("Not Enough Memory");

	bmap = &ibuf[2];

	strcpy(fname,argv[1]);
	if (strchr(fname,'.') == 0)
		strcat(fname,".SFP");
	if ((ifile = fopen(fname,"rb")) == NULL)
		erxit("Can't open Input File: %s\n",fname);

	for (c=0; c<256; ++c)
		char_ptrs[c]=0L;

	get_header();
	mark_chars();

	registerbgidriver(EGAVGA_driver); 
	registerbgidriver(CGA_driver);	 
	registerbgidriver(Herc_driver);

	initgraph(&g_driver,&g_mode,"");
	if (g_driver < 0)
		erxit("No Graphics, or .BGI driver Available");
	setbkcolor(1);

	maxx = getmaxx();
	maxy = getmaxy();
	maxcx = maxx/(mbytes<<3);
	maxcy = maxy/font_header.height;
	maxcs = maxcx*maxcy;
	
	ch = min_c;
	och = -1;
	while (1) {
		if (och != ch) {
			och = ch;
			show_bmaps(ch);
		}

		c = getch();
		if (c == 0)	c = getch() << 8;
		switch (c) {
		case 3:
		case 26:
		case ESC:	fr_exit();
		case HOME:	ch = min_c;	break;
		case END:	ch = max_c - maxcs + 1;
				if (ch < min_c)	ch = min_c;
				break;
		case RIGHT:	if (ch < max_c)	++ch;	break;
		case '\b':
		case LEFT:	if (ch > min_c)	--ch;	break;
		case ' ':
		case DOWN:	if (ch+maxcx <= max_c)	ch += maxcx;
				break;
		case UP:	if (ch-maxcx >= min_c)	ch -= maxcx;
				break;
		case '\r':
		case PGDN:	if (ch+maxcs <= max_c)	ch += maxcs;
				break;
		case PGUP:	if (ch-maxcs >= min_c)	ch -= maxcs;
				break;
		default:	if (c >= '!' && c <= max_c)
					ch = c;
				break;
		}
	}
}

get_header()
{
	unsigned int tmp;
	int c;

	fseek(ifile,0L,0);
	do {
		while ((c = getc(ifile)) != EOF && c != ESC)
			;
		if (c == EOF)
			erxit("Invalid Font File");
		tmp = getw(ifile);
	} while (tmp != ')s');
	tmp = get_number();
	fread(&ibuf[0],tmp,1,ifile);
	memcpy(&font_header,&ibuf[0],sizeof(font_header));
	font_header.width = iswap(font_header.width);
	font_header.height = iswap(font_header.height);
	font_header.baseline = iswap(font_header.baseline);
	mbytes = ((font_header.width-1) >> 3) + 1;
}

mark_chars()
{
	long fptr,ftell();
	int cno;
	while (1) {
		fptr = ftell(ifile);
		if ((cno = get_char_header()) == EOF)	return;
		if (cno > max_c)	max_c = cno;
		if (cno < min_c)	min_c = cno;
		char_ptrs[cno] = fptr;
	}
}

get_char(cno)
{
	if (char_ptrs[cno] == 0L)
		return(0);
	fseek(ifile,char_ptrs[cno],0);
	get_char_header();
	return(1);
}

get_char_header()
{
	int tmp;
	int c,cno;
	do {
		while ((c = getc(ifile)) != EOF && c != ESC)
			;
		if (c == EOF)		return EOF;
		tmp = getw(ifile);
	} while (tmp != '*c');
	cno = get_number();
	do {
		while ((c = getc(ifile)) != EOF && c != ESC)
			;
		if (c == EOF)		return EOF;
		tmp = getw(ifile);
	} while (tmp != '(s');
	tmp = get_number();

	fread(&char_header,sizeof(char_header),1,ifile);
	fread(bmap,tmp-sizeof(char_header),1,ifile);

	char_header.width = iswap(char_header.width);
	char_header.height = iswap(char_header.height);
	char_header.top_offset = iswap(char_header.top_offset);
	char_header.left_offset = iswap(char_header.left_offset);
	char_header.delta_x = iswap(char_header.delta_x)>>2;

	ibuf[0] = char_header.width-1 | 0x07;	
	ibuf[1] = char_header.height-1;
	return cno;
}

show_bmaps(ch)
{
	int xf,yf,c;

	cleardevice();
	setcolor(7);

	xf = 16; yf = 0;							/* Start indented */
	for (c = ch; c <= max_c; ++c)
	{
		if (get_char(c) == 0)	continue;
		if (xf + (mbytes << 3) > maxx)
			{
			yf += font_header.height;
			xf = 16;
			if (yf + font_header.height > maxy)	return;
			}

		if (g_driver==CGA || g_driver==HERCMONO)	/* if one color, draw before */
			putimage(xf,yf+font_header.baseline-char_header.top_offset,ibuf,0);

		xf -= char_header.left_offset;
		line(xf,yf+font_header.height-1,					  /* Draw bottom */
				xf+mbytes<<3,yf+font_header.height-1);
		line(xf,yf,xf,yf+font_header.height-1);		  /* Left character line */
		line(xf+char_header.delta_x,yf,					  /* Right character line*/
				xf+char_header.delta_x,yf+font_header.height-1);
		line(xf,yf+font_header.baseline,					  /* Character baseline */
			xf+char_header.delta_x,yf+font_header.baseline);
		xf += char_header.left_offset;

		if (g_driver!=CGA && g_driver!=HERCMONO)
			putbits(xf,yf+font_header.baseline-char_header.top_offset,
						char_header.width,char_header.height,bmap,15);
		xf += (mbytes << 3);
	}
	yf += font_header.height;
	if (yf-1 <= maxy)	line(0,yf-1,maxx,yf-1);			/* I haven't bothered */
}																	/* to omit this bottom line */

get_number()
{
	char *p;
	int c;
	p = (char *) ibuf;
	while ((c = getc(ifile)) != EOF && isdigit(c))
		*p++ = c;
	*p = 0;
	return(atoi((char *) ibuf));
}

iswap(n)
unsigned int n;
{
	return((n >> 8) | (n << 8));
}

fr_exit()
{
	#ifndef DEBUG
	closegraph();
	#endif

	exit();
}

erxit(char *tmp,...)
{
	va_list arg_ptr;
	va_start(arg_ptr,tmp);
	vfprintf(stderr,tmp,arg_ptr);
	va_end(arg_ptr);
	exit(0);
}
