/* Amiga Type Engine 1.5 (BETA 5)

   Perpetrated by OPTIMUS PRIME, AUTOBOT Commander
   (Also known as Gordon Fecyk)

   Source is specific for DICE C 3.0 for the Amiga.  Requires
   postlib.h and post.library 1.7 by Adrian Ayward.  Also works
   with HWGPOST.

   Additions since 1.0:
   better CharKern handling so weird italic characters don't suffer from tail chop
   use of .AFM files and ATEencoding.ps instead of typeface itself to improve
       rendering speed and character spacing

   Additions since 1.2:
   better soft style handling.  I change fonts in the Text() patch now, to
       accomodate stupid programs that don't even try to load styles other than
       the plain style, then SetSoftStyle() them
   AvailFonts() patch to avoid requiring stupid .font files, and an attempt
       to reduce disk access by intercepting AvailFonts() calls with a zero buffer

   Additions for 1.3c
   More efficient searches through the fontlist; since the patches do searches,
       why does the mainline need to?

   Additions for 1.3d
   Crude CLI detachment via Execute(argv[0], 0, 0) which actually works.
   Minor char chop fixing, but it chops on the other side now. Arrgh.
   Beginning of parameter passing via public message port, facility
       to add more parameters as needed.
   No more breaking via CTRL-C: must type ATE -exit to break.
   Now can run from Workbench!!!!

   Additions for 1.4
   Removed all references to callextfunc, so I no longer need several
       functions that the PostScript code uses.
   Began introducing more parameters into parameter handler, introduced
       -trace and -debug.
   Introduced function to rebuild ATE font lists upon adding or removing
       typefaces, and for changing the AvailFonts size options.
   Improved character rendering which takes about 2/3 the original time
       to draw!  FAAAAST!
   Expunge patch for post.library added.  In a low memory panic, ATE will
       free up unused TextFonts and FontNodes.

   New for 1.5:
   Modifications for HWG version of post (V22).  This requires post V22
       to operate along with the various extensions for this library.
   Support for ta_DeviceDPI following Commodore's misguided spec
   Support for NewScaledDiskFont() following a slightly better spec

*/

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <exec/libraries.h>
#include <clib/exec_protos.h>
#include <dos/dos.h>
#include <graphics/rastport.h>
#include <graphics/text.h>
#include <diskfont/diskfont.h>
#include <clib/utility_protos.h>
#include <utility/tagitem.h>
#include "hwgpostlib.h"

/* Set to TRUE for printing PostScript debugging messages */
	BOOL		optTrace;
	BOOL		optDebug;
/* Another BOOL for allowing software styles on ATE fonts */
	BOOL		optSoftStyles;
/* Default density of untagged fonts */
	int		defaultDPI;

/* PostScript external data */
struct	Library		*PSbase;		/* Library struct for post.library */
struct	PSparm		*psParm;		/* For some stupid reason this needs */
						/* to be external.  Thanks Adrian. */
	int		psActivation;		/* Record for PS activation */
	int		psError;		/* Error checking for each PS call */
	char		nameBuffer[100 + 5];	/* Bogus space for PS initalization */

/* end of PostScript external data (I hope) */

/* External pointers for system patches */
struct	Library		*diskfontBase;
struct	Library		*gfxBase;

/* This is an extended diskfont header with two longwords preceeding it.
   This is for the NewScaledDiskFont patch but it will apply to all
   ATE fonts, just to streamline some of the code.  Normal FontNodes
   won't use this extra data. */
struct	ExtDFHeader {
		ULONG		edf_Length;
		ULONG		edf_NextSeg;	/* This will be zero */
	struct	DiskFontHeader	edf_DFHeader;	/* Including TextFont */
	};

/* FontNode struct, holds all data specific to a built TextFont */
struct	FontNode {
	/* basic Node struct for searches */
	struct	Node		fn_Node;
	/* format for fn_Name: "%50s / %5d / %2x" for "name / size / style" */
	/* fn_Name is mainly used for node searching */
		char		fn_Name[64];
	/* As of Beta 3B, this is in to prevent re-opening of error-prone fonts */
		BOOL		fn_BlackList;
	/* Set to non-zero if a certain character exists already */
		char		fn_BuiltChars[256];
	/* Data POST uses */
		int		fn_LowChar, fn_HighChar;
		int		fn_OptBaseLine, fn_BaseLine;
		int		fn_NominalWidth, fn_NominalCount;
		char		fn_OptFontEncoding, fn_TypefaceName[64];
		int		fn_MaxFontLength, fn_MaxCharLength;
		int		fn_MaxModulo, fn_MaxWidth, fn_ActWidth;
		int		fn_NomCount, fn_NomWidth;
		int		fn_BaseLength, fn_FontSize;
		UBYTE		fn_Style;
	/* Bounding box & graphic position info */
		int		fn_CharWidths[256];
		int		fn_LowLeftX[256], fn_LowLeftY[256];
		int		fn_UpRightX[256], fn_UpRightY[256];
		int		fn_CharPosX, fn_CharPosY;
	/* XDPI generated from (ta_XDPI / ta_YDPI) * defaultDPI
	   as per Commodore spec */
		int		fn_XDPI;
	/* Pointers to data areas in the TextFont struct */
		char		*fn_CharData, *fn_CharFontName;
		short		*fn_CharLoc, *fn_CharSpace, *fn_CharKern;
	/* Heinz says I can use multiple page descriptions now.  Not. */
//	struct	PSdevice	fn_Page;
	/* Ptr to a diskfont header with an 8 byte prefix (Seglist header) */
	struct	ExtDFHeader	*fn_ExtDFHeader;
	/* The TextFont in question */
	struct	TextFont	*fn_TextFont;	/* Within fn_extDFHeader */
	/* the TextFont will soon immediately follow the FontNode struct */
	};

/* modes for fn_BuiltChars */
#define	CHAR_NOT_DRAWN	0
#define	CHAR_DRAWN	2
#define	CHAR_NEEDED	1

/* ATEFontList struct, contains a Semaphore and the FontList itself */
struct	ATEFontList {
	struct	SignalSemaphore	ateSemaphore;
	struct	List		fontList;
	};

/* One external pointer so the patches can search the list */
struct	ATEFontList	*ateFontList;

/* Simple fcn that generates an OpenCount of all ATE fonts in use */
	int		CountOpenFonts(void);

/* Logic behind ATEAvailFonts struct:
      Stores enough data to build AvailFonts structs for the AvailFonts()
   patch.  PrepAvailFonts() builds this structure from the size max and
   size increment values, and the _ATE_ names fount in FONTS:.
      Because changes can happen anytime, I set aside an external Semaphore
   to protect the ptr to this data, as even the ptr can change at any time.
      TextAttrs use pointers to names, not the names themselves.  So the names
   need to be in that memory space somewhere.  I work around diskfont.library's
   AvailFonts() call by spotting the temporary AvailFontsHeader in the middle
   of the memory pool, then call it with the original parameters, and copy
   the NumEntries value.  Then I add my extra data at the end of where 
   diskfont.library put its extra data, and fill in the beginning of the pool
   with my (T)AvailFonts, NumEntries plus numTAs, then exit. (whew.) 

   ***** This is the buggiest part, even though I tested it many times,
   some apps just don't like it. I think the apps are broken. */

/* ATEAvailFonts struct, contains needed info for AvailFonts() patch */
struct	ATEAvailFonts {
		int		aaf_SizeDiskFonts;  /* Memory for diskfonts before ATE */
		int		aaf_SizeATEFonts;   /* Memory for all ATE TTextAttrs */
		int		aaf_SizeATEData;    /* Size of fontname & tag data */
	struct	TagItem		aaf_ATETags[2];	    /* Taglist for ATE TTextAttrs */
		char		*aaf_FontNames;     /* ptr to start of ATE fontnames */
		int		aaf_NumNames;       /* total all unique ATE fontnames */
		int		aaf_SizeInc;        /* Point size increment */
		int		aaf_SizeMax;	    /* Maximum point size */
/*		char		aaf_FontNames[][32];   Start of font names */
	/* memory sizes based on TAvailFonts structures, just to be safe */
	};

/* One external pointer for ATEAvailFonts for other processes to see */
struct	ATEAvailFonts	*ateAvailFonts;
/* Semaphore to allow safe access */
struct	SignalSemaphore	aafSemaphore;
/* Here's the fcn that builds this struct.
   diskfont size of zero means hide all Amiga diskfonts */
struct	ATEAvailFonts	*PrepATEAvailFonts(int sizeMax, int sizeInc, int diskfontSize);

/* An external for the encoding array */
	char		encodingExternal[256][24];

/* Message structures, all based on my extended Message struct ATEMessage */
struct	ATEMessage {
	struct	Message		ate_Message;
		int		ate_MsgLength;
	struct	MsgPort		*ate_DestPort;
	};

struct	DiskfontMsg {
	struct	ATEMessage	df_ATEMsg;
	struct	TextAttr	*df_TextAttr;
	struct	FontNode	*df_FontNode;
	struct	TextFont	*df_TextFont;
		BOOL		df_ATEFont;
	};

struct	NsdfMsg {
	struct	ATEMessage	nsdf_ATEMsg;
	struct	TextFont	*nsdf_TextFont;
	struct	TextAttr	*nsdf_TextAttr;
	struct	DiskFontHeader	*nsdf_DFHeader;
	};

struct	TextMsg {
	struct	ATEMessage	tm_ATEMsg;
	struct	RastPort	*tm_RastPort;
	struct	FontNode	*tm_FontNode;
		STRPTR		tm_Chars;
		WORD		tm_Length;
		BOOL		tm_ATEFont;
	};

struct	SSStyleMsg {
	struct	ATEMessage	ss_ATEMsg;
	struct	RastPort	*ss_RastPort;
		ULONG		ss_NewStyle;
		ULONG		ss_Enable;
	struct	TextFont	*ss_ChangedFont;
	struct	FontNode	*ss_FontNode;
		ULONG		ss_SoftStyleNeeded;
		BOOL		ss_ATEFont;
	};

struct	CommandMsg {
	struct	ATEMessage	cm_ATEMsg;
		int		cm_ArgC;
		char		**cm_ArgV;
		BOOL		cm_Result;
	};

/* Ptrs to MsgPorts internal to ATE */
struct	MsgPort		*ateODFPort, *ateTextPort, *ateSSSPort, *ateNSDFPort;

/* Signal info for the Expunge() patch, for this task
   and the allocated signal */
struct	Task		*ateMainTask;
	BYTE		ateDfeSigBit;

/* Prototypes of system patches and original functions */
__geta4 __regargs struct TextFont	*NewOpenDiskFont(__A0 struct TextAttr *textAttr, __A6 struct Library *libBase);
__geta4		  struct TextFont	*(*OldOpenDiskFont)(__A0 struct TextAttr *textAttr, __A6 struct Library *libBase);
__geta4	__regargs	 void		NewText(__A1 struct RastPort *rastPort, __A0 STRPTR textString, __D0 WORD length, __A6 struct Library *libBase);
__geta4		  	 void		(*OldText)(__A1 struct RastPort *rastPort, __A0 STRPTR textString, __D0 WORD length, __A6 struct Library *libBase);
__geta4	__regargs	 ULONG		NewSSStyle(__A1 struct RastPort *rastPort, __D0 ULONG newStyle, __D1 ULONG enable, __A6 struct Library *libBase);
__geta4			 ULONG		(*OldSSStyle)(__A1 struct RastPort *rastPort, __D0 ULONG newStyle, __D1 ULONG enable, __A6 struct Library *libBase);
__geta4 __regargs	 LONG		NewAvailFonts(__A0 struct AvailFontsHeader *afhBuffer, __D0 LONG afBufSize, __D1 ULONG afFlags, __A6 struct Library *libBase);
__geta4			 LONG		(*OldAvailFonts)(__A0 struct AvailFontsHeader *afhBuffer, __D0 LONG afBufSize, __D1 ULONG afFlags, __A6 struct Library *libBase);
__geta4	__regargs	 ULONG		NewDFbaseExpunge(__A6 struct Library *libBase);
__geta4			 ULONG		(*OldDFbaseExpunge)(__A6 struct Library *libBase);
__geta4 __regargs struct DiskFontHeader *NewNSDF(__A0 struct TextFont *tf, __A1 struct TextAttr *ta, __A6 struct Library *libBase);
__geta4		  struct DiskFontHeader *(*OldNSDF)(__A0 struct TextFont *tf, __A1 struct TextAttr *ta, __A6 struct Library *libBase);

/* These were a misguided attempt to work around a bug in Deluxe Video III */
//__geta4 __regargs	 WORD		NewTextLength(__A1 struct RastPort *rastPort, __A0 STRPTR aString, __D0 WORD strCount, __A6 struct Library *libBase);
//__geta4		 WORD		(*OldTextLength)(__A1 struct RastPort *rastPort, __A0 STRPTR aString, __D0 WORD strCount, __A6 struct Library *libBase);
//__geta4 __regargs struct TextExtent	*NewTextExtent(__A1 struct RastPort *rastPort, __A0 STRPTR aString, __D0 WORD strCount, __A2 struct TextExtent *te);
//__geta4	    struct TextExtent	*(*OldTextExtent)(__A1 struct RastPort *rastPort, __A0 STRPTR aString, __D0 WORD strCount, __A2 struct TextExtent *te, __A6 struct Library *libBase);

/* Message sender for the above patches */
			 BOOL		ATESendMsg(struct ATEMessage *ateMsg);

/* A couple of dead functions not in here anymore */
//		  struct FontNode	*SwapSoftStyle(struct RastPort *rp);
//			 void		UndoSwapSoftStyle(struct RastPort *rp, struct TextFont *tf, UBYTE softStyle);

/* Functions for the PostScript interface and tracing */
	void		PSTrace(char *format, ...);
	void		PSIntf(char *format, ...);

/* Functions to simplify some loops, these do most of the PostScript gruntwork */
struct	TextFont	*MakeATEFont(struct FontNode *fontNode, struct TextAttr *textAttr);
	BOOL		MakeATEChars(struct FontNode *fontNode);

/* Functions from older versions of ATEServer (with a new one: AddATEStyle) */
	void		chkabort(void) { return; };	/* Kill CTRL-C handler */
	void		ClearFontNames(struct List *fontList);
	BOOL		AddATEFont(struct List *fontList, struct DiskfontMsg *diskfontMsg);
	BOOL		AddATEStyle(struct List *fontList, struct SSStyleMsg *sssMsg);
	BOOL		AddATEChars(struct List *fontList, struct TextMsg *textMsg);
struct	DiskFontHeader	*BuildScaledDiskFont(struct TextFont *textFont, struct TextAttr *textAttr);
	void		ClearUnusedATEFonts(struct FontList *fontList);

/* One fcn which is the main process */
	int		ATEmain(struct Task *callingTask, BYTE okSigBit, BYTE failSigBit);

/* external file handle for ATE output */
	FILE		*ateOutput;

/* wbmain() entry point, supposed to read tooltypes and start ATE 
   with tooltypes options.  In future will include a user interface
   and perhaps become a commodity */

int wbmain(struct WBStartup *wbMsg)
{
struct	MsgPort		*ateCmdPort;
	char		*ateCmdPortName = "ATE_Cmd_Port";
	int		exitCode;
	char		*argv[2];
struct	CommandMsg	*ateCmdMsg;
	BOOL		ateStartSuccess;

	/* Ok, this makes one VERY BIG assumption that the msgport won't go away
	   after I find it.  This makes sense because the only way you can
	   break ATE is to send an exit message to it. */
	Forbid();
	ateCmdPort = FindPort(ateCmdPortName);
	Permit();
	
	if (ateCmdPort == 0)
	{
		/* Since this was run from Workbench or WBStartup, I can run
		   ATE without having to detach from anything. */
		ateOutput = fopen("CON:0/0/600/75/ATE Message/AUTO/WAIT", "w");
		if (ateOutput != 0)
		{
//			fprintf(ateOutput, "Starting ATE... when you see ATE Ready you can close this window.\n");
//			fprintf(ateOutput, "Double-click this icon again to exit ATE.\n");
			fflush(ateOutput);
			exitCode = ATEmain(0, 0, 0);
			/* This will immediately exit upon returning from ATEmain() */
			fclose(ateOutput);
			return(exitCode);
		}
	}
	else
	{
		/* Send -exit parameter to ATE, but first build the thing */
		ateCmdMsg = (struct CommandMsg *)AllocVec(sizeof(struct CommandMsg) + 64, MEMF_PUBLIC | MEMF_CLEAR);
		if (ateCmdMsg != 0)
		{
			argv[0] = (char *)&ateCmdMsg[1];
			argv[1] = argv[0] + 32;
			strcpy(argv[1], "-exit");
			strcpy(argv[0], "ATEbeta5");
			ateCmdMsg->cm_ATEMsg.ate_MsgLength = sizeof(struct CommandMsg);
			ateCmdMsg->cm_ATEMsg.ate_DestPort = ateCmdPort;
			ateCmdMsg->cm_ArgC = 2;
			ateCmdMsg->cm_ArgV = argv;
			ateStartSuccess = ATESendMsg((struct ATEMessage *)ateCmdMsg);
			if (ateStartSuccess == FALSE)
				exitCode = 20;
			else
				exitCode = 0;
			FreeVec(ateCmdMsg);
		}
	}
	return(exitCode);
}

/* command line entry point, looks for an existing port and passes
   arguments to it, otherwise it starts the ATE mainline */

int main(int argc, char *argv[])
{
struct	MsgPort		*ateCmdPort;
struct	CommandMsg	*ateCmdMsg;
	char		*ateCmdPortName = "ATE_Cmd_Port";
	char		startAteCmdLine[80];
	BOOL		ateStartSuccess;
	int		exitCode = 0;
struct	Task		*callingTask = (struct Task *)0;
	BYTE		okSigBit, failSigBit;
	ULONG		okSig, failSig, signal;

	/* Ok, this makes one VERY BIG assumption that the msgport won't go away
	   after I find it.  This makes sense because the only way you can
	   break ATE is to send an exit message to it. */
	Forbid();
	ateCmdPort = FindPort(ateCmdPortName);
	Permit();
	
	if (ateCmdPort == 0)
	{
		/* Check for "-start" parameter, if so, call ATEmain() */
		if (argc > 1)
		{
			if (strcmp(argv[1], "-start") == 0)
			{
				ateOutput = fopen("CON:0/0/600/75/ATE Message/AUTO/WAIT", "w");
				if (ateOutput != 0)
				{
					callingTask = (struct Task *)atoi(argv[2]);
					okSigBit = (BYTE)atoi(argv[3]);
					failSigBit = (BYTE)atoi(argv[4]);
					exitCode = ATEmain(callingTask, okSigBit, failSigBit);
					/* This will immediately exit upon returning from ATEmain() */
					fclose(ateOutput);
					return(exitCode);
				}
			}
		}
		/* No message port found, send command with "-start" parameter */
		callingTask = FindTask(0);
		okSigBit = AllocSignal(-1);
		failSigBit = AllocSignal(-1);

		sprintf(startAteCmdLine, "Run >nil: <nil: %s -start %d %d %d",
			argv[0], callingTask, okSigBit, failSigBit);

		ateStartSuccess = Execute(startAteCmdLine, 0, 0);
		if (ateStartSuccess == FALSE)
			exitCode = 20;
		else
		{
			printf("ATE started... type %s -exit to terminate ATE.\n", argv[0]);
			printf("Amiga Typeface Engine BETA 1.5\n");

			/* Now wait on the signals then send parameters */

			okSig = 1 << okSigBit;
			failSig = 1 << failSigBit;
			signal = Wait(okSig | failSig);

			if (signal & okSig)
			{
				exitCode = 0;
				/* Obtain the new port ptr now */
				Forbid();
				ateCmdPort = FindPort(ateCmdPortName);
				Permit();
			}
			else
				exitCode = 20;
			FreeSignal(okSigBit);
			FreeSignal(failSigBit);
		}
	}
	if (argc > 1 && exitCode == 0)
	{
		/* There's an active ATE now running, pass parameters to it */
		ateCmdMsg = (struct CommandMsg *)AllocVec(sizeof(struct CommandMsg), MEMF_PUBLIC | MEMF_CLEAR);
		if (ateCmdMsg != 0 && ateCmdPort != 0)
		{
			ateCmdMsg->cm_ATEMsg.ate_MsgLength = sizeof(struct CommandMsg);
			ateCmdMsg->cm_ATEMsg.ate_DestPort = ateCmdPort;
			ateCmdMsg->cm_ArgC = argc;
			ateCmdMsg->cm_ArgV = argv;
			ateStartSuccess = ATESendMsg((struct ATEMessage *)ateCmdMsg);
			if (ateStartSuccess == FALSE)
			{
				printf("No active ATE to send messages to...\n");
				exitCode = 20;
			}
			else
			{
				printf("Updated parameters sent OK\n");
				exitCode = 0;
			}
			FreeVec(ateCmdMsg);
		}
		else
		{
			if (ateCmdMsg == 0)
				printf("Not enough memory to send any messages\n");
			if (ateCmdPort == 0)
				printf("No active ATE to send messages to.\n");
			ateStartSuccess = FALSE;
			exitCode = 20;
		}
	}
	else if (callingTask == 0)
	{
		printf(	"ATE Beta 5 already active\n"
			"Usage: %s -arguments\n"
			"================================\n"
			"-(no)trace          Hide or Show trace messages in code, default NO\n"
			"-(no)debug          Hide or Show all PS commands executed, default NO\n"
			"-hidediskfonts      Show only loaded fonts and ATE fonts to apps\n"
			"-showdiskfonts      Show all Amiga and ATE fonts to apps (default)\n"
			"-softstyleson       Enable algorithmic styles on ATE fonts\n"
			"-softstylesoff      Disable algorithmic styles on ATE fonts (default)\n"
			"-availfonts SM SI   Show what sizes of ATE fonts appear in lists\n"
			"                    SM = size maximum, SI = size increment\n"
			"                    72 and 6 default, shows sizes\n"
			"                    6 12 18 24 30 36 42 48 54 60 66 72\n"
			"-dpi DPI            Change display resolution of ATE fonts\n"
			"                    DPI = dots per inch on screen.  Default 72\n"
			"                    Must close all apps using ATE before using -dpi\n"
			"-exit               Unloads all ATE fonts and exits ATE\n"
			"                    Must close all apps using ATE before using -exit\n"
			"================================\n"
			"You can use many arguments on the same command line.\n"
			"All arguments work in startup as well.\n", argv[0]);
		exitCode = 0;
	}
	return(exitCode);
}

/* Mainline of code */
int ATEmain(struct Task *callingTask, BYTE okSigBit, BYTE failSigBit)
{
	APTR		oldFuncPtr, newFuncPtr = &NewOpenDiskFont;
	APTR		oldTextPtr, newTextPtr = &NewText;
	APTR		oldSSSPtr, newSSSPtr = &NewSSStyle;
	APTR		oldAFPtr, newAFPtr = &NewAvailFonts;
	APTR		oldDFEPtr, newDFEPtr = &NewDFbaseExpunge;
	APTR		oldNSDFPtr, newNSDFPtr = &NewNSDF;
//	APTR		oldTLPtr, newTLPtr = &NewTextLength;
//	APTR		oldTEPtr, newTEPtr = &NewTextExtent;
	char		*versionInfo = "$VER:  AmigaTypeEngine_BETA 1.5 (13.8.95)";
	char		*moreInfo = "Written by Gordon Fecyk of Winnipeg / Calgary / Vancouver :)";
struct	MsgPort		*ateCmdPort;
struct	CommandMsg	*commandMsg;
struct	List		*fontList;
struct	SignalSemaphore	*ateSemaphore, *nafSemaphore = &aafSemaphore;
struct	DiskfontMsg	*diskfontMsg;
struct	TextMsg		*textMsg;
struct	SSStyleMsg	*sssMsg;
struct	NsdfMsg		*nsdfMsg;
	ULONG		signal, odfSig, textSig, sssSig, cmdSig, dfeSig, nsdfSig;
	BOOL		keepGoing = TRUE;
	FILE		*encodingFile, *nilInput;
	int		index, asciiValue, openCount, diskfontSize;
	char		readLine[100], charName[32];

	optTrace = FALSE;
	optDebug = FALSE;
	optSoftStyles = FALSE;
	defaultDPI = 72;
	/* Do as much allocating as practical then check for failures */
		/* Message ports */
	ateODFPort = CreateMsgPort();
	ateTextPort = CreateMsgPort();
	ateSSSPort = CreateMsgPort();
	ateCmdPort = CreateMsgPort();
	ateNSDFPort = CreateMsgPort();
	ateDfeSigBit = AllocSignal(-1);
		/* ATE font list */
	ateFontList = (struct ATEFontList *)AllocVec(sizeof(struct ATEFontList), MEMF_PUBLIC | MEMF_CLEAR);
		/* post.library (minimum V22) */
	PSbase = OpenLibrary("post.library", 22L);
		/* graphics and diskfont libraries (mininum V36) */
	diskfontBase = OpenLibrary("diskfont.library", 36L);
	gfxBase = OpenLibrary("graphics.library", 36L);
	diskfontSize = AvailFonts(readLine, 0, AFF_DISK | AFF_TAGGED);
	ateAvailFonts = PrepATEAvailFonts(72, 6, diskfontSize);
	psParm = (struct PSparm *)AllocVec(sizeof(struct PSparm), MEMF_PUBLIC | MEMF_CLEAR);

	/* check for failures */
	if (ateODFPort == 0 || ateTextPort == 0 || ateSSSPort == 0 || ateCmdPort == 0
	|| PSbase == 0 || gfxBase == 0 || diskfontBase == 0 || ateDfeSigBit == -1
	|| ateFontList == 0 || ateAvailFonts == 0 || psParm == 0 || ateNSDFPort == 0)
	{
		if (ateNSDFPort != 0)
			DeleteMsgPort(ateNSDFPort);
		else
			fprintf(ateOutput, "Error allocatine one message port\n");
		if (psParm != 0)
			FreeVec(psParm);
		else
			fprintf(ateOutput, "Error allocating RAM for PS struct \n");
		if (ateDfeSigBit != -1)
			FreeSignal(ateDfeSigBit);
		else
			fprintf(ateOutput, "Error obtaining a signal bit\n");
		if (ateCmdPort != 0)
			DeleteMsgPort(ateCmdPort);
		else
			fprintf(ateOutput, "Error opening command port\n");
		if (ateAvailFonts != 0)
			FreeVec(ateAvailFonts);
		else
			fprintf(ateOutput, "Error obtaining memory for ATEAvailFonts\n");
		if (ateSSSPort != 0)
			DeleteMsgPort(ateSSSPort);
		else
			fprintf(ateOutput, "Error opening one message port\n");
		if (ateODFPort != 0)
			DeleteMsgPort(ateODFPort);
		else
			fprintf(ateOutput, "Error opening one message port\n");
		if (ateTextPort != 0)
			DeleteMsgPort(ateTextPort);
		else
			fprintf(ateOutput, "Error opening one message port\n");
		if (PSbase != 0)
			CloseLibrary(PSbase);
		else
			fprintf(ateOutput, "Error opening post.library\n"
	    				   "You require V22 post.library (HWG)\n");
		if (ateFontList != 0)
			FreeVec(ateFontList);
		else
			fprintf(ateOutput, "Error allocating RAM for fontList\n");
		if (gfxBase != 0)
			CloseLibrary(gfxBase);
		else
			fprintf(ateOutput, "Error opening graphics.library\n");
		if (diskfontBase != 0)
			CloseLibrary(diskfontBase);
		else
			fprintf(ateOutput, "Error opening diskfont.library\n"
					   "This requires at least WB 2.04\n");
		if (callingTask != 0)
			Signal(callingTask, 1 << failSigBit);
		return(20);
	}

	/* initalize the PostScript activation */
	PSTrace("%%Initalizing PostScript Activation\n");
	psParm->page.buf[0] = nameBuffer;
	psParm->page.len = 100;
	psParm->page.depth = 1;
	psParm->page.xbytes = 10;
	psParm->page.xsize = 80;
	psParm->page.ysize = 10;
	psParm->page.xden = 72;
	psParm->page.yden = 72;
	psParm->page.ydir = -1;
	psParm->memvlen = 20000;
	psParm->memflen = 10000;
	psParm->memllen = defmemllen;
	psParm->memhlen = minmemhlen;
	/* This must be a real file handle (IE: "NIL:" in Beta 5) */
	nilInput = fopen("nil:", "r");
	psParm->infh = fdtofh(nilInput);
	psParm->outfh = fdtofh(ateOutput);
	psParm->errfh = fdtofh(ateOutput);
	/* I'm getting lazy... I like MEMF_CLEAR... :) */

	psActivation = PScreateact(psParm);
	if (psActivation <= errmax)
	{
		fprintf(ateOutput, "PostScript activation failed\n");
		DeleteMsgPort(ateNSDFPort);
		DeleteMsgPort(ateODFPort);
		DeleteMsgPort(ateTextPort);
		DeleteMsgPort(ateSSSPort);
		DeleteMsgPort(ateCmdPort);
		FreeSignal(ateDfeSigBit);
		FreeVec(psParm);
		FreeVec(ateFontList);
		FreeVec(ateAvailFonts);
		CloseLibrary(PSbase);
		CloseLibrary(gfxBase);
		CloseLibrary(diskfontBase);
		if (callingTask != 0)
			Signal(callingTask, 1 << failSigBit);
		return(20);
	}

	/* Run ATE startup files */
	PSTrace("%%All initalization passed, running PS startup & encoding files\n");
	PSIntf("(%.100s) run clear\n", "PSFonts:init.ps");
	if (psError != 0)
	{
		fprintf(ateOutput, "Error running initalization file,\n"
				    "check your PSFonts:init.ps file.\n");
	}

	PSIntf("/encoding StandardEncoding 256 array copy def\n");
	PSIntf("[ (%.100s) run] aload length 2 idiv\n", "PSFonts:ATEencoding.ps");
	PSIntf("{ encoding 3 1 roll put } repeat\n");
	PSIntf("/cstr 1 string def\n");
	if (psError != 0)
	{
		fprintf(ateOutput, "Error running initalization file,\n"
				   "check your PSFonts:ATEencoding.ps file.\n");
	}

	/* Read encoding file into memory */
	encodingFile = fopen("PSFonts:ATEencoding.ps", "r");
	if (encodingFile != 0)
	{
		while (!feof(encodingFile))
		{
			asciiValue = 0;
			charName[0] = 0;
			readLine[0] = 0;
			fgets(readLine, 100, encodingFile);
			sscanf(readLine, "%3d /%s\n", &asciiValue, charName);
			if (asciiValue != 0)
			{
				strcpy(encodingExternal[asciiValue], charName);
			}
		}
	}
	if (psError != 0 || encodingFile == 0)
	{
		fprintf(ateOutput, "Cannot parse ATEencoding.ps file\n");
		if (encodingFile != 0)
			fclose(encodingFile);
		DeleteMsgPort(ateNSDFPort);
		DeleteMsgPort(ateODFPort);
		DeleteMsgPort(ateTextPort);
		DeleteMsgPort(ateSSSPort);
		DeleteMsgPort(ateCmdPort);
		FreeSignal(ateDfeSigBit);
		FreeVec(psParm);
		FreeVec(ateFontList);
		FreeVec(ateAvailFonts);
		CloseLibrary(PSbase);
		CloseLibrary(gfxBase);
		CloseLibrary(diskfontBase);
		if (callingTask != 0)
			Signal(callingTask, 1 << failSigBit);
		return(20);
	}
	fclose(encodingFile);

//	fprintf(ateOutput, "Number of unique typefaces %d\n", ateAvailFonts->aaf_NumNames);

	/* Setup ports */
	odfSig = 1 << ateODFPort->mp_SigBit;
	textSig = 1 << ateTextPort->mp_SigBit;
	sssSig = 1 << ateSSSPort->mp_SigBit;
	cmdSig = 1 << ateCmdPort->mp_SigBit;
	nsdfSig = 1 << ateNSDFPort->mp_SigBit;
	dfeSig = 1 << ateDfeSigBit;
	ateODFPort->mp_Node.ln_Pri = 0;
	ateTextPort->mp_Node.ln_Pri = 0;
	ateSSSPort->mp_Node.ln_Pri = 0;
	ateCmdPort->mp_Node.ln_Pri = 0;
	ateNSDFPort->mp_Node.ln_Pri = 0;
	ateCmdPort->mp_Node.ln_Name = "ATE_Cmd_Port";
	AddPort(ateCmdPort);
	/* prepare list */
	fontList = &ateFontList->fontList;
	fontList->lh_Type = NT_USER;
	NewList(fontList);
	/* Prepare semaphores */
	ateSemaphore = &ateFontList->ateSemaphore;
	InitSemaphore(ateSemaphore);
	InitSemaphore(nafSemaphore);
//	fprintf(ateOutput, "ATE BETA 1.5 ready.\n");
	fflush(ateOutput);
	/* Grab the task ptr for the DFE signals */
	ateMainTask = FindTask(0);

	/* Perform patches */
	Forbid();
	oldFuncPtr = SetFunction(diskfontBase, -0x1E, newFuncPtr);
	OldOpenDiskFont = oldFuncPtr;
	oldTextPtr = SetFunction(gfxBase, -0x3C, newTextPtr);
	OldText = oldTextPtr;
	oldSSSPtr = SetFunction(gfxBase, -0x5A, newSSSPtr);
	OldSSStyle = oldSSSPtr;
	oldAFPtr = SetFunction(diskfontBase, -0x24, newAFPtr);
	OldAvailFonts = oldAFPtr;
	oldDFEPtr = SetFunction(diskfontBase, -0x12, newDFEPtr);
	OldDFbaseExpunge = oldDFEPtr;
	oldNSDFPtr = SetFunction(diskfontBase, -0x36, newNSDFPtr);
	OldNSDF = oldNSDFPtr;
//	oldTLPtr = SetFunction(gfxBase, -0x36, newTLPtr);
//	OldTextLength = oldTLPtr;
//	oldTEPtr = SetFunction(gfxBase, -0x2B2, newTEPtr);
//	OldTextExtent = oldTEPtr;
	Permit();
	/* I got the offsets from the included pragmas files. */

	/* Signal the calling process we're ready */
	if (callingTask != 0)
		Signal(callingTask, 1 << okSigBit);

	/* Begin main process loop */
	for (;;)
	{
		signal = Wait (textSig | odfSig | sssSig | dfeSig | cmdSig | nsdfSig);

		if ((signal & cmdSig))
		{
			/* Someone sent a command here. */
			while (commandMsg = (struct CommandMsg *)GetMsg(ateCmdPort))
			{
				if (commandMsg->cm_ArgC <= 1)
				{
					fprintf(ateOutput, "No parameters sent with command \n");
				}
				/* Several if() statements happen here for each parameter */
				else for (index = 1; index < commandMsg->cm_ArgC; index++)
				{
					if (strcmp(commandMsg->cm_ArgV[index], "-exit") == 0)
					{
						keepGoing = FALSE;
						break;
					}
					/* More if () statements for each argument
					   happen here, and mods happen accordingly */
					if (strcmp(commandMsg->cm_ArgV[index], "-trace") == 0)
						optTrace = TRUE;
					if (strcmp(commandMsg->cm_ArgV[index], "-notrace") == 0)
						optTrace = FALSE;
					if (strcmp(commandMsg->cm_ArgV[index], "-debug") == 0)
						optDebug = TRUE;
					if (strcmp(commandMsg->cm_ArgV[index], "-nodebug") == 0)
						optDebug = FALSE;
					if (strcmp(commandMsg->cm_ArgV[index], "-availfonts") == 0)
					{
						/* Make sure these are valid parameters */
						int	sizeMax, sizeInc, mySizeDiskFonts;

						index++;
						if (index < commandMsg->cm_ArgC)
							sizeMax = atoi(commandMsg->cm_ArgV[index]);
						else
							sizeMax = 0;
						index++;
						if (index < commandMsg->cm_ArgC)
							sizeInc = atoi(commandMsg->cm_ArgV[index]);
						else
							sizeInc = 0;

						if (sizeMax > sizeInc && sizeInc > 0)
						{
							/* make the call */
							ObtainSemaphore(nafSemaphore);
							mySizeDiskFonts = ateAvailFonts->aaf_SizeDiskFonts;
							FreeVec(ateAvailFonts);
							ateAvailFonts = 0;
							ateAvailFonts = PrepATEAvailFonts(sizeMax, sizeInc, mySizeDiskFonts);
							if (ateAvailFonts == 0)
							{
								fprintf(ateOutput, "Warning: System extremely low on memory\n");
								fflush(ateOutput);
								keepGoing = FALSE;
							}
							ReleaseSemaphore(nafSemaphore);
						}
						else
						{
							fprintf(ateOutput, "Usage for -availfonts:\n"
									   "-availfonts sizemax sizeinc\n");
							fflush(ateOutput);
						}
					}
					if (strcmp(commandMsg->cm_ArgV[index], "-dpi") == 0)
					{
						/* Make sure these are valid parameters */
						int	newDpi, sizeInc, sizeMax, mySizeDiskFonts;

						index++;
						if (index < commandMsg->cm_ArgC)
							newDpi = atoi(commandMsg->cm_ArgV[index]);
						else
							newDpi = 0;
						if (newDpi > 49)
						{
							/* check opencount */
							openCount = CountOpenFonts();
							if (openCount == 0)
							{
								ClearUnusedATEFonts(fontList);
								defaultDPI = newDpi;
								/* reset ATEAvailFonts */
								ObtainSemaphore(nafSemaphore);
								mySizeDiskFonts = ateAvailFonts->aaf_SizeDiskFonts;
								sizeInc = ateAvailFonts->aaf_SizeInc;
								sizeMax = ateAvailFonts->aaf_SizeMax;
								FreeVec(ateAvailFonts);
								ateAvailFonts = 0;
								ateAvailFonts = PrepATEAvailFonts(sizeMax, sizeInc, mySizeDiskFonts);
								if (ateAvailFonts == 0)
								{
									fprintf(ateOutput, "Warning: System extremely low on memory\n");
									fflush(ateOutput);
									keepGoing = FALSE;
								}
								ReleaseSemaphore(nafSemaphore);
							}
							else
							{
								fprintf(ateOutput,
								"Cannot change default DPI unless you close all apps\n"
								"using ATE fonts.\n");
								fflush(ateOutput);
							}
						}
						else
						{
							fprintf(ateOutput, "DPI choice set too small, use DPI greater than 50.\n");
							fflush(ateOutput);
						}
					}
					if (strcmp(commandMsg->cm_ArgV[index], "-hidediskfonts") == 0)
					{
						ObtainSemaphore(nafSemaphore);
						/* First check to see if diskfonts are
						   already hidden */
						if (ateAvailFonts->aaf_SizeDiskFonts != 0)
						{
							int	sizeMax, sizeInc;

							sizeMax = ateAvailFonts->aaf_SizeMax;
							sizeInc = ateAvailFonts->aaf_SizeInc;
							FreeVec(ateAvailFonts);
							ateAvailFonts = 0;
							ateAvailFonts = PrepATEAvailFonts(sizeMax, sizeInc, 0);
							if (ateAvailFonts == 0)
							{
								fprintf(ateOutput, "Warning: System extremely low on memory\n");
								fflush(ateOutput);
								keepGoing = FALSE;
							}
						}
						else
						{
							fprintf(ateOutput, "Amiga diskfonts already hidden.  No changes made.\n");
							fflush(ateOutput);
						}
						ReleaseSemaphore(nafSemaphore);
					}
					if (strcmp(commandMsg->cm_ArgV[index], "-showdiskfonts") == 0)
					{
						ObtainSemaphore(nafSemaphore);
						/* Check to see if we're already showing diskfonts */
						if (ateAvailFonts->aaf_SizeDiskFonts == 0)
						{
							int	mySizeDiskFonts, sizeMax, sizeInc;

							sizeMax = ateAvailFonts->aaf_SizeMax;
							sizeInc = ateAvailFonts->aaf_SizeInc;

							mySizeDiskFonts = OldAvailFonts(readLine, 0, AFF_DISK | AFF_TAGGED, diskfontBase);
							ateAvailFonts = 0;
							ateAvailFonts = PrepATEAvailFonts(sizeMax, sizeInc, mySizeDiskFonts);
							if (ateAvailFonts == 0)
							{
								fprintf(ateOutput, "Warning: System extremely low on memory\n");
								fflush(ateOutput);
								keepGoing = FALSE;
							}
						}
						else
						{
							fprintf(ateOutput, "Amiga diskfonts already visible.  No changes made.\n");
							fflush(ateOutput);
						}
						ReleaseSemaphore(nafSemaphore);
					}
					if (strcmp(commandMsg->cm_ArgV[index], "-softstyleson") == 0)
						optSoftStyles = TRUE;
					if (strcmp(commandMsg->cm_ArgV[index], "-softstylesoff") == 0)
						optSoftStyles = FALSE;
				}
				ReplyMsg((struct Message *)commandMsg);
			}
		}

		if (keepGoing == FALSE)
		{
			/* check open count */
			openCount = CountOpenFonts();
			if (openCount != 0)
			{
				fprintf(ateOutput,  "WARNING: Some apps have ATE fonts in use!\n"
					"Either close all apps using ATE fonts and try again,\n"
					"or simply reboot (ATE won't cause data loss).\n");
				fprintf(ateOutput, "ATE open font count: %d\n", openCount);
				fflush(ateOutput);
				keepGoing = TRUE;
			}
			else
			{
				RemPort(ateCmdPort);
				/* Clear out all ports */
				while (diskfontMsg = (struct DiskfontMsg *)GetMsg(ateODFPort))
				{
					diskfontMsg->df_ATEFont = FALSE;
					ReplyMsg((struct Message *)diskfontMsg);
				}
				while (textMsg = (struct textMsg *)GetMsg(ateTextPort))
				{
					textMsg->tm_ATEFont = FALSE;
					ReplyMsg((struct Message *)textMsg);
				}
				while (sssMsg = (struct sssMsg *)GetMsg(ateSSSPort))
				{
					sssMsg->ss_ATEFont = FALSE;
					ReplyMsg((struct Message *)sssMsg);
				}
				while (commandMsg = (struct CommandMsg *)GetMsg(ateCmdPort))
				{
					ReplyMsg((struct Message *)commandMsg);
				}
				while (nsdfMsg = (struct NSDFMsg *)GetMsg(ateNSDFPort))
				{
					ReplyMsg((struct Message *)nsdfMsg);
				}
				keepGoing = FALSE;
				break;
			}
		}
		if ((signal & dfeSig))
		{
			ClearUnusedATEFonts(fontList);
			SetSignal(0, dfeSig);
		}
		if (signal & nsdfSig)
		{
			while (nsdfMsg = (struct NsdfMsg *)GetMsg(ateNSDFPort))
			{
				nsdfMsg->nsdf_DFHeader = BuildScaledDiskFont(nsdfMsg->nsdf_TextFont, nsdfMsg->nsdf_TextAttr);
				ReplyMsg((struct Message *)nsdfMsg);
			}
		}
		if ((signal & textSig))
		{
			while (textMsg = (struct TextMsg *)GetMsg(ateTextPort))
			{
				keepGoing = AddATEChars(fontList, textMsg);
				if (keepGoing == FALSE)
				{
					PSTrace("%%Out of memory or some other error drawing new chars\n");
					psError = 0;
				}
				keepGoing = TRUE;
				ReplyMsg((struct Message *)textMsg);
			}
		}
		if ((signal & odfSig))
		{
			while (diskfontMsg = (struct DiskfontMsg *)GetMsg(ateODFPort))
			{
				keepGoing = AddATEFont(fontList, diskfontMsg);
				if (keepGoing == FALSE)
				{
					PSTrace("%%Out of memory creating new textfont\n");
					psError = 0;
				}
				keepGoing = TRUE;
				ReplyMsg((struct Message *)diskfontMsg);
			}
		}
		if ((signal & sssSig))
		{
			while (sssMsg = (struct SSStyleMsg *)GetMsg(ateSSSPort))
			{
				keepGoing = AddATEStyle(fontList, sssMsg);
				if (keepGoing == FALSE)
				{
					PSTrace("%%Out of memory creating new textfont for new style\n");
					psError = 0;
				}
				keepGoing = TRUE;
				ReplyMsg((struct Message *)sssMsg);
			}
		}
	}

	/* Clean up time */
	Forbid();
	/* There is a proper way to undo these, but I'm too lazy */
	newNSDFPtr = SetFunction(diskfontBase, -0x36, oldNSDFPtr);
	newFuncPtr = SetFunction(diskfontBase, -0x1E, oldFuncPtr);
	newTextPtr = SetFunction(gfxBase, -0x3C, oldTextPtr);
	newSSSPtr = SetFunction(gfxBase, -0x5A, oldSSSPtr);
	newAFPtr = SetFunction(diskfontBase, -0x24, oldAFPtr);
	newDFEPtr = SetFunction(diskfontBase, -0x12, oldDFEPtr);
//	newTLPtr = SetFunction(gfxBase, -0x36, oldTLPtr);
//	newTEPtr = SetFunction(gfxBase, -0x2B2, oldTEPtr);
	Permit();
	fprintf(ateOutput, "Patches removed, cleaning up...");
	DeleteMsgPort(ateCmdPort);
	DeleteMsgPort(ateODFPort);
	DeleteMsgPort(ateTextPort);
	DeleteMsgPort(ateSSSPort);
	DeleteMsgPort(ateNSDFPort);
	FreeSignal(ateDfeSigBit);
	ClearFontNames(fontList);
	ObtainSemaphore(ateSemaphore);
	ReleaseSemaphore(ateSemaphore);
	FreeVec(ateFontList);
	ObtainSemaphore(nafSemaphore);
	ReleaseSemaphore(nafSemaphore);
	FreeVec(ateAvailFonts);
	fclose(nilInput);
	PSdeleteact(psActivation);
	FreeVec(psParm);
	CloseLibrary(PSbase);
	CloseLibrary(gfxBase);
	CloseLibrary(diskfontBase);

	fprintf(ateOutput, "Now exiting.\nRemember: This is BETA software!  Use at own risk!\n");
	return(0);
}

void ClearFontNames(struct List *fontList)
{
struct	FontNode	*workNode, *nextNode;
struct	SignalSemaphore	*ateSemaphore = &ateFontList->ateSemaphore;

	ObtainSemaphore(ateSemaphore);
	workNode = (struct FontNode *)(fontList->lh_Head);
	while (nextNode = (struct FontNode *)(workNode->fn_Node.ln_Succ))
	{
		if (workNode->fn_TextFont != 0)
		{
			RemFont(workNode->fn_TextFont);
			StripFont(workNode->fn_TextFont);
			FreeMem(workNode->fn_ExtDFHeader, workNode->fn_ExtDFHeader->edf_Length);
//			FreeVec(workNode->fn_TextFont);
		}
		FreeVec(workNode);
		workNode = nextNode;
	}
	ReleaseSemaphore(ateSemaphore);
	return;
}

BOOL AddATEChars(struct List *fontList, struct TextMsg *textMsg)
{
struct	FontNode	*fontNode;
	char		*builtChars;
	STRPTR		oneChar;
	UBYTE		indexY;
	BOOL		callMakeATEChars = FALSE;
	BOOL		addATECharsOK;
	WORD		indexX, length;

	/* Needed fontnode already found by the Text() patch. */

	fontNode = textMsg->tm_FontNode;

	if (fontNode != 0)
	{
		/* begin pre-scan, determine what chars really need to be drawn */
		length = textMsg->tm_Length;
		builtChars = fontNode->fn_BuiltChars;
		oneChar = (textMsg->tm_Chars);
		for (indexX = 0; indexX < length; indexX++)
		{
			/* Mark needed characters */
			indexY = oneChar[indexX];
			if (builtChars[indexY] == CHAR_NOT_DRAWN)
			{
				builtChars[indexY] = CHAR_NEEDED;
				callMakeATEChars = TRUE;
			}
		}
		textMsg->tm_ATEFont = TRUE;
		addATECharsOK = TRUE;
		if (callMakeATEChars == TRUE)
		{
			addATECharsOK = MakeATEChars(fontNode);
		}
	}
	else
	{
		textMsg->tm_ATEFont = FALSE;
		addATECharsOK = TRUE;
	}

	return(addATECharsOK);
}

BOOL AddATEFont(struct List *fontList, struct DiskfontMsg *diskfontMsg)
{
struct	TextAttr	*textAttr;
struct	TTextAttr	*taggedTextAttr;
struct	FontNode	*fontNode;
struct	SignalSemaphore	*ateSemaphore = &ateFontList->ateSemaphore;
	UBYTE		fontStyle;
	char		fontName[64], regularName[64], typefaceName[64];
	char		dummyString[80], *dotPtr, optFontEncoding;
	BOOL		addATEFontOK;
	FILE		*ateFile;
	int		lowChar, highChar;
	float		xDPI, yDPI;
	float		dpiRatio;
struct	TagItem		*dpiTag;
	ULONG		dpiData;

	textAttr = diskfontMsg->df_TextAttr;
	if (textAttr->ta_Style & FSF_TAGGED)
		taggedTextAttr = (struct TTextAttr *)textAttr;
	else
		taggedTextAttr = 0;

	/* Make sure the font in question is an ATE font. */
	strcpy(fontName, "FONTS:");
	strcat(fontName, textAttr->ta_Name);
	dotPtr = strchr(fontName, '.');
	*dotPtr = '\0';
	/* OK try opening the file */
	ateFile = fopen(fontName, "r");
	if (ateFile == 0)
	{
		diskfontMsg->df_ATEFont = FALSE;
		return(TRUE);
		/* hey, not an ATE-ready typeface so exit */
	}
	/* Now search to see if requested font already exists */
	textAttr = diskfontMsg->df_TextAttr;
	fontStyle = textAttr->ta_Style & (FSF_BOLD | FSF_ITALIC);
	sprintf(fontName, "%50s / %5d / %2x", textAttr->ta_Name, textAttr->ta_YSize, fontStyle);
	ObtainSemaphoreShared(ateSemaphore);
	fontNode = (struct FontNode *)FindName(fontList, fontName);
	ReleaseSemaphore(ateSemaphore);
	if (fontNode != 0)
	{
		diskfontMsg->df_ATEFont = TRUE;
		diskfontMsg->df_TextFont = fontNode->fn_TextFont;
		return(TRUE);
		/* Hey, why work if you already have results? */
	}

	/* NOTE: ATE can only worry about substituting bold or italic versions, */
	/*       setting soft styles will take care of underlining */

	fgets(dummyString, 79, ateFile);
	sscanf(dummyString, "%c %d %d", &optFontEncoding, &lowChar, &highChar);
	dotPtr = strchr(dummyString, '.');
	dotPtr++;
	strcpy(regularName, dotPtr);
	strcpy(typefaceName, regularName);
	switch(fontStyle)
	{
		case 0x02:
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x04:
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x06:
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		default:
			break;
	}

	fclose(ateFile);
	/* If no real typeface exists for desired style, use plain style */
	if (strcmp(typefaceName, regularName) == 0)
		fontStyle = FS_NORMAL;

	/* Build search string and see if we don't already have this font */
	sprintf(fontName, "%50s / %5d / %2x", textAttr->ta_Name, textAttr->ta_YSize, fontStyle);
	ObtainSemaphoreShared(ateSemaphore);
	fontNode = (struct FontNode *)FindName(fontList, fontName);
	ReleaseSemaphore(ateSemaphore);
	if (fontNode != 0)
	{
		diskfontMsg->df_ATEFont = TRUE;
		diskfontMsg->df_TextFont = fontNode->fn_TextFont;
		return(TRUE);
		/* Hey, why work if you already have results? */
	}

	/* Original OpenDiskFont takes over here.  If the TA_DeviceDPI
	   don't match, tough luck as per C= spec. */

	dpiData = 0;
	/* So no font node eh?  Time to make one. */
	if (taggedTextAttr != 0)
	{
		dpiTag = taggedTextAttr->tta_Tags;
		dpiData = GetTagData(TA_DeviceDPI, 0L, dpiTag);

		if (dpiData != 0)
		{
			xDPI = (dpiData & 0xFFFF0000) >> 16;
			yDPI = dpiData & 0x0000FFFF;
			dpiRatio = xDPI / yDPI;
			PSTrace("Typeface DPI: %d x, %d y\n", xDPI, yDPI);
			PSTrace("DPI ratio: %f\n", dpiRatio);
		}

	}

	/* Consider a function to allocate the entire node and TextFont too */
	fontNode = (struct FontNode *)AllocVec(sizeof(struct FontNode), MEMF_PUBLIC | MEMF_CLEAR);
	if (fontNode != 0)
	{
		strcpy(fontNode->fn_Name, fontName);
		fontNode->fn_Node.ln_Name = fontNode->fn_Name;
		fontNode->fn_Node.ln_Type = NT_USER;
		fontNode->fn_Node.ln_Pri = 0;
		strcpy(fontNode->fn_TypefaceName, typefaceName);
		dotPtr = strchr(fontNode->fn_TypefaceName, '\n');
		if (dotPtr != 0)
			*dotPtr = 0;
		fontNode->fn_LowChar = lowChar;
		fontNode->fn_HighChar = highChar;
		fontNode->fn_OptFontEncoding = optFontEncoding;
		fontNode->fn_Style = fontStyle;
		fontNode->fn_FontSize = textAttr->ta_YSize;
		if (dpiData != 0)
			fontNode->fn_XDPI = dpiRatio * defaultDPI;
		else
			fontNode->fn_XDPI = defaultDPI;
		PSTrace("X DPI for this font is %f\n", fontNode->fn_XDPI);

		fontNode->fn_TextFont = MakeATEFont(fontNode, textAttr);
		if (fontNode->fn_TextFont != 0)
		{
			AddFont(fontNode->fn_TextFont);
			diskfontMsg->df_TextFont = fontNode->fn_TextFont;
			diskfontMsg->df_ATEFont = TRUE;
			ObtainSemaphore(ateSemaphore);
			AddHead(fontList, (struct Node *)fontNode);
			ReleaseSemaphore(ateSemaphore);
			addATEFontOK = TRUE;
			if (dpiData != 0)
				ExtendFont(fontNode->fn_TextFont, dpiTag);
			else
				ExtendFont(fontNode->fn_TextFont, 0);
			fontNode->fn_BlackList = FALSE;
			/* Stupid kludge inserted to draw the Space character first, to work
			   around a weird bug I have drawing the first char in a set. */
			fontNode->fn_BuiltChars[32] = CHAR_NEEDED;
//			MakeATEChars(fontNode);
			/* end of stupid kludge */
		}
		else
		{
			diskfontMsg->df_ATEFont = FALSE;
			addATEFontOK = FALSE;
			fontNode->fn_BlackList = TRUE;
			ObtainSemaphore(ateSemaphore);
			AddHead(fontList, (struct Node *)fontNode);
			ReleaseSemaphore(ateSemaphore);
		}
	}
	else
	{
		diskfontMsg->df_ATEFont = FALSE;
		addATEFontOK = FALSE;
	}
	return(addATEFontOK);
}

/* This function mimics AddATEFont except it adds fonts upon SetSoftStyle()
   calls instead of OpenDiskFont() calls.  This fcn takes special
   consideration of ta_Style flags. */
BOOL AddATEStyle(struct List *fontList, struct SSStyleMsg *sssMsg)
{
struct	FontNode	*fontNode;
struct	RastPort	*sssRastPort = sssMsg->ss_RastPort;
struct	TextFont	*sssTextFont = sssMsg->ss_RastPort->Font;
static struct	TextAttr	dummyAttr;	/* For calling MakeATEFont */
struct	SignalSemaphore	*ateSemaphore = &ateFontList->ateSemaphore;
	char		*currentFontName, fontName[64], dummyString[80], *dotPtr;
	char		typefaceName[64], regularName[64], optFontEncoding;
	int		fontSize, currentStyle, desiredStyle, lowChar, highChar;
	FILE		*ateFile;
	int		xDPI;	/* Check if the normal font has a ratio */
	BOOL		addATEStyleOK;

	currentFontName = sssRastPort->Font->tf_Message.mn_Node.ln_Name;
	fontSize = sssRastPort->Font->tf_YSize;
	desiredStyle = sssMsg->ss_NewStyle & sssMsg->ss_Enable;
	currentStyle = desiredStyle & (FSF_BOLD | FSF_ITALIC);
	/* Only pay attention to FSF_BOLD and FSF_ITALIC */
	/* Build search string and see if we don't already have this font */
	sprintf(fontName, "%50s / %5d / %2x", currentFontName, fontSize, currentStyle);
	ObtainSemaphoreShared(ateSemaphore);
	fontNode = (struct FontNode *)FindName(fontList, fontName);
	ReleaseSemaphore(ateSemaphore);
	if (fontNode != 0)
	{
		sssMsg->ss_ATEFont = TRUE;
		sssMsg->ss_ChangedFont = fontNode->fn_TextFont;
		sssMsg->ss_SoftStyleNeeded = currentStyle ^ desiredStyle;
		return(TRUE);
		/* Hey, why work if you already have results? */
	}

	/* Do repeat search for normal style and copy XDPI */
	sprintf(fontName, "%50s / %5d / %2x", currentFontName, fontSize, FS_NORMAL);
	ObtainSemaphoreShared(ateSemaphore);
	fontNode = (struct FontNode *)FindName(fontList, fontName);
	ReleaseSemaphore(ateSemaphore);
	if (fontNode != 0)
		xDPI = fontNode->fn_XDPI;

	/* OK currentStyle doesn't exist yet and it IS an ATE font.  So make it. */
	
	/* Make sure the font in question is an ATE font. */
	strcpy(fontName, "FONTS:");
	strcat(fontName, currentFontName);
	dotPtr = strchr(fontName, '.');
	*dotPtr = '\0';
	/* OK try opening the file */
	ateFile = fopen(fontName, "r");
	if (ateFile == 0)
	{
		sssMsg->ss_ATEFont = FALSE;
		sssMsg->ss_SoftStyleNeeded = sssMsg->ss_NewStyle;
		return(TRUE);
		/* hey, not an ATE-ready typeface so exit */
	}

	/* Now search to see if requested typeface version exists */
	fgets(dummyString, 79, ateFile);
	sscanf(dummyString, "%c %d %d", &optFontEncoding, &lowChar, &highChar);
	dotPtr = strchr(dummyString, '.');
	dotPtr++;
	strcpy(regularName, dotPtr);
	strcpy(typefaceName, regularName);
	switch(currentStyle)
	{
		case 0x02:	/* FSF_BOLD */
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x04:	/* FSF_ITALIC */
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x06:	/* FSF_BOLD | FSF_ITALIC */
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		default:
			break;
	}
	fclose(ateFile);

	/* If no real typeface exists for desired style, exit */
	if (strcmp(typefaceName, regularName) == 0)
	{
		sssMsg->ss_ATEFont = FALSE;
		sssMsg->ss_SoftStyleNeeded = sssMsg->ss_NewStyle;
		return(TRUE);
	}

	/* OK now make a new font node for this new style */
	fontNode = (struct FontNode *)AllocVec(sizeof(struct FontNode), MEMF_PUBLIC | MEMF_CLEAR);
	if (fontNode != 0)
	{
		sprintf(fontName, "%50s / %5d / %2x", currentFontName, fontSize, currentStyle);
		strcpy(fontNode->fn_Name, fontName);
		fontNode->fn_Node.ln_Name = fontNode->fn_Name;
		fontNode->fn_Node.ln_Type = NT_USER;
		fontNode->fn_Node.ln_Pri = 0;
		strcpy(fontNode->fn_TypefaceName, typefaceName);
		dotPtr = strchr(fontNode->fn_TypefaceName, '\n');
		if (dotPtr != 0)
			*dotPtr = 0;
		fontNode->fn_LowChar = lowChar;
		fontNode->fn_HighChar = highChar;
		fontNode->fn_OptFontEncoding = optFontEncoding;
		fontNode->fn_Style = currentStyle;
		fontNode->fn_FontSize = fontSize;
		fontNode->fn_XDPI = xDPI;
		dummyAttr.ta_Name = currentFontName;
		dummyAttr.ta_YSize = fontSize;
		dummyAttr.ta_Style = currentStyle;
		dummyAttr.ta_Flags = 0;
		/* Call MakeATEFont() to build this new font */
		fontNode->fn_TextFont = MakeATEFont(fontNode, &dummyAttr);
		if (fontNode->fn_TextFont != 0)
		{
			AddFont(fontNode->fn_TextFont);
			sssMsg->ss_ChangedFont = fontNode->fn_TextFont;
			sssMsg->ss_ATEFont = TRUE;
			ObtainSemaphore(ateSemaphore);
			AddHead(fontList, (struct Node *)fontNode);
			ReleaseSemaphore(ateSemaphore);
			ExtendFont(fontNode->fn_TextFont, 0);
			sssMsg->ss_SoftStyleNeeded = currentStyle ^ desiredStyle;
			addATEStyleOK = TRUE;
			fontNode->fn_BlackList = FALSE;
			/* Stupid kludge inserted to draw the Space character first, to work
			   around a weird bug I have drawing the first char in a set. */
			fontNode->fn_BuiltChars[32] = CHAR_NEEDED;
//			MakeATEChars(fontNode);
			/* end of stupid kludge */
		}
		else
		{
			sssMsg->ss_ATEFont = FALSE;
			addATEStyleOK = FALSE;
			sssMsg->ss_SoftStyleNeeded = sssMsg->ss_NewStyle;
			fontNode->fn_BlackList = TRUE;
		}
	}
	else
	{
		sssMsg->ss_ATEFont = FALSE;
		sssMsg->ss_SoftStyleNeeded = sssMsg->ss_NewStyle;
		addATEStyleOK = FALSE;
	}
	return(addATEStyleOK);
}

/* Yet another mimic-er of AddATEFont, except this one builds SegLists and
   clears the fontnode after use.  Used for the NewScaledDiskFont() patch */
struct DiskFontHeader *BuildScaledDiskFont(struct TextFont *textFont, struct TextAttr *textAttr)
{
struct	TTextAttr	*taggedTextAttr;
struct	FontNode	*fontNode;
struct	DiskFontHeader	*dfHeader;
	UBYTE		fontStyle;
	char		fontName[64], regularName[64], typefaceName[64];
	char		dummyString[80], *dotPtr, optFontEncoding;
	FILE		*ateFile;
	int		lowChar, highChar, index;
	BOOL		addATEFontOK = FALSE;
	float		xDPI, yDPI;
	float		dpiRatio;
struct	TagItem		*dpiTag;
	ULONG		dpiData;

	if (textAttr->ta_Style & FSF_TAGGED)
		taggedTextAttr = (struct TTextAttr *)textAttr;
	else
		taggedTextAttr = 0;

	/* Make sure the font in question is an ATE font. */
	strcpy(fontName, "FONTS:");
	strcat(fontName, textFont->tf_Message.mn_Node.ln_Name);
	dotPtr = strchr(fontName, '.');
	*dotPtr = '\0';
	/* OK try opening the file */
	ateFile = fopen(fontName, "r");
	if (ateFile == 0)
		return(0);

	fontStyle = (textAttr->ta_Style) & (FSF_BOLD | FSF_ITALIC);

	fgets(dummyString, 79, ateFile);
	sscanf(dummyString, "%c %d %d", &optFontEncoding, &lowChar, &highChar);
	dotPtr = strchr(dummyString, '.');
	dotPtr++;
	strcpy(regularName, dotPtr);
	strcpy(typefaceName, regularName);
	switch(fontStyle)
	{
		case 0x02:
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x04:
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x06:
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			fgets(dummyString, 79, ateFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		default:
			break;
	}

	fclose(ateFile);
	/* If no real typeface exists for desired style, use plain style */
	if (strcmp(typefaceName, regularName) == 0)
		fontStyle = FS_NORMAL;

	dpiData = 0;
	if (taggedTextAttr != 0)
	{
		dpiTag = taggedTextAttr->tta_Tags;
		dpiData = GetTagData(TA_DeviceDPI, 0L, dpiTag);

		if (dpiData != 0)
		{
			xDPI = (dpiData & 0xFFFF0000) >> 16;
			yDPI = dpiData & 0x0000FFFF;
			dpiRatio = xDPI / yDPI;
			PSTrace("Typeface DPI: %d x, %d y\n", xDPI, yDPI);
			PSTrace("DPI ratio: %f\n", dpiRatio);
		}

	}

	fontNode = (struct FontNode *)AllocVec(sizeof(struct FontNode), MEMF_PUBLIC | MEMF_CLEAR);
	if (fontNode != 0)
	{
		strcpy(fontNode->fn_Name, fontName);
		fontNode->fn_Node.ln_Name = fontNode->fn_Name;
		fontNode->fn_Node.ln_Type = NT_USER;
		fontNode->fn_Node.ln_Pri = 0;
		strcpy(fontNode->fn_TypefaceName, typefaceName);
		dotPtr = strchr(fontNode->fn_TypefaceName, '\n');
		if (dotPtr != 0)
			*dotPtr = 0;
		fontNode->fn_LowChar = lowChar;
		fontNode->fn_HighChar = highChar;
		fontNode->fn_OptFontEncoding = optFontEncoding;
		fontNode->fn_Style = fontStyle;
		fontNode->fn_FontSize = textAttr->ta_YSize;
		if (dpiData != 0)
			fontNode->fn_XDPI = dpiRatio * defaultDPI;
		else
			fontNode->fn_XDPI = defaultDPI;
		PSTrace("X DPI for this font is %f\n", fontNode->fn_XDPI);

		fontNode->fn_TextFont = MakeATEFont(fontNode, textAttr);
		if (fontNode->fn_TextFont != 0)
		{
			if (dpiData != 0)
				ExtendFont(fontNode->fn_TextFont, dpiTag);
//			else
//				ExtendFont(fontNode->fn_TextFont, 0);
			/* Build all characters */
			for (index = lowChar; index <= highChar; index++)
				fontNode->fn_BuiltChars[index] = CHAR_NEEDED;
			addATEFontOK = MakeATEChars(fontNode);
		}
		else
		{
			addATEFontOK = FALSE;
			fontNode->fn_BlackList = TRUE;
		}
	}
	else
	{
		addATEFontOK = FALSE;
		return(0);
	}

	if (addATEFontOK == FALSE)
	{
		PSTrace("%%Error building scaled diskfont\n");
		FreeMem(fontNode->fn_ExtDFHeader, fontNode->fn_ExtDFHeader->edf_Length);
		FreeVec(fontNode);
		return(0);
	}
	dfHeader = &fontNode->fn_ExtDFHeader->edf_DFHeader;
	FreeVec(fontNode);
	return(dfHeader);

}

/* Here we build a new TextFont */
struct TextFont *MakeATEFont(struct FontNode *fontNode, struct TextAttr *textAttr)
{
struct	TextFont	*newFont;
struct	ExtDFHeader	*extDFHeader;
	FILE		*afmFile;
	char		lineIn[256], afmFilename[64], checkString[64], charName[24];
	int		zZ, z1, z2, index, y1, y2;
	int		asciiCode, llX, llY, urX, urY, xWidth;
//structPSdevice	*localPage = &fontNode->fn_Page;

	if (fontNode->fn_BlackList == TRUE)
		return(0);
	/* Pre-check: Make sure the typeface is in PSFonts: */
	strcpy(afmFilename, "PSFonts:");
	strcat(afmFilename, fontNode->fn_TypefaceName);
	afmFile = fopen(afmFilename, "r");
	if (afmFile == 0)
	{
		fprintf(ateOutput, "Cannot locate typeface file %s.  Check your _AFM_ files or\n"
		       "Re-install the typeface.\n", fontNode->fn_TypefaceName);
		fflush(ateOutput);
		fclose(afmFile);
		return(0);
	}

	/* Find AFM and encoding files and get charWidth & bounding box info */
	strcpy(afmFilename, "PSFonts:afms/");
	strcat(afmFilename, fontNode->fn_TypefaceName);
	strcat(afmFilename, ".afm");
	PSTrace("%%Will attempt to open %s\n", afmFilename);
	afmFile = fopen(afmFilename, "r");
	if (afmFile == 0)
	{
		PSTrace("%%Can't open AFM file\n");
		fprintf(ateOutput, "Cannot locate AFM file for typeface %s.  Check your\n"
		       "PSFonts/afms diectory and _ATE_ files or re-install.\n",
		       fontNode->fn_TypefaceName);
		fflush(ateOutput);
		fclose(afmFile);
		return(0);
	}

	/* NOTICE: This routine looks for specific keywords and I'm not responsible
	   if you don't use AFMs that follow Adobe FontMetrics2.0.  Also notice:
	   I do not check the typeface names in the .afm itself.  The Install prg
	   will do that stupid checking when I finish it. */

	fontNode->fn_OptBaseLine = 0;
	/* Search for FontBBox keyword */
	while (!feof(afmFile))
	{
		fgets(lineIn, 256, afmFile);
		sscanf(lineIn, "%s ", checkString);
		if (strcmp(checkString, "FontBBox") == 0)
		{
			llY = 0;
			sscanf(lineIn, "%s %d %d %d %d", checkString, &llX, &llY, &urX, &urY);
			PSTrace("%%Bounding box: %d %d %d %d\n", llX, llY, urX, urY);
			if (llY < 0)
				fontNode->fn_OptBaseLine = -llY;
			if (llY > 0)
				fontNode->fn_OptBaseLine = llY;
			PSTrace("%%Baseline read from AFM file at %d\n", fontNode->fn_OptBaseLine);
			break;
		}
	}

	/* Search for StartCharMetrics keyword */
	while (!feof(afmFile))
	{
		fgets(lineIn, 256, afmFile);
		sscanf(lineIn, "%s ", checkString);
		if (strcmp(checkString, "StartCharMetrics") == 0)
			break;
	}
	if (feof(afmFile))
	{
		fprintf(ateOutput, "Error parsing AFM file for %s.  Ensure the AFM follows\n"
		       "AdobeFontMetrics 2.0 spec, including bounding boxes for\n"
		       "each character.\n", fontNode->fn_TypefaceName);
		fflush(ateOutput);
		fclose(afmFile);
		return(0);
	}

	/* OK very next statements until EndCharMetrics are width and bounding box
	   info.  Read it all in, compare charnames with encodingExternal and build
	   width and bbox info.  */

	while (!feof(afmFile))
	{
		asciiCode = 0;
		fgets(lineIn, 256, afmFile);
		sscanf(lineIn, "%s", checkString);
		if (strcmp(checkString, "EndCharMetrics") == 0)
			break;
		sscanf(lineIn, "C %d ; WX %d ; N %s ; B %d %d %d %d",
			&asciiCode, &xWidth, charName, &llX, &llY, &urX, &urY);

		if (asciiCode == -1)
		{
			for (index = fontNode->fn_LowChar; index <= fontNode->fn_HighChar; index++)
			{
				if (strcmp(encodingExternal[index], charName) == 0)
				{
					if (urX - llX < xWidth)
						urX = xWidth;
					fontNode->fn_CharWidths[index] = xWidth;
					fontNode->fn_LowLeftX[index] = llX;
					fontNode->fn_LowLeftY[index] = llY;
					fontNode->fn_UpRightX[index] = urX;
					fontNode->fn_UpRightY[index] = urY;
					break;
				}
			}
		}
		else
		{
			if ((urX - llX) < xWidth)
				urX = xWidth;
			fontNode->fn_CharWidths[asciiCode] = xWidth;
			fontNode->fn_LowLeftX[asciiCode] = llX;
			fontNode->fn_LowLeftY[asciiCode] = llY;
			fontNode->fn_UpRightX[asciiCode] = urX;
			fontNode->fn_UpRightY[asciiCode] = urY;
		}
	}

	if (feof(afmFile))
	{
		PSTrace("%%Disk error or format error reading AFM file\n");
		fclose(afmFile);
		return(0);
	}

	/* Since AddATEFont() did all the checking for this fcn, just start rendering */
	PSTrace("%%Loading typeface %s\n", fontNode->fn_TypefaceName);
	/* A bit of weeding out; these weren't needed */
//	PSIntf("/fontname /%.100s def\n", fontNode->fn_TypefaceName);
//	PSIntf("fontname findfont pop\n");
//	PSIntf("/font fontname .findfont def\n");

	PSIntf("/font /%.100s findfont def\n", fontNode->fn_TypefaceName);

	if (psError != 0)
		PSTrace("%%Error loading typeface\n");
	PSTrace("%%Encoding font\n");
	PSIntf("/newfont font maxlength dict def\n");
	PSIntf(	"font\n"
		"{ exch dup /FID ne"
		"{ exch newfont 3 1 roll put } { pop pop } ifelse }\n"
		"forall\n");
	if (fontNode->fn_OptFontEncoding == 'S')
		PSIntf("newfont /Encoding encoding put\n");
	PSIntf("/_%.100s newfont definefont pop\n", fontNode->fn_TypefaceName);
	if (psError != 0)
	{
		PSTrace("%%PostScript error encoding typeface\n");
		return(0);
	}

	if (fontNode->fn_OptBaseLine == 0)
	{
		/* Start generating baseline info from BBox info */
		zZ = 1000 * 72 / defaultDPI;	/* Formerly zZ = (1000 * 72) / optYDen */
		z1 = z2 = 0;
		for (index = fontNode->fn_LowChar; index <= fontNode->fn_HighChar; index++)
		{
			if (fontNode->fn_LowLeftY[index] < z1)
				z1 = fontNode->fn_LowLeftY[index];
			if (fontNode->fn_UpRightY[index] > z2)
				z2 = fontNode->fn_UpRightY[index];
		}
		if (z2 == z1)
		{
			PSTrace("%%All chars in this typeface are null!\n");
			psError = -1;
			return(0);
		}
		fontNode->fn_OptBaseLine = (1000 * (-z1) + (z2 - z1) / 2) / (z2 - z1);
		if ((z2 - z1 > zZ) && fontNode->fn_OptFontEncoding == 'S')
		{
			y1 = y2 = 0;
			for (index = 'A'; index <= 'Z'; index++)
			{
				if (fontNode->fn_LowLeftY[index] < y1)
					y1 = fontNode->fn_LowLeftY[index];
				if (fontNode->fn_UpRightY[index] > y2)
					y2 = fontNode->fn_UpRightY[index];
			}
			for (index = 'a'; index <= 'z'; index++)
			{
				if (fontNode->fn_LowLeftY[index] < y1)
					y1 = fontNode->fn_LowLeftY[index];
				if (fontNode->fn_UpRightY[index] > y2)
					y2 = fontNode->fn_UpRightY[index];
			}
			if (y2 - y1 <= zZ)
				fontNode->fn_OptBaseLine = (1000 * (-y1) + zZ / 2) / zZ;
			else
				fontNode->fn_OptBaseLine = (1000 * (-y1) + (y2 - y1) / 2) / (y2 - y1);
		}
	}

	PSTrace("%%Baseline set to %d/1000 of pixel height\n", fontNode->fn_OptBaseLine);

	/* Prepare memory space for the new font */
	PSTrace("%%Allocating space for new TextFont\n");
	fontNode->fn_BaseLength = sizeof(struct ExtDFHeader) + 8 * (fontNode->fn_HighChar - fontNode->fn_LowChar + 2);
	fontNode->fn_MaxWidth = 0;
	for (index = fontNode->fn_LowChar; index <= fontNode->fn_HighChar; index++)
		fontNode->fn_MaxWidth += (((fontNode->fn_UpRightX[index] * 1.3) -
		fontNode->fn_LowLeftX[index]) * fontNode->fn_FontSize * fontNode->fn_XDPI) / 72000 + 2;
		/* 72 = opt X den */
	fontNode->fn_MaxModulo = ((fontNode->fn_MaxWidth + 15) >> 3) & ~1;
	fontNode->fn_MaxCharLength = fontNode->fn_MaxModulo * fontNode->fn_FontSize;
	fontNode->fn_MaxFontLength = fontNode->fn_BaseLength + fontNode->fn_MaxCharLength + 2 + 76;

	/* This time: use AllocMem because this might be a diskfont seglist */
	extDFHeader = (struct ExtDFHeader *)AllocMem((fontNode->fn_MaxFontLength), (MEMF_PUBLIC | MEMF_CLEAR));
	if (extDFHeader == 0)
	{
		PSTrace("%%Cannot get memory for new TextFont\n");
		psError = -1;
		return(0);
	}
	fontNode->fn_ExtDFHeader = extDFHeader;
	extDFHeader->edf_Length = fontNode->fn_MaxFontLength;
	/* Fill dfHeader up */
	extDFHeader->edf_DFHeader.dfh_DF.ln_Name = extDFHeader->edf_DFHeader.dfh_Name;
	extDFHeader->edf_DFHeader.dfh_FileID = DFH_ID;
	/* seglist pointer one longword ahead of the extDFHeader */
	extDFHeader->edf_DFHeader.dfh_Segment = MKBADDR((ULONG)extDFHeader + 4);
	extDFHeader->edf_DFHeader.dfh_Revision = 1;
	/* Continue filling TextFont struct */
	newFont = &extDFHeader->edf_DFHeader.dfh_TF;
	fontNode->fn_CharLoc =		(short *)&newFont[1];
	fontNode->fn_CharSpace = 	(short *)&fontNode->fn_CharLoc[(fontNode->fn_HighChar - fontNode->fn_LowChar + 2) * 2];
	fontNode->fn_CharKern =		(short *)&fontNode->fn_CharSpace[fontNode->fn_HighChar - fontNode->fn_LowChar + 2];
	fontNode->fn_CharData = 	(char  *)&fontNode->fn_CharKern[fontNode->fn_HighChar - fontNode->fn_LowChar + 2];
	fontNode->fn_CharFontName = 	(char  *)extDFHeader->edf_DFHeader.dfh_Name;
//	fontNode->fn_CharFontName = 	(char  *)&fontNode->fn_CharData[fontNode->fn_MaxCharLength];
	strcpy(fontNode->fn_CharFontName, textAttr->ta_Name);
	PSTrace("TextFont pointers:   Font at    %8X\n", newFont);
	PSTrace("                     Loc at     %8X\n", fontNode->fn_CharLoc);
	PSTrace("                     Space at   %8X\n", fontNode->fn_CharSpace);
	PSTrace("                     Kern at    %8X\n", fontNode->fn_CharKern);
	PSTrace("                     Data at    %8X\n", fontNode->fn_CharData);
	PSTrace("                     Name at    %8X\n", fontNode->fn_CharFontName);
	PSTrace("                     Name is %s\n", fontNode->fn_CharFontName);

	/* Prepare remaining TextFont attributes */
	newFont->tf_Message.mn_Node.ln_Name = fontNode->fn_CharFontName;
	newFont->tf_Message.mn_Node.ln_Type = NT_FONT;
	newFont->tf_Message.mn_Length = fontNode->fn_MaxFontLength + 64;
	newFont->tf_YSize = textAttr->ta_YSize;
	newFont->tf_Style = fontNode->fn_Style;
	newFont->tf_Flags = (FPF_DISKFONT | FPF_PROPORTIONAL | FPF_DESIGNED);
	fontNode->fn_BaseLine = (textAttr->ta_YSize * fontNode->fn_OptBaseLine + 500) / 1000;
	if (fontNode->fn_BaseLine < 0)
		fontNode->fn_BaseLine = 0;
	if (fontNode->fn_BaseLine > textAttr->ta_YSize)
		fontNode->fn_BaseLine = textAttr->ta_YSize - 1;
	newFont->tf_Baseline = textAttr->ta_YSize - fontNode->fn_BaseLine - 1;
	newFont->tf_BoldSmear = textAttr->ta_YSize / 20 + 1;
	newFont->tf_LoChar = fontNode->fn_LowChar;
	newFont->tf_HiChar = fontNode->fn_HighChar;
	newFont->tf_Modulo = fontNode->fn_MaxModulo;
	newFont->tf_CharLoc = (APTR)fontNode->fn_CharLoc;
	newFont->tf_CharSpace = (APTR)fontNode->fn_CharSpace;
	newFont->tf_CharKern = (APTR)fontNode->fn_CharKern;
	newFont->tf_CharData = (APTR)fontNode->fn_CharData;

	/* Prepare additional values in fontNode struct */
	fontNode->fn_ActWidth = 0;
	fontNode->fn_NomWidth = 0;
	fontNode->fn_NomCount = 0;
	fontNode->fn_CharPosX = 0;

	/* Right here should be the end of MakeATEFont() except for tf_CharSpace */
	/* and tf_CharKern array generation.  The rest will move to MakeATEChars() */
	/* And it has.  This part just pre-builds the font shell */

	for (index = fontNode->fn_LowChar; index <= fontNode->fn_HighChar; index ++)
	{
		z1 = (fontNode->fn_LowLeftX[index] * fontNode->fn_FontSize * fontNode->fn_XDPI - 41000) / 72000;
			/* opt x den */
		z2 = (fontNode->fn_UpRightX[index] * fontNode->fn_FontSize * fontNode->fn_XDPI + 41000) / 72000;
			/* opt x den */
		if (z1 < 0)
			zZ = z2 - z1;
		else
			zZ = z2 + z1;
		fontNode->fn_CharLoc[(index - fontNode->fn_LowChar) * 2 + 1] = zZ;
		fontNode->fn_CharSpace[(index - fontNode->fn_LowChar)] = -z1 + (fontNode->fn_CharWidths[index] * fontNode->fn_FontSize * fontNode->fn_XDPI + 41000) / 72000;
		fontNode->fn_CharKern[(index - fontNode->fn_LowChar)] = z1;
		if (fontNode->fn_LowLeftY[index] != fontNode->fn_UpRightY[index])
		{
			fontNode->fn_NomWidth += (zZ * 1.3);
			fontNode->fn_NomCount++;
		}
	}

	/* Some extra parts of the TextFont struct missed above */
	newFont->tf_XSize = fontNode->fn_NomWidth / (fontNode->fn_HighChar - fontNode->fn_LowChar);
	/* Reset position ptr for char drawing */
	/* OK, finally the new TextFont is ready for use (maybe...) */
	if (psError != 0)
	{
		FreeMem(extDFHeader, fontNode->fn_MaxFontLength);
		return(0);
	}

	return(newFont);		
}

/* MakeATEChars() searches fn_BuiltChars and builds characters flagged with */
/* CHAR_NEEDED, then sets the value to CHAR_DRAWN.  */
BOOL MakeATEChars(struct FontNode *fontNode)
{
	int		index, z1, z2, zZ;
//	int		y1, y2;
struct	TextFont	*newFont = fontNode->fn_TextFont;
//structPSdevice	*localPage = &psParm->page;

	/* Check for blacklisting */
	if (fontNode->fn_BlackList == TRUE)
		return(FALSE);

	/* Prepare page area for the new chars */
	psParm->page.buf[0] = newFont->tf_CharData;
	psParm->page.len = fontNode->fn_MaxCharLength;
	psParm->page.depth = 1;
	psParm->page.xbytes = fontNode->fn_MaxModulo;
	psParm->page.xsize = fontNode->fn_MaxWidth;
	psParm->page.ysize = fontNode->fn_FontSize;
	psParm->page.yheight = fontNode->fn_FontSize;

	/* Beginning of MakeATEChars() (Fingers crossed) */
	PSsetdevice(psActivation, &psParm->page);

	/* OK, draw some characters. */
	/* first re-load the typeface needed... */
//	PSIntf("/fontname /%.100s def\n", fontNode->fn_TypefaceName);
//	PSIntf("fontname findfont pop\n");
//	PSIntf("/font fontname .findfont def\n");

	PSIntf("/font /%.100s findfont def\n", fontNode->fn_TypefaceName);

	PSIntf("/newfont font maxlength dict def\n");
	PSIntf(	"font\n"
		"{ exch dup /FID ne"
		"{ exch newfont 3 1 roll put } { pop pop } ifelse }\n"
		"forall\n");
	if (fontNode->fn_OptFontEncoding == 'S')
		PSIntf("newfont /Encoding encoding put\n");
	PSIntf("/_%.100s newfont definefont pop\n", fontNode->fn_TypefaceName);

	/* ... then initmatrix the drawing area and start drawing */
	PSIntf("initmatrix\n");
	PSIntf("/xscale %d %d mul 72 div def\n", newFont->tf_YSize, fontNode->fn_XDPI);
		/* 72 = optXDen */
	PSIntf("/yscale %d %d mul 72 div def\n", newFont->tf_YSize, defaultDPI);
		/* 72 = optYDen */
	PSIntf("newfont [ xscale 0 0 yscale 0 0 ] makefont setfont\n");

	/* Character loop.  MakeATEChars() keeps a running position ptr and fills */
	/* the CharLoc and CharKern arrays along with the CharData bitmap. */
	/* Since the Amiga uses the position ptrs in tf_CharLoc the chars can */
	/* render in any order. */
	for (index = fontNode->fn_LowChar; index <= fontNode->fn_HighChar; index ++)
	{
		if (fontNode->fn_BuiltChars[index] == CHAR_NEEDED)
		{
			z1 = (fontNode->fn_LowLeftX[index] * fontNode->fn_FontSize * fontNode->fn_XDPI - 41000) / 72000;
				/* opt x den */
			z2 = (fontNode->fn_UpRightX[index] * fontNode->fn_FontSize * fontNode->fn_XDPI + 41000) / 72000;
				/* opt x den */
			if (z1 < 0)
				zZ = z2 - z1;
			else
				zZ = z2 + z1;
			PSIntf("cstr 0 %d put\n", index);
			PSIntf("%d %d moveto ", fontNode->fn_ActWidth - z1, fontNode->fn_BaseLine);
			/* reference to optxden in y1 was here */
			PSIntf("cstr show\n");
			if (psError != 0)
			{
				PSTrace("PostScript error drawing character %d %c\n", index, index);
				break;
			}
			fontNode->fn_CharLoc[(index - fontNode->fn_LowChar) * 2] = fontNode->fn_ActWidth;
			fontNode->fn_ActWidth += (zZ * 1.3);
			fontNode->fn_BuiltChars[index] = CHAR_DRAWN;
		}
	}
	if (psError != 0)
		fontNode->fn_BlackList = TRUE;

	/* I really don't expect any non-PS errors here so just return(TRUE). */
	/* The font already exists and there's enough memory by this point. */
	return(TRUE);
}

/* Unloads all unused ATE fonts and fontnodes */
void ClearUnusedATEFonts(struct FontList *fontList)
{
struct	SignalSemaphore		*listSemaphore = &ateFontList->ateSemaphore;
struct	List			*localFontList = &ateFontList->fontList;
struct	FontNode		*workNode, *nextNode, *tempNode;
	BOOL			killFont;
	char			workName[64];

	/* Get access to the list */
	ObtainSemaphore(listSemaphore);

	/* If the list is empty to begin with, exit */
	if (localFontList->lh_Head->ln_Succ == 0)
	{
		ReleaseSemaphore(listSemaphore);
		return();
	}

	/* Begin traversing the font list */
	workNode = (struct FontNode *)localFontList->lh_Head;

	for (workNode = (struct FontNode *)localFontList->lh_Head;
	     workNode->fn_Node.ln_Succ; )
	{
		nextNode = (struct FontNode *)workNode->fn_Node.ln_Succ;

		killFont = FALSE;

		if (workNode->fn_BlackList == TRUE)
			killFont = TRUE;
		else if (workNode->fn_TextFont->tf_Accessors == 0)
		{
			/* if this is a styled font, make sure this isn't
			   used through SetSoftStyle() */
			if (workNode->fn_Style != FS_NORMAL)
			{
				sprintf(workName, "%50s / %5d / %2x",
					workNode->fn_TextFont->tf_Message.mn_Node.ln_Name,
					workNode->fn_FontSize, FS_NORMAL);
				tempNode = (struct FontNode *)FindName(localFontList, workName);
				if (tempNode != 0)
				{
					/* So it is used via SetSoftStyle...
					   check its count */
					if (tempNode->fn_TextFont->tf_Accessors == 0)
						killFont = TRUE;
				}
				else
					killFont = TRUE;
			}
			else
				killFont = TRUE;
		}
		tempNode = workNode;
		workNode = (struct FontNode *)workNode->fn_Node.ln_Succ;

		/* If killFont was set, remove it and the node */
		if (killFont == TRUE)
		{
			if (tempNode->fn_TextFont != 0)
			{
				RemFont(tempNode->fn_TextFont);
				StripFont(tempNode->fn_TextFont);
				FreeMem(tempNode->fn_ExtDFHeader, tempNode->fn_ExtDFHeader->edf_Length);
//				FreeVec(tempNode->fn_TextFont);
			}
			Remove((struct Node *)tempNode);
			FreeVec(tempNode);
		}
	}
	ReleaseSemaphore(listSemaphore);

	/* "Re-boot" the PS interpreter */
	PSdeleteact(psActivation);

	/* re-initalize the PostScript activation */
	PSTrace("%%Re-initalizing PostScript Activation\n");
	psParm->page.buf[0] = nameBuffer;
	psParm->page.len = 100;
	psParm->page.depth = 1;
	psParm->page.xbytes = 10;
	psParm->page.xsize = 80;
	psParm->page.ysize = 10;
	psParm->page.xden = 72;
	psParm->page.yden = 72;
	psParm->page.ydir = -1;
	psParm->memvlen = 20000;
	psParm->memflen = 10000;
	psParm->memllen = defmemllen;
	psParm->memhlen = minmemhlen;

	psActivation = PScreateact(psParm);

	/* Run ATE startup files */
	PSTrace("%%All initalization passed, re-running PS startup & encoding files\n");
	PSIntf("(%.100s) run clear\n", "PSFonts:init.ps");
	PSIntf("/encoding StandardEncoding 256 array copy def\n");
	PSIntf("[ (%.100s) run] aload length 2 idiv\n", "PSFonts:ATEencoding.ps");
	PSIntf("{ encoding 3 1 roll put } repeat\n");
	PSIntf("/cstr 1 string def\n");

	return;
}

/* Fcn that counts the opencount in each ATE font */
int CountOpenFonts(void)
{
struct	TextFont	*currentFont, *nextFont;
	int		openCount;
struct	TextAttr	topazAttr;

	topazAttr.ta_Name = "topaz.font";
	topazAttr.ta_YSize = 8;
	topazAttr.ta_Style = FS_NORMAL;
	topazAttr.ta_Flags = 0;

	openCount = 0;

	/* Start by obtaining topaz.8, the first font in the system list */
	currentFont = (struct TextFont *)OpenFont(&topazAttr);
	CloseFont(currentFont);

	/* Now go into a Forbid() state and check the list */
	Forbid();
	nextFont = (struct TextFont *)currentFont->tf_Message.mn_Node.ln_Succ;
	while (nextFont != 0)
	{
		if (memcmp(currentFont->tf_Message.mn_Node.ln_Name, "_ATE_", 5) == 0)
		{
			openCount = openCount + currentFont->tf_Accessors;
		}
		currentFont = nextFont;
		nextFont = (struct TextFont *)currentFont->tf_Message.mn_Node.ln_Succ;
	}
	Permit();

	return(openCount);
}

/* Fcn which builds ATEAvailFonts struct */
struct ATEAvailFonts *PrepATEAvailFonts(int sizeMax, int sizeInc, int diskfontSize)
{
struct	ATEAvailFonts		*tempATEAvailFonts;
	BOOL			executeSuccess;
	FILE			*ateListFile;
	char			readLine[100], charName[32], *afATEFontNames;
	int			asciiValue, afATEFonts, numAteSizes, numAteNames;
	int			newSizeMax, remainderTest;
	int			index;

	/* Check and decrease sizeMax as necessary */
	numAteSizes = sizeMax / sizeInc;
	remainderTest = numAteSizes * sizeInc;
	if (remainderTest == sizeMax)
		newSizeMax = sizeMax;
	else
		newSizeMax = remainderTest;
	if (newSizeMax <= sizeInc || sizeInc == 0)
	{
		fprintf(ateOutput, "You goofed over here\n");
		fflush(ateOutput);
		return(0);
	}

	/* Generate list file in T: */
	executeSuccess = Execute("List FONTS:_ATE_#? <NIL: >T:ateFonts.ate", 0, 0);
	if (executeSuccess == FALSE)
	{
		fprintf(ateOutput, "Some stupid goofup gathering ATE fonts happened.\n"
				   "Make sure you have the List command in your system.\n");
		fflush(ateOutput);
		return(0);
	}
	ateListFile = fopen("T:ateFonts.ate", "r");
	if (ateListFile == 0)
	{
		fprintf(ateOutput, "This isn't supposed to happen; make sure you have T: assigned.\n");
		fflush(ateOutput);
		return(0);
	}
	fgets(readLine, 100, ateListFile);	/* skip first line */
	while (!feof(ateListFile))
	{
		asciiValue = 0;
		numAteNames = 0;
		charName[0] = 0;
		readLine[0] = 0;
		fgets(readLine, 100, ateListFile);
		sscanf(readLine, "%d files - %d blocks used", &numAteNames, &asciiValue);
		if (numAteNames != 0)
			break;
	}
	if (feof(ateListFile) && numAteNames == 0)
	{
		fprintf(ateOutput, "You don't have any _ATE_ files in FONTS:.\n"
				   "Run ATE Control Panel to install them.\n");
		fflush(ateOutput);
		fclose(ateListFile);
		return(0);
	}
	fclose(ateListFile);

	/* ATEAvailFonts struct */
	tempATEAvailFonts = (struct ATEAvailFonts *)AllocVec(sizeof(struct ATEAvailFonts)
							+ numAteNames * 32,
							MEMF_PUBLIC | MEMF_CLEAR);
	if (tempATEAvailFonts == 0)
	{
		fprintf(ateOutput, "Not enough memory to get AvailFonts struct\n"
				   "in place, probably not enough memory to run ATE.\n");
		fflush(ateOutput);
		return(0);
	}

	/* Fill out contents of ATEAvailFonts struct */
	afATEFonts = numAteNames * numAteSizes * sizeof(struct TAvailFonts);
	tempATEAvailFonts->aaf_SizeDiskFonts = diskfontSize;
	tempATEAvailFonts->aaf_SizeATEFonts =  afATEFonts;
	tempATEAvailFonts->aaf_SizeATEData = numAteNames * 32 + sizeof(struct TagItem) * 2;
	tempATEAvailFonts->aaf_ATETags[0].ti_Tag = TA_DeviceDPI;
	tempATEAvailFonts->aaf_ATETags[0].ti_Data = 0x00010000 * defaultDPI + defaultDPI;
	tempATEAvailFonts->aaf_ATETags[1].ti_Tag = TAG_END;
	tempATEAvailFonts->aaf_ATETags[1].ti_Data = 0;
	/* Now build all the fontname list (Oh joy) at least it should work */
	tempATEAvailFonts->aaf_FontNames = (char *)&tempATEAvailFonts[1];/* Right after struct */
	tempATEAvailFonts->aaf_NumNames = numAteNames;
	tempATEAvailFonts->aaf_SizeATEData = sizeof(struct TagItem) * 2 + numAteNames * 32;
	afATEFontNames = tempATEAvailFonts->aaf_FontNames;
	ateListFile = fopen("T:ateFonts.ate", "r");
	/* Skip the first line */
	fgets(readLine, 100, ateListFile);
	for (index = 0; index < numAteNames; index++)
	{
		readLine[0] = 0;
		charName[0] = 0;
		fgets(readLine, 100, ateListFile);
		sscanf(readLine, "%s ", charName);
		if (charName[0] != 0)
		{
			strcpy(&afATEFontNames[index * 32], charName);
			strcat(&afATEFontNames[index * 32], ".font");
		}
	}
	fclose(ateListFile);
	tempATEAvailFonts->aaf_SizeInc = sizeInc;
	tempATEAvailFonts->aaf_SizeMax = newSizeMax;

	return(tempATEAvailFonts);
}

/* Nice function for PS tracing */
void PSTrace(char *format, ...)
{
	va_list	ap;

	if (optTrace == TRUE)
	{
		va_start(ap, format);
		vfprintf(ateOutput, format, ap);
		fflush(ateOutput);
		va_end(ap);
	}
	return;
}

/* Nice function for PS command tracing too */
void PSIntf(char *format, ...)
{
	va_list	ap;
	char	psString[200];

	if (psError != 0)
		return;

	va_start(ap, format);
	if (optDebug == TRUE)
	{
		vfprintf(ateOutput, format, ap);
		fflush(ateOutput);
	}
	vsprintf(psString, format, ap);
	psError = PSintstring(psActivation, psString, -1, PSFLAGSTRING);
	va_end(ap);
	return;
}

__geta4 __regargs ULONG NewDFbaseExpunge(__A6 struct Library *libBase)
{
	ULONG		tempResult;

	tempResult = OldDFbaseExpunge(libBase);
	/* This gives a PS re-start a better chance */

	/* Signal the main task to unload unused stuff */
	Signal(ateMainTask, 1 << ateDfeSigBit);

	return(tempResult);
}

__geta4 __regargs struct TextFont *NewOpenDiskFont(__A0 struct TextAttr *textAttr, __A6 struct Library *libBase)
{
struct	DiskfontMsg	*diskFontMsg;
struct	TextFont	*tempTextFont;
struct	SignalSemaphore	*ateSemaphore = &ateFontList->ateSemaphore;
struct	List		*fontList = &ateFontList->fontList;
struct	FontNode	*fontNode;
	char		*searchString;
	BOOL		msgSent;
	BOOL		ateFont;

	diskFontMsg = (struct DiskFontMsg *)AllocVec(sizeof(struct DiskfontMsg) + 64, MEMF_PUBLIC | MEMF_CLEAR);
	if (diskFontMsg != 0)
	{
		/* Search for existing font in node first */
		searchString = (char *)&diskFontMsg[1];
		sprintf(searchString, "%50s / %5d / %2x", textAttr->ta_Name, textAttr->ta_YSize, (textAttr->ta_Style & (FSF_BOLD | FSF_ITALIC)));
		ObtainSemaphoreShared(ateSemaphore);
		fontNode = (struct FontNode *)FindName(fontList, searchString);
		ReleaseSemaphore(ateSemaphore);
		if (fontNode == 0)
		{
			/* Prepare message for sending */
			diskFontMsg->df_ATEMsg.ate_MsgLength = sizeof(struct DiskfontMsg);
			diskFontMsg->df_ATEMsg.ate_DestPort = ateODFPort;
			diskFontMsg->df_TextAttr = textAttr;
			diskFontMsg->df_TextFont = 0;
			/* send message */
			msgSent = ATESendMsg((struct ATEMessage *)diskFontMsg);
			ateFont = diskFontMsg->df_ATEFont;
			tempTextFont = diskFontMsg->df_TextFont;
		}
		FreeVec(diskFontMsg);
	}
	tempTextFont = OldOpenDiskFont(textAttr, libBase);
	return(tempTextFont);
}

/* New patch for NewScaledDiskFont() */
__geta4 __regargs struct DiskFontHeader *NewNSDF(__A0 struct TextFont *textFont, __A1 struct TextAttr *textAttr, __A6 struct Library *libBase)
{
	char		*fontName;
struct	DiskFontHeader	*dfHeader;
struct	NsdfMsg		*nsdfMsg;
	BOOL		msgSent;

	fontName = textFont->tf_Message.mn_Node.ln_Name;
	if (memcmp(fontName, "_ATE_", 5) == 0)
	{
		nsdfMsg = (struct NsdfMsg *)AllocVec(sizeof(struct NsdfMsg), MEMF_PUBLIC | MEMF_CLEAR);
		if (nsdfMsg != 0)
		{
			nsdfMsg->nsdf_ATEMsg.ate_MsgLength = sizeof(struct NsdfMsg);
			nsdfMsg->nsdf_ATEMsg.ate_DestPort = ateNSDFPort;
			nsdfMsg->nsdf_TextAttr = textAttr;
			nsdfMsg->nsdf_TextFont = textFont;
			nsdfMsg->nsdf_DFHeader = 0;
			/* send message */
			msgSent = ATESendMsg((struct ATEMessage *)nsdfMsg);
			dfHeader = nsdfMsg->nsdf_DFHeader;
		}
	}
	else
		dfHeader = OldNSDF(textFont, textAttr, libBase);
	
	return(dfHeader);

}

__geta4 __regargs void NewText(__A1 struct RastPort *rastPort, __A0 STRPTR textString, __D0 WORD length, __A6 struct Library *libBase)
{
struct	TextMsg		*textMsg;
struct	FontNode	*fontNode;
struct	SignalSemaphore	*ateSemaphore = &ateFontList->ateSemaphore;
struct	List		*fontList = &ateFontList->fontList;
	BOOL		msgSent;
	char		*searchString;
	BOOL		softStyleMode = FALSE;
	BOOL		localOptSoftStyles = optSoftStyles;
	UBYTE		ateStyle = FS_NORMAL;
	UBYTE		ssModeOldStyle = rastPort->AlgoStyle;
struct	TextFont	*ssModeOldFont = rastPort->Font;

	textMsg = (struct TextMsg *)AllocVec(sizeof(struct TextMsg) + 64, (MEMF_PUBLIC | MEMF_CLEAR));
	if (textMsg != 0)
	{
		/* Check if SetSoftStyle was blatantly used */
		ateStyle = ssModeOldStyle & (FSF_BOLD | FSF_ITALIC);
		if (ateStyle != FS_NORMAL)
			softStyleMode = TRUE;

		searchString = (char *)&textMsg[1];
		/* find the fontNode */
		if (softStyleMode == TRUE)
			sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, ateStyle);
		else
			sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, rastPort->Font->tf_Style);
		ObtainSemaphoreShared(ateSemaphore);
		fontNode = (struct FontNode *)FindName(fontList, searchString);
		ReleaseSemaphore(ateSemaphore);

		if (softStyleMode == TRUE && fontNode != 0)
		{
			if (fontNode->fn_BlackList == FALSE)
			{
				SetFont(rastPort, fontNode->fn_TextFont);
				OldSSStyle(rastPort, ssModeOldStyle ^ ateStyle,
					   FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED, gfxBase);
			}
			else
				fontNode = 0;
		}
		if (fontNode == 0)
		{
			/* Repeat search for normal style */
			sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, FS_NORMAL);
			ObtainSemaphoreShared(ateSemaphore);
			fontNode = (struct FontNode *)FindName(fontList, searchString);
			ReleaseSemaphore(ateSemaphore);
			/* If this was an ATE font without styles, cancel SoftStyle mode */
			if (fontNode != 0)
			{
				softStyleMode = FALSE;
				/* If soft styles aren't allowed on ATE fonts, change it */
				if (localOptSoftStyles == FALSE)
					rastPort->AlgoStyle = ssModeOldStyle ^ ateStyle;
			}
		}
		if (fontNode != 0)
		{
			if (fontNode->fn_BlackList == FALSE)
			{
				/* Prepare TextMsg struct for use */
				textMsg->tm_ATEMsg.ate_DestPort = ateTextPort;
				textMsg->tm_ATEMsg.ate_MsgLength = sizeof(struct TextMsg);
				textMsg->tm_RastPort = rastPort;
				textMsg->tm_FontNode = fontNode;
				textMsg->tm_Chars = textString;
				textMsg->tm_Length = length;
				/* send the message */
				msgSent = ATESendMsg((struct ATEMessage *)textMsg);
			}
		}
		FreeVec(textMsg);
	}

	OldText(rastPort, textString, length, libBase);

	if (softStyleMode == TRUE && fontNode != 0)
	{
		SetFont(rastPort, ssModeOldFont);
		OldSSStyle(rastPort, ssModeOldStyle ^ ateStyle,
			   FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED, gfxBase);
	}
	if (localOptSoftStyles == FALSE && softStyleMode == FALSE && fontNode != 0)
		OldSSStyle(rastPort, ssModeOldStyle ^ ateStyle,
			   FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED, gfxBase);

	return;
}

/* Various patches for TextLength, TextExtent, and TextFit

__geta4 __regargs WORD NewTextLength(__A1 struct RastPort *rastPort, __A0 STRPTR aString, __D0 WORD strCount, __A6 struct Library *libBase)
{
	WORD		textLength;
struct	FontNode	*fontNode;
struct	TextFont	*oldTextFont = rastPort->Font;
	UBYTE		oldStyle = rastPort->AlgoStyle;

	fontNode = SwapSoftStyle(rastPort);
	
	textLength = OldTextLength(rastPort, aString, strCount, libBase);

	if (fontNode != 0)
		UndoSwapSoftStyle(rastPort, oldTextFont, oldStyle);

	return(textLength);
}

__geta4 __regargs struct TextExtent *NewTextExtent(__A1 struct RastPort *rastPort, __A0 STRPTR aString, __D0 WORD strCount, __A2 struct TextExtent *tExtent)
{
struct	TextExtent	*destTextExtent;
struct	FontNode	*fontNode;
struct	TextFont	*oldTextFont = rastPort->Font;
	UBYTE		oldStyle = rastPort->AlgoStyle;

	fontNode = SwapSoftStyle(rastPort);
	
	destTextExtent = OldTextExtent(rastPort, aString, strCount, tExtent, gfxBase);

	if (fontNode != 0)
		UndoSwapSoftStyle(rastPort, oldTextFont, oldStyle);

	return(destTextExtent);
} */

/* Unlike the previous patches, this patch needs a bit more intelligence.
   As such, the server will pass back a new TextFont ptr and style bits
   not yet set (such as FSF_UNDERLINED) so the patch can still set a 
   software style as required.  This will then SetFont() the font passed
   back and SetSoftStyle() any missing styles.

   Oops.  Because some programs work in mysterious ways, I SetFont() the
   styled fonts in the Text() patch now, instead. */
__geta4 __regargs ULONG NewSSStyle(__A1 struct RastPort *rastPort, __D0 ULONG newStyle, __D1 ULONG enable, __A6 struct Library *libBase)
{
struct	SSStyleMsg	*sssMsg;
struct	FontNode	*fontNode;
struct	SignalSemaphore	*ateSemaphore = &ateFontList->ateSemaphore;
struct	List		*fontList = &ateFontList->fontList;
	ULONG		stylesNeeded = newStyle;
	ULONG		resultingStyle;
	ULONG		ateStyle;
	BOOL		msgSent;
	char		*searchString;

	ateStyle = newStyle & enable & (FSF_BOLD | FSF_ITALIC);
	if (ateStyle != FS_NORMAL)
	{
		sssMsg = (struct SSStyleMsg *)AllocVec(sizeof(struct SSStyleMsg) + 64, (MEMF_PUBLIC | MEMF_CLEAR));
		if (sssMsg != 0)
		{
			/* Search through list for existing style first */
			searchString = (char *)&sssMsg[1];
			sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, ateStyle);
			ObtainSemaphoreShared(ateSemaphore);
			fontNode = (struct FontNode *)FindName(fontList, searchString);
			ReleaseSemaphore(ateSemaphore);
			if (fontNode == 0)
			{
				/* Check for ATE normal style */
				sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, FS_NORMAL);
				ObtainSemaphoreShared(ateSemaphore);
				fontNode = (struct FontNode *)FindName(fontList, searchString);
				ReleaseSemaphore(ateSemaphore);
				if (fontNode != 0)
				{
					/* prepare message struct */
					sssMsg->ss_ATEMsg.ate_DestPort = ateSSSPort;
					sssMsg->ss_ATEMsg.ate_MsgLength = sizeof(struct SSStyleMsg);
					sssMsg->ss_RastPort = rastPort;
					sssMsg->ss_FontNode = fontNode;
					sssMsg->ss_NewStyle = newStyle;
					sssMsg->ss_Enable = enable;
					sssMsg->ss_SoftStyleNeeded = newStyle;
					/* Send the message */
					msgSent = ATESendMsg((struct ATEMessage *)sssMsg);
				}
			}
			FreeVec(sssMsg);
		}
	}

	/* Call original function to complete any needed style change */
	resultingStyle = OldSSStyle(rastPort, newStyle, enable, libBase);

	return(resultingStyle);
}

/* Logic behind AvailFonts() patch:
   textAttrs use pointers to names, not the names themselves.  So the names
   need to be in that memory space somewhere.  I work around diskfont.library's
   AvailFonts() call by spotting the temporary AvailFontsHeader in the middle
   of the memory pool, then call it with the original parameters, and copy
   the NumEntries value.  Then I add my extra data at the end of where 
   diskfont.library put its extra data, and fill in the beginning of the pool
   with my (T)AvailFonts, NumEntries plus numTAs, then exit. (whew.) */
__geta4 __regargs LONG NewAvailFonts(__A0 struct AvailFontsHeader *afhBuffer, __D0 LONG afBufSize, __D1 ULONG afFlags, __A6 struct Library *libBase)
{
	/* Use local ptrs */
struct	ATEAvailFonts		*nafAteAvailFonts;
struct	SignalSemaphore		*nafSemaphore = &aafSemaphore;
struct	AvailFonts		*nafAvailFonts;
struct	TAvailFonts		*nafTAvailFonts;
	int			diskAFSize, ateAFSize, ramAFSize, ateDataSize;
	int			totalAFSize, tempAFSize;
	int			numAteAfs, numEachName;
	int			numAmigaAfs, index, index2;
struct	AvailFontsHeader	*tempAfhBuffer;
	char			*ateFontNames;
struct	TagItem			*ateTags;

	/* First get access to the ATEAvailFonts struct */
	ObtainSemaphoreShared(nafSemaphore);

	/* Preload local variables */
	nafAteAvailFonts = ateAvailFonts;
	diskAFSize = nafAteAvailFonts->aaf_SizeDiskFonts;
	ateAFSize = nafAteAvailFonts->aaf_SizeATEFonts;
	ateDataSize = nafAteAvailFonts->aaf_SizeATEData;
	numEachName = nafAteAvailFonts->aaf_SizeMax / nafAteAvailFonts->aaf_SizeInc;
	numAteAfs = numEachName * nafAteAvailFonts->aaf_NumNames;

	/* Determine total size needed */
	ramAFSize = OldAvailFonts(afhBuffer, 0, afFlags & !(AFF_DISK), libBase);
	totalAFSize = ramAFSize;
	if (afFlags & AFF_DISK)
		totalAFSize = totalAFSize + diskAFSize + ateAFSize + ateDataSize;
	if (totalAFSize > afBufSize)
	{
		/* Reject and return space needed */
		ReleaseSemaphore(nafSemaphore);
		return(totalAFSize - afBufSize);
	}

	/* If they don't want diskfonts, call AvailFonts again and exit now */
	if (!(afFlags & AFF_DISK))
	{
		tempAFSize = OldAvailFonts(afhBuffer, afBufSize, afFlags, libBase);
		ReleaseSemaphore(nafSemaphore);
		return(tempAFSize);
	}

	/* Supposely we have enough space now.  Spot the beginning of the Amiga
	   font list further down the list, by NumTAs * sizeof(struct [T]TextAttr) */
	if (afFlags & AFF_TAGGED)
		ateAFSize = sizeof(struct TAvailFonts) * numAteAfs;
	else
		ateAFSize = sizeof(struct AvailFonts) * numAteAfs;
	tempAfhBuffer = (struct AvailFontsHeader *)((ULONG)afhBuffer + ateAFSize);

	/* Call AvailFonts() with new buffer position */
	if (diskAFSize != 0)
		tempAFSize = OldAvailFonts(tempAfhBuffer, ramAFSize + diskAFSize, afFlags, libBase);
	else
		tempAFSize = OldAvailFonts(tempAfhBuffer, ramAFSize, (afFlags & (!AFF_DISK)), libBase);

	/* Position other pointers past Amiga availfonts data */
	ateTags = (struct TagItem *)((ULONG)afhBuffer + ateAFSize + ramAFSize + diskAFSize);
	ateFontNames = (char *)((ULONG)afhBuffer + ateAFSize + ramAFSize + diskAFSize + sizeof(struct TagItem) * 2);
	/* Insert tagitems and font names after Amiga availfonts data */
	ateTags[0].ti_Tag = nafAteAvailFonts->aaf_ATETags[0].ti_Tag;
	ateTags[0].ti_Data = nafAteAvailFonts->aaf_ATETags[0].ti_Data;
	ateTags[1].ti_Tag = nafAteAvailFonts->aaf_ATETags[1].ti_Tag;
	ateTags[1].ti_Data = nafAteAvailFonts->aaf_ATETags[1].ti_Data;
	/* Insert font names after the tagitems */
	for (index = 0; index < nafAteAvailFonts->aaf_NumNames; index++)
	{
		strcpy(&ateFontNames[index * 32], &nafAteAvailFonts->aaf_FontNames[index * 32]);
	}
	/* Get number of Non-ATE AFs */
	numAmigaAfs = tempAfhBuffer->afh_NumEntries;

	/* Now insert ATE TextAttrs at the top of the list */
	afhBuffer->afh_NumEntries = numAmigaAfs + numAteAfs;
	/* Do two versions: one for AvailFonts and one for TAvailFonts */
	if (afFlags & AFF_TAGGED)
	{
		nafTAvailFonts = (struct TAvailFonts *)&afhBuffer[1];
		for (index = 0; index < nafAteAvailFonts->aaf_NumNames; index++)
		{
			for (index2 = 1; index2 <= numEachName; index2++)
			{ 
				nafTAvailFonts->taf_Type = AFF_DISK;
				nafTAvailFonts->taf_Attr.tta_Name = &ateFontNames[index * 32];
				nafTAvailFonts->taf_Attr.tta_YSize = nafAteAvailFonts->aaf_SizeInc * index2;
				nafTAvailFonts->taf_Attr.tta_Style = FS_NORMAL | FSF_TAGGED;
				nafTAvailFonts->taf_Attr.tta_Flags = FPF_DESIGNED | FPF_DISKFONT | FPF_PROPORTIONAL;
				nafTAvailFonts->taf_Attr.tta_Tags = ateTags;
				nafTAvailFonts++;
			}
		}
	}
	else
	{
		nafAvailFonts = (struct AvailFonts *)&afhBuffer[1];
		for (index = 0; index < nafAteAvailFonts->aaf_NumNames; index++)
		{
			for (index2 = 1; index2 <= numEachName; index2++)
			{
				nafAvailFonts->af_Type = AFF_DISK;
				nafAvailFonts->af_Attr.ta_Name = &ateFontNames[index * 32];
				nafAvailFonts->af_Attr.ta_YSize = nafAteAvailFonts->aaf_SizeInc * index2;
				nafAvailFonts->af_Attr.ta_Style = FS_NORMAL;
				nafAvailFonts->af_Attr.ta_Flags = FPF_DESIGNED | FPF_DISKFONT | FPF_PROPORTIONAL;
				nafAvailFonts++;
			}
		}
	}

	ReleaseSemaphore(nafSemaphore);
	return(0);
	/* whew! */
}

/* Message sender.  This guy gets a lot of working out! */
BOOL ATESendMsg(struct ATEMessage *ateMsg)
{
struct	MsgPort		*msgPort, *replyPort;
struct	Message		*replyMsg;
	ULONG		portSig;

/* generate reply port */
	replyPort = CreateMsgPort();
	if (replyPort == 0)
		return(FALSE);
	
/* Reply port set up.  Now build the message. */
	ateMsg->ate_Message.mn_Length = ateMsg->ate_MsgLength;
	ateMsg->ate_Message.mn_ReplyPort = replyPort;

/* OK we have a valid reply port and a message.  Time to send it. */
	portSig = 1 << replyPort->mp_SigBit;
	msgPort = ateMsg->ate_DestPort;
	PutMsg(msgPort,(struct Message *)ateMsg);
	Wait(portSig);
	replyMsg=GetMsg(replyPort);

/* So, sent the message.  Now free the port & exit */
	DeleteMsgPort(replyPort);
	if ((msgPort != 0) && (replyMsg != 0))
		return(TRUE);
	else
		return(FALSE);
}

/* This function will provide a new font ptr in case the app calling
   a Text or text measuring function blatantly used a software style
   instead of asking for a style in OpenFont().  It also returns
   a fontnode for the Text() patch. 

struct FontNode *SwapSoftStyle(struct RastPort *rastPort, BOOL textSizer)
{
struct	List		*fontList = &ateFontList->fontList;
struct	SignalSemaphore	*ateSemaphore = &ateFontList->ateSemaphore;
struct	FontNode	*fontNode;
	char		searchString[64];
	int		checkATEvar;
	BOOL		softStyleMode = FALSE;
	BOOL		localOptSoftStyles = optSoftStyles;
	UBYTE		ateStyle = FS_NORMAL;
	UBYTE		ssModeOldStyle = rastPort->AlgoStyle;
struct	TextFont	*ssModeOldFont = rastPort->Font;

	 First check for blatant software styles 
	ateStyle = ssModeOldStyle & (FSF_BOLD | FSF_ITALIC);
	checkATEvar = memcmp(rastPort->Font->tf_Message.mn_Node.ln_Name, "_ATE_", 5);

	if (ateStyle != FS_NORMAL && ckeckATEvar == 0)
		softStyleMode = TRUE;
	else
		return(0);

	if (softStyleMode == TRUE)
		sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, ateStyle);
	else
		sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, rastPort->Font->tf_Style);

	ObtainSemaphoreShared(ateSemaphore);
	fontNode = (struct FontNode *)FindName(fontList, searchString);
	ReleaseSemaphore(ateSemaphore);
	if (softStyleMode == TRUE && fontNode != 0)
	{
		if (fontNode->fn_BlackList == FALSE)
		{
			SetFont(rastPort, fontNode->fn_TextFont);
			OldSSStyle(rastPort, ssModeOldStyle ^ ateStyle,
				   FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED, gfxBase);
		}
		else
			fontNode = 0;
	}
	if (fontNode == 0)
	{
		 Repeat search for normal style 
		sprintf(searchString, "%50s / %5d / %2x", rastPort->Font->tf_Message.mn_Node.ln_Name, rastPort->Font->tf_YSize, FS_NORMAL);
		ObtainSemaphoreShared(ateSemaphore);
		fontNode = (struct FontNode *)FindName(fontList, searchString);
		ReleaseSemaphore(ateSemaphore);
		 If this was an ATE font without styles, cancel SoftStyle mode

		if (fontNode != 0)
		{
			softStyleMode = FALSE;
			 If soft styles aren't allowed on ATE fonts, change it 
			if (localOptSoftStyles == FALSE)
				OldSSStyle(rastPort, ssModeOldStyle ^ ateStyle,
				           FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED, gfxBase);
		}
	}

	return(fontNode);
}

void UndoSwapSoftStyle(struct RastPort *rastPort, struct TextFont *textFont, UBYTE softStyle)
{

	if (softStyle != 0)
	{
		SetFont(rastPort, textFont);
		OldSSStyle(rastPort, softStyle, FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED, gfxBase);
	}

	return;
} */
