Commandoptions v. 1.1 --------------------- ...is a class for parsing the options and parameters passed to your program from the command line. It has no requirements besides a relatively standard conforming C++ compiler. A recent GCC will do. The class has been designed with two goals in mind: - to be easy to use - to take over as much as possible of the tedious and boring work of defining and parsing arguments Consequently the class will automatically construct the options and arguments with the least possible given information, format usage and help messages ('--usage' and '-?/--help') which documents the program interface to the user, and report errors together with a meaningful explanation when the supplied arguments are wrong. So when you have registered with the class the variables you want users of your program to be able to influence, the entire command line interface has essentially been taken care of. All code is written by me, Ole Laursen, and released under the terms of the GNU Lesser General Public License. See COPYING for details. Free software is fun software. Tutorial -------- Usage is (deliberately) very simple: 1. Include the 'commandoptions.hpp' header: #include Depending on how you have installed the library, you might need to alter this directive. 2. Define a commandoptions object: commandoptions op; 3. And define the variables which you want the command line options to affect: int foo = 2; bool baz_bar = false; std::string outfile; std::vector infiles; Options that the user doesn't specify are left alone so it might be a good idea to initialize the variables to sensible defaults before processing the command line - here the default for 'foo' is 2. 4. Register the various arguments and options needed: op.register_option(foo, "foo", 'f', "How many times to foo the bar", "NUMBER"); op.register_flag(baz_bar, "bazzing", 'b', "Turn on bazzing of bars"); op.register_argument(outfile, "output-file", "Processed bars end up here"); op.register_leftover_arguments(infile, "input-files...", "Preprocessed bars are read from here"); 5. Process the command line by feeding argc and argv to the object: op.process_command_line(argc, argv); Since various errors might occur, you may want to wrap this in a try block. Upon error, the method will throw a commandoptions_error with the member function what() which returns a meaningful description of the problem: try { op.process_command_line(argc, argv); } catch (commandoptions_error &ex) { std::cerr << "Error: " << ex.what << std::endl; exit(1); } 6. Use the registered variables std::cout << "reading from " << infiles.size() << "files"; // ... foobar(foo, bars); if (baz_bar) baz(bars); std::ofstream out(outfile); out << bars; Library API ----------- Three different sorts of parameters are currently supported: options, flags and arguments. The first two is based on the notion of a switch which is either a '-' followed by a character or a '--' followed by a string. The following command line contains two switches: foobar --foo 9 -b The basic idea in the library is that you register the variables you want to be configurable by the user - if they are specified by the user, they will then be updated by the commandoptions object, else they are left alone. Thus it is probably a good idea to specify a sensible default value for the variables you use for options; for flags it is required since they reverse the default value so if you don't specify that, you get unpredictable behaviour; for ordinary arguments it doesn't matter since they are mandatory and must be supplied by the user anyway. Options are in this library defined to be an optional switch followed by a (mandatory) argument. The prototype for registration is (the standard namespace is implicitly assumed to be imported to improve readability): template void register_option(T &variable, string long_name, char short_name, string description, string argument_name) The arguments are: the variable to update, a long option name (becomes '--xxx'), a short name (becomes '-y'), and a short description which is displayed in the help message. To get meaningful help messages the name of the mandatory argument for the option is specied as the last parameter. The register call in the tutorial above will produce '[-f NUMBER]' in the usage message. Flags are defined to be optional switches which simply reverses the value of the variable when supplied - flags operate on Boolean variables. Thus if the flag for 'baz_bar' is specified in the command line for a call to the tutorial program above, the value of the variable will be true after calling 'process_command_line'. The prototype for registration is void register_flag(bool &variable, string long_name, char short_name, string description) The arguments for flag registration are the same as for options, though of course with the difference that the last argument, the name of the option argument, is omitted since flags don't take arguments. Arguments are defined to be mandatory ordinary command line arguments (i.e. unlike switches they aren't prefixed with dashes). In the following command line there are two arguments: mv bomb-manufacturing.html doc/howto-dig-potatoes.html The prototype for registering arguments is template void register_argument(T &variable, string name, string description) And the registration arguments are: the variable to set, the name of the argument for use in error and usage reporting, and a description of the argument for the help message. For flags and options, either the long name or short name may be omitted by passing the empty string "" or the null character '\0' respectively to the register method. Option argument names and all descriptions may also be omitted/squashed in a similar way. For support for a variable number of arguments, the library has a concept of "left-over arguments": template void register_leftover_arguments(vector &arg_vector, string name, string description) With this member function it is possible to register a vector for storing any left-over arguments, i.e. arguments that have not been swallowed by any other registered arguments. Note that left-over arguments are always considered optional so if you always need one or more Ts you have to check the size of the vector yourself after processing the command line. If you don't call this function, the library will barf at the user if extra arguments are supplied. Calling register_leftover_arguments a second time will just overwrite the first value so is rather pointless. It doesn't matter which order you call this function in with respect to other register functions, since the vector always will be filled only when there are no other registered arguments left for processing. Supported command line concepts ------------------------------- As mentioned in the introductionary section, the commandoptions class will supply your program with a complete interface to the command line. The argument parsing follows approximately the GNU standard since it is quite sensible and, well..., a standard on the GNU/Linux platform. This means that switches have either the long form '--name-of-switch' which consist of two dashes followed by a name string (that must not begin with a space), or the short one '-c' which consist of a single dash followed by a single character. Options which take an argument consist of the long or the short form of the option followed by whitespace followed by the argument, like '--name-of-option argument' or '-c argument'. Ordinary program arguments are recognized by the fact that they don't begin with a dash, and may appear anywhere between the options as long as the relative order among the arguments is preserved, thus the following command lines are equal program --boink -t blip beep program --boink blip beep -t program blip --boink beep -t provided 'boink' and 't' are flags. All options are processed from left to right so the rightmost supplied option will overwrite any previous specifications. Consequently program --sound boink --sound blip results in the variable behind the option 'sound' getting the value "blip". If the same flag is specified multiple times, all but one is ignored. So if the variable behind the flag 'think' has a default value of 'false', the two commands program --think program --think --think are the same way of giving it the value 'true' (although the second is somewhat more cumbersome). Short flags may be combined by putting multiple characters after the single dash, like this: '-trf'. Any number of flags may be combined this way, but since options take an argument, only one option may be stuffed in such group. If '-o' and '-i' are two options, the following command lines are all equal program -s -q -w -o floink -i boink program -sq -w -o floink -i boink program -sqw -o floink -i boink program -sqwo floink -i boink program -sqwi boink -o floink A few swiches are generated automatically by the library from the information you supply when you register switches. Currently these are '--usage', '--help' and '-?'. When one of these switches are met, a help message is output on std::cerr and the program is terminated with the exit code 1. '--usage' outputs a very terse listing of the available flags, options (short names are used when available) and necessary arguments, like Usage: program [-t?] [-o OUTPUT] [--usage] for a program with the flag '-t', the option '-o' and the argument 'inputfile'. '--help' and '-?' are the same and output a complete listing of the available switches with both long and short names together with the registered descriptions. If an ordinary argument has a description it will also get a special entry for that. So if your arguments are selfdescriptive, like 'inputfile' or 'outputfile', thus making any comment superfluous, feel free to omit the description (by passing an empty string). This avoids the extra entry which saves some space in the output and makes it easier for the user to get an overview of the program interface. Invalid supplied command lines at runtime results in the library trowing an commandoptions_error exception which has the member function what() that returns a const char * with a description of the error. A lot of different things are detected, e.g. wrong number of arguments, unknown options, etc. An important thing is that invalid arguments (either option arguments or ordinary program arguments) cause an exception. If, for instance, an option '--pointless-sounds' which is registered to update an integer variable is passed a string that can't be converted to a number, as in '--pointless-sounds three', the parsing will fail and throw an exception. This releaves the burden of parsing (and reporting errors in connection with) arguments from your shoulders. If you really need the kind of flexibility that homebrewed parsing gives, you can always simply register a string and then do the parsing with that afterwards. Though another, and better, option is to define a new type, e.g. a class, for the argument and then define the input operator >> for the type; internally the library puts the argument string inside an istringstream and then uses '>>' to extract it. This also implies that userdefined types for which operator >> already has been defined will work seamlessly with this library. Contact info ------------ Suggestions, criticism or any other sorts of comments are welcome - my email address is Ole Laursen Some people think the last part of the address is a joke; it isn't, it's the truth. The .dk suffix means I live in Denmark. Which also means I normally speak Danish - that's the cause (and the only one, of course) of all spelling mistakes & other linguistic errors in this documentation. I was wondering if I ought to include my snail mail address here too, but since you don't need that unless you're going to date me, I've left it out (in my experience not many C++ coders are female anyway).