2001-2006
Bernd Schoeller
Bernd
Schoeller
bernd@fams.de 14 September 2006

# Argument Parser Introduction

The argument library gives you the ability to parse the command line arguments that are passed to your application. It is a feature-rich library that tries to achieve the maximum comfort for the developer and for the user of the application at the same time.

## About arguments

Arguments normally come in two different forms: options and parameters. Parameters (sometimes also called operands) are the main inputs to the program, for example the filename give to a text editor or the URL that a web-browser should open on startup.

    myprog parameter1 parameter2 ... parameterX

Options - on the other hand - are normally not mandatory for the proper operation of the application. They are introduced with the - (minus) character.

There are short options and there are long options. Short options are introduced by a - (a single minus) followed by a single character. Long options are introduced by -- (two minus) and the name of the option.

    myprog -o --foo --bar=HALLO

In the given example, -o and --foo are so-called flags to the program. Flags are options that do not take any argument. The option --bar is an option that takes an argument, in this case the string HALLO.

Options and parameters can be mixed together and there are ways to combine options. This can create creating complex command lines. The following is an example call of the GNU ls command available on most Linux systems:

    /bin/ls -Al /tmp -I '*~' -I*.bak --color=always

Here, /tmp is the only parameter. The flags -A and -l have been merged into a single option. The option -I is set twice with the argument '*~' and '*.bak' and the option --color is set with the argument 'always' (note that the command line parser does not care whether the arguments to a short options are introduced by a space or follow directly).

## Design decisions and goals

The main focus of a developer is to create a program that provides the needed functionality. Comfortable command line parsing is difficult. Many programmers regard it as dispensable and few invest the necessary time to get it right.

As a consequence, the command line behavior of tools varies a lot. There are probably as many ways to parse the command line as there are developers writing applications. Often you have difficulties to use a tool because you wrote the command line arguments wrong, as the tool required them in a very specific form. If also a useful help text message is missing, the user wastes unnecessary time browsing through man pages and application documentation, or just uses trial-and-error until the command line arguments are OK.

The Gobo Eiffel Argument Library tries to take the burden off the developer to bother himself with command line parsing. Instead, she or he just defines a number of options that the application should have, calls the parser and checks which options were supplied and what the applications parameters are.

The goal is: It should be easier to parse the command line of the application with the library than to write a manual test, even if the application only has one or two options. Only this can motivate developers to use the library for their applications. At the same time, the library should provide a maximum in comfort for the user of the application, including support for many option styles, abbreviation facilities, and a useful, automatically generated help text.

With this goals in mind, there are a number of properties that the library has, that will not satisfy every need for software development. Specially, the library imposes a certain, standard way of command line parsing onto the application. If you want a very different way of command line parsing, perhaps because you want to be 'backward compatible' with another application, the argument parsing library might not be the best choice for you. Also, if you have a very large application that requires complex argument patterns, then you will need a significant amount of extra work to parse them using this library.

This being said, it is my firm belief that the library should be suited for most application needs. And it enforces a consistent behavior of different applications, something that your users will appreciate.

## Feature overview

To get the buzz-words right, here is a short overview of what you get when you are using the library.

- Different types of options: flags, strings, integers, booleans ...

- Long (--make-love) and short (-l) options are supported.

- Short form can be joined (-abc instead of -a -b -c), assuming that every one but the last is a flag (does not require an argument).

- Arguments to the short form can be added with or without space (-ltoday or -l today).

- Arguments to the long form can be added with '=' or with a space (--make-love=today or --make-love today)

- Option termination introduced by '--'.

- Usage instructions and a help text will be generated automatically from the options.

- Good default values, minimal code is required for standard applications.

- No special 'option description language' is required. It is all just plain Eiffel code.

## Usage strategy

The general usage strategy of the argument parser library involves the following four steps:

1. Create an instance of `AP_PARSER` and configure it (for example setting up a descriptions of the application).

2. Create instances of options types, that is of the classes that inherit from `AP_OPTION`. Configure these instances (for example with a help text for this option). Register these options at the parser.

3. Parse the command line, most of the time by just calling parse_arguments on the parser.

4. See if options were found by calling was_found in its instances. Get the parameters (non-option arguments) from the parser itself by querying it for parameters.

## An example

Lets go for an example that shows how to apply these four steps in practice. The example is rather lengthy, but it shows most of the possibilities of the library. The different steps in the usage strategy above have been marked by comments.

As an example we look again at the GNU ls and implement command line parsing for only the four options we already used above.

    feature -- Options and Flags

       allmost_all_flag: AP_FLAG
       long_format_flag: AP_FLAG
       color_option: AP_ENUMERATION_OPTION
       ignore_option: AP_STRING_OPTION

    feature -- Main

       make is
             -- Main routine, called when the program is executed.
          local
             parser: AP_PARSER
          do
                -- STEP 1: Creation and configuration of the parser

             create parser.make
             parser.set_application_description
                ("List information about the FILEs (the current directory by default).")
             parser.set_parameters_description ("[file] ...")

                -- STEP 2: Creation and configuration of the flags

             create allmost_all_flag.make ('A',"allmost-all")
             allmost_all_flag.set_description ("do not list implied . and ..")
             parser.options.force_last (allmost_all_flag)

             create long_format_flag.make_with_short_form ('l')
             long_format_flag.set_description ("use a long listing format")
             parser.options.force_last (long_format_flag)

             create color_option.make_with_long_form ("color")
             color_option.set_description ("control whether color is used to distinguish file types.")
             color_option.extend ("never")
             color_option.extend ("always")
             color_option.extend ("auto")
             parser.options.force_last (color_option)

             create ignore_option.make ('I',"ignore")
             ignore_option.set_description ("do not list implied entries matching shell PATTERN")
             ignore_option.set_parameter_description ("PATTERN")
             parser.options.force_last (ignore_option)

                -- STEP 3: Parse the arguments

             parser.parse_arguments

                -- STEP 4: Read results

             if allmost_all_flag.was_found then
                print ("list allmost all%N")
             end
             if long_format_flag.was_found then
                print ("use long format%N")
             end
             if color_option.was_found then
                print ("use coloring "+color_option.parameter+"%N")
             end

             if ignore_option.was_found then
                from
                   ignore_option.parameters.start
                until ignore_option.parameters.off loop
                   print ("ignore pattern: "+
                          ignore_option.parameters.item_for_iteration+"%N")
                   ignore_option.parameters.forth
                end
             end
             from
                parser.parameters.start
             until parser.parameters.off loop
                print ("parameter: "+
                       parser.parameters.item_for_iteration+"%N")
                parser.parameters.forth
             end
          end

If we now call the application with the arguments are given in the example above, we get the following output:

    $ ./my_ls -Al /tmp -I '*~' -I*.bak --color=always
    list allmost all
    use long format
    use coloring always
    ignore pattern: *~
    ignore pattern: *.bak
    parameter: /tmp

Also, we get a full help text for free (!). See what happens when we call the application with '-h'.

    $ ./my_ls -h
    usage: ls_example [-A] [-l] [--color=never|always|auto] [-I PATTERN] [file] ...
           ls_example --help

    List information about the FILEs (the current directory by default).

    Options:
    -A, --allmost-all             do not list implied . and ..
        --color=never|always|auto control whether color is used to distinguish
                                  file types.
    -h, --help                    Display this help text.
    -I, --ignore=PATTERN          do not list implied entries matching shell
                                  PATTERN
    -l                            use a long listing format

A second example is provided in the `$GOBO/example/argument` directory.