This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Re: getopt reinvocation/reentrancy
Gregory Pietsch wrote:
I believe that I caught the problem. In your test program, the -a and -b
switches weren't defined in your list of short options, so getopt was
returning a question mark. Fixing the testing program and applying the
latest Bug-Free(tm) getopt should work. -- Gregory
Sorry about the stupid mistake in the test program.
Am I supposed to have the Bug-Free(tm) version of getopt?
Fixing that still doesn't make the version I have work.
I have attached my updated test program. Am I doing
something else stupid that you fixed?
Thanks.
--joel
Joel Sherrill wrote:
Gregory Pietsch wrote:
I tried to add the reentrant functions to the getopt implementation.
Please check it out and if it's okay, patch away. -- Gregory Pietsch
It doesn't work for me. I have attached a test which I
hacked together which I think shows the failure. It could
be me but you have a test anyway. I hacked a bit to
get it to compile natively on Fedora but use the RTEMS
shell make args and call a main() a couple of times.
A quick look at the shows the old global variables
are still in getopt.c.
Thanks for the quick turn around.
Joel Sherrill wrote:
Hi,
We have been working on the RTEMS Shell and
I noticed something that I don't know how to
properly deal with. I am sure it is beyond
the requirements of opengroup.
RTEMS applications are usually a single statically
linked executable so there can only be one main.
So we have main's for each command (e.g. main_cat(),
main_cp(), main_cpuuse(), etc.). Each main_XXX
is passed an argc, argv set and may use getopt()
to interpret it.
The problem is that newlib's getopt() uses global
variables to hold state as the arguments are parsed.
That is the crux of the reentrancy issue.
If you invoke getopt() to parse a second set of
options, the state information on the second set
is left over from the end of parsing the first set.
In the case I discovered this, I was doing this:
netstats -c -u -i
netstats -t
On the second netstats invocation, the state pointed
passed the end of the set of arguments so nothing
was parsed.
I am looking for suggestions on how to enhance
getopt to support this type of usage. I do not
see getopt_r in /usr/include on Fedora 8 but Google
shows that glibc had this type of functionality at
one point. I think the minimum requirement is a
parallel set of getoptXXX_r with a state variable that
can be initialized by the user.
I also noticed that stdlib/getopt.c has multiple
public API functions in it. Should these be broken
out? I know they are individually small but....
Any thoughts?
--
Joel Sherrill, Ph.D. Director of Research & Development
joel.sherrill@OARcorp.com On-Line Applications Research
Ask me about RTEMS: a free RTOS Huntsville AL 35805
Support Available (256) 722-9985
/*
* Tester for getopt_r
*/
#include <stdio.h>
#include <string.h>
#include "getopt.h"
static void netstats_usage()
{
printf(
"netstats [-vAimfpcut] where:\n"
" -A print All statistics\n"
" -i print Inet Routes\n"
" -m print MBUF Statistics\n"
" -f print IF Statistics\n"
" -p print IP Statistics\n"
" -c print ICMP Statistics\n"
" -u print UDP Statistics\n"
" -t print TCP Statistics\n"
);
}
int rtems_shell_main_netstats(
int argc,
char *argv[]
)
{
int option;
int doAll = 0;
int doInetRoutes = 0;
int doMBUFStats = 0;
int doIFStats = 0;
int doIPStats = 0;
int doICMPStats = 0;
int doUDPStats = 0;
int doTCPStats = 0;
int verbose = 0;
struct getopt_data getopt_reent = GETOPT_DATA_INITIALIZER;
while ( (option = getopt_r( argc, argv, "Aimfpcutv", &getopt_reent)) != -1 ) {
fprintf( stderr, "getopt returned %c\n", option );
switch ((char)option) {
case 'A': doAll = 1; break;
case 'i': doInetRoutes = 1; break;
case 'm': doMBUFStats = 1; break;
case 'f': doIFStats = 1; break;
case 'p': doIPStats = 1; break;
case 'c': doICMPStats = 1; break;
case 'u': doUDPStats = 1; break;
case 't': doTCPStats = 1; break;
case 'v': verbose = 1; break;
case '?':
default:
netstats_usage();
return -1;
}
}
if ( verbose ) {
printf(
"doAll=%d\n"
"doInetRoutes=%d\n"
"doMBUFStats=%d\n"
"doIFStats=%d\n"
"doIPStats=%d\n"
"doICMPStats=%d\n"
"doUDPStats=%d\n"
"doTCPStats=%d\n",
doAll,
doInetRoutes,
doMBUFStats,
doIFStats,
doIPStats,
doICMPStats,
doUDPStats,
doTCPStats
);
}
return 0;
}
void testit(const char *command)
{
char *c;
int argc;
char *argv[32];
extern int rtems_shell_make_args(
char *commandLine,
int *argc_p,
char **argv_p,
int max_args
);
c = strdup(command);
printf( "===================\n" );
printf( "COMMAND: %s\n", c );
rtems_shell_make_args( c, &argc, argv, 32 );
rtems_shell_main_netstats( argc, argv );
printf( "===================\n" );
free(c);
}
int main(
int argc,
char **argv
)
{
testit( "cmd -?" );
testit( "cmd -t -u -v" );
testit( "cmd -t -i -c extra1" );
}