home *** CD-ROM | disk | FTP | other *** search
- egetopt.c -- Extended 'getopt'.
-
- A while back, a public-domain version of getopt() was posted to the
- net. A bit later, a gentleman by the name of Keith Bostic made some
- enhancements and reposted it.
-
- In recent weeks (i.e., early-to-mid 1988) there has been a sometimes
- heated discussion in comp.lang.c about the merits and drawbacks of
- getopt(), especially with regard to its handling of '?'.
-
- In light of this, I have taken Mr. Bostic's public-domain getopt()
- and have made some changes that I hope will be considered to be
- improvements. I call this routine 'egetopt' ("Extended getopt").
- The default behavior of this routine is the same as that of getopt(),
- but it has some optional features that make it more useful. These
- options are controlled by the settings of some global variables.
- By not setting any of these extra global variables, you will have
- the same functionality as getopt(), which should satisfy those
- purists who believe getopt() is perfect and can never be improved.
- If, on the other hand, you are someone who isn't satisfied with the
- status quo, egetopt() may very well give you the added capabilities
- you want.
-
- egetopt() behaves like getopt() with the following added capabilities:
-
- -- The '?' which gets returned when there is an unrecognized option
- is now stored in a global integer called 'optbad', and the caller
- can set this value to anything. The initial value in 'optbad' is
- '?', which means that the default behavior is just like that of
- getopt(). For example, If you want egetopt() to return '~'
- instead of '?' when it sees an invalid option, put the following
- lines in your code before egetopt() gets called:
-
- extern int optbad;
- optbad = (int)'~';
-
- -- Options can begin with characters other than just '-'. There
- is now a global character pointer called 'optstart'. It points
- to a string which consists of a list of characters which can
- be used to begin options. The initial string that 'optstart'
- points to is "-", so the default behavior is like that of
- getopt(). For example, if you want to allow both '+' and '-'
- as option delimiters, put the following lines in your code
- before egetopt() gets called:
-
- extern char *optstart;
- optstart = "-+";
-
- -- Now that there's a choice of the characters that can precede options
- it's desirable to let the caller know what character begins a
- given option. In egetopt(), the global integer 'optchar' will
- now contain the character that begins a given option, or 0 if
- there was an error. Just put the following line in your code
- and you can check the value of 'optchar' after each call to
- egetopt():
-
- extern int optchar;
-
- -- The old getopt() writes error messages to file descriptor 2
- (or to stderr, depending on your implementation). In egetopt(),
- you can change this file descriptor to be anything you want.
- The global integer 'opterrfd' contains the file descriptor
- to use for writing error messages. As you might have guessed,
- this variable is initialized to 2. As an example, if you want
- your egetopt() errors to go to the file "egetopt.errs", do
- something similar to the following before calling egetopt():
-
- extern int opterrfd;
-
- FILE *eout = fopen("egetopt.errs", "w");
-
- if (eout == (FILE)NULL) {
- /* error condition/
- ...
- exit(1);
- }
-
- opterrfd = fileno(eout);
-
- -- Some implementations of getopt() allow you to set the global
- integer 'opterr' to control whether error output is printed:
- it is initialized to 1, which enables error output (as does
- any non-zero value); setting it to 0 disables error output.
- In egetopt(), 'opterr' is treated the same way.
-
- -- The old getopt() forces you to use ':' in the string of option
- letters to show that a given option takes an argument. There is
- now a global integer called 'optneed' which contains this value,
- so you can change it to something else if you want. As you might
- have suspected, 'optneed' is initialized to ':'.
-
- In addition, something that I always found annoying about the old
- getopt() is its inability to handle non-mandatory option arguments.
- For example, if an option called 'd' was specified as taking
- an argument to the program 'foo', you'd get the following
- results when invoking 'foo' in different ways:
-
- 1) foo -dABC -x ...
-
- getopt() return: 'd'
- optarg: "ABC"
-
- 2) foo -dABC -x ...
-
- getopt() return: 'd'
- optarg: "ABC"
-
- 3) foo -d -x ...
-
- A) getopt() return: 'd'
- optarg: "-x"
-
- In the case of number 3, sometimes one would prefer to get ...
-
- B) getopt() return: 'd'
- optarg: NULL
-
- This would allow "-x" to be handled as another option in the next
- call. In the old getopt(), you can get the 3B behavior by testing
- the first character of 'optarg' and decrementing 'optind' if this
- character is '-'. However, since I am enhancing the routine
- anyway, I decided to build in the ability to have either the 3A
- or the 3B behavior.
-
- Since this behavior isn't always desired, I have added another
- global integer called 'optmaybe' which optionally allows you to
- control whether an option with an argument will get treated as number
- 3A or as number 3B above. It is used similarly to 'optneed'. It is
- initialized to 0, meaning that behavior 3B is impossible in the
- default case. The following example shows how 'optneed' and
- 'optmaybe' can be used:
-
- extern int optneed;
- extern int optmaybe;
-
- optneed = (int)'!'; /* use '!' instead of ':'/
- optmaybe = (int)'%'; /* use '%' for optional arguments/
-
- ...
-
- while ((c = egetopt(argc, argv, "abc!d%x")) != EOF) ...
-
- In this example, options 'a', 'b', and 'x' take no arguments,
- option 'c' takes a mandatory argument, and option 'd' takes
- a non-mandatory argument. If this is contained in program 'foo',
- you'll get the following behavior when you run it:
-
- foo -a -cABC -dXYZ -d -x -c -b ...
-
- egetopt() return: 'a'
- optarg: NULL
-
- egetopt() return: 'c'
- optarg: "ABC"
-
- egetopt() return: 'd'
- optarg: "XYZ"
-
- >>>>>>>>>> egetopt() return: 'd'
- >>>>>>>>>> optarg: NULL
- >> NOTE >>
- >>>>>>>>>> egetopt() return: 'x'
- >>>>>>>>>> optarg: NULL
-
- egetopt() return: 'c'
- optarg: "-b"
-
- ...
-
- Remember that 'optneed' is initialized to ':' and 'optmaybe'
- is initialized to 0. This causes behavior identical to that
- of getopt() unless you specifically override it.
-
- Since the default behavior of egetopt() is the same as that of getopt(),
- there is no reason why you can't rename this routine to getopt() and
- use it in place of the original. I gave it a new name so as not to
- offend those of you who believe that getopt() is perfect and should
- never have any new features added to it.
-
- The code was originally posted to the net as getopt.c by ...
-
- Keith Bostic
- ARPA: keith@seismo
- UUCP: seismo!keith
-
- Current version: added enhancements and comments, reformatted code.
-
- Lloyd Zusman
- Master Byte Software
- Los Gatos, California
- Internet: ljz@fx.com
- UUCP: ...!ames!fxgrp!ljz
-
- May, 1988
-