/* fontwo.c
 * Double the height or width of an Amiga font
 * (C)1989 Ephraim Cohen
 *
 * Compile (Manx Aztec 3.6):
 *  cc +l fontwo.c
 *  ln fontwo.o -lc32
 */
#include <libraries/diskfont.h>
#include <libraries/dos.h>
#include <stdio.h>
#define REV 33

char *note[]= {
	"Usage: option font height [Attributes]",
	"Options:",
	"t	Make a tall font (double the height)",
	"w	Make a wide font (double the width)",
	"The name of the new font ends with 'x'",
	"For example",
	"\tfontwo t Topaz 8",
	"will create the font Fonts:Topaz/16wx",
	"Attributes:",
	"e  Extended", "i  Italic", "b  Bold", "u  Underline",
	"t  Tall Dot", "w  Wide Dot", "p  Proportional",
	0};

extern struct TextFont *OpenDiskFont();
extern char	*malloc(),
		*OpenLibrary();

char	*GfxBase,
	*DiskfontBase;
char	noroom[]= "Not Enough Memory";

char	*fontab;	/* The new font body */
long	attab[20];	/* Relocation information */

struct TextAttr		tea;
struct TextFont		*tfp;
struct TextFont		new;
struct DiskFontHeader	dfh;

getfont(ta)struct TextAttr *ta;{	/* Get a font with these attributes */
	register struct TextFont *tf;

	ta->ta_Flags |= FPF_ROMFONT|FPF_DISKFONT|FPF_DESIGNED;
	if(tf= OpenDiskFont(ta)){
		endfont();
		tfp= tf;
		return TRUE;
	}
	return 0;
}
endfont(){				/* Done with this font */
	if(tfp)CloseFont(tfp);	tfp= 0;
}
char *outname(tf, name)register struct TextFont *tf; char *name;{
	/* Create a name for the new font
	 * It is the font height, followed by some letters for
	 * the attributes, and followed by 'x' (because it's new)
	 */
	static char buf[80], attr[12];
	register char *cp= attr;

	if(tf->tf_Style&FSF_EXTENDED)*cp++= 'e';
	if(tf->tf_Style&FSF_ITALIC)*cp++= 'i';
	if(tf->tf_Style&FSF_BOLD)*cp++= 'b';
	if(tf->tf_Style&FSF_UNDERLINED)*cp++= 'u';
	if(tf->tf_Flags&FPF_TALLDOT)*cp++= 't';
	if(tf->tf_Flags&FPF_WIDEDOT)*cp++= 'w';
	if(tf->tf_Flags&FPF_PROPORTIONAL)*cp++= 'p';
	*cp= 0;
	sprintf(buf, "Fonts:%s/%d%sx", name, tf->tf_YSize, attr);
	return buf;
}
getatts(name, hi, cp)register char *cp;{
	/* Setup the TextAttr from the arguments */
	static char buf[64];

	strcpy(buf, name); strcat(buf, ".font");
	tea.ta_Name= (STRPTR)buf;
	tea.ta_YSize= hi;
	tea.ta_Style= 0;
	tea.ta_Flags= 0;
	if(cp)while(*cp)switch(toupper(*cp++)){
	case 'E':	tea.ta_Style |= FSF_EXTENDED; break;
	case 'I':	tea.ta_Style |= FSF_ITALIC; break;
	case 'B':	tea.ta_Style |= FSF_BOLD; break;
	case 'U':	tea.ta_Style |= FSF_UNDERLINED; break;
	case 'T':	tea.ta_Flags |= FPF_TALLDOT; break;
	case 'W':	tea.ta_Flags |= FPF_WIDEDOT; break;
	case 'P':	tea.ta_Flags |= FPF_PROPORTIONAL; break;
	}
}
char *
opelib(name)char *name;{	/* Open a library--complain if it's absent */
	register char *lib;

	aver(lib= OpenLibrary(name,REV), name);
	return lib;
}
openlibs(){			/* Get these libraries */
	GfxBase=	opelib("graphics.library");
	DiskfontBase= 	opelib("diskfont.library");
}
main(ac,av)register char **av;{
	BPTR fd;		/* File pointer */
	register size,		/* size of fontab */
		fun;		/* Function (Taller or Wider) */

	if(ac<3){
err:		for(av= note; *av; ++av)
			printf("%s\n", *av);
		exit(5);
	}
	getatts(av[2], atoi(av[3]), ac>4? av[4]:0);
	fun= toupper(av[1][0]);

	/* Must be Taller or Wider */
	if(fun!='T' && fun!='W')goto err;

	openlibs();				/* Get a font */
	getfont(&tea);
	aver(tfp, "No such font/size");

	if(fun=='T')taller(tfp);		/* Make a taller version */
	else wider(tfp);			/* or a wider version */

	aver(size= makefont(&new), noroom);	/* >>> */

	fd= Open(outname(&new, av[2]), MODE_NEWFILE);	/* Write it out */
	aver(fd, "Cannot create the new font");
	aver(writehunx(fd, fontab, size), "Write failed");
	Close(fd);

	aver(0,0);					/* All done */
}
aver(bool, msg)char *msg;{	/* Quit cleanly if bool is false */
	if(bool)return;
	if(msg)printf("?%s\n", msg);

	endfont();
	if(GfxBase)CloseLibrary(GfxBase);
	if(DiskfontBase)CloseLibrary(DiskfontBase);
	exit(msg? 5:0);
}
taller(tf)register struct TextFont *tf;{	/* Double the height */
	register char *sp, *dp;
	register x,y;

	new= *tf;				/* Copy the original */
	new.tf_YSize *= 2;			/* Double height */
	new.tf_Baseline *= 2;

	if(new.tf_Flags&FPF_TALLDOT)		/* It's a wider font now */
		new.tf_Flags &= ~FPF_TALLDOT;
	else	new.tf_Flags |= FPF_WIDEDOT;
	
	aver(dp= (char *)malloc(new.tf_YSize*new.tf_Modulo),noroom);

	new.tf_CharData= (APTR)dp;		/* Copy the character data */
	sp= (char *)(tf->tf_CharData);
	for(y= 0; y<tf->tf_YSize; y++){		/* For each scanline:	*/
		for(x= 0; x<tf->tf_Modulo; x++)	/*  Copy it once	*/
			*dp++= *sp++;
		sp -= tf->tf_Modulo;
		for(x= 0; x<tf->tf_Modulo; x++)	/*  and copy it again	*/
			*dp++= *sp++;
	}
}
APTR duexshort(wp, n)register unsigned short *wp;{
	/* Copy and double all the values in a table of unsigned shorts */
	register unsigned short *dp, *dp0;

	aver(dp0= dp= (unsigned short *)malloc(n*sizeof(short)), noroom);
	do
		*dp++= (*wp++) << 1;
	while(--n);
	return (APTR)dp0;
}
wider(tf)register struct TextFont *tf;{
	unsigned short widtab[256];
	register unsigned char *cp;
	register unsigned short *wp;
	register x,y;

	new= *tf;				/* Copy the original */
	new.tf_Modulo *= 2;
	new.tf_XSize *= 2;

	if(new.tf_Flags&FPF_WIDEDOT)		/* It's a taller font now */
		new.tf_Flags &= ~FPF_WIDEDOT;
	else	new.tf_Flags |= FPF_TALLDOT;

	for(x= 0; x<256; x++){		/* Make the widening table: */
		widtab[x]= 0;		/* (Look up a byte, get a bbyyttee) */
		for(y= 0; y<8; y++)
			if(x&(1<<y))
				widtab[x] |= 3 << (y+y);
	}

	/* space for the new character data */
	wp= (unsigned short *)malloc(new.tf_YSize*new.tf_Modulo);
	aver(wp ,noroom);

	new.tf_CharData= (APTR)wp;		/* Copy and widen: */
	cp= (unsigned char *)(tf->tf_CharData);
	for(y= 0; y<tf->tf_YSize; y++)		/* For each (long) scanline */
		for(x= 0; x<tf->tf_Modulo; x++)
			*wp++= widtab[*cp++];	/* Widen chars to shorts */

	y= tf->tf_HiChar + 2 - tf->tf_LoChar;	/* Number of chars in font */

	/* Widen and copy the other tables */
	new.tf_CharLoc= duexshort(tf->tf_CharLoc, y+y);
	if(tf->tf_CharSpace)
		new.tf_CharSpace= duexshort(tf->tf_CharSpace, y);
	if(tf->tf_CharKern)
		new.tf_CharKern= duexshort(tf->tf_CharKern, y);
}
addr(at, cp)long *at; char *cp;{
	/* Add a relocation datum, in hackish imitation of an assembler */
	/* When loaded, the contents of at is the address of cp		*/

	*at= cp-fontab;			/* Location gets offset to data */
	cp= (char *)at;
	attab[attab[1]+3]= cp-fontab;	/* Offset to location		*/
	++attab[1];			/* Count of relocated stuff	*/
}
char *
bcopy(dp, sp, n)register char *dp, *sp;{
	/* Copy and return past end of copy */
	do
		*dp++= *sp++;
	while(--n);
	return dp;
}
makefont(tf)register struct TextFont *tf;{
	/* Put together the pieces for a font */

	static char rts[]= {0x70, 0xff, 0x4e, 0x75};	/* rts instruction */
	register struct DiskFontHeader *dfh;
	register char *cp, *name;
	register n, size;

	/* This is the relocation hunk--start it empty */
	attab[0]= 0x3EC; attab[1]= 0; attab[2]= 0;

	/* How long is the font?  */
	n= tf->tf_HiChar + 2 - tf->tf_LoChar;
	size= 4 + sizeof(*dfh) + tf->tf_Modulo*tf->tf_YSize + 4*n;
	if(tf->tf_CharSpace)size+= sizeof(short)*n;
	if(tf->tf_CharKern)size+= sizeof(short)*n;

	fontab= (char *)malloc(size);	/* Get and clear the font space */
	if(!fontab)return 0;
	cp= fontab+size;
	do
		*--cp= 0;
	while(cp>fontab);

	/* Start with 'return 0' (fonts look just like executables) */
	bcopy(fontab, rts, 4);

	/* Next comes this structure: */
	dfh= (struct DiskFontHeader *)(&fontab[4]);
	dfh->dfh_DF.ln_Type= NT_FONT;
	addr(&dfh->dfh_DF.ln_Name, dfh->dfh_Name);
	dfh->dfh_FileID= DFH_ID;
	dfh->dfh_Revision= 1;
	dfh->dfh_Segment= 0;
	strncpy(dfh->dfh_Name,tf->tf_Message.mn_Node.ln_Name,MAXFONTNAME);

	dfh->dfh_TF= *tf;
	dfh->dfh_TF.tf_Message.mn_Node.ln_Succ= 0;
	dfh->dfh_TF.tf_Message.mn_Node.ln_Pred= 0;
	dfh->dfh_TF.tf_Message.mn_Node.ln_Type= NT_FONT;
	addr(&dfh->dfh_TF.tf_Message.mn_Node.ln_Name, dfh->dfh_Name);
	dfh->dfh_TF.tf_Message.mn_ReplyPort= 0;
	dfh->dfh_TF.tf_Accessors= 0;

	/* Now comes font data--copy it in */
	cp= fontab + sizeof(*dfh) + sizeof(long);

	addr(&dfh->dfh_TF.tf_CharData, cp);
	cp= bcopy(cp, tf->tf_CharData, tf->tf_Modulo*tf->tf_YSize);

	addr(&dfh->dfh_TF.tf_CharLoc, cp);
	cp= bcopy(cp, tf->tf_CharLoc, n*2*sizeof(short));

	if(tf->tf_CharSpace){
		addr(&dfh->dfh_TF.tf_CharSpace, cp);
		cp= bcopy(cp, tf->tf_CharSpace, n*sizeof(short));
	}
	if(tf->tf_CharKern){
		addr(&dfh->dfh_TF.tf_CharKern, cp);
		cp= bcopy(cp, tf->tf_CharKern, n*sizeof(short));
	}
	/* Now set the size of all this stuff */
	dfh->dfh_TF.tf_Message.mn_Length= cp - ((char *)(&dfh->dfh_TF));

	return size;
}
writehunx(fd, cp, size)BPTR fd; char *cp;{
	/* Write the font hunks */
	static long hunkstat[]= {	/* Pre-canned program header */
	0x000003F3, 0x00000000, 0x00000001, 0x00000000,
	0x00000000, 0x000000FE, 0x000003E9, 0x000000FE};

    	size= (size+3) >>2;
	hunkstat[5]= size;	/* Put sizes in the header */
	hunkstat[7]= size;	/* (now we pretend we're a linker) */

	/* Write the header */
	if(Write(fd, hunkstat, sizeof(hunkstat))<0)return 0;

	/* Font body as a code hunk */
	if(Write(fd, cp, size<<2)<0)return 0;

	/* Relocation hunk */
	attab[attab[1]+3]= 0;
	attab[attab[1]+4]= 0x3F2;
	if(Write(fd, attab, (attab[1]+5)<<2)<0)return 0;
}
