Click here to Skip to main content
15,896,730 members
Articles / Programming Languages / C#

Param.NET - An Automated Command-line Parameter Parser

Rate me:
Please Sign up or sign in to vote.
2.48/5 (11 votes)
19 Oct 2005CPOL3 min read 54.4K   407   24  
A library that allows developers to specify the parameters that they expect to receive from the command line and provides an easier way to access them
using System;
using System.Collections;
using System.Xml;
using System.Reflection;
using System.Configuration;

namespace Params
{
	public class ParamCollection
	{
		#region Internal Fields 

		internal string ShortControlString; // usually "/" or "-"
		internal string LongControlString; //usually "--"
		internal char[] AttribChars; // ' ' or '='
		internal char SeparatorChar; // ' ' - the separator betweeb the values of the same parameter

		internal bool AutoGenerateParams; // if unknown params are found, generate them and add them to the dictionary ?
			
		internal bool DefaultAllowMultipleValues;
		internal bool DefaultIsOptional;
		internal ParamType DefaultType;

		internal Hashtable hashtable;

		#endregion

		#region Dictionary Methods

		public Param this[string name]
		{
			get
			{
				return (Param)hashtable[name];
			}
		}

		public ICollection Names
		{
			get
			{
				return this.hashtable.Keys;
			}
		}

		public bool Contains(string key)
		{
			return hashtable.Contains(key);
		}

		internal void Add(Param p)
		{
			if(p.ShortName != null && p.ShortName != string.Empty)
				hashtable.Add(p.ShortName, p);
			if(p.LongName != null && p.LongName != string.Empty)
				hashtable.Add(p.LongName, p);
		}

		internal void Remove(string name)
		{
			Param p = (Param)hashtable[name];
			Remove(p);
		}

		internal void Remove(Param p)
		{
			foreach(string s in hashtable.Keys)
			{
				if(p == hashtable[s])
					hashtable.Remove(s);
			}
		}

		#endregion

		#region Constructor

		internal ParamCollection()
		{
			this.hashtable = new Hashtable();	
		}

		#endregion
	
		#region Singleton Related

		public static readonly ParamCollection ApplicationParameters;

		static ParamCollection()
		{
			try
			{
				ApplicationParameters = (ParamCollection)ConfigurationSettings.GetConfig("parameters");
			}
			catch
			{
				Console.WriteLine("An error occured while reading the configuration file. Please fix it and run the program again.");
				Environment.Exit(-1);
			}

			try
			{
				//TODO: Should optimize this, but it's only done once, no big performance hit here
				System.Text.StringBuilder sbCmdLine = new System.Text.StringBuilder();
				string []cmdargs = Environment.GetCommandLineArgs();
				for(int i=1; i<cmdargs.Length; i++)
				{
					sbCmdLine.Append(cmdargs[i]);
					sbCmdLine.Append(' ');
				}

				string cmdLine = sbCmdLine.ToString();

				int index = 0;
				while(index < cmdLine.Length && char.IsWhiteSpace(cmdLine[index]))
					index++;

				while(index < cmdLine.Length)
				{
					Param p = null;

					//-1 is none -> no parameter found, 0 is short parameter, 1 is long parameter
					int paramLength = Helper.BeginsWith(cmdLine, index, ApplicationParameters.LongControlString, ApplicationParameters.ShortControlString);
					if(paramLength != -1)//a parameter is there
					{
						index += (paramLength == 1 ? ApplicationParameters.ShortControlString.Length : ApplicationParameters.LongControlString.Length);
						int nameEndIndex = cmdLine.IndexOfAny(ApplicationParameters.AttribChars, index);
						if(nameEndIndex == -1)
							nameEndIndex = cmdLine.Length-1;

						string name = cmdLine.Substring(index, nameEndIndex-index).Trim();
						p = ApplicationParameters[name];

						if(p == null)
						{
							if(ApplicationParameters.AutoGenerateParams)
							{
								p = new Param(name, null, ApplicationParameters);
								ApplicationParameters.Add(p);
							}
							else
							{
								throw new ParameterException("Invalid parameter specified");
							}
						}

						if((paramLength == 0 && p.LongName != name) || (paramLength == 1 && p.ShortName != name))
							throw(new ParameterException("Cannot parse command line"));

						index = nameEndIndex+1;
					}
					else
					{
						foreach(Param pd in ApplicationParameters.hashtable.Values)
						{
							if(pd.IsDefault)
							{
								p = pd;
								break;
							}
						}

						if(p == null)
						{
					
							if(ApplicationParameters.AutoGenerateParams)
							{
								p = new Param("_default_", null, true, true);
								ApplicationParameters.Add(p);
							}
							else
							{
								throw new ParameterException("Invalid parameter specified");
							}
						}
					}

					//time to read the value of the parameter
					int valueEndIndex = cmdLine.Length;
					string strValue = string.Empty;

					//trim all the white spaces and attrib chars
					string attribString = new String(ApplicationParameters.AttribChars);
					while(index < cmdLine.Length && (char.IsWhiteSpace(cmdLine[index]) || (attribString.IndexOf(cmdLine[index]) != -1)))
						index++;

                    if(index < cmdLine.Length)
					{
						valueEndIndex = Helper.GetNextParamIndex(cmdLine, index, ApplicationParameters.ShortControlString, ApplicationParameters.LongControlString);								
						strValue = cmdLine.Substring(index, valueEndIndex - index).Trim();
					}

					//TODO: split strValue by separatorChar and add all the values

					if(strValue == string.Empty)
					{
						if(p.DefaultValue != null)
						{
							strValue = p.DefaultValue.ToString();
						}
						else
						{
							while(valueEndIndex < cmdLine.Length && char.IsWhiteSpace(cmdLine[valueEndIndex]))
								valueEndIndex++;

							if(cmdLine.Substring(valueEndIndex, ApplicationParameters.LongControlString.Length) == ApplicationParameters.LongControlString)
								valueEndIndex += ApplicationParameters.LongControlString.Length;

							if(cmdLine.Substring(valueEndIndex, ApplicationParameters.ShortControlString.Length) == ApplicationParameters.ShortControlString)
								valueEndIndex += ApplicationParameters.ShortControlString.Length;
							
							valueEndIndex = Helper.GetNextParamIndex(cmdLine, valueEndIndex, ApplicationParameters.ShortControlString, ApplicationParameters.LongControlString);
									
							strValue = cmdLine.Substring(index, valueEndIndex-index);
						}				
					}

					if(p.AllowMultipleValues)
						p.AddValue(strValue);
					else
						p.SetValue(strValue);
					
					index = valueEndIndex;

					while(index < cmdLine.Length && char.IsWhiteSpace(cmdLine[index]))
						index++;
				}

				ApplicationParameters.Validate();
			}
			catch//(Exception ex)
			{
				ApplicationParameters.PrintUsage();
				Environment.Exit(-1);
			}
		}

		#endregion

		public string GetUsage()
		{
			System.Text.StringBuilder sb = new System.Text.StringBuilder(1024);
			//TODO: Optimize this
			ArrayList list = new ArrayList();				

			if(DefaultIsOptional)
                sb.Append("All parameters are optional unless specified otherwise.\n");
			else
				sb.Append("All parameters are mandatory unless specified otherwise.\n");

			foreach(Param p in hashtable.Values)
			{
				if(list.Contains(p))
					continue;
				else
					list.Add(p);

				sb.Append("\n");
				if(p.ShortName != null)
				{
					sb.Append(ShortControlString);
					sb.Append(p.ShortName);
				}
				if(p.LongName != null)
				{
					if(p.ShortName != null)
						sb.Append(", ");
					sb.Append(LongControlString);
					sb.Append(p.LongName);
				}
				sb.Append("\t:  ");
				
				sb.Append("Type: ");
				sb.Append(p.Type.ToString());
				sb.Append(". ");

				if(p.DefaultValue != null)
				{
					sb.Append("Default value: ");
					sb.Append(p.DefaultValue.ToString());
					sb.Append(". ");
				}

				
				if(p.IsOptional && !DefaultIsOptional)
					sb.Append("This parameter is optional. ");
				if(!p.IsOptional && DefaultIsOptional)
					sb.Append("This parameter is mandatory. ");

				if(p.Description != null)
				{
					sb.Append("Description: ");	
					sb.Append(p.Description);
					sb.Append(" ");
				}
				//sb.Append("\n");
			}

			sb.Append("\n\n");

			return sb.ToString();
		}

		public void PrintUsage()
		{
			System.Console.Write(GetUsage());
		}

		public bool Validate()
		{
			foreach(Param p in hashtable.Values)
			{
				if(!p.IsOptional && p.Value == null)
					throw new ParameterException("Mandatory parameter not specified");

				//TODO: A lot more checking to do.
			}

			return true;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Romania Romania
Just you average programmer geek from Romania. Student at Faculty of Computer Science, Al. I. Cuza University Iasi, Romania.

Comments and Discussions