#1213 getopt() regression: optind not set to next option

closed-fixed
2008-10-04
2008-10-03
Christian Franke
No

The new getopt() from Cygwin package mingw-runtime-3.15 sets optind to the index of the current option instead of the next option. See attached testcase.

Output for "./getopt-test -a -b arg -c":

- mingw-runtime-3.14, Cygwin, GNU getopt:
opt=a, optind=2
opt=b, optind=4
opt=c, optind=5
end optind=5

- mingw-runtime-3.15:
opt=a, optind=1
opt=b, optind=2
opt=c, optind=4
end optind=5

The new behavior violates this POSIX requirement:
"The variable optind is the index of the next element of the argv[] vector to be processed."
http://www.opengroup.org/onlinepubs/009695399/functions/getopt.html

Discussion

  • Testcase

     
    Attachments
  • Keith Marshall
    Keith Marshall
    2008-10-03

    • priority: 5 --> 8
    • assigned_to: nobody --> keithmarshall
    • milestone: --> IINR_-_Include_In_Next_Release
     
  • Keith Marshall
    Keith Marshall
    2008-10-03

    Thanks Christian.

    > The new behavior violates this POSIX requirement:
    > "The variable optind is the index of the next element of
    > the argv[] vector to be processed."

    That's a rather bold assertion, based as it is, on only partial context from the POSIX standard.

    On the basis of the full context, as it appears here:
    http://www.opengroup.org/onlinepubs/009695399/functions/getopt.html
    | The variable optind is the index of the next element of the argv[]
    | vector to be processed. It shall be initialized to 1 by the system,
    | and getopt() shall update it when it finishes with each element of
    ^^^^^^^^^^^^^^^^^^^^^
    | argv[]. When an element of argv[] contains multiple option
    | characters, it is unspecified how getopt() determines which
    | options have already been processed.

    I could make a tentative case for acceptance of the current mingwrt getopt() implementation. This uses a lazy evaluation technique, which defers the decision regarding when it has finished with any particular element of argv[] until it fails to find any candidate option within it; thus when it returns optind = 1, it still has to examine argv[1] at least one more time, to determine that it can find no further options within it.

    However, the POSIX standard goes on to say:
    | If the option takes an argument, getopt() shall set the variable
    | optarg to point to the option-argument as follows:
    |
    | 1. If the option was the last character in the string
    | pointed to by an element of argv, then optarg shall
    | contain the next element of argv, and optind shall be
    | incremented by 2. If the resulting value of optind
    | is greater than argc, this indicates a missing
    | option-argument, and getopt() shall return an
    | error indication.
    |
    | 2. Otherwise, optarg shall point to the string following
    | the option character in that element of argv, and optind
    | shall be incremented by 1.

    Clearly, the mingwrt-3.15 implementation doesn't deliver this behaviour, so an appropriate change is necessary. I am testing a patch right now; it delivers the expected behaviour in your test case, but I need to confirm that I haven't broken it in some other respect.

     
  • Keith Marshall
    Keith Marshall
    2008-10-03

    • status: open --> pending-fixed
     
  • Keith Marshall
    Keith Marshall
    2008-10-03

    Patch applied, per ChangeLog entry:

    * mingwex/getopt.c (optind): Make global variable value conform to
    behaviour specified by POSIX; do not use it for internal state in...
    (getopt_parse): ...this static function; use...
    (optbase): ...this new static local variable instead.
    (getopt_resolved): Update `optind' as required.

    Please test.

     
    • status: pending-fixed --> open-fixed
     
  • Test of mingwex/getopt.c CVS rev 1.7:
    Both getopt() and getopt_long() set optind properly.

    Thanks!

     
  • Keith Marshall
    Keith Marshall
    2008-10-04

    Thanks for checking this, Christian.

    > Both getopt() and getopt_long() set optind properly.

    My own testing suggests that getopt_long_only() also behaves correctly. I think this may be closed. If you encounter any further problems, please open a new ticket.

     
  • Keith Marshall
    Keith Marshall
    2008-10-04

    • status: open-fixed --> closed-fixed