Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C#

Yet Another Command Line Parser

Rate me:
Please Sign up or sign in to vote.
4.31/5 (8 votes)
5 Mar 2008CPOL 37.9K   909   41  
A simple to use C# Command Line parser.
//---------------------------------------------------------------------
/// Simple CommandLine Parser
/// Copyright (C) 2008  Chris Stoy
/// For questions or comments see the article on CodeProject (www.codeproject.com)
/// or email me at cstoy at nc.rr.com.
/// 
/// You are free to use this code in all commercial and non-commercial applications
/// as long as this copyright message is left intact.
/// Use this code at your own risk.  I take no responsibility if it should fail to
/// do anything you would expect it to do and it could, at any time, fail to function
/// in any manner.  You have the source code, make it do what you want.
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;

//---------------------------------------------------------------------
namespace Utility
{
    //---------------------------------------------------------------------
    /// <summary>
    /// Contains the parsed command line arguments.  This consists of two
    /// lists, one of argument pairs, and one of stand-alone arguments.
    /// </summary>
    public class CommandArgs
    {
        //---------------------------------------------------------------------
        /// <summary>
        /// Returns the dictionary of argument/value pairs.  
        /// </summary>
        public Dictionary<string, string> ArgPairs
        {
            get { return mArgPairs; }
        }
        Dictionary<string, string> mArgPairs = new Dictionary<string,string>();
    
        //---------------------------------------------------------------------
        /// <summary>
        /// Returns the list of stand-alone parameters.
        /// </summary>
        public List<string> Params
        {
            get { return mParams; }
        }
        List<string> mParams = new List<string>();
    }

    //---------------------------------------------------------------------
    /// <summary>
    /// Implements command line parsing
    /// </summary>
    public class CommandLine
    {
        //---------------------------------------------------------------------
        /// <summary>
        /// Parses the passed command line arguments and returns the result
        /// in a CommandArgs object.
        /// </summary>
        /// The command line is assumed to be in the format:
        /// 
        ///     CMD [param] [[-|--|\]&lt;arg&gt;[[=]&lt;value&gt;]] [param]
        /// 
        /// Basically, stand-alone parameters can appear anywhere on the command line.
        /// Arguments are defined as key/value pairs. The argument key must begin
        /// with a '-', '--', or '\'.  Between the argument and the value must be at
        /// least one space or a single '='.  Extra spaces are ignored.  Arguments MAY
        /// be followed by a value or, if no value supplied, the string 'true' is used.
        /// You must enclose argument values in quotes if they contain a space, otherwise
        /// they will not parse correctly.
        /// 
        /// Example command lines are:
        /// 
        /// cmd first -o outfile.txt --compile second \errors=errors.txt third fourth --test = "the value" fifth
        /// 
        /// <param name="args">array of command line arguments</param>
        /// <returns>CommandArgs object containing the parsed command line</returns>
        public static CommandArgs Parse(string[] args)
        {
            char[] kEqual = new char[] { '=' };
            char[] kArgStart = new char[] { '-', '\\' };

            CommandArgs ca = new CommandArgs();
            int ii = -1;
            string token = NextToken( args, ref ii );
            while ( token != null )
            {
                if (IsArg(token))
                {
                    string arg = token.TrimStart(kArgStart).TrimEnd(kEqual);

                    string value = null;

                    if (arg.Contains("="))
                    {
                        // arg was specified with an '=' sign, so we need
                        // to split the string into the arg and value, but only
                        // if there is no space between the '=' and the arg and value.
                        string[] r = arg.Split(kEqual, 2);
                        if ( r.Length == 2 && r[1] != string.Empty)
                        {
                            arg = r[0];
                            value = r[1];
                        }
                    }
                    
                    while ( value == null )
                    {
                        string next = NextToken(args, ref ii);
                        if (next != null)
                        {
                            if (IsArg(next))
                            {
                                // push the token back onto the stack so
                                // it gets picked up on next pass as an Arg
                                ii--;
                                value = "true";
                            }
                            else if (next != "=")
                            {
                                // save the value (trimming any '=' from the start)
                                value = next.TrimStart(kEqual);
                            }
                        }
                    }

                    // save the pair
                    ca.ArgPairs.Add(arg, value);
                }
                else if (token != string.Empty)
                {
                    // this is a stand-alone parameter. 
                    ca.Params.Add(token);
                }

                token = NextToken(args, ref ii);
            }

            return ca;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Returns True if the passed string is an argument (starts with 
        /// '-', '--', or '\'.)
        /// </summary>
        /// <param name="arg">the string token to test</param>
        /// <returns>true if the passed string is an argument, else false if a parameter</returns>
        static bool IsArg(string arg)
        {
            return (arg.StartsWith("-") || arg.StartsWith("\\"));
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Returns the next string token in the argument list
        /// </summary>
        /// <param name="args">list of string tokens</param>
        /// <param name="ii">index of the current token in the array</param>
        /// <returns>the next string token, or null if no more tokens in array</returns>
        static string NextToken(string[] args, ref int ii)
        {
            ii++; // move to next token
            while ( ii < args.Length )
            {
                string cur = args[ii].Trim();
                if (cur != string.Empty)
                {
                    // found valid token
                    return cur;
                }
                ii++;
            }

            // failed to get another token
            return null;
        }

    }
}

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
Software Developer (Senior)
United States United States
Professional game programmer for over 10 years. Doing my best to become a better programmer.

Comments and Discussions