fix getopt[_long] clobbering of optopt on success
authorRich Felker <dalias@aerifal.cx>
Thu, 5 Jan 2017 00:02:02 +0000 (19:02 -0500)
committerRich Felker <dalias@aerifal.cx>
Thu, 5 Jan 2017 00:43:59 +0000 (19:43 -0500)
getopt is only specified to modify optopt on error, and some software
apparently infers an error from optopt!=0.

getopt_long is changed analogously. the resulting behavior differs
slightly from the behavior of the GNU implementation of getopt_long,
which keeps an internal shadow copy of optopt and copies it to the
public one on return, but since the GNU implementation also exhibits
this shadow-copy behavior for plain getopt where is is non-conforming,
I think this can reasonably be considered a bug rather than an
intentional behavior that merits mimicing.

src/misc/getopt.c
src/misc/getopt_long.c

index 8290aef..e9bab41 100644 (file)
@@ -60,7 +60,6 @@ int getopt(int argc, char * const argv[], const char *optstring)
                c = 0xfffd; /* replacement char */
        }
        optchar = argv[optind]+optpos;
                c = 0xfffd; /* replacement char */
        }
        optchar = argv[optind]+optpos;
-       optopt = c;
        optpos += k;
 
        if (!argv[optind][optpos]) {
        optpos += k;
 
        if (!argv[optind][optpos]) {
@@ -79,6 +78,7 @@ int getopt(int argc, char * const argv[], const char *optstring)
        } while (l && d != c);
 
        if (d != c) {
        } while (l && d != c);
 
        if (d != c) {
+               optopt = c;
                if (optstring[0] != ':' && opterr)
                        __getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
                return '?';
                if (optstring[0] != ':' && opterr)
                        __getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
                return '?';
@@ -86,6 +86,7 @@ int getopt(int argc, char * const argv[], const char *optstring)
        if (optstring[i] == ':') {
                if (optstring[i+1] == ':') optarg = 0;
                else if (optind >= argc) {
        if (optstring[i] == ':') {
                if (optstring[i+1] == ':') optarg = 0;
                else if (optind >= argc) {
+                       optopt = c;
                        if (optstring[0] == ':') return ':';
                        if (opterr) __getopt_msg(argv[0],
                                ": option requires an argument: ",
                        if (optstring[0] == ':') return ':';
                        if (opterr) __getopt_msg(argv[0],
                                ": option requires an argument: ",
index c6e1462..568ae7b 100644 (file)
@@ -75,9 +75,9 @@ static int __getopt_long_core(int argc, char *const *argv, const char *optstring
                if (cnt==1) {
                        i = match;
                        optind++;
                if (cnt==1) {
                        i = match;
                        optind++;
-                       optopt = longopts[i].val;
                        if (*opt == '=') {
                                if (!longopts[i].has_arg) {
                        if (*opt == '=') {
                                if (!longopts[i].has_arg) {
+                                       optopt = longopts[i].val;
                                        if (colon || !opterr)
                                                return '?';
                                        __getopt_msg(argv[0],
                                        if (colon || !opterr)
                                                return '?';
                                        __getopt_msg(argv[0],
@@ -89,6 +89,7 @@ static int __getopt_long_core(int argc, char *const *argv, const char *optstring
                                optarg = opt+1;
                        } else if (longopts[i].has_arg == required_argument) {
                                if (!(optarg = argv[optind])) {
                                optarg = opt+1;
                        } else if (longopts[i].has_arg == required_argument) {
                                if (!(optarg = argv[optind])) {
+                                       optopt = longopts[i].val;
                                        if (colon) return ':';
                                        if (!opterr) return '?';
                                        __getopt_msg(argv[0],
                                        if (colon) return ':';
                                        if (!opterr) return '?';
                                        __getopt_msg(argv[0],
@@ -107,6 +108,7 @@ static int __getopt_long_core(int argc, char *const *argv, const char *optstring
                        return longopts[i].val;
                }
                if (argv[optind][1] == '-') {
                        return longopts[i].val;
                }
                if (argv[optind][1] == '-') {
+                       optopt = 0;
                        if (!colon && opterr)
                                __getopt_msg(argv[0], cnt ?
                                        ": option is ambiguous: " :
                        if (!colon && opterr)
                                __getopt_msg(argv[0], cnt ?
                                        ": option is ambiguous: " :