/**********************************************************************/
/*                                                                    */
/*      AddTools - Adds menu items to the Workbench Tools menu.       */
/*                                                                    */
/*                            Version 1.1                             */
/*                                                                    */
/*                          by Steve Tibbett                          */
/*                                                                    */
/**********************************************************************/

	// 2.0 includes required

#include <exec/types.h>
#include <exec/ports.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <intuition/intuition.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <exec/memory.h>
#include <string.h>
#include <proto/wb.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/exec.h>

struct Library *WorkbenchBase;
struct Library *IntuitionBase;

struct AppMenuItem *AppList[32];
BPTR AppListDirs[32];
char *AppListNames[32];
char *AppListCommands[32];
struct Remember *Remember=0;
struct MsgPort *port;
int NumApps=0;

/**********************************************************************/
/*                     Lattice C Cleanup Routine                      */
/**********************************************************************/
void
CleanupRoutine(void)
{
while (NumApps)
	{
	NumApps--;
	if (AppListDirs[NumApps])
		UnLock(AppListDirs[NumApps]);
	RemoveAppMenuItem(AppList[NumApps]);
	};

if (Remember) FreeRemember(&Remember, TRUE);
if (port) DeletePort(port);
if (WorkbenchBase) CloseLibrary(WorkbenchBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
}


/**********************************************************************/
/* Start a command with an output window from a WBArg list.           */
/* The Cmd string that is passed is the template the filenames,       */
/* if any, will be added to.  If there are no arguments, the          */
/* file is invoked directly.  If one argument, it is just appended    */
/* and run (if the Cmd contains %s or %l).  If more than one          */
/* argument, %s will be replaced with one filename and the            */
/* executable will be invoked once for each argument, and a %l will   */
/* be replaced with a list of filenames and the executable invoked    */
/* only once.                                                         */
/**********************************************************************/
void
RunCommandFromWBArgs(char *OrigCmd, BPTR DefDir, long NumWBArgs, struct WBArg *WArgs)
{
BPTR CurDir;
struct Remember *Remember=0;
struct WBArg *WA;
char *CLine, *ExecuteMe, *Cmd, *ConsoleName;
long BufLen=0, NumArgs;
APTR ConsoleTask=0;
static ULONG ConIOTags[] =
	{ SYS_Output, 0, SYS_Input, 0, SYS_Asynch, 1, SYS_UserShell, 1, TAG_DONE };
static ULONG NoIOTags[] = 
	{ SYS_Asynch, 1, SYS_UserShell, 1, TAG_DONE, };

// If only one arg is expected, recursively call until done.
if ((NumWBArgs>1) && (strstr(OrigCmd, "%s")))
	{
	WA=WArgs;
	while (NumWBArgs)
		{
		RunCommandFromWBArgs(OrigCmd, DefDir, 1, WA);
		WA++;
		};
	return;
	};

// If %l passed, copy string and replace with %s
if (strstr(OrigCmd, "%l"))
	{
	char *p;

	Cmd=(char *)AllocRemember(&Remember, strlen(OrigCmd)+1, MEMF_CLEAR);
	if (Cmd==0) return;
	strcpy(Cmd, OrigCmd);
	p=strstr(Cmd, "%l");
	if (p) p[1]='s';		// change %l to %s
	} else Cmd=OrigCmd;

ExecuteMe=Cmd;

if (NumWBArgs==0 && strstr(Cmd, "%s"))
	{
	char *p;
	ExecuteMe=(char *)AllocRemember(&Remember, strlen(Cmd)+8, MEMF_CLEAR);
	if (ExecuteMe==0) { FreeRemember(&Remember, TRUE); return; };
	sprintf(ExecuteMe, Cmd, "");
	};

if (NumWBArgs && strstr(Cmd, "%s"))
	{
	WA=WArgs;
	NumArgs=NumWBArgs;

	BufLen=strlen(Cmd)+4;

	while (NumArgs--)
		{
		char PathName[512];
		NameFromLock(WA->wa_Lock, PathName, 512);
		BufLen+=6+strlen(WA->wa_Name)+strlen(PathName);
		WA++;
		};
	
	CLine=(char *)AllocRemember(&Remember, BufLen, MEMF_CLEAR);
	if (CLine)
		{
		WA=WArgs;
		NumArgs=NumWBArgs;

		while (NumArgs--)
			{
			char TempBuff[255], c;
			
			strcat(CLine, " \"");
			NameFromLock(WA->wa_Lock, TempBuff, 255);
			strcat(CLine, TempBuff);
			c=CLine[strlen(CLine)-1];
			if (c!=':' && c!='/')
				strcat(CLine, "/");
			strcat(CLine, WA->wa_Name);
			strcat(CLine, "\"");
			WA++;
			};

		ExecuteMe=(char *)AllocRemember(&Remember, strlen(CLine)+strlen(Cmd)+8, MEMF_CLEAR);
		if (ExecuteMe==0) 

			{
			FreeRemember(&Remember, TRUE);
			return;
			};

		sprintf(ExecuteMe, Cmd, CLine);
		};
	};

ConIOTags[1]=0;

ConsoleName=(char *)AllocRemember(&Remember, strlen(ExecuteMe)+50, MEMF_CLEAR);
if (ConsoleName)
	{
	char *buff=AllocRemember(&Remember, strlen(Cmd)+1, MEMF_CLEAR);
	
	if (buff)
		{
		sprintf(buff, Cmd, "");
		if (buff[strlen(buff)-1]==32) 
			buff[strlen(buff)-1]=0;
		
		sprintf(ConsoleName, "CON:10/25/550/150/%s Output/AUTO/CLOSE/WAIT", buff);
		ConIOTags[1]=Open(ConsoleName, MODE_NEWFILE);
		if (ConIOTags[1])
			{
			struct Process *Proc=((struct Process *)FindTask(0L));
			struct FileHandle *FH;

			ConsoleTask=Proc->pr_ConsoleTask;
			FH=BADDR(ConIOTags[1]);
			SetConsoleTask(FH->fh_Type);
			ConIOTags[3]=Open("*", MODE_OLDFILE);
			};
		};
	};

if (DefDir)
	CurDir=CurrentDir(DefDir);

if (ConIOTags[1])
 	System(ExecuteMe, (ULONG *)&ConIOTags);
	else System(ExecuteMe, (ULONG *)&NoIOTags);

if (DefDir)
	CurrentDir(CurDir);

if (ConsoleTask)
	SetConsoleTask(ConsoleTask);

FreeRemember(&Remember, TRUE);
}


/**********************************************************************/
/*                        It all happens here                         */
/**********************************************************************/
int
main(void)
{
BPTR FP;
struct AppMessage *msg;

onexit(CleanupRoutine);

if ((WorkbenchBase = OpenLibrary("workbench.library",36))==0)
	return(0);

if ((IntuitionBase = OpenLibrary("intuition.library", 33))==0)
	return(0);

if ((port = CreatePort(0,0))==0)
	return(0);

if ((FP=(LONG)Open("S:ToolsList", MODE_OLDFILE))==0)
	return(0);

while (TRUE)
	{
	char buff[255];
	char otherbuff[255];
	char dirbuff[255];

	if (FGets(FP, buff, 255)==0) break;
	if (isspace(buff[0]) || buff[0]==';' || buff[0]=='-') continue;
	if (FGets(FP, otherbuff, 255)==0) break;
	if (FGets(FP, dirbuff, 255)==0) break;

	if (buff[0]) buff[strlen(buff)-1]=0;
	if (otherbuff[0]) otherbuff[strlen(otherbuff)-1]=0;
	if (dirbuff[0]) dirbuff[strlen(dirbuff)-1]=0;

	AppListNames[NumApps]=(char *)AllocRemember(&Remember, strlen(buff)+1, MEMF_CLEAR);
	AppListCommands[NumApps]=(char *)AllocRemember(&Remember, strlen(otherbuff)+1, MEMF_CLEAR);
	if (AppListCommands[NumApps]==0 || AppListNames[NumApps]==0)
		return(0);

	AppListDirs[NumApps]=Lock(dirbuff, ACCESS_READ);

	strcpy(AppListCommands[NumApps], otherbuff);
	strcpy(AppListNames[NumApps], buff);
	AppList[NumApps] = (struct AppMenuItem *)AddAppMenuItemA(NumApps,NumApps,AppListNames[NumApps],port,NULL);
	NumApps++;
	}

Close(FP);

while (TRUE)
	{
	ULONG ID;

	Wait((1<<port->mp_SigBit)|SIGBREAKF_CTRL_F);

	// If no message arrived, it must be a CTRL_F

	if ((msg = (struct AppMessage *) GetMsg(port))==0)
		break;

	ID=msg->am_ID;
	RunCommandFromWBArgs(AppListCommands[ID], AppListDirs[ID], msg->am_NumArgs, msg->am_ArgList);
	ReplyMsg((struct Message *) msg);
	}
}
