fix getopt handling of ':' modifier for multibyte option characters
[musl] / src / misc / getopt.c
1 #include <unistd.h>
2 #include <wchar.h>
3 #include <string.h>
4 #include <limits.h>
5 #include <stdlib.h>
6 #include "libc.h"
7
8 char *optarg;
9 int optind=1, opterr=1, optopt, __optpos, __optreset=0;
10
11 #define optpos __optpos
12 weak_alias(__optreset, optreset);
13
14 int getopt(int argc, char * const argv[], const char *optstring)
15 {
16         int i;
17         wchar_t c, d;
18         int k, l;
19         char *optchar;
20
21         if (!optind || __optreset) {
22                 __optreset = 0;
23                 __optpos = 0;
24                 optind = 1;
25         }
26
27         if (optind >= argc || !argv[optind])
28                 return -1;
29
30         if (argv[optind][0] != '-') {
31                 if (optstring[0] == '-') {
32                         optarg = argv[optind++];
33                         return 1;
34                 }
35                 return -1;
36         }
37
38         if (!argv[optind][1])
39                 return -1;
40
41         if (argv[optind][1] == '-' && !argv[optind][2])
42                 return optind++, -1;
43
44         if (!optpos) optpos++;
45         if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
46                 k = 1;
47                 c = 0xfffd; /* replacement char */
48         }
49         optchar = argv[optind]+optpos;
50         optopt = c;
51         optpos += k;
52
53         if (!argv[optind][optpos]) {
54                 optind++;
55                 optpos = 0;
56         }
57
58         if (optstring[0] == '-')
59                 optstring++;
60
61         i = 0;
62         d = 0;
63         do {
64                 l = mbtowc(&d, optstring+i, MB_LEN_MAX);
65                 if (l>0) i+=l; else i++;
66         } while (l && d != c);
67
68         if (d != c) {
69                 if (optstring[0] != ':' && opterr) {
70                         write(2, argv[0], strlen(argv[0]));
71                         write(2, ": illegal option: ", 18);
72                         write(2, optchar, k);
73                         write(2, "\n", 1);
74                 }
75                 return '?';
76         }
77         if (optstring[i] == ':') {
78                 if (optstring[i+1] == ':') optarg = 0;
79                 else if (optind >= argc) {
80                         if (optstring[0] == ':') return ':';
81                         if (opterr) {
82                                 write(2, argv[0], strlen(argv[0]));
83                                 write(2, ": option requires an argument: ", 31);
84                                 write(2, optchar, k);
85                                 write(2, "\n", 1);
86                         }
87                         return '?';
88                 }
89                 if (optstring[i+1] != ':' || optpos) {
90                         optarg = argv[optind++] + optpos;
91                         optpos = 0;
92                 }
93         }
94         return c;
95 }
96
97 weak_alias(getopt, __posix_getopt);