pjones@pmade.org
Copyright © 2000-2001 by Peter J Jones
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.
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.
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.
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.
This section describes the various configuration elements that clo++ will use.
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>
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>
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>
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>
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/>
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/>
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/>
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>
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
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.
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.
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.
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.
The description element allows you to give a description text about this element. This text is seen in help messages.
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.
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.
If the mandatory element is present then this option must be given on the command line or the parser will throw an exception.
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.
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.
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.
This element allows you to give a description of this (sub)command that will be seen in help messages.
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; }
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:
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.
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.
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="")
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="")
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="")
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:
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; }
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; } }