Xref: utzoo comp.lang.c:8560 comp.unix.wizards:7376 Path: utzoo!mnetor!uunet!mcvax!enea!zyx!aj From: aj@zyx.UUCP (Arndt Jonasson) Newsgroups: comp.lang.c,comp.unix.wizards Subject: command line options Message-ID: <2414@zyx.UUCP> Date: 25 Mar 88 16:23:47 GMT Reply-To: aj@zyx.SE (Arndt Jonasson) Organization: ZYX Sweden AB, Stockholm, Sweden Lines: 100 [If your interest is not Unix, skip the rest of this article.] This is a suggestion for a command line parsing routine for C programs in Unix. To be sure, 'getopt(3)' exists. It comes with SystemV, I believe, and there exists a public-domain version written by Henry Spencer. I find it a little bit too awkward to use, since I have to write a lot of code to interface to it (a loop with a case statement in it, usually). Another problem is that the names of the options occur twice, once in the argument to 'getopt' and once in the 'case' statement. It is never a good thing to duplicate information in a program. This is not really criticism of 'getopt'. No doubt it is being used by some, and after a few times of using it, I could probably remember its calling conventions. [Do many people actually use it? I don't know. Most Unix tools don't seem to use it.] Does the ANSI C committee address this issue? Probably not, since argument parsing can be quite different on various operating systems. POSIX, perhaps? Recently, I invented a parsing routine of my own that doesn't require the program logic to be supplied by the application programmer. Instead, a static option descriptor array is initialized at compile time and passed to the function 'O_parse_options' at runtime. Most programs won't need to access 'argc' and 'argv' at all (they have to be supplied to this function, of course). I post this in the hope of getting constructive comments on what features are missing in my scheme, and whether it is perhaps too restrictive or too general. If it seems to be generally useful, I will post the code to comp.unix.sources. An example program that exhibits nearly all the features follows: #include "options.h" #include main (argc, argv) int argc; char **argv; { int n; static int flag = 0; static int number = 0; static double dbl = 3.14; static char character = 'A'; static char *string = "kvack"; static Option desc[] = { O_flg ('f', flag), O_int ('i', number), O_str ('s', string), O_chr ('c', character), O_dbl ('d', dbl), O_directive ("remaining: 1-2"), O_directive ("usage: [-f] [-i nn] [-cC] [-d float] [-s string] src [dst]"), O_end, }; n = O_parse_options (desc, argc, argv); } 'O_parse_options' uses the same model as 'getopt', i.e. first come the options, preceded by hyphens (they may be grouped together after one hyphen), then come the non-option arguments. If an option -s takes an argument, both '-sfoo' and '-s foo' are valid. It will either successfully parse all the options and store values in the appropriate variables, or exit the program with an error message. The error message describes what option was offending, and in what way, e.g.: 1 to 2 non-option arguments are required The -i option requires an argument There is no -q option Invalid integer 'foo' given to the -i option After the error message, the usage line will be printed, consisting of the contents of the "usage" directive with the name of the program inserted, like this: usage: tst [-f] [-i nn] [-cC] [-d float] [-s string] src [dst] This is also what 'usage()' will print when called from the application program, unless a '#undef usage' has been done. The name of the program is available in the variable O_programname for use by the application. If successful, 'O_parse_options' returns a positive integer which is the index in argv of the first non-option argument (if none, it will point past the argument list). The application program can thus easily pick up the remaining arguments; that they are not too few or too many has already been checked. -- Arndt Jonasson, ZYX Sweden AB, Styrmansgatan 6, 114 54 Stockholm, Sweden email address: aj@zyx.SE or !mcvax!enea!zyx!aj