Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Param.NET - An Automated Command-line Parameter Parser

, 19 Oct 2005 CPOL
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)

Share

About the Author

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 20 Oct 2005
Article Copyright 2005 by eugen.anghel
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid