Mono 2.2 Feature: Mono.Options

by Miguel de Icaza

In the upcoming Mono 2.2 release we will be distributing Jonathan Pryor's most excellent Mono.Options library.

Mono.Options is a beautiful command line parsing library. It is small, succinct, a joy to use, easy and powerful, all in one.

It is one of those libraries that does more with less. Something that every programmer aspires to write, but that we seldom achieve.

It has also struck a good balance for Unix and Windows developers as options can be used on both systems, and map well to practices on both systems. It took a long time to get the right "blend" of parsing, but I think Jonathan has achieved it.

Consider this example:


using System;
using System.Collections.Generic;
using NDesk.Options;

class Test {
    static int verbosity;

    public static void Main (string[] args)
    {
        bool show_help = false;
        List names = new List ();
        int repeat = 1;

        var p = new OptionSet () {
            { "n|name=", "the name of someone to greet.",
              v => names.Add (v) },
            { "r|repeat=", "the number of times to repeat the greeting.",
              (int v) => repeat = v },
            { "v", "increase debug message verbosity",
              v => { if (v != null) ++verbosity; } },
            { "h|help",  "show this message and exit", 
              v => show_help = v != null },
        };

        List extra;
        try {
            extra = p.Parse (args);
        }
        catch (OptionException e) {
            Console.Write ("greet: ");
            Console.WriteLine (e.Message);
            Console.WriteLine ("Try `greet --help' for more information.");
            return;
        }

        if (show_help) {
            ShowHelp (p);
            return;
        }

        string message;
        if (extra.Count > 0) {
            message = string.Join (" ", extra.ToArray ());
            Debug ("Using new message: {0}", message);
        }
        else {
            message = "Hello {0}!";
            Debug ("Using default message: {0}", message);
        }

        foreach (string name in names) {
            for (int i = 0; i < repeat; ++i)
                Console.WriteLine (message, name);
        }
    }

    static void ShowHelp (OptionSet p)
    {
        Console.WriteLine ("Usage: greet [OPTIONS]+ message");
        Console.WriteLine ("Greet a list of individuals with an optional message.");
        Console.WriteLine ("If no message is specified, a generic greeting is used.");
        Console.WriteLine ();
        Console.WriteLine ("Options:");
        p.WriteOptionDescriptions (Console.Out);
    }

    static void Debug (string format, params object[] args)
    {
        if (verbosity > 0) {
            Console.Write ("# ");
            Console.WriteLine (format, args);
        }
    }
}
	

And here is an example of its use:

$ mono greet.exe --help
Usage: greet [OPTIONS]+ message
Greet a list of individuals with an optional message.
If no message is specified, a generic greeting is used.

Options:
  -n, --name=VALUE           the name of someone to greet.
  -r, --repeat=VALUE         the number of times to repeat the greeting.
  -v                         increase debug message verbosity
  -h, --help                 show this message and exit

$ mono greet.exe -v- -n A -name=B --name=C /name D -nE
Hello A!
Hello B!
Hello C!
Hello D!
Hello E!

$ mono greet.exe -v -n E custom greeting for: {0}
# Using new message: custom greeting for: {0}
custom greeting for: E

$ mono greet.exe -r 3 -n A
Hello A!
Hello A!
Hello A!

$ mono greet.exe -r not-an-int
greet: Could not convert string `not-an-int' to type Int32 for option `-r'.
Try `greet --help' for more information.

	

He has also documented it thoroughly.

Where possible (new tools being written, or tools that have a similar command line structure that is compatible) we will be switching to this command line parsing library.

The library is small, so developers should include a copy of the source code in their application, this is how you should include it in your makefiles:


Options.cs:
	cp `pkg-config --variable=Sources mono-options` .

	

Then your code can just include a reference to it.

Posted on 14 Oct 2008