This is how you can make your own programs handle options using a standard option parser just like all of the test programs supplied with Prosody.
The option parser is generated from a file which lists the options required. To use it, you need some code like this in your program:
static const char version[] = "v1.2"; #include "gen/ansplay.args.i" int main(int argc, char **argv) { /* <- your normal declarations here */ ARGS_DECL /* <- possibly more normal declarations */ (void) argc; if (ARGS_CALL || !*argv || argv[1]) { fprintf(stderr, "Usage: %s" ARGS_USAGE " file\n", progname); return 1; } /* use the options by referring to arg.OPTIONNAME */
So how does this work?
#include
arg
into which all the option values will be stored.
argv
to the first non-option.
Since this would lose the name of the program (which was in
argv[0]
) it copies the program name into the variable
progname
. In the example, the program expects to have a
file name as its only non-option argument. Therefore the "if
(...
" tests for a parsing error (ARGS_CALL
returns
a non-zero value if the options are syntactically invalid), and then
tests to make sure that there is exactly one argument remaining (by
checking for the null pointer which is always the last entry in
argv
).
arg.
optionname
ARGS_CALL
has returned successfully, all the option
values are in the arg
structure. For example, if you
have an option "-v 6
" which is the volume
option, then arg.volume
will be six. The names of the
fields are the long option names which are also used in the usage
message, so a program with such a volume option would have "...
-v volume
..." in its usage message.
You also need the file which specifies the options. Here is an example. It's the argument specification for ansplay.
-TiNGtrace a agc unsigned F format string s speed signed t timeslot timeslot v volume signed
The usage message is:
Usage: ansplay [--version] [-a agc] [-F format] [-s speed] [-t timeslot] [-v volume] file
As you can see, there are five normal options, the special
"-version
" option, and the special
"-TiNGtrace
n" option (which is not listed).
Each line specifies one option. Normally, the first column shows the
name of each option. The next column gives a longer name to it. This
name is used in the "usage" message and as the name of the field in
the arg
structure. The third column says what kind of
option it is. There are five kinds of options:
type | meaning | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
bool | A boolean option. This takes no value, so it is either
present or absent. The value in the arg field is
zero if the option was omitted, non-zero otherwise.
| ||||||||||||
unsigned | An unsigned number. The value associated with this option
will be returned in an unsigned long .
| ||||||||||||
signed | A signed number. The value associated with this option
will be returned in a long .
| ||||||||||||
string | An arbitrary string. The value associated with this option
will be returned in a char * . Note that this is
the only option whose presence can be detected by the
application, since the NULL string is returned if the option
is omitted.
| ||||||||||||
timeslot | A timeslot specification. This uses the type
MVIP which you must define. It must be a
structure with three fields: stream ,
timeslot , and type . If the user
invokes the command with a timeslot option whose value is
1:2:u then these fields will be set to
1 , 2 , and
kSMTimeslotTypeMuLaw respectively. The values
used in the type field are:
|
The first line in the example argument specification specifies the special
option "-TiNGtrace
". This option is treated differently
from all the others because the code generated to handle it does
everything required. The program does not need to know when it is
used. When used, this option controls API tracing by setting the
global variable TiNGtrace
to the value specified with
the option.
Run the perl script $(TiNG)/libutil/mkargs.pl passing it the name of the file in which you put the option specification. It will print out some C code which implements the option parsing. For example:
perl ../libutil/mkargs.pl ansplay.args >gen/ansplay.args.i
You can use any name you like for the output file, but in Prosody
the extension ".i
" is used for C code which is
#include
d into another file, while ".h
" is
used only for declarations.
That's it.