# clo++ Handbook

### Peter Jones

pjones@pmade.org

Copyright © 2000-2001 by Peter J Jones

This is the clo++ handbook. The clo++ handbook documents the allowed elements in the XML file and the clo++ API.

     Copyright (C) 2000-2001 Peter J Jones (pjones@pmade.org)
     All Rights Reserved

     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
     3. Neither the name of the Author nor the names of its contributors
        may be used to endorse or promote products derived from this software
        without specific prior written permission.

     THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
     ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
     DAMAGE.

# Chapter 1. Introduction

# What is clo++

clo++ is a command line option parser generator for C++. You describe the options that your application takes in a XML file. From there clo++ generates a C++ header file with a class that can parse your command line. It supports just about anything that you want to do with your command line. It also generates usage information and can handle subcommands that take their own options. clo++ is itself written in C++ and uses a command line option parser that it generated.

# How to Use This Document

This document is best used while you have quick access to the sample code in the examples directory. I recommend looking at the sample code along with the sample XML files before you start to read this document.

# Chapter 2. The XML File

# Basic XML File

The XML file should have a root element of clo. Here is a blank document to demonstrate.

    <?xml version="1.0"?>
    <clo>
    	<!-- clo++ tags here -->
    </clo>

Between the opening and closing clo elements you would place configuration elements, option elements or command elements. The next sections take a deeper look into each of these elements.

# Configuration Elements

This section describes the various configuration elements that clo++ will use.

## class

The class element specifies the name of the generated class. This allows you to change the name of the class that is generated in the header file. The deault is `Parser`.

Here is an example:

    <class>SomeClassName</class>

## namespace

The namespace element allows you to change the namespace in which the class will be generated. The default namespace is `Clo`.

Here is an example:

    <namespace>SomeNameSpace</namespace>

## file

The file element allows you to pick the name of the file to use when generating the header file.

Here is an example:

    <file>somefile.hh</file>

## codefile

The codefile element allows you to give a filename for the class definition. The class definition will be put into this file and the class declaration will be put into the file given by the file element.

This is an optional element, the default action is to put the declaration and definition into one file.

Here is an example:

    <codefile>somefile.cc</file>

## autohelp and autoversion

The autohelp element tells clo++ to generate code that looks for `--help` and `-h` command line options. When one of these options are found, an exception is thrown and the `autohelp` bool flag is set in the exception.

The autoversion element tells clo++ to generate code that looks for `--version` and `-v` command line options. When one of these options are found, an exception is thrown and the `autoversion` bool flag is set in the exception. This gives you a chance to print out information about the version of your application and exit.

Here is an example on how to set autohelp and autoversion:

    <autohelp/>
    <autoversion/>

## nomix

The nomix element tells clo++ that the generated parser should not allow options and non-options to be mixed. As soon as the parser encounters a non-option the remaining arguments are saved as non-options in the file list. This is for POSIX compliance. The default is to allow options and non-options to be mixed.

Also note that the parser will always stop parsing when it encounters a double dash by itself like "--". The remaining arguments are put into the file list.

Here is an example on how to set the nomix flag:

    <nomix/>

## mandatory

The mandatory element, if pressent, will make the command line parser throw an exception if the user did not use a (sub)command. We talk about (sub)commands a little later.

Here is an example:

    <mandatory/>

# Option Element

The option element is used to define an option that your program will take or an option that one of the (sub)commands will take.

Here is an example of a complete option:

    <option>
            <type>string</type>
            <long>create</long>
            <short>c</short>
            <argname>filename</argname>
            <description>create a file using the given filename</description>
            <default>somefile</default>
    </option>

## type

The type element tells the command line parser what type of option to expect. Here is a list of supported types.

- flag - True if option was on command line

- count - Counts the nuber of time option was on command line

- bool - Allows user to give a boolean option, like "true" or "false"

- int - Allows user to give an interger value

- double - Allows user to give a double percision real number

- string - Allows the user to give some character data

## long

The long element is so that you can specify the long name of this option. Long options, when on the command line, begin with a double dash.

The long element is optional, but only if you have short element.

## short

The short element is so that you can specify the short name of this option. Short options are only one character, and when on the command line, begin with one dash. Short options can be bundled.

The short element is optional, but only if you have a long element.

## argname

If this option takes an argument, because it is either of type bool, int, double or string, then this element allows you to give the string that is used in help messages for the name of the argument to give to that option.

## default

The default element allows you to set a default value of this option. The default value is used when the user does not give this option on the command line.

## description

The description element allows you to give a description text about this element. This text is seen in help messages.

## list

The list element is for options that take arguments, such as the bool, int, double and string option types. If present, this element tells the command line parser that this option may be repeated on the command line. Each time it is given, it's value is pushed into a vector.

## map

The map element, if present, tells the command line parser that this option takes two arguments, a key and a value, seperated by an equal sign. The option may also be repeated on the command line. Each time the option is on the command line, the key and value are put inside a Standard C++ map object.

## mandatory

If the mandatory element is present then this option must be given on the command line or the parser will throw an exception.

# Command Element

Sometimes you may want to have the same options do different things based on what the program is going to do. A good example of this is the cvs command. The cvs command has what I call (sub)commands, like add, checkout, commit and update.

Each of these (sub)commands has it's own options. An option with the same name means different things for one (sub)command and something different for another (sub)command.

To add to this, the program itself can have options with the same name as one of the (sub)commands. So, your program can have a `-d` option and so can one or all of it's (sub)commands.

You tell the command line parser which options each of the (sub)commands take by putting Option elements inside of the command element. I recommend that you look at some sample code for help.

## name

This element allows you to give a name to this (sub)command so that you can refer to it in your code and from the command line.

## alias

This element allows you to give another name for the (sub)command. This new name is only good on the command line. You can give as many aliases to a (sub)command as you wish.

## description

This element allows you to give a description of this (sub)command that will be seen in help messages.

# Chapter 3. The API

# Creating a Parser Object

All that you need to do to create a parser object is include the generated header file and create an instance of the class that you named in the XML file or the command line.

Here is an example using the default settings for the class and namespace names:

    #include "Clo.hh"

    int main (int argc, char *argv[]) {
        Clo::Parser clo;

        // other code here

        return 0;
    }

# Parsing the Command Line

Once you have a parser object you can call the `parse` method to parse the command line.

Here is a function synopsis for the `parse` method:

``void parse`( int argc char *argv[] );`

Here is an example using the default settings for the class and namespace names:

    #include "Clo.hh"

    int main (int argc, char *argv[]) {
        Clo::Parser clo;

        clo.parse(argc, argv);

        return 0;
    }

> Note: The `parse` method will throw an exception if there is an error parsing the command line. See the exception section for more details.

# Getting Option Values

Depending on what types of options that you have specified in the XML file, there wil be different methods that you will use to get the value of a command line option.

The various methods are divided into three groups, methods that return a single value, methods that return a list, and methods that return a map. All methods take the same arguments, a string that specifies the name of the option, and a string that specifies the name of the command.

The command argument will only be in the method signature when using command elements in the XML file. If you are using the command elements, then you can get the root options by not giving a command argument to the method.

## Methods That Return a Single Value

These methods are used to get values for options that do not use the `list` or `map` elements in the XML file.

- `bool get_flag_option ( string option, string command="" )`

- `int get_count_option ( string option, string command="" )`

- `bool get_bool_option ( string option, string command="" )`

- `int get_int_option (string option, string command="")`

- `double get_double_option ( string option, string command="")`

- `string get_string_option ( string option, string command="")`

## Methods That Return a List

If you use the `list` elemment in the XML file, because you want an option to be able to be repeated, you will need to use the following methods to get a list of values for one option.

- `vector<bool> get_bool_list ( string option, string command="" )`

- `vector<int> get_int_list ( string option, string command="")`

- `vector<double> get_double_list ( string option, string command="")`

- `vector<string> get_string_list ( string option, string command="")`

## Methods That Return a Map

When you specify the `map` element in the XML file for one of your options, because you want the option to be repeated and take two arguments, then you will need to use the following methods to get a map of values for one option.

- `map<string, bool> get_bool_map (string option, string command="" )`

- `map<string, int> get_int_map ( string option, string command="")`

- `map<string, double> get_double_map ( string option, string command="")`

- `map<string, string> get_string_map ( string option, string command="")`

# Getting the File List

Words that are on the command line that are not command line options are considered file names. Depending on the presence of the `nomix` element in the XML file, file names can or cannot be mixed with command line options.

Another way that a word will be added to the file list is the presence of the double dash "--". When the parser encounters a double dash, all words after that point are added to the file list without option processing.

To get the file list, use the follong method:

``vector<string> &get_file_list`();`

Here is an example using the clo++ defaults:

    #include <string>
    #include <vector>
    #include "Clo.hh"

    int main (int argc, char *argv[]) {
        Clo::Parser    clo;
        vector<string> files;

        clo.parse(argc, argv);

        files = clo.get_file_list();

       return 0;
    }

# Handling Exceptions

The `parse` method and the various `get_*_*` methods, except the `get_file_list`, all can throw an exception. The exception that they throw is of the class `Exception`. That class will be in the same namespace as the parser class.

The `get_*_*` methods will only throw an exception when you try to get the value of a option and pass in an invalid option name. That just leaves us with the `parse` method.

If someone were to give an invalid option, or not give a mandator option, the `parse` method will throw an exception. You can use `what` method to get a char* that describes the error.

You should also check the `autohelp` and `autoversion` bool members if you are using autohelp or autoversion.

There is another method of the `Exception` class that you can use, `fancy`. You can call this method the exact same way that you use the `what` method. The only difference is that the `fancy` method will return a fancier looking error message.

Here is an example:

    try {
        clo.parse(argc, argv);
    } catch (Clo::Exception &e) {
        if (e.autohelp) {
            cout << "Usage: yourapp [options]" << endl;
            cout << e.fancy(); // or e.what();
            return 0;
        } else if (e.autoversion) {
            cout << "This is yourapp version 1.0" << endl;
            return 0;
        } else {
            cerr << e.fancy(); // or e.what();
            return 1;
        }
    }