While writing a CLI application, Argument parsing is an important task.
For parsing the CLI arguments in c
, you can use Argp
from Glibc (the Gnu standard C library).
To parse the command line arguments in a c
program the procedure is as follows.
First of all we need to include argp.h
.
argp.h
is where the prototypes for all the APIs for argument parsing are found.
After doing that, we need to declare following variables;
const char *argp_program_version
:
This is the version string.
for example:
const char *argp_program_version = "your-cool-app 1.0.0";
static char doc[]
:
This is the documentation string.
for example:
static char doc[] = "documentation for your cool application :)";
const char *argp_program_bug_address
:
This is the email address for reporting bugs.
for example:
const char *argp_program_bug_address = "<your e-mail address>";
static char args_doc[]
:
These are the mandatory arguments that the program is expecting.
for example:
static char args_doc[] = "ARG1";
static struct argp_option options[]
:
These are the options that can be used with your cli application.
For example if you want the usage for your cli application to look like
$ ./cli -o something
or
$ ./cli --option1 something
your struct argp_option
struct will look like:
static struct argp_option options[] = {
{"verbose", 'v', 0, 0, "Produce verbose output"},
{"option1", 'o', "Option1", 0},
{0}
};
This is essentially an array of struct argp_option
.
struct argp_option
This structure specifies a single option that an argp parser understands, as well as how to parse and document that option. It has the following fields:
const char *name
:The long name for this option, corresponding to the long option
--name
.int key
:The integer key provided by the current option to the option parser. If key has a value that is a printable ASCII character (i.e., isascii (key) is true), it also specifies a short option
-char
, where char is the ASCII character with the code key.const char *arg
:If non-zero, this is the name of an argument associated with this option, which must be provided (e.g., with the
--name=value
or-char value
syntaxes)int flags
: Flags associated with this option. Available Flags are as follows.OPTION_ARG_OPTIONAL
:The argument associated with this option is optional.
OPTION_HIDDEN
: This option isn’t displayed in any help messages.OPTION_ALIAS
:This option is an alias for the closest previous non-alias option.
OPTION_DOC
:It is an arbitrary section of documentation
OPTION_NO_USAGE
:This option shouldn’t be included in
long
usage messages, but should still be included in other help messages. This is intended for options that are completely documented in an argp’s args_doc field.
const char *doc
:A documentation string for this option, for printing in help messages.
int group
:Group identity for this option. In a long help message, options are sorted alphabetically within each group, and the groups presented in the order 0, 1, 2, …, n, -m, …, -2, -1.
Note that because of C structure initialization rules, this field often need not be specified, because 0 is the correct value.
You can find more details about struct argp_option
in the glibc official
doc
struct arguments
:
This structure is used to hold all of the arguments.
For example, for the options that we have used above, the struct arguments
will look like:
struct arguments{
int verbose;
char *args[1];
char *option1;
};
A function to parse options and set the values in struct arguments
.
The next thing is to initialize the struct arguments
according to the options that we have specified in struct argp_option options[]
. To do that we need to define a function which will parse one option at a time and depending upon the option flag, it will set the corresponding value in struct arguments
.
Prototype for this function is:
static error_t parse_opt(int, char*, struct argp_state*);
this function take three inputs.
- A key, for example if your option is
-o
; theno
is your key. - A String (
char*
), the value associated with that key. - A pointer to
struct argp_state
, this the struct in which the value for the given argument will be stored.
static error_t parse_opt(int key, char *arg, struct argp_state *state){
struct arguments *arguments = state->input;
switch(key){
case 'v':
arguments->verbose = 1;
break;
case 'o':
arguments->option1 = arg;
break;
case ARGP_KEY_ARG:
// Too many arguments, if your program expects only one argument.
if(state->arg_num > 1)
argp_usage(state);
arguments->args[state->arg_num] = arg;
break;
case ARGP_KEY_END:
// Not enough arguments. if your program expects exactly one argument.
if(state->arg_num < 1)
argp_usage(state);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
Initialize struct argp argp
:
Now the last thing remaining is to initialize struct argp
, Where we need to use options
, parse_opt
, args_doc
and doc
that we have defined earlier.
For example:
static struct argp argp = {options, parse_opt, args_doc, doc};
Parse the arguments using argp_parse()
.
At this point we are all set to use Argp
.
Now We can use argp_parse()
function for parsing the command line arguments.
// create a new struct to hold arguments.
struct arguments arguments;
// set the default values for all of the args.
arguments.verbose = 0;
arguments.option1 = "";
// parse the cli arguments.
argp_parse(&argp, argc, args, 0, 0, &arguments);
After doing this we have values for all of the arguments passed to the executable from command line, stored in the struct arguments
.
The complete code for this example.
#include<stdlib.h>
#include<argp.h>
// need to mention a version string.
const char *argp_program_version = "your-cool-app 1.0.0";
// documentation string that will be displayed in the help section.
static char doc[] = "documentation for your cool application :)";
// email address for bug reporting.
const char *argp_program_bug_address = "<your e-mail address>";
// argument list for doc. This will be displayed on --help
static char args_doc[] = "ARG1";
// cli argument availble options.
static struct argp_option options[] = {
{"verbose", 'v', 0, 0, "Produce verbose output"},
{"option1", 'o', "Option1", 0},
{0}
};
// define a struct to hold the arguments.
struct arguments{
int verbose;
char *args[1];
char *option1;
};
// define a function which will parse the args.
static error_t parse_opt(int key, char *arg, struct argp_state *state){
struct arguments *arguments = state->input;
switch(key){
case 'v':
arguments->verbose = 1;
break;
case 'o':
arguments->option1 = arg;
break;
case ARGP_KEY_ARG:
// Too many arguments.
if(state->arg_num > 1)
argp_usage(state);
arguments->args[state->arg_num] = arg;
break;
case ARGP_KEY_END:
// Not enough arguments.
if(state->arg_num < 1)
argp_usage(state);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
// initialize the argp struct. Which will be used to parse and use the args.
static struct argp argp = {options, parse_opt, args_doc, doc};
int main(int argc, char *args[]){
// create a new struct to hold arguments.
struct arguments arguments;
// set the default values for all of the args.
arguments.verbose = 0;
arguments.option1 = "";
arguments.option2 = "";
// parse the cli arguments.
argp_parse(&argp, argc, args, 0, 0, &arguments);
printf("ARG1: %s", arguments.args[0]);
printf("\nVERBOSE: %s", arguments.verbose? "yes" : "no");
printf("\nOption1: %s", arguments.option1);
printf("\n");
}
To compile this code.
$ gcc -o argparsing argparsing.c
The output of this code:
$ ./argparsing --help
Usage: argparsing [OPTION...] ARG1
documentation for your cool application :)
-o, --option1=Option1
-v, --verbose Produce verbose output
-?, --help Give this help list
--usage Give a short usage message
-V, --version Print program version
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
Report bugs to <your e-mail address>.
Output of the above code whe you pass arguments to it.
$ ./argparsing -o "option1" "this is trial argument"
ARG1: this is trial argument
VERBOSE: no
Option1: option1