Subject: pkg/30319: incorrect getopt reset in bmake
To: None <pkg-manager@netbsd.org, gnats-admin@netbsd.org,>
From: None <joerg@leaf.dragonflybsd.org>
List: pkgsrc-bugs
Date: 05/24/2005 10:27:00
>Number:         30319
>Category:       pkg
>Synopsis:       incorrect getopt reset in bmake
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue May 24 10:27:00 +0000 2005
>Originator:     Jörg Sonnenberger
>Release:        pkgsrc-HEAD
>Organization:
>Environment:
DragonFly britannica.bec.de 1.3.1-DEVELOPMENT DragonFly 1.3.1-DEVELOPMENT #15: Tue May 17 13:31:47 2005     joerg@britannica.bec.de:/home/joerg/wd/DragonFly/world/src/sys/compile/TURTLE  i386 1.1.1.1.0.2

>Description:
bmake resets getopt by reinitialising optind. It should use optreset for that. It also triggers the GNU getopt compatibility code on DragonFly, since optind = 0 is interpreted as reset by GNU getopt.
This results in skipping of the first option block after the each non-option.
>How-To-Repeat:
bmake clean -f Makefile
>Fix:
Index: main.c
===================================================================
RCS file: /home/joerg/wd/repository/netbsd/pkgsrc/bootstrap/bmake/main.c,v
retrieving revision 1.2
diff -u -r1.2 main.c
--- main.c      5 Jan 2005 21:54:40 -0000       1.2
+++ main.c      23 May 2005 15:24:12 -0000
@@ -199,13 +199,16 @@
        if (argv[0] == 0)
                argv[0] = progname;     /* avoid problems in getopt */
 
-       optind = 1;     /* since we're called more than once */
 #ifdef REMOTE
 # define OPTFLAGS "BD:I:J:L:NPST:V:Wd:ef:ij:km:nqrst"
 #else
 # define OPTFLAGS "BD:I:J:NPST:V:Wd:ef:ij:km:nqrst"
 #endif
-rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) {
+rearg:
+       optind = 1;     /* since we're called more than once */
+       optreset = 1;
+
+       while((c = getopt(argc, argv, OPTFLAGS)) != -1) {
                switch(c) {
                case 'D':
                        Var_Set(optarg, "1", VAR_GLOBAL, 0);
@@ -405,6 +408,8 @@
                        usage();
                }
        }
+       argv += optind;
+       argc -= optind;
 
        oldVars = TRUE;
 
@@ -413,21 +418,29 @@
         * perform them if so. Else take them to be targets and stuff them
         * on the end of the "create" list.
         */
-       for (argv += optind, argc -= optind; *argv; ++argv, --argc)
+       for (; *argv != NULL; ++argv, --argc) {
                if (Parse_IsVar(*argv)) {
                        Parse_DoVar(*argv, VAR_CMD);
-               } else {
-                       if (!**argv)
-                               Punt("illegal (null) argument.");
-                       if (**argv == '-') {
-                               if ((*argv)[1])
-                                       optind = 0;     /* -flag... */
-                               else
-                                       optind = 1;     /* - */
+               } else if ((*argv)[0] == '-'){
+                       if ((*argv)[1] == '\0') {
+                               /*
+                                * (*argv) is a single dash, so we
+                                * just ignore it.
+                                */
+                       } else {
+                               argc++;
+                               argv--;
                                goto rearg;
                        }
+               } else if ((*argv)[0] == '\0') {
+                       /* 
+                        * Check against empty strings as argument.
+                        */
+                       Punt("illegal (null argument.");
+               } else {
                        (void)Lst_AtEnd(create, (ClientData)estrdup(*argv));
                }
+       }
 }
 
 /*-