Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for checkvarsvbs.cs

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6.  
  7.  
  8. namespace RobvanderWoude
  9. {
  10. 	class CheckVarsVBS
  11. 	{
  12. 		static string progver = "1.01";
  13.  
  14.  
  15. 		static int Main( string[] args )
  16. 		{
  17. 			#region Initialize Variables
  18.  
  19. 			int rc = 0;
  20. 			SortedList<string, int> subroutines = new SortedList<string, int>( );
  21. 			SortedList<string, int> variables = new SortedList<string, int>( );
  22. 			bool htawindowevents = false;
  23. 			bool showsubs = true;
  24. 			bool showvars = true;
  25. 			bool unusedonly = false;
  26. 			string scriptcode = String.Empty;
  27. 			string scriptext = String.Empty;
  28. 			string scriptfile = String.Empty;
  29. 			int columnwidth = 12;
  30. 			int unusedsubs = 0;
  31. 			int unusedvars = 0;
  32. 			List<string> ignoredsubs = new List<string>( )
  33. 			{
  34. 				"window_onbeforeunload",
  35. 				"window_onblur",
  36. 				"window_onfocus",
  37. 				"window_onhelp",
  38. 				"window_onload",
  39. 				"window_onresize",
  40. 				"window_onunload"
  41. 			};
  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. 			foreach ( string arg in args )
  54. 			{
  55. 				if ( arg[0] == '/' )
  56. 				{
  57. 					if ( arg.ToUpper( ) == "/?" )
  58. 					{
  59. 						return ShowHelp( );
  60. 					}
  61. 					else if ( arg.ToUpper( ) == "/S" )
  62. 					{
  63. 						if ( !showvars )
  64. 						{
  65. 							return ShowHelp( "Duplicate command line switch /S" );
  66. 						}
  67. 						if ( !showsubs )
  68. 						{
  69. 							return ShowHelp( "Use /S or /V or neither, but not both" );
  70. 						}
  71. 						showvars = false;
  72. 					}
  73. 					else if ( arg.ToUpper( ) == "/U" )
  74. 					{
  75. 						if ( unusedonly )
  76. 						{
  77. 							return ShowHelp( "Duplicate command line switch /U" );
  78. 						}
  79. 						unusedonly = true;
  80. 					}
  81. 					else if ( arg.ToUpper( ) == "/V" )
  82. 					{
  83. 						if ( !showsubs )
  84. 						{
  85. 							return ShowHelp( "Duplicate command line switch /V" );
  86. 						}
  87. 						if ( !showvars )
  88. 						{
  89. 							return ShowHelp( "Use /S or /V or neither, but not both" );
  90. 						}
  91. 						showsubs = false;
  92. 					}
  93. 					else if ( arg.ToUpper( ) == "/W" )
  94. 					{
  95. 						if ( htawindowevents )
  96. 						{
  97. 							return ShowHelp( "Duplicate command line switch /W" );
  98. 						}
  99. 						htawindowevents = true;
  100. 					}
  101. 					else
  102. 					{
  103. 						return ShowHelp( "Invalid command line switch \"{0}\"", arg );
  104. 					}
  105. 				}
  106. 				else
  107. 				{
  108. 					if ( !String.IsNullOrWhiteSpace( scriptfile ) )
  109. 					{
  110. 						return ShowHelp( "Duplicate command line argument for VBScript file" );
  111. 					}
  112. 					if ( !File.Exists( arg ) )
  113. 					{
  114. 						return ShowHelp( "Invalid file name or file not found: \"{0}\"", arg );
  115. 					}
  116. 					scriptext = Path.GetExtension( arg ).ToLower( );
  117. 					if ( scriptext != ".hta" && scriptext != ".vbs" )
  118. 					{
  119. 						return ShowHelp( "Invalid file type \"{0}\"", arg );
  120. 					}
  121. 					scriptfile = Path.GetFullPath( arg );
  122. 				}
  123.  
  124. 			}
  125.  
  126. 			if ( String.IsNullOrWhiteSpace( scriptfile ) )
  127. 			{
  128. 				return ShowHelp( "Please specify a source file" );
  129. 			}
  130.  
  131. 			#endregion Command Line Parsing
  132.  
  133.  
  134. 			#region Read File
  135.  
  136. 			// Read the code from the file
  137. 			scriptcode = File.ReadAllText( scriptfile, Encoding.UTF8 );
  138. 			// Remove comment lines from the code (does NOT strip comments starting halfway on a line)
  139. 			string pattern = @"(^|\n|\r)[ \t]*'[^\n\r]+";
  140. 			Regex regex = new Regex( pattern );
  141. 			scriptcode = regex.Replace( scriptcode, String.Empty );
  142.  
  143.  
  144. 			#endregion Read File
  145.  
  146.  
  147. 			#region List Subroutines
  148.  
  149. 			// Create a list of subroutines found in the code
  150. 			if ( showsubs )
  151. 			{
  152. 				pattern = @"(?:^|\n|\r)[ \t]*(?:Sub|Function)[ \t]+([A-Z][^\s\(]+)";
  153. 				regex = new Regex( pattern, RegexOptions.IgnoreCase );
  154. 				if ( regex.IsMatch( scriptcode ) )
  155. 				{
  156. 					MatchCollection matches = regex.Matches( scriptcode );
  157. 					if ( matches.Count > 0 )
  158. 					{
  159. 						foreach ( Match match in matches )
  160. 						{
  161. 							bool listed = false;
  162. 							string sub = match.Groups[1].ToString( );
  163. 							foreach ( string key in subroutines.Keys )
  164. 							{
  165. 								if ( sub.ToLower( ) == key.ToLower( ) )
  166. 								{
  167. 									listed = true;
  168. 								}
  169. 							}
  170. 							if ( !listed )
  171. 							{
  172. 								subroutines[sub] = 0;
  173. 								if ( sub.Length > columnwidth )
  174. 								{
  175. 									columnwidth = sub.Length;
  176. 								}
  177. 							}
  178. 						}
  179. 					}
  180. 				}
  181. 			}
  182.  
  183. 			#endregion List Subroutines
  184.  
  185.  
  186. 			#region List Variables
  187.  
  188. 			// Create a list of variables found in the code
  189. 			if ( showvars )
  190. 			{
  191. 				pattern = @"(?:^|\n|\r)[ \t]*Dim[ \t]+([A-Z][^\n\r:]+)";
  192. 				regex = new Regex( pattern, RegexOptions.IgnoreCase );
  193. 				if ( regex.IsMatch( scriptcode ) )
  194. 				{
  195. 					MatchCollection matches = regex.Matches( scriptcode );
  196. 					if ( matches.Count > 0 )
  197. 					{
  198. 						foreach ( Match match in matches )
  199. 						{
  200. 							string[] vars = match.Groups[1].ToString( ).Split( ", ()".ToCharArray( ), StringSplitOptions.RemoveEmptyEntries );
  201. 							foreach ( string var in vars )
  202. 							{
  203. 								bool listed = false;
  204. 								foreach ( string key in subroutines.Keys )
  205. 								{
  206. 									if ( var.ToLower( ) == key.ToLower( ) )
  207. 									{
  208. 										listed = true;
  209. 									}
  210. 								}
  211. 								if ( !listed )
  212. 								{
  213. 									variables[var] = 0;
  214. 									if ( var.Length > columnwidth )
  215. 									{
  216. 										columnwidth = var.Length;
  217. 									}
  218. 								}
  219. 							}
  220. 						}
  221. 					}
  222. 				}
  223. 			}
  224.  
  225. 			#endregion List Variables
  226.  
  227.  
  228. 			#region Count and Display Subroutines Usage
  229.  
  230. 			// Iterate through the list of subroutines and count the occurences of its name
  231. 			if ( showsubs )
  232. 			{
  233. 				List<string> keys = new List<string>( subroutines.Keys );
  234. 				foreach ( string sub in keys )
  235. 				{
  236. 					bool ignorethissub = !htawindowevents && scriptext == ".hta" && ignoredsubs.Contains( sub.ToLower( ) );
  237. 					if ( !ignorethissub )
  238. 					{
  239. 						pattern = String.Format( @"\b{0}\b", sub );
  240. 						regex = new Regex( pattern, RegexOptions.IgnoreCase );
  241. 						if ( regex.IsMatch( scriptcode ) )
  242. 						{
  243. 							subroutines[sub] = regex.Matches( scriptcode ).Count - 1;
  244. 							if ( subroutines[sub] == 0 )
  245. 							{
  246. 								unusedsubs += 1;
  247. 							}
  248. 						}
  249. 					}
  250. 				}
  251. 				// Show the results
  252. 				if ( unusedonly )
  253. 				{
  254. 					Console.WriteLine( "{0} Unused Subroutine{1}{2}", unusedsubs, ( unusedsubs == 1 ? String.Empty : "s" ), ( unusedsubs == 0 ? String.Empty : ":" ) );
  255. 					Console.WriteLine( "{0}=================={1}{2}", new String( '=', unusedsubs.ToString( ).Length ), ( unusedsubs == 1 ? String.Empty : "=" ), ( unusedsubs == 0 ? String.Empty : "=" ) );
  256.  
  257. 				}
  258. 				else
  259. 				{
  260. 					Console.WriteLine( "{0,-" + columnwidth + "}    Occurences:", "Subroutine:" );
  261. 					Console.WriteLine( "{0,-" + columnwidth + "}    ===========", "===========" );
  262. 				}
  263. 				foreach ( string key in subroutines.Keys )
  264. 				{
  265. 					bool ignorethissub = !htawindowevents && scriptext == ".hta" && ignoredsubs.Contains( key.ToLower( ) );
  266. 					if ( subroutines[key] == 0 )
  267. 					{
  268. 						if ( unusedonly )
  269. 						{
  270. 							if ( !ignorethissub )
  271. 							{
  272. 								Console.WriteLine( key );
  273. 							}
  274. 						}
  275. 						else
  276. 						{
  277. 							if ( ignorethissub )
  278. 							{
  279. 								Console.WriteLine( "{0,-" + columnwidth + "}    {1}", key, subroutines[key] );
  280. 							}
  281. 							else
  282. 							{
  283. 								RedLine( String.Format( "{0,-" + columnwidth + "}    {1}", key, subroutines[key] ) );
  284. 							}
  285. 						}
  286. 						rc += 1;
  287. 					}
  288. 					else if ( !unusedonly )
  289. 					{
  290. 						Console.WriteLine( "{0,-" + columnwidth + "}    {1}", key, subroutines[key] );
  291. 					}
  292. 				}
  293. 				Console.WriteLine( );
  294. 			}
  295.  
  296. 			#endregion Count and Display Subroutines Usage
  297.  
  298.  
  299. 			#region Count and Display Variables Usage
  300.  
  301. 			// Iterate through the list of variables and count the occurences of its name
  302. 			if ( showvars )
  303. 			{
  304. 				List<string> keys = new List<string>( variables.Keys );
  305. 				foreach ( string variable in keys )
  306. 				{
  307. 					pattern = String.Format( @"\b{0}\b", variable );
  308. 					regex = new Regex( pattern, RegexOptions.IgnoreCase );
  309. 					if ( regex.IsMatch( scriptcode ) )
  310. 					{
  311. 						variables[variable] = regex.Matches( scriptcode ).Count - 1;
  312. 						if ( variables[variable] == 0 )
  313. 						{
  314. 							unusedvars += 1;
  315. 						}
  316. 					}
  317. 				}
  318. 				// Show the results
  319. 				if ( unusedonly )
  320. 				{
  321. 					Console.WriteLine( "{0} Unused Variable{1}{2}", unusedvars, ( unusedvars == 1 ? String.Empty : "s" ), ( unusedvars == 0 ? String.Empty : ":" ) );
  322. 					Console.WriteLine( "{0}================{1}{2}", new String( '=', unusedvars.ToString( ).Length ), ( unusedvars == 1 ? String.Empty : "=" ), ( unusedvars == 0 ? String.Empty : "=" ) );
  323. 				}
  324. 				else
  325. 				{
  326. 					Console.WriteLine( "{0,-" + columnwidth + "}    Occurences:", "Variable:" );
  327. 					Console.WriteLine( "{0,-" + columnwidth + "}    ===========", "=========" );
  328. 				}
  329. 				foreach ( string key in variables.Keys )
  330. 				{
  331. 					if ( variables[key] == 0 )
  332. 					{
  333. 						if ( unusedonly )
  334. 						{
  335. 							Console.WriteLine( key );
  336. 						}
  337. 						else
  338. 						{
  339. 							RedLine( String.Format( "{0,-" + columnwidth + "}    {1}", key, variables[key] ) );
  340. 						}
  341. 						rc += 1;
  342. 					}
  343. 					else if ( !unusedonly )
  344. 					{
  345. 						Console.WriteLine( "{0,-" + columnwidth + "}    {1}", key, variables[key] );
  346. 					}
  347. 				}
  348. 				Console.WriteLine( );
  349. 			}
  350.  
  351. 			#endregion Count and Display Variables Usage
  352.  
  353.  
  354. 			return rc;
  355. 		}
  356.  
  357.  
  358. 		static void RedLine( string line )
  359. 		{
  360. 			Console.ForegroundColor = ConsoleColor.Red;
  361. 			Console.WriteLine( line );
  362. 			Console.ResetColor( );
  363. 		}
  364.  
  365.  
  366. 		static int ShowHelp( params string[] errmsg )
  367. 		{
  368. 			#region Error Message
  369.  
  370. 			if ( errmsg.Length > 0 )
  371. 			{
  372. 				List<string> errargs = new List<string>( errmsg );
  373. 				errargs.RemoveAt( 0 );
  374. 				Console.Error.WriteLine( );
  375. 				Console.ForegroundColor = ConsoleColor.Red;
  376. 				Console.Error.Write( "ERROR:\t" );
  377. 				Console.ForegroundColor = ConsoleColor.White;
  378. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  379. 				Console.ResetColor( );
  380. 			}
  381.  
  382. 			#endregion Error Message
  383.  
  384.  
  385. 			#region Help Text
  386.  
  387. 			/*
  388. 			CheckVarsVBS.exe,  Version 1.01
  389. 			Check VBScript code for unused variables and subroutines
  390.  
  391. 			Usage:    CheckVarsVBS.exe  "vbsfile"  [ /S | /V ]  [ /U ]  [ /W ]
  392.  
  393. 			Where:    "vbsfile"         is the VBScript or HTA file to be examined
  394. 			          /S                tests Subroutines only
  395. 			                            (default: subroutines as well as variables)
  396. 			          /U                list Unused subroutines and variables only
  397. 			                            (default: list all subroutines and variables)
  398. 			          /V                tests Variables only
  399. 			                            (default: subroutines as well as variables)
  400. 			          /W                include Window_On* subroutines for HTAs
  401. 			                            (default: ignore Window_On* subroutines in HTAs)
  402.  
  403. 			Notes:    For HTAs only the following special subroutines are ignored
  404. 			          (not listed in red, or not at all with /U switch) by default:
  405. 			          Window_OnBeforeUnload, Window_OnBlur, Window_OnFocus,
  406. 			          Window_OnHelp, Window_OnLoad, Window_OnResize, Window_OnUnload;
  407. 			          use /W to treat them as ordinary subroutines.
  408. 			          The program's return code equals the number of unused subroutines
  409. 			          and/or variables, or -1 in case of (command line) errors.
  410.  
  411. 			Written by Rob van der Woude
  412. 			http://www.robvanderwoude.com
  413. 			*/
  414.  
  415. 			Console.Error.WriteLine( );
  416.  
  417. 			Console.Error.WriteLine( "CheckVarsVBS.exe,  Version {0}", progver );
  418.  
  419. 			Console.Error.WriteLine( "Check VBScript code for unused variables and subroutines" );
  420.  
  421. 			Console.Error.WriteLine( );
  422.  
  423. 			Console.Error.Write( "Usage:    " );
  424. 			Console.ForegroundColor = ConsoleColor.White;
  425. 			Console.Error.WriteLine( "CheckVarsVBS.exe  \"vbsfile\"  [ /S | /V ]  [ /U ]  [ /W ]" );
  426. 			Console.ResetColor( );
  427.  
  428. 			Console.Error.WriteLine( );
  429.  
  430. 			Console.Error.Write( "Where:    " );
  431. 			Console.ForegroundColor = ConsoleColor.White;
  432. 			Console.Error.Write( "\"vbsfile\"" );
  433. 			Console.ResetColor( );
  434. 			Console.Error.WriteLine( "         is the VBScript or HTA file to be examined" );
  435.  
  436. 			Console.ForegroundColor = ConsoleColor.White;
  437. 			Console.Error.Write( "          /S" );
  438. 			Console.ResetColor( );
  439. 			Console.Error.Write( "                tests " );
  440. 			Console.ForegroundColor = ConsoleColor.White;
  441. 			Console.Error.Write( "S" );
  442. 			Console.ResetColor( );
  443. 			Console.Error.WriteLine( "ubroutines only" );
  444.  
  445. 			Console.Error.WriteLine( "                            (default: subroutines as well as variables)" );
  446.  
  447. 			Console.ForegroundColor = ConsoleColor.White;
  448. 			Console.Error.Write( "          /U" );
  449. 			Console.ResetColor( );
  450. 			Console.Error.Write( "                list " );
  451. 			Console.ForegroundColor = ConsoleColor.White;
  452. 			Console.Error.Write( "U" );
  453. 			Console.ResetColor( );
  454. 			Console.Error.WriteLine( "nused subroutines and variables only" );
  455.  
  456. 			Console.Error.WriteLine( "                            (default: list all subroutines and variables)" );
  457.  
  458. 			Console.ForegroundColor = ConsoleColor.White;
  459. 			Console.Error.Write( "          /V" );
  460. 			Console.ResetColor( );
  461. 			Console.Error.Write( "                tests " );
  462. 			Console.ForegroundColor = ConsoleColor.White;
  463. 			Console.Error.Write( "V" );
  464. 			Console.ResetColor( );
  465. 			Console.Error.WriteLine( "ariables only" );
  466.  
  467. 			Console.Error.WriteLine( "                            (default: subroutines as well as variables)" );
  468.  
  469. 			Console.ForegroundColor = ConsoleColor.White;
  470. 			Console.Error.Write( "          /W" );
  471. 			Console.ResetColor( );
  472. 			Console.Error.Write( "                include " );
  473. 			Console.ForegroundColor = ConsoleColor.White;
  474. 			Console.Error.Write( "W" );
  475. 			Console.ResetColor( );
  476. 			Console.Error.WriteLine( "indow_On* subroutines for HTAs" );
  477.  
  478. 			Console.Error.WriteLine( "                            (default: ignore Window_On* subroutines in HTAs)" );
  479.  
  480. 			Console.Error.WriteLine( );
  481.  
  482. 			Console.Error.WriteLine( "Notes:    For HTAs only the following special subroutines are ignored" );
  483.  
  484. 			Console.Error.Write( "          (not listed in red, or not at all with " );
  485. 			Console.ForegroundColor = ConsoleColor.White;
  486. 			Console.Error.Write( "/U" );
  487. 			Console.ResetColor( );
  488. 			Console.Error.WriteLine( " switch) by default:" );
  489.  
  490. 			Console.Error.WriteLine( "          Window_OnBeforeUnload, Window_OnBlur, Window_OnFocus," );
  491.  
  492. 			Console.Error.WriteLine( "          Window_OnHelp, Window_OnLoad, Window_OnResize, Window_OnUnload;" );
  493.  
  494. 			Console.Error.Write( "          use " );
  495. 			Console.ForegroundColor = ConsoleColor.White;
  496. 			Console.Error.Write( "/W" );
  497. 			Console.ResetColor( );
  498. 			Console.Error.WriteLine( " to treat them as ordinary subroutines." );
  499.  
  500. 			Console.Error.WriteLine( "          The program's return code equals the number of unused subroutines" );
  501.  
  502. 			Console.Error.WriteLine( "          and/or variables, or -1 in case of (command line) errors." );
  503.  
  504. 			Console.Error.WriteLine( );
  505.  
  506. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  507.  
  508. 			Console.Error.WriteLine( "http://www.robvanderwoude.com" );
  509.  
  510. 			#endregion Help Text
  511.  
  512.  
  513. 			return -1;
  514. 		}
  515. 	}
  516. }
  517.  

page last uploaded: 2017-07-06, 12:37