home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume3
/
egetopt
/
README
< prev
Wrap
Text File
|
1989-02-03
|
7KB
|
195 lines
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