This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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" );
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]