Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!cs.utexas.edu!uunet!crdgw1!sungod.crd.ge.com!davidsen From: davidsen@sungod.crd.ge.com (William Davidsen) Newsgroups: alt.sources Subject: getoptx - an extended getopt Message-ID: <906@crdgw1.crd.ge.com> Date: 20 Jun 89 20:08:56 GMT Sender: news@crdgw1.crd.ge.com Reply-To: davidsen@crdos1.UUCP (bill davidsen) Distribution: alt Organization: General Electric Corp. R&D, Schenectady, NY Lines: 329 I recently was installing a new version of PD diff and noted that if the -c option was used the argument had to be specified. This appeared to be a limitation of getopt, so I took the PD version which came with smail2.5 and changed it to accept optional arguments to options. Thanks to the people who responded to my initial posting on this. My first idea was to use ? to indicate an optional argument, but I am assurred that -? is a fairly common way of requesting help, so I changed to *. Here's my getopt, called getoptx although I think it's a valid superset of the existing version. This is all PD, and I invite and encourage anyone to include it with their distribution. I was able to convert a number of programs to getopt usage with new use of the new option. Enjoy! #!/bin/sh # shar: Shell Archiver (v1.24) # # Run the following text with /bin/sh to create: # getoptx.c # getoptst.c # getoptx.3 # getoptx.mak # echo "x - extracting getoptx.c (Text)" sed 's/^X//' << 'SHAR_EOF' > getoptx.c && X/* X** @(#)getopt.c 2.5 (smail) 9/15/87 X*/ X X/* X * NOTE: this source has been hacked to allow * in the optstring, X * meaning "an optional argument which must follow the option X * character without a blank." Read the comments following with X * that in mind. X * bill davidsen (davidsen@crdos1.crd.ge.com) June 1989 X */ X X#define OptArgFlg '*' X X/* X * Here's something you've all been waiting for: the AT&T public domain X * source for getopt(3). It is the code which was given out at the 1985 X * UNIFORUM conference in Dallas. I obtained it by electronic mail X * directly from AT&T. The people there assure me that it is indeed X * in the public domain. X * X * There is no manual page. That is because the one they gave out at X * UNIFORUM was slightly different from the current System V Release 2 X * manual page. The difference apparently involved a note about the X * famous rules 5 and 6, recommending using white space between an option X * and its first argument, and not grouping options that have arguments. X * Getopt itself is currently lenient about both of these things White X * space is allowed, but not mandatory, and the last option in a group can X * have an argument. That particular version of the man page evidently X * has no official existence, and my source at AT&T did not send a copy. X * The current SVR2 man page reflects the actual behavor of this getopt. X * However, I am not about to post a copy of anything licensed by AT&T. X */ X X/* for SysV use strchr instead of index */ X#ifdef USG X#define index strchr X#define rindex strrchr X#endif X X/*LINTLIBRARY*/ X#define NULL 0 X#define EOF (-1) X#define ERR(s, c) if(opterr){\ X extern int write();\ X char errbuf[2];\ X errbuf[0] = c; errbuf[1] = '\n';\ X (void) write(2, argv[0], (unsigned)strlen(argv[0]));\ X (void) write(2, s, (unsigned)strlen(s));\ X (void) write(2, errbuf, 2);} X Xextern char *index(); X Xint opterr = 1; Xint optind = 1; Xint optopt; Xchar *optarg; X Xint Xgetoptx(argc, argv, opts) Xint argc; Xchar **argv, *opts; X{ X static int sp = 1; X register int c, ch; X register char *cp; X X if(sp == 1) X if(optind >= argc || X argv[optind][0] != '-' || argv[optind][1] == '\0') X return(EOF); X else if(strcmp(argv[optind], "--") == NULL) { X optind++; X return(EOF); X } X X optopt = c = argv[optind][sp]; X if(c == ':' || c == OptArgFlg || (cp=index(opts, c)) == NULL) { X ERR(": illegal option -- ", c); X if(argv[optind][++sp] == '\0') { X optind++; X sp = 1; X } X return('?'); X } X if((ch = *++cp) == OptArgFlg) { X if(argv[optind][sp+1] != '\0') X optarg = &argv[optind++][sp+1]; X else { X optarg = ""; X optind++; X sp = 1; X } X } X else if(ch == ':') { X if(argv[optind][sp+1] != '\0') X optarg = &argv[optind++][sp+1]; X else if(++optind >= argc) { X ERR(": option requires an argument -- ", c); X sp = 1; X return('?'); X } else X optarg = argv[optind++]; X sp = 1; X } else { X if(argv[optind][++sp] == '\0') { X sp = 1; X optind++; X } X optarg = NULL; X } X return(c); X} SHAR_EOF chmod 0644 getoptx.c || echo "restore of getoptx.c fails" echo "x - extracting getoptst.c (Text)" sed 's/^X//' << 'SHAR_EOF' > getoptst.c && X#include X Xextern char *optarg; Xextern int opterr, optind; X Xmain(argc, argv) X int argc; X char *argv[]; X{ X int ch; X X while ((ch = getoptx(argc, argv, "abc:xD*n?")) != EOF) { X switch (ch) { X case 'c': X printf("option c required arg: %s\n", optarg); X break; X case 'D': X if (*optarg) { X printf("option D optional arg: %s\n", optarg); X } X else { X printf("option D no argument\n"); X } X break; X case 'a': X case 'b': X case 'x': X printf("option %c\n", ch); X break; X case 'n': X printf("Error reporting disabled\n"); X opterr = 0; X break; X default: X printf("Get unknown option! Usage follows.\n"); X } X } X X for (ch = optind; ch < argc; ch++) { X printf("Arg[%2d]: %s\n", ch, argv[ch]); X } X X exit(0); X} SHAR_EOF chmod 0644 getoptst.c || echo "restore of getoptst.c fails" echo "x - extracting getoptx.3 (Text)" sed 's/^X//' << 'SHAR_EOF' > getoptx.3 && X.TH GETOPTX 3 local X.SH NAME Xgetoptx - decode command line options X.SH SYNOPSIS X.B "char getoptx(argc, argv, optstring) X int argc; X char *argv[]; X char *optstring; X extern int optind, opterr; X extern char *optarg; X.SH DESCRIPTION X.I getoptx Xreturns a character which is either (a) one of the known option characters Xspecified in X.IR optstring , X(b) a question mark character (?) if the option is unknown or Xincorrectly specified, or X.B EOF Xif all options have been returned. If the caller has specified that an Xoption requires or accepts an argument, the string value of the argument Xis returned in X.IR optarg . XIn the case of an optional argument X.I optarg Xmay point to an empty ("") string. X.SS Format of optstring X.I optstring Xcontains the values of the option characters which are recognized. In Xaddition any character may be followed by a colon (:) is it requires an Xargument, or an asterisk (*) if it accepts an optional argument. X.SS Format of the command line XThe command line parsed by X.I getoptx Xconsists of the command name, followed by zero or more options separated Xby blanks, followed by arguments to the command. The options are ended Xby any of (a) the end of data on the command line, (b) a token which Xdoes not start with a hyphen (-), or (c) the special token --. X.SS Using ? as a valid option XAlthough X.I getoptx Xreturns the ? as an indication of an unknown option, or one used Xwithout a required argument, the ? may be included in the X.I optstr Xso that ? becomes a known option. The effect is that specifying any Xinvalid option will generate an error message, while using -? as an Xoption does not. In either case a ? returned from X.I getoptx Xcan be used to display a usage message. X.br X.ne 1.5i X.SH EXAMPLES X.tr ~ X cval = getoptx(argc, argv, "al:sD*"); X XThe options 'a' and 's' are returned without arguments. The option 'l' Xrequires an argument, which may be part of the same command line token Xas the option (as:~-l40) or as the following token (as:~-c~40). The Xoption 'D' may be immediately followed by an argument, and if there is Xno argument it must be the last option in the token. X.br X.ne 1.5i X.SH WARNINGS XA warning message is displayed on X.B stderr Xand the character ? is returned is either (a) an option character not in X.I optstr Xis found, or (b) a known option which requires an argument does not have Xone. If the variable X.I opterr Xis set to zero the warning message will not be displayed. X.br X.ne 1.5i X.SH SEE ALSO X.SH LIMITATIONS XThe characters colon (:) and asterisk (*) may not be option characters. X.br X.ne 1.5i X.SH AUTHOR XMan page by Bill Davidsen (davidsen@crdos1.crd.ge.com). Original getopt Xsource attributed to AT&T public domain version from 1985 UNIFORUM, Xchanges by Bill Davidsen. All original work by Bill Davidsen is hereby Xplaced in the public domain. SHAR_EOF chmod 0666 getoptx.3 || echo "restore of getoptx.3 fails" echo "x - extracting getoptx.mak (Text)" sed 's/^X//' << 'SHAR_EOF' > getoptx.mak && X# makefile for extended getopt program X# X# make via "make -f getoptx.mak" X X# define USG if V&, SysIII, SysV or other non-BSD XUSGOPT = -DUSG X X.c.o: X $(CC) $(USGOPT) $< -c X Xtest: getoptst suite X Xgetoptst: getoptst.o getoptx.o X $(CC) -o getoptst getoptst.o getoptx.o X Xsuite: X @echo; echo "Test1: (one valid option)" X ./getoptst -a "just a" X @echo; echo "Test2: (option withy arg and args to program)" X ./getoptst -xc40 -a x "c inline arg 40" "a follows" X @echo; echo "Test3: (arg to option after whitespace)" X ./getoptst -c 40 "c arg 40" X @echo; echo "Test4: (optional arg to -D not given)" X ./getoptst -D -a "options D and a" X @echo; echo "Test5: (optional arg to -D given)" X ./getoptst -Dokay -x "D arg okay" x X @echo; echo "Test6: (-- ends options, -c arg to prog)" X ./getoptst -c"last arg" -- -c "-c arg not option" X @echo; echo "Test7: (invalid option m)" X -./getoptst -m X @echo; echo "Test8: (missing arg to option c)" X -./getoptst -c X @echo; echo "Test9: (explicit ? option)" X -./getoptst -? X @echo; echo "Test10: (use -n to disable warning)" X -./getoptst -n -Q X X# subsitute your favorite shar here or on the make line, as X# make shar "SHAR=myshar -options" X XSHAR = shar Xshar: X $(SHAR) getoptx.c getoptst.c getoptx.3 getoptx.mak > getoptx.shar SHAR_EOF chmod 0644 getoptx.mak || echo "restore of getoptx.mak fails" exit 0 bill davidsen (davidsen@crdos1.crd.GE.COM) {uunet | philabs}!crdgw1!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me