/*
 *	Copyright © 1991 by S.R. & P.C.
 *
 *	Created:	23 May 1992	 12:00:40
 *	Modified:	18 Mar 1993  22:35:21
 *
 * Make>> sc <file>.c
 * Make>> SLink LIB:cs.o <file>.o SC SD BATCH NOICONS LIB LIB:Startup.lib LIB:String.lib
 */

#include <libraries/WhatIsBase.h>
#include <proto/WhatIs.h>


struct Library *WhatIsBase = NULL;

/* have problem whith stack size so I reduce string len */
#define MAXSTRINGLEN 255/2
#define MAXCMDLEN 512/2

#define MAX_PATHLEN 512
/*ULONG const MaxStringLen = MAXSTRINGLEN;*/

#define MAXNUMARGS 64
#define MAXDEFAULTLEN 512/2

/* char used in the filetype spec string */
#define NOTFileType '!'
#define ONLYFileType '%'
#define WHITHSubSub '#'

STRPTR Template = "Pattern/M,Files/K,Dirs/K,Since/K,Before/K,MinSize/K/N,MaxSize/K/N,PosProtect/K,NegProtect/K,Type/K,ALL/K/S,ASYNC/K/S,READSIZE/N,SHOWBYTE/N,D=DEEP/K/N,SFT=SHOWFILETYPE/K/S,DO/K/F";

#define ARG_NameA	0
#define ARG_Files		1
#define ARG_Dirs		2
#define ARG_Since		3
#define ARG_Before	4
#define ARG_MinSize	5
#define ARG_MaxSize	6
#define ARG_PosProtect	7
#define ARG_NegProtect	8
#define ARG_Type		9
#define ARG_ALL		10
#define ARG_ASYNC		11
#define ARG_READSIZE	12
#define ARG_SHOWBYTE	13
#define ARG_DEEPWHATIS	14
#define ARG_SHOWFILETYPE	15
#define ARG_CMD		16
#define ARG_ENDARG	17

STRPTR CliHelp = "For V2.0 [32m© 1992 S.R. & P.C.[31m\n\
Usage: For <Pattern> [FILES <MATCH|YES|NO>]  [DIRS <MATCH|YES|NO>] [Since <Date>] [Before <Date>] [MinSize <Number>] [MaxSize <Number>] [PosProtect <L|C|H|S|P|A|R|W|E|D>] [NegProtect <L|C|H|S|P|A|R|W|E|D>] [Type <FileType0...FileType9|%=ONLY|*=SUB|!=EXLC>] [ALL] [ASYNC] [READSIZE] [SHOWBYTE] [DEEPWHATIS] [SHOWFILETYPE] [DO <Command [args] [,Command [args] [,...]]>]\n";

/*******************************************************/
/* not in dos.h !! */
#define	FIBB_HIDDEN		7
#define	FIBF_HIDDEN		(1<<FIBB_HIDDEN)

/* it is my own definition: not standard */
#define	FIBB_COMMENT	8
#define	FIBF_COMMENT	(1<<FIBB_COMMENT)
#define	FIBB_LINK		9
#define	FIBF_LINK		(1<<FIBB_LINK)


#define PATTERN_BUF_SIZE	32
#define MAX_FTS				10	/* Max FileTypeSpec in SelectInfo */

struct FileTypeSpec {
	FileType fs_FileType;
	UWORD fs_Flags;
};

/* FileTypeSpec flags */
#define FTSF_EXCLUDETYPE	0x0001	/* Exclude this type (otherwise include) */
#define FTSF_WITHSUBTYPES	0x0002	/* Affect Include/Exclude to subtypes */


struct SelectInfo {
	UBYTE si_Pattern[PATTERN_BUF_SIZE];	/* Pattern						*/
	UBYTE si_PatTok[PATTERN_BUF_SIZE];	/* PreParsed pattern			*/
	LONG si_MinSize;	/* Show files bigger than that	*/
	LONG si_MaxSize;	/*   and smaller than that		*/
	struct DateStamp si_SinceDate;	/* Show files newer than that	*/
	struct DateStamp si_BeforeDate;	/*   and older than that		*/
	LONG si_SinceSecs;	/* date in seconds				*/
	LONG si_BeforeSecs;	/* date in seconds				*/
	UWORD si_PosProtect;	/* Show files that have these bits set   */
	UWORD si_NegProtect;	/* Show files that have these bits clear */
	struct FileTypeSpec si_FileTypes[MAX_FTS];	/* Include and Exclude file types */
	UWORD si_NumFts;	/* Number of FileTypeSpec in previous array */
	UWORD si_Flags;		/* Flags. See below				*/
};

/* SelectInfo flags */

#define SI_ALL_FILES		0x0001
#define SI_MATCH_FILES		0x0002
#define SI_ALL_DIRS			0x0004
#define SI_MATCH_DIRS		0x0008
#define SI_AFFECT_SUBDIRS	0x0010
#define SI_NAME				0x0020
#define SI_SIZE				0x0040
#define SI_SINCEDATE		0x0080
#define SI_BEFOREDATE		0x0100
#define SI_POSPROTECTION	0x0200
#define SI_NEGPROTECTION	0x0400
//
#define SI_INVERT			0x0800	/* Invert filters */
//
#define SI_AFFECT_INFO		0x1000	/* do actions on .info files too (WARNING: also defined as an option (for menu)) */
#define SI_POSFILETYPE		0x2000
#define SI_NEGFILETYPE		0x4000

#define SI_FILETYPE			(SI_POSFILETYPE|SI_NEGFILETYPE)
#define SI_MATCHBITS		(SI_NAME|SI_SIZE|SI_SINCEDATE|SI_BEFOREDATE|SI_POSPROTECTION|SI_NEGPROTECTION|SI_FILETYPE)
/*************************************************/

/*#pragma tagcall WhatIsBase WhatIs 1E 9802*/
FileType _WhatIsTags(char *Name, Tag FirstTag,...)
{
	return (WhatIsBase) ? WhatIs(Name, (struct TagItem *) & FirstTag) : TYPE_UNSCANNED;
}


/*************************************************/
/*
 *	return pointer to the first non blank char in a string, or to the '\0' if
 *	the string is empty
 */

static char *FirstNonBlank(char *buf)
{
	while (*buf && *buf == ' ')
		buf++;
	return buf;
}


/* check if buffer is empty or not */

static BOOL IsEmpty(char *buf)
{
	return (BOOL) ((*FirstNonBlank(buf)) ? FALSE : TRUE);
}


static BOOL String2Date(char *src, struct DateStamp * ds)
{
	struct DateTime *dt;
	BOOL Ok = TRUE;
	char *s1, *s2;
	char buf[PATTERN_BUF_SIZE];

	if (!(dt = AllocMem(sizeof(struct DateTime), MEMF_PUBLIC | MEMF_CLEAR)))
		return FALSE;
	strcpy(buf, src);
	s1 = s2 = FirstNonBlank(buf);
	if (*s1) {
		dt->dat_StrDate = s1;
		while (*s2 && *s2 != ' ')
			s2++;
		if (*s2) {
			*s2++ = '\0';
			s2 = FirstNonBlank(s2);
		}
		if (*s2) {
			dt->dat_StrTime = s2;
			if (!StrToDate(dt))
				Ok = FALSE;
		}
		else if (!StrToDate(dt)) {
			dt->dat_StrDate = NULL;
			dt->dat_StrTime = s1;
			if (!StrToDate(dt))
				Ok = FALSE;
		}
		if (Ok)
			*ds = dt->dat_Stamp;
	}
	FreeMem(dt, sizeof(struct DateTime));
	return Ok;
}

/* Convert DateStamp into a number of seconds since 1-Jan-78 */

long Date2Secs(struct DateStamp * ds)
{
	return ds->ds_Days * 86400 + ds->ds_Minute * 60 + ds->ds_Tick / 50;
}

/*************************************************/

long __regargs _Main(void)
{
	char *ArgV[MAXNUMARGS];
	struct RDArgs *RA;
	struct RDArgs *DefaultRDArgs;
	LONG RC = 20;		/* assumle the worst */

	if (DOSBase->dl_lib.lib_Version < 37)
		return 20;


	if (RA = AllocDosObject(DOS_RDARGS, NULL)) {
		memset(ArgV, 0, MAXNUMARGS * sizeof(APTR));
		RA->RDA_ExtHelp = CliHelp;
		/* first read default */
		/* getting the default string */
		if (DefaultRDArgs = AllocDosObject(DOS_RDARGS, NULL)) {
			UBYTE Default[MAXDEFAULTLEN];

			if ((DefaultRDArgs->RDA_Source.CS_Length = GetVar("For.DefOpts", Default, MAXDEFAULTLEN - 1, 0L)) > 0) {
				/* let ReadArgs() allocate neccesary buffer sinc I use diferrent RDArgs for Default and CLI opts */

				/* Ok I succefuly read a Default Option string now parse it */
				Default[DefaultRDArgs->RDA_Source.CS_Length++] = '\n';	/* this is need by ReadArgs() */
				Default[DefaultRDArgs->RDA_Source.CS_Length] = '\0';	/* this is need by ReadArgs() */
				DefaultRDArgs->RDA_Source.CS_Buffer = Default;
				DefaultRDArgs->RDA_Source.CS_CurChr = 0;
				DefaultRDArgs->RDA_Flags = RDAF_NOPROMPT;
				if (!ReadArgs(Template, (long *) ArgV, DefaultRDArgs)) {
					PutStr("Error in Default:");
					PrintFault(IoErr(), NULL);
					memset(ArgV, 0, MAXNUMARGS * sizeof(APTR));
				}
				DefaultRDArgs->RDA_Source.CS_Buffer = NULL;	/* Now ReadArgs() from Command line */
				/* the ArgV is leaving unchanged: the second ReadArgs() take actual value as default */
			}
		}
		/* Let ReadArgs() allocate necessay buffer rather using stack space */
		if (ReadArgs(Template, (long *) ArgV, RA))
			RC = Main(ArgV, NULL);
		else
			PrintFault(IoErr(), NULL);
		FreeDosObject(DOS_RDARGS, RA);
		/* Free RDargs now I don't need the option value */
		if (DefaultRDArgs)
			FreeDosObject(DOS_RDARGS, DefaultRDArgs);
	}
	return RC;
}

/**** ****/

void RemoveDir(char FullDir[])
{
	char *s;

	if (s = PathPart(FullDir))
		*s = '\0';
}

void PrintByte(UBYTE Buffer[], long BufLen, UBYTE Num)
{
	register short i;

	for (i = 0; i < Num && i < BufLen; i++)
		Printf("%02lx", (long) Buffer[i]);
}

/*
 *	Parse a line that may contain comas. Backslash ('\') is the override char.
 */
void ParseCmdLine(char *cmd)
{
	char *s, *d, c;

	s = d = cmd;
	while (c = *d++ = *s++) {
		if (c == '\\')
			*(d - 1) = *s++;
		else if (c == ',')
			*(d - 1) = '\n';
	}
}

void MakeFmt(char Cmd[], char CmdFmt[])
{
	char *s;
	BOOL Found = FALSE;

	strcpy(CmdFmt, Cmd);
	ParseCmdLine(CmdFmt);	/* Replace , by \n to separate commands */
	s = CmdFmt;
	while (*s) {
		if (*s == '%' && *(s + 1) == '%') {
			*(s + 1) = 's';
			Found = TRUE;
		}
		s++;
	}
	if (!Found)
		StrnCat(CmdFmt, " %s", MAXCMDLEN - 1);
}

UWORD ProtectBit(char P[])
{
	UWORD PB = 0;

	while (*P) {
		switch (*P) {
		case 'L':
		case 'l':
			PB |= FIBF_LINK;	/* another magic bit! */
			break;
		case 'C':
		case 'c':
			PB |= FIBF_COMMENT;	/* our magic bit! */
			break;
		case 'H':
		case 'h':
			PB |= FIBF_HIDDEN;
			break;
		case 'S':
		case 's':
			PB |= FIBF_SCRIPT;
			break;
		case 'P':
		case 'p':
			PB |= FIBF_PURE;
			break;
		case 'A':
		case 'a':
			PB |= FIBF_ARCHIVE;
			break;
		case 'R':
		case 'r':
			PB |= FIBF_READ;
			break;
		case 'W':
		case 'w':
			PB |= FIBF_WRITE;
			break;
		case 'E':
		case 'e':
			PB |= FIBF_EXECUTE;
			break;
		case 'D':
		case 'd':
			PB |= FIBF_DELETE;
			break;
		default:	/* nothing to do */
			break;
		}
		P++;
	}

	return PB;
}

UWORD EasyProtect(LONG Protection)
{
	return (UWORD) ((Protection ^ 0x0F) & 0x00FF);	/* Complement 4 lower bits so all work the same way */
}

BOOL Match(struct SelectInfo * SelectInfo, struct FileInfoBlock * FIB)
{
	if (FIB->fib_DirEntryType < 0) {	/* this is a file */
		if (SelectInfo->si_Flags & SI_ALL_FILES)
			return TRUE;
		else if (!(SelectInfo->si_Flags & SI_MATCH_FILES))
			return FALSE;
	}
	else {			/* Dir */
		if (SelectInfo->si_Flags & SI_ALL_DIRS)
			return TRUE;
		else if (!(SelectInfo->si_Flags & SI_MATCH_DIRS))
			return FALSE;
	}
	if (SelectInfo->si_Flags & SI_NAME) {
		if (!MatchPatternNoCase(SelectInfo->si_PatTok, FIB->fib_FileName))
			return FALSE;
	}
	{
		long Secs = Date2Secs(&FIB->fib_Date);

		if (SelectInfo->si_Flags & SI_SINCEDATE) {
			if (Secs < SelectInfo->si_SinceSecs)
				return FALSE;
		}
		if (SelectInfo->si_Flags & SI_BEFOREDATE) {
			if (Secs > SelectInfo->si_BeforeSecs)
				return FALSE;
		}
	}
	if (FIB->fib_Size < SelectInfo->si_MinSize)
		return FALSE;
	if (SelectInfo->si_MaxSize && (FIB->fib_Size > SelectInfo->si_MaxSize))
		return FALSE;
	{
		UWORD Protection = EasyProtect(FIB->fib_Protection);

		if (SelectInfo->si_Flags & SI_POSPROTECTION) {
			if (!(Protection & SelectInfo->si_PosProtect))
				return FALSE;
		}
		if (SelectInfo->si_Flags & SI_NEGPROTECTION) {
			if ((Protection & SelectInfo->si_NegProtect))
				return FALSE;
		}
	}

	return TRUE;
}

BOOL MatchFileType(struct SelectInfo * SelectInfo, struct FileInfoBlock * FIB, FileType Type)
{
	if (WhatIsBase && (SelectInfo->si_Flags & SI_FILETYPE)) {
		UWORD Flags, i;

		for (i = 0; i < SelectInfo->si_NumFts; i++) {
			Flags = SelectInfo->si_FileTypes[i].fs_Flags;
			if (!CmpFileType(SelectInfo->si_FileTypes[i].fs_FileType, Type))
				return (BOOL) ((Flags & FTSF_EXCLUDETYPE) ? FALSE : TRUE);
			if ((Flags & FTSF_WITHSUBTYPES) && IsSubTypeOf(Type, SelectInfo->si_FileTypes[i].fs_FileType))
				return (BOOL) ((Flags & FTSF_EXCLUDETYPE) ? FALSE : TRUE);
		}
		if (SelectInfo->si_Flags & SI_POSFILETYPE)
			return FALSE;	/* no match within include FileTypes, exclude file */
		else
			return TRUE;	/* Only exclude types, and not found in them, include file */
	}
	return TRUE;
}


long __regargs Main(char *ArgV[], struct WBStartup *WBenchMsg)
{
	LONG rc = 0;
	long ReadSize = 480;
	UBYTE ShowByte = 8;
	ULONG Deep = 0;
	BOOL ShowFileType;
	char FmtCmd[MAXCMDLEN], Cmd[MAXCMDLEN];
	struct SelectInfo SelectInfo;

	WhatIsBase = OpenLibrary("whatis.library", 3L);

	memset(&SelectInfo, 0, sizeof(SelectInfo));
	if (ArgV[ARG_Files]) {
		if (!Stricmp(ArgV[ARG_Files], "MATCH"))
			SelectInfo.si_Flags |= SI_MATCH_FILES;
		else if (!Stricmp(ArgV[ARG_Files], "YES"))
			SelectInfo.si_Flags |= SI_ALL_FILES;
	}
	else			/* set default */
		SelectInfo.si_Flags |= SI_MATCH_FILES;
	if (ArgV[ARG_Dirs]) {
		if (!Stricmp(ArgV[ARG_Dirs], "MATCH"))
			SelectInfo.si_Flags |= SI_MATCH_DIRS;
		else if (!Stricmp(ArgV[ARG_Dirs], "YES"))
			SelectInfo.si_Flags |= SI_ALL_DIRS;
	}
	else			/* set default */
		SelectInfo.si_Flags |= SI_MATCH_DIRS;
	if (ArgV[ARG_Since]) {
		struct DateStamp DateStamp;

		String2Date(ArgV[ARG_Since], &DateStamp);
		SelectInfo.si_SinceDate = DateStamp;
		SelectInfo.si_SinceSecs = Date2Secs(&DateStamp);
		SelectInfo.si_Flags |= SI_SINCEDATE;
	}
	if (ArgV[ARG_Before]) {
		struct DateStamp DateStamp;

		String2Date(ArgV[ARG_Before], &DateStamp);
		SelectInfo.si_BeforeDate = DateStamp;
		SelectInfo.si_BeforeSecs = Date2Secs(&DateStamp);
		SelectInfo.si_Flags |= SI_BEFOREDATE;
	}
	if (ArgV[ARG_MinSize])
		SelectInfo.si_MinSize = *(ULONG *) ArgV[ARG_MinSize];
	if (ArgV[ARG_MaxSize])
		SelectInfo.si_MaxSize = *(ULONG *) ArgV[ARG_MaxSize];
	if (ArgV[ARG_PosProtect]) {
		SelectInfo.si_Flags |= SI_POSPROTECTION;
		SelectInfo.si_PosProtect = ProtectBit(ArgV[ARG_PosProtect]);
	}
	if (ArgV[ARG_NegProtect]) {
		SelectInfo.si_Flags |= SI_NEGPROTECTION;
		SelectInfo.si_NegProtect = ProtectBit(ArgV[ARG_NegProtect]);
	}
	if (ArgV[ARG_Type] && WhatIsBase) {
		UBYTE NumFT = 0;
		UWORD Flags = 0;
		char *c;

		for (c = ArgV[ARG_Type]; *c; c++) {
			Printf("\"%s\"\n", c);
			switch (*c) {
			case ONLYFileType:
				Flags &= ~FTSF_EXCLUDETYPE;
				break;
			case NOTFileType:
				Flags |= FTSF_EXCLUDETYPE;
				break;
			case WHITHSubSub:
				Flags |= FTSF_WITHSUBTYPES;
				break;
			case '(':	/* for ReadArgs()/Template reaseon, the quote '"' can't be used */
				{
					char IDType[100];
					char *i = IDType;

					c++;	/* skip '(' */
					while (*c != ')')
						*i++ = *c++;	/* copy until ')' */
					*i = '\0';	/* NULL terminate the string */
					/* BUG: the SAS don't warn on this : i = '\0' */

					SelectInfo.si_FileTypes[NumFT].fs_FileType = GetIDType(IDType);
					SelectInfo.si_FileTypes[NumFT].fs_Flags = Flags;
					if (TYPE_UNKNOWNIDSTRING == SelectInfo.si_FileTypes[NumFT].fs_FileType)
						Printf("Unknown FileType:\"%s\"\n", IDType);
					else
						NumFT++;
				}
				break;
			case ')':
				/* just the mark of the end of and FileType ident, nothing to do */
			case ',':
				/* just a separator, nothing to do */
				break;
			      delault:
				Printf("FileType spec have errors at:%s\n", c);
			}
		}
		SelectInfo.si_NumFts = NumFT;
		SelectInfo.si_Flags |= (Flags & FTSF_EXCLUDETYPE) ? SI_NEGFILETYPE : SI_POSFILETYPE;
	}

	if (ArgV[ARG_READSIZE])
		ReadSize = *(long *) ArgV[ARG_READSIZE];
	if (ArgV[ARG_SHOWBYTE])
		ShowByte = (UBYTE) * (long *) ArgV[ARG_SHOWBYTE];

	if (ArgV[ARG_DEEPWHATIS])
		Deep = *(long *) ArgV[ARG_DEEPWHATIS];

	ShowFileType = (BOOL) ArgV[ARG_SHOWFILETYPE];
	if (ArgV[ARG_CMD])
		MakeFmt(ArgV[ARG_CMD], FmtCmd);
	else
		ShowFileType = TRUE;	/* If user don't supply cmd I suppose he call "For" for somthing */

	/* SASBUG: this line generte incorrect code:
		 move.l 03c(a5), a0
		 move #1,(a0)
		 ( BOOL )ArgV[ ARG_SHOWFILETYPE] = TRUE;
	*/
	{
		LONG ReturnCode = RETURN_ERROR;
		FileType Type = TYPE_UNSCANNED;
		char FullDir[MAXSTRINGLEN];
		BPTR InputFH, OutputFH;
		BPTR InputLock, OutputLock;
		UBYTE *Buffer;

		//BPTR InitialDir;

		FullDir[0] = '\0';
		//InitialDir = Lock("", ACCESS_READ);
		//CurrentDir(((struct Process *) SysBase->ThisTask)->pr_CurrentDir);
		InputFH = Input();
		OutputFH = Output();
		if (ArgV[ARG_ASYNC]) {
			InputLock = DupLockFromFH(Input());
			OutputLock = DupLockFromFH(Output());
		}
		if (Buffer = AllocVec(ReadSize + 1, MEMF_ANY)) {
			struct AnchorPath *AP;

			if (AP = AllocVec(sizeof(struct AnchorPath) + MAX_PATHLEN, MEMF_ANY | MEMF_CLEAR)) {
				char Buf[MAXSTRINGLEN];
				char *Pat;
				UBYTE i;

				AP->ap_BreakBits = SIGBREAKF_CTRL_C;	/* Break on these bits	*/
				AP->ap_Strlen = MAX_PATHLEN;
				AP->ap_Flags = (ArgV[ARG_ALL]) ? APF_DODOT : APF_DODOT | APF_DOWILD;	/* allow convertion of '.' to CurrentDir */
				/*  Well  I have one probleme here:  how corectly handle the
					ALL  flags:  if the user specify a pattern the MatchNext()
					hide  all  file  and  DIRS  which  don't  match to the
					pattern,  so  I  don't  see  dir  and  in  fact can't ask
					MatchNext()  to  enter it.  This limitation is STUPID and
					important  liumitation.   I  hope is only because I don't
					know how to do it.  I hope...
				*/
				for (i = 0, Pat = ((char **) ArgV[ARG_NameA])[0]; Pat; i++, Pat = ((char **) ArgV[ARG_NameA])[i]) {
					char ScanDir[MAXSTRINGLEN] =
					{'#', '?', '\0'};
					BOOL DoIt = TRUE;

					{
						char *FilePattern;

						FilePattern = FilePart(Pat);
						if (*FilePattern) {
							SelectInfo.si_Flags |= SI_NAME;
							strcpy(SelectInfo.si_Pattern, FilePattern);
							ParsePatternNoCase(FilePattern, SelectInfo.si_PatTok, PATTERN_BUF_SIZE);
						}
						*FilePattern = '\0';	/* terminate the full name at end of path */
						strcpy(ScanDir, Pat);
						StrCat(ScanDir, "#?");
					}
					for (ReturnCode = MatchFirst(ScanDir, AP);
					     ReturnCode == 0;
					     ReturnCode = MatchNext(AP)
						) {
						if (AP->ap_Flags & APF_DirChanged) {
						}
						if (AP->ap_Info.fib_DirEntryType > 0) {
							if (AP->ap_Flags & APF_DIDDIR) {
								RemoveDir(FullDir);
								Printf("[33m\"%s\"[31m\n", FullDir);
								DoIt = FALSE;	/* we have treated this dir before entering in it so don't treat it twice */
							}
							else if (ArgV[ARG_ALL]) {
								AddPart(FullDir, AP->ap_Info.fib_FileName, MAXSTRINGLEN);
								Printf("[33m\"%s\"[31m\n", FullDir);

								/* make it enter the directory */
								AP->ap_Flags |= APF_DODIR;
							}
							/* clear the completed directory flag */
							AP->ap_Flags &= ~APF_DIDDIR;
						}
						/* Here is code for handling each particular file */
						if (DoIt && Match(&SelectInfo, &AP->ap_Info)) {
							long Readed;

							SPrintf(Buf, "\"%s\"", AP->ap_Buf);
							if (Deep) {
								if (AP->ap_Info.fib_DirEntryType <= 0) {
									BPTR FH;

									if (FH = Open(AP->ap_Buf, MODE_OLDFILE)) {
										Readed = Read(FH, Buffer, ReadSize);
										Buffer[Readed] = '\0';	/* whatis.library need that */
										Type = _WhatIsTags(AP->ap_Buf, WI_Deep, Deep, WI_FIB, &AP->ap_Info, WI_Buffer, Buffer, WI_BufLen, Readed, TAG_DONE);
										Close(FH);
									}
									else
										Type = _WhatIsTags(AP->ap_Buf, WI_Deep, Deep, WI_FIB, &AP->ap_Info, TAG_DONE);
								}
								else
									Type = _WhatIsTags(AP->ap_Buf, WI_Deep, Deep, WI_FIB, &AP->ap_Info, TAG_DONE);
							}
							else
								Type = _WhatIsTags(AP->ap_Buf, WI_Deep, LIGHTTYPE, WI_FIB, &AP->ap_Info, TAG_DONE);

							if (MatchFileType(&SelectInfo, &AP->ap_Info, Type)) {
								if (ShowFileType) {
									Printf("%-32s\t", AP->ap_Info.fib_FileName);	/* due my print of dir herarhy, only print base name here */
									Printf("%-9s \t", GetIDString(Type));
									if (AP->ap_Info.fib_DirEntryType <= 0)
										PrintByte(Buffer, Readed, ShowByte);
									PutStr("\n");
								}

								if (ArgV[ARG_CMD]) {
									if (ArgV[ARG_ASYNC]) {
										/* Need to do this because Async mode close the Input/Output */
										InputFH = OpenFromLock(InputLock);
										OutputFH = OpenFromLock(OutputLock);
									}
									/* Allow 5 %% in cmd */
									SPrintf(Cmd, FmtCmd, Buf, Buf, Buf, Buf, Buf);	/* building comand line */
									SystemTags(Cmd,
										   SYS_Input, InputFH,
										   SYS_Output, OutputFH,
										   SYS_Asynch, ArgV[ARG_ASYNC],
										   SYS_UserShell, TRUE,
										   TAG_DONE
										);
								}
							}
						}
						DoIt = TRUE;
					}
					MatchEnd(AP);	/* This absolutely, positively must be called, all of the time. */
					if (ReturnCode != ERROR_NO_MORE_ENTRIES) {
						PrintFault(ReturnCode, NULL);
					}
					//CurrentDir(InitialDir);
				}
				FreeVec(AP);
			}
			FreeVec(Buffer);
		}
		else
			PutStr("Can't allocate Memory for Buffer\n");
		//UnLock(InitialDir);
		if (ArgV[ARG_ASYNC]) {
			UnLock(InputLock);
			UnLock(OutputLock);
		}
	}

	if (WhatIsBase)
		CloseLibrary((struct Library *) WhatIsBase);

	return rc;
}
