/* * Copyright © 1992-94 by S.R. & P.C. * * Created: 30 Mar 1992 18:26:36 * Modified: 09 Nov 1994 23:11:45 * * Make>> rx BumpRev For 3 8 * Make>> sc .c * Make>> slink LIB:cs.o .o SC SD BATCH NOICONS TO LIB LIB:c.lib * Make>> protect P ADD * * * 30/03/1992: V1.0 (Pierre Carrette) * Simple version with template: "Args/M,ALL/S,DONTFAIL/S,DO/K/A/F" * 4/07/1994: V2.2 (Sylvain Rougier) * No longer add the name of the object if no '%%' present * 5/07/1994: V3.0 * Add the 'Quiet' option not to print hierarchy (but still print FileType if asked) * Now work as it should always work: don't scan all the directory if no pattern * but scan all subdir if 'All' option specified. * Add the 'GivePathName' option to provide a Full Path arguments to the command. * No longuer add '"' around the file name. User can type '"%%"' if he need it. * 7/07/1994 V3.1 * If a full pathname file entry was specified, For don't find it type. fixed * 15/07/1994 V3.2 * Guru if a single file was suplied. fixed * Now FullPathArgs realy work * Don't put optimize or it guru ! (see note) * 31/07/1994 V3.3 * Check the stack size because it need at least 8192 (probably !...) * put optimize again. just to see. * 07/08/1994 V3.4 * Remove optimize because the sasc bug still here * correct some error int the doc ( the '*' was incorrectly used instead of the '"') * 21/08/1994 V3.5 * Now use StackSwap() to avoid stack pb * 22/09/1994 V3.6 (Pierre Carrette is back :-) * Major code cleanup. No more need StackSwap(). Bug fixes in template. whatis.library now Optional. * Inverted 'Quiet' to 'Verbose'. Changed 'VNFileType' to more comprehensive 'FileTypeVar' keyword. * Changed 'GivePathName' to 'FullPathArgs'. * FileTypeVar was not set if Showbytes was off. * Showbytes/ShowFileType is now off if no Cmd supplied. * 'Type' argument syntax simplified. now: "#text,!source c" * MatchFileType() bug fix. "#text,!source c" was not working!! * SAS Optimisation now works!!! * 22/09/1994 V3.7 * Recompiled with new version of c.lib which had a bug for 'ENV:' var parsing * 09/11/1994 V3.8 * Bug fix. File UnLock()ed before processed so that command can open it for writing. */ #include #include #include #include "For_rev.h" // Startup Modules... CliArgs; ReadEnvArgs("For"); static char Version[] = VERSTAG; STRPTR Template = "\ Pattern/A/M,Files/K,Dirs/K,Since/K,Before/K,MinSize/K/N,MaxSize/K/N,\ PosProtect/K,NegProtect/K,Type/K,All/S,ASync/S,ReadSize/K/N,ShowBytes/K/N,\ D=Deep/K/N,SFT=ShowFileType/S,FTV=FileTypeVar/K,FPA=FullPathArgs/S,Verbose/S,Do/K/F"; STRPTR CliHelp = VERS" ("DATE") © Sylvain Rougier & Pierre Carrette.\n\ Usage: For [Files ] [Dirs ]\n\ [Since ] [Before ] [MinSize ] [MaxSize ]\n\ [PosProtect ] [NegProtect ]\n\ [Type <[#=SUB,~=EXLC]FileType0,,,FileType15>] [All] [ASync] [ReadSize]\n\ [ShowBytes] [Deep] [ShowFileType] [FileTypeVar ] [FullPathArgs]\n\ [DO ]\n"; #define ARG_Template 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_SHOWBYTES 13 #define ARG_DEEPWHATIS 14 #define ARG_SHOWFILETYPE 15 #define ARG_FileTypeVar 16 #define ARG_FullPathArgs 17 #define ARG_Verbose 18 #define ARG_CMD 19 #define ARG_ENDARG 20 struct Library *WhatIsBase; #define MAX_PATHLEN 256 #define MAX_CMDLEN 512 /* char used in the filetype spec string */ #define NOTFileType '~' #define WITHSubTypes '#' /*******************************************************/ /* not in dos.h !! */ #define FIBB_HOLD 7 #define FIBF_HOLD (1<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; } static void PrintByte(UBYTE Buffer[], LONG BufLen, UBYTE Num) { register short i; if (BufLen > 0) { for (i = 0; i < Num && i < BufLen; i++) Printf("%02lx", Buffer[i]); } } /* * Parse a line that may contain comas. Backslash ('\') is the override char. */ static 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_HOLD; 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; } P++; } return PB; } static UWORD __inline EasyProtect(LONG Protection) { return (UWORD) ((Protection ^ 0x0F) & 0x00FF); /* Complement 4 lower bits so all work the same way */ } static 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; } if (SelectInfo->si_Flags & SI_SINCEDATE) { if (CompareDates(&SelectInfo->si_SinceDate, &fib->fib_Date) < 0) return FALSE; } if (SelectInfo->si_Flags & SI_BEFOREDATE) { if (CompareDates(&SelectInfo->si_BeforeDate, &fib->fib_Date) > 0) 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; } static BOOL MatchFileType(struct SelectInfo *SelectInfo, struct FileInfoBlock *fib, FileType Type) { if (WhatIsBase && (SelectInfo->si_Flags & SI_FILETYPE)) { BOOL Sub = FALSE; UWORD Flags, i; do { for( i=0 ; isi_NumFts ; i++ ) { Flags = SelectInfo->si_FileTypes[i].fs_Flags; if ((!Sub || (Flags & FTSF_WITHSUBTYPES)) && !CmpFileType(SelectInfo->si_FileTypes[i].fs_FileType, Type)) return (BOOL)((Flags & FTSF_EXCLUDETYPE) ? FALSE : TRUE); } Sub = TRUE; } while (Type = ParentFileType(Type)); 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; } /* * Parse a line that may contain comas ','. Backslash ('\') is the override * char. This function replace comas by cariage returns so that SystemTags() * takes them as different command lines, just like a script file. */ static 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'; } } /* Replaces %% by %s, suitable for SPrintf() */ static void MakeFmt(char *CmdFmt, char *Cmd) { char *s; strcpy(CmdFmt, Cmd); ParseCmdLine(CmdFmt); /* Replace , by \n to separate commands */ s = CmdFmt; while (*s) { if (*s == '%' && *(s + 1) == '%') *(s + 1) = 's'; s++; } } static LONG ExecuteCmd(char *Cmd, STRPTR StartPath, char *Name, struct Opt *Opt) { char *CmdBuf, *CmdFmt, *NameBuf; LONG rc = 20; BOOL NoMem = TRUE; if (CmdBuf = AllocVec(MAX_CMDLEN, MEMF_ANY)) { if (NameBuf = AllocVec(MAX_CMDLEN, MEMF_ANY)) { if (CmdFmt = AllocVec(MAX_CMDLEN, MEMF_ANY)) { MakeFmt(CmdFmt, Cmd); if (Opt->FullPathArgs) { strcpy(NameBuf, StartPath); AddPart(NameBuf, Name, MAX_CMDLEN); } else strcpy(NameBuf, Name); /* Allow 5 %% in cmd */ SPrintf(CmdBuf, CmdFmt, NameBuf, NameBuf, NameBuf, NameBuf, NameBuf); /* build command line */ if (Opt->Async) { SystemTags(CmdBuf, SYS_Input, Open("*", MODE_OLDFILE), SYS_Output, NULL, // System() will open it SYS_Asynch, TRUE, SYS_UserShell, TRUE, TAG_DONE); rc = 0; } else rc = SystemTags(CmdBuf, SYS_UserShell, TRUE, TAG_DONE); NoMem = FALSE; FreeVec(CmdFmt); } FreeVec(NameBuf); } FreeVec(CmdBuf); } if (NoMem) PrintFault(ERROR_NO_FREE_STORE, "For"); else if (rc) PrintFault(IoErr(), "For"); return rc; } static LONG ProcessEntry(struct SelectInfo *SelectInfo, struct FileInfoBlock *fib, STRPTR StartPath, STRPTR Name, UBYTE *FileData, struct Opt *Opt, STRPTR Cmd) { LONG RC = 0, BytesRead = 0; FileType Type = TYPE_UNSCANNED; if (WhatIsBase) { if (Opt->Deep && fib->fib_DirEntryType <= 0) { BPTR FH; if (FH = Open(Name, MODE_OLDFILE)) { BytesRead = Read(FH, FileData, Opt->ReadSize); FileData[BytesRead] = '\0'; /* whatis.library need that */ Type = WhatIsTags(Name, WI_Deep, Opt->Deep, WI_FIB, fib, WI_Buffer, FileData, WI_BufLen, BytesRead, TAG_DONE); Close(FH); } } else Type = WhatIsTags(Name, WI_Deep, LIGHTTYPE, WI_FIB, fib, TAG_DONE); } if (MatchFileType(SelectInfo, fib, Type)) { if (WhatIsBase) { STRPTR IDString; BOOL CR = FALSE; IDString = GetIDString(Type); if (Opt->ShowFileType) { Printf("%-12s %-32s", IDString, (Opt->Verbose) ? fib->fib_FileName : Name); CR = TRUE; } if (Opt->Showbytes && fib->fib_DirEntryType <= 0) { PrintByte(FileData, BytesRead, Opt->Showbytes); CR = TRUE; } if (CR) PutStr("\n"); if (Opt->FileTypeVar) SetVar(Opt->FileTypeVar, IDString, -1L, GVF_LOCAL_ONLY); } if (Cmd) RC = ExecuteCmd(Cmd, StartPath, Name, Opt); } return RC; } static LONG ProcessEntryPattern(struct AnchorPath *AP, struct SelectInfo *SelectInfo, struct Opt *Opt, STRPTR StartPath, STRPTR Pattern, UBYTE *FileData, STRPTR Cmd) { BOOL DoIt = TRUE; LONG RC=0, MatchErr; for (MatchErr = MatchFirst(Pattern, AP); RC == 0 && MatchErr == 0; MatchErr = MatchNext(AP)) { if (AP->ap_Flags & APF_DIDDIR) { if (Opt->Verbose) Printf("%s\n", AP->ap_Buf); DoIt = FALSE; /* Dir processed before entering it, don't process it twice */ AP->ap_Flags &= ~APF_DIDDIR; /* clear the completed directory flag */ } else if (AP->ap_Info.fib_DirEntryType > 0) { if (SelectInfo->si_Flags & SI_AFFECT_SUBDIRS) { if (Opt->Verbose) Printf("%s\n", AP->ap_Buf); AP->ap_Flags |= APF_DODIR; /* make Matchext() enter the directory */ } else AP->ap_Flags &= ~APF_DODIR; /* RESET this bit after MatchFirst/MatchNext to AVOID entering a dir. */ } /* Here is code for handling each particular file */ if (DoIt && Match(SelectInfo, &AP->ap_Info)) RC = ProcessEntry(SelectInfo, &AP->ap_Info, StartPath, AP->ap_Buf, FileData, Opt, Cmd); DoIt = TRUE; } MatchEnd(AP); if (MatchErr != ERROR_NO_MORE_ENTRIES) PrintFault(MatchErr, "For"); return RC; } LONG Main(char *ArgV[], struct WBStartup *WBenchMsg) { LONG rc = RETURN_OK; char *StartPath = NULL, *Buffer = NULL; struct FileInfoBlock *fib = NULL; struct SelectInfo SelectInfo; struct Opt Opt; UBYTE *FileData; WhatIsBase = OpenLibrary("whatis.library", 3L); memset(&SelectInfo, 0, sizeof(SelectInfo)); memset(&Opt, 0, sizeof(struct Opt)); 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_Flags |= SI_SINCEDATE; } if (ArgV[ARG_Before]) { struct DateStamp DateStamp; String2Date(ArgV[ARG_Before], &DateStamp); SelectInfo.si_BeforeDate = 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) { char IDType[100]; UBYTE NumFT = 0; char *c, *i; for (c = ArgV[ARG_Type]; *c && NumFT < MAX_FTS && rc == 0;) { switch (*c) { case NOTFileType: // ~ SelectInfo.si_FileTypes[NumFT].fs_Flags |= FTSF_EXCLUDETYPE; break; case WITHSubTypes: // # SelectInfo.si_FileTypes[NumFT].fs_Flags |= FTSF_WITHSUBTYPES; break; default: i = IDType; while (*c && *c != ',' && i < IDType+100-1) *i++ = *c++; // copy until ',' or end of string *i = '\0'; // nul terminate the string if (SelectInfo.si_FileTypes[NumFT].fs_Flags & FTSF_EXCLUDETYPE) SelectInfo.si_Flags |= SI_NEGFILETYPE; else SelectInfo.si_Flags |= SI_POSFILETYPE; SelectInfo.si_FileTypes[NumFT].fs_FileType = GetIDType(IDType); if (TYPE_UNKNOWNIDSTRING == SelectInfo.si_FileTypes[NumFT].fs_FileType) { Printf("Unknown FileType: %s\n", IDType); rc = 21; // Hack to prevent PrintFault('no memory') } NumFT++; } if (*c) c++; } SelectInfo.si_NumFts = NumFT; } if (ArgV[ARG_ALL]) SelectInfo.si_Flags |= SI_AFFECT_SUBDIRS; Opt.Async = (BOOL) ArgV[ARG_ASYNC]; Opt.ReadSize = (ArgV[ARG_READSIZE]) ? *(LONG *) ArgV[ARG_READSIZE] : 488; Opt.Deep = (ArgV[ARG_DEEPWHATIS]) ? *(LONG *) ArgV[ARG_DEEPWHATIS] : LIGHTTYPE; if (ArgV[ARG_SHOWBYTES]) { Opt.Showbytes = (UBYTE) (*(LONG *) ArgV[ARG_SHOWBYTES]); Opt.Deep = DEEPTYPE; } Opt.ShowFileType = (BOOL) ArgV[ARG_SHOWFILETYPE]; Opt.FileTypeVar = (STRPTR) ArgV[ARG_FileTypeVar]; Opt.FullPathArgs = (BOOL) ArgV[ARG_FullPathArgs]; Opt.Verbose = (BOOL) ArgV[ARG_Verbose]; if (rc == 0 && !(Buffer = AllocVec(MAX_PATHLEN, MEMF_ANY))) rc = RETURN_FAIL; if (rc == 0 && !(StartPath = AllocVec(MAX_PATHLEN, MEMF_ANY))) rc = RETURN_FAIL; if (rc == 0 && !(fib = AllocVec(sizeof(struct FileInfoBlock), MEMF_ANY))) rc = RETURN_FAIL; if (rc == 0 && (FileData = AllocVec(Opt.ReadSize + 1, MEMF_ANY))) { struct AnchorPath *AP; if (AP = AllocVec(sizeof(struct AnchorPath) + MAX_PATHLEN, MEMF_ANY)) { LONG IsWild; STRPTR Elmt; UBYTE i; if (Opt.FullPathArgs) NameFromLock(((struct Process *)SysBase->ThisTask)->pr_CurrentDir, StartPath, MAX_PATHLEN); else StartPath[0] = '\0'; for (i = 0; rc == 0 && (Elmt = ((char **) ArgV[ARG_Template])[i]); i++) { memset(AP, 0, sizeof(struct AnchorPath) + MAX_PATHLEN); AP->ap_BreakBits = SIGBREAKF_CTRL_C; /* Break on these bits */ AP->ap_Strlen = MAX_PATHLEN; /* * For wildcard matching with ALL flag set, two situations are handled differently * 1. foo#?/bar * 2. foobar#? * In the first case, a standard MatchFirst()/MatchNext() is used. * For the second one, if 'ALL' option is on, the pattern is replaced with "#?" * so that all directories are parsed, and then files filtered out by the more * powerfull function Match() */ IsWild = ParsePatternNoCase(Elmt, Buffer, MAX_PATHLEN); if (ArgV[ARG_ALL] && IsWild == 1 && FilePart(Elmt) == Elmt) { SelectInfo.si_Flags |= SI_NAME; strcpy(SelectInfo.si_PatTok, Buffer); rc = ProcessEntryPattern(AP, &SelectInfo, &Opt, StartPath, "#?", FileData, ArgV[ARG_CMD]); } else { BPTR L; switch (IsWild) { case 1: /* * Pattern * Dir1/Dir2/Pattern * Vol:Dir1/Dir2/Pattern */ rc = ProcessEntryPattern(AP, &SelectInfo, &Opt, StartPath, Elmt, FileData, ArgV[ARG_CMD]); break; case 0: if (L = Lock(Elmt, SHARED_LOCK)) { long ok; ok = Examine(L, fib); UnLock(L); // UnLock so that command can open file for writing if (ok) { if (ArgV[ARG_ALL] && fib->fib_DirEntryType >= 0) { // This is a dir strcpy(Buffer, Elmt); AddPart(Buffer, "#?", MAX_PATHLEN); rc = ProcessEntryPattern(AP, &SelectInfo, &Opt, StartPath, Buffer, FileData, ArgV[ARG_CMD]); } else rc = ProcessEntry(&SelectInfo, fib, StartPath, Elmt, FileData, &Opt, ArgV[ARG_CMD]); } else { PrintFault(IoErr(), Elmt); rc = RETURN_FAIL; } } else if (ArgV[ARG_CMD]) // Arg does not exists, allow: For 1 2 3 DO Echo %% rc = ExecuteCmd(ArgV[ARG_CMD], StartPath, Elmt, &Opt); else rc = RETURN_WARN; break; default: PrintFault(IoErr(), Elmt); rc = RETURN_FAIL; } } } FreeVec(AP); } FreeVec(FileData); } else if (rc == 21) rc = RETURN_FAIL; else PrintFault(ERROR_NO_FREE_STORE, "For"); if (fib) FreeVec(fib); if (Buffer) FreeVec(Buffer); if (StartPath) FreeVec(StartPath); if (WhatIsBase) CloseLibrary(WhatIsBase); return rc; }