/*  :ts=8 bk=0
 *
 * nopaz.c:	Slaughter Topaz forever!
 *
 *		Compile under SAS/C 5.10b with:
 *		lc -cq -v -rr -L nopaz.c
 *
 * Leo L. Schwab			(415) 903-9321	9205.29
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/text.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/diskfont.h>


/***************************************************************************
 * Forward function prototypes.  (I hate ANSI.)
 */
void main (int, char **);
char *checkfont (int);
void removenopaz (void);
void copyfont (struct TextFont *, struct TextFont *);
struct FontPort *createfontport (void);
void deletefontport (struct FontPort *);
void openstuff (void);
void closestuff (void);
void die (char *);


/***************************************************************************
 * Structure definition.
 */
struct FontPort {
	struct MsgPort	fp_MsgPort;
	struct TextFont	fp_OldTopaz;
	struct TextFont	*fp_Replacer;
	char		fp_PortName[8];	/*  "_nopaz"  */
};


/***************************************************************************
 * Data.
 */
struct TextAttr	topaz = {
	(STRPTR) "topaz.font",
	8,
	FS_NORMAL,
	0
};

struct TextFont		*topaztf, *tf;
char			portname[] = "_nopaz";
char			err_openfail[] = "Couldn't open Topaz (!).\n";

struct GfxBase		*GfxBase;
struct Library		*DiskfontBase;

char			usage[] = "\0$VER: \
Nopaz 1.0 (8.6.92) -- Replace Topaz imagery.\n\
Written by Leo L. Schwab.\n\
This program is freely distributable.\n\
\n\
\2331mUSAGE:\233m\n\
\tNopaz <fontname> [ <pointsize> ] ; Replace Topaz imagery.\n\
\tNopaz -q\t\t\t ; Restore original Topaz imagery.\n\
";


/***************************************************************************
 * Code.
 */
void
main (ac, av)
int	ac;
char	**av;
{
	struct FontPort	*fp;
	struct TextAttr	ta;
	int		ysize;
	char		*err, name[40];

	if (ac < 2)
		die (&usage[7]);

	openstuff ();

	/*
	 * Check to see if we're to remove changes.
	 */
	if (!stricmp (av[1], "-q")) {
		removenopaz ();
		goto cleanexit;
	}

	/*
	 * Collect arguments.
	 */
	strcpy (name, av[1]);
	strcat (name, ".font");

	if (ac >= 3) {
		ysize = atoi (av[2]);
		if (!ysize)
			die ("Bad point size.\n");
	} else
		ysize = 8;

	/*
	 * Create TextAttr structures and open fonts.
	 */
	topaz.ta_YSize = ysize;
	if (!(topaztf = OpenFont (&topaz)))
		die (err_openfail);
	if (!(topaztf->tf_Flags & FPF_ROMFONT))
		die ("Disk-based copies of Topaz cannot be replaced.\n");

	ta.ta_Name	= name;
	ta.ta_YSize	= ysize;
	ta.ta_Style	= FS_NORMAL;
	ta.ta_Flags	= FPF_ROMFONT | FPF_DISKFONT | FPF_DESIGNED;

	if (tf = OpenFont (&ta))
		if (checkfont (ysize)) {
			CloseFont (tf);
			tf = NULL;
		}

	if (!tf) {
		if (!(tf = OpenDiskFont (&ta)))
			die ("Failed to open requested font.\n");
		if (err = checkfont (ysize))
			die (err);
	}

	/*
	 * Well, I *guess* it's okay...  Create placeholder.
	 */
	if (!(fp = createfontport ()))
		die ("Can't create FontPort.\n");
	CopyMem (topaztf, &fp->fp_OldTopaz, sizeof (*topaztf));
	fp->fp_Replacer = tf;

	/*
	 * Obliterate Topaz.  (Ahhhhh.....)
	 */
	copyfont (tf, topaztf);
	tf = NULL;			/*  Prevent it from unloading.	*/

cleanexit:
	closestuff ();
	exit (0);
}

char *
checkfont (ysize)
int	ysize;
{
	/*
	 * Sanity checks.
	 */
	if (tf->tf_YSize != ysize)
		return ("Requested font size not available.\n");

	if (tf->tf_XSize & FPF_PROPORTIONAL  ||
	    tf->tf_CharSpace  ||
	    tf->tf_CharKern)
		return ("Proportional fonts not allowed.\n");

	if (tf->tf_Style & FSF_COLORFONT)
		return ("Color fonts not allowed.\n");

	if (tf->tf_YSize != topaztf->tf_YSize  ||
	    tf->tf_XSize != topaztf->tf_XSize)
		return ("Size mismatch between Topaz and requested font.\n");

	return (NULL);
}

void
removenopaz ()
{
	register struct FontPort	*fp;

	while (fp = FindPort (portname)) {
		/*
		 * Open the version of Topaz that we stepped on.
		 */
		topaz.ta_YSize = fp->fp_OldTopaz.tf_YSize;
		if (!(topaztf = OpenFont (&topaz)))
			die (err_openfail);
		if (topaztf->tf_YSize != fp->fp_OldTopaz.tf_YSize)
			die ("Restoration size mismatch!\n");

		/*
		 * Put Topaz back.  (Why?)
		 */
		copyfont (&fp->fp_OldTopaz, topaztf);

		/*
		 * Close the font we opened to replace it.
		 */
		CloseFont (fp->fp_Replacer);
		CloseFont (topaztf), topaztf = NULL;

		/*
		 * Free the placeholder.
		 */
		deletefontport (fp);
	}
}


/***************************************************************************
 * Copies only the relevant fields of the TextFont structure over.
 * Forces the destination to FPF_ROMFONT.
 */
void
copyfont (src, dest)
register struct TextFont	*src, *dest;
{
	dest->tf_YSize		= src->tf_YSize;
	dest->tf_XSize		= src->tf_XSize;
	dest->tf_Style		= src->tf_Style;
	dest->tf_Baseline	= src->tf_Baseline;
	dest->tf_BoldSmear	= src->tf_BoldSmear;
	dest->tf_LoChar		= src->tf_LoChar;
	dest->tf_HiChar		= src->tf_HiChar;
	dest->tf_CharData	= src->tf_CharData;
	dest->tf_Modulo		= src->tf_Modulo;
	dest->tf_CharLoc	= src->tf_CharLoc;

	src->tf_Flags	|= dest->tf_Flags & FPF_ROMFONT;
	dest->tf_Flags	= src->tf_Flags & ~FPF_DISKFONT;
}


/***************************************************************************
 * FontPort handling.  FontPorts are used as placeholders, if the user
 * should for some preposterous reason wish to restore the original Topaz
 * imagery.
 */
struct FontPort *
createfontport ()
{
	register struct FontPort	*fp;

	if (!(fp = AllocMem (sizeof (*fp), MEMF_CLEAR | MEMF_PUBLIC)))
		return (NULL);

	fp->fp_MsgPort.mp_Node.ln_Name	= fp->fp_PortName;
	fp->fp_MsgPort.mp_Node.ln_Pri	= 0;
	fp->fp_MsgPort.mp_Node.ln_Type	= NT_MSGPORT;
	fp->fp_MsgPort.mp_Flags		= PA_IGNORE;
	strcpy (fp->fp_PortName, portname);

	AddPort (fp);
	return (fp);
}

void
deletefontport (fp)
register struct FontPort	*fp;
{
	register void	*msg;

	if (fp) {
		RemPort (fp);

		/*
		 * Just in case someone got cute.
		 */
		while (msg = GetMsg (fp))
			ReplyMsg (msg);

		FreeMem (fp, sizeof (*fp));
	}
}


/***************************************************************************
 * Housekeeping.
 */
void
openstuff ()
{
	if (!(GfxBase = OpenLibrary ("graphics.library", 0)))
		die ("Can't open graphics.\n");

	if (!(DiskfontBase = OpenLibrary ("diskfont.library", 0)))
		die ("Can't open diskfont.library.\n");
}

void
closestuff ()
{
	if (tf)			CloseFont (tf);
	if (topaztf)		CloseFont (topaztf);
	if (DiskfontBase)	CloseLibrary (DiskfontBase);
	if (GfxBase)		CloseLibrary (GfxBase);
}

void
die (str)
char *str;
{
	extern long	Output();
	register LONG	fh;

	if (fh = Output ())
		Write (fh, str, (long) strlen (str));
	closestuff ();
	exit (20);
}
