#define __USE_SYSBASE

#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/rdargs.h>
#include <dos/dosasl.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <utility/tagitem.h>
#include <support/types.h>
#include <support/exec.h>

#include <string.h>

#include <proto/exec.h>
#include <proto/dos.h>

#include "for.rev.h"

#define DOS_NAME		"dos.library"
#define DOS_VERN 		37L

#define TEMPLATE		"FILE/A,COMMAND/F,ALL/S"

#define DEF_COMM		"%S"

STATIC CONST TEXT VersionString[]=
	VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);

#define OPT_FILE		0
#define OPT_COMM		1
#define OPT_ALL			2
#define OPT_COUNT		3

#define NAME_SIZE		32			/* File's name */
#define BUFF_SIZE		1024		/* Expanded command */
#define PATH_SIZE		256			/* For file's path */

STATIC BOOL SPrintf(STRPTR format, STRPTR buffer, ULONG buffSize,
										STRPTR name, STRPTR path);

ULONG For(VOID)
{
	struct ExecBase *SysBase=*((struct ExecBase **)4);
	struct DosLibrary *DOSBase;

	STATIC CONST struct TagItem CommandTags[]=
	{
		{SYS_UserShell,TRUE},
		{TAG_DONE,0}
	};

	struct RDArgs *Args;
	struct AnchorPath *Anchor;
	LONG Opts[OPT_COUNT];
	ULONG TempRC,RC=RETURN_FAIL;
	CHAR FName[NAME_SIZE];
	STRPTR CommBuffer;
	BPTR CurrLock,OldLock;
	BOOL ErrOccured=FALSE;

	unless(DOSBase=(struct DosLibrary *)OpenLibrary(DOS_NAME,DOS_VERN))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		goto InvalidDOS;
	}

	unless(Anchor=AllocVec(sizeof(struct AnchorPath)+PATH_SIZE,MEMF_CLEAR))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto NoMemory1;
	}
	Anchor->ap_BreakBits=SIGBREAKF_CTRL_C;		/* Allow break */
	Anchor->ap_Strlen=PATH_SIZE;

	unless(CommBuffer=AllocVec(BUFF_SIZE,MEMF_CLEAR))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto NoMemory2;
	}

	clear(&Opts);
	unless(Args=ReadArgs(TEMPLATE,Opts,NULL))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto NoArgs;
	}
	unless(Opts[OPT_COMM])
		Opts[OPT_COMM]=(ULONG)DEF_COMM;

	TempRC=MatchFirst((STRPTR)Opts[OPT_FILE],Anchor);
	while(TempRC==0)
	{
		strcpy(FName,Anchor->ap_Info.fib_FileName);
		if(Anchor->ap_Info.fib_DirEntryType>=0)
		{
			if(Opts[OPT_ALL])
			{
				if(!ftst(Anchor->ap_Flags,APF_DIDDIR))
					fset(Anchor->ap_Flags,APF_DODIR);
				fclr(Anchor->ap_Flags,APF_DIDDIR);
			}
			goto Next;	
		}
		CurrLock=DupLock(Anchor->ap_Current->an_Lock);
		OldLock=CurrentDir(CurrLock);
		if(SPrintf((STRPTR)Opts[OPT_COMM],CommBuffer,BUFF_SIZE,
								FName,Anchor->ap_Buf))
		{
			if(System(CommBuffer,CommandTags))	/* An error */
			{
				PrintFault(IoErr(),NULL);
				ErrOccured=TRUE;
			}
		}
		else
		{
			PrintFault(ERROR_LINE_TOO_LONG,NULL);
			SetIoErr(ERROR_LINE_TOO_LONG);
			ErrOccured=TRUE;
		}
		CurrentDir(OldLock);
		UnLock(CurrLock);
Next:
		TempRC=MatchNext(Anchor);
	}
	if(TempRC==ERROR_NO_MORE_ENTRIES)
		RC=(ErrOccured ? RETURN_ERROR : RETURN_OK);
	else
	{
		PrintFault(TempRC,NULL);
		RC=(TempRC==ERROR_BREAK ? RETURN_WARN : RETURN_FAIL);
	}
	MatchEnd(Anchor);

	FreeArgs(Args);
NoArgs:
	FreeVec(CommBuffer);
NoMemory2:
	FreeVec(Anchor);
NoMemory1:
	CloseLibrary((struct Library *)DOSBase);
InvalidDOS:
	return(RC);
}

STATIC BOOL SPrintf(STRPTR format, STRPTR buffer, ULONG buffSize,
										STRPTR name, STRPTR path)
{
	ULONG NameLen=strlen(name),PathLen=strlen(path),Len;
	CHAR CurrChar;
	STRPTR Arg,HighBuffer=buffer+buffSize-1;

	memset(buffer,0,buffSize);		/* Clear buffer */
	while(CurrChar=*format++)
	{
		if(buffer<HighBuffer)				/* The char will fit */
			*buffer=CurrChar;
		else
			return(FALSE);

		if(CurrChar=='%')
		{
			switch(*format)
			{
				case 's':
				case 'S':
					Len=NameLen;
					Arg=name;
					break;
				case 'p':
				case 'P':
					Len=PathLen;
					Arg=path;
					break;
				default:
					goto NextChar;
			}
			if(buffer+Len+2<HighBuffer)
			{
				*buffer++='"';
				strcpy(buffer,Arg);			/* Insert arg */
				buffer+=Len;						/* Update dest */
				*buffer='"';
				format++;								/* Skip control char */
			}
			else
				return(FALSE);
		}
NextChar:
		buffer++;
	}
	return(TRUE);
}
