This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


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

The different behavior of getopt and optind


Hi, Ulrich,

I got this bug report. I saw

revision 1.26
date: 1997/04/07 00:45:52;  author: drepper;  state: Exp;  lines: +4 -3
(_getopt_internal): Preserve optind.
(_getopt_internal): Set optind to 1 if optind == 0 before
calling _getopt_initialize ().

in CVS log. Will this change break anything?

Thanks.


H.J.
---
Index: posix/getopt.c
===================================================================
RCS file: /work/cvs/gnu/glibc/posix/getopt.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 getopt.c
--- posix/getopt.c	2000/05/21 21:11:20	1.1.1.1
+++ posix/getopt.c	2000/07/19 21:50:06
@@ -526,10 +526,9 @@ _getopt_internal (argc, argv, optstring,
 
   optarg = NULL;
 
-  if (optind == 0 || !__getopt_initialized)
+  if (!__getopt_initialized)
     {
-      if (optind == 0)
-	optind = 1;	/* Don't scan ARGV[0], the program name.  */
+      optind = 1;
       optstring = _getopt_initialize (argc, argv, optstring);
       __getopt_initialized = 1;
     }


-----
Anyway, here's a reasonable example of the problem:

  #include <stdio.h>
  #include <unistd.h>
  
  int main (int argc, char **argv)
  {
      int c;
      
      while ((c = getopt (argc, argv, "abc")) != -1) {
          fprintf (stderr, "first pass: %c\n", c);
      }
  
      argc  -= optind;
      argv  += optind;
      optind = 0;
      
      while ((c = getopt (argc, argv, "def")) != -1) {
          fprintf (stderr, "second pass: %c\n", c);
      }
      
      return 0;
  }
/*
The real problem is just that Linux and other OSes (we've tried, HPUX,
OSF1, and whatever SGI is discontinuing) behave differently:

  linux$ gcc -Wall getopt.example.c && ./a.out -a -b -- -e
  first pass: a
  first pass: b

  solaris2.7$ gcc -Wall getopt.example.c && ./a.out -a -b -- -e
  first pass: a
  first pass: c
  second pass: e

The obvious solution albeit unplesant solution is to insert:

  #ifdef linux
  argc++;
  argv--;
  optind = 1; /* this line is unecessary, but instructive */
  #endif

but I'm not convinced this is worthy of such a code branch (IMHO
special-casing hardware is asking for trouble).  My suggestion is to
modify getopt_internal to remove "optind == 0 || " from the outter
if's condition clause to read:

  if (!__getopt_initialized)
    {
      if (optind == 0)
        optind = 1;     /* Don't scan ARGV[0], the program name.  */
      optstring = _getopt_initialize (argc, argv, optstring);
      __getopt_initialized = 1;
    }

So, while I totally understand anyone's hesitation to change glibc's
behavior given it's pervasive distribution within the Linux community,
I wonder if it would ready affect many people given:

  A.  their application would have to call getopt more than once AND
  B.  set optind to zero after the first call

The risk seems to be that applications might call getopt or it's
variants on different strings in addition to argv (eg. config file
contents).  I would think new programmers would want the behavior I'm
suggesting, but that's not an option if it breaks existing code.


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