fix popen not to leak pipes from one child to another
[musl] / src / misc / getopt.c
index f1a1639..c3f6699 100644 (file)
@@ -1,9 +1,11 @@
+#define _BSD_SOURCE
 #include <unistd.h>
 #include <wchar.h>
 #include <string.h>
 #include <limits.h>
 #include <stdlib.h>
-#include "libc.h"
+#include "locale_impl.h"
+#include "stdio_impl.h"
 
 char *optarg;
 int optind=1, opterr=1, optopt, __optpos, __optreset=0;
@@ -11,6 +13,18 @@ int optind=1, opterr=1, optopt, __optpos, __optreset=0;
 #define optpos __optpos
 weak_alias(__optreset, optreset);
 
+void __getopt_msg(const char *a, const char *b, const char *c, size_t l)
+{
+       FILE *f = stderr;
+       b = __lctrans_cur(b);
+       FLOCK(f);
+       fputs(a, f)>=0
+       && fwrite(b, strlen(b), 1, f)
+       && fwrite(c, 1, l, f)==l
+       && putc('\n', f);
+       FUNLOCK(f);
+}
+
 int getopt(int argc, char * const argv[], const char *optstring)
 {
        int i;
@@ -24,8 +38,20 @@ int getopt(int argc, char * const argv[], const char *optstring)
                optind = 1;
        }
 
-       if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1])
+       if (optind >= argc || !argv[optind])
+               return -1;
+
+       if (argv[optind][0] != '-') {
+               if (optstring[0] == '-') {
+                       optarg = argv[optind++];
+                       return 1;
+               }
+               return -1;
+       }
+
+       if (!argv[optind][1])
                return -1;
+
        if (argv[optind][1] == '-' && !argv[optind][2])
                return optind++, -1;
 
@@ -35,7 +61,6 @@ int getopt(int argc, char * const argv[], const char *optstring)
                c = 0xfffd; /* replacement char */
        }
        optchar = argv[optind]+optpos;
-       optopt = c;
        optpos += k;
 
        if (!argv[optind][optpos]) {
@@ -43,30 +68,36 @@ int getopt(int argc, char * const argv[], const char *optstring)
                optpos = 0;
        }
 
-       for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1);
+       if (optstring[0] == '-' || optstring[0] == '+')
+               optstring++;
 
-       if (d != c) {
-               if (optstring[0] != ':' && opterr) {
-                       write(2, argv[0], strlen(argv[0]));
-                       write(2, ": illegal option: ", 18);
-                       write(2, optchar, k);
-                       write(2, "\n", 1);
-               }
+       i = 0;
+       d = 0;
+       do {
+               l = mbtowc(&d, optstring+i, MB_LEN_MAX);
+               if (l>0) i+=l; else i++;
+       } while (l && d != c);
+
+       if (d != c || c == ':') {
+               optopt = c;
+               if (optstring[0] != ':' && opterr)
+                       __getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
                return '?';
        }
-       if (optstring[i+1] == ':') {
-               if (optind >= argc) {
+       if (optstring[i] == ':') {
+               optarg = 0;
+               if (optstring[i+1] != ':' || optpos) {
+                       optarg = argv[optind++] + optpos;
+                       optpos = 0;
+               }
+               if (optind > argc) {
+                       optopt = c;
                        if (optstring[0] == ':') return ':';
-                       if (opterr) {
-                               write(2, argv[0], strlen(argv[0]));
-                               write(2, ": option requires an argument: ", 31);
-                               write(2, optchar, k);
-                               write(2, "\n", 1);
-                       }
+                       if (opterr) __getopt_msg(argv[0],
+                               ": option requires an argument: ",
+                               optchar, k);
                        return '?';
                }
-               optarg = argv[optind++] + optpos;
-               optpos = 0;
        }
        return c;
 }