<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Rob Reynolds - The Fervent Coder : Mono</title><link>http://devlicio.us/blogs/rob_reynolds/archive/tags/Mono/default.aspx</link><description>Tags: Mono</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Command Line Parsing on Windows with Mono.Options</title><link>http://devlicio.us/blogs/rob_reynolds/archive/2009/11/22/command-line-parsing-with-mono-options.aspx</link><pubDate>Sun, 22 Nov 2009 18:41:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:53997</guid><dc:creator>Rob Reynolds</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/rsscomments.aspx?PostID=53997</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_reynolds/commentapi.aspx?PostID=53997</wfw:comment><comments>http://devlicio.us/blogs/rob_reynolds/archive/2009/11/22/command-line-parsing-with-mono-options.aspx#comments</comments><description>&lt;p&gt;When you have command line arguments to parse (whether in Windows or Linux), the place to look is &lt;a href="http://mono-project.com/Main_Page" target="_blank"&gt;Mono.Options&lt;/a&gt;. To date, I have not found anything better to get the job done. It is a single &lt;a href="http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/Mono.Options/Mono.Options/Options.cs?revision=116877&amp;amp;view=markup" target="_blank"&gt;C# file&lt;/a&gt; if you do not want to download the entire Mono Library to use it. I was first introduced in &lt;a href="http://tirania.org/blog/archive/2008/Oct-14.html" target="_blank"&gt;Mono 2.2&lt;/a&gt;. The equivalent product is &lt;a href="http://www.ndesk.org/Options" target="_blank"&gt;NDesk.Options&lt;/a&gt; by Jonathan Pryor. His single Options.cs file has been &lt;a href="http://tirania.org/blog/archive/2009/Feb-21.html" target="_blank"&gt;implemented&lt;/a&gt; as Mono.Options.&lt;/p&gt;  &lt;p&gt;To demonstrate how easy command line parsing can be, I’m going to show you is part of the source for &lt;a href="http://projectroundhouse.org/" target="_blank"&gt;RoundhousE DB Migrations&lt;/a&gt;. RoundhousE has 2 required arguments and 22 total arguments. So I needed something that would make that super easy. And the ramp up time had to be less than 10 minutes. Mono.Options wins on both of these requirements.&lt;/p&gt;  &lt;h4&gt;&lt;strong&gt;&lt;u&gt;Setting Your Command Line Options&lt;/u&gt;&lt;/strong&gt;&lt;/h4&gt;  &lt;pre class="c#" name="code"&gt;OptionSet option_set = new OptionSet()
    .Add(&amp;quot;?|help|h&amp;quot;, &amp;quot;Prints out the options.&amp;quot;, option =&amp;gt; help = option != null)
    .Add(&amp;quot;d=|db=|database=|databasename=&amp;quot;,
       &amp;quot;REQUIRED: DatabaseName - The database you want to create/migrate.&amp;quot;,
       option =&amp;gt; configuration.DatabaseName = option)
    .Add(&amp;quot;f=|files=|sqlfilesdirectory=&amp;quot;,
       &amp;quot;REQUIRED: SqlFilesDirectory - The directory where your SQL scripts are.&amp;quot;,
       option =&amp;gt; configuration.SqlFilesDirectory = option)
    .Add(&amp;quot;s=|server=|servername=|instance=|instancename=&amp;quot;,
       string.Format(&amp;quot;ServerName - The server and instance you would like to run on. (local) and (local)\\SQL2008 are both valid values. Defaults to \&amp;quot;{0}\&amp;quot;.&amp;quot;,
           ApplicationParameters.default_server_name),
       option =&amp;gt; configuration.ServerName = option)
;&lt;/pre&gt;

&lt;p&gt;I am setting up the arguments here and what they will be assigned to. The first item in &lt;strong&gt;.Add &lt;/strong&gt;is the command line argument (parameter). For more than one, you add a pipe “&lt;strong&gt;|&lt;/strong&gt;”. &lt;a href="http://www.jprl.com/Blog/" target="_blank"&gt;Jonathan Pryor&lt;/a&gt; mentions in his &lt;a href="http://www.jprl.com/Blog/archive/development/mono/2008/Jan-07.html" target="_blank"&gt;“So you want to parse a command line…” post&lt;/a&gt; that parameters are passed following ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Parameters of the form: &lt;tt&gt;-flag&lt;/tt&gt;, &lt;tt&gt;--flag&lt;/tt&gt;, &lt;tt&gt;/flag&lt;/tt&gt;, &lt;tt&gt;-flag=value&lt;/tt&gt;, &lt;tt&gt;--flag=value&lt;/tt&gt;, &lt;tt&gt;/flag=value&lt;/tt&gt;, &lt;tt&gt;-flag:value&lt;/tt&gt;, &lt;tt&gt;--flag:value&lt;/tt&gt;, &lt;tt&gt;/flag:value&lt;/tt&gt;, &lt;tt&gt;-flag value&lt;/tt&gt;, &lt;tt&gt;--flag value&lt;/tt&gt;, &lt;tt&gt;/flag value&lt;/tt&gt;. &lt;/li&gt;

  &lt;li&gt;&amp;quot;boolean&amp;quot; parameters of the form: &lt;tt&gt;-flag&lt;/tt&gt;, &lt;tt&gt;--flag&lt;/tt&gt;, and &lt;tt&gt;/flag&lt;/tt&gt;. Boolean parameters can have a `&lt;tt&gt;+&lt;/tt&gt;&amp;#39; or `&lt;tt&gt;-&lt;/tt&gt;&amp;#39; appended to explicitly enable or disable the flag (in the same fashion as &lt;tt&gt;mcs -debug+&lt;/tt&gt;). For boolean callbacks, the provided value is non-&lt;tt&gt;null&lt;/tt&gt; for enabled, and &lt;tt&gt;null&lt;/tt&gt; for disabled. &lt;/li&gt;

  &lt;li&gt;&amp;quot;value&amp;quot; parameters with a required value (append `&lt;tt&gt;=&lt;/tt&gt;&amp;#39; to the option name) or an optional value (append `&lt;tt&gt;:&lt;/tt&gt;&amp;#39; to the option name). The option value can either be in the current option (&lt;tt&gt;--opt=value&lt;/tt&gt;) or in the following parameter (&lt;tt&gt;--opt value&lt;/tt&gt;). The actual value is provided as the parameter to the callback delegate, unless it&amp;#39;s (1) optional and (2) missing, in which case &lt;tt&gt;null&lt;/tt&gt; is passed. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second item in &lt;strong&gt;.Add&lt;/strong&gt; is description. When you want to provide information about the argument, put a nice description in here. If you take a look at my last &lt;strong&gt;.Add&lt;/strong&gt;, I have set the description to “ServerName – The server and instance you would like to run on. (local) and (local)\SQL2008 are both valid values. Defaults to ‘(local)’.” It gives enough information to allow someone to understand what is going on. It also lets you know that there is a default setting.&lt;/p&gt;

&lt;p&gt;The third item in &lt;strong&gt;.Add&lt;/strong&gt; is what you want the argument set to when found. With the second &lt;strong&gt;.Add&lt;/strong&gt; I am setting &lt;strong&gt;configuration.DatabaseName&lt;/strong&gt; to the argument’s (&lt;strong&gt;option&lt;/strong&gt;) value.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;&lt;u&gt;Parsing the Command Line&lt;/u&gt;&lt;/strong&gt;&lt;/h4&gt;

&lt;pre class="c#" name="code"&gt;try
{
    option_set.Parse(args);
}
catch (OptionException)
{
    show_help(&amp;quot;Error - usage is:&amp;quot;, option_set);
}&lt;/pre&gt;

&lt;p&gt;This is how easy it is to parse the command line. Once your OptionSet is ready, all you need to do is call Parse and pass it the arguments.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;&lt;u&gt;Showing Help&lt;/u&gt;&lt;/strong&gt;&lt;/h4&gt;

&lt;pre class="c#" name="code"&gt;if (help)
{
    const string usage_message = 
        &amp;quot;rh.exe /d[atabase] VALUE /[sql]f[ilesdirectory] VALUE &amp;quot; +
        &amp;quot;[ /s[ervername] VALUE ]&amp;quot;;
    show_help(usage_message, option_set);
}&lt;/pre&gt;

&lt;p&gt;If the user asks for help, you set help to true. Then you set up a usage message and pass that to a function that shows both your message and the descriptions of all the arguments.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;&lt;u&gt;Checking For Required Items&lt;/u&gt;&lt;/strong&gt;&lt;/h4&gt;

&lt;pre class="c#" name="code"&gt;if (configuration.DatabaseName == null)
{
    show_help(&amp;quot;Error: You must specify Database Name (/d).&amp;quot;, option_set);
}&lt;/pre&gt;

&lt;p&gt;When you have required items, you can check to see if the user has sent in an argument properly. Then if not, you send them to the show_help function with a message about a necessary argument not being set.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;&lt;u&gt;Show Help Function&lt;/u&gt;&lt;/strong&gt;&lt;/h4&gt;

&lt;pre class="c#" name="code"&gt;public static void show_help(string message, OptionSet option_set)
{
    Console.Error.WriteLine(message);
    option_set.WriteOptionDescriptions(Console.Error);
    Environment.Exit(-1);
}&lt;/pre&gt;

&lt;p&gt;In show_help you first show the message, then you write out the options and their descriptions.&lt;/p&gt;

&lt;p&gt;That’s all great, but what does it look actually like?&amp;#160; Let’s run “rh /?” and see what we get for output.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;rh.exe /d[atabase] VALUE /[sql]f[ilesdirectory] VALUE [ /s[ervername] VALUE ] 
    &lt;br /&gt;&amp;#160; -?, --help, -h&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Prints out the options. 

    &lt;br /&gt;&amp;#160; -d, --db, --database, --databasename=VALUE 

    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; REQUIRED: DatabaseName - The database you want to create/migrate. 

    &lt;br /&gt;&amp;#160; -f, --files, --sqlfilesdirectory=VALUE 

    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; REQUIRED: SqlFilesDirectory - The directory where your SQL scripts are. 

    &lt;br /&gt;&amp;#160; -s, --server, --servername, --instance, --instancename=VALUE 

    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ServerName - The server and instance you would like to run on. (local) and (local)\SQL2008 are both valid values. Defaults to &amp;quot;(local)&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;&lt;strong&gt;&lt;u&gt;Conclusion&lt;/u&gt;&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Mono.Options definitely wins the Rock Star Tool Award*! Mono.Options makes what would be a nightmare to parse a joy and accomplished without a lot of work. If you have more than one argument to parse with your command line, I would definitely give it a look. &lt;/p&gt;

&lt;p&gt;* The rock star tool award means a tool is very powerful but takes less than 10 minutes to learn how to use.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I am always on the lookout for rock star tools that make it easier and more enjoyable to accomplish things in development that need to be done. If you have a rock star that you want me to look at, please feel free to contact me. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=53997" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/Mono/default.aspx">Mono</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/RoundhousE/default.aspx">RoundhousE</category><category domain="http://devlicio.us/blogs/rob_reynolds/archive/tags/HowTo/default.aspx">HowTo</category></item></channel></rss>