/*
    JOKER.C

Written by DavidW
Started on 15/11/91

*/

#include <p_std.h>
#include <p_file.h>
#include <epoc.h>
#include <wlib.h>
#include <hwif.h>


LOCAL_D TEXT *cmds[]=
    {
    "oOverwrite",
    "dDouble free",
    "fFaulty free",
    "wWind up stack",
    "bBusy",
    "sSlow exit",
    "xExit",
    NULL
    };

#define CORRUPT_ITEMS       3
#define SPECIAL_ITEMS       4

#define ITEMS_BEFORE_CORRUPT    0
#define ITEMS_BEFORE_SPECIAL    CORRUPT_ITEMS

LOCAL_D H_MENU_DATA mdata[]=
    {
    "Corrupt heap",CORRUPT_ITEMS,
    "Special",SPECIAL_ITEMS,
    NULL
    };

GLDEF_D TEXT ** _cmds=(&cmds[0]);
GLDEF_D H_MENU_DATA * _mdata=(&mdata[0]);


LOCAL_D UINT MainWid;

LOCAL_D LONG delay=50l;


LOCAL_C VOID DoSleep(VOID)
    {
    TEXT buf[30];

    p_atos(&buf[0],"Waiting %ld/10 secs",delay);
    wSetBusyMsg(&buf[0],W_CORNER_BOTTOM_LEFT);
    p_sleep(delay);
    wCancelBusyMsg();
    }

LOCAL_C INT AddInDelayItem(VOID)
    {
    H_DI_NUMBER num;

    num.value=(&delay);
    num.low=0;
    num.high=1000;
    return(uAddDialogItem(H_DIALOG_NUMBER,"Delay (10ths of secs)",&num));
    }

LOCAL_C INT AddNumberEditor(TEXT *prompt,LONG *pnum,INT low,INT high)
    {
    H_DI_NUMBER num;

    num.value=pnum;
    num.low=low;
    num.high=high;
    return(uAddDialogItem(H_DIALOG_NUMBER,prompt,&num));
    }

LOCAL_C VOID OverwriteAllocCell(VOID)
    {
    LONG cellen;
    LONG overwlen;
    UBYTE *cell;

    if (uOpenDialog("Overwrite alloc cell"))
        return;
    cellen=0x100;
    if (AddNumberEditor("Length of cell to alloc",&cellen,4,0x1000))
        return;
    overwlen=4;
    if (AddNumberEditor("Length of overwrite",&overwlen,1,0x100))
        return;
    if (AddInDelayItem())
        return;
    if (uRunDialog()<=0)
        return;
    cell=p_alloc((UWORD)cellen);
    if (!cell)
        {
        wInfoMsg("Cell too large to alloc");
        return;
        }
    DoSleep();
    p_bfil(cell,(UWORD)(cellen+overwlen),0xee);
    }

LOCAL_C VOID FreeCellTwice(VOID)
    {
    LONG cellen;
    UBYTE *cell;

    if (uOpenDialog("Free cell twice"))
        return;
    cellen=0x100;
    if (AddNumberEditor("Length of cell to free twice",&cellen,4,0x1000))
        return;
    if (AddInDelayItem())
        return;
    if (uRunDialog()<=0)
        return;
    cell=p_alloc((UWORD)cellen);
    if (!cell)
        {
        wInfoMsg("Cell too large to alloc");
        return;
        }
    p_free(cell);
    DoSleep();
    p_free(cell);
    }

LOCAL_C VOID FreeWrongCell(VOID)
    {
    LONG cellen;
    UBYTE *cell;

    if (uOpenDialog("Free wrong cell"))
        return;
    cellen=0x100;
    if (AddNumberEditor("Length of correct cell",&cellen,4,0x1000))
        return;
    if (AddInDelayItem())
        return;
    if (uRunDialog()<=0)
        return;
    cell=p_alloc((UWORD)cellen);
    if (!cell)
        {
        wInfoMsg("Cell too large to alloc");
        return;
        }
    DoSleep();
    p_free(cell+1);
    }

LOCAL_C VOID MainLoop(VOID);

LOCAL_C VOID DoWindupStack(VOID)
    {
    UBYTE junk[256];

    p_bfil(&junk[0],256,0);
    MainLoop();
    }

LOCAL_C VOID WindupStack(VOID)
    {
    if (uOpenDialog("Wind up stack"))
        return;
    if (AddInDelayItem())
        return;
    if (uRunDialog()<=0)
        return;
    DoSleep();
    DoWindupStack();
    }

#define Y_BUSY_LOW  10
#define Y_BUSY_HIGH 78
#define X_BUSY      83
#define BUSY_SCALE  1000

LOCAL_C VOID DoPrint(UINT y)
    {
    gPrintText(X_BUSY,y,"Busy",4);
    wFlush();
    }

LOCAL_C VOID GoBusy(VOID)
    {
    LONG nloops;
    UWORD y;
    UWORD lasty;
    ULONG j;

    if (uOpenDialog("Go busy"))
        return;
    nloops=3;
    if (AddNumberEditor("Number of loops of activity",&nloops,1,10))
        return;
    if (AddInDelayItem())
        return;
    if (uRunDialog()<=0)
        return;
    DoSleep();
    while (nloops--)
        {
        lasty=Y_BUSY_LOW;
        DoPrint(lasty);
        j=Y_BUSY_LOW*BUSY_SCALE;
        FOREVER
            {
            j++;
            y=(UWORD)(j/BUSY_SCALE);
            if (y!=lasty)
                {
                DoPrint(lasty);
                if (y>Y_BUSY_HIGH)
                    break;
                lasty=y;
                DoPrint(y);
                }
            }
        }
    }

LOCAL_C VOID SlowExit(VOID)
    {
    if (uOpenDialog("Slow exit"))
        return;
    if (AddInDelayItem())
        return;
    if (uRunDialog()<=0)
        return;
    DoSleep();
    p_exit(0);
    }

LOCAL_C VOID ManageCommand(INT index)
    {
    switch (index)
        {
    case ITEMS_BEFORE_CORRUPT:
        OverwriteAllocCell();
        break;
    case ITEMS_BEFORE_CORRUPT+1:
        FreeCellTwice();
        break;
    case ITEMS_BEFORE_CORRUPT+2:
        FreeWrongCell();
        break;
    case ITEMS_BEFORE_SPECIAL:
        WindupStack();
        break;
    case ITEMS_BEFORE_SPECIAL+1:
        GoBusy();
        break;
    case ITEMS_BEFORE_SPECIAL+2:
        SlowExit();
        break;
    case ITEMS_BEFORE_SPECIAL+3:
        p_exit(0);
        }
    }

LOCAL_C VOID TryExecuteCommand(INT keycode)
    {
    keycode=uLocateCommand(keycode);
    if (keycode>=0)
        ManageCommand(keycode);
    }

LOCAL_C VOID GoToSystemScreen(VOID)
    {
    wClientPosition(0,p_pidfind("SYS$SHLL.*"));
    }

LOCAL_C VOID MainLoop(VOID)
    {
    INT ret;
    WMSG_KEY key;

    FOREVER
        {
        uGetKey(&key);
        if (key.keycode&W_SPECIAL_KEY)
            TryExecuteCommand(key.keycode&(~W_SPECIAL_KEY));
        else if (key.keycode==W_KEY_MENU && !(key.modifiers&W_CTRL_MODIFIER))
            {
            ret=uPresentMenus();
            if (ret>0)
                TryExecuteCommand(ret);
            }
        else if (key.keycode==26)
            GoToSystemScreen();
        }
    }

LOCAL_C VOID ReduceScreenSize(VOID)
    {
    W_WINDATA wd;

    wd.extent.tl.x=wd.extent.tl.y=0;
    wd.extent.width=189;
    wd.extent.height=80;
    wSetWindow(MainWid,W_WIN_EXTENT,&wd);
    if (uErrorValue(wCheckPoint()))
        p_exit(0);
    }

LOCAL_C VOID CreateGC(VOID)
    {
    G_GC gc;
    INT hgc;

    gc.textmode=G_TRMODE_INV;
    hgc=gCreateGC(MainWid,G_GC_MASK_TEXTMODE,&gc);
    if (hgc<0)
        p_exit(hgc);
    }

LOCAL_C VOID SpecificInit(VOID)
    {
    MainWid=uFindMainWid();
    CreateGC();
    ReduceScreenSize();
    gBorder(W_BORD_CORNER_4);
    wsEnable();
    wCaptureKey(26,W_CTRL_MODIFIER,W_CTRL_MODIFIER);
    }

GLDEF_C VOID main(VOID)
    {
    uCommonInit();
    SpecificInit();
    MainLoop();
    }
