#include <dos.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <utility/tagitem.h>
#include <dos/dostags.h>
#include <clib/dos_protos.h>
#include <libraries/dosextens.h>
#include <proto/exec.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* These are only used in ks1.3 , in 2.0 we use System() */
long SyncRun(char *,char *,BPTR,BPTR);
#pragma libcall ArpBase SyncRun                 021C    109804
extern struct Library *ArpBase;

extern struct ExecBase *SysBase;
extern struct CommandLineInterface *Mycli;

long MyRunCommand(char *command,char *args,BPTR in,BPTR out,int residents)
{	struct Segment *seg;
	int ret, len=strlen(args);
	char buf2[200], *buf=(char *)((long)(buf2+3)&~3);
	struct TagItem stags[4];
	BPTR seglist_cmd,lock,oldin=Input(),oldout=Output();
	BPTR oldmodule,oldname;
	char *commandbuffer;
	long size;

/*	while((long)buf & 3)
		buf++;*/	/* make it a BPTR:able */

	if(!in)
		in=Input();
	if(!out)
		out=Output();

	if(ArpBase)
		return (SyncRun(command,args,in,out));

	SelectInput(in);
	SelectOutput(out);

	oldname = Mycli->cli_CommandName;
	args[len]='\n';
	args[len+1]='\0';
	buf[0] = strlen(command);
	strncpy(buf+1,command,180);

	if(residents)
	{
		Forbid();
		if(!(seg=FindSegment( (UBYTE *)command, NULL, 0 )))
			seg=FindSegment( (UBYTE *)command, NULL, CMD_INTERNAL );

		if(seg && seg->seg_UC!=CMD_SYSTEM && seg->seg_UC>CMD_DISABLED)
		{
			if(seg->seg_UC>=0)
				seg->seg_UC++;
		}
		Permit();

		if(seg)
		{
			Mycli->cli_CommandName = (long)buf>>2;

			ret=RunCommand(seg->seg_Seg, Mycli->cli_DefaultStack * 4, (UBYTE *)args, strlen(args));

			Forbid();
			if(seg->seg_UC > 0)
				seg->seg_UC--;
			Permit();

			Mycli->cli_CommandName = (long)oldname;
			args[len]='\0';

			SelectInput(oldin);
			SelectOutput(oldout);

			return ret;
		}
	}

	if(lock=Lock(command,ACCESS_READ))
	{
	    stags[0].ti_Tag = TAG_DONE;
	    stags[0].ti_Data = 0;

		seglist_cmd = NewLoadSeg(command,stags);

		if(seglist_cmd)
		{
			UnLock(lock);
			Mycli->cli_CommandName = (long)buf>>2;	/* SetProgramName(buf); */
			if(Mycli->cli_DefaultStack<1000)
				Mycli->cli_DefaultStack=1000;

			oldmodule= Mycli->cli_Module;
			Mycli->cli_Module=seglist_cmd;

			ret=RunCommand(seglist_cmd, Mycli->cli_DefaultStack*4, (UBYTE *)args, strlen(args));

			/* It is important that we unload cli_Module, NOT the original segment! */
			/* This is how self-detaching programs avoid unloading of their code. */
			UnLoadSeg(Mycli->cli_Module);
			Mycli->cli_Module=oldmodule;
			Mycli->cli_CommandName = (long)oldname;	/* SetProgramName(oldname*4); */

			args[len]='\0';			/* remove '\n' from args */

			SelectInput(oldin);
			SelectOutput(oldout);

			return ret;
		}
		else
		{
			UnLock(lock);
		}
	}

	size = strlen(command) + strlen(args) + 8;
	if(commandbuffer = (char *)AllocMem(size, MEMF_PUBLIC | MEMF_CLEAR))
	{
		sprintf(commandbuffer,"%s %s",command,args);	/* '\n' included */
		args[len]='\0';
		stags[0].ti_Tag = SYS_Input;
		stags[0].ti_Data= in;
		stags[1].ti_Tag = SYS_Output;
		stags[1].ti_Data= out;
		stags[2].ti_Tag = TAG_DONE;

		SelectInput(oldin);
		SelectOutput(oldout);

		ret = System(commandbuffer, stags);
		FreeMem(commandbuffer, size);
	}
	return ret;
}

