Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for rxreplace.cs

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8.  
  9.  
  10. namespace RobvanderWoude
  11. {
  12. 	class RxReplace
  13. 	{
  14. 		static readonly string progver = "1.02";
  15.  
  16.  
  17. 		static int Main( string[] args )
  18. 		{
  19. 			#region Initialize variables
  20.  
  21. 			string filename = string.Empty;
  22. 			string input = string.Empty;
  23. 			string pattern = string.Empty;
  24. 			string replacement = string.Empty;
  25. 			string result = string.Empty;
  26. 			string targetfile = string.Empty;
  27. 			string[] options = null;
  28. 			RegexOptions regexoptions = RegexOptions.None;
  29. 			Encoding encoding = Encoding.Default;
  30. 			bool errorredirected = ConsoleEx.ErrorRedirected;
  31. 			bool inputredirected = ConsoleEx.InputRedirected;
  32. 			bool outputredirected = ConsoleEx.OutputRedirected;
  33. 			bool caseset = false;
  34. 			bool outputset = false;
  35. 			bool skipset = false;
  36. 			bool takeset = false;
  37. 			bool unescape = true;
  38. 			int redirectnum = ( inputredirected ? 1 : 0 );
  39. 			int searchbytes = -1;
  40. 			int skipmatches = 0;
  41. 			int takematches = 0;
  42.  
  43. 			#endregion Initialize variables
  44.  
  45.  
  46. 			#region Command Line Parsing
  47.  
  48. 			if ( args.Length == 0 )
  49. 			{
  50. 				return ShowHelp( );
  51. 			}
  52.  
  53. 			// Check for /? on the command line
  54. 			foreach ( string arg in args )
  55. 			{
  56. 				if ( arg == "/?" )
  57. 				{
  58. 					return ShowHelp( );
  59. 				}
  60. 			}
  61.  
  62. 			// Check and interpret command line arguments
  63. 			if ( args.Length + redirectnum == 3 )
  64. 			{
  65. 				if ( inputredirected )
  66. 				{
  67. 					pattern = args[0];
  68. 					replacement = args[1];
  69. 				}
  70. 				else
  71. 				{
  72. 					filename = args[0];
  73. 					pattern = args[1];
  74. 					replacement = args[2];
  75. 				}
  76. 			}
  77. 			else if ( args.Length + redirectnum > 7 )
  78. 			{
  79. 				return ShowHelp( );
  80. 			}
  81. 			else
  82. 			{
  83. 				if ( inputredirected )
  84. 				{
  85. 					pattern = args[0];
  86. 					replacement = args[1];
  87. 					options = args.Slice( 2, args.Length );
  88. 				}
  89. 				else
  90. 				{
  91. 					filename = args[0];
  92. 					pattern = args[1];
  93. 					replacement = args[2];
  94. 					options = args.Slice( 3, args.Length );
  95. 				}
  96. 			}
  97.  
  98. 			if ( options != null )
  99. 			{
  100. 				foreach ( string option in options )
  101. 				{
  102. 					switch ( option.ToUpper( ).Substring( 0, 2 ) )
  103. 					{
  104. 						case "/F":
  105. 							if ( searchbytes != -1 )
  106. 							{
  107. 								return ShowHelp( "Duplicate command line switch /F" );
  108. 							}
  109. 							try
  110. 							{
  111. 								searchbytes = Convert.ToInt32( option.Substring( 3 ) );
  112. 							}
  113. 							catch ( Exception )
  114. 							{
  115. 								return ShowHelp( "Invalid command line switch {0}", option );
  116. 							}
  117. 							break;
  118. 						case "/I":
  119. 							if ( caseset )
  120. 							{
  121. 								return ShowHelp( "Duplicate command line switch /I" );
  122. 							}
  123. 							regexoptions |= RegexOptions.IgnoreCase;
  124. 							caseset = true;
  125. 							break;
  126. 						case "/L":
  127. 							if ( !unescape )
  128. 							{
  129. 								return ShowHelp( "Duplicate command line switch /L" );
  130. 							}
  131. 							unescape = false;
  132. 							break;
  133. 						case "/O":
  134. 							if ( outputset )
  135. 							{
  136. 								return ShowHelp( "Duplicate switch /O" );
  137. 							}
  138. 							if ( outputredirected )
  139. 							{
  140. 								return ShowHelp( "Cannot combine command line switch /O and output redirection" );
  141. 							}
  142. 							if ( option.Trim( '"' ).Length > 4 && option[2] == ':' )
  143. 							{
  144. 								targetfile = option.Substring( 3 );
  145. 								if ( !Directory.GetParent( targetfile ).Exists )
  146. 								{
  147. 									return ShowHelp( "Invalid output path \"{0}\"", targetfile );
  148. 								}
  149. 							}
  150. 							else if ( !inputredirected )
  151. 							{
  152. 								targetfile = filename;
  153. 							}
  154. 							else
  155. 							{
  156. 								return ShowHelp( "Output file name is mandatory when combining command line switch /O and input redirection" );
  157. 							}
  158. 							outputset = true;
  159. 							break;
  160. 						case "/S":
  161. 							if ( skipset )
  162. 							{
  163. 								return ShowHelp( "Duplicate command line switch /S" );
  164. 							}
  165. 							try
  166. 							{
  167. 								skipmatches = Convert.ToInt32( option.Substring( 3 ) );
  168. 							}
  169. 							catch ( Exception e )
  170. 							{
  171. 								Console.Error.WriteLine( "Error: {0}", e.Message );
  172. 								return ShowHelp( "Invalid command line argument \"{0}\"", option );
  173. 							}
  174. 							skipset = true;
  175. 							break;
  176. 						case "/T":
  177. 							if ( takeset )
  178. 							{
  179. 								return ShowHelp( "Duplicate switch /T" );
  180. 							}
  181. 							try
  182. 							{
  183. 								takematches = Convert.ToInt32( option.Substring( 3 ) );
  184. 							}
  185. 							catch ( Exception e )
  186. 							{
  187. 								Console.Error.WriteLine( "Error: {0}", e.Message );
  188. 								return ShowHelp( "Invalid command line argument \"{0}\"", option );
  189. 							}
  190. 							takeset = true;
  191. 							break;
  192. 						default:
  193. 							return ShowHelp( "Invalid command line {0}: \"{1}\"", ( option[0] == '/' ? "switch" : "argument" ), option );
  194. 					}
  195. 				}
  196. 			}
  197.  
  198. 			if ( unescape )
  199. 			{
  200. 				// Unescape replacement to allow unicode characters, newlines, tabs, etc.
  201. 				replacement = UnEscapeString( replacement );
  202. 			}
  203.  
  204. 			#endregion Command Line Parsing
  205.  
  206.  
  207. 			#region Read input
  208.  
  209. 			if ( inputredirected )
  210. 			{
  211. 				// Read the redirected Standard Input
  212. 				input = Console.In.ReadToEnd( );
  213. 				if ( searchbytes > -1 && searchbytes < input.Length )
  214. 				{
  215. 					input = input.Substring( 0, searchbytes );
  216. 				}
  217. 			}
  218. 			else
  219. 			{
  220. 				// Check if the file name is valid
  221. 				if ( filename.IndexOf( "/" ) > -1 )
  222. 				{
  223. 					return ShowHelp( );
  224. 				}
  225. 				if ( filename.IndexOfAny( "?*".ToCharArray( ) ) > -1 )
  226. 				{
  227. 					return ShowHelp( "Wildcards not allowed" );
  228. 				}
  229. 				// Check if the file exists
  230. 				if ( File.Exists( filename ) )
  231. 				{
  232. 					// Get file size
  233. 					long filesize = new FileInfo( filename ).Length;
  234. 					// Read the file content
  235. 					using ( StreamReader file = new StreamReader( filename, true ) )
  236. 					{
  237. 						if ( searchbytes > -1 && searchbytes < filesize )
  238. 						{
  239. 							char[] buffer = new char[searchbytes];
  240. 							file.Read( buffer, 0, searchbytes );
  241. 							input = string.Join( string.Empty, buffer );
  242. 						}
  243. 						else
  244. 						{
  245. 							input = file.ReadToEnd( );
  246. 						}
  247. 						encoding = file.CurrentEncoding;
  248. 						file.Close( );
  249. 					}
  250. 				}
  251. 				else
  252. 				{
  253. 					return ShowHelp( "File not found: \"{0}\"", filename );
  254. 				}
  255. 			}
  256.  
  257. 			#endregion Read input
  258.  
  259.  
  260. 			#region Replace text
  261.  
  262. 			if ( skipmatches == 0 && takematches == 0 )
  263. 			{
  264. 				result = Regex.Replace( input, pattern, replacement );
  265. 			}
  266. 			else
  267. 			{
  268. 				// Get all matches
  269. 				Regex regex = new Regex( pattern, regexoptions );
  270. 				MatchCollection matches = Regex.Matches( input, pattern, regexoptions );
  271. 				if ( matches.Count > skipmatches )
  272. 				{
  273. 					int counter = 0;
  274. 					int lastindex = 0;
  275. 					int replaced = 0;
  276. 					foreach ( Match match in matches )
  277. 					{
  278. 						if ( counter >= skipmatches && ( replaced < takematches || takematches == 0 ) )
  279. 						{
  280. 							result += input.Substring( lastindex, match.Index ) + match.ToString( );
  281. 							lastindex = match.Index + match.Length;
  282. 							replaced += 1;
  283. 						}
  284. 						counter += 1;
  285. 					}
  286. 					if ( lastindex < input.Length )
  287. 					{
  288. 						result += input.Substring( lastindex );
  289. 					}
  290. 				}
  291. 			}
  292.  
  293. 			#endregion Replace text
  294.  
  295.  
  296. 			#region Return results
  297.  
  298. 			if ( string.IsNullOrWhiteSpace( targetfile ) )
  299. 			{
  300. 				Console.Write( result );
  301. 			}
  302. 			else
  303. 			{
  304. 				using ( StreamWriter file = new StreamWriter( targetfile, false, Encoding.GetEncoding( encoding.CodePage ) ) )
  305. 				{
  306. 					file.Write( result );
  307. 					file.Close( );
  308. 				}
  309. 			}
  310.  
  311. 			return 0;
  312.  
  313. 			#endregion Return results
  314. 		}
  315.  
  316.  
  317. 		static string UnEscapeString( string text )
  318. 		{
  319. 			// Unescaping tabs, linefeeds and quotes
  320. 			text = text.Replace( "\\n", "\n" );
  321. 			text = text.Replace( "\\r", "\r" );
  322. 			text = text.Replace( "\\t", "\t" );
  323. 			text = text.Replace( "\\007", "\t" );
  324. 			text = text.Replace( "\\012", "\n" );
  325. 			text = text.Replace( "\\015", "\r" );
  326. 			text = text.Replace( "\\042", "\"" );
  327. 			text = text.Replace( "\\047", "'" );
  328. 			// Unescaping Unicode, technique by "dtb" on StackOverflow.com: http://stackoverflow.com/a/8558748
  329. 			text = Regex.Replace( text, @"\\[Uu]([0-9A-Fa-f]{4})", m => char.ToString( (char) ushort.Parse( m.Groups[1].Value, NumberStyles.AllowHexSpecifier ) ) );
  330. 			return text;
  331. 		}
  332.  
  333.  
  334. 		#region Redirection Detection
  335.  
  336. 		// Code to detect redirection by Hans Passant on StackOverflow.com
  337. 		// http://stackoverflow.com/questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected
  338. 		public static class ConsoleEx
  339. 		{
  340. 			public static bool OutputRedirected
  341. 			{
  342. 				get
  343. 				{
  344. 					return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stdout ) );
  345. 				}
  346. 			}
  347.  
  348. 			public static bool InputRedirected
  349. 			{
  350. 				get
  351. 				{
  352. 					return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stdin ) );
  353. 				}
  354. 			}
  355.  
  356. 			public static bool ErrorRedirected
  357. 			{
  358. 				get
  359. 				{
  360. 					return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stderr ) );
  361. 				}
  362. 			}
  363.  
  364. 			// P/Invoke:
  365. 			private enum FileType { Unknown, Disk, Char, Pipe };
  366. 			private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
  367.  
  368. 			[DllImport( "kernel32.dll" )]
  369. 			private static extern FileType GetFileType( IntPtr hdl );
  370.  
  371. 			[DllImport( "kernel32.dll" )]
  372. 			private static extern IntPtr GetStdHandle( StdHandle std );
  373. 		}
  374.  
  375. 		#endregion Redirection Detection
  376.  
  377.  
  378. 		#region Error Handling
  379.  
  380. 		static int ShowHelp( params string[] errmsg )
  381. 		{
  382. 			#region Error Message
  383.  
  384. 			if ( errmsg.Length > 0 )
  385. 			{
  386. 				List<string> errargs = new List<string>( errmsg );
  387. 				errargs.RemoveAt( 0 );
  388. 				Console.Error.WriteLine( );
  389. 				Console.ForegroundColor = ConsoleColor.Red;
  390. 				Console.Error.Write( "ERROR:\t" );
  391. 				Console.ForegroundColor = ConsoleColor.White;
  392. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  393. 				Console.ResetColor( );
  394. 			}
  395.  
  396. 			#endregion Error Message
  397.  
  398.  
  399. 			#region Help Text
  400.  
  401. 			/*
  402. 			RxReplace,  Version 1.02
  403. 			Multi-line regex find and replace tool
  404.  
  405. 			Usage:   RXREPLACE  filename  pattern  replacement  [ options ]
  406. 			or:      some_command  |  RXREPLACE  pattern  replacement  [ options ]
  407.  
  408. 			Where:   filename       is the file to be filtered
  409. 			         some_command   is the command whose standard output is to be filtered
  410. 			         pattern        is the regex pattern for text to be replaced
  411. 			         replacement    replaces all matches (backreferences allowed, e.g. $1)
  412.  
  413. 			Options: /F:bytes       search the First specified number of bytes only
  414. 			         /I             makes the search case Insensitive
  415. 			         /L             treat replacement as Literal text
  416. 			                        (default: unescape replacement)
  417. 			         /O[:newfile]   Overwrite original, or write Output to newfile
  418. 			         /S:nn          Skip the first nn matches
  419. 			         /T:nn          Take only nn matches
  420.  
  421. 			Notes:   If /F:bytes is used and a file is specified, only the first bytes
  422. 			         of that file will be read; if the input is redirected, it is read
  423. 			         entirely, and will then be chopped to the specified number of bytes
  424. 			         before being searched. In both cases, the remainder of the input will
  425. 			         be discarded.
  426.  			         Unless /O switch is used, result will be written to Standard Output.
  427. 			         Backreferences in replacement can not be used with /S or /T.
  428.  
  429. 			Credits: Check for redirection by Hans Passant on StackOverflow.com:
  430. 			         http://stackoverflow.com/a/3453272
  431. 			         Array Slice extension by Sam Allen on DotNetPerls.com:
  432. 			         http://www.dotnetperls.com/array-slice
  433. 			         Unescaping Unicode by "dtb" on StackOverflow.com:
  434. 			         http://stackoverflow.com/a/8558748
  435.  
  436. 			Written by Rob van der Woude
  437. 			http://www.robvanderwoude.com
  438. 			 */
  439.  
  440. 			#endregion Help Text
  441.  
  442.  
  443. 			#region Display Help
  444.  
  445. 			Console.Error.WriteLine( );
  446.  
  447. 			Console.Error.WriteLine( "RxReplace,  Version {0}", progver );
  448.  
  449. 			Console.Error.WriteLine( "Multi-line regex find and replace tool" );
  450.  
  451. 			Console.Error.WriteLine( );
  452.  
  453. 			Console.Error.Write( "Usage:   " );
  454. 			Console.ForegroundColor = ConsoleColor.White;
  455. 			Console.Error.WriteLine( "RXREPLACE  filename  pattern  replacement  [ options ]" );
  456. 			Console.ResetColor( );
  457.  
  458. 			Console.Error.Write( "or:      " );
  459. 			Console.ForegroundColor = ConsoleColor.White;
  460. 			Console.Error.WriteLine( "some_command  |  RXREPLACE  pattern  replacement  [ options ]" );
  461. 			Console.ResetColor( );
  462.  
  463. 			Console.Error.WriteLine( );
  464.  
  465. 			Console.Error.Write( "Where:   " );
  466. 			Console.ForegroundColor = ConsoleColor.White;
  467. 			Console.Error.Write( "filename" );
  468. 			Console.ResetColor( );
  469. 			Console.Error.WriteLine( "       is the file to be filtered" );
  470.  
  471. 			Console.ForegroundColor = ConsoleColor.White;
  472. 			Console.Error.Write( "         some_command" );
  473. 			Console.ResetColor( );
  474. 			Console.Error.WriteLine( "   is the command whose standard output is to be filtered" );
  475.  
  476. 			Console.ForegroundColor = ConsoleColor.White;
  477. 			Console.Error.Write( "         pattern" );
  478. 			Console.ResetColor( );
  479. 			Console.Error.WriteLine( "        is the regex pattern for text to be replaced" );
  480.  
  481. 			Console.ForegroundColor = ConsoleColor.White;
  482. 			Console.Error.Write( "         replacement" );
  483. 			Console.ResetColor( );
  484. 			Console.Error.WriteLine( "    replaces all matches (backreferences allowed, e.g. $1)" );
  485.  
  486. 			Console.Error.WriteLine( );
  487.  
  488. 			Console.Error.Write( "Options: " );
  489. 			Console.ForegroundColor = ConsoleColor.White;
  490. 			Console.Error.Write( "/F:bytes" );
  491. 			Console.ResetColor( );
  492. 			Console.Error.Write( "       search the " );
  493. 			Console.ForegroundColor = ConsoleColor.White;
  494. 			Console.Error.Write( "F" );
  495. 			Console.ResetColor( );
  496. 			Console.Error.Write( "irst specified number of " );
  497. 			Console.ForegroundColor = ConsoleColor.White;
  498. 			Console.Error.Write( "bytes" );
  499. 			Console.ResetColor( );
  500. 			Console.Error.WriteLine( " only" );
  501.  
  502. 			Console.ForegroundColor = ConsoleColor.White;
  503. 			Console.Error.Write( "         /I" );
  504. 			Console.ResetColor( );
  505. 			Console.Error.Write( "             makes the search case " );
  506. 			Console.ForegroundColor = ConsoleColor.White;
  507. 			Console.Error.Write( "I" );
  508. 			Console.ResetColor( );
  509. 			Console.Error.WriteLine( "nsensitive" );
  510.  
  511. 			Console.ForegroundColor = ConsoleColor.White;
  512. 			Console.Error.Write( "         /L" );
  513. 			Console.ResetColor( );
  514. 			Console.Error.Write( "             treat " );
  515. 			Console.ForegroundColor = ConsoleColor.White;
  516. 			Console.Error.Write( "replacement" );
  517. 			Console.ResetColor( );
  518. 			Console.Error.Write( " as " );
  519. 			Console.ForegroundColor = ConsoleColor.White;
  520. 			Console.Error.Write( "L" );
  521. 			Console.ResetColor( );
  522. 			Console.Error.WriteLine( "iteral text" );
  523.  
  524. 			Console.Error.Write( "                        (default: unescape " );
  525. 			Console.ForegroundColor = ConsoleColor.White;
  526. 			Console.Error.Write( "replacement" );
  527. 			Console.ResetColor( );
  528. 			Console.Error.WriteLine( ")" );
  529.  
  530. 			Console.ForegroundColor = ConsoleColor.White;
  531. 			Console.Error.Write( "         /O[:newfile]   O" );
  532. 			Console.ResetColor( );
  533. 			Console.Error.Write( "verwrite original, or write " );
  534. 			Console.ForegroundColor = ConsoleColor.White;
  535. 			Console.Error.Write( "O" );
  536. 			Console.ResetColor( );
  537. 			Console.Error.Write( "utput to " );
  538. 			Console.ForegroundColor = ConsoleColor.White;
  539. 			Console.Error.WriteLine( "newfile" );
  540. 			Console.ResetColor( );
  541.  
  542. 			Console.ForegroundColor = ConsoleColor.White;
  543. 			Console.Error.Write( "         /S:nn          S" );
  544. 			Console.ResetColor( );
  545. 			Console.Error.Write( "kip the first " );
  546. 			Console.ForegroundColor = ConsoleColor.White;
  547. 			Console.Error.Write( "nn" );
  548. 			Console.ResetColor( );
  549. 			Console.Error.WriteLine( " matches" );
  550.  
  551. 			Console.ForegroundColor = ConsoleColor.White;
  552. 			Console.Error.Write( "         /T:nn          T" );
  553. 			Console.ResetColor( );
  554. 			Console.Error.Write( "ake only " );
  555. 			Console.ForegroundColor = ConsoleColor.White;
  556. 			Console.Error.Write( "nn" );
  557. 			Console.ResetColor( );
  558. 			Console.Error.WriteLine( " matches" );
  559.  
  560. 			Console.Error.WriteLine( );
  561.  
  562. 			Console.Error.Write( "Notes:   If " );
  563. 			Console.ForegroundColor = ConsoleColor.White;
  564. 			Console.Error.Write( "/F:bytes" );
  565. 			Console.ResetColor( );
  566. 			Console.Error.Write( " is used and a file is specified, only the first " );
  567. 			Console.ForegroundColor = ConsoleColor.White;
  568. 			Console.Error.WriteLine( "bytes" );
  569. 			Console.ResetColor( );
  570.  
  571. 			Console.Error.WriteLine( "         of that file will be read; if the input is redirected, it is read" );
  572.  
  573. 			Console.Error.Write( "         entirely, and will then be chopped to the specified number of " );
  574. 			Console.ForegroundColor = ConsoleColor.White;
  575. 			Console.Error.WriteLine( "bytes" );
  576. 			Console.ResetColor( );
  577.  
  578. 			Console.Error.WriteLine( "         before being searched. In both cases, the remainder of the input will" );
  579.  
  580. 			Console.Error.WriteLine( "         be discarded." );
  581.  
  582. 			Console.Error.Write( "         Unless " );
  583. 			Console.ForegroundColor = ConsoleColor.White;
  584. 			Console.Error.Write( "/O" );
  585. 			Console.ResetColor( );
  586. 			Console.Error.WriteLine( " switch is used, result will be written to Standard Output." );
  587.  
  588. 			Console.Error.Write( "         Backreferences in " );
  589. 			Console.ForegroundColor = ConsoleColor.White;
  590. 			Console.Error.Write( "replacement" );
  591. 			Console.ResetColor( );
  592. 			Console.Error.Write( " can " );
  593. 			Console.ForegroundColor = ConsoleColor.White;
  594. 			Console.Error.Write( "not" );
  595. 			Console.ResetColor( );
  596. 			Console.Error.Write( " be used with " );
  597. 			Console.ForegroundColor = ConsoleColor.White;
  598. 			Console.Error.Write( "/S" );
  599. 			Console.ResetColor( );
  600. 			Console.Error.Write( " or " );
  601. 			Console.ForegroundColor = ConsoleColor.White;
  602. 			Console.Error.Write( "/T" );
  603. 			Console.ResetColor( );
  604. 			Console.Error.WriteLine( "." );
  605.  
  606. 			Console.Error.WriteLine( );
  607.  
  608. 			Console.Error.WriteLine( "Credits: Check for redirection by Hans Passant on StackOverflow.com:" );
  609.  
  610. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  611. 			Console.Error.WriteLine( "         http://stackoverflow.com/a/3453272" );
  612. 			Console.ResetColor( );
  613.  
  614. 			Console.Error.WriteLine( "         Array Slice extension by Sam Allen on DotNetPerls.com:" );
  615.  
  616. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  617. 			Console.Error.WriteLine( "         http://www.dotnetperls.com/array-slice" );
  618. 			Console.ResetColor( );
  619.  
  620. 			Console.Error.WriteLine( "         Unescaping Unicode by \"dtb\" on StackOverflow.com:" );
  621.  
  622. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  623. 			Console.Error.WriteLine( "         http://stackoverflow.com/a/8558748" );
  624. 			Console.ResetColor( );
  625.  
  626. 			Console.Error.WriteLine( );
  627.  
  628. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  629.  
  630. 			Console.Error.WriteLine( "http://www.robvanderwoude.com" );
  631.  
  632. 			#endregion Display Help
  633.  
  634.  
  635. 			return 1;
  636. 		}
  637.  
  638. 		#endregion Error Handling
  639. 	}
  640.  
  641.  
  642. 	#region Extensions
  643.  
  644. 	// Array Slice
  645. 	// http://www.dotnetperls.com/array-slice
  646. 	public static class Extensions
  647. 	{
  648. 		/// <summary>
  649. 		/// Get the array slice between the two indexes.
  650. 		/// ... Inclusive for start index, exclusive for end index.
  651. 		/// </summary>
  652. 		public static T[] Slice<T>( this T[] source, int start, int end )
  653. 		{
  654. 			// Handles negative ends.
  655. 			if ( end < 0 )
  656. 			{
  657. 				end = source.Length + end;
  658. 			}
  659. 			int len = end - start;
  660.  
  661. 			// Return new array.
  662. 			T[] res = new T[len];
  663. 			for ( int i = 0; i < len; i++ )
  664. 			{
  665. 				res[i] = source[i + start];
  666. 			}
  667. 			return res;
  668. 		}
  669. 	}
  670.  
  671. 	#endregion Extensions
  672. }
  673.  

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