Command line arguments in C and C++ with gengetopt

2013-10-26
#howto #tutorial #gengetopt #cpp #c

Gengetopt is a tool for parsing command line arguments in C and C++ applications. It generates cmdline.c and cmdline.h files in pure C, which contain the parser, helper functions, error handling, and a structure to store argument values. The arguments to be included in the auto-generated file are defined in the config. I usually name the gengetopt config file cmdline.ggo. In this note I provide an example of the gengetopt config file and argument usage in code.

The header of the config file contains information about the version, app name, and description. You can use the following template:

1version "13.10.25"
2package "app"
3purpose "Sample application description.
4
5By John Doe <sample@example.com>"

Arguments are listed after the header in the same config file. Even if no options are given below the header, two default ones are defined: -h shows the help message and -V shows the app version string. You can specify the long option name (in a call it can be used as --long-option), the short option name, the option type, and whether the option is required.

A string option with the long name filename, the short name f, and the description String argument; it is required. The option can be called as -f myfile or --filename myfile.

1option "filename" f "String argument" string required

It is possible to define options that take several values, separated by a comma. The following option takes exactly 3 arguments of type int:

1option "size" s "Optional argument, takes exactly 3 int values separated by commas" multiple(3) optional int

An option can take «one (two, etc.) or more» arguments:

1option "array" a "Required argument, takes 1 or more args" multiple(1-) required int

It is possible not to specify a short name:

1option "long-option" - "Option without short version" optional float

You can provide a default value for an option. The default value is used if the option is not used in the app call.

1option "default-value" d "Argument with default value" optional float default="0.003"

There are flags. If a flag is provided in the app call, its value is toggled to the opposite:

1option "console" c "Flag with default 'off'" flag off

The whole config file:

 1version "13.10.25"
 2package "app"
 3purpose "Sample application description.
 4
 5By John Doe <sample@example.com>"
 6
 7# Options
 8option "filename" f "String argument" string required
 9option "size" s "Optional argument, takes exactly 3 int values separated by commas" multiple(3) optional int
10option "array" a "Required argument, takes 1 or more args" multiple(1-) required int
11option "long-option" - "Option without short version" optional float
12option "default-value" d "Argument with default value" optional float default="0.003"
13option "console" c "Flag with default 'off'" flag off

Arguments are used in the source code via the gengetopt_args_info structure defined in cmdline.h. Example:

 1#include <iostream>
 2#include <cstdlib>
 3
 4#include "cmdline.h"
 5
 6int main(int argc, char *argv[])
 7{
 8    gengetopt_args_info ai;
 9    if (cmdline_parser (argc, argv, &ai) != 0) {
10        exit(1);
11    }
12
13    std::cout << ai.filename_arg << std::endl;
14
15    if (ai.size_given) {
16        std::cout << ai.size_arg[0] << " "
17                  << ai.size_arg[1] << " "
18                  << ai.size_arg[2] << std::endl;
19    }
20
21    for (int i=0; i<ai.array_given; ++i) {
22        std::cout << ai.array_arg[i] << " ";
23    }
24    std::cout << std::endl;
25
26    if (ai.long_option_given) {
27        std::cout << ai.long_option_arg << std::endl;
28    }
29
30    std::cout << ai.default_value_arg << std::endl;
31    std::cout << ai.console_flag << std::endl;
32
33    return 0;
34}

And the Makefile to build them all (you need gengetopt to be installed):

 1APPNAME = app
 2OBJECTS = main.o cmdline.o
 3
 4CC = gcc
 5CXX = g++
 6
 7all: $(OBJECTS)
 8	$(CXX) $(OBJECTS) -o $(APPNAME)
 9cmdline.o: cmdline.c
10	$(CC) -c $< -o $@
11main.o: main.cpp
12	$(CXX) -c $< -o $@
13cmdline.c: cmdline.ggo
14	gengetopt --input=cmdline.ggo --include-getopt
15clean:
16	rm -rf *.o $(APPNAME)

Place main.cpp, cmdline.ggo and Makefile in one folder and build this example.

Output samples:

1$ ./app -a 1,2,3,4,5,6 -f test -s 16,32,64 --long-option 0.4 -d 0.8
2test
316 32 64
41 2 3 4 5 6
50.4
60.8
70
1$ ./app -a 1 -f test -c
2test
31
40.003
51
1$ ./app
2./app: '--filename' ('-f') option required
3./app: '--array' ('-a') option required

Have fun!