Friday, March 26, 2010

Commandline HelperClass in C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;

namespace Kurapaty.Solutions.Utils
{
	/// 
	/// Commandline Arguments Parser class
	/// 
	/// 
	/// Source: 
	/// 
	public class Arguments
	{
		/// 
		/// Splits the command line. When main(string[] args) is used escaped quotes (ie a path “c:\folder\”)
		/// Will consume all the following command line arguments as the one argument. 
		/// This function ignores escaped quotes making handling paths much easier.
		/// 
		/// The command line.		/// 
		public static string[] SplitCommandLine(string commandLine)
		{
			var translatedArguments = new StringBuilder(commandLine);
			var escaped = false;
			for (var i = 0; i < translatedArguments.Length; i++)
			{
				if (translatedArguments[i] == '"')
				{
					escaped = !escaped;
				}
				if (translatedArguments[i] == ' ' && !escaped)
				{
					translatedArguments[i] = '\n';
				}
			}

			var toReturn = translatedArguments.ToString().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (var i = 0; i < toReturn.Length; i++)
			{
				toReturn[i] = RemoveMatchingQuotes(toReturn[i]);
			}
			return toReturn;
		}

		public static string RemoveMatchingQuotes(string stringToTrim)
		{
			var firstQuoteIndex = stringToTrim.IndexOf('"');
			var lastQuoteIndex = stringToTrim.LastIndexOf('"');
			while (firstQuoteIndex != lastQuoteIndex)
			{
				stringToTrim = stringToTrim.Remove(firstQuoteIndex, 1);
				stringToTrim = stringToTrim.Remove(lastQuoteIndex - 1, 1); //-1 because we’ve shifted the indicies left by one
				firstQuoteIndex = stringToTrim.IndexOf('"');
				lastQuoteIndex = stringToTrim.LastIndexOf('"');
			}

			return stringToTrim;
		}

		private readonly Dictionary> _parameters;
		private string _waitingParameter;

		public Arguments(IEnumerable arguments)
		{
			_parameters = new Dictionary>();

			string[] parts;

			//Splits on beginning of arguments ( – and — and / )
			//And on assignment operators ( = and : )
			var argumentSplitter = new Regex(@"^-{1,2}|^/|=|:", RegexOptions.IgnoreCase | RegexOptions.Compiled);

			foreach (var argument in arguments)
			{
				parts = argumentSplitter.Split(argument, 3);
				switch (parts.Length)
				{
					case 1:
						AddValueToWaitingArgument(parts[0]);
						break;
					case 2:
						AddWaitingArgumentAsFlag();

						//Because of the split index 0 will be a empty string
						_waitingParameter = parts[1];
						break;
					case 3:
						AddWaitingArgumentAsFlag();

						//Because of the split index 0 will be a empty string
						string valuesWithoutQuotes = RemoveMatchingQuotes(parts[2]);

						AddListValues(parts[1], valuesWithoutQuotes.Split(','));
						break;
				}
			}

			AddWaitingArgumentAsFlag();
		}

		private void AddListValues(string argument, IEnumerable values)
		{
			foreach (var listValue in values)
			{
				Add(argument, listValue);
			}
		}

		private void AddWaitingArgumentAsFlag()
		{
			if (_waitingParameter == null) return;

			AddSingle(_waitingParameter, "true");
			_waitingParameter = null;
		}

		private void AddValueToWaitingArgument(string value)
		{
			if (_waitingParameter == null) return;

			value = RemoveMatchingQuotes(value);

			Add(_waitingParameter, value);
			_waitingParameter = null;
		}

		/// 
		/// Gets the count.
		/// 
		/// The count.
		public int Count
		{
			get
			{
				return _parameters.Count;
			}
		}

		/// 
		/// Adds the specified argument.
		/// 
		/// The argument.		/// The value.		public void Add(string argument, string value)
		{
			if (!_parameters.ContainsKey(argument))
				_parameters.Add(argument, new Collection());

			_parameters[argument].Add(value);
		}

		public void AddSingle(string argument, string value)
		{
			if (!_parameters.ContainsKey(argument))
				_parameters.Add(argument, new Collection());
			else
				throw new ArgumentException(string.Format("Argument {0} has already been defined", argument));

			_parameters[argument].Add(value);
		}

		public void Remove(string argument)
		{
			if (_parameters.ContainsKey(argument))
				_parameters.Remove(argument);
		}

		/// 
		/// Determines whether the specified argument is true.
		/// 
		/// The argument.		/// 
		///     true if the specified argument is true; otherwise, false.
		/// 
		public bool IsTrue(string argument)
		{
			AssertSingle(argument);

			var arg = this[argument];

			return arg != null && arg[0].Equals("true", StringComparison.OrdinalIgnoreCase);
		}

		public bool IsExists(string argument)
		{
			return IsTrue(argument);
		}

		private void AssertSingle(string argument)
		{
			if (this[argument] != null && this[argument].Count > 1)
				throw new ArgumentException(string.Format("{0} has been specified more than once, expecting single value", argument));
		}

		public string Single(string argument)
		{
			AssertSingle(argument);

			//only return value if its NOT true, there is only a single item for that argument
			//and the argument is defined
			if (this[argument] != null && !IsTrue(argument))
				return this[argument][0];

			return null;
		}

		public bool Exists(string argument)
		{
			return (this[argument] != null && this[argument].Count > 0);
		}

		/// 
		/// Gets the  with the specified parameter.
		/// 
		/// 
		public Collection this[string parameter]
		{
			get
			{
				return _parameters.ContainsKey(parameter) ? _parameters[parameter] : null;
			}
		}
	}
}

Usage:
		private bool ProcessCommandLineParameters()
		{
			// Usage: -ec -source:"C:\Temp\formDefinition.txt" -target:"C:\Temp\formDefinition.enc"
			try
			{
				Arguments parser = new Arguments(Arguments.SplitCommandLine(Environment.CommandLine));

				if (parser.IsExists("help") || parser.IsExists("?"))
					ShowUsageHelpMessage();

				if (parser.Exists("source") && 1 == parser["source"].Count) tbSource.Text = parser.Single("source");
				if (parser.Exists("target") && 1 == parser["target"].Count) tbTarget.Text = parser.Single("target");

				if (parser.Exists("ec") && parser.IsTrue("ec"))
				{
					button1_Click(null, null);
					return true;
				}
				if (parser.Exists("dc") && parser.IsTrue("dc"))
				{
					button2_Click(null, null);
					return true;
				}
			}
			catch (Exception)
			{
				MessageBox.Show("Invalid commandline arguments passed. Please use GUI or type \"help\" at commandline.",
				                "Commandline processor", MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			return false;
		}

No comments: