Click here to Skip to main content
Email Password   helpLost your password?

Introduction

When writing applications that require run-time information supplied by a command shell, the best way to communicate the additional information to your executable is via command line parameters. You frequently have to write code to parse the command line parameters looking for specific information to customize execution of your application. I'll show you how to write a reusable library callable from your code to expose the command line arguments as name-value pairs, allowing you to avoid having to write tedious parsing code over and over again in different projects.

Background

In the "C" family of languages, including C, C++ and C#, command line information is conveyed by the command shell to the running executable using a string array passed to the static main() function. The string array is composed of the text that followed the executable name, chopped up into sub-strings delimited by the space character. See the image above.

If you force your users to specify all possible parameters on every execution in a specific order, you ease your parameter reading grief and can just jump to specific indexes of the args[] array to get the parameter values. If you have any consideration at all for your users and allow them to specify parameters in any order they choose, or allow your users to specify optional parameters, you have to write code to identify parameters by their name and then to read the value associated with that variable.

There are several hundred examples of code that does similar work written in C and C++, and a few written in C# (hence the project name prefix "Yet Another..."). This code is different from the others on CodeProject in that it allows you to specify additional information to the parsing process to allow for idiosyncrasies in your command line syntax, and also to allow for the run-time parameters supplied to your applications to be removed into separate files for organization and easy re-use.

Using the code

The project consists of three classes enclosed in a single source code file:

ArgParser is the main class you instantiate, handing the constructor the args string array passed to your executable. Optionally, you can specify the character you want to use to mark your argument names and the character you want to use to separate your variable names from their values. It's really a matter of style, but you can configure the class to parse arguments that look like this:

c:\>YACLAPTester.exe /user:kim /test:yes /verbose

or like this:

c:\>YACLAPTester.exe -user=kim -test=yes -verbose

Just pass '/' and ':' to the ArgParser constructor used by your YACLAPTester application in the first case (or don't specify any characters -> these are the defaults) or '-' and '=' to the constructor in the latter case.

The VVPair class holds the name of a variable (user, test and verbose in the examples above) and its value (Kim, yes and a zero length string above). The VVPairs class is a collection class of these custom variable-value pair objects. I considered using one of the intrinsic name-value pair types like StringDictionary and DictionaryEntry but decided against it. The slight amount of extra code allows you to be more flexible in processing.

When instantiated, the ArgParser constructor starts a two-phase process.

Phase I

The constructor iterates over the string array, and compares the initial character of each string in the array to two characters:

You'll be in good company if you support command parameter files. Microsoft is using this technique in supplying parameters to the C# 2.0 command line compiler through response file specifiers. They use files that are named *.rsp, but I'm not fussy about the extension here.

Phase II

Once phase I is complete, the ArrayList is full of the parameters found in the string array (and any expanded response files). The constructor will then loop through the ArrayList and examine each string. If the string starts with the variable specifier character, it will parse it into a new VVPair object, separating out the name of the variable from the value by the valueDelimiter character parameter, and add it to the VVPairs collection.

Once the VVPairs collection is populated at the end of the ArgParser constructor, you can allow the variables to be read by exposing an indexer property on the ArgParser class that returns a VVPair object based on a string passed to it. When I implemented the indexer property, I chose to return a new VVPair object if the name of the variable was not found in the collection, rather than null so you don't have to constantly test for uninitialized objects, and your code can look like this:

if (argParser["MyVariable"].Value == "true") {
   // Do some processing here

}

rather than like this:

VVPair pair = argParser["MyVariable"];
if (pair != null) {
   if (pair.Value == "true") {
      // Do some processing here

   }
}

Just compile the library, include it in your project (Console or Windows) and you can provide as much flexibility as your users need in initializing your application. The ArgParser class implements IDisposable, so just put it in a using{} block and it will clean up after itself nicely.

Points of interest

Nothing fancy about this code. Just drudge code that you've probably written a thousand times before.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralI use the class, but....
arie_b16
5:19 27 Sep '06  
The Dispose implementation is poor.
You dont need to implement dispose in this case, and if you need Dispose,
see the "Dispose Pattern".
Any case - tnx for the contribution.


GeneralSupport for command line switches
eulernt
15:02 12 Jul '06  
I was about to add code to handle command line switches (arguments with only a variable, no value, an on/off sort of thing) but I discovered that there is already code to support this (sort of). The problem (as I saw it) was that because a new VVPair was created if you attempted to get the value of a variable that didn't exist, it was difficult to check if a variable was given with no value, since in both cases, you would get an empty string back. However, it is possible to use the built in method Exists to determine if a command line switch was used. It means that for switches, you need to handle them slightly different than for normal variable/value pairs, but it is still possible and works well.
GeneralGreat Artical
tareqGamal
3:42 23 Jan '06  
thank u Very much about this artical ,
about my code :
I develop program which takes array of paths of files And Directories once and then analysis them inside the program
which can't done by this way ,
for example :
i want to pass :
c:\pics d:\Docs and Settings \my folder c:\MyFile

which come in the program as :
arg[0] = c:\pics
arg[1] =d:\docs
arg[2] =and
arg[3] = settings
and so on


expected :
arg[0] =c:\pics
arg[1] =d:\Docs and Settings \my folder
and so on

have i repair it inside the code?
if yes.. how ?

welcome for any comments , Questions
GeneralRe: Great Artical
eulernt
12:31 12 Jul '06  
I would actually treat this as a documentation issue. If you surround your path with quotes, it populates the arguments correctly. For example, using - and = as your delimiters you would specify:

yourprogram -path="D:\Documents and Settings"

and your arguments array would be properly populated. Hope this helps.
Generalvalidating args
Ben Incani
20:28 28 Sep '05  
because VVPairs is private there is no way to validate the args...

// check all arguments against a know list
string [] valid_args = new string [] {"xmlpath", "aldpath", "clone_to", "record_limit"};
foreach(string arg in args) {
     log.Info("check arg: " + arg);
     bool arg_ok = false;
     foreach(string valid_arg in valid_args) {
          arg_ok = arg.StartsWith("-" + valid_arg);
          if (arg_ok) {
               break;
          }
     }
     if (!arg_ok) {
          throw(new Exception("invalid arg; " + arg));
     }
}
GeneralRe: validating args
Mike Russo
8:26 10 Jul '06  
I took Ben's idea and implemented it as a new method of the ArgParser class. After instantiating ArgParser, call the IsValidCommandLine() method, specifying an array of all valid parameters. You will get back a boolean with the result of the validation. If false, the new BadArgs ArrayList property will provide all of the unknown arguments. Note that arguments improperly entered without the argDelimiter character are ignored by the ArgParser constructor and consequently will not be listed in BadArgs.

Here are my additions to the ArgParser class in ArgParser.cs:

// region Private Members
private ArrayList badArgs = new ArrayList();

// region Public Methods
/// /// Function to determine if all parameters found on command line are valid.
///
/// Array of valid parameters. /// True if all are valid, false otherwise. public bool IsValidCommandLine(string[] validParams)
{
bool result = true;
try {
foreach (VVPair pair in _pairs)
{
if (Array.IndexOf(validParams, pair.Variable) < 0)
{
result = false;
this.badArgs.Add(pair.Variable);
}
}
}
catch {
result = false;
}
return result;
}

// region Public Properties
/// /// List of all unrecognized command line arguments following invocation of IsValidCommandLine().
///
public ArrayList BadArgs
{
get
{
return this.badArgs;
}
}
Here is a sample usage:
            using (ArgParser argParser = new ArgParser(args))
{
if (argParser.IsValidCommandLine(new string[] { "limit", "delay" }))
{
// do something with your args
}
else {
Console.WriteLine("Invalid command line - Unknown arguments: ");
foreach (string arg in argParser.BadArgs)
{
Console.Write("{0} ", arg);
}
Console.WriteLine();
}
}

GeneralYACLAPTester.exe
AMFXG
9:25 27 Jan '05  
Can you upload the source code for the example program listed in the image example?

Thanks,

AG
GeneralRe: YACLAPTester.exe
Sean Michael Murphy
10:26 27 Jan '05  
Hey AG
I've uploaded a test project to show how to exercise the library. It prints to the console the values for /user and /demo parameters, and whether a contrived /verbose switch is present. It also includes a sample rst file to play with.

If you run the test project from the IDE, remember to add your command line arguments to the Project Properties -> Configuration Properties -> Debugging -> Start Options -> Command Line Arguments section.

Share and enjoy.
Sean


Last Updated 2 Jan 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010