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.Linq;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7.  
  8.  
  9. namespace RobvanderWoude
  10. {
  11. 	class CheckVarsVBS
  12. 	{
  13. 		static readonly string progver = "1.10";
  14.  
  15.  
  16. 		static List<string> csserrors = new List<string>( );
  17.  
  18.  
  19. 		static int Main( string[] args )
  20. 		{
  21. 			#region Initialize Variables
  22.  
  23. 			int rc = 0;
  24. 			SortedList<string, int> subroutines = new SortedList<string, int>( );
  25. 			SortedList<string, int> variables = new SortedList<string, int>( );
  26. 			bool htawindowevents = false;
  27. 			bool showsubs = true;
  28. 			bool showvars = true;
  29. 			bool unusedonly = false;
  30. 			string scriptcode = String.Empty;
  31. 			string scriptext = String.Empty;
  32. 			string scriptfile = String.Empty;
  33. 			int columnwidth = 12;
  34. 			int unusedsubs = 0;
  35. 			int unusedvars = 0;
  36. 			List<string> ignoredsubs = new List<string>( )
  37. 			{
  38. 				"window_onbeforeunload",
  39. 				"window_onblur",
  40. 				"window_onfocus",
  41. 				"window_onhelp",
  42. 				"window_onload",
  43. 				"window_onresize",
  44. 				"window_onunload"
  45. 			};
  46.  
  47. 			#endregion Initialize Variables
  48.  
  49.  
  50. 			#region Command Line Parsing
  51.  
  52. 			if ( args.Length == 0 )
  53. 			{
  54. 				return ShowHelp( );
  55. 			}
  56.  
  57. 			foreach ( string arg in args )
  58. 			{
  59. 				if ( arg[0] == '/' )
  60. 				{
  61. 					if ( arg.ToUpper( ) == "/?" )
  62. 					{
  63. 						return ShowHelp( );
  64. 					}
  65. 					else if ( arg.ToUpper( ) == "/S" )
  66. 					{
  67. 						if ( !showvars )
  68. 						{
  69. 							return ShowHelp( "Duplicate command line switch /S" );
  70. 						}
  71. 						if ( !showsubs )
  72. 						{
  73. 							return ShowHelp( "Use /S or /V or neither, but not both" );
  74. 						}
  75. 						showvars = false;
  76. 					}
  77. 					else if ( arg.ToUpper( ) == "/U" )
  78. 					{
  79. 						if ( unusedonly )
  80. 						{
  81. 							return ShowHelp( "Duplicate command line switch /U" );
  82. 						}
  83. 						unusedonly = true;
  84. 					}
  85. 					else if ( arg.ToUpper( ) == "/V" )
  86. 					{
  87. 						if ( !showsubs )
  88. 						{
  89. 							return ShowHelp( "Duplicate command line switch /V" );
  90. 						}
  91. 						if ( !showvars )
  92. 						{
  93. 							return ShowHelp( "Use /S or /V or neither, but not both" );
  94. 						}
  95. 						showsubs = false;
  96. 					}
  97. 					else if ( arg.ToUpper( ) == "/W" )
  98. 					{
  99. 						if ( htawindowevents )
  100. 						{
  101. 							return ShowHelp( "Duplicate command line switch /W" );
  102. 						}
  103. 						htawindowevents = true;
  104. 					}
  105. 					else
  106. 					{
  107. 						return ShowHelp( "Invalid command line switch \"{0}\"", arg );
  108. 					}
  109. 				}
  110. 				else
  111. 				{
  112. 					if ( !String.IsNullOrWhiteSpace( scriptfile ) )
  113. 					{
  114. 						return ShowHelp( "Duplicate command line argument for VBScript file" );
  115. 					}
  116. 					if ( !File.Exists( arg ) )
  117. 					{
  118. 						return ShowHelp( "Invalid file name or file not found: \"{0}\"", arg );
  119. 					}
  120. 					scriptext = Path.GetExtension( arg ).ToLower( );
  121. 					if ( scriptext != ".hta" && scriptext != ".vbs" )
  122. 					{
  123. 						return ShowHelp( "Invalid file type \"{0}\"", arg );
  124. 					}
  125. 					scriptfile = Path.GetFullPath( arg );
  126. 				}
  127.  
  128. 			}
  129.  
  130. 			if ( String.IsNullOrWhiteSpace( scriptfile ) )
  131. 			{
  132. 				return ShowHelp( "Please specify a source file" );
  133. 			}
  134.  
  135. 			#endregion Command Line Parsing
  136.  
  137.  
  138. 			#region Read File
  139.  
  140. 			// Read the code from the file
  141. 			scriptcode = File.ReadAllText( scriptfile, Encoding.UTF8 );
  142. 			// Remove comment lines from the code (does NOT strip comments starting halfway on a line)
  143. 			string pattern = @"(^|\n|\r)[ \t]*'[^\n\r]+";
  144. 			Regex regex = new Regex( pattern );
  145. 			scriptcode = regex.Replace( scriptcode, String.Empty );
  146.  
  147. 			#endregion Read File
  148.  
  149.  
  150. 			#region Ignore JavaScript in HTAs
  151.  
  152. 			string vbscriptcode = scriptcode;
  153. 			if ( scriptext == ".hta" )
  154. 			{
  155. 				pattern = @"[\n\r][\t ]*<script[\t ]+[^>]+javascript\"">[\w\W]*?[\n\r][\t ]*?</script>";
  156. 				regex = new Regex( pattern, RegexOptions.IgnoreCase );
  157. 				if ( regex.IsMatch( scriptcode ) )
  158. 				{
  159. 					vbscriptcode = regex.Replace( scriptcode, "" );
  160. 				}
  161. 			}
  162.  
  163. 			#endregion Ignore JavaScript in HTAs
  164.  
  165.  
  166. 			#region List Subroutines
  167.  
  168. 			// Create a list of subroutines found in the code
  169. 			if ( showsubs )
  170. 			{
  171. 				pattern = @"(?:^|\n|\r)[ \t]*(?:Private|Public)? *(?:Sub|Function)[ \t]+([A-Z][^\s\(]+)";
  172. 				regex = new Regex( pattern, RegexOptions.IgnoreCase );
  173. 				if ( regex.IsMatch( vbscriptcode ) )
  174. 				{
  175. 					MatchCollection matches = regex.Matches( vbscriptcode );
  176. 					if ( matches.Count > 0 )
  177. 					{
  178. 						foreach ( Match match in matches )
  179. 						{
  180. 							bool listed = false;
  181. 							string sub = match.Groups[1].Value;
  182. 							foreach ( string key in subroutines.Keys )
  183. 							{
  184. 								if ( sub.ToLower( ) == key.ToLower( ) )
  185. 								{
  186. 									listed = true;
  187. 								}
  188. 							}
  189. 							if ( !listed )
  190. 							{
  191. 								if ( sub.ToLower( ).StartsWith( "window_on" ) )
  192. 								{
  193. 									subroutines[sub] = 1;
  194. 								}
  195. 								else
  196. 								{
  197. 									subroutines[sub] = 0;
  198. 								}
  199. 								if ( sub.Length > columnwidth )
  200. 								{
  201. 									columnwidth = sub.Length;
  202. 								}
  203. 							}
  204. 						}
  205. 					}
  206. 				}
  207. 			}
  208.  
  209. 			#endregion List Subroutines
  210.  
  211.  
  212. 			#region Check Subroutine Nesting
  213.  
  214. 			if ( showsubs )
  215. 			{
  216. 				pattern = @"(?:^|\n|\r)[ \t]*End[ \t]+(?:Sub|Function)('|\s|$)";
  217. 				regex = new Regex( pattern, RegexOptions.IgnoreCase );
  218. 				if ( regex.IsMatch( vbscriptcode ) )
  219. 				{
  220. 					MatchCollection matches = regex.Matches( vbscriptcode );
  221. 					if ( matches.Count != subroutines.Count )
  222. 					{
  223. 						RedLine( "{0} Sub and Function statements found, against {1} End Sub and End Function statements\n", subroutines.Count, matches.Count );
  224.  
  225. 					}
  226. 					pattern = @"(?:^|\r|\n)\s*(?:Private|Public)? *(Sub|Function)\s.*?(?:^|\n|\r)[ \t]*End[ \t]+\1('|\s|$)";
  227. 					regex = new Regex( pattern, RegexOptions.Singleline );
  228. 					if ( regex.IsMatch( vbscriptcode ) )
  229. 					{
  230. 						matches = regex.Matches( vbscriptcode );
  231. 						foreach ( Match match in matches )
  232. 						{
  233. 							string subroutine = match.Groups[0].ToString( );
  234. 							List<string> subs = new List<string>( );
  235. 							int startsubs = 0;
  236. 							int endsubs = 0;
  237. 							pattern = @"(?:^|\r|\n)\s*(?:Private|Public)? *(?:Sub|Function)\s(\w+)";
  238. 							regex = new Regex( pattern );
  239. 							if ( regex.IsMatch( subroutine ) )
  240. 							{
  241. 								MatchCollection submatches = regex.Matches( subroutine );
  242. 								startsubs = submatches.Count;
  243. 								foreach ( Match sub in submatches )
  244. 								{
  245. 									subs.Add( sub.Value.Trim( "\n\r\t ".ToCharArray( ) ) );
  246. 								}
  247. 							}
  248. 							pattern = @"[\n\r]+\s*End[ \t]+(Sub|Function)(?:\s|$)";
  249. 							regex = new Regex( pattern );
  250. 							if ( regex.IsMatch( subroutine ) )
  251. 							{
  252. 								MatchCollection submatches = regex.Matches( subroutine );
  253. 								endsubs = submatches.Count;
  254. 							}
  255. 							if ( startsubs > 1 || endsubs > 1 )
  256. 							{
  257. 								RedLine( "Possibly nested or improperly terminated functions and/or subroutines:" );
  258. 								Console.WriteLine( "\t{0}\n", String.Join( "\n\t", subs.ToArray( ) ) );
  259. 							}
  260. 						}
  261. 					}
  262. 				}
  263. 			}
  264.  
  265. 			#endregion Check Subroutine Nesting
  266.  
  267.  
  268. 			#region List Variables
  269.  
  270. 			// Create a list of variables found in the code
  271. 			if ( showvars )
  272. 			{
  273. 				pattern = @"(?:^|\n|\r)[ \t]*(?:(?:Dim|Private|Public)[ \t]+){1,2}([A-Z][^\n\r:]+)";
  274. 				regex = new Regex( pattern, RegexOptions.IgnoreCase );
  275. 				if ( regex.IsMatch( vbscriptcode ) )
  276. 				{
  277. 					MatchCollection matches = regex.Matches( vbscriptcode );
  278. 					if ( matches.Count > 0 )
  279. 					{
  280. 						foreach ( Match match in matches )
  281. 						{
  282. 							string varstring = match.Groups[1].ToString( );
  283. 							if ( varstring.Contains( "'" ) )
  284. 							{
  285. 								varstring = varstring.Substring( 0, varstring.IndexOf( "'" ) );
  286. 							}
  287. 							string[] vars = varstring.Split( ", ()".ToCharArray( ), StringSplitOptions.RemoveEmptyEntries );
  288. 							foreach ( string var in vars )
  289. 							{
  290. 								if ( !int.TryParse( var[0].ToString( ), out int dummy ) ) // ignore variables starting with a number
  291. 								{
  292. 									bool listed = false;
  293. 									foreach ( string key in subroutines.Keys )
  294. 									{
  295. 										if ( var.ToLower( ) == key.ToLower( ) )
  296. 										{
  297. 											listed = true;
  298. 										}
  299. 									}
  300. 									if ( !listed )
  301. 									{
  302. 										variables[var] = 0;
  303. 										if ( var.Length > columnwidth )
  304. 										{
  305. 											columnwidth = var.Length;
  306. 										}
  307. 									}
  308. 								}
  309. 							}
  310. 						}
  311. 					}
  312. 				}
  313. 			}
  314.  
  315. 			#endregion List Variables
  316.  
  317.  
  318. 			#region Count and Display Subroutines Usage
  319.  
  320. 			// Iterate through the list of subroutines and count the occurrences of its name
  321. 			if ( showsubs )
  322. 			{
  323. 				List<string> keys = new List<string>( subroutines.Keys );
  324. 				foreach ( string sub in keys )
  325. 				{
  326. 					bool ignorethissub = !htawindowevents && scriptext == ".hta" && ignoredsubs.Contains( sub.ToLower( ) );
  327. 					if ( !ignorethissub )
  328. 					{
  329. 						string strippedcode = vbscriptcode;
  330. 						pattern = string.Format( @"Function\s+{0}\([\w\W]*?End\s+Function", sub );
  331. 						regex = new Regex( pattern, RegexOptions.IgnoreCase );
  332. 						if ( regex.IsMatch( vbscriptcode ) )
  333. 						{
  334. 							strippedcode = regex.Replace( vbscriptcode, string.Empty );
  335. 						}
  336. 						else
  337. 						{
  338. 							pattern = string.Format( @"Sub\s+{0}\([\w\W]*?End\s+Sub", sub );
  339. 							regex = new Regex( pattern, RegexOptions.IgnoreCase );
  340. 							if ( regex.IsMatch( strippedcode ) )
  341. 							{
  342. 								strippedcode = regex.Replace( strippedcode, string.Empty );
  343. 							}
  344. 						}
  345. 						pattern = string.Format( @"\b{0}\b", sub );
  346. 						regex = new Regex( pattern, RegexOptions.IgnoreCase );
  347. 						if ( regex.IsMatch( strippedcode ) )
  348. 						{
  349. 							if ( !sub.ToLower( ).StartsWith( "window_on" ) )
  350. 							{
  351. 								subroutines[sub] += regex.Matches( strippedcode ).Count;
  352. 								if ( subroutines[sub] == 0 )
  353. 								{
  354. 									unusedsubs += 1;
  355. 								}
  356. 							}
  357. 						}
  358. 						else
  359. 						{
  360. 							unusedsubs += 1;
  361. 						}
  362. 					}
  363. 				}
  364. 				// Show the results
  365. 				if ( unusedonly )
  366. 				{
  367. 					if ( unusedsubs == 0 )
  368. 					{
  369. 						Console.WriteLine( "0 Unused Subs or Functions" );
  370. 						Console.WriteLine( "==========================" );
  371. 					}
  372. 					else if ( unusedsubs == 1 )
  373. 					{
  374. 						Console.WriteLine( "1 Unused Sub or Function:" );
  375. 						Console.WriteLine( "=========================" );
  376. 					}
  377. 					else
  378. 					{
  379. 						Console.WriteLine( "{0} Unused Subs and Functions:", unusedsubs );
  380. 						Console.WriteLine( "{0}===========================", new String( '=', unusedsubs.ToString( ).Length ) );
  381. 					}
  382. 				}
  383. 				else
  384. 				{
  385. 					Console.WriteLine( "{0,-" + columnwidth + "}    Occurrences:", "Sub or Function:" );
  386. 					Console.WriteLine( "{0,-" + columnwidth + "}    ============", "================" );
  387. 				}
  388. 				foreach ( string key in subroutines.Keys )
  389. 				{
  390. 					bool ignorethissub = !htawindowevents && scriptext == ".hta" && ignoredsubs.Contains( key.ToLower( ) );
  391. 					if ( subroutines[key] == 0 )
  392. 					{
  393. 						if ( unusedonly )
  394. 						{
  395. 							if ( !ignorethissub )
  396. 							{
  397. 								Console.WriteLine( key );
  398. 							}
  399. 						}
  400. 						else
  401. 						{
  402. 							if ( ignorethissub )
  403. 							{
  404. 								Console.WriteLine( "{0,-" + columnwidth + "}    {1}", key, subroutines[key] );
  405. 							}
  406. 							else
  407. 							{
  408. 								RedLine( string.Format( "{0,-" + columnwidth + "}    {1}", key, subroutines[key] ) );
  409. 							}
  410. 						}
  411. 						rc += 1;
  412. 					}
  413. 					else if ( !unusedonly )
  414. 					{
  415. 						Console.WriteLine( "{0,-" + columnwidth + "}    {1}", key, subroutines[key] );
  416. 					}
  417. 				}
  418. 				Console.WriteLine( );
  419. 			}
  420.  
  421. 			#endregion Count and Display Subroutines Usage
  422.  
  423.  
  424. 			#region Count and Display Variables Usage
  425.  
  426. 			// Iterate through the list of variables and count the occurrences of its name
  427. 			if ( showvars )
  428. 			{
  429. 				List<string> keys = new List<string>( variables.Keys );
  430. 				foreach ( string variable in keys )
  431. 				{
  432. 					pattern = string.Format( @"\b{0}\b", variable );
  433. 					regex = new Regex( pattern, RegexOptions.IgnoreCase );
  434. 					if ( regex.IsMatch( vbscriptcode ) )
  435. 					{
  436. 						variables[variable] = regex.Matches( vbscriptcode ).Count - 1;
  437. 						if ( variables[variable] == 0 )
  438. 						{
  439. 							unusedvars += 1;
  440. 						}
  441. 					}
  442. 				}
  443. 				// Show the results
  444. 				if ( unusedonly )
  445. 				{
  446. 					Console.WriteLine( "{0} Unused Variable{1}{2}", unusedvars, ( unusedvars == 1 ? String.Empty : "s" ), ( unusedvars == 0 ? String.Empty : ":" ) );
  447. 					Console.WriteLine( "{0}================{1}{2}", new String( '=', unusedvars.ToString( ).Length ), ( unusedvars == 1 ? String.Empty : "=" ), ( unusedvars == 0 ? String.Empty : "=" ) );
  448. 				}
  449. 				else
  450. 				{
  451. 					Console.WriteLine( "{0,-" + columnwidth + "}    Occurrences:", "Variable:" );
  452. 					Console.WriteLine( "{0,-" + columnwidth + "}    ============", "=========" );
  453. 				}
  454. 				foreach ( string key in variables.Keys )
  455. 				{
  456. 					if ( variables[key] == 0 )
  457. 					{
  458. 						if ( unusedonly )
  459. 						{
  460. 							Console.WriteLine( key );
  461. 						}
  462. 						else
  463. 						{
  464. 							RedLine( string.Format( "{0,-" + columnwidth + "}    {1}", key, variables[key] ) );
  465. 						}
  466. 						rc += 1;
  467. 					}
  468. 					else if ( !unusedonly )
  469. 					{
  470. 						Console.WriteLine( "{0,-" + columnwidth + "}    {1}", key, variables[key] );
  471. 					}
  472. 				}
  473. 				Console.WriteLine( );
  474. 			}
  475.  
  476. 			#endregion Count and Display Variables Usage
  477.  
  478.  
  479. 			#region Check HTA Head
  480.  
  481. 			if ( showsubs && showvars )
  482. 			{
  483. 				if ( Path.GetExtension( scriptfile ).ToLower( ) == ".hta" )
  484. 				{
  485. 					UnderLine( "HTA Head:" );
  486. 					int htaerrors = 0;
  487. 					pattern = @"<style[^>]*>((?:.|\n|\r)*?)</style>";
  488. 					regex = new Regex( pattern, RegexOptions.IgnoreCase );
  489. 					if ( regex.IsMatch( vbscriptcode ) )
  490. 					{
  491. 						MatchCollection matches = regex.Matches( vbscriptcode );
  492. 						if ( matches.Count > 0 )
  493. 						{
  494. 							foreach ( Match match in matches )
  495. 							{
  496. 								foreach ( Group submatch in match.Groups )
  497. 								{
  498. 									htaerrors += CheckStyles( submatch.ToString( ) );
  499. 								}
  500. 							}
  501. 						}
  502. 					}
  503. 					switch ( htaerrors )
  504. 					{
  505. 						case 0:
  506. 							Console.WriteLine( "No CSS errors found" );
  507. 							break;
  508. 						case 1:
  509. 							RedLine( "\n1 possible CSS error found" );
  510. 							break;
  511. 						default:
  512. 							RedLine( "\n{0} possible CSS errors found", htaerrors );
  513. 							break;
  514. 					}
  515. 				}
  516. 			}
  517.  
  518. 			#endregion Check HTA Head
  519.  
  520.  
  521. 			#region Check HTA Event Handlers Case
  522.  
  523. 			if ( showsubs && showvars )
  524. 			{
  525. 				if ( Path.GetExtension( scriptfile ).ToLower( ) == ".hta" )
  526. 				{
  527. 					UnderLine( "\nHTA Event Handlers:" );
  528.  
  529. 					List<string> eventnames = Enum.GetNames( typeof( Events ) ).Cast<string>( ).ToList<string>( );
  530. 					List<string> warnings = new List<string>( );
  531. 					Regex regexci = new Regex( @"\bsub\s+window_onload\b", RegexOptions.IgnoreCase );
  532. 					bool caseissue = false;
  533. 					foreach ( Match match in regexci.Matches( vbscriptcode ) )
  534. 					{
  535. 						Regex regexcs = new Regex( @"\b[Ss][Uu][Bb]\s+window_onload\b", RegexOptions.None );
  536. 						if ( !caseissue && regexci.IsMatch( vbscriptcode ) && !regexcs.IsMatch( match.Value ) )
  537. 						{
  538. 							warnings.Add( match.Value );
  539. 							caseissue = true;
  540. 						}
  541. 					}
  542. 					regexci = new Regex( @"\bsub\s+window_onunload\b", RegexOptions.IgnoreCase );
  543. 					caseissue = false;
  544. 					foreach ( Match match in regexci.Matches( vbscriptcode ) )
  545. 					{
  546. 						Regex regexcs = new Regex( @"\b[Ss][Uu][Bb]\s+window_onunload\b", RegexOptions.None );
  547. 						if ( !caseissue && regexci.IsMatch( vbscriptcode ) && !regexcs.IsMatch( match.Value ) )
  548. 						{
  549. 							warnings.Add( match.Value );
  550. 							caseissue = true;
  551. 						}
  552. 					}
  553. 					foreach ( string eventname in eventnames )
  554. 					{
  555. 						string eventhandler = CheckEvent( eventname, vbscriptcode );
  556. 						if ( !String.IsNullOrEmpty( eventhandler ) )
  557. 						{
  558. 							warnings.Add( eventname );
  559. 						}
  560. 					}
  561. 					warnings.Sort( );
  562. 					switch ( warnings.Count )
  563. 					{
  564. 						case 0:
  565. 							Console.WriteLine( "No case mismatches for event handlers found" );
  566. 							break;
  567. 						case 1:
  568. 							RedLine( "\n1 possible case mismatch for event handler \"{0}\"", warnings[0] );
  569. 							break;
  570. 						default:
  571. 							foreach ( string warning in warnings )
  572. 							{
  573. 								Console.WriteLine( "Possible case mismatch for event handler \"{0}\"", warning );
  574. 							}
  575. 							RedLine( "\n{0} possible case mismatches for event handlers found", warnings.Count );
  576. 							break;
  577. 					}
  578. 				}
  579. 			}
  580.  
  581. 			#endregion Check HTA Event Handlers Case
  582.  
  583.  
  584. 			return rc;
  585. 		}
  586.  
  587.  
  588. 		static string CheckEvent( string eventname, string code )
  589. 		{
  590. 			string pattern = string.Format( @"\s({0})=", eventname );
  591. 			Regex regexci = new Regex( pattern, RegexOptions.IgnoreCase );
  592. 			if ( regexci.IsMatch( code ) )
  593. 			{
  594. 				MatchCollection matches = regexci.Matches( code );
  595. 				Regex regexcs = new Regex( pattern, RegexOptions.None );
  596. 				foreach ( Match match in matches )
  597. 				{
  598. 					if( match.Groups[1].Value != eventname )
  599. 					{
  600. 						return match.Groups[1].Value;
  601. 					}
  602. 				}
  603.  
  604. 			}
  605. 			return null;
  606. 		}
  607.  
  608.  
  609. 		static int CheckStyle( string styledef )
  610. 		{
  611. 			int errors = 0;
  612. 			string pattern = @"^([^@\{]+)\{([^\}]+)\}";
  613. 			Regex regex = new Regex( pattern );
  614. 			if ( regex.IsMatch( styledef ) )
  615. 			{
  616. 				string tagdef = regex.Match( styledef ).Groups[1].ToString( ).Trim( "\n\r\t ".ToCharArray( ) );
  617. 				string tagstyle = regex.Match( styledef ).Groups[2].ToString( ).Trim( "\n\r\t ".ToCharArray( ) );
  618. 				string[] tagcssall = tagstyle.Split( ';' );
  619. 				for ( int i = 0; i < tagcssall.Length; i++ )
  620. 				{
  621. 					tagcssall[i] = tagcssall[i].Trim( "\n\r\t ".ToCharArray( ) );
  622. 				}
  623. 				string pattern1 = @"^([\w-]+)\s*:\s*([^\n\r\;\{\}]+)$";
  624. 				Regex regex1 = new Regex( pattern1 );
  625. 				string pattern2 = @"^([\w-]+)\s*:";
  626. 				Regex regex2 = new Regex( pattern2 );
  627. 				foreach ( string line in tagcssall )
  628. 				{
  629. 					if ( String.IsNullOrWhiteSpace( line ) )
  630. 					{
  631. 						// No action required
  632. 					}
  633. 					else if ( regex1.IsMatch( line ) )
  634. 					{
  635. 						MatchCollection matches1 = regex1.Matches( line );
  636. 						string csskey = matches1[0].Groups[1].ToString( );
  637. 						string cssval = matches1[0].Groups[2].ToString( );
  638. 						string pattern3 = @"^[^\(]*\)|\([^\)]*$";
  639. 						regex = new Regex( pattern3 );
  640. 						if ( regex.IsMatch( cssval ) )
  641. 						{
  642. 							if ( !csserrors.Contains( csskey ) )
  643. 							{
  644. 								csserrors.Add( csskey );
  645. 								RedLine( "Possible CSS error for {0}:", csskey );
  646. 								Console.WriteLine( "\t{0}\n", cssval );
  647. 								errors += 1;
  648. 							}
  649. 						}
  650. 					}
  651. 					else if ( regex2.IsMatch( line ) )
  652. 					{
  653. 						MatchCollection matches2 = regex2.Matches( line );
  654. 						string csskey = matches2[0].Groups[1].ToString( );
  655. 						if ( !csserrors.Contains( csskey ) )
  656. 						{
  657. 							csserrors.Add( csskey );
  658. 							RedLine( "Possible CSS error(s) for {0}:", csskey );
  659. 							errors += 1;
  660. 						}
  661. 					}
  662. 					else
  663. 					{
  664. 						string csserror = styledef.Substring( 0, styledef.IndexOfAny( "{\n\r".ToCharArray( ) ) ).Trim( "{\n\r\t ".ToCharArray( ) );
  665. 						if ( !csserrors.Contains( csserror ) )
  666. 						{
  667. 							RedLine( "Possible CSS error(s):" );
  668. 							Console.WriteLine( "{0}\n", styledef );
  669. 							errors += 1;
  670. 						}
  671. 					}
  672. 				}
  673. 			}
  674. 			return errors;
  675. 		}
  676.  
  677.  
  678. 		static int CheckStyles( string stylesheet )
  679. 		{
  680. 			int errors = 0;
  681. 			string pattern = @"\/\*(.|\n|\r)*?\*\/";
  682. 			Regex regex = new Regex( pattern );
  683. 			if ( regex.IsMatch( stylesheet ) )
  684. 			{
  685. 				stylesheet = regex.Replace( stylesheet, string.Empty );
  686. 			}
  687. 			pattern = @"[^\n\r\{\}]+\s*\{[^\}]+\}";
  688. 			regex = new Regex( pattern, RegexOptions.IgnoreCase );
  689. 			if ( regex.IsMatch( stylesheet ) )
  690. 			{
  691. 				MatchCollection matches = regex.Matches( stylesheet );
  692. 				foreach ( Match match in matches )
  693. 				{
  694. 					errors += CheckStyle( match.ToString( ) );
  695. 				}
  696. 			}
  697. 			return errors;
  698. 		}
  699.  
  700.  
  701. 		static void RedLine( string line, params object[] rlargs )
  702. 		{
  703. 			Console.ForegroundColor = ConsoleColor.Red;
  704. 			if ( rlargs.Length > 0 )
  705. 			{
  706. 				Console.WriteLine( line, rlargs );
  707. 			}
  708. 			else
  709. 			{
  710. 				Console.WriteLine( line );
  711. 			}
  712. 			Console.ResetColor( );
  713. 		}
  714.  
  715.  
  716. 		static int ShowHelp( params string[] errmsg )
  717. 		{
  718. 			#region Error Message
  719.  
  720. 			if ( errmsg.Length > 0 )
  721. 			{
  722. 				List<string> errargs = new List<string>( errmsg );
  723. 				errargs.RemoveAt( 0 );
  724. 				Console.Error.WriteLine( );
  725. 				Console.ForegroundColor = ConsoleColor.Red;
  726. 				Console.Error.Write( "ERROR:\t" );
  727. 				Console.ForegroundColor = ConsoleColor.White;
  728. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  729. 				Console.ResetColor( );
  730. 			}
  731.  
  732. 			#endregion Error Message
  733.  
  734.  
  735. 			#region Help Text
  736.  
  737. 			/*
  738. 			CheckVarsVBS.exe,  Version 1.06
  739. 			Check VBScript code for unused variables and subroutines
  740.  
  741. 			Usage:    CheckVarsVBS.exe  "vbsfile"  [ /S | /V ]  [ /U ]  [ /W ]
  742.  
  743. 			Where:    "vbsfile"         is the VBScript or HTA file to be examined
  744. 			          /S                tests Subroutines and functions only
  745. 			                            (default: test all)
  746. 			          /U                list only Unused subroutines, functions, variables
  747. 			                            (default: list all)
  748. 			          /V                tests Variables only
  749. 			                            (default: test all)
  750. 			          /W                include Window_On* subroutines for HTAs
  751. 			                            (default: ignore Window_On* subroutines in HTAs)
  752.  
  753. 			Notes:    When checking subroutines and functions, the program will also check
  754. 			          for improperly terminated and nested subroutines and functions.
  755. 			          For HTAs only, the following special subroutines are ignored
  756. 			          (not listed in red, or not at all with /U switch) by default:
  757. 			          Window_OnBeforeUnload, Window_OnBlur, Window_OnFocus,
  758. 			          Window_OnHelp, Window_OnLoad, Window_OnResize, Window_OnUnload;
  759. 			          use /W to treat them as ordinary subroutines.
  760. 			          For HTAs only, unless checking for variables only (/V switch),
  761. 			          this program will search the HTA's head for CSS style definitions,
  762. 			          and check those for some common typos.
  763. 			          JavaScript subroutines and variables in HTAs are ignored.
  764. 			          The program's return code equals the sum of unused subroutines,
  765. 			          functions and variables, or -1 in case of (command line) errors.
  766.  
  767. 			Written by Rob van der Woude
  768. 			https://www.robvanderwoude.com
  769. 			*/
  770.  
  771. 			#endregion Help Text
  772.  
  773.  
  774. 			#region Display Help Text
  775.  
  776. 			Console.Error.WriteLine( );
  777.  
  778. 			Console.Error.WriteLine( "CheckVarsVBS.exe,  Version {0}", progver );
  779.  
  780. 			Console.Error.WriteLine( "Check VBScript code for unused variables and subroutines" );
  781.  
  782. 			Console.Error.WriteLine( );
  783.  
  784. 			Console.Error.Write( "Usage:    " );
  785. 			Console.ForegroundColor = ConsoleColor.White;
  786. 			Console.Error.WriteLine( "CheckVarsVBS.exe  \"vbsfile\"  [ /S | /V ]  [ /U ]  [ /W ]" );
  787. 			Console.ResetColor( );
  788.  
  789. 			Console.Error.WriteLine( );
  790.  
  791. 			Console.Error.Write( "Where:    " );
  792. 			Console.ForegroundColor = ConsoleColor.White;
  793. 			Console.Error.Write( "\"vbsfile\"" );
  794. 			Console.ResetColor( );
  795. 			Console.Error.WriteLine( "         is the VBScript or HTA file to be examined" );
  796.  
  797. 			Console.ForegroundColor = ConsoleColor.White;
  798. 			Console.Error.Write( "          /S" );
  799. 			Console.ResetColor( );
  800. 			Console.Error.Write( "                tests " );
  801. 			Console.ForegroundColor = ConsoleColor.White;
  802. 			Console.Error.Write( "S" );
  803. 			Console.ResetColor( );
  804. 			Console.Error.WriteLine( "ubroutines and functions only" );
  805.  
  806. 			Console.Error.WriteLine( "                            (default: test all)" );
  807.  
  808. 			Console.ForegroundColor = ConsoleColor.White;
  809. 			Console.Error.Write( "          /U" );
  810. 			Console.ResetColor( );
  811. 			Console.Error.Write( "                list only " );
  812. 			Console.ForegroundColor = ConsoleColor.White;
  813. 			Console.Error.Write( "U" );
  814. 			Console.ResetColor( );
  815. 			Console.Error.WriteLine( "nused subroutines, functions, variables" );
  816.  
  817. 			Console.Error.WriteLine( "                            (default: list all)" );
  818.  
  819. 			Console.ForegroundColor = ConsoleColor.White;
  820. 			Console.Error.Write( "          /V" );
  821. 			Console.ResetColor( );
  822. 			Console.Error.Write( "                tests " );
  823. 			Console.ForegroundColor = ConsoleColor.White;
  824. 			Console.Error.Write( "V" );
  825. 			Console.ResetColor( );
  826. 			Console.Error.WriteLine( "ariables only" );
  827.  
  828. 			Console.Error.WriteLine( "                            (default: test all)" );
  829.  
  830. 			Console.ForegroundColor = ConsoleColor.White;
  831. 			Console.Error.Write( "          /W" );
  832. 			Console.ResetColor( );
  833. 			Console.Error.Write( "                include " );
  834. 			Console.ForegroundColor = ConsoleColor.White;
  835. 			Console.Error.Write( "W" );
  836. 			Console.ResetColor( );
  837. 			Console.Error.WriteLine( "indow_On* subroutines for HTAs" );
  838.  
  839. 			Console.Error.WriteLine( "                            (default: ignore Window_On* subroutines in HTAs)" );
  840.  
  841. 			Console.Error.WriteLine( );
  842.  
  843. 			Console.Error.WriteLine( "Notes:    When checking subroutines and functions, the program will also check" );
  844.  
  845. 			Console.Error.WriteLine( "          for improperly terminated and nested subroutines and functions." );
  846.  
  847. 			Console.Error.WriteLine( "          For HTAs only, the following special subroutines are ignored" );
  848.  
  849. 			Console.Error.Write( "          (not listed in red, or not at all with " );
  850. 			Console.ForegroundColor = ConsoleColor.White;
  851. 			Console.Error.Write( "/U" );
  852. 			Console.ResetColor( );
  853. 			Console.Error.WriteLine( " switch) by default:" );
  854.  
  855. 			Console.Error.WriteLine( "          Window_OnBeforeUnload, Window_OnBlur, Window_OnFocus," );
  856.  
  857. 			Console.Error.WriteLine( "          Window_OnHelp, Window_OnLoad, Window_OnResize, Window_OnUnload;" );
  858.  
  859. 			Console.Error.Write( "          use " );
  860. 			Console.ForegroundColor = ConsoleColor.White;
  861. 			Console.Error.Write( "/W" );
  862. 			Console.ResetColor( );
  863. 			Console.Error.WriteLine( " to treat them as ordinary subroutines." );
  864.  
  865. 			Console.Error.Write( "          For HTAs only, unless checking for variables only (" );
  866. 			Console.ForegroundColor = ConsoleColor.White;
  867. 			Console.Error.Write( "/V" );
  868. 			Console.ResetColor( );
  869. 			Console.Error.WriteLine( " switch)," );
  870.  
  871. 			Console.Error.WriteLine( "          this program will search the HTA's head for CSS style definitions," );
  872.  
  873. 			Console.Error.WriteLine( "          and check those for some common typos." );
  874.  
  875. 			Console.Error.WriteLine( "          JavaScript subroutines and variables in HTAs are ignored." );
  876.  
  877. 			Console.Error.WriteLine( "          The program's return code equals the sum of unused subroutines," );
  878.  
  879. 			Console.Error.WriteLine( "          functions and variables, or -1 in case of (command line) errors." );
  880.  
  881. 			Console.Error.WriteLine( );
  882.  
  883. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  884.  
  885. 			Console.Error.WriteLine( "https://www.robvanderwoude.com" );
  886.  
  887. 			#endregion Display Help Text
  888.  
  889.  
  890. 			return -1;
  891. 		}
  892.  
  893.  
  894. 		static void UnderLine( string text )
  895. 		{
  896. 			Console.WriteLine( text );
  897. 			Console.WriteLine( new string( '=', text.Replace( "\n", "" ).Replace( "\r", "" ).Length ) );
  898. 		}
  899. 	}
  900.  
  901.  
  902. 	public enum Events
  903. 	{
  904. 		onabort,
  905. 		onafterprint,
  906. 		onbeforeprint,
  907. 		onbeforeunload,
  908. 		onblur,
  909. 		oncanplay,
  910. 		oncanplaythrough,
  911. 		onchange,
  912. 		onclick,
  913. 		oncontextmenu,
  914. 		oncopy,
  915. 		oncut,
  916. 		ondblclick,
  917. 		ondrag,
  918. 		ondragend,
  919. 		ondragenter,
  920. 		ondragleave,
  921. 		ondragover,
  922. 		ondragstart,
  923. 		ondrop,
  924. 		ondurationchange,
  925. 		onemptied,
  926. 		onended,
  927. 		onerror,
  928. 		onfocus,
  929. 		onfocusin,
  930. 		onfocusout,
  931. 		onhashchange,
  932. 		oninput,
  933. 		oninvalid,
  934. 		onkeydown,
  935. 		onkeypress,
  936. 		onkeyup,
  937. 		onload,
  938. 		onloadeddata,
  939. 		onloadedmetadata,
  940. 		onloadstart,
  941. 		onmessage,
  942. 		onmousedown,
  943. 		onmouseenter,
  944. 		onmouseleave,
  945. 		onmousemove,
  946. 		onmouseout,
  947. 		onmouseover,
  948. 		onmouseup,
  949. 		onmousewheel,
  950. 		onoffline,
  951. 		ononline,
  952. 		onopen,
  953. 		onpagehide,
  954. 		onpageshow,
  955. 		onpaste,
  956. 		onpause,
  957. 		onplay,
  958. 		onplaying,
  959. 		onpopstate,
  960. 		onprogress,
  961. 		onratechange,
  962. 		onreset,
  963. 		onresize,
  964. 		onscroll,
  965. 		onsearch,
  966. 		onseeked,
  967. 		onseeking,
  968. 		onselect,
  969. 		onshow,
  970. 		onstalled,
  971. 		onstorage,
  972. 		onsubmit,
  973. 		onsuspend,
  974. 		ontimeupdate,
  975. 		ontoggle,
  976. 		onunload,
  977. 		onvolumechange,
  978. 		onwaiting,
  979. 		onwheel
  980. 	}
  981. }

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