regexps.com
The functions and macros in this chapter provide a convenient and standard way to parse command line arguments and provide on-line help for command-line invocation. An example at the end of the chapter illustrates their use.
It is important to understand that these functions are designed to support consistent command line interfaces, rather than arbitrary command line interfaces. Consequently, these functions aren't especially useful for implementing some of the standard Posix command line syntaxes.
struct opt_desc { int opt_value; t_uchar * char_name; t_uchar * long_name; int requires_arg; t_uchar * desc; };
struct opt_parsed { int opt_value; t_uchar * opt_string; t_uchar * arg_string; struct opt_desc * desc; };
An array of struct opt_desc
is used to describe the options
accepted by a program.
The easiest way to create this array is by defining a macro OPTS
of two arguments: OP
, which is used to define a program option
and OP2
, which is used to add additional lines of documentation
to an option.
Both OP
and OP2
are used as macros which accept 5
arguments:
name an enum name for the option char_name 0 or a string beginning with a one-character name for the option. long_name 0 or a string beginning with a long name for the option arg 1 if the option requires an argument, 0 otherwise desc A documentation string for the option
Once you have defined OPTS
it is easy to create a table of
struct opt_desc
, as in the following example:
#define OPTS(OP, OP2) \ OP (opt_help_msg, /* An enum name for the option */ \ "h", /* A short name for the option */ \ "help", /* A long name for the option */ \ 0, /* The option takes no arguments */ \ "Display a help message and exit.") /* help message */ \ \ OP (opt_version, "V", "version", 0, \ "Display a release identifier string and exit.") \ \ /* The next option illustrates how to handle a multi-line */ \ /* help message: */ \ \ OP (opt_output_file, "o file", "output-file=file", 1, \ "Write output to FILE.") \ OP2 (opt_output_file, 0, 0, 1, \ "The file must not already exist.") \ OP (...) ... /* Note that the short and long names for an option are optional * (may be 0) but if both are omitted, then there is no way to * specify the option on a command line. */ enum options { OPTS (OPT_ENUM, OPT_IGN) }; struct opt_desc opts[] = { OPTS (OPT_DESC, OPT_DESC) {-1, 0, 0, 0, 0} };
int opt_low (t_uchar * opt_string, t_uchar * opt_arg, struct opt_desc ** desc, struct opt_desc * opts, int * argcp, char ** argv, t_uchar * opt_string_space);
Return the next command line option and modify argc/argv to remove that option.
opts
should point to an array of struct opt_desc
whose final
element contains a value less than 0
in the field opt_value
.
Ordinarily opt
returns the opt_value
field from the element of
opts
that matches the next argument. If the field requires_arg
is not 0
, then the option argument is also returned. The option
and its argument are removed from argc/argv. opt_string
returns
a string naming the option (
-x
,
--long-opt
or
--long-opt=value
). The string returned in opt_string
may be
overwritten by later calls to opt
. opt_arg
returns
the argument to the option, if the argument requires an argument
and one was provided. A string returned in opt_arg
points to
a string or substring from argv
. desc
returns the option
description for the option returned.
Any of opt_string
, opt_arg
, and desc
may be 0
.
opt_string_space
should point to an array of three characters.
If the next option is a short option, the value stored in *opt_string
will point to opt_string_space
. opt_string_space
may be 0
if opt_string
is 0
.
If the option requires an argument but none is provided, *opt_arg
is set to 0
, and the opt_value
field of the option is returned;
argc/argv is not modified. To see that an option with required
argument has been correctly provided, it is necessary to check both
the return value of opt
, and the value of *opt_arg
. This
behavior is to facilitate providing a specific error message to the
user -- to quote POSIX:
option arguments may not be optional
.
If the next argument is not an ordinary option, a value less than 0
is returned. These special values are given symbolic names in
opt.h
(enum opt_return_values
):
opt_dash -- the next argument is simply "-". opt_double_dash -- the next argument is simply "--".
In either case, the argument ( - or -- ) is removed from argc/argv.
opt_unknown -- the next argument does not match any known option.
opt_bogus_argument -- a recognized long option was provided with an option argument, but the option does not accept an argument.
opt_none -- the next argument does not begin with "-".
In any of those cases, argc/argv is not modified.
int opt_standard (alloc_limits limits, struct opt_parsed ** parsed_p, struct opt_desc * opts, int * argcp, char * argvp[], t_uchar * program_name, t_uchar * usage, t_uchar * version_string, t_uchar * long_help, int help_option, int long_help_option, int version_option);
This function calls opt
, but handles some commonly
implemented options internally, in a standard way.
The parameters limits
, parsed_p
, opts
, argcp
,
and argvp
are as to opt_low
.
The parameters program_name
, usage
and version_string
are
used in error and informational messages printed by this function.
The parameters help_option
, long_help_option
and version_option
are the name
value for some standard options, which are
usually given the command line names:
-h --help help_option -H long_help_option -V --version version_option
If this function detects the help_option
, it prints a
multi-line message summarizing the available options
to standard output and exits the process with a 0
status.
If this function detects the long_help_option
, it prints a
multi-line message summarizing the available options
to standard output, adds text from long_help
and exits the
process with a 0
status. The first line of long_help
should
summarize the command (conventionally uncapitalized and without
punctuation). The rest of long_help
should expand upon the
explanation. Long help messages are formatted as:
first line of long_help usage: program_name .... option list
rest of long_help
If this function detects the version_option
, it prints a
single-line message containing version_string
to standard output and exits the process with a 0
status.
If this function detects an unrecognized option, a missing option argument, or an argument provided for an option that doesn't accept arguments, it prints a usage message to standard error and exits the process with a non-0 status.
void opt_usage (int fd, char * argv0, t_uchar * program_name, t_uchar * usage, int suggest_help);
Print a usage message on fd
using the format:
"usage: %s %s\n", program_name, usage
If suggest_help
is not 0
, also print:
"try %s --help\n", argv0
By convention, argv0
should be the first command line string
passed to the program (the name by which the program was invoked).
program_name
should be the default name for the program (not
necessarily the name by which it was invoked).
void opt_help (int fd, struct opt_desc * opts);
Print a help message based on opts
.
A long option name in opts
can have the form
--foo=BAR
.
The text
=BAR
is included in the help message.
Function
opt_shift_char_option
void opt_shift_char_option (int * argcp, char ** argv);
Remove a single character argument from argc/argv. For example,
Before:
*argcp = 3 argv = {"prog", "-abc", "-def", 0}
After:
*argcp = 3 argv = {"prog", "-bc", "-def", 0}
Before:
*argcp = 3 argv = {"prog", "-a", "-def", 0}
After:
*argcp = 2 argv = {"prog", "-def", 0}
void opt_shift (int * argcp, char ** argv);
Remove a single argument from argc/argv. For example,
Before:
*argcp = 3 argv = {"prog", "--abc", "-def", 0}
After:
*argcp = 2 argv = {"prog", "-def", 0}
The following program illustrates option parsing with opt
.
These examples illustrates its usage:
% test --version test 1.0.0
% test --help usage: ./,test [options] [input-file]
-h, --help Display a help message and exit. -V, --version Display a release identifier string and exit. -o file, --output-file=file Write output to FILE.
% ./,test -o one --output-file two -othree --output-file=four output file argument: `one' output file argument: `two' output file argument: `three' output file argument: `four'
% ./,test -xyzzy unhandled option `-xyzzy' usage: ./,test [options] [input-file] try ./,test --help
Here's the code:
#include "hackerlab/cmd/main.h" static t_uchar * program_name = "test"; static t_uchar * usage = "[options]"; static t_uchar * version_string = "1.0"; #define OPTS(OP, OP2) \ OP (opt_help_msg, "h", "help", 0, \ "Display a help message and exit.") \ OP (opt_version, "V", "version", 0, \ "Display a release identifier string") \ OP2 (opt_version, 0, 0, 0, "and exit.") \ OP (opt_output_file, "o file", "output-file=file", 1, \ "Write output to FILE.") enum options { OPTS (OPT_ENUM, OPT_IGN) }; struct opt_desc opts[] = { OPTS (OPT_DESC, OPT_DESC) {-1, 0, 0, 0, 0} }; int main (int argc, char * argv[]) { int errn; int o; struct opt_parsed * option; option = 0; while (1) { o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv, program_name, usage, version_string, opt_help_msg, opt_version); if (o == opt_none) break; switch (o) { default: safe_printfmt (2, "unhandled option `%s'\n", option->opt_string); panic ("internal error parsing arguments"); usage_error: opt_usage (2, argv[0], program_name, usage, 1); panic_exit (); bogus_arg: safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string); goto usage_error; case opt_output_file: if (!opt_arg) { printfmt (&errn, 2, "missing argument for `%s'\n", opt_string); goto usage_error; } printfmt (&errn, 2, "output file argument: `%s'\n", opt_arg); break; } } return 0; }libhackerlab: The Hackerlab C Library
regexps.com