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 parser, helper functions, error handling and structure to store argument values. Arguments to be included in auto-generated file are defined in config. I usually gengetopt config file as cmdline.ggo. In this note I provide an example of gengetopt config file and arguments usage in code.

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

version "13.10.25"
package "app"
purpose "Sample application description.

By John Doe <sample@example.com>"

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

String option with long name filename and short name f, description String argument and it is required. Option can be called as -f myfile or --filename myfile.

option "filename" f "String argument" string required

It is possible to define options that takes several values, separated by comma. The following opition takes exactly 3 arguments with type int:

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

Option can take «one (two, etc) or more» arguments:

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

It is possible not to specify short name:

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

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

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

There is flags. If flag is provided in app call, it’s value triggered to opposite:

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

The whole config file:

version "13.10.25"
package "app"
purpose "Sample application description.

By John Doe <sample@example.com>"

# Options
option "filename" f "String argument" string required
option "size" s "Optional argument, takes exactly 3 int values separated by commas" multiple(3) optional int
option "array" a "Required argument, takes 1 or more args" multiple(1-) required int
option "long-option" - "Option without short version" optional float
option "default-value" d "Argument with default value" optional float default="0.003"
option "console" c "Flag with default 'off'" flag off

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

#include <iostream>
#include <cstdlib>

#include "cmdline.h"

int main(int argc, char *argv[])
{
    gengetopt_args_info ai;
    if (cmdline_parser (argc, argv, &ai) != 0) {
        exit(1);
    }

    std::cout << ai.filename_arg << std::endl;

    if (ai.size_given) {
        std::cout << ai.size_arg[0] << " "
                  << ai.size_arg[1] << " "
                  << ai.size_arg[2] << std::endl;
    }

    for (int i=0; i<ai.array_given; ++i) {
        std::cout << ai.array_arg[i] << " ";
    }
    std::cout << std::endl;

    if (ai.long_option_given) {
        std::cout << ai.long_option_arg << std::endl;
    }

    std::cout << ai.default_value_arg << std::endl;
    std::cout << ai.console_flag << std::endl;

    return 0;
}

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

APPNAME = app
OBJECTS = main.o cmdline.o

CC = gcc
CXX = g++

all: $(OBJECTS)
	$(CXX) $(OBJECTS) -o $(APPNAME)
cmdline.o: cmdline.c
	$(CC) -c $< -o $@
main.o: main.cpp
	$(CXX) -c $< -o $@
cmdline.c: cmdline.ggo
	gengetopt --input=cmdline.ggo --include-getopt
clean:
	rm -rf *.o $(APPNAME)

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

Output samples:

$ ./app -a 1,2,3,4,5,6 -f test -s 16,32,64 --long-option 0.4 -d 0.8
test
16 32 64
1 2 3 4 5 6
0.4
0.8
0
$ ./app -a 1 -f test -c
test
1
0.003
1
$ ./app
./app: '--filename' ('-f') option required
./app: '--array' ('-a') option required

Have fun!