Richard Kettlewell, <rjk@greenend.org.uk>
© 1999, 2000, 2003 Richard Kettlewell
This manual is free software; you may redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version.
This is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details.
A copy of the GNU General Public License is available on the World Wide Web at http://www.gnu.org/copyleft/gpl.html. You can also obtain it by writing to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Rgetopt is a library of C functions for parsing program command line arguments.
When you invoke a program from a shell, you often supply a number of arguments on the command line. For example:
ls -lR *.c >ls-lR
Some of these arguments are handled by the shell itself; for example the redirection >ls-lR never reaches the program ls, instead the shell redirects the programs output before starting it. Also, the *.c is "expanded" and replaced with the names of all the files in the current directory matching the pattern.
So as far as the called program is concerned the command line probably looks something like this:
ls -lR foo.c bar.c
It is then the job of ls to determine which of the arguments are filenames and which are options; and to act according to the meaning of the options. For a simple program this is relatively easy, for more complex programs the job of parsing the command line can occupy many lines of C.
A common solution is to use the getopt function. However, it has a couple of flaws.
Firstly, it only supports "short" argument names - -d but not --debug, for example. While short option names are suitable for users who use a program every day and are very familiar with it, they can be very opaque for new or occasional users.
Secondly, you must call it in a loop and "switch" on the return value to distinguish between the various options. Any parsing beyond the simple question of whether an option takes an argument or not must be done by the calling code.
Other flaws include the fact that it uses global variables to pass information around. Although this isn't a problem for its usual application, it's not a clean way to work.
Rgetopt works differently to getopt. It takes as a parameter a table of command-line options, each of which may have long and short forms. Each option has a description field, and a type field which indicates what kind of argument (if any) it takes - an integer, a string, etc.
It is called only once, and parses the entire set of options. Pointers in the table are used to set the appropriate variables according to the options, rather than relying on the calling code to handle this. When the required action for an option is outside the set that Rgetopt knows about, it can call back a supplied function to handle it (though this isn't necessarily the best way to handle this kind of situation).
Rgetopt can do file type and existence checks, and use regular expressions to check the value of string options.
Any source file that calls part of Rgetopt must include the header file first. It's necessary to include <stdio.h> since <rgetopt.h> refers to types defined in that header. For example:
#include <stdio.h> #include <rgetopt.h>
The following things are defined:
The macros rgetopt_ret_error, rgetopt_ret_version and rgetopt_ret_help,
The types struct rgetopt and enum rgetopt_fileflags
Various functions including rgetopt and rgetopt_printhelp,
Helper macros with names starting RGETOPT_, and
Various private internal things with names starting rgetopt_ or RGETOPT_.
Future versions may define further private or public names starting rgetopt_ or RGETOPT_.
It is necessary to write an option table, which is an array of type struct rgetopt. See section 3.1.4 for the definition of this type and the meanings of the fields. For each element you write three values specifying the long name of the option, a description, and the short name (or 0 if there isn't one) followed by a macro indicating the type of the option and providing extra information.
The table is terminated with the RGETOPT_END macro.
There is one special option (with two forms) built in to Rgetopt; the strings - and -- always indicate the end of the options parsed by Rgetopt; anything beyond whichever of them is used will never be treated as an option.
Here is an example option table, from the test program:
static const struct rgetopt options[] = {
{"--int", "rgetopt_int test", 'i',
RGETOPT_INT(&intval, 99)},
{"--long", "rgetopt_long test", 'I',
RGETOPT_LONG(&longval, 999)},
{"--intparm", "rgetopt_intparm test", 'p',
RGETOPT_INTPARM(&intval)},
{"--longparm", "rgetopt_longparm test", 'P',
RGETOPT_LONGPARM(&longval)},
{"--string", "rgetopt_string test", 's',
RGETOPT_STRING(&stringval)},
{"--addint", "rgetopt_addint test", 'a',
RGETOPT_ADDINT(&intval, 66)},
{"--addlong", "rgetopt_addlong test", 'A',
RGETOPT_ADDLONG(&longval, 666)},
{"--fn", "rgetopt_fnparm test", 'f',
RGETOPT_FNPARM(testfn)},
{"--toggle", "rgetopt_toggle test", 0,
RGETOPT_TOGGLE(&intval)},
{"-toggle", "rgetopt_toggle test", 0,
RGETOPT_TOGGLE(&intval)},
{"", NULL, 0,
RGETOPT_HELP},
{"", NULL, 0,
RGETOPT_VERSION},
{RGETOPT_END},
};
Notice that although most of the long options start with --, this is not mandatory; a single dash will do. However, it is possible to confuse such options with the short option names; in such a situation, the "long" version always wins.
You call rgetopt as follows:
int main(int argc, const char *const argv[]) {
int n;
n = rgetopt(argc, argv, options);
/* ... */
...where options is the option table described in the previous section.
The return value may be a non-negative integer, in which case the call succeeded and the return value represents the index of the first non-option argument (or the value of argc if there were none); or a negative integer indicating some kind of special condition. See section 3.1.6 for the list of these.
rgetopt_printhelp is used to produce part of the help output from a program. You call it as follows:
/* ... */
if(rgetopt_printhelp(stdout, options)) {
/* I/O error */
}
If all the I/O function calls to output the list succeed, the return value is 0. If one of them fails then rgetopt_printhelp immediately returns -1. It doesn't touch errno at all so assuming that was set to something useful, it will be preserved for the calling code to interpret.
The output typically looks something like this:
-i,--int rgetopt_int test -I,--long rgetopt_long test -p,--intparm rgetopt_intparm test -P,--longparm rgetopt_longparm test -s,--string rgetopt_string test -a,--addint rgetopt_addint test -A,--addlong rgetopt_addlong test -f,--fn rgetopt_fnparm test --toggle,--no-toggle rgetopt_toggle test -toggle,-no-toggle rgetopt_toggle test -h,--help Issue help message -V,--version Display version number
There is an alternative interface, rgetopt_helpstring, which just returns the full help text as a null-terminated string.
For a complete example, see rgtest.c in the source distribution. This uses all of the features of Rgetopt, and is used in testing.
Errors are (largely) reported by calling the function pointer stored in rgetopt_error. The default version of this, rgetopt_default_error, writes a message to standard error, which will be fine for most applications, but it can be overridden to do something more interesting.
You can set rgetopt_progname to your program's name (deduced from argv[0] for instance) to include it in the error message.
Memory management is performed by calling the function pointers stored in rgetopt_malloc, rgetopt_realloc and rgetopt_free. By default these are initialized to the obvious C library functions, but they can be changed to something else by the caller.
If they are set to something else then they should follow the same basic rules as the C library versions. In particular it must be safe to pass a null pointer to rgetopt_free and rgetopt_realloc. However, rgetopt_realloc will never be called with a second argument of zero (at least by Rgetopt).
rgetopt - table-driven option parsing
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
struct rgetopt;
int rgetopt(int argc, const char *const *argv,
const struct rgetopt *tab);
rgetopt parses program command line options according to a table. The argc and argv parameters are taken from the arguments to main and the tab parameter is the address of the option table. Everything starting "-" is considered to be an option, up to the first non-option argument, with the exception that "-" or "--" on their own ends the list of options (and counts neither as an option nor a non-option argument).
The option table has the following structure:
struct rgetopt {
const char *longname;
const char *description;
int shortname;
/* ... */
};
The meanings of the fields are as follows:
The "long" name for the option. Always starts with -- or -.
The description for the option. This should be a piece of text which describes the meaning of the option; it is used by rgetopt_printhelp.
The "short" name for the option. This should be a character literal, e.g. 'd'. If there is no short name for the option, use 0.
There are additional fields, but their values are not supposed to be used by user programs. Instead, use the various RGETOPT_ macros to fill them in.
The following macros are currently supported:
The option takes no argument and sets *ptr to have value value. ptr has type int * or long *, respectively.
As above, but the value is added to *ptr instead of being assigned to it.
The option takes an argument and sets *ptr to that value. If the argument is not a number, or is not in range, an error is returned. Again, ptr has type int * or long *, respectively.
The option takes no argument and sets *ptr to 1. However, if the option is used with an initial --no then *ptr is set to 0 instead. ptr has type int *.
Note that the `short' name for toggle options must be zero.
The option takes an argument, which is saved at *ptr. ptr has type const char **.
This is the same as RGETOPT_STRING except that it has an extra parameter which should be a POSIX extended regular expression. If the option does not match the regexp then it will be rejected.
Note that if you use an invalid regexp here, your program will coredump.
Rgetopt requires the <regex.h> header file (and the associated C functions) to be present for this to work. It will still build if they are missing, however; but trying to use the feature will return an error.
This is the same as RGETOPT_STRING, except that it has an extra flags parameter which specifies a set of checks to be performed on the parameter (which is assumed to be a filename).
This value should be the bitwise or of any of the values of the enumeration rgetopt_fileflags (see below). The order that the flags are checked in is not defined.
The checks are performed via the rgetopt_access callback, defined below. By default this points to access(2) but it could be modified to something else.
Note that this check is for user interface purposes, not for security purposes. A hostile user could easily subvert it.
The option takes many arguments. The first is a delimiter; this may be any of {, [, ( or < in which case the corresponding end delimiter will be the same character "reversed", or any other string in which case the end delimiter will just be the same string again.
The arguments between the delimiter and the end delimiter are passed back in an array of pointers to characters via ptr, which has type const char ***.
The array is allocated with rgetopt_malloc, and the elements point into the argument vector. Any previous value will be released with rgetopt_free.
These implement the --version and --help options.
The option takes an argument, which is passed to the specified function. The function should take two arguments, the first having type const struct rgetopt * and pointing to the table entry which matched, and the second having type const char * and pointing to argument string.
The function returns an int, which should be zero on success and non-zero on error. If an error is detected then rgetopt_ret_error will be returned, without rgetopt_error having been called.
The table ptr, which is of type const struct rgetopt *, will be searched for additional options.
Additionally the macro RGETOPT_END should always be used to fill in the last line of the table.
rgetopt_fileflags is an enumeration containing the possible file checks. They are rgetopt_exists, rgetopt_readable, rgetopt_writable, rgetopt_execable and rgetopt_directory. To find the inverse of a particular check, either insert a _not_ in the middle or use the macro RGETOPT_NOT().
If you want to e.g. check for a file that exists and has some other property, e.g. readability, just check for the other property; a nonexistent file is not considered to be readable, writable or executable.
The return value is the index in the argv array of the first non-option argument, or a negative number from the following list:
Some kind of error occurred parsing the arguments. rgetopt_error will have been called, except as noted above. The normal action in this case would be to terminate the program with a non-zero exit status, possibly after issuing a message describing how to get usage information for the program.
The --version option was used. The normal action in this case would be to report the program's name and version number to standard output, and terminate with status 0.
The --help option was used. The normal action would be to print a synopsis of the program's command-line syntax, and then called rgetopt_printhelp(3) to output the descriptions for each option in the option table. See below for more information.
rgetopt_printhelp(3), rgetopt_helpstring(3), rgetopt_from_rcfile(3), rgetopt_from_file(3), rgetopt_from_fp(3), rgetopt_parse(3), rgetopt_zsh_compctl(3), rgetopt_error(3), rgetopt_malloc(3)
rgetopt_printhelp - display usage message
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
struct rgetopt;
int rgetopt_printhelp(FILE *fp,
struct rgetopt *tab);
rgetopt_printhelp is used to generate a list of options and descriptions from the same table. It returns 0 on success or -1 if an output error occurs. errno is unchanged since the error (it may depend on the local stdio whether it is meaningful).
rgetopt(3), rgetopt_helpstring(3)
rgetopt_helpstring - construct usage message
cc ... -lrgetopt #include <stdio.h> #include <rgetopt.h> struct rgetopt; char *rgetopt_helpstring(struct rgetopt *tab);
rgetopt_helpstring is used to generate a list of options and descriptions from the same table. It returns a pointer to a null-terminated string containing the help text on success and a null pointer on error. errno is unchanged since the error (it may depend on the local stdio whether it is meaningful).
The memory for the string is allocated as by regopt_malloc(3) and the caller is responsible for freeing it.
rgetopt(3), rgetopt_printhelp(3), rgetopt_malloc(3)
rgetopt_from_file - read options from a file
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
struct rgetopt;
int rgetopt_from_file(const char *path,
const struct rgetopt *tab);
rgetopt_from_file opens the named file, reads options from it as described in rgetopt_parse(3) and then interprets them by passing them and the option table to rgetopt(3). It is an error for the file not to exist.
The return value is non-negative on success and negative on error. rgetopt_error(3) is called to report any errors.
rgetopt_parse(3), rgetopt(3), rgetopt_from_fp(3), rgetopt_from_rcfile(3), rgetopt_error(3)
rgetopt_from_fp - read options from an open file
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
struct rgetopt;
int rgetopt_from_fp(FILE *fp, const char *path,
const struct rgetopt *tab);
rgetopt_from_fp reads options from file fp as described in rgetopt_parse(3) and then interprets them by passing them and the option table to rgetopt(3).
If an I/O error occurs, then path is used in the error message as the filename.
The return value is non-negative on success and negative on error. rgetopt_error(3) is called to report any errors.
rgetopt_parse(3), rgetopt(3), rgetopt_from_file(3), rgetopt_from_rcfile(3), rgetopt_error(3)
rgetopt_from_rcfile - read default options
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
struct rgetopt;
int rgetopt_from_rcfile(const char *filename,
const struct rgetopt *tab);
rgetopt_from_rcfile tests for a file with the name given by filename in the user's home directory. If it exists, then options are read from it as described in rgetopt_parse(3) and then interprets them by passing them and the option table to rgetopt(3).
The return value is non-negative on success and negative on error. rgetopt_error(3) is called to report any errors.
If the process is privileged, as detected by having a distint UID and effective UID or a distinct GID and effective GID, rgetopt_from_rcfile currently an error.
The point of this check is that by setting the value of HOME, a hostile user could otherwise trick this function into reading a file that it should not be able to. However, rather than rely on this check, you should simply not call this function in any privileged program.
rgetopt_parse(3), rgetopt(3), rgetopt_from_file(3), rgetopt_from_fp(3), rgetopt_error(3)
rgetopt_parse - read default options
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
struct rgetopt;
int rgetopt_parse(FILE *fp, const char *path,
int *argcp, char ***argvp);
rgetopt_parse reads options from the open file fp and stores them in an array of strings.
*argcp is assigned the number of elements in the array, and *argvp is assigned with the address of the array itself. The array includes a terminating NULL which is not included in the count. The array and all its members are allocated individually with rgetopt_malloc and rgetopt_realloc.
If an I/O error occurs, then path is used in the error message as the filename.
The return value is 0 on success and nonzero on error.
The basic structure of the input file is of a list of tokens separated by whitespace. All characters contained in single quotes stand for themselves. Double quotes are similar except that a backslash may be used to escape a following backslash or double quote; a backslash not followed by an escape or double quote does not have any special properties. The backslash can also be used outside of any quotes to escape any character.
Currently it is impossible to spread a token across many lines.
Lines starting # are ignored, as comments.
The return value is 0 on success and nonzero on error. rgetopt_error(3) is called to report any errors.
rgetopt(3), rgetopt_from_rcfile(3), rgetopt_from_file(3), rgetopt_from_fp(3), rgetopt_error(3), rgetopt_malloc(3)
rgetopt_zsh_compctl - generate zsh compctl instructions
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
struct rgetopt;
int rgetopt_zsh_compctl(const struct rgetopt *tab,
const char *progname,
FILE *fp);
rgetopt_zsh_compctl outputs a compctl command suitable for use by zsh(1) to the specified stream.
tab gives the table to interpret, progname gives the program name to use and fp is the file to which output should be written.
The return value is 0 on success and nonzero on error.
This function is not really finished; it does not recurse into sub-tables and it only adds completion over option names.
rgetopt(3)
rgetopt_error - rgetopt error reporting callback
cc ... -lrgetopt
extern void (*rgetopt_error)(int errno_value,
const char *fmt,
...);
rgetopt_error is called by the rgetopt library to report an error. The default value, rgetopt_default_error, just reports to standar error but by assining this variable alternative styles of error reporting may be used.
fmt is a printf-style format string controlling the interpretation of the remaining arguments. If errno_value is nonzero then the result of strerror(errno) should be included in the error message.
rgetopt_default_error(3)
rgetopt_default_error - default rgetopt error reporting callback
cc ... -lrgetopt
#include <stdio.h>
#include <rgetopt.h>
void rgetopt_default_error(int errno_value,
const char *fmt,
...);
extern const char *rgetopt_progname;
rgetopt_default_error is the default implementation of rgetopt_error. It writes the error message to stderr with a terminating newline.
If rgetopt_progname is not a null pointer then it is included in the error output.
rgetopt_error(3)
rgetopt_malloc, rgetopt_realloc, rgetopt_free - memory management callbacks for rgetopt
cc ... -lrgetopt #include <stdio.h> #include <rgetopt.h> extern void *(*rgetopt_malloc)(size_t n); extern void *(*rgetopt_realloc)(void *ptr, size_t n); extern void (*rgetopt_free)(void *ptr);
These function pointers are used for memory allocation by all the rgetopt_ routines. By default they point to the standard C library functions malloc, realloc and free.
rgetopt_malloc should allocate space for n bytes, aligned suitably for any type, and return a pointer to it. If memory cannot be allocated it should return a null pointer. It is also allowed to return a null pointer if n is zero. The memory need not be initialized to anything in particular.
rgetopt_realloc grows or shrinks an allocated region to be n bytes long, and return a pointer to the modified region (which might be different to the orgiginal location). ptr might be a null pointer in which case new space should be allocated. The behaviour is not defined when n is zero and the rgetopt_ functions never do this.
rgetopt_free releases memory allocated with the above functions. If ptr is a null pointer it should do nothing.
rgetopt_malloc and rgetopt_realloc both return a pointer to the newly allocated or modified space, or a null pointer on error, and may return a null pointer if the size argument is zero.
rgetopt(3)
rgetopt_access - callback to check file access
cc ... -lrgetopt #include <stdio.h> #include <rgetopt.h> extern int (*rgetopt_access)(const char *path, int mode);
This function pointer is used by Rgetopt to check whether path can be accessed according to mode. By default it points to the standard library function access, but it could point instead to euidaccess (if available) or some other function with the same interface.
The regexp support will call abort(3) under certain circumstances, leading to coredumps. This is documented and is not a bug; it indicates a problem with your program.
(There may be other circumstances in which you get coredumps where rgetopt really is at fault, however.)
Please report any bugs to Richard Kettlewell at <richard+rgetopt@greenend.org.uk>. If possible, include a small example which demonstrates the problem. See http://www.greenend.org.uk/rjk/2002/11/patches.html for details about sending patches.
If you don't send me enough information to replicate the problem, your bug won't get fixed.