Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for rxgrep.cs

(view source code of rxgrep.cs as plain text)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text.RegularExpressions;
  5.  
  6.  
  7. namespace RobvanderWoude
  8. {
  9. 	class RxGrep
  10. 	{
  11. 		static readonly string progver = "2.04";
  12.  
  13. 		static bool dedup = false;
  14. 		static int skipmatches = 0;
  15. 		static int takematches = 0;
  16. 		static int bytes = -1;
  17.  
  18.  
  19. 		static int Main( string[] args )
  20. 		{
  21. 			#region Initialize Variables
  22.  
  23. 			bool caseset = false;
  24. 			bool quiet = false;
  25. 			bool skipset = false;
  26. 			bool takeset = false;
  27. 			string filename = string.Empty;
  28. 			string pattern = string.Empty;
  29. 			string input = string.Empty;
  30. 			int redirectnum = ( Console.IsInputRedirected ? 1 : 0 );
  31. 			RegexOptions regexoptions = RegexOptions.None;
  32.  
  33. 			#endregion Initialize Variables
  34.  
  35.  
  36. 			#region Command Line Parsing
  37.  
  38. 			if ( args.Length + redirectnum < 2 )
  39. 			{
  40. 				return ShowHelp( );
  41. 			}
  42.  
  43. 			List<string> arguments = new List<string>( args );
  44. 			if ( arguments.Contains( "/?" ) )
  45. 			{
  46. 				return ShowHelp( );
  47. 			}
  48.  
  49. 			if ( !Console.IsInputRedirected )
  50. 			{
  51. 				filename = arguments[0];
  52. 				arguments.RemoveAt( 0 );
  53. 			}
  54. 			pattern = arguments[0];
  55. 			arguments.RemoveAt( 0 );
  56.  
  57. 			foreach ( string option in arguments )
  58. 			{
  59. 				switch ( option.ToUpper( ).Substring( 0, 2 ) )
  60. 				{
  61. 					case "/D":
  62. 						if ( dedup )
  63. 						{
  64. 							return ShowHelp( "Duplicate switch /D" );
  65. 						}
  66. 						dedup = true;
  67. 						break;
  68. 					case "/F":
  69. 						if ( bytes != -1 )
  70. 						{
  71. 							return ShowHelp( "Duplicate switch /F" );
  72. 						}
  73. 						try
  74. 						{
  75. 							bytes = Convert.ToInt32( option.Substring( 3 ) );
  76. 						}
  77. 						catch ( Exception e )
  78. 						{
  79. 							Console.Error.WriteLine( "Error: {0}", e.Message );
  80. 							return ShowHelp( string.Format( "Invalid command line switch \"{0}\"", option ) );
  81. 						}
  82. 						break;
  83. 					case "/I":
  84. 						if ( caseset )
  85. 						{
  86. 							return ShowHelp( "Duplicate switch /I" );
  87. 						}
  88. 						regexoptions |= RegexOptions.IgnoreCase;
  89. 						caseset = true;
  90. 						break;
  91. 					case "/Q":
  92. 						if ( quiet )
  93. 						{
  94. 							return ShowHelp( "Duplicate switch /Q" );
  95. 						}
  96. 						quiet = true;
  97. 						break;
  98. 					case "/S":
  99. 						if ( skipset )
  100. 						{
  101. 							return ShowHelp( "Duplicate switch /S" );
  102. 						}
  103. 						try
  104. 						{
  105. 							skipmatches = Convert.ToInt32( option.Substring( 3 ) );
  106. 						}
  107. 						catch ( Exception e )
  108. 						{
  109. 							Console.Error.WriteLine( "Error: {0}", e.Message );
  110. 							return ShowHelp( string.Format( "Invalid command line switch \"{0}\"", option ) );
  111. 						}
  112. 						break;
  113. 					case "/T":
  114. 						if ( takeset )
  115. 						{
  116. 							return ShowHelp( "Duplicate switch /T" );
  117. 						}
  118. 						try
  119. 						{
  120. 							takematches = Convert.ToInt32( option.Substring( 3 ) );
  121. 						}
  122. 						catch ( Exception e )
  123. 						{
  124. 							Console.Error.WriteLine( "Error: {0}", e.Message );
  125. 							return ShowHelp( string.Format( "Invalid command line switch \"{0}\"", option ) );
  126. 						}
  127. 						break;
  128. 					default:
  129. 						return ShowHelp( string.Format( "Invalid command line {0}: \"{1}\"", ( option[0] == '/' ? "switch" : "argument" ), option ) );
  130. 				}
  131. 			}
  132.  
  133. 			#endregion Command Line Parsing
  134.  
  135.  
  136. 			#region Command Line Arguments Validation
  137.  
  138. 			if ( Console.IsInputRedirected )
  139. 			{
  140. 				// Read the redirected Standard Input
  141. 				input = Console.In.ReadToEnd( );
  142. 				if ( bytes != -1 )
  143. 				{
  144. 					input = input.Substring( 0, Math.Min( bytes, input.Length ) );
  145. 				}
  146. 			}
  147. 			else
  148. 			{
  149. 				// Check if the file name is valid
  150. 				if ( filename.IndexOf( "/" ) > -1 )
  151. 				{
  152. 					return ShowHelp( );
  153. 				}
  154. 				if ( filename.IndexOfAny( "?*".ToCharArray( ) ) > -1 )
  155. 				{
  156. 					return ShowHelp( "Wildcards not allowed" );
  157. 				}
  158. 				// Check if the file exists
  159. 				if ( File.Exists( filename ) )
  160. 				{
  161. 					// Read the file content
  162. 					using ( StreamReader file = new StreamReader( filename ) )
  163. 					{
  164. 						if ( bytes == -1 )
  165. 						{
  166. 							input = file.ReadToEnd( );
  167. 						}
  168. 						else
  169. 						{
  170. 							char[] buffer = new char[bytes];
  171. 							file.Read( buffer, 0, bytes );
  172. 							input = string.Join( string.Empty, buffer );
  173. 						}
  174. 					}
  175. 				}
  176. 				else
  177. 				{
  178. 					return ShowHelp( string.Format( "File not found: \"{0}\"", filename ) );
  179. 				}
  180. 			}
  181.  
  182. 			if ( dedup && ( skipset || takeset ) )
  183. 			{
  184. 				return ShowHelp( "Switch /D cannot be combined with switches /S or /T" );
  185. 			}
  186.  
  187. 			#endregion Command Line Arguments Validation
  188.  
  189.  
  190. 			// Now that the command line parsing is done, let's get some action
  191. 			if ( DisplayMatches( input, pattern, regexoptions ) == 0 && !quiet )
  192. 			{
  193. 				return ShowHelp( "No match found" );
  194. 			}
  195. 			return 0;
  196. 		}
  197.  
  198.  
  199. 		// The main functionality: display all matching substrings
  200. 		public static int DisplayMatches( string haystack, string needle, RegexOptions options )
  201. 		{
  202. 			int counter = 0;
  203. 			int displayed = 0;
  204. 			// Get all matches
  205. 			MatchCollection matches = Regex.Matches( haystack, needle, options );
  206. 			if ( dedup )
  207. 			{
  208. 				List<string> dedupedmatches = new List<string>( );
  209. 				foreach ( Match match in matches )
  210. 				{
  211. 					if ( !dedupedmatches.Contains( match.Value ) )
  212. 					{
  213. 						Console.WriteLine( match.Value );
  214. 						dedupedmatches.Add( match.Value );
  215. 						displayed += 1;
  216. 					}
  217. 				}
  218. 			}
  219. 			else
  220. 			{
  221. 				if ( matches.Count > skipmatches )
  222. 				{
  223. 					foreach ( Match match in matches )
  224. 					{
  225. 						if ( counter >= skipmatches && ( displayed < takematches || takematches == 0 ) )
  226. 						{
  227. 							Console.WriteLine( match.Value );
  228. 							displayed += 1;
  229. 						}
  230. 						counter += 1;
  231. 					}
  232. 				}
  233. 			}
  234. 			return displayed;
  235. 		}
  236.  
  237.  
  238. 		#region Error Handling
  239.  
  240. 		public static int ShowHelp( params string[] errmsg )
  241. 		{
  242. 			#region Error Message
  243.  
  244. 			if ( errmsg.Length > 0 )
  245.  
  246. 			{
  247. 				List<string> errargs = new List<string>( errmsg );
  248. 				errargs.RemoveAt( 0 );
  249. 				Console.Error.WriteLine( );
  250. 				Console.ForegroundColor = ConsoleColor.Red;
  251. 				Console.Error.Write( "ERROR:\t" );
  252. 				Console.ForegroundColor = ConsoleColor.White;
  253. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  254. 				Console.ResetColor( );
  255. 			}
  256.  
  257. 			#endregion Error Message
  258.  
  259.  
  260. 			#region Help Text
  261.  
  262. 			/*
  263. 			RxGrep,  Version 2.03
  264. 			Multi-line FindStr/Grep like tool
  265.  
  266. 			Usage:   RXGREP  filename  pattern  [ options ]
  267. 			or:      command  |  RXGREP  pattern  [ options ]
  268.  
  269. 			Where:   filename   is the file to be filtered
  270. 			         command    is the command whose standard output is to be filtered
  271. 			         pattern    is the search pattern (regular expression)
  272.  
  273. 			Options: /D         do not show Duplicate matches
  274. 			         /F:nn      search only the First nn bytes
  275. 			         /I         case Insensitive search
  276. 			         /Q         Quiet mode: no message if no match is found
  277. 			         /S:nn      Skip the first nn matches
  278. 			         /T:nn      Take only nn matches
  279.  
  280. 			Example: ROBOCOPY D:\sourcedir E:\targetdir /NP /MIR |
  281. 			         RXGREP "\s+\d+\s+D:\\sourcedir\\[^\n\r]*\r\n([^\n\r\\]+\r\n)+"
  282. 			         (to be read as a single command line) will return something like:
  283. 			                         125    D:\sourcedir\subdir\
  284. 			            New File                 342        brandnewfile.ext
  285. 			            Newer                  4.06m        updatedfile.ext
  286. 			          *EXTRA File              2.40m        deletedfile.ext
  287.  
  288. 			Notes:   If /F:nn is used and a file is specified, only the first nn bytes
  289. 			         of that file will be read; if the input is redirected, it is read
  290. 			         entirely, and then chopped to nn bytes before being searched.
  291. 			         Switch /D cannot be combined with /S or /T.
  292. 			         Return code ("errorlevel") will be 1 in case of (command line)
  293. 			         errors or if no match was found, otherwise 0.
  294. 			         This version of the program requires .NET Framework 4.5.
  295.  
  296. 			Written by Rob van der Woude
  297. 			http://www.robvanderwoude.com
  298. 			 */
  299.  
  300. 			#endregion Help Text
  301.  
  302.  
  303. 			#region Display Help Text
  304.  
  305. 			Console.Error.WriteLine( );
  306. 			Console.Error.WriteLine( "RxGrep,  Version {0}", progver );
  307. 			Console.Error.WriteLine( "Multi-line FindStr/Grep like tool" );
  308. 			Console.Error.WriteLine( );
  309.  
  310. 			Console.Error.Write( "Usage:   " );
  311. 			Console.ForegroundColor = ConsoleColor.White;
  312. 			Console.Error.WriteLine( "RXGREP  filename  pattern  [ options ]" );
  313. 			Console.ResetColor( );
  314.  
  315. 			Console.Error.Write( "or:      " );
  316. 			Console.ForegroundColor = ConsoleColor.White;
  317. 			Console.Error.WriteLine( "command | RXGREP  pattern  [ options ]" );
  318. 			Console.ResetColor( );
  319.  
  320. 			Console.Error.WriteLine( );
  321.  
  322. 			Console.Error.Write( "Where:   " );
  323. 			Console.ForegroundColor = ConsoleColor.White;
  324. 			Console.Error.Write( "filename" );
  325. 			Console.ResetColor( );
  326. 			Console.Error.WriteLine( "   is the file to be filtered" );
  327.  
  328. 			Console.ForegroundColor = ConsoleColor.White;
  329. 			Console.Error.Write( "         command" );
  330. 			Console.ResetColor( );
  331. 			Console.Error.WriteLine( "    is the command whose standard output is to be filtered" );
  332.  
  333. 			Console.ForegroundColor = ConsoleColor.White;
  334. 			Console.Error.Write( "         pattern" );
  335. 			Console.ResetColor( );
  336. 			Console.Error.WriteLine( "    is the search pattern (regular expression)" );
  337.  
  338. 			Console.Error.WriteLine( );
  339.  
  340. 			Console.Error.Write( "Options: " );
  341. 			Console.ForegroundColor = ConsoleColor.White;
  342. 			Console.Error.Write( "/D" );
  343. 			Console.ResetColor( );
  344. 			Console.Error.Write( "         do not show " );
  345. 			Console.ForegroundColor = ConsoleColor.White;
  346. 			Console.Error.Write( "D" );
  347. 			Console.ResetColor( );
  348. 			Console.Error.WriteLine( "uplicate matches" );
  349.  
  350. 			Console.ForegroundColor = ConsoleColor.White;
  351. 			Console.Error.Write( "         /F:nn" );
  352. 			Console.ResetColor( );
  353. 			Console.Error.Write( "      search only the " );
  354. 			Console.ForegroundColor = ConsoleColor.White;
  355. 			Console.Error.Write( "F" );
  356. 			Console.ResetColor( );
  357. 			Console.Error.Write( "irst " );
  358. 			Console.ForegroundColor = ConsoleColor.White;
  359. 			Console.Error.Write( "nn" );
  360. 			Console.ResetColor( );
  361. 			Console.Error.WriteLine( " bytes" );
  362.  
  363. 			Console.ForegroundColor = ConsoleColor.White;
  364. 			Console.Error.Write( "         /I" );
  365. 			Console.ResetColor( );
  366. 			Console.Error.Write( "         case " );
  367. 			Console.ForegroundColor = ConsoleColor.White;
  368. 			Console.Error.Write( "I" );
  369. 			Console.ResetColor( );
  370. 			Console.Error.WriteLine( "nsensitive search" );
  371.  
  372. 			Console.ForegroundColor = ConsoleColor.White;
  373. 			Console.Error.Write( "         /Q         Q" );
  374. 			Console.ResetColor( );
  375. 			Console.Error.WriteLine( "uiet mode: no message if no match is found" );
  376.  
  377. 			Console.ForegroundColor = ConsoleColor.White;
  378. 			Console.Error.Write( "         /S:nn      S" );
  379. 			Console.ResetColor( );
  380. 			Console.Error.Write( "kip the first " );
  381. 			Console.ForegroundColor = ConsoleColor.White;
  382. 			Console.Error.Write( "nn" );
  383. 			Console.ResetColor( );
  384. 			Console.Error.WriteLine( " matches" );
  385.  
  386. 			Console.ForegroundColor = ConsoleColor.White;
  387. 			Console.Error.Write( "         /T:nn      T" );
  388. 			Console.ResetColor( );
  389. 			Console.Error.Write( "ake only " );
  390. 			Console.ForegroundColor = ConsoleColor.White;
  391. 			Console.Error.Write( "nn" );
  392. 			Console.ResetColor( );
  393. 			Console.Error.WriteLine( " matches" );
  394.  
  395. 			Console.Error.WriteLine( );
  396.  
  397. 			Console.Error.Write( "Example: " );
  398. 			Console.ForegroundColor = ConsoleColor.White;
  399. 			Console.Error.WriteLine( @"ROBOCOPY D:\sourcedir E:\targetdir /NP /MIR |" );
  400.  
  401. 			Console.Error.WriteLine( @"         RXGREP ""\s+\d+\s+D:\\sourcedir\\[^\n\r]*\r\n([^\n\r\\]+\r\n)+""" );
  402. 			Console.ResetColor( );
  403.  
  404. 			Console.Error.WriteLine( "         (to be read as a single command line) will return something like:" );
  405.  
  406. 			Console.ForegroundColor = ConsoleColor.White;
  407. 			Console.Error.WriteLine( @"                         125    D:\sourcedir\subdir\" );
  408.  
  409. 			Console.Error.WriteLine( "            New File                 342        brandnewfile.ext" );
  410.  
  411. 			Console.Error.WriteLine( "            Newer                  4.06m        updatedfile.ext" );
  412.  
  413. 			Console.Error.WriteLine( "          *EXTRA File              2.40m        deletedfile.ext" );
  414. 			Console.ResetColor( );
  415.  
  416. 			Console.Error.WriteLine( );
  417.  
  418. 			Console.Error.Write( "Notes:   If " );
  419. 			Console.ForegroundColor = ConsoleColor.White;
  420. 			Console.Error.Write( "/F:nn" );
  421. 			Console.ResetColor( );
  422. 			Console.Error.Write( " is used and a file is specified, only the first " );
  423. 			Console.ForegroundColor = ConsoleColor.White;
  424. 			Console.Error.Write( "nn" );
  425. 			Console.ResetColor( );
  426. 			Console.Error.WriteLine( " bytes" );
  427.  
  428. 			Console.Error.WriteLine( "         of that file will be read; if the input is redirected, it is read" );
  429.  
  430. 			Console.Error.Write( "         entirely, and then chopped to " );
  431. 			Console.ForegroundColor = ConsoleColor.White;
  432. 			Console.Error.Write( "nn" );
  433. 			Console.ResetColor( );
  434. 			Console.Error.WriteLine( " bytes before being searched." );
  435.  
  436. 			Console.Error.Write( "         Switch " );
  437. 			Console.ForegroundColor = ConsoleColor.White;
  438. 			Console.Error.Write( "/D" );
  439. 			Console.ResetColor( );
  440. 			Console.Error.Write( " cannot be combined with " );
  441. 			Console.ForegroundColor = ConsoleColor.White;
  442. 			Console.Error.Write( "/S" );
  443. 			Console.ResetColor( );
  444. 			Console.Error.Write( " or " );
  445. 			Console.ForegroundColor = ConsoleColor.White;
  446. 			Console.Error.Write( "/T" );
  447. 			Console.ResetColor( );
  448. 			Console.Error.WriteLine( "." );
  449.  
  450. 			Console.Error.WriteLine( "         Return code (\"errorlevel\") will be 1 in case of (command line)" );
  451.  
  452. 			Console.Error.WriteLine( "         errors or if no match was found, otherwise 0." );
  453.  
  454. 			Console.Error.WriteLine( "         This version of the program requires .NET Framework 4.5." );
  455.  
  456. 			Console.Error.WriteLine( );
  457.  
  458. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  459.  
  460. 			Console.Error.WriteLine( "http://www.robvanderwoude.com" );
  461.  
  462. 			#endregion Display Help Text
  463.  
  464.  
  465. 			return 1;
  466. 		}
  467.  
  468. 		#endregion Error Handling
  469. 	}
  470. }
  471.  

page last modified: 2024-04-16; loaded in 0.0573 seconds