#include <dos/dos.h>
#include <dos/rdargs.h>
#include <exec/libraries.h>
#include <intuition/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

#ifdef __SASC
int CXBRK(void) { return 0; }   /* Disable SAS/C ctrl-C handling */
int chkabort(void) { return 0; }        /* Really */
#define __USE_SYSBASE
#define REG(x)  register __## x
#else
/* Whatever needed for other compilers. */
#endif
#define LVOText -0x3C

/* Much easier to define function pointer variables, and do type-casting this way. */
typedef void __asm (*text)(REG(a1) struct RastPort *, REG(a0) STRPTR, REG(d0) WORD, REG(a6) struct Library *);

/* Global function pointer */
text            gfx_Text;

static const STRPTR version = "\0$VER: OutlineFont 1.1 (18.03.97)";
static const STRPTR programName = "OutlineFont";
static const STRPTR warning = "Warning: Removing the patch is dangerous!\nRemove anyway?";
static const STRPTR esgadgets =  "Yes|No";
static const STRPTR template = "FRONTPEN/N/A,BACKPEN/N/A,OUTLINEWIDTH/N/A";

far LONG fgpen, bgpen, owidth;

void __asm __saveds
of_Text(REG(a1) struct RastPort *rp,
        REG(a0) STRPTR str,
        REG(d0) WORD len,
        REG(a6) struct Library *base)
{
    int x,y,w;
    ULONG drmd;
    struct Task *task;
    UBYTE *nstr;
    
    task = FindTask(NULL);
    nstr = task->tc_Node.ln_Name;
    if( nstr[0]=='W' && nstr[1]=='o' && nstr[2]=='r' && nstr[3]=='k' && nstr[4]=='b' && nstr[5]=='e' && nstr[6]=='n' && nstr[7]=='c' && nstr[8]=='h' )
    {
        if( GetAPen(rp)==fgpen && GetBPen(rp)==bgpen && (drmd=GetDrMd(rp))==JAM2 )
        {
            x=rp->cp_x;
            y=rp->cp_y;
	    w=owidth;
	    
	    SetDrMd(rp,JAM1);
	    
	    SetAPen(rp,bgpen);
	    
	    Move(rp,x-w,y-w);
	    (*gfx_Text)(rp,str,len,base);
	    
	    Move(rp,x+w,y-w);
	    (*gfx_Text)(rp,str,len,base);
	    
	    Move(rp,x+w,y+w);
	    (*gfx_Text)(rp,str,len,base);
	    
	    Move(rp,x-w,y+w);
	    (*gfx_Text)(rp,str,len,base);
	    
	    SetAPen(rp,fgpen);
	    
	    Move(rp,x,y);
	    (*gfx_Text)(rp,str,len,base);
	    
	    SetDrMd(rp,drmd);
    	}
        else (*gfx_Text)(rp,str,len,base);
    }
    else (*gfx_Text)(rp,str,len,base);
}

ULONG main(void)
{
    struct RDArgs *args, *argptr;
    LONG array[3] = { 0, 0, 0, };
    BOOL safe = FALSE;
    struct EasyStruct es;
    
    /* Fill in EasyStruct */
    es.es_StructSize = sizeof(struct EasyStruct);
    es.es_Flags = 0;
    es.es_Title = programName;
    es.es_TextFormat = warning;
    es.es_GadgetFormat = esgadgets;
    
    /* Read program arguments with AmigaDOS ReadArgs() */
    if( args = AllocDosObject(DOS_RDARGS, NULL) )
    {
        if( argptr = ReadArgs(template, array, args) )
        {
            if( array[0] ) fgpen = *(LONG *)array[0];
            if( array[1] ) bgpen = *(LONG *)array[1];
            if( array[2] ) owidth = *(LONG *)array[2];
            /* Indicate that arguments are valid */
            safe = TRUE;
            FreeArgs(argptr);
        }
        else PrintFault(IoErr(), programName);
        FreeDosObject(DOS_RDARGS, args);
    }
    else PrintFault(IoErr(), programName);
    
    /* If arguments are valid, reset the 'safe' variable so it can be used again. */
    if( safe ) safe = FALSE;
    else return RETURN_ERROR;
    
    /* Patch graphics.library/Text() */
    gfx_Text = (text)SetFunction((struct Library *)GfxBase, LVOText, (APTR)of_Text);
    
    while( !safe )
    {
        Wait(SIGBREAKF_CTRL_C);
        /* SetMan and its ilk make un-patching safe. */
        if( FindPort("SetMan") ) safe = TRUE;
        /* Un-patching without a safeguard is bad voodoo, but some users may wish
           to do it anyway.  Ask first.
        */
        else if( EasyRequestArgs(NULL, &es, NULL, NULL) == 1 ) safe = TRUE;
    }
    
    /* Un-patch graphics.library/Text() */
    SetFunction((struct Library *)GfxBase, LVOText, (APTR)gfx_Text);
    
    return RETURN_OK;
}
