private static int Main(string[] args) { Console.WriteLine("==="); Console.WriteLine("AddonGrep"); Console.WriteLine("==="); Console.WriteLine(); if (args.Length == 0 || args[0] == "--help" || args[0] == "-help" || args[0] == "-h") { Console.WriteLine("Finds files inside GMA files within a Garry's Mod addons folder."); Console.WriteLine(); Console.WriteLine("Usage:"); Console.WriteLine(" dotnet AddonGrep.dll <addons folder path> [--print-files]"); Console.WriteLine("Along with any amount of the following:"); Console.WriteLine(" -F | --match-path <glob>"); Console.WriteLine(" -R | --regex-path <regex>"); Console.WriteLine(" -C | --match-content <glob>"); Console.WriteLine(" -T | --regex-content <regex>"); Console.WriteLine("If there is not at least one pattern, every file will be printed."); Console.WriteLine("Every pattern must match for a file to be printed."); Console.WriteLine(""); Console.WriteLine("Searches are case-insensitive regardless of filesystem, and slashes are normalized."); return(2); } string sourcePath = null; var shouldPrintFiles = false; var pathMatchers = new List <Regex>(); var contentMatchers = new List <Regex>(); for (var i = 0; i < args.Length; i++) { if (args[i].Length == 0) { continue; } bool NotPair(out int exitCode) { if (i + 1 >= args.Length) { Console.WriteLine($"All arguments found after the input directory must be in pairs. Last argument: {args[i]}"); { exitCode = 3; return(true); } } exitCode = 0; return(false); } switch (args[i]) { case "-P": case "--match-path": if (NotPair(out var exitCode1)) { return(exitCode1); } pathMatchers.Add(Glob(args[++i])); break; case "-R": case "--regex-path": if (NotPair(out var exitCode2)) { return(exitCode2); } pathMatchers.Add(new Regex(args[++i], RegexOptions.Compiled)); break; case "-C": case "--match-content": if (NotPair(out var exitCode3)) { return(exitCode3); } contentMatchers.Add(Glob(args[++i])); break; case "-D": case "--regex-content": if (NotPair(out var exitCode4)) { return(exitCode4); } contentMatchers.Add(new Regex(args[++i], RegexOptions.Compiled)); break; case "--print-files": shouldPrintFiles = true; break; default: sourcePath = args[i]; if (!Directory.Exists(sourcePath)) { Console.WriteLine($"No directory exists at path: {sourcePath}"); return(4); } break; } } if (sourcePath == null) { Console.WriteLine("No addons directory path provided"); return(5); } foreach (var file in Directory.EnumerateFiles(sourcePath).Where(file => file.EndsWith(".gma"))) { if (shouldPrintFiles) { Console.WriteLine(file); } using (var addon = RealtimeAddon.Load(file, true, true)) { foreach (var addonFile in addon.OpenAddon.Files) { if (CheckMatch(addonFile, pathMatchers, contentMatchers)) { Console.WriteLine($"{Path.GetFileName(file)}:{addonFile.Path}"); } } } } return(0); }
private static int Main(string[] args) { Console.WriteLine("Hello World!"); if (args.Length == 0 || args[0] == "--help" || args[0] == "-help" || args[0] == "-h") { Console.WriteLine("Finds the GMA files associated to Lua files in a specifically-formatted, line-separated list."); Console.WriteLine("Files are expected to be UTF-8, no BOM, as GMod's console log appears to use it."); Console.WriteLine(); Console.WriteLine("Usage:"); Console.WriteLine(" dotnet ClientSideLuaSeeker.dll <addons folder path> [...paths to text files]"); return(1); } if (args.Length == 1) { Console.WriteLine("Please provide at least one text file to crawl through, or pass --help for help."); return(2); } var addonsFolder = args[0]; var dumpPaths = args.Skip(1); var paths = new HashSet <string>(); var duplicates = 0; var i = 1; foreach (var path in dumpPaths) { var text = File.ReadAllText(path, Encoding.UTF8); foreach (var match in Pattern1.Matches(text).Concat(ConsoleLogPattern.Matches(text))) { if (!paths.Add(match.Groups["path"].Value)) { duplicates++; } RewriteLine($"Match {i++} of {args.Length - 1}, total {paths.Count} uniq, {duplicates} dup"); } } RewriteLine(""); Console.WriteLine($"In {args.Length - 1} text files"); Console.WriteLine($"{paths.Count + duplicates} total, {paths.Count} uniq, {duplicates} dup"); Console.WriteLine("Beginning dig."); Console.WriteLine(); var countsPerAddon = new Dictionary <string, ulong>(); foreach (var file in Directory.EnumerateFiles(addonsFolder).Where(file => file.EndsWith(".gma"))) { using (var addon = RealtimeAddon.Load(file, true, true)) { var fileName = Path.GetFileName(file); var count = 0UL; foreach (var addonFile in addon.OpenAddon.Files) { if (!paths.Contains(addonFile.Path)) { continue; } Console.WriteLine($"{fileName}:{addonFile.Path}"); count++; } var key = $"{addon.OpenAddon.Title} ({fileName})"; countsPerAddon[key] = count; } } Console.WriteLine(); Console.WriteLine("Finished dig."); var counts = countsPerAddon.Select(e => (double)e.Value).ToArray(); Console.WriteLine($"Mean amount of lua files/addon: {MathHelpers.Mean(counts):0.##}"); Console.WriteLine($"StdDev: {MathHelpers.StdDev(counts):0.##}"); Console.WriteLine($"Median: {MathHelpers.Median(counts)}"); Console.WriteLine("Individual counts of lua files (most to least):"); const bool printEmpties = false; // ReSharper disable once ConditionIsAlwaysTrueOrFalse // ReSharper disable HeuristicUnreachableCode RedundantIfElseBlock #pragma warning disable 162 if (printEmpties) { foreach (var(key, value) in countsPerAddon.OrderByDescending(e => e.Value)) { Console.WriteLine(key + ": " + value); } } else { foreach (var(key, value) in countsPerAddon.OrderByDescending(e => e.Value)) { if (value > 0) { Console.WriteLine(key + ": " + value); } } } #pragma warning restore 162 // ReSharper restore HeuristicUnreachableCode RedundantIfElseBlock return(0); }