Powered by GeSHi

Source code for readline.cs

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

  1. using System;
  2. using System.IO;
  3. using System.Runtime.InteropServices;
  4. using System.Text.RegularExpressions;
  5. using System.Collections.Generic;
  6.  
  7. namespace RobvanderWoude
  8. {
  9. 	class ReadLine
  10. 	{
  11. 		static int Main( string[] args )
  12. 		{
  13. 			#region Command Line Parsing
  14.  
  15. 			string filename = string.Empty;
  16. 			int linestart = 1;
  17. 			int lineend = 2;
  18. 			bool concat = false;
  19. 			bool addspaces = false;
  20. 			string concatchar = string.Empty;
  21. 			bool skipempty = false;
  22. 			bool trimlines = false;
  23. 			bool numlines = false;
  24. 			bool redirected;
  25. 			bool set_c = false;
  26. 			bool set_l = false;
  27. 			bool set_s = false;
  28. 			bool set_t = false;
  29. 			bool set_input = false;
  30.  
  31. 			if ( ConsoleEx.InputRedirected )
  32. 			{
  33. 				set_input = true;
  34. 				redirected = true;
  35. 			}
  36. 			else
  37. 			{
  38. 				if ( args.Length == 0 )
  39. 				{
  40. 					return WriteError( );
  41. 				}
  42. 				redirected = false;
  43. 			}
  44.  
  45. 			foreach ( string arg in args )
  46. 			{
  47. 				if ( arg[0] == '/' )
  48. 				{
  49. 					try
  50. 					{
  51. 						switch ( arg.ToUpper( )[1] )
  52. 						{
  53. 							case '?':
  54. 								return WriteError( );
  55. 							case 'C':
  56. 								if ( arg.ToUpper( ) != "/C" && arg.ToUpper( ) != "/CS" )
  57. 								{
  58. 									return WriteError( "Invalid command line switch " + arg );
  59. 								}
  60. 								concat = true;
  61. 								if ( arg.ToUpper( ) == "/CS" )
  62. 								{
  63. 									addspaces = true;
  64. 								}
  65. 								if ( set_c )
  66. 								{
  67. 									return WriteError( "Duplicate command line argument /C*" );
  68. 								}
  69. 								set_c = true;
  70. 								break;
  71. 							case 'L':
  72. 								if ( arg.ToUpper( ).StartsWith( "/L:" ) && arg.Length > 3 )
  73. 								{
  74. 									if ( arg[2] == ':' )
  75. 									{
  76. 										string linessel = arg.Substring( 3 );
  77. 										string pattern = @"^(\-?\d+)$";
  78. 										Match match = Regex.Match( linessel, pattern );
  79. 										if ( match.Success )
  80. 										{
  81. 											linestart = Convert.ToInt32( match.Groups[1].Value );
  82. 											lineend = linestart + 1;
  83. 										}
  84. 										else
  85. 										{
  86. 											pattern = @"^(\-?\d+)\.\.(\-?\d+)$";
  87. 											match = Regex.Match( linessel, pattern );
  88. 											if ( match.Success )
  89. 											{
  90. 												linestart = Convert.ToInt32( match.Groups[1].Value );
  91. 												lineend = Convert.ToInt32( match.Groups[2].Value ) + 1;
  92. 											}
  93. 											else
  94. 											{
  95. 												pattern = @"^(\-?\d+),(\-?\d+)$";
  96. 												match = Regex.Match( linessel, pattern );
  97. 												if ( match.Success )
  98. 												{
  99. 													// numlines is true if the second number specifies the number of lines instead of a line number
  100. 													numlines = true;
  101. 													linestart = Convert.ToInt32( match.Groups[1].Value );
  102. 													lineend = Convert.ToInt32( match.Groups[2].Value );
  103. 													if ( lineend < 1 )
  104. 													{
  105. 														return WriteError( "Invalid number of lines (" + lineend.ToString( ) + "), must be 1 or higher" );
  106. 													}
  107. 												}
  108. 											}
  109. 										}
  110. 									}
  111. 									else
  112. 									{
  113. 										return WriteError( "Invalid command line switch " + arg );
  114. 									}
  115. 								}
  116. 								else
  117. 								{
  118. 									return WriteError( "Invalid command line switch " + arg );
  119. 								}
  120. 								if ( set_l )
  121. 								{
  122. 									return WriteError( "Duplicate command line argument /L" );
  123. 								}
  124. 								set_l = true;
  125. 								break;
  126. 							case 'S':
  127. 								if ( arg.ToUpper( ) != "/SE" )
  128. 								{
  129. 									return WriteError( "Invalid command line switch " + arg );
  130. 								}
  131. 								skipempty = true;
  132. 								if ( set_s )
  133. 								{
  134. 									return WriteError( "Duplicate command line argument /SE" );
  135. 								}
  136. 								set_s = true;
  137. 								break;
  138. 							case 'T':
  139. 								if ( arg.ToUpper( ) != "/T" )
  140. 								{
  141. 									return WriteError( "Invalid command line switch " + arg );
  142. 								}
  143. 								trimlines = true;
  144. 								if ( set_t )
  145. 								{
  146. 									return WriteError( "Duplicate command line argument /T" );
  147. 								}
  148. 								set_t = true;
  149. 								break;
  150. 							default:
  151. 								return WriteError( "Invalid command line switch " + arg );
  152. 						}
  153. 					}
  154. 					catch
  155. 					{
  156. 						return WriteError( "Invalid command line switch " + arg );
  157. 					}
  158. 				}
  159. 				else
  160. 				{
  161. 					if ( set_input )
  162. 					{
  163. 						return WriteError( "Multiple inputs specified (file + redirection or multiple files)" );
  164. 					}
  165. 					if ( redirected )
  166. 					{
  167. 						return WriteError( "Do not specify a file name when using redirected input" );
  168. 					}
  169. 					else
  170. 					{
  171. 						filename = arg;
  172. 					}
  173. 				}
  174. 			}
  175.  
  176. 			#endregion
  177.  
  178. 			try
  179. 			{
  180. 				int count = 0;
  181. 				bool output = false;
  182. 				string[] lines;
  183. 				List<string> alllines = new List<string>( );
  184.  
  185. 				if ( redirected )
  186. 				{
  187. 					// Read standard input and store the lines in a list
  188. 					int peek = 0;
  189. 					do
  190. 					{
  191. 						alllines.Add( Console.In.ReadLine( ) );
  192. 					} while ( peek != -1 );
  193. 					// Convert the list to an array
  194. 					lines = alllines.ToArray( );
  195. 				}
  196. 				else
  197. 				{
  198. 					// Read the file and store the lines in a list
  199. 					lines = File.ReadAllLines( filename );
  200. 				}
  201.  
  202. 				// Check if negative numbers were used, and if so, calculate the resulting line numbers
  203. 				if ( linestart < 0 )
  204. 				{
  205. 					linestart += lines.Length + 1;
  206. 				}
  207. 				if ( lineend < 0 )
  208. 				{
  209. 					lineend += lines.Length + 1;
  210. 				}
  211. 				if ( numlines )
  212. 				{
  213. 					lineend += linestart;
  214. 				}
  215.  
  216. 				// Iterate through the array of lines and display the ones matching the command line switches
  217. 				foreach ( string line in lines )
  218. 				{
  219. 					string myline = line;
  220. 					if ( trimlines )
  221. 					{
  222. 						myline = myline.Trim( );
  223. 					}
  224. 					bool skip = skipempty && ( myline.Trim( ) == string.Empty );
  225. 					if ( !skip )
  226. 					{
  227. 						count += 1;
  228. 						if ( count >= linestart && count < lineend )
  229. 						{
  230. 							if ( concat )
  231. 							{
  232. 								Console.Write( "{0}{1}", concatchar, myline );
  233. 							}
  234. 							else
  235. 							{
  236. 								Console.WriteLine( myline );
  237. 							}
  238. 							if ( addspaces )
  239. 							{
  240. 								concatchar = " ";
  241. 							}
  242. 						}
  243. 					}
  244. 				}
  245. 			}
  246. 			catch ( Exception e )
  247. 			{
  248. 				return WriteError( e.Message );
  249. 			}
  250.  
  251. 			return 0;
  252. 		}
  253.  
  254. 		#region Redirection Detection
  255.  
  256. 		// Code to detect redirection by Hans Passant on StackOverflow.com
  257. 		// http://stackoverflow.com/questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected
  258. 		public static class ConsoleEx
  259. 		{
  260. 			public static bool OutputRedirected
  261. 			{
  262. 				get
  263. 				{
  264. 					return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stdout ) );
  265. 				}
  266. 			}
  267.  
  268. 			public static bool InputRedirected
  269. 			{
  270. 				get
  271. 				{
  272. 					return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stdin ) );
  273. 				}
  274. 			}
  275.  
  276. 			public static bool ErrorRedirected
  277. 			{
  278. 				get
  279. 				{
  280. 					return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stderr ) );
  281. 				}
  282. 			}
  283.  
  284. 			// P/Invoke:
  285. 			private enum FileType { Unknown, Disk, Char, Pipe };
  286. 			private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
  287.  
  288. 			[DllImport( "kernel32.dll" )]
  289. 			private static extern FileType GetFileType( IntPtr hdl );
  290.  
  291. 			[DllImport( "kernel32.dll" )]
  292. 			private static extern IntPtr GetStdHandle( StdHandle std );
  293. 		}
  294.  
  295. 		#endregion
  296.  
  297. 		#region Error Handling
  298.  
  299. 		public static int WriteError( Exception e = null )
  300. 		{
  301. 			return WriteError( e == null ? null : e.Message );
  302. 		}
  303.  
  304. 		public static int WriteError( string errorMessage )
  305. 		{
  306. 			if ( string.IsNullOrEmpty( errorMessage ) == false )
  307. 			{
  308. 				Console.Error.WriteLine( );
  309. 				Console.ForegroundColor = ConsoleColor.Red;
  310. 				Console.Error.Write( "ERROR: " );
  311. 				Console.ForegroundColor = ConsoleColor.White;
  312. 				Console.Error.WriteLine( errorMessage );
  313. 				Console.ResetColor( );
  314. 			}
  315.  
  316. 			/*
  317. 			ReadLine,  Version 0.30 beta
  318. 			Return the specified line(s) from a file or Standard Input
  319.  
  320. 			Usage:   READLINE  filename  [ options ]
  321. 			   or:   READLINE  [ options ]  <  filename
  322. 			   or:   command  |  READLINE  [ options ]
  323.  
  324. 			Where:   filename   is the optional file to be read
  325. 					 command    is the optional command whose output is to be read
  326.  
  327. 			Options: /C         Concatenate lines
  328. 					 /CS        Concatenate lines with Spaces in between
  329. 					 /L:n       read line n
  330. 					 /L:n..m    read lines n through m
  331. 					 /L:n,m     read m lines starting at line n
  332. 								(negative numbers start counting from the end backwards)
  333. 					 /SE        Skip Empty lines
  334. 			         /T         Trim leading and trailing whitespace from lines
  335.  
  336. 			Examples:
  337. 			READLINE  file                        read the first non-empty line (default)
  338. 			READLINE  file  /L:2  /SE             read the second non-empty line of file
  339. 			READLINE  file  /L:5..7               read lines 5..7 of file
  340. 			READLINE  file  /L:-1                 read the last line of file
  341. 			READLINE  file  /L:-2..-1             read the last 2 lines of file
  342. 			READLINE  file  /L:-2,2               read the last 2 lines of file
  343.  
  344. 			Check for redirection by Hans Passant on StackOverflow.com
  345. 			/questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected
  346.  
  347. 			Written by Rob van der Woude
  348. 			http://www.robvanderwoude.com
  349. 			*/
  350.  
  351. 			Console.Error.WriteLine( );
  352. 			Console.Error.WriteLine( "ReadLine,  Version 0.30 beta" );
  353. 			Console.Error.WriteLine( "Return the specified line(s) from a file or Standard Input" );
  354. 			Console.Error.WriteLine( );
  355. 			Console.Error.Write( "Usage:   " );
  356. 			Console.ForegroundColor = ConsoleColor.White;
  357. 			Console.Error.WriteLine( "READLINE  filename  [ options ]" );
  358. 			Console.ResetColor( );
  359. 			Console.Error.Write( "   or:   " );
  360. 			Console.ForegroundColor = ConsoleColor.White;
  361. 			Console.Error.WriteLine( "READLINE  [ options ]  <  filename" );
  362. 			Console.ResetColor( );
  363. 			Console.Error.Write( "   or:   " );
  364. 			Console.ForegroundColor = ConsoleColor.White;
  365. 			Console.Error.WriteLine( "command  |  READLINE  [ options ]" );
  366. 			Console.ResetColor( );
  367. 			Console.Error.WriteLine( );
  368. 			Console.Error.Write( "Where:   " );
  369. 			Console.ForegroundColor = ConsoleColor.White;
  370. 			Console.Error.Write( "filename" );
  371. 			Console.ResetColor( );
  372. 			Console.Error.WriteLine( "   is the optional file to be read" );
  373. 			Console.ForegroundColor = ConsoleColor.White;
  374. 			Console.Error.Write( "         command" );
  375. 			Console.ResetColor( );
  376. 			Console.Error.WriteLine( "    is the optional command whose output is to be read" );
  377. 			Console.Error.WriteLine( );
  378. 			Console.Error.Write( "Options: " );
  379. 			Console.ForegroundColor = ConsoleColor.White;
  380. 			Console.Error.Write( "/C         C" );
  381. 			Console.ResetColor( );
  382. 			Console.Error.WriteLine( "oncatenate lines" );
  383. 			Console.ForegroundColor = ConsoleColor.White;
  384. 			Console.Error.Write( "         /CS        C" );
  385. 			Console.ResetColor( );
  386. 			Console.Error.Write( "oncatenate lines with " );
  387. 			Console.ForegroundColor = ConsoleColor.White;
  388. 			Console.Error.Write( "S" );
  389. 			Console.ResetColor( );
  390. 			Console.Error.WriteLine( "paces in between" );
  391. 			Console.ForegroundColor = ConsoleColor.White;
  392. 			Console.Error.Write( "         /L:n" );
  393. 			Console.ResetColor( );
  394. 			Console.Error.Write( "       read line " );
  395. 			Console.ForegroundColor = ConsoleColor.White;
  396. 			Console.Error.WriteLine( "n" );
  397. 			Console.ResetColor( );
  398. 			Console.ForegroundColor = ConsoleColor.White;
  399. 			Console.Error.Write( "         /L:n..m" );
  400. 			Console.ResetColor( );
  401. 			Console.Error.Write( "    read lines " );
  402. 			Console.ForegroundColor = ConsoleColor.White;
  403. 			Console.Error.Write( "n" );
  404. 			Console.ResetColor( );
  405. 			Console.Error.Write( " through " );
  406. 			Console.ForegroundColor = ConsoleColor.White;
  407. 			Console.Error.WriteLine( "m" );
  408. 			Console.Error.Write( "         /L:n,m" );
  409. 			Console.ResetColor( );
  410. 			Console.Error.Write( "     read " );
  411. 			Console.ForegroundColor = ConsoleColor.White;
  412. 			Console.Error.Write( "m" );
  413. 			Console.ResetColor( );
  414. 			Console.Error.Write( " lines starting at line " );
  415. 			Console.ForegroundColor = ConsoleColor.White;
  416. 			Console.Error.WriteLine( "n" );
  417. 			Console.ResetColor( );
  418. 			Console.Error.WriteLine( "                    (negative numbers start counting from the end backwards)" );
  419. 			Console.ForegroundColor = ConsoleColor.White;
  420. 			Console.Error.Write( "         /SE        S" );
  421. 			Console.ResetColor( );
  422. 			Console.Error.Write( "kip " );
  423. 			Console.ForegroundColor = ConsoleColor.White;
  424. 			Console.Error.Write( "E" );
  425. 			Console.ResetColor( );
  426. 			Console.Error.WriteLine( "mpty lines" );
  427. 			Console.ForegroundColor = ConsoleColor.White;
  428. 			Console.Error.Write( "         /T         T" );
  429. 			Console.ResetColor( );
  430. 			Console.Error.WriteLine( "rim leading and trailing whitespace from lines" );
  431. 			Console.Error.WriteLine( );
  432. 			Console.Error.WriteLine( "Examples:" );
  433. 			Console.Error.WriteLine( "READLINE  file                        read the first non-empty line (default)" );
  434. 			Console.Error.WriteLine( "READLINE  file  /L:2  /SE             read the second non-empty line of file" );
  435. 			Console.Error.WriteLine( "READLINE  file  /L:5..7               read lines 5..7 of file" );
  436. 			Console.Error.WriteLine( "READLINE  file  /L:-1                 read the last line of file" );
  437. 			Console.Error.WriteLine( "READLINE  file  /L:-2..-1             read the last 2 lines of file" );
  438. 			Console.Error.WriteLine( "READLINE  file  /L:-2,2               read the last 2 lines of file" );
  439. 			Console.Error.WriteLine( );
  440. 			Console.Error.Write( "Check for redirection by Hans Passant on " );
  441. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  442. 			Console.Error.WriteLine( "StackOverflow.com" );
  443. 			Console.Error.WriteLine( "/questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected" );
  444. 			Console.ResetColor( );
  445. 			Console.Error.WriteLine( );
  446. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  447. 			Console.Error.WriteLine( "http://www.robvanderwoude.com" );
  448. 			return 1;
  449. 		}
  450.  
  451. 		#endregion
  452.  
  453. 	}
  454. }
  455.