/*
 *	File:					ARexxMacro.h
 *	Description:	Handles ARexxMacros
 *
 *	(C) 1995, Ketil Hunn
 *
 */

#ifndef AREXXMACRO_H
#define AREXXMACRO_H

/*** PRIVATE INCLUDES ****************************************************************/
#include <exec/lists.h>
#include <proto/exec.h>

#include "myinclude:exists.c"

/*** DEFINES *************************************************************************/
#define every_command	command=macro->list->lh_Head;command->ln_Succ;command=command->ln_Succ

/*** FUNCTIONS ***********************************************************************/

__asm __saveds ARexxMacro AllocARexxMacroA(register __a0 struct TagItem *taglist)
{
	ARexxMacro macro;

	if(macro=(ARexxMacro)AllocVec(sizeof(struct ARexxMacroData), MEMF_CLEAR|MEMF_PUBLIC))
	{
		if(macro->list=(struct List *)AllocVec(sizeof(struct List), MEMF_PUBLIC))
			NewList(macro->list);
		else
		{
			FreeVec(macro);
			macro=NULL;
		}
	}
	return macro;
}

__asm __saveds BYTE IsARexxMacroEmpty(register __a0 ARexxMacro macro)
{
	return (BYTE)(macro && macro->list ? IsListEmpty(macro->list):1);
}

__asm __saveds void ClearARexxMacro(register __a0 ARexxMacro macro)
{
	while(!IsARexxMacroEmpty(macro))
	{
		register struct Node *node=macro->list->lh_Head;

		Remove(node);
		Free(node->ln_Name);
		FreeVec(node);
	}
}

__asm __saveds void FreeARexxMacro(register __a0 ARexxMacro macro)
{
	if(macro)
	{
		ClearARexxMacro(macro);
		FreeVec(macro->list);
		FreeVec(macro);
	}
}

__asm __saveds void AddARexxMacroCommandA(register __a1 ARexxMacro			macro,
																					register __a0 struct TagItem	*taglist)
{
	if(macro && macro->list)
	{
		struct TagItem	*tstate=taglist;
		register struct TagItem	*tag;
		register struct Node		*command;
		UBYTE										*commandstring	=NULL,
														done						=FALSE;
		LONG										*arguments			=0L,
														numlen					=0L;

		if(command=(struct Node *)AllocVec(sizeof(struct Node), MEMF_CLEAR|MEMF_PUBLIC))
		{
			while(!done && (tag=NextTagItem(&tstate)))
				switch(tag->ti_Tag)
				{
					case ER_Command:
						commandstring=(UBYTE *)tag->ti_Data;
						break;
					case ER_Arguments:
						arguments=&tag->ti_Data;
						if(numlen==0)
							numlen=40;
						done=TRUE;
						break;
					case ER_ArgumentsLength:
						numlen=tag->ti_Data;
						break;
				}
			if(	commandstring &&
					(command->ln_Name=(UBYTE *)AllocVec(sizeof(UBYTE)*(StrLen(commandstring)+numlen+2), MEMF_CLEAR|MEMF_PUBLIC)))
				vsprintf(command->ln_Name, commandstring, (APTR)arguments);

			AddTail(macro->list, command);
		}
	}
}

__asm __saveds BYTE WriteARexxMacroA(	register __a1 struct ARexxContext	*context,
																			register __a2 ARexxMacro					macro,
																			register __a3 UBYTE								*macroname,
																			register __a0 struct TagItem			*taglist)
{
	BPTR fp;
	BYTE success=FALSE;

	if(fp=Open(macroname, MODE_NEWFILE))
	{
		register struct Node *command;
		UBYTE remark[]=	"/* Macro generated by " NAME " " VERS " */\n\n"
										"OPTIONS RESULTS\n\n";

		Write(fp, remark, StrLen(remark));

		for(every_command)
		{
			Write(fp, command->ln_Name, StrLen(command->ln_Name));
			Write(fp, "\n", 1);
		}
		success=TRUE;

		Close(fp);
	}
	return success;
}

__asm __saveds UBYTE RunARexxMacroA(register __a1 struct ARexxContext	*context,
																		register __a0 struct TagItem			*taglist)
{
	struct TagItem					*tstate=taglist;
	register struct TagItem	*tag;
	register struct Node		*command;
	ULONG										type=0L;
	UBYTE										*macrofile,
													success=FALSE;
	ARexxMacro							macro;


	while(tag=NextTagItem(&tstate))
		switch(tag->ti_Tag)
		{
			case ER_Macro:
				type=ER_Macro;
				macro=(ARexxMacro)tag->ti_Data;
				break;
			case ER_MacroFile:
				type=ER_MacroFile;
				macrofile=(UBYTE *)tag->ti_Data;
				break;
		}

	switch(type)
	{
		case ER_Macro:
			if(context && macro)
			{
				struct TagItem taglist2[5];

				SETTAG(taglist2[0], ER_Port, 		(ULONG)context->port);
				SETTAG(taglist2[1], ER_Context,	(ULONG)context);
				SETTAG(taglist2[2], ER_Asynch,	TRUE);
				SETTAG(taglist2[4], TAG_DONE,		TAG_DONE);

				for(every_command)
					SendARexxCommandA(command->ln_Name, taglist2);

				success=TRUE;
			}
			break;
		case ER_MacroFile:
			if(context && macrofile)
			{
				BPTR fp, lock, oldlock;
				struct FileInfoBlock	*fib;

				if(fp=Open(macrofile, MODE_OLDFILE))
				{
					if(fib=AllocDosObject(DOS_FIB, TAG_DONE))
					{
						if(lock=Lock(macrofile, SHARED_LOCK))
						{
							oldlock=CurrentDir(lock);
							if(Examine(lock, fib))
							{
#define	MACROHEADER "/**/ADDRESS '%s' "

								register UBYTE *buffer;
								register ULONG headerlen=StrLen(MACROHEADER)+StrLen(context->portname);

								if(buffer=(UBYTE *)AllocVec(fib->fib_Size+2+headerlen, MEMF_CLEAR))
								{
									sprintf(buffer, MACROHEADER, context->portname);
									if(Read(fp, buffer+headerlen-2, fib->fib_Size))
									{
										struct TagItem taglist2[4];

										SETTAG(taglist2[0], ER_Context,	(ULONG)context);
										SETTAG(taglist2[1], ER_Flags,		(ULONG)RXFF_STRING);
										SETTAG(taglist2[2], ER_Asynch,	(ULONG)TRUE);
										SETTAG(taglist2[3], TAG_DONE,		TAG_DONE);
										SendARexxCommandA(buffer, taglist2);
										success=TRUE;
									}
									FreeVec(buffer);
								}
							}
							CurrentDir(oldlock);
							UnLock(lock);
						}
						FreeDosObject(DOS_FIB, fib);
					}
					Close(fp);
				}
			}
			break;
	}
	return success;
}

#endif
