/* Adobe Type Manager BETA 1.0 for the Amiga
   Perpetrated by OPTIMUS PRIME, AUTOBOT Commander
   (Also known as Gordon Fecyk)

   This BETA source code may NOT be disributed or altered.
   Liabilities: If anything bad happens to your computer I'm not responsible.
   So there.  Thphth.

   Source is specific for DICE C 3.0 for the Amiga.  Requires
   postlib.h and post.library 1.7 by Adrian Ayward.
*/

#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 "postlib.h"

/* Set to 1 for printing PostScript debugging messages */
#define OPTTRACE 0
#define OPTDEBUG 0

/* 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 */
	APTR		functionTable[10];	/* Table of external fcns for POST */
	char		nameBuffer[100 + 5];	/* Bogus space for PS initalization */

	/* Functions called by POST use these pointers */
	int		*charPosX, *charPosY;
	int		*lowLeftX, *lowLeftY, *upRightX, *upRightY;
/* end of PostScript external data (I hope) */

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

/* 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];
	/* 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_LowLeftX[256], fn_LowLeftY[256];
		int		fn_UpRightX[256], fn_UpRightY[256];
		int		fn_CharPosX, fn_CharPosY;
	/* Pointers to data areas in the TextFont struct */
		char		*fn_CharData, *fn_CharFontName;
		short		*fn_CharLoc, *fn_CharSpace, *fn_CharKern;
	/* The TextFont in question */
	struct	TextFont	*fn_TextFont;
	};

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

/* Message structures, all based on my extended Message struct ATMMessage */
struct	ATMMessage {
	struct	Message		atm_Message;
		int		atm_MsgLength;
		char		*atm_DestPort;
	};

struct	DiskfontMsg {
	struct	ATMMessage	df_ATMMsg;
	struct	TextAttr	*df_TextAttr;
	struct	TextFont	*df_TextFont;
		BOOL		df_ATMFont;
	};

struct	TextMsg {
	struct	ATMMessage	tm_ATMMsg;
	struct	RastPort	*tm_RastPort;
		STRPTR		tm_Chars;
		WORD		tm_Length;
		BOOL		tm_ATMFont;
	};

struct	SSStyleMsg {
	struct	ATMMessage	ss_ATMMsg;
	struct	RastPort	*ss_RastPort;
		ULONG		ss_NewStyle;
		ULONG		ss_Enable;
	struct	TextFont	*ss_ChangedFont;
		ULONG		ss_SoftStyleNeeded;
		BOOL		ss_ATMFont;
	};

/* 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);
/* Message sender for the above three patches */
__geta4		  	 BOOL		ATMSendMsg(struct ATMMessage *atmMsg);

/* Prototypes of external functions that POST will use */
__geta4	void		SetBBox(int aChar, int leftX, int leftY, int rightX, int rightY);
__geta4	void		SetCPos(int charPosX, int charPosY);
__geta4	void		SigInt(void);

/* 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	*MakeATMFont(struct FontNode *fontNode, struct TextAttr *textAttr);
	BOOL		MakeATMChars(struct FontNode *fontNode);

/* Functions from older versions of ATMServer (with a new one: AddATMStyle) */
	void		chkabort(void) { return; };	/* Kill CTRL-C handler */
	void		ClearFontNames(struct List *fontList);
	BOOL		AddATMFont(struct List *fontList, struct DiskfontMsg *diskfontMsg);
	BOOL		AddATMStyle(struct List *fontList, struct SSStyleMsg *sssMsg);
	BOOL		AddATMChars(struct List *fontList, struct TextMsg *textMsg);

/* Mainline of code */
int main()
{
	APTR		oldFuncPtr, newFuncPtr = &NewOpenDiskFont;
	APTR		oldTextPtr, newTextPtr = &NewText;
	APTR		oldSSSPtr, newSSSPtr = &NewSSStyle;
	char		*versionInfo = "$VER:  AdobeTypeManager_BETA 1.0 for the Amiga (01.4.95)";
struct	List		*fontList;
struct	DiskfontMsg	*diskfontMsg;
struct	TextMsg		*textMsg;
struct	SSStyleMsg	*sssMsg;
struct	MsgPort		*atmODFPort, *atmTextPort, *atmSSSPort;
	ULONG		signal, odfSig, textSig, sssSig, breakSig = SIGBREAKF_CTRL_C;
	BOOL		keepGoing = TRUE;

	/* Do as much allocating as practical then check for failures */
		/* Message ports */
	atmODFPort = CreateMsgPort();
	atmTextPort = CreateMsgPort();
	atmSSSPort = CreateMsgPort();
		/* ATM font list */
	fontList = (struct List *)AllocMem(sizeof(struct List ), MEMF_CLEAR);
		/* post.library (minimum V15) */
	PSbase = OpenLibrary("post.library", 15L);
		/* graphics and diskfont libraries (mininum V36) */
	diskfontBase = OpenLibrary("diskfont.library", 36L);
	gfxBase = OpenLibrary("graphics.library", 36L);

	/* check for failures */
	if (atmODFPort == 0 || atmTextPort == 0 || atmSSSPort == 0 || PSbase == 0 || gfxBase == 0 || diskfontBase == 0 || fontList == 0)
	{
		if (atmSSSPort != 0)
			DeleteMsgPort(atmSSSPort);
		else
			printf("Error opening one message port\n");
		if (atmODFPort != 0)
			DeleteMsgPort(atmODFPort);
		else
			printf("Error opening one message port\n");
		if (atmTextPort != 0)
			DeleteMsgPort(atmTextPort);
		else
			printf("Error opening one message port\n");
		if (PSbase != 0)
			CloseLibrary(PSbase);
		else
			printf("Error opening post.library\n");
		if (fontList != 0)
			FreeMem(fontList, sizeof(struct List));
		else
			printf("Error allocating RAM for fontList\n");
		if (gfxBase != 0)
			CloseLibrary(gfxBase);
		else
			printf("Error opening graphics.library\n");
		if (diskfontBase != 0)
			CloseLibrary(diskfontBase);
		else
			printf("Error opening diskfont.library\n");
	}

	/* initalize the PostScript activation */
	PSTrace("%%Initalizing PostScript Activation\n");
	psParm.page.buf[0] = nameBuffer;
	psParm.page.len = 100;
	psParm.page.depth = 1;
	psParm.page.xoff = 0;
	psParm.page.yoff = 0;
	psParm.page.xbytes = 10;
	psParm.page.xsize = 80;
	psParm.page.ysize = 10;
	psParm.page.ybase = 0;
	psParm.page.xden = 72;
	psParm.page.yden = 72;
	psParm.page.ydir = -1;
	psParm.memvlen = 20000;
	psParm.memflen = 10000;
	psParm.memllen = defmemllen;
	psParm.memhlen = minmemhlen;
	psParm.infh = Input();
	psParm.outfh = Output();
	psParm.errfh = Output();
	psParm.funcmax = 2;
	functionTable[0] = &SetBBox;
	functionTable[1] = &SetCPos;
	psParm.functab = functionTable;
	psParm.userdata = 0;
	psParm.flushfunc = 0;
	psParm.copyfunc = 0;
	psParm.reserved[0] = 0;
	psParm.reserved[1] = 0;

	psActivation = PScreateact(&psParm);
	if (psActivation <= errmax)
	{
		printf("PostScript activation failed\n");
		DeleteMsgPort(atmODFPort);
		DeleteMsgPort(atmTextPort);
		DeleteMsgPort(atmSSSPort);
		FreeMem(fontList, sizeof(struct List));
		CloseLibrary(PSbase);
		CloseLibrary(gfxBase);
		CloseLibrary(diskfontBase);
		return(20);
	}

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

	/* Setup ports and list */
	atmODFPort->mp_Node.ln_Name = "ATM_ODF_Port";
	atmTextPort->mp_Node.ln_Name = "ATM_Text_Port";
	atmSSSPort->mp_Node.ln_Name = "ATM_SSS_Port";
	odfSig = 1 << atmODFPort->mp_SigBit;
	textSig = 1 << atmTextPort->mp_SigBit;
	sssSig = 1 << atmSSSPort->mp_SigBit;
	atmODFPort->mp_Node.ln_Pri = 0;
	atmTextPort->mp_Node.ln_Pri = 0;
	atmSSSPort->mp_Node.ln_Pri = 0;
	AddPort(atmODFPort);
	AddPort(atmTextPort);
	AddPort(atmSSSPort);
	fontList->lh_Type = NT_USER;
	NewList(fontList);
	printf("ATM BETA 1.0 ready.  Press CTRL-C to exit.\n");

	/* Perform patches */
	Forbid();
	oldFuncPtr = SetFunction(diskfontBase, -0x1E, newFuncPtr);
	OldOpenDiskFont = oldFuncPtr;
	oldTextPtr = SetFunction(gfxBase, -0x3C, newTextPtr);
	OldText = oldTextPtr;
	oldSSSPtr = SetFunction(gfxBase, -0x5A, newSSSPtr);
	OldSSStyle = oldSSSPtr;
	Permit();
	/* I got the offsets from the included pragmas files. */

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

		if ((signal & breakSig) || (keepGoing == FALSE))
		{
			/* Clear out all ports */
			while (diskfontMsg = (struct DiskfontMsg *)GetMsg(atmODFPort))
			{
				diskfontMsg->df_ATMFont = FALSE;
				ReplyMsg((struct Message *)diskfontMsg);
			}
			RemPort(atmODFPort);
			while (textMsg = (struct textMsg *)GetMsg(atmTextPort))
			{
				textMsg->tm_ATMFont = FALSE;
				ReplyMsg((struct Message *)textMsg);
			}
			RemPort(atmTextPort);
			while (sssMsg = (struct sssMsg *)GetMsg(atmSSSPort))
			{
				sssMsg->ss_ATMFont = FALSE;
				ReplyMsg((struct Message *)sssMsg);
			}
			RemPort(atmSSSPort);
			keepGoing = FALSE;
			break;
		}
		if ((signal & textSig) && (keepGoing == TRUE))
		{
			while (textMsg = (struct TextMsg *)GetMsg(atmTextPort))
			{
				keepGoing = AddATMChars(fontList, textMsg);
				if (keepGoing == FALSE)
					PSTrace("%%Out of memory or some other error drawing new chars\n");
				ReplyMsg((struct Message *)textMsg);
			}
		}
		if ((signal & odfSig) && (keepGoing == TRUE))
		{
			while (diskfontMsg = (struct DiskfontMsg *)GetMsg(atmODFPort))
			{
				keepGoing = AddATMFont(fontList, diskfontMsg);
				if (keepGoing == FALSE)
					PSTrace("%%Out of memory creating new textfont\n");
				ReplyMsg((struct Message *)diskfontMsg);
			}
		}
		if ((signal & sssSig) && (keepGoing == TRUE))
		{
			while (sssMsg = (struct SSStyleMsg *)GetMsg(atmSSSPort))
			{
				keepGoing = AddATMStyle(fontList, sssMsg);
				if (keepGoing == FALSE)
					PSTrace("%%Out of memory creating new textfont for new style\n");
				ReplyMsg((struct Message *)sssMsg);
			}
		}
	}

	/* Clean up time */
	Forbid();
	newFuncPtr = SetFunction(diskfontBase, -0x1E, oldFuncPtr);
	newTextPtr = SetFunction(gfxBase, -0x3C, oldTextPtr);
	newSSSPtr = SetFunction(gfxBase, -0x5A, oldSSSPtr);
	Permit();
	/* Allow user to close applications that use ATM fonts */
	printf("Patches removed, press CTRL-C again to exit\n");
	Wait(breakSig);
	DeleteMsgPort(atmODFPort);
	DeleteMsgPort(atmTextPort);
	DeleteMsgPort(atmSSSPort);
	ClearFontNames(fontList);
	FreeMem(fontList, sizeof(struct List));
	PSdeleteact(psActivation);
	CloseLibrary(PSbase);

	printf("Now exiting.  Remember: This is BETA software!  Use at own risk!\n");
	return(0);
}

void ClearFontNames(struct List *fontList)
{
struct	FontNode	*workNode, *nextNode;

	workNode = (struct FontNode *)(fontList->lh_Head);
	while (nextNode = (struct FontNode *)(workNode->fn_Node.ln_Succ))
	{
		RemFont(workNode->fn_TextFont);
		FreeMem(workNode->fn_TextFont, workNode->fn_MaxFontLength + 64);
		FreeMem(workNode, sizeof(struct FontNode));
		workNode = nextNode;
	}
	return;
}

BOOL AddATMChars(struct List *fontList, struct TextMsg *textMsg)
{
struct	FontNode	*fontNode;
	char		*fontName, *builtChars, nodeName[64];
	STRPTR		oneChar;
	UWORD		fontSize;
	UBYTE		fontStyle, indexY;
	BOOL		callMakeATMChars = FALSE;
	BOOL		addATMCharsOK;
	WORD		indexX, length;

	fontName = textMsg->tm_RastPort->Font->tf_Message.mn_Node.ln_Name;
	fontSize = textMsg->tm_RastPort->Font->tf_YSize;
	fontStyle = (textMsg->tm_RastPort->Font->tf_Style) & (FSF_BOLD | FSF_ITALIC);
	/* NOTE: ATM can only worry about substituting bold or italic versions, */
	/*       setting soft styles will take care of underlining */

	sprintf(nodeName, "%50s / %5d / %2x", fontName, fontSize, fontStyle);
	fontNode = (struct FontNode *)FindName(fontList, nodeName);

	/* If the desired style isn't found try finding the plain style */
	if (fontNode == 0)
	{
		fontStyle = FS_NORMAL;
		sprintf(nodeName, "%50s / %5d / %2x", fontName, fontSize, fontStyle);
		fontNode = (struct FontNode *)FindName(fontList, nodeName);
	}

	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;
				callMakeATMChars = TRUE;
			}
		}
		textMsg->tm_ATMFont = TRUE;
		addATMCharsOK = TRUE;
		if (callMakeATMChars == TRUE)
		{
			addATMCharsOK = MakeATMChars(fontNode);
		}
	}
	else
	{
		textMsg->tm_ATMFont = FALSE;
		addATMCharsOK = TRUE;
	}

	return(addATMCharsOK);
}

BOOL AddATMFont(struct List *fontList, struct DiskfontMsg *diskfontMsg)
{
struct	TextAttr	*textAttr;
struct	FontNode	*fontNode;
	UBYTE		fontStyle;
	char		fontName[64], regularName[64], typefaceName[64];
	char		dummyString[80], *dotPtr, optFontEncoding;
	BOOL		addATMFontOK;
	FILE		*atmFile;
	int		lowChar, highChar;

	textAttr = diskfontMsg->df_TextAttr;
	/* Make sure the font in question is an ATM font. */
	strcpy(fontName, "FONTS:");
	strcat(fontName, textAttr->ta_Name);
	dotPtr = strchr(fontName, '.');
	*dotPtr = '\0';
	strcat(fontName, ".atm");
	/* OK try opening the file */
	atmFile = fopen(fontName, "r");
	if (atmFile == 0)
	{
		diskfontMsg->df_ATMFont = FALSE;
		return(TRUE);
		/* hey, not an ATM-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);
	/* NOTE: ATM can only worry about substituting bold or italic versions, */
	/*       setting soft styles will take care of underlining */

	fgets(dummyString, 79, atmFile);
	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, atmFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x04:
			fgets(dummyString, 79, atmFile);
			fgets(dummyString, 79, atmFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x06:
			fgets(dummyString, 79, atmFile);
			fgets(dummyString, 79, atmFile);
			fgets(dummyString, 79, atmFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		default:
			break;
	}

	fclose(atmFile);
	/* 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);
	fontNode = (struct FontNode *)FindName(fontList, fontName);
	if (fontNode != 0)
	{
		diskfontMsg->df_ATMFont = TRUE;
		diskfontMsg->df_TextFont = fontNode->fn_TextFont;
		return(TRUE);
		/* Hey, why work if you already have results? */
	}

	/* So no font node eh?  Time to make one. */
	fontNode = (struct FontNode *)AllocMem(sizeof(struct FontNode), 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);
		fontNode->fn_LowChar = lowChar;
		fontNode->fn_HighChar = highChar;
		fontNode->fn_OptFontEncoding = optFontEncoding;
		fontNode->fn_Style = fontStyle;
		fontNode->fn_FontSize = textAttr->ta_YSize;
		fontNode->fn_TextFont = MakeATMFont(fontNode, textAttr);
		if (fontNode->fn_TextFont != 0)
		{
			AddFont(fontNode->fn_TextFont);
			diskfontMsg->df_TextFont = fontNode->fn_TextFont;
			diskfontMsg->df_ATMFont = TRUE;
			AddHead(fontList, (struct Node *)fontNode);
			addATMFontOK = TRUE;
		}
		else
		{
			diskfontMsg->df_ATMFont = FALSE;
			addATMFontOK = FALSE;
			FreeMem(fontNode, sizeof(struct FontNode));
		}
	}
	else
	{
		diskfontMsg->df_ATMFont = FALSE;
		addATMFontOK = FALSE;
	}
	return(addATMFontOK);
}

/* This function mimics AddATMFont except it adds fonts upon SetSoftStyle()
   calls instead of OpenDiskFont() calls.  This fcn takes special
   consideration of ta_Style flags. */
BOOL AddATMStyle(struct List *fontList, struct SSStyleMsg *sssMsg)
{
struct	FontNode	*fontNode;
struct	RastPort	*sssRastPort = sssMsg->ss_RastPort;
struct	TextFont	*sssTextFont = sssMsg->ss_RastPort->Font;
struct	TextAttr	dummyAttr;	/* For calling MakeATMFont */
	char		*currentFontName, fontName[64], dummyString[80], *dotPtr;
	char		typefaceName[64], regularName[64], optFontEncoding;
	int		fontSize, currentStyle, desiredStyle, lowChar, highChar;
	FILE		*atmFile;
	BOOL		addATMStyleOK;

	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);
	fontNode = (struct FontNode *)FindName(fontList, fontName);
	if (fontNode != 0)
	{
		sssMsg->ss_ATMFont = TRUE;
		sssMsg->ss_ChangedFont = fontNode->fn_TextFont;
		sssMsg->ss_SoftStyleNeeded = currentStyle ^ desiredStyle;
		return(TRUE);
		/* Hey, why work if you already have results? */
	}

	/* repeat search for plain style (to avoid Intuition hangups) */
	sprintf(fontName, "%50s / %5d / %2x", currentFontName, fontSize, FS_NORMAL);
	fontNode = (struct FontNode *)FindName(fontList, fontName);
	if (fontNode == 0)
	{
		sssMsg->ss_ATMFont = FALSE;
		sssMsg->ss_SoftStyleNeeded = sssMsg->ss_NewStyle;
		return(TRUE);
		/* This isn't a loaded ATM font so exit */
	}

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

	/* Now search to see if requested typeface version exists */
	fgets(dummyString, 79, atmFile);
	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, atmFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		case 0x04:	/* FSF_ITALIC */
			fgets(dummyString, 79, atmFile);
			fgets(dummyString, 79, atmFile);
			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, atmFile);
			fgets(dummyString, 79, atmFile);
			fgets(dummyString, 79, atmFile);
			sscanf(dummyString, "&c %d %d", &optFontEncoding, &lowChar, &highChar);
			dotPtr = strchr(dummyString, '.');
			dotPtr++;
			strcpy(typefaceName, dotPtr);
			break;
		default:
			break;
	}
	fclose(atmFile);

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

	/* OK now make a new font node for this new style */
	fontNode = (struct FontNode *)AllocMem(sizeof(struct FontNode), 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);
		fontNode->fn_LowChar = lowChar;
		fontNode->fn_HighChar = highChar;
		fontNode->fn_OptFontEncoding = optFontEncoding;
		fontNode->fn_Style = currentStyle;
		fontNode->fn_FontSize = fontSize;
		dummyAttr.ta_Name = currentFontName;
		dummyAttr.ta_YSize = fontSize;
		dummyAttr.ta_Style = currentStyle;
		dummyAttr.ta_Flags = 0;
		/* Call MakeATMFont() to build this new font */
		fontNode->fn_TextFont = MakeATMFont(fontNode, &dummyAttr);
		if (fontNode->fn_TextFont != 0)
		{
			AddFont(fontNode->fn_TextFont);
			sssMsg->ss_ChangedFont = fontNode->fn_TextFont;
			sssMsg->ss_ATMFont = TRUE;
			AddHead(fontList, (struct Node *)fontNode);
			sssMsg->ss_SoftStyleNeeded = currentStyle ^ desiredStyle;
			addATMStyleOK = TRUE;
		}
		else
		{
			sssMsg->ss_ATMFont = FALSE;
			addATMStyleOK = FALSE;
			sssMsg->ss_SoftStyleNeeded = sssMsg->ss_NewStyle;
			FreeMem(fontNode, sizeof(struct FontNode));
		}
	}
	else
	{
		sssMsg->ss_ATMFont = FALSE;
		sssMsg->ss_SoftStyleNeeded = sssMsg->ss_NewStyle;
		addATMStyleOK = FALSE;
	}
	return(addATMStyleOK);
}

/* Here we build a new TextFont */
struct TextFont *MakeATMFont(struct FontNode *fontNode, struct TextAttr *textAttr)
{
struct	TextFont	*newFont;
	int		zZ, z1, z2, index, y1, y2;

	/* Since AddATMFont() did all the checking for this fcn, just start rendering */
	PSTrace("%%Loading typeface %s\n", fontNode->fn_TypefaceName);
	PSIntf("/fontname /%.100s def\n", fontNode->fn_TypefaceName);
	PSIntf("fontname findfont pop\n");
	PSIntf("/font fontname .findfont def\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");
		psError = -1;
		return(0);
	}

	/* Prepare external ptrs for BBox generation and start generating */
	lowLeftX = fontNode->fn_LowLeftX;
	lowLeftY = fontNode->fn_LowLeftY;
	upRightX = fontNode->fn_UpRightX;
	upRightY = fontNode->fn_UpRightY;
	PSTrace("%%Generating Bounding Boxes\n");
	PSIntf("/cstr 1 string def\n");
	PSIntf("newfont 1000 scalefont setfont\n");
	PSIntf(	"%d 1 %d\n"
		"{ /i exch def cstr 0 i put null i\n"
		"  0 0 moveto cstr false charpath pathbbox newpath\n"
		"  4 { round cvi 4 1 roll } repeat\n"
		"  5 0 callextfunc\n"
		"} for\n", fontNode->fn_LowChar, fontNode->fn_HighChar);
	if (psError != 0)
	{	
		PSTrace("%%PostScript error generating bounding boxes\n");
		psError = -1;
		return(0);
	}

	/* Start generating baseline info from BBox info */
	zZ = 1000;	/* 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 TextFont) + 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] - fontNode->fn_LowLeftX[index]) * fontNode->fn_FontSize) / 1000 + 2;
	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;

	newFont = (struct TextFont *)AllocMem((fontNode->fn_MaxFontLength + 64), (MEMF_PUBLIC | MEMF_CLEAR | MEMF_CHIP));
	if (newFont == 0)
	{
		PSTrace("%%Cannot get memory for new TextFont\n");
		psError = -1;
		return(0);
	}
	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  *)&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_ROMFONT | 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 MakeATMFont() except for tf_CharSpace */
	/* and tf_CharKern array generation.  The rest will move to MakeATMChars() */

	for (index = fontNode->fn_LowChar; index <= fontNode->fn_HighChar; index ++)
	{
		z1 = (fontNode->fn_LowLeftX[index] * fontNode->fn_FontSize * 72 - 41000) / 72000;
		z2 = (fontNode->fn_UpRightX[index] * fontNode->fn_FontSize * 72 + 41000) / 72000;
//		if (z1 < 0)
//			z1 = 0;
		zZ = z2 - z1;
//		fontNode->fn_CharPosX += zZ;
		fontNode->fn_CharLoc[(index - fontNode->fn_LowChar) * 2 + 1] = zZ;
		fontNode->fn_CharSpace[(index - fontNode->fn_LowChar)] = zZ + 1;
		fontNode->fn_CharKern[(index - fontNode->fn_LowChar)] = z1;
		fontNode->fn_ActWidth += zZ;
		if (fontNode->fn_LowLeftY[index] != fontNode->fn_UpRightY[index])
		{
			fontNode->fn_NomWidth += zZ;
//			fontNode->fn_NomWidth += (z1 + zZ);
			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 */
	fontNode->fn_ActWidth = 0;
	/* OK, finally the new TextFont is ready for use (maybe...) */
	if (psError != 0)
	{
		FreeMem(newFont, fontNode->fn_MaxFontLength + 64);
		return(0);
	}
	return(newFont);		
}

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

	/* Beginning of MakeATMChars() (Fingers crossed) */
	/* 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.xoff = 0;
	psParm.page.yoff = 0;
	psParm.page.xbytes = fontNode->fn_MaxModulo;
	psParm.page.xsize = fontNode->fn_MaxWidth;
	psParm.page.ysize = fontNode->fn_FontSize;
	psParm.page.ybase = 0;
	psParm.page.yheight = fontNode->fn_FontSize;
	/* For a silly reason I can't have multiple page descriptions. Thanks Adrian. */
	PSsetdevice(psActivation, &psParm.page);
	/* Prepare external pointers charPosX and Y */
	charPosX = &fontNode->fn_CharPosY;
	charPosY = &fontNode->fn_CharPosY;

	/* OK, draw some characters.  NOTE: I will move actual drawing to */
	/* the MakeATMChars() fcn.  This is NOT permament. */
	PSTrace("%%Rendering characters\n");
	/* 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");
	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);
	/* ... then initmatrix the drawing area and start drawing */
	PSIntf("initmatrix\n");
	PSIntf("/xscale %d %d mul 72 div def\n", newFont->tf_YSize, 72);	/* 72 = optXDen */
	PSIntf("/yscale %d %d mul 72 div def\n", newFont->tf_YSize, 72);	/* 72 = optYDen */
	PSIntf("newfont [ xscale 0 0 yscale 0 0 ] makefont setfont\n");

	/* Character loop.  MakeATMChars() 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 * 72 - 41000) / 72000;
			z2 = (fontNode->fn_UpRightX[index] * fontNode->fn_FontSize * 72 + 41000) / 72000;
			zZ = z2 - z1;
//			if (z1 < 0)
//				z1 = 0;
			PSIntf("cstr 0 %d put\n", index);
			PSIntf("%d %d moveto\n", fontNode->fn_ActWidth, fontNode->fn_BaseLine);
			PSIntf(	"gsave %d 0 rlineto 0 %d rlineto "
				"-%d 0 rlineto closepath clip\n", z2, -fontNode->fn_BaseLine, z2);
			PSIntf("1 setgray fill 0 setgray\n");
			PSIntf("%d %d moveto ", fontNode->fn_ActWidth - z1, fontNode->fn_BaseLine);
			y1 = ((-fontNode->fn_LowLeftY[index]) * fontNode->fn_FontSize * 72) / 72;
			y2 = fontNode->fn_BaseLine * 1000;
			if (y1 > y2)
				PSIntf("1 %d %d div scale\n", y2, y1);
			PSIntf( "cstr show\n"
				"grestore\n");
			PSIntf( "gsave %d 0 rlineto 0 %d rlineto "
				"-%d 0 rlineto closepath clip\n", zZ, fontNode->fn_FontSize - fontNode->fn_BaseLine, zZ);
			/* formerly z2 and z2, used zZ to fix nasty character clipping */
			PSIntf("1 setgray fill newpath 0 setgray\n");
			PSIntf("%d %d moveto ", fontNode->fn_ActWidth - z1, fontNode->fn_BaseLine);
			if (psError != 0)
			{
				PSTrace("PostScript error drawing character %d %c\n", index, index);
				break;
			}
			y1 = (fontNode->fn_UpRightY[index] * fontNode->fn_FontSize * 72) / 72;
			y2 = (newFont->tf_YSize - fontNode->fn_BaseLine) * 1000;
			if (y1 > y2)
				PSIntf("1 %d %d div scale\n", y2, y1);
			PSIntf(	"cstr show\n"
				"null currentpoint 2 { round cvi exch } repeat "
				"2 1 callextfunc\n"
				"grestore\n");
//			fontNode->fn_CharPosX += zZ;
			fontNode->fn_CharLoc[(index - fontNode->fn_LowChar) * 2] = fontNode->fn_ActWidth;
			fontNode->fn_ActWidth += zZ;
			fontNode->fn_BuiltChars[index] = CHAR_DRAWN;
		}
	}

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

/* External function for POST activation */
__geta4 void SetBBox (int ch, int lx, int ly, int rx, int ry)
{
	lowLeftX[ch] = lx;
	lowLeftY[ch] = ly;
	upRightX[ch] = rx;
	upRightY[ch] = ry;
	return;
}

/* External function for POST activation */
__geta4 void SetCPos(int cpx, int cpy)
{
	*charPosX = cpx;
	*charPosY = cpy;
	return;
}

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

	if (psError != 0)
		return;

	if (OPTTRACE)
	{
		va_start(ap, format);
		vfprintf(stdout, format, ap);
		fflush(stdout);
		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)
	{
		vfprintf(stdout, format, ap);
		fflush(stdout);
	}
	vsprintf(psString, format, ap);
	psError = PSintstring(psActivation, psString, -1, PSFLAGSTRING);
	va_end(ap);
	return;
}

__geta4 __regargs struct TextFont *NewOpenDiskFont(__A0 struct TextAttr *textAttr, __A6 struct Library *libBase)
{
struct	DiskfontMsg	*diskFontMsg;
struct	TextFont	*tempTextFont;
	BOOL		msgSent;
	BOOL		atmFont;

	diskFontMsg = (struct DiskFontMsg *)0x00000000;
	tempTextFont = (struct TextFont *)0x00000000;

	diskFontMsg = (struct DiskFontMsg *)AllocVec(sizeof(struct DiskfontMsg), MEMF_PUBLIC | MEMF_CLEAR);
	if (diskFontMsg != 0)
	{
		/* Prepare message for sending */
		diskFontMsg->df_ATMMsg.atm_MsgLength = sizeof(struct DiskfontMsg);
		diskFontMsg->df_ATMMsg.atm_DestPort = "ATM_ODF_Port";
		diskFontMsg->df_TextAttr = textAttr;
		diskFontMsg->df_TextFont = 0;
		/* send message */
		msgSent = ATMSendMsg((struct ATMMessage *)diskFontMsg);
		atmFont = diskFontMsg->df_ATMFont;
		tempTextFont = diskFontMsg->df_TextFont;
		FreeVec(diskFontMsg);
	}
	tempTextFont = OldOpenDiskFont(textAttr, libBase);
	return(tempTextFont);
}

__geta4 __regargs void NewText(__A1 struct RastPort *rastPort, __A0 STRPTR textString, __D0 WORD length, __A6 struct Library *libBase)
{
struct	TextMsg		*textMsg;
	BOOL		msgSent;

	textMsg = (struct TextMsg *)AllocVec(sizeof(struct TextMsg), (MEMF_PUBLIC | MEMF_CLEAR));

	if (textMsg != 0)
	{
		/* Prepare TextMsg struct for use */
		textMsg->tm_ATMMsg.atm_DestPort = "ATM_Text_Port";
		textMsg->tm_ATMMsg.atm_MsgLength = sizeof(struct TextMsg);
		textMsg->tm_RastPort = rastPort;
		textMsg->tm_Chars = textString;
		textMsg->tm_Length = length;
			/* send the message */
		msgSent = ATMSendMsg((struct ATMMessage *)textMsg);
		FreeVec(textMsg);
	}

	OldText(rastPort, textString, length, libBase);
	/* don't forget the gfxBase in A6, or you're toast. */
	return;
}

/* 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. */
__geta4 __regargs ULONG NewSSStyle(__A1 struct RastPort *rastPort, __D0 ULONG newStyle, __D1 ULONG enable, __A6 struct Library *libBase)
{
struct	SSStyleMsg	*sssMsg;
	ULONG		stylesNeeded = newStyle;
	ULONG		resultingStyle;
struct	TextFont	*changedFont;
	BOOL		msgSent;

	sssMsg = (struct SSStyleMsg *)AllocVec(sizeof(struct SSStyleMsg), (MEMF_PUBLIC | MEMF_CLEAR));
	if (sssMsg != 0)
	{
		/* prepare message struct */
		sssMsg->ss_ATMMsg.atm_DestPort = "ATM_SSS_Port";
		sssMsg->ss_ATMMsg.atm_MsgLength = sizeof(struct SSStyleMsg);
		sssMsg->ss_RastPort = rastPort;
		sssMsg->ss_NewStyle = newStyle;
		sssMsg->ss_Enable = enable;
		sssMsg->ss_SoftStyleNeeded = newStyle;
		/* Send the message */
		msgSent = ATMSendMsg((struct ATMMessage *)sssMsg);
		/* Check for successful style changes and change the font as needed */
		changedFont = sssMsg->ss_ChangedFont;
		stylesNeeded = sssMsg->ss_SoftStyleNeeded;
		if (changedFont != 0)
		{
			OpenFont(changedFont);
			SetFont(rastPort, changedFont);
		}
		FreeVec(sssMsg);
	}

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

/* Message sender.  This guys gets a lot of working out! */
__geta4 BOOL ATMSendMsg(struct ATMMessage *atmMsg)
{
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. */
	atmMsg->atm_Message.mn_Length = atmMsg->atm_MsgLength;
	atmMsg->atm_Message.mn_ReplyPort = replyPort;

/* OK we have a valid reply port and a message.  Time to send it. */
	portSig = 1 << replyPort->mp_SigBit;
	Forbid();
	msgPort = FindPort(atmMsg->atm_DestPort);
	if (msgPort)
		PutMsg(msgPort,(struct Message *)atmMsg);
	Permit();
	if (msgPort)
	{
		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);
}
