Skip to main content

Parse and organize command line options using C#

This class will parse, organize and collect command line options. I couldn't find anything like it, so I wrote one. This works all the way down to .NET 1.1 if you are lucky enough to still be using that. Save this as ArgDictionary.cs, change the namespace as needed, and feel free to use it in your projects.
using System;
using System.Collections.Generic;

namespace Utilities
{
 /// 
 /// Implements a Dictionary object for handling command line options.
 /// Supports options with prefixes -, --, or /.
 /// Supports Boolean, String, or Int32 option values.
 /// String options are in the following format:
 ///  /stringOption value
 /// Int32 options are in the following format:
 ///  /intOption 200
 /// Boolean options are in the following format:
 ///  /boolOption
 /// NOTE: if the Boolean option is present in the command line, it is true.
 /// 
 /// Supports both a long and short version for each option (e.g. /a and /Account
 /// can be mapped to the same value).
 /// NOTE: When working with options in the code, always use the long version.
 /// NOTE: Options (short and long) are CASE SENSITIVE! unix4ever!
 /// 
 /// 
 /// Program.exe /boolOption /stringOption value /int 200 /h
 /// 
 /// static void Main(string[] args)
 /// {
 ///  ArgDictionary options = new ArgDictionary();
 ///  try
 ///   {
 ///    options.AddBooleanOption("h", "help");
 ///    options.AddBooleanOption("boolOption");
 ///    options.AddStringOption("stringOption");
 ///    options.AddInt32Option("i", "int");
 ///    options.ParseOptions(args);
 ///   }
 ///   catch (Exception ex)
 ///   {
 ///    PrintError("Error with the command line options.", ex);
 ///    Usage();
 ///    return;
 ///   }
 ///  }
 ///  
 ///  if (options.Count == 0 || options.ContainsKey("help"))
 ///  {
 ///   Usage();
 ///   return;
 ///  }
 ///
 ///  // Prompt for options the user may have forgotten
 ///  if (!options.ContainsKey("accountId"))
 ///   options.PromptForOption("accountId", typeof(String));
 ///  
 ///     // Use the options in your program
 ///  Int32 number = (Int32)options["int"];
 ///  Console.WriteLine("stringOption: " + (string)options["stringOption"]);
 /// }
 /// 
 class ArgDictionary: Dictionary
 {
  private Dictionary optionTypes;
  /// 
  /// Maps short options to the long version (we want to use the long version in code for readability)
  /// 
  private Dictionary optionShortMap;

  public ArgDictionary()
  {
   optionTypes = new Dictionary();
   optionShortMap = new Dictionary();
  }

  #region Add methods
  public void Add(string option, Type type)
  {
   optionTypes.Add(option, type);
  }

  public void Add(string shortOption, string longOption, Type type)
  {
   if (shortOption != longOption)
    optionShortMap.Add(shortOption, longOption);
   optionTypes.Add(longOption, type);
  }

  public void AddStringOption(string option)
  {
   optionTypes.Add(option, typeof(String));
  }

  public void AddStringOption(string shortOption, string longOption)
  {
   if (shortOption != longOption)
    optionShortMap.Add(shortOption, longOption);
   optionTypes.Add(longOption, typeof(String));
  }

  public void AddBooleanOption(string option)
  {
   optionTypes.Add(option, typeof(Boolean));
  }

  public void AddBooleanOption(string shortOption, string longOption)
  {
   if (shortOption != longOption)
    optionShortMap.Add(shortOption, longOption);
   optionTypes.Add(longOption, typeof(Boolean));
  }

  public void AddInt32Option(string option)
  {
   optionTypes.Add(option, typeof(Int32));
  }

  public void AddInt32Option(string shortOption, string longOption)
  {
   if (shortOption != longOption)
    optionShortMap.Add(shortOption, longOption);
   optionTypes.Add(longOption, typeof(Int32));
  }
  #endregion Add methods

  #region Option parsing methods
  /// 
  /// Parses the command line options. Accepts options with the following prefixes:
  /// - -- /
  /// 
  /// 
  /// options.ParseOptions(args);
  /// 
  /// The command line arguments
  public void ParseOptions(string[] args)
  {
   int i = 0;
   string option = string.Empty;
   string optionIn = string.Empty; // NOTE: this is ONLY for friendlier error messages if there is a problem with the option
   Type type = typeof(String);
   while (i < args.Length)
   {
    option = args[i];
    option = option.TrimStart(new char[] { '-', '/' }); // Accept parameters in format -param --param or /param
    optionIn = option;
    i++;

    // Get the short version if this is long
    if (optionShortMap.ContainsKey(option))
     option = optionShortMap[option];

    if (!optionTypes.ContainsKey(option))
     throw new ArgumentException("Invalid Option Found: " + optionIn, optionIn);

    type = optionTypes[option];

    if (type == typeof(String))
    {
     this.Add(option, args[i]);
     i++;
    }
    else if (type == typeof(Boolean))
    {
     this.Add(option, true);
    }
    else if (type == typeof(Int32))
    {
     string intOption = args[i];
     i++;
     try
     {
      this.Add(option, Int32.Parse(intOption));
     }
     catch (Exception ex)
     {
      throw new ArgumentException("Unable to parse Int32 Option: " + optionIn + " " + intOption, optionIn, ex);
     }
    }
    else
    {
     throw new ArgumentException("We don't support that type: " + optionIn, optionIn);
    } // if (type ==
   } // while
  }

  /// 
  /// Allows you to prompt the user for an option at runtime.
  /// 
  /// 
  /// options.PromptForOption("accountId", typeof(String));
  /// 
  /// This will print the following to the console:
  /// 
  /// accountId: 
  /// 
  /// Name of the option (long version)
  /// Option Type
  public void PromptForOption(string option, Type type)
  {
   Console.Write(option + ": ");
   string optionValue = Console.ReadLine();

   if (type == typeof(String))
   {
    this.Add(option, optionValue);
   }
   else if (type == typeof(Boolean))
   {
    this.Add(option, true);
   }
   else if (type == typeof(Int32))
   {
    try
    {
     this.Add(option, Int32.Parse(optionValue));
    }
    catch (Exception ex)
    {
     throw new ArgumentException("Unable to parse Int32 Option: " + option + " " + optionValue, option, ex);
    }
   }
   else
   {
    throw new ArgumentException("We don't support that type: " + option, option);
   } // if (type ==
  }
  #endregion Option parsing methods
 }
}
TODO: Create a function that will output usage text.

Comments

Popular posts from this blog

Running PowerShell commands from Linux

There are several options for running PowerShell commands from Linux. Run the PowerShell script over a REST interface Unless you need a remote shell, the easiest option is to set up a REST interface for your PowerShell scripts. More information here . Using the winrm Ruby Gem https://github.com/WinRb/WinRM Using a WS-Management client on Linux Set up Windows for remote access: https://github.com/Openwsman/openwsman/wiki/winrm-over-openwsman-setup Install OpenWSMAN on Linux: http://openwsman.github.io/ Use Openwsman Command-Line Client: https://github.com/Openwsman/openwsman/wiki/openwsman-command-line-client OR - Use Ruby client bindings: http://users.suse.com/~kkaempf/openwsman/ Install an SSH server on Windows Install a Salt Minion on Windows Install Salt Master on Linux Install Python on Windows Install Salt Minion on Windows Open firewall on Windows for Salt access On Linux, run: # salt "winServer" cmd.run "powersh...

How to make an HTTP request with PowerShell

If you are making an HTTP request to a RESTful web service, you can use the PowerShell  Invoke-RestMethod cmdlet. This provides a very simple HTTP REST interface, and will also format the result into a PowerShell object. If you would like to use your own functions, you can follow the instructions below. This is a helper function to format (indent) an XML response from a web service. function Format-XML { Param ([string]$xml) $out = New-Object System.IO.StringWriter $Doc=New-Object system.xml.xmlDataDocument $doc.LoadXml($xml) $writer=New-Object system.xml.xmltextwriter($out) $writer.Formatting = [System.xml.formatting]::Indented $doc.WriteContentTo($writer) $writer.Flush() $out.flush() Write-Output $out.ToString() } Here is the function to make the http call. It dumps the response data on the terminal and also returns it as a string to the caller. If there is an error it will dump the HTTP status code and comment on the terminal and return the re...

A simple IIS HTTP module to log request headers and post data

This is a simple http module that hijacks the incoming request and logs it to a file. Using this module prevents the application from getting the post data because the input stream can only be read once. With .NET 4.0 the module could be much smaller, and could allow the application to read the data. To compile this, create a new "Class Library" application called PostDataLogger. Most of this class is pieced together from stolen code (stack overflow, etc.) using System; using System.IO; using System.Web; /// /// Dump PostDataLogger.DLL in your bin, and put this in your web.config inside of /// /// /// /// public class SimpleLogger : IHttpModule { private HttpApplication _ctx; public void Init(HttpApplication context) { _ctx = context; context.BeginRequest += new EventHandler(Context_BeginRequest); } void Context_BeginRequest(object sender, EventArgs e) { string GUID = Guid.NewGuid().ToString(); string filename = @"d:\temp\adeber...