/*
 *	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

#define MACROLIST 1
#define MACROFILE	2

/*** PROTOTYPES **********************************************************************/
//extern int vsprintf(char *, const char *, va_list);

/*** 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);
	}
	return macro;
}

__asm __saveds BYTE IsARexxMacroEmpty(register __a0 ARexxMacro macro)
{
	if(macro==NULL)
		return 1;
	else if(macro->list==NULL)
		return 1;
	return (BYTE)(IsListEmpty(macro->list));
}

__asm void RemoveARexxMacro(register __a0 struct Node *node)
{
	if(node)
	{
		Free(node->ln_Name);
		Remove(node);
		FreeVec(node);
	}
}

__asm __saveds void ClearARexxMacro(register __a0 ARexxMacro macro)
{
	while(!IsARexxMacroEmpty(macro))
		RemoveARexxMacro(macro->list->lh_Head);
}

__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)
		if(macro->list)
		{
			struct TagItem	*tstate=taglist;
			register struct TagItem	*tag;
			register struct Node *command;
			UBYTE	*commandstring	=NULL,
											*argumentstring	=NULL,
											numlen					=0;
			LONG						argumentnumber	=0L,
											*arguments			=0L;

			if(command=(struct Node *)
									AllocVec(sizeof(struct Node), MEMF_CLEAR|MEMF_PUBLIC))
			{
				while(tag=NextTagItem(&tstate))
					switch(tag->ti_Tag)
					{
						case ER_Command:
							commandstring=(UBYTE *)tag->ti_Data;
							break;
						case ER_ArgumentString:
							argumentstring=(UBYTE *)tag->ti_Data;
							break;
						case ER_ArgumentNumber:
							argumentnumber=(LONG)tag->ti_Data;
							numlen=64;
							break;
						case ER_Arguments:
							arguments=&tag->ti_Data;
							numlen=250;
							break;
					}
				if(StrLen(commandstring))
					if(command->ln_Name=(UBYTE *)AllocVec(sizeof(UBYTE)*(StrLen(commandstring)+StrLen(argumentstring)+numlen+2), MEMF_CLEAR|MEMF_PUBLIC))
					{
						if(arguments)
							vsprintf(command->ln_Name, commandstring, (APTR)arguments);
						else if(numlen)
							sprintf(command->ln_Name, commandstring, argumentnumber);
						else if(argumentstring)
							sprintf(command->ln_Name, commandstring, argumentstring);
						else
							sprintf(command->ln_Name, "%s", commandstring);
					}

				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=0;
	UBYTE *macrofile;
	ARexxMacro macro;
	UBYTE success=FALSE;

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

	switch(type)
	{
		case MACROLIST:
			if(context!=NULL & macro!=NULL)
			{
				struct TagItem taglist2[4];

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

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

				success=TRUE;
			}
			break;
		case MACROFILE:
			if(context!=NULL & macrofile!=NULL)
			{
				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 "/**/\nADDRESS %s\n"

								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
