#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.2 "__AMIGADATE__" Nyberg,Gapen,Rotvel";
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,SHADOW/S";

__far LONG fgpen, bgpen, owidth;
__far BOOL shadow;

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);

            if (shadow == FALSE)
            {
                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 opts[4] = { 0, 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, opts, args) )
        {
            if (opts[0]) fgpen  = *((LONG *) opts[0]);
            if (opts[1]) bgpen  = *((LONG *) opts[1]);
            if (opts[2]) owidth = *((LONG *) opts[2]);
            if (opts[3]) shadow = opts[3]; 
            /* 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;
}
