#include <OSIncludes.h>

#pragma header

#include <stdio.h>
#include <stdlib.h>

extern "ASM" void New_CreateProc(void);
extern "ASM" void New_CreateNewProc(void);
extern "ASM" void New_SystemTagList(void);
extern "ASM" void New_RunCommand(void);

char *VersionString = "$VER: StackAttack 1.3 (08.09.01)";
char *AuthorString  = "$AUTH: Georg Steger";

char *TEMPLATE	     = "MINSTACK=MIN/N/K,ADDSTACK=ADD/N/K";
	
enum {ARG_MINSTACK,ARG_ADDSTACK,NUM_ARGS};
	
#define LVO_CreateProc -138
#define LVO_CreateNewProc -498
#define LVO_SystemTagList -606
#define LVO_RunCommand -504
	

struct RDArgs *MyArgs;
LONG	*Args[NUM_ARGS];

BOOL	DontCloseUtility;

extern "C" // C-Style variables in patch.asm
{
	struct UtilityBase *UtilityBase;

	struct Library *CDOSBase;

	APTR	Old_CreateProc,
			Old_CreateNewProc,
			Old_SystemTagList,
			Old_RunCommand;

	ULONG MinStack,StackAdd;
};

extern "ASM"
{
	void PATCHSTART(void);
	void PATCHEND(void);
};

void Cleanup(LONG rc)
{
	if (UtilityBase && (!DontCloseUtility)) CloseLibrary((struct Library *)UtilityBase);
	exit(rc);
}

void Init(void)
{
	/* DOSBase is already open and will be closed by the
	   compiler, so we use another name for the variable  */
	CDOSBase=OpenLibrary("dos.library",36);
}

void OpenLibs(void)
{
	if (!(UtilityBase=(struct UtilityBase *)OpenLibrary(UTILITYNAME,36)))
	{
		Cleanup(RETURN_WARN);
	}
}

void GetArguments(void)
{
	BOOL ok=FALSE;

	if ((MyArgs=ReadArgs(TEMPLATE,(LONG *)Args,0)))
	{
		if (Args[ARG_MINSTACK])
		{
			MinStack=(*Args[ARG_MINSTACK]+3)&0xFFFFFFFC;
			ok=TRUE;
		}
		if (Args[ARG_ADDSTACK])
		{
			StackAdd=(*Args[ARG_ADDSTACK]+3)&0xFFFFFFFC;
			ok=TRUE;
		}
		FreeArgs(MyArgs);
	}
	if (!ok) Cleanup(RETURN_WARN);
}

/* NEW_CreateNewProc and NEW_SystemTagList initially
   were written in C but have been converted to Assembly
   language, later. So the routines here are commented
   out!!
   
   Note: The ASM-Routines now call CloneTagItems
   ===== The C-Routines here don't do that and may vary also
         in some other ways!!!!

LONG NEW_CreateNewProc(struct TagItem *tags)
{
	struct TagItem newti[2] = {NP_StackSize,MinStack+StackAdd,TAG_MORE,(LONG)tags};

	struct TagItem *ti;

	if (tags && ((ti=FindTagItem(NP_StackSize,tags))))
	{
		if (ti->ti_Data<MinStack) ti->ti_Data=MinStack;
		ti->ti_Data+=StackAdd;
		return JumpOld_CreateNewProc(tags);
	} else {
		if (!tags) newti[1].ti_Tag=TAG_DONE;
		return JumpOld_CreateNewProc(newti);
	}
}

LONG NEW_SystemTagList(STRPTR command, struct TagItem *tags)
{
	struct TagItem newti[2] = {NP_StackSize,MinStack+StackAdd,TAG_MORE,(LONG)tags};

	struct TagItem *ti;

	if (tags && ((ti=FindTagItem(NP_StackSize,tags))))
	{
		if (ti->ti_Data<MinStack) ti->ti_Data=MinStack;
		ti->ti_Data+=StackAdd;
		return JumpOld_SystemTagList(command,tags);
	} else {
		if (!tags) newti[1].ti_Tag=TAG_DONE;
		return JumpOld_SystemTagList(command,newti);
	}
	
}
*/
void DoPatches(void)
{
	#define REALPOS(routine) (APTR) (((UBYTE *)routine) - ((UBYTE *)PATCHSTART) + mem)

	UBYTE *mem;
	ULONG len=((UBYTE *)PATCHEND) - ((UBYTE *)PATCHSTART) + 1;

	if (!(mem=AllocMem(len,MEMF_PUBLIC))) Cleanup(RETURN_WARN);

	/* Now we know that StackAttack will not fail to run,
	   therefore Cleanup must not close utility.library
	   (because of the patches needing it)!! */
	   
	DontCloseUtility=TRUE;

	Forbid();

	Old_CreateProc=SetFunction((struct Library *)DOSBase,LVO_CreateProc,REALPOS(New_CreateProc));
	Old_CreateNewProc=SetFunction((struct Library *)DOSBase,LVO_CreateNewProc,REALPOS(New_CreateNewProc));
	Old_SystemTagList=SetFunction((struct Library *)DOSBase,LVO_SystemTagList,REALPOS(New_SystemTagList));
	Old_RunCommand=SetFunction((struct Library *)DOSBase,LVO_RunCommand,REALPOS(New_RunCommand));

	// we copymem only here because the Old_??
	// variables will be copied, too!!

	CopyMem(PATCHSTART,mem,len);
	CacheClearU(); // !!

	Permit();
}

void main(void)
{
	Init();
	OpenLibs();
	GetArguments();
	DoPatches();
	Cleanup(RETURN_OK);
}

	
