public static void RunCommand(string commandRaw, GrepResultCollection grepResultCollection) { string SplitPattern = @"\|(?![^{]*}|[^\(]*\)|[^\[]*\])"; string[] CommandCollection = Regex.Split(commandRaw, SplitPattern); foreach (string command in CommandCollection) { var CommandArgs = ConsoleUtils.DiscoverCommandArgs(command); ConsoleCommand ConsoleCommand = new ConsoleCommand() { CommandArgs = CommandArgs }; BeginProcessCommand(ConsoleCommand, grepResultCollection); } }
private static void BeginProcessCommand(ConsoleCommand consoleCommand, GrepResultCollection grepResultCollection) { bool WriteFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Write); Stopwatch CommandTimer = Stopwatch.StartNew(); string Filepath = GetPath(consoleCommand); List <string> Files = GetFiles(consoleCommand, grepResultCollection, Filepath); Files = GetFilteredFiles(consoleCommand, Files); // Clear the result collection between chained commands so that only the results of the final command are returned grepResultCollection.Clear(); ConsoleUtils.WriteConsoleItem(new ConsoleItem() { ForegroundColor = ConsoleColor.Red, Value = $"{Environment.NewLine}[Searching {Files.Count} file(s)]{Environment.NewLine}" }); RegexOptions OptionsFlags = GetRegexOptions(consoleCommand); ProcessCommand(grepResultCollection, Files, consoleCommand, OptionsFlags); if (WriteFlag) { grepResultCollection.Write(consoleCommand.CommandArgs[ConsoleFlag.Write]); } // Publish command run time CommandTimer.Stop(); ConsoleUtils.WriteConsoleItem(new ConsoleItem() { ForegroundColor = ConsoleColor.Red, Value = $"{Environment.NewLine}[{Math.Round((CommandTimer.ElapsedMilliseconds / 1000.0), 2)} second(s)]" }); ConsoleUtils.WriteConsoleItem(new ConsoleItem() { Value = Environment.NewLine + Environment.NewLine }); }
private static void BuildSearchResultsFileContent(ConsoleCommand consoleCommand, GrepResultCollection grepResultCollection, List <Match> matches, string filename, long fileSize, string fileRaw) { bool IgnoreBreaksFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.IgnoreBreaks); bool IgnoreCaseFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.IgnoreCase); bool ContextFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Context); bool NResultsFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.NResults); // Build file context search pattern string SearchTerm = consoleCommand.CommandArgs[ConsoleFlag.SearchTerm]; int ContextLength = ContextFlag ? Convert.ToInt32(consoleCommand.CommandArgs[ConsoleFlag.Context]) : 0; matches.ToList().ForEach(match => { string LeadingContext = string.Empty; string TrailingContext = string.Empty; if (ContextFlag) { // Rebuild matches with contextual text int LeadingContextStartIndex = match.Groups["MatchedString"].Index - ContextLength < 0 ? 0 : match.Groups["MatchedString"].Index - ContextLength; int LeadingContextLength = match.Groups["MatchedString"].Index < ContextLength ? match.Groups["MatchedString"].Index : ContextLength; int TrailingContextStartIndex = match.Groups["MatchedString"].Index + match.Groups["MatchedString"].Value.Length; int TrailingContextLength = TrailingContextStartIndex + ContextLength > fileRaw.Length ? fileRaw.Length - TrailingContextStartIndex : ContextLength; LeadingContext = Environment.NewLine + fileRaw.Substring(LeadingContextStartIndex, LeadingContextLength); TrailingContext = fileRaw.Substring(TrailingContextStartIndex, TrailingContextLength) + Environment.NewLine; } string MatchedString = match.Groups["MatchedString"].Value; GrepResult GrepResult = new GrepResult(filename, ResultScope.FileContent) { FileSize = fileSize, LeadingContextString = LeadingContext, TrailingContextString = TrailingContext, MatchedString = MatchedString }; // Line number int LineNumber = fileRaw.Substring(0, match.Groups["MatchedString"].Index).Split('\n').Length; GrepResult.LineNumber = LineNumber; lock (grepResultCollection) { if (!NResultsFlag || grepResultCollection.Count < Convert.ToInt32(consoleCommand.CommandArgs[ConsoleFlag.NResults])) { grepResultCollection.AddItem(GrepResult); } } }); }
private static void ProcessCommand(GrepResultCollection grepResultCollection, IEnumerable <string> files, ConsoleCommand consoleCommand, RegexOptions optionsFlags) { bool FixedStringsFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.FixedStrings); bool DeleteFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Delete); bool ReplaceFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Replace); bool WriteFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Write); bool FileNamesOnlyFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.FileNamesOnly); bool FileSizeMinimumFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.FileSizeMinimum); bool FileSizeMaximumFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.FileSizeMaximum); bool NResultsFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.NResults); int FileReadFailedCount = 0; int FileWriteFailedCount = 0; int DeleteSuccessCount = 0; int ReplacedSuccessCount = 0; int TotalFilesMatchedCount = 0; long FileSizeMin = GetFileSizeMinimum(consoleCommand); long FileSizeMax = GetFileSizeMaximum(consoleCommand); // Build content search pattern string SearchPattern = BuildSearchPattern(consoleCommand); Regex SearchRegex = new Regex(SearchPattern, optionsFlags); if (FileNamesOnlyFlag) { Regex FileNameRegex = new Regex(@"^(.+)[\/\\](?<FileName>[^\/\\]+)$"); var Matches = new List <GrepResult>(); files.ToList().ForEach(file => { if (!NResultsFlag || Matches.Count < Convert.ToInt32(consoleCommand.CommandArgs[ConsoleFlag.NResults])) { // Don't want to waste any time on files that have already been added bool FileAdded = Matches.Any(x => x.SourceFile == file); if (!FileAdded) { // Parse filename from path var FileNameMatch = FileNameRegex.Match(file)?.Groups["FileName"]; if (FileNameMatch != null) { // Query against filename var SearchMatch = SearchRegex.Match(FileNameMatch.Value); if (SearchMatch != Match.Empty) { // Write operations bool isWriteOperation = ReplaceFlag || DeleteFlag; if (isWriteOperation) { ProcessWriteOperations(consoleCommand, file, SearchPattern, Matches.Count, ref file, ref TotalFilesMatchedCount, ref DeleteSuccessCount, ref ReplacedSuccessCount, ref FileWriteFailedCount); } else { int TrailingContextStringStartIndex = FileNameMatch.Index + SearchMatch.Index + SearchMatch.Length; // Validate any filesize parameters var FileSize = FileSizeMaximumFlag || FileSizeMinimumFlag ? WindowsUtils.GetFileSizeOnDisk(file) : -1; bool FileSizevalidateSuccess = ValidateFileSize(consoleCommand, FileSize, FileSizeMin, FileSizeMax); if (FileSizevalidateSuccess) { GrepResult GrepResult = new GrepResult(file, ResultScope.FileName) { FileSize = FileSize, LeadingContextString = file.Substring(0, FileNameMatch.Index + SearchMatch.Index), MatchedString = SearchMatch.Value, TrailingContextString = file.Substring(TrailingContextStringStartIndex, file.Length - TrailingContextStringStartIndex) }; Matches.Add(GrepResult); } } } } } } }); TotalFilesMatchedCount = Matches.Count(); grepResultCollection.AddItemRange(Matches); } else { if (consoleCommand.CommandArgs[ConsoleFlag.SearchTerm] == string.Empty) { throw new Exception("Error: Search term not supplied"); } files.AsParallel().ForAll(file => { try { if (!NResultsFlag || grepResultCollection.Count < Convert.ToInt32(consoleCommand.CommandArgs[ConsoleFlag.NResults])) { List <Match> Matches = new List <Match>(); // Validate any filesize parameters var FileSize = FileSizeMaximumFlag || FileSizeMinimumFlag ? WindowsUtils.GetFileSizeOnDisk(file) : -1; bool FileSizevalidateSuccess = ValidateFileSize(consoleCommand, FileSize, FileSizeMin, FileSizeMax); if (FileSizevalidateSuccess) { string FileRaw = File.ReadAllText(file); Matches = SearchRegex.Matches(FileRaw).ToList(); if (Matches.Any()) { // Write operations bool isWriteOperation = ReplaceFlag || DeleteFlag; if (isWriteOperation) { ProcessWriteOperations(consoleCommand, file, SearchPattern, Matches.Count, ref FileRaw, ref TotalFilesMatchedCount, ref DeleteSuccessCount, ref ReplacedSuccessCount, ref FileWriteFailedCount); } // Read operations else { BuildSearchResultsFileContent(consoleCommand, grepResultCollection, Matches, file, FileSize, FileRaw); lock (_SearchLock) { TotalFilesMatchedCount++; } } } } } } catch { lock (_SearchLock) { FileReadFailedCount++; } } }); } // Notify the user of any files that could not be read from or written to PublishFileAccessSummary(FileReadFailedCount, FileWriteFailedCount); // Publish command summary to console PublishCommandSummary(consoleCommand, grepResultCollection, TotalFilesMatchedCount, DeleteSuccessCount, ReplacedSuccessCount); }
private static void BuildSearchResultsFileContent(ConsoleCommand consoleCommand, GrepResultCollection grepResultCollection, List <Match> matches, string filename, string fileRaw, string searchPattern) { bool IgnoreBreaksFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.IgnoreBreaks); bool IgnoreCaseFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.IgnoreCase); bool ContextFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Context); // Build file context search pattern string SearchTerm = consoleCommand.CommandArgs[ConsoleFlag.SearchTerm]; int ContextLength = ContextFlag ? Convert.ToInt32(consoleCommand.CommandArgs[ConsoleFlag.Context]) : 0; string ContextPattern = @"(?:(?<ContextString>.{0," + ContextLength.ToString() + @"}?))"; Regex ContextRegex = new Regex(ContextPattern + searchPattern); matches.ToList().ForEach(match => { // Rebuild matches with contextual text if (ContextFlag) { int ContextStartIndex = (match.Index - ContextLength) < 0 ? 0 : (match.Index - ContextLength); match = ContextRegex.Match(fileRaw, ContextStartIndex); } string ContextString = ContextFlag ? match.Groups["ContextString"]?.Value ?? string.Empty : string.Empty; string MatchedString = match.Groups["MatchedString"].Value; GrepResult GrepResult = new GrepResult(filename, ResultScope.FileContent) { LeadingContextString = ContextString, MatchedString = MatchedString }; // Line number if (!IgnoreBreaksFlag) { int LineNumber = fileRaw.Substring(0, match.Groups["MatchedString"].Index).Split('\n').Length; GrepResult.LineNumber = LineNumber; } grepResultCollection.AddItem(GrepResult); }); }
private static void ProcessCommand(GrepResultCollection grepResultCollection, IEnumerable <string> files, ConsoleCommand consoleCommand, RegexOptions optionsFlags) { bool FixedStringsFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.FixedStrings); bool DeleteFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Delete); bool ReplaceFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Replace); bool WriteFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.Write); bool FileNamesOnlyFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.FileNamesOnly); bool IgnoreBreaksFlag = consoleCommand.CommandArgs.ContainsKey(ConsoleFlag.IgnoreBreaks); int FileReadFailedCount = 0; int FileWriteFailedCount = 0; int DeleteSuccessCount = 0; int ReplacedSuccessCount = 0; int FilesMatchedCount = 0; // Build content search pattern string SearchPattern = BuildSearchPattern(consoleCommand); Regex SearchRegex = new Regex(SearchPattern, optionsFlags); if (FileNamesOnlyFlag) { Regex FileNameRegex = new Regex(@"^(.+)[\/\\](?<FileName>[^\/\\]+)$"); var Matches = new List <GrepResult>(); files.ToList().ForEach(file => { // Don't want to waste any time on files that have already been added bool FileAdded = Matches.Any(x => x.SourceFile == file); if (!FileAdded) { // Parse filename from path var FileNameMatch = FileNameRegex.Match(file)?.Groups["FileName"]; if (FileNameMatch != null) { // Query against filename var SearchMatch = SearchRegex.Match(FileNameMatch.Value); if (SearchMatch != Match.Empty) { var MatchedString = SearchMatch.Groups["MatchedString"]; int TrailingContextStringStartIndex = FileNameMatch.Index + FileNameMatch.Value.ToLower().IndexOf(MatchedString.Value.ToLower()) + MatchedString.Length; GrepResult GrepResult = new GrepResult(file, ResultScope.FileName) { LeadingContextString = file.Substring(0, FileNameMatch.Index), MatchedString = MatchedString.Value, TrailingContextString = file.Substring(TrailingContextStringStartIndex, file.Length - TrailingContextStringStartIndex) }; Matches.Add(GrepResult); } } } }); FilesMatchedCount = Matches.Count(); grepResultCollection.AddItemRange(Matches); } else { files.AsParallel().ForAll(file => { try { List <Match> Matches = new List <Match>(); string FileRaw = File.ReadAllText(file); // Apply linebreak filtering options if (IgnoreBreaksFlag) { string FileLineBreakFilteredNull = FileRaw.Replace("\r", string.Empty).Replace("\n", string.Empty); string FileLineBreakFilteredSpace = Regex.Replace(FileRaw, @"[\r\n]+", " "); Matches.AddRange(SearchRegex.Matches(FileLineBreakFilteredNull)); Matches.AddRange(SearchRegex.Matches(FileLineBreakFilteredSpace)); } else { Matches = SearchRegex.Matches(FileRaw).ToList(); } if (Matches.Any()) { // Write operations bool isWriteOperation = ReplaceFlag || DeleteFlag; if (isWriteOperation) { List <ConsoleItem> ConsoleItemCollection = new List <ConsoleItem>(); // FileName ConsoleItemCollection.Add(new ConsoleItem() { ForegroundColor = ConsoleColor.DarkYellow, Value = $"{file} " }); try { if (DeleteFlag) { // Delete file File.Delete(file); ConsoleItemCollection.Add(new ConsoleItem() { ForegroundColor = ConsoleColor.Red, Value = $"Deleted" }); lock (_searchLock) { DeleteSuccessCount++; } } else if (ReplaceFlag) { // Replace all occurrences in file FileRaw = Regex.Replace(FileRaw, SearchPattern, consoleCommand.CommandArgs[ConsoleFlag.Replace]); File.WriteAllText(file, FileRaw); string MatchesText = Matches.Count == 1 ? "match" : "matches"; ConsoleItemCollection.Add(new ConsoleItem() { ForegroundColor = ConsoleColor.DarkMagenta, Value = $"{Matches.Count} {MatchesText}" }); lock (_searchLock) { ReplacedSuccessCount += Matches.Count; } } } catch (Exception ex) { ConsoleItemCollection.Add(new ConsoleItem() { ForegroundColor = ConsoleColor.Gray, BackgroundColor = ConsoleColor.DarkRed, Value = $"Access Denied" }); lock (_searchLock) { FileWriteFailedCount++; } } finally { // Empty buffer ConsoleItemCollection.Add(new ConsoleItem() { Value = Environment.NewLine }); ConsoleUtils.WriteConsoleItemCollection(ConsoleItemCollection); lock (_searchLock) { FilesMatchedCount++; } } } // Read operations else { BuildSearchResultsFileContent(consoleCommand, grepResultCollection, Matches, file, FileRaw, SearchPattern); lock (_searchLock) { FilesMatchedCount++; } } } } catch (Exception ex) { lock (_searchLock) { FileReadFailedCount++; } } }); } // Notify the user of any files that could not be read from or written to PublishFileAccessSummary(FileReadFailedCount, FileWriteFailedCount); // Publish command summary to console PublishCommandSummary(consoleCommand, grepResultCollection, FilesMatchedCount, DeleteSuccessCount, ReplacedSuccessCount); }