1139 lines
41 KiB
XML
1139 lines
41 KiB
XML
|
<?xml version='1.0'?>
|
||
|
<!DOCTYPE book PUBLIC "-//Norman Walsh//DTD DocBk XML V4.2//EN"
|
||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||
|
|
||
|
<!--
|
||
|
-
|
||
|
- file: manual.xml
|
||
|
-
|
||
|
- Copyright (c) 2003, 2004 Michael E. Smoot .
|
||
|
- All rights reserved.
|
||
|
-
|
||
|
- See the file COPYING in the top directory of this distribution for
|
||
|
- more information.
|
||
|
-
|
||
|
- THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||
|
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||
|
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
- DEALINGS IN THE SOFTWARE.
|
||
|
-
|
||
|
-->
|
||
|
<book>
|
||
|
<bookinfo>
|
||
|
<title>Templatized C++ Command Line Parser Manual</title>
|
||
|
<author>
|
||
|
<firstname>Michael</firstname>
|
||
|
<surname>Smoot</surname>
|
||
|
<othername role='mi'>E</othername>
|
||
|
</author>
|
||
|
<copyright>
|
||
|
<year>2003,2004,2005,2006,2009,2011</year>
|
||
|
<holder>Michael E. Smoot</holder>
|
||
|
</copyright>
|
||
|
</bookinfo>
|
||
|
|
||
|
<chapter id="BASIC_USAGE">
|
||
|
<title>Basic Usage</title>
|
||
|
<sect1 id="OVERVIEW">
|
||
|
<title>Overview</title>
|
||
|
<para>
|
||
|
<emphasis>TCLAP</emphasis> has a few key classes to be aware of.
|
||
|
The first is the
|
||
|
<classname>CmdLine</classname> (command line) class. This class parses
|
||
|
the command line passed to it according to the arguments that it
|
||
|
contains. Arguments are separate objects that are added to the
|
||
|
<classname>CmdLine</classname> object one at a time. The six
|
||
|
argument classes are: <classname>ValueArg</classname>,
|
||
|
<classname>UnlabeledValueArg</classname>,
|
||
|
<classname>SwitchArg</classname>, <classname>MultiSwitchArg</classname>,
|
||
|
<classname>MultiArg</classname> and
|
||
|
<classname>UnlabeledMultiArg</classname>.
|
||
|
These classes are templatized, which means they can be defined to parse
|
||
|
a value of any <link linkend="USING_ARGTRAITS"> type</link>. Once you add the
|
||
|
arguments to the <classname>CmdLine</classname> object, it parses the
|
||
|
command line
|
||
|
and assigns the data it finds to the specific argument objects it
|
||
|
contains. Your program accesses the values parsed by
|
||
|
calls to the <methodname>getValue()</methodname> methods of the
|
||
|
argument objects.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="EXAMPLE">
|
||
|
<title>Example</title>
|
||
|
<para>
|
||
|
Here is a simple <ulink url="test1.cpp"> example</ulink> ...
|
||
|
|
||
|
<programlisting>
|
||
|
#include <string>
|
||
|
#include <iostream>
|
||
|
#include <algorithm>
|
||
|
#include <tclap/CmdLine.h>
|
||
|
|
||
|
int main(int argc, char** argv)
|
||
|
{
|
||
|
|
||
|
// Wrap everything in a try block. Do this every time,
|
||
|
// because exceptions will be thrown for problems.
|
||
|
try {
|
||
|
|
||
|
// Define the command line object, and insert a message
|
||
|
// that describes the program. The "Command description message"
|
||
|
// is printed last in the help text. The second argument is the
|
||
|
// delimiter (usually space) and the last one is the version number.
|
||
|
// The CmdLine object parses the argv array based on the Arg objects
|
||
|
// that it contains.
|
||
|
TCLAP::CmdLine cmd("Command description message", ' ', "0.9");
|
||
|
|
||
|
// Define a value argument and add it to the command line.
|
||
|
// A value arg defines a flag and a type of value that it expects,
|
||
|
// such as "-n Bishop".
|
||
|
TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");
|
||
|
|
||
|
// Add the argument nameArg to the CmdLine object. The CmdLine object
|
||
|
// uses this Arg to parse the command line.
|
||
|
cmd.add( nameArg );
|
||
|
|
||
|
// Define a switch and add it to the command line.
|
||
|
// A switch arg is a boolean argument and only defines a flag that
|
||
|
// indicates true or false. In this example the SwitchArg adds itself
|
||
|
// to the CmdLine object as part of the constructor. This eliminates
|
||
|
// the need to call the cmd.add() method. All args have support in
|
||
|
// their constructors to add themselves directly to the CmdLine object.
|
||
|
// It doesn't matter which idiom you choose, they accomplish the same thing.
|
||
|
TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);
|
||
|
|
||
|
// Parse the argv array.
|
||
|
cmd.parse( argc, argv );
|
||
|
|
||
|
// Get the value parsed by each arg.
|
||
|
std::string name = nameArg.getValue();
|
||
|
bool reverseName = reverseSwitch.getValue();
|
||
|
|
||
|
// Do what you intend.
|
||
|
if ( reverseName )
|
||
|
{
|
||
|
std::reverse(name.begin(),name.end());
|
||
|
std::cout << "My name (spelled backwards) is: " << name << std::endl;
|
||
|
}
|
||
|
else
|
||
|
std::cout << "My name is: " << name << std::endl;
|
||
|
|
||
|
|
||
|
} catch (TCLAP::ArgException &e) // catch any exceptions
|
||
|
{ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
|
||
|
}
|
||
|
</programlisting>
|
||
|
|
||
|
The output should look like:
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
% test1 -n mike
|
||
|
My name is: mike
|
||
|
|
||
|
% test1 -n mike -r
|
||
|
My name (spelled backwards) is: ekim
|
||
|
|
||
|
% test1 -r -n mike
|
||
|
My name (spelled backwards) is: ekim
|
||
|
|
||
|
% test1 -r
|
||
|
PARSE ERROR:
|
||
|
One or more required arguments missing!
|
||
|
|
||
|
Brief USAGE:
|
||
|
test1 [-r] -n <string> [--] [-v] [-h]
|
||
|
|
||
|
For complete USAGE and HELP type:
|
||
|
test1 --help
|
||
|
|
||
|
|
||
|
% test1 --help
|
||
|
|
||
|
USAGE:
|
||
|
|
||
|
test1 [-r] -n <string> [--] [-v] [-h]
|
||
|
|
||
|
|
||
|
Where:
|
||
|
|
||
|
-r, --reverse
|
||
|
Print name backwards
|
||
|
|
||
|
-n <string> --name <string>
|
||
|
(required) (value required) Name to print
|
||
|
|
||
|
--, --ignore_rest
|
||
|
Ignores the rest of the labeled arguments following this flag.
|
||
|
|
||
|
-v, --version
|
||
|
Displays version information and exits.
|
||
|
|
||
|
-h, --help
|
||
|
Displays usage information and exits.
|
||
|
|
||
|
|
||
|
Command description message
|
||
|
|
||
|
</programlisting>
|
||
|
</para>
|
||
|
|
||
|
<sect2 id="LIBRARY_PROPERTIES">
|
||
|
<title>Library Properties</title>
|
||
|
<para>
|
||
|
This example shows a number of different properties of the
|
||
|
library...
|
||
|
<itemizedlist>
|
||
|
<listitem>Arguments can appear in any order (...mostly,
|
||
|
<link linkend="COMPLICATIONS"> more</link> on this later).</listitem>
|
||
|
|
||
|
<listitem>The <parameter>help</parameter>, <parameter>version</parameter>
|
||
|
and <parameter>--</parameter> <classname>SwitchArg</classname>s
|
||
|
are specified automatically. Using either the <parameter>-h</parameter> or
|
||
|
<parameter>--help</parameter> flag will cause the USAGE message to be displayed,
|
||
|
<parameter>-v</parameter> or <parameter>--version</parameter> will cause
|
||
|
any version information to
|
||
|
be displayed, and <parameter>--</parameter> or
|
||
|
<parameter>--ignore_rest</parameter> will cause the
|
||
|
remaining labeled arguments to be ignored. These switches are
|
||
|
included by default on every command line. You can <link linked="NO_HELP_VERSION">disable this functionality</link> if desired (although we don't recommend it).
|
||
|
How we generate the behavior behind these flags is described
|
||
|
<link linkend="VISITORS"> later</link>.
|
||
|
</listitem>
|
||
|
|
||
|
<listitem>If there is an error parsing the command line (e.g. a required
|
||
|
argument isn't provided), the program exits and displays a brief
|
||
|
USAGE and an error message.</listitem>
|
||
|
|
||
|
<listitem>The program name is assumed to always be argv[0], so it isn't
|
||
|
specified directly.</listitem>
|
||
|
|
||
|
<listitem>A value delimiter character can be specified. This means that if you
|
||
|
prefer arguments of the style <parameter>-s=asdf</parameter> instead of
|
||
|
<parameter>-s asdf</parameter>, you can do so.</listitem>
|
||
|
|
||
|
<listitem><emphasis>Always wrap everything in a try block that catches
|
||
|
ArgExceptions!</emphasis> Any problems found in constructing the
|
||
|
<classname>CmdLine</classname>, constructing the <classname>Arg</classname>s,
|
||
|
or parsing the command line will throw an
|
||
|
<classname>ArgException</classname>.</listitem>
|
||
|
|
||
|
</itemizedlist>
|
||
|
</para>
|
||
|
</sect2>
|
||
|
|
||
|
<sect2 id="ARG_PROPERTIES">
|
||
|
<title>Common Argument Properties</title>
|
||
|
<para>
|
||
|
Arguments, whatever their type, have a few common properties.
|
||
|
These properties are set in the constructors of the arguments.
|
||
|
<itemizedlist>
|
||
|
<listitem>First is the flag or the character preceded by a dash(-) that
|
||
|
signals the beginning of the argument on the command line.</listitem>
|
||
|
|
||
|
<listitem>Arguments also have names, which can also be used
|
||
|
as an alternative flag on the command line, this time preceded by two dashes
|
||
|
(--) [like the familiar <function>getopt_long()</function>].</listitem>
|
||
|
|
||
|
<listitem>Next is the description of the argument. This is a short
|
||
|
description of the argument displayed in the help/usage message
|
||
|
when needed.</listitem>
|
||
|
|
||
|
<listitem>The following parameters in the constructors vary depending on
|
||
|
the type of argument. Some possible values include:
|
||
|
<itemizedlist>
|
||
|
<listitem>A boolean value indicating whether the Arg is required or not. </listitem>
|
||
|
<listitem>A default value.</listitem>
|
||
|
<listitem>A <link linkend="DESCRIPTION_EXCEPTIONS">description</link> of the type of value expected.</listitem>
|
||
|
<listitem>A <link linkend="CONSTRAINT">constraint</link> on the value expected.</listitem>
|
||
|
<listitem>The CmdLine instance that the Arg should be added to.</listitem>
|
||
|
<listitem>A <link linkend="VISITORS">Visitor</link>.</listitem>
|
||
|
</itemizedlist>
|
||
|
</listitem>
|
||
|
<listitem>See the <ulink url="html/index.html">API Documentation</ulink> for more detail.</listitem>
|
||
|
</itemizedlist>
|
||
|
</para>
|
||
|
</sect2>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="COMPILING">
|
||
|
<title>Compiling</title>
|
||
|
<para>
|
||
|
<emphasis>TCLAP</emphasis> is implemented entirely in header files
|
||
|
which means you only need to include CmdLine.h to use the library.
|
||
|
<programlisting>
|
||
|
#include <tclap/CmdLine.h>
|
||
|
</programlisting>
|
||
|
You'll need to make sure that your compiler can see the header
|
||
|
files. If you do the usual "make install" then your compiler should
|
||
|
see the files by default. Alternatively, you can use the -I
|
||
|
complier argument to specify the exact location of the libraries.
|
||
|
<programlisting>
|
||
|
c++ -o my_program -I /some/place/tclap-1.X/include my_program.cpp
|
||
|
</programlisting>
|
||
|
Where /some/place/tclap-1.X is the place you have unpacked the
|
||
|
distribution.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
Finally, if you want to include <emphasis>TCLAP</emphasis> as part of
|
||
|
your software
|
||
|
(which is perfectly OK, even encouraged) then simply copy the
|
||
|
contents of /some/place/tclap-1.X/include (the tclap directory and
|
||
|
all of the header files it contains) into your include
|
||
|
directory. The necessary m4 macros for proper configuration are included
|
||
|
in the config directory.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
<emphasis>TCLAP</emphasis> was developed on Linux and MacOSX systems.
|
||
|
It is also known
|
||
|
to work on Windows, Sun and Alpha platforms. We've made every
|
||
|
effort to keep the library compliant with the ANSI C++ standard so
|
||
|
if your compiler meets the standard, then this library should work
|
||
|
for you. Please let us know if this is not the case!
|
||
|
<sect2 id="WINDOWS_NOTE">
|
||
|
<title>Windows Note</title>
|
||
|
<para>
|
||
|
As we understand things, Visual C++ does not have the file
|
||
|
<filename>config.h</filename> which is used to make platform
|
||
|
specific definitions. In this situation, we assume that you
|
||
|
have access to <classname>sstream</classname>. Our understanding is that
|
||
|
this should not be a problem for VC++ 7.x. However, if this
|
||
|
is not the case and you need to use <classname>strstream</classname>,
|
||
|
then simply tell your compiler to define the variable
|
||
|
<constant>HAVE_STRSTREAM</constant> and undefine
|
||
|
<constant>HAVE_SSTREAM</constant> That
|
||
|
<emphasis>should</emphasis> work. We think. Alternatively, just edit
|
||
|
the files <filename>ValueArg.h</filename> and <filename>MultiArg.h</filename>.
|
||
|
</para>
|
||
|
</sect2>
|
||
|
<sect2 id="RANDOM_NOTE">
|
||
|
<title>Random Note</title>
|
||
|
<para>
|
||
|
If your compiler doesn't support the <methodname>using</methodname> syntax used
|
||
|
in <classname>UnlabeledValueArg</classname> and
|
||
|
<classname>UnlabeledMultiArg</classname> to support two stage name lookup,
|
||
|
then you have two options. Either comment out the statements if you don't
|
||
|
need two stage name lookup, or do a bunch of search and replace and use
|
||
|
the <methodname>this</methodname> pointer syntax: e.g.
|
||
|
<methodname>this->_ignoreable</methodname> instead
|
||
|
of just <methodname>_ignorable</methodname> (do this for each variable
|
||
|
or method referenced by <methodname>using</methodname>).
|
||
|
</para>
|
||
|
</sect2>
|
||
|
</para>
|
||
|
</sect1>
|
||
|
</chapter>
|
||
|
<chapter id="FUNDAMENTAL_CLASSES">
|
||
|
<title>Fundamental Classes</title>
|
||
|
<sect1 id="COMMAND_LINE">
|
||
|
<title><classname>CmdLine</classname></title>
|
||
|
<para>
|
||
|
The <classname>CmdLine</classname> class contains the arguments that define
|
||
|
the command line and manages the parsing of the command line. The
|
||
|
<classname>CmdLine</classname> doesn't parse the command line itself it only
|
||
|
manages the parsing. The actual parsing of individual arguments occurs within
|
||
|
the arguments themselves. The <classname>CmdLine</classname> keeps track of
|
||
|
of the required arguments, <link linkend="XOR">relationships</link>
|
||
|
between arguments, and <link linkend="CHANGE_OUTPUT">output</link> generation.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
<sect1 id="SWITCH_ARG">
|
||
|
<title><classname>SwitchArg</classname></title>
|
||
|
<para><classname>SwitchArg</classname>s are what the name implies:
|
||
|
simple, on/off, boolean switches. Use <classname>SwitchArg</classname>s
|
||
|
anytime you want to turn
|
||
|
some sort of system property on or off. <classname>SwitchArg</classname>s
|
||
|
don't parse a value. They return <constant>TRUE</constant> or
|
||
|
<constant>FALSE</constant>, depending on whether the switch has been found
|
||
|
on the command line and what the default value was defined as.</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="VALUE_ARG">
|
||
|
<title><classname>ValueArg</classname></title>
|
||
|
<para><classname>ValueArg</classname>s are arguments that read a
|
||
|
value of some type
|
||
|
from the command line. Any time you need a file name, a number,
|
||
|
etc. use a <classname>ValueArg</classname> or one of its variants.
|
||
|
All <classname>ValueArg</classname>s are
|
||
|
<link linkend="USING_ARGTRAITS"> templatized</link> and will attempt to parse
|
||
|
the string its flag matches on the command line as the type it is
|
||
|
specified as. <classname>ValueArg<int></classname>
|
||
|
will attempt to parse an
|
||
|
int, <classname>ValueArg<float></classname> will attempt to
|
||
|
parse a float, etc. If <methodname>operator>></methodname>
|
||
|
for the specified type doesn't
|
||
|
recognize the string on the command line as its defined type, then
|
||
|
an exception will be thrown.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="MULTI_ARG">
|
||
|
<title><classname>MultiArg</classname></title>
|
||
|
<para>
|
||
|
A <classname>MultiArg</classname> is a <classname>ValueArg</classname> that
|
||
|
can be specified more than once on a command line and instead of returning
|
||
|
a single value, returns a <classname>vector</classname> of values.
|
||
|
</para>
|
||
|
<para>
|
||
|
Imagine a compiler that allows you to specify multiple directories
|
||
|
to search for libraries...
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
% fooCompiler -L /dir/num1 -L /dir/num2 file.foo
|
||
|
</programlisting>
|
||
|
<para>
|
||
|
Exceptions will occur if you try to do this
|
||
|
with a <classname>ValueArg</classname> or a <classname>SwitchArg</classname>.
|
||
|
In situations like this, you will want to use a
|
||
|
<classname>MultiArg</classname>. A
|
||
|
<classname>MultiArg</classname> is essentially a
|
||
|
<classname>ValueArg</classname> that appends any
|
||
|
value that it matches and parses onto a vector of values. When the
|
||
|
<methodname>getValue()</methodname> method is called, a vector of
|
||
|
values, instead of a single value is returned. A
|
||
|
<classname>MultiArg</classname> is declared much like
|
||
|
a <classname>ValueArg</classname>:
|
||
|
|
||
|
|
||
|
<programlisting>
|
||
|
MultiArg<int> itest("i", "intTest", "multi int test", false,"int" );
|
||
|
cmd.add( itest );
|
||
|
</programlisting>
|
||
|
Note that <classname>MultiArg</classname>s can be added to the
|
||
|
<classname>CmdLine</classname> in any order (unlike
|
||
|
<link linkend="UNLABELED_MULTI_ARG"> UnlabeledMultiArg</link>).
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="MULTI_SWITCH_ARG">
|
||
|
<title><classname>MultiSwitchArg</classname></title>
|
||
|
<para>
|
||
|
A <classname>MultiSwitchArg</classname> is a <classname>SwitchArg</classname>
|
||
|
that can be specified more than once on a command line.
|
||
|
This can be useful
|
||
|
when command lines are constructed automatically from within other applications
|
||
|
or when a switch occurring
|
||
|
more than once indicates a value (-V means a little verbose -V -V -V means a lot
|
||
|
verbose), You can use a <classname>MultiSwitchArg</classname>.
|
||
|
The call
|
||
|
to <methodname>getValue()</methodname> for a <classname>MultiSwitchArg</classname> returns the number (int) of times
|
||
|
the switch has been found on the command line in addition to the default value.
|
||
|
Here is an example using the default initial value of 0:
|
||
|
<programlisting>
|
||
|
MultiSwitchArg quiet("q","quiet","Reduce the volume of output");
|
||
|
cmd.add( quiet );
|
||
|
</programlisting>
|
||
|
Alternatively, you can specify your own initial value:
|
||
|
<programlisting>
|
||
|
MultiSwitchArg quiet("q","quiet","Reduce the volume of output",5);
|
||
|
cmd.add( quiet );
|
||
|
</programlisting>
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="UNLABELED_VALUE_ARG">
|
||
|
<title><classname>UnlabeledValueArg</classname></title>
|
||
|
<para>
|
||
|
An <classname>UnlabeledValueArg</classname> is a <classname>ValueArg</classname> that is not identified by a flag on the command line. Instead
|
||
|
<classname>UnlabeledValueArg</classname>s are identified by their position in
|
||
|
the argv array.
|
||
|
</para>
|
||
|
<para>
|
||
|
To this point all of our arguments have had labels (flags)
|
||
|
identifying them on the command line, but there are some
|
||
|
situations where flags are burdensome and not worth the effort. One
|
||
|
example might be if you want to implement a magical command we'll
|
||
|
call <command>copy</command>. All <command>copy</command> does is
|
||
|
copy the file specified
|
||
|
in the first argument to the file specified in the second argument.
|
||
|
We can do this using <classname>UnlabeledValueArg</classname>s which are pretty
|
||
|
much just <classname>ValueArg</classname>s without the flag specified,
|
||
|
which tells
|
||
|
the <classname>CmdLine</classname> object to treat them accordingly.
|
||
|
The code would look like this:
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
UnlabeledValueArg<float> nolabel( "name", "unlabeled test", 3.14,
|
||
|
"nameString" );
|
||
|
cmd.add( nolabel );
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
Everything else is handled identically to what is seen above. The
|
||
|
only difference to be aware of, and this is important: <emphasis>the order
|
||
|
that UnlabeledValueArgs are added to the <classname>CmdLine</classname>
|
||
|
is the order that they will be parsed!!!!</emphasis>
|
||
|
This is <emphasis>not</emphasis> the case for normal
|
||
|
<classname>SwitchArg</classname>s and <classname>ValueArg</classname>s.
|
||
|
What happens internally is the first argument that the
|
||
|
<classname>CmdLine</classname> doesn't recognize is assumed to be
|
||
|
the first <classname>UnlabeledValueArg</classname> and
|
||
|
parses it as such. Note that you are allowed to intersperse labeled
|
||
|
args (SwitchArgs and ValueArgs) in between
|
||
|
<classname>UnlabeledValueArgs</classname> (either on the command line
|
||
|
or in the declaration), but the <classname>UnlabeledValueArgs</classname>
|
||
|
will still be parsed in the order they are added. Just remember that order is
|
||
|
important for unlabeled arguments.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="UNLABELED_MULTI_ARG">
|
||
|
<title><classname>UnlabeledMultiArg</classname></title>
|
||
|
<para>
|
||
|
An <classname>UnlabeledMultiArg</classname> is an <classname>UnlabeledValueArg</classname> that allows more than one value to be specified. Only one
|
||
|
<classname>UnlabeledMultiArg</classname> can be specified per command line.
|
||
|
The <classname>UnlabeledMultiArg</classname> simply reads the remaining
|
||
|
values from argv up until -- or the end of the array is reached.
|
||
|
</para>
|
||
|
<para>
|
||
|
Say you want a strange command
|
||
|
that searches each file specified for a given string (let's call it
|
||
|
<command>grep</command>), but you don't want to have to type in all of the file
|
||
|
names or write a script to do it for you. Say,
|
||
|
|
||
|
<programlisting>
|
||
|
% grep pattern *.txt
|
||
|
</programlisting>
|
||
|
|
||
|
First remember that the <emphasis>*</emphasis> is handled by the shell and
|
||
|
expanded accordingly, so what the program <command>grep</command> sees is
|
||
|
really something like:
|
||
|
|
||
|
<programlisting>
|
||
|
% grep pattern file1.txt file2.txt fileZ.txt
|
||
|
</programlisting>
|
||
|
|
||
|
To handle situations where multiple, unlabeled arguments are needed,
|
||
|
we provide the <classname>UnlabeledMultiArg</classname>.
|
||
|
<classname>UnlabeledMultiArg</classname>s
|
||
|
are declared much like everything else, but with only a description
|
||
|
of the arguments. By default, if an <classname>UnlabeledMultiArg</classname>
|
||
|
is specified, then at least one is required to be present or an
|
||
|
exception will be thrown. The most important thing to remember is,
|
||
|
that like <classname>UnlabeledValueArg</classname>s: order matters!
|
||
|
In fact, <emphasis>an UnlabeledMultiArg must be the last argument added to the
|
||
|
CmdLine!</emphasis>. Here is what a declaration looks like:
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
//
|
||
|
// UnlabeledMultiArg must be the LAST argument added!
|
||
|
//
|
||
|
UnlabeledMultiArg<string> multi("file names");
|
||
|
cmd.add( multi );
|
||
|
cmd.parse(argc, argv);
|
||
|
|
||
|
vector<string> fileNames = multi.getValue();
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
You must only ever specify one (1) <classname>UnlabeledMultiArg</classname>.
|
||
|
One <classname>UnlabeledMultiArg</classname> will read every unlabeled
|
||
|
Arg that wasn't already processed by a
|
||
|
<classname>UnlabeledValueArg</classname> into a
|
||
|
<classname>vector</classname> of type T. Any
|
||
|
<classname>UnlabeledValueArg</classname> or other
|
||
|
<classname>UnlabeledMultiArg</classname> specified after the first
|
||
|
<classname>UnlabeledMultiArg</classname> will be ignored, and if
|
||
|
they are required,
|
||
|
exceptions will be thrown. When you call the
|
||
|
<methodname>getValue()</methodname>
|
||
|
method of the <classname>UnlabeledValueArg</classname> argument,
|
||
|
a <classname>vector</classname>
|
||
|
will be returned. If you can imagine a situation where there will
|
||
|
be multiple args of multiple types (stings, ints, floats, etc.)
|
||
|
then just declare the <classname>UnlabeledMultiArg</classname> as type
|
||
|
<classname>string</classname> and parse the different values yourself or use
|
||
|
several <classname>UnlabeledValueArg</classname>s.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
</chapter>
|
||
|
|
||
|
<chapter id="COMPLICATIONS">
|
||
|
<title>Complications</title>
|
||
|
<para>
|
||
|
Naturally, what we have seen to this point doesn't satisfy all of
|
||
|
our needs.
|
||
|
</para>
|
||
|
|
||
|
<sect1 id="COMBINE_SWITCHES">
|
||
|
<title>I want to combine multiple switches into one argument...</title>
|
||
|
<para>
|
||
|
Multiple <classname>SwitchArg</classname>s can be combined into a
|
||
|
single argument on the command line. If you have switches -a, -b and -c
|
||
|
it is valid to do either:
|
||
|
|
||
|
<programlisting>
|
||
|
% command -a -b -c
|
||
|
</programlisting>
|
||
|
|
||
|
<emphasis>or</emphasis>
|
||
|
|
||
|
<programlisting>
|
||
|
% command -abc
|
||
|
</programlisting>
|
||
|
|
||
|
<emphasis>or</emphasis>
|
||
|
|
||
|
<programlisting>
|
||
|
% command -ba -c
|
||
|
</programlisting>
|
||
|
|
||
|
This is to make this library more in line with the POSIX and GNU
|
||
|
standards (as I understand them).
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="XOR">
|
||
|
<title>I want one argument or the other, but not both...</title>
|
||
|
<para>
|
||
|
Suppose you have a command that must read input from one of two
|
||
|
possible locations, either a local file or a URL. The command
|
||
|
<emphasis>must</emphasis> read something, so <emphasis>one</emphasis>
|
||
|
argument is required, but
|
||
|
not both, yet neither argument is strictly necessary by itself.
|
||
|
This is called "exclusive or" or "XOR". To accommodate this
|
||
|
situation, there is now an option to add two or more
|
||
|
<classname>Arg</classname>s to
|
||
|
a <classname>CmdLine</classname> that are exclusively or'd with one another:
|
||
|
<methodname>xorAdd()</methodname>. This means that exactly one of the
|
||
|
<classname>Arg</classname>s must be set and no more.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
<methodname>xorAdd()</methodname> comes in two flavors, either
|
||
|
<methodname>xorAdd(Arg& a, Arg& b)</methodname>
|
||
|
to add just two <classname>Arg</classname>s to be xor'd and
|
||
|
<methodname>xorAdd( vector<Arg*> xorList )</methodname>
|
||
|
to add more than two <classname>Arg</classname>s.
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
|
||
|
ValueArg<string> fileArg("f","file","File name to read",true,"/dev/null", "filename");
|
||
|
ValueArg<string> urlArg("u","url","URL to load",true, "http://example.com", "URL");
|
||
|
|
||
|
cmd.xorAdd( fileArg, urlArg );
|
||
|
cmd.parse(argc, argv);
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
Once one <classname>Arg</classname> in the xor list is matched on the
|
||
|
<classname>CmdLine</classname> then the others in the xor list will be
|
||
|
marked as set. The question then, is how to determine which of the
|
||
|
<classname>Arg</classname>s has been set? This is accomplished by calling the
|
||
|
isSet() method for each <classname>Arg</classname>. If the
|
||
|
<classname>Arg</classname> has been
|
||
|
matched on the command line, the <methodname>isSet()</methodname> will return
|
||
|
<constant>TRUE</constant>, whereas if the <classname>Arg</classname>
|
||
|
has been set as a result of matching the other <classname>Arg</classname>
|
||
|
that was xor'd <methodname>isSet()</methodname> will
|
||
|
return <constant>FALSE</constant>.
|
||
|
(Of course, if the <classname>Arg</classname> was not xor'd and
|
||
|
wasn't matched, it will also return <constant>FALSE</constant>.)
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
if ( fileArg.isSet() )
|
||
|
readFile( fileArg.getValue() );
|
||
|
else if ( urlArg.isSet() )
|
||
|
readURL( urlArg.getValue() );
|
||
|
else
|
||
|
// Should never get here because TCLAP will note that one of the
|
||
|
// required args above has not been set.
|
||
|
throw("Very bad things...");
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
It is helpful to note that <classname>Arg</classname>s of any type can be xor'd together.
|
||
|
This means that you can xor a <classname>SwitchArg</classname> with a <classname>ValueArg</classname>.
|
||
|
This is helpful in situations where one of several options is necessary and one of the options
|
||
|
requires additional information.
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
SwitchArg stdinArg("s", "stdin", "Read from STDIN", false);
|
||
|
ValueArg<string> fileArg("f","file","File name to read",true,"/dev/null", "filename");
|
||
|
ValueArg<string> urlArg("u","url","URL to load",true, "http://example.com", "URL");
|
||
|
|
||
|
vector<Arg*> xorlist;
|
||
|
xorlist.push_back(&stdinArg);
|
||
|
xorlist.push_back(&fileArg);
|
||
|
xorlist.push_back(&urlArg);
|
||
|
|
||
|
cmd.xorAdd( xorlist );
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
|
||
|
<sect1 id="NO_FLAG">
|
||
|
<title>I have more arguments than single flags make sense for...</title>
|
||
|
<para>
|
||
|
Some commands have so many options that single flags no longer map
|
||
|
sensibly to the available options. In this case, it is desirable to
|
||
|
specify <classname>Arg</classname>s using only long options. This one is easy to
|
||
|
accomplish, just make the flag value blank in the <classname>Arg</classname>
|
||
|
constructor. This will tell the <classname>Arg</classname> that only the long
|
||
|
option should be matched and will force users to specify the long
|
||
|
option on the command line. The help output is updated accordingly.
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
ValueArg<string> fileArg("","file","File name",true,"homer","filename");
|
||
|
|
||
|
SwitchArg caseSwitch("","upperCase","Print in upper case",false);
|
||
|
|
||
|
</programlisting>
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
|
||
|
<sect1 id="CONSTRAINT">
|
||
|
<title>I want to constrain the values allowed for a particular
|
||
|
argument...</title>
|
||
|
<para>
|
||
|
<emphasis>Interface Change!!!</emphasis> Sorry folks, but we've changed
|
||
|
the interface since version 1.0.X for constraining <classname>Arg</classname>s.
|
||
|
Constraints are now hidden behind the <classname>Constraint</classname>
|
||
|
interface. To
|
||
|
constrain an <classname>Arg</classname> simply implement the interface
|
||
|
and specify the new class in the constructor as before.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
You can still constrain <classname>Arg</classname>s based on
|
||
|
a list of values. Instead of adding a <classname>vector</classname> of
|
||
|
allowed values to the <classname>Arg</classname> directly,
|
||
|
create a <classname>ValuesConstraint</classname> object
|
||
|
with a <classname>vector</classname> of values and add that to the
|
||
|
<classname>Arg</classname>. The <classname>Arg</classname> constructors
|
||
|
have been modified accordingly.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
When the value for the
|
||
|
<classname>Arg</classname> is parsed,
|
||
|
it is checked against the list of values specified in the
|
||
|
<classname>ValuesConstraint</classname>.
|
||
|
If the value is in the list then it is accepted. If
|
||
|
not, then an exception is thrown. Here is a simple example:
|
||
|
|
||
|
<programlisting>
|
||
|
vector<string> allowed;
|
||
|
allowed.push_back("homer");
|
||
|
allowed.push_back("marge");
|
||
|
allowed.push_back("bart");
|
||
|
allowed.push_back("lisa");
|
||
|
allowed.push_back("maggie");
|
||
|
ValuesConstraint<string> allowedVals( allowed );
|
||
|
|
||
|
ValueArg<string> nameArg("n","name","Name to print",true,"homer",&allowedVals);
|
||
|
cmd.add( nameArg );
|
||
|
</programlisting>
|
||
|
|
||
|
When a <classname>ValuesConstraint</classname> is specified,
|
||
|
instead of a type description being specified in the
|
||
|
<classname>Arg</classname>, a
|
||
|
type description is created by concatenating the values in the
|
||
|
allowed list using operator<< for the specified type. The
|
||
|
help/usage for the <classname>Arg</classname> therefore lists the
|
||
|
allowable values. Because of this, you might want to keep the list
|
||
|
relatively small, however there is no limit on this.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
Obviously, a list of allowed values isn't always the best way to
|
||
|
constrain things. For instance, one might wish to allow only
|
||
|
integers greater than 0. In this case, simply create a class that
|
||
|
implements the <classname>Constraint<int></classname> interface and
|
||
|
checks whether the value parsed is greater than 0 (done in the
|
||
|
<methodname>check()</methodname> method) and create your
|
||
|
<classname>Arg</classname> with your new <classname>Constraint</classname>.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
|
||
|
<sect1 id="ARG_ADD_CMDLINE">
|
||
|
<title>I want the Args to add themselves to the CmdLine...</title>
|
||
|
<para>
|
||
|
New constructors have been added for each <classname>Arg</classname>
|
||
|
that take a <classname>CmdLine</classname> object as an argument.
|
||
|
Each <classname>Arg</classname> then
|
||
|
<methodname>add</methodname>s itself to the <classname>CmdLine</classname>
|
||
|
object. There is no difference in how the <classname>Arg</classname>
|
||
|
is handled between this method and calling the
|
||
|
<methodname>add()</methodname> method directly. At the moment, there is
|
||
|
no way to do an <methodname>xorAdd()</methodname> from the constructor. Here
|
||
|
is an example:
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
// Create the command line.
|
||
|
CmdLine cmd("this is a message", '=', "0.99" );
|
||
|
|
||
|
// Note that the following args take the "cmd" object as arguments.
|
||
|
SwitchArg btest("B","existTestB", "exist Test B", cmd, false );
|
||
|
|
||
|
ValueArg<string> stest("s", "stringTest", "string test", true, "homer",
|
||
|
"string", cmd );
|
||
|
|
||
|
UnlabeledValueArg<string> utest("unTest1","unlabeled test one",
|
||
|
"default","string", cmd );
|
||
|
|
||
|
// NO add() calls!
|
||
|
|
||
|
// Parse the command line.
|
||
|
cmd.parse(argc,argv);
|
||
|
|
||
|
</programlisting>
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="CHANGE_OUTPUT">
|
||
|
<title>I want different output than what is provided...</title>
|
||
|
<para>
|
||
|
It is straightforward to change the output generated by
|
||
|
<emphasis>TCLAP</emphasis>. Either subclass the
|
||
|
<classname>StdOutput</classname> class and re-implement the methods you choose,
|
||
|
or write your own class that implements the
|
||
|
<classname>CmdLineOutput</classname> interface. Once you have done this,
|
||
|
then use the <classname>CmdLine</classname> <methodname>setOutput</methodname>
|
||
|
method to tell the <classname>CmdLine</classname> to use your new output
|
||
|
class. Here is a simple example:
|
||
|
<programlisting>
|
||
|
class MyOutput : public StdOutput
|
||
|
{
|
||
|
public:
|
||
|
virtual void failure(CmdLineInterface& c, ArgException& e)
|
||
|
{
|
||
|
cerr << "My special failure message for: " << endl
|
||
|
<< e.what() << endl;
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
virtual void usage(CmdLineInterface& c)
|
||
|
{
|
||
|
cout << "my usage message:" << endl;
|
||
|
list<Arg*> args = c.getArgList();
|
||
|
for (ArgListIterator it = args.begin(); it != args.end(); it++)
|
||
|
cout << (*it)->longID()
|
||
|
<< " (" << (*it)->getDescription() << ")" << endl;
|
||
|
}
|
||
|
|
||
|
virtual void version(CmdLineInterface& c)
|
||
|
{
|
||
|
cout << "my version message: 0.1" << endl;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int main(int argc, char** argv)
|
||
|
{
|
||
|
CmdLine cmd("this is a message", ' ', "0.99" );
|
||
|
|
||
|
// set the output
|
||
|
MyOutput my;
|
||
|
cmd.setOutput( &my );
|
||
|
|
||
|
// proceed normally ...
|
||
|
</programlisting>
|
||
|
|
||
|
See <filename>test4.cpp</filename> in the examples directory for the full
|
||
|
example. <emphasis>NOTE</emphasis>: if you supply your own Output object, we
|
||
|
will not delete it in the <classname>CmdLine</classname> destructor. This
|
||
|
could lead to a (very small) memory leak if you don't take care of the object
|
||
|
yourself. Also note that the <methodname>failure</methodname> method is
|
||
|
now responsible for exiting the application (assuming that is the desired
|
||
|
behavior).
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="NO_HELP_VERSION">
|
||
|
<title>I don't want the --help and --version switches to be created automatically...</title>
|
||
|
<para>
|
||
|
Help and version information is useful for nearly all command line applications
|
||
|
and as such we generate flags that provide those options automatically.
|
||
|
However, there are situations when these flags are undesirable. For these
|
||
|
cases we've added we've added a forth parameter to the
|
||
|
<classname>CmdLine</classname> constructor. Making this boolean parameter
|
||
|
false will disable automatic help and version generation.
|
||
|
<programlisting>
|
||
|
CmdLine cmd("this is a message", ' ', "0.99", false );
|
||
|
</programlisting>
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="IGNORE_ARGS">
|
||
|
<title>I want to ignore certain arguments...</title>
|
||
|
<para>
|
||
|
The <parameter>--</parameter> flag is automatically included in the
|
||
|
<classname>CmdLine</classname>.
|
||
|
As (almost) per POSIX and GNU standards, any argument specified
|
||
|
after the <parameter>--</parameter> flag is ignored.
|
||
|
<emphasis>Almost</emphasis> because if an
|
||
|
<classname>UnlabeledValueArg</classname> that has not been set or an
|
||
|
<classname>UnlabeledMultiArg</classname> has been specified, by default
|
||
|
we will assign any arguments beyond the <parameter>--</parameter>
|
||
|
to the those arguments as
|
||
|
per the rules above. This is primarily useful if you want to pass
|
||
|
in arguments with a dash as the first character of the argument. It
|
||
|
should be noted that even if the <parameter>--</parameter> flag is
|
||
|
passed on the command line, the <classname>CmdLine</classname> will
|
||
|
<emphasis>still</emphasis> test to make sure all of the required
|
||
|
arguments are present.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
Of course, this isn't how POSIX/GNU handle things, they explicitly
|
||
|
ignore arguments after the <parameter>--</parameter>. To accommodate this,
|
||
|
we can make both <classname>UnlabeledValueArg</classname>s and
|
||
|
<classname>UnlabeledMultiArg</classname>s ignoreable in their constructors.
|
||
|
See the <ulink url="html/index.html"> API Documentation</ulink> for details.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="READING_HEX_INTEGERS">
|
||
|
<title>I want to read hex integers as arguments...</title>
|
||
|
<para>
|
||
|
Sometimes it's desirable to read integers formatted in decimal, hexadecimal,
|
||
|
and octal format. This is now possible by #defining the <parameter>TCLAP_SETBASE_ZERO</parameter>
|
||
|
directive. Simply define this directive in your code and integer arguments will be parsed
|
||
|
in each base.
|
||
|
<programlisting>
|
||
|
|
||
|
#define TCLAP_SETBASE_ZERO 1
|
||
|
|
||
|
#include "tclap/CmdLine.h"
|
||
|
#include <iostream>
|
||
|
|
||
|
using namespace TCLAP;
|
||
|
using namespace std;
|
||
|
|
||
|
int main(int argc, char** argv)
|
||
|
{
|
||
|
|
||
|
try {
|
||
|
|
||
|
CmdLine cmd("this is a message", ' ', "0.99" );
|
||
|
|
||
|
ValueArg<int> itest("i", "intTest", "integer test", true, 5, "int");
|
||
|
cmd.add( itest );
|
||
|
|
||
|
//
|
||
|
// Parse the command line.
|
||
|
//
|
||
|
cmd.parse(argc,argv);
|
||
|
|
||
|
//
|
||
|
// Set variables
|
||
|
//
|
||
|
int _intTest = itest.getValue();
|
||
|
cout << "found int: " << _intTest << endl;
|
||
|
|
||
|
} catch ( ArgException& e )
|
||
|
{ cout << "ERROR: " << e.error() << " " << e.argId() << endl; }
|
||
|
}
|
||
|
</programlisting>
|
||
|
</para>
|
||
|
<para>
|
||
|
The reason that this behavior is not the default behavior for <emphasis>TCLAP</emphasis> is that the use of
|
||
|
<methodname>setbase(0)</methodname> appears to be something of a side effect and is not necessarily how
|
||
|
<methodname>setbase()</methodname> is meant to be used. So while we're making this functionality
|
||
|
available, we're not turning it on by default for fear of bad things happening in different compilers.
|
||
|
If you know otherwise, please let us know.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="USING_ARGTRAITS">
|
||
|
<title>I want to use different types...</title>
|
||
|
<para>
|
||
|
The usual C++ types (int, long, bool, etc.) are supported by <emphasis>TCLAP</emphasis> out
|
||
|
of the box. As
|
||
|
long as operator>> and operator<< are supported, other types should work fine
|
||
|
too, you'll just need to specify the <classname>ArgTraits</classname> which
|
||
|
tells <emphasis>TCLAP</emphasis> how you expect the type to be handled.
|
||
|
</para>
|
||
|
<para>
|
||
|
For example, assume that you'd like to read one argument on the command line in as a
|
||
|
<classname>std::pair</classname> object. All you'll need to do is tell
|
||
|
<emphasis>TCLAP</emphasis> whether to treat <classname>std::pair</classname> as a
|
||
|
String or Value. StringLike means to treat the string on the command line as a string
|
||
|
and use it directly, whereas ValueLike means that a value object should be extracted from the
|
||
|
string using operator>>. For <classname>std::pair</classname> we'll choose ValueLike.
|
||
|
To accomplish this, add the following declaration to your file:
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
template<class T, class U>
|
||
|
struct ArgTraits<std::pair<T, U>> {
|
||
|
typedef ValueLike ValueCategory;
|
||
|
};
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
For complete examples see the files <filename>test11.cpp</filename>
|
||
|
and <filename>test12.cpp</filename> in the examples directory.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="CHANGING_STARTSTRINGS">
|
||
|
<title>I want to use Windows-style flags like "/x" and "/y"...</title>
|
||
|
<para>
|
||
|
It is traditional in Posix environments that the "-" and "--" strings are used to signify
|
||
|
the beginning of argument flags and long argument names. However, other environments,
|
||
|
namely Windows, use different strings. <emphasis>TCLAP</emphasis> allows you to
|
||
|
control which strings are used with <methodname>#define</methodname> directives. This allows
|
||
|
you to use different strings based on your operating environment. Here is an example:
|
||
|
|
||
|
<programlisting>
|
||
|
//
|
||
|
// This illustrates how to change the flag and name start strings for
|
||
|
// Windows, otherwise the defaults are used.
|
||
|
//
|
||
|
// Note that these defines need to happen *before* tclap is included!
|
||
|
//
|
||
|
#ifdef WINDOWS
|
||
|
#define TCLAP_NAMESTARTSTRING "~~"
|
||
|
#define TCLAP_FLAGSTARTSTRING "/"
|
||
|
#endif
|
||
|
|
||
|
#include "tclap/CmdLine.h"
|
||
|
|
||
|
using namespace TCLAP;
|
||
|
using namespace std;
|
||
|
|
||
|
int main(int argc, char** argv)
|
||
|
{
|
||
|
// Everything else is identical!
|
||
|
...
|
||
|
</programlisting>
|
||
|
|
||
|
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
</chapter>
|
||
|
|
||
|
<chapter id="NOTES">
|
||
|
<title>Notes</title>
|
||
|
<para>
|
||
|
Like all good rules, there are many exceptions....
|
||
|
</para>
|
||
|
|
||
|
<sect1 id="DESCRIPTION_EXCEPTIONS">
|
||
|
<title>Type Descriptions</title>
|
||
|
<para>
|
||
|
Ideally this library would use RTTI to return a human readable name
|
||
|
of the type declared for a particular argument. Unfortunately, at
|
||
|
least for <command>g++</command>, the names returned aren't
|
||
|
particularly useful.
|
||
|
</para>
|
||
|
</sect1>
|
||
|
<sect1 id="VISITORS">
|
||
|
<title>Visitors</title>
|
||
|
|
||
|
<para>
|
||
|
Disclaimer: Almost no one will have any use for
|
||
|
<classname>Visitor</classname>s, they were
|
||
|
added to provide special handling for default arguments. Nothing
|
||
|
that <classname>Visitor</classname>s do couldn't be accomplished
|
||
|
by the user after the
|
||
|
command line has been parsed. If you're still interested, keep
|
||
|
reading...
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
Some of you may be wondering how we get the <parameter>--help</parameter>,
|
||
|
<parameter>--version</parameter> and <parameter>--</parameter>
|
||
|
arguments to do their thing without mucking up the
|
||
|
<classname>CmdLine</classname> code with lots of <emphasis>if</emphasis>
|
||
|
statements and type checking. This is accomplished by using a
|
||
|
variation on the Visitor Pattern. Actually, it may not be a Visitor
|
||
|
Pattern at all, but that's what inspired me.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
If we want some argument to do some sort of special handling,
|
||
|
besides simply parsing a value, then we add a <classname>Visitor</classname>
|
||
|
pointer to the <classname>Arg</classname>. More specifically, we add a
|
||
|
<emphasis>subclass</emphasis> of the <classname>Visitor</classname>
|
||
|
class. Once the argument has been successfully parsed, the
|
||
|
<classname>Visitor</classname> for that argument is
|
||
|
called. Any data that needs to be operated on is declared in the
|
||
|
<classname>Visitor</classname> constructor and then operated on in the
|
||
|
<methodname>visit()</methodname> method. A <classname>Visitor</classname>
|
||
|
is added to an <classname>Arg</classname> as the last argument in its
|
||
|
declaration. This may sound
|
||
|
complicated, but it is pretty straightforward. Let's see an
|
||
|
example.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
Say you want to add an <parameter>--authors</parameter> flag to a program that
|
||
|
prints the names of the authors when present. First subclass
|
||
|
<classname>Visitor</classname>:
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
#include "Visitor.h"
|
||
|
#include <string>
|
||
|
#include <iostream>
|
||
|
|
||
|
class AuthorVisitor : public Visitor
|
||
|
{
|
||
|
protected:
|
||
|
string _author;
|
||
|
public:
|
||
|
AuthorVisitor(const string& name ) : Visitor(), _author(name) {} ;
|
||
|
void visit() { cout << "AUTHOR: " << _author << endl; exit(0); };
|
||
|
};
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
Now include this class definition somewhere and go about creating
|
||
|
your command line. When you create the author switch, add the
|
||
|
<classname>AuthorVisitor</classname> pointer as follows:
|
||
|
|
||
|
<programlisting>
|
||
|
|
||
|
SwitchArg author("a","author","Prints author name", false,
|
||
|
new AuthorVisitor("Homer J. Simpson") );
|
||
|
cmd.add( author );
|
||
|
|
||
|
</programlisting>
|
||
|
|
||
|
Now, any time the <parameter>-a</parameter> or
|
||
|
<parameter>--author</parameter> flag is specified,
|
||
|
the program will print the author name, Homer J. Simpson and exit
|
||
|
without processing any further (as specified in the
|
||
|
<methodname>visit()</methodname> method).
|
||
|
</para>
|
||
|
</sect1>
|
||
|
|
||
|
<sect1 id="MORE_INFO">
|
||
|
<title>More Information</title>
|
||
|
<para>
|
||
|
For more information, look at the <ulink url="html/index.html">
|
||
|
API Documentation</ulink> and the examples included with the
|
||
|
distribution.
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
<emphasis>Happy coding!</emphasis>
|
||
|
</para>
|
||
|
|
||
|
</sect1>
|
||
|
</chapter>
|
||
|
</book>
|