fix issues from public functions defined without declaration visible
[musl] / src / misc / getopt_long.c
1 #define _GNU_SOURCE
2 #include <stddef.h>
3 #include <stdlib.h>
4 #include <limits.h>
5 #include <getopt.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 extern int __optpos, __optreset;
10
11 static void permute(char *const *argv, int dest, int src)
12 {
13         char **av = (char **)argv;
14         char *tmp = av[src];
15         int i;
16         for (i=src; i>dest; i--)
17                 av[i] = av[i-1];
18         av[dest] = tmp;
19 }
20
21 void __getopt_msg(const char *, const char *, const char *, size_t);
22
23 static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly);
24
25 static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
26 {
27         int ret, skipped, resumed;
28         if (!optind || __optreset) {
29                 __optreset = 0;
30                 __optpos = 0;
31                 optind = 1;
32         }
33         if (optind >= argc || !argv[optind]) return -1;
34         skipped = optind;
35         if (optstring[0] != '+' && optstring[0] != '-') {
36                 int i;
37                 for (i=optind; ; i++) {
38                         if (i >= argc || !argv[i]) return -1;
39                         if (argv[i][0] == '-' && argv[i][1]) break;
40                 }
41                 optind = i;
42         }
43         resumed = optind;
44         ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
45         if (resumed > skipped) {
46                 int i, cnt = optind-resumed;
47                 for (i=0; i<cnt; i++)
48                         permute(argv, skipped, optind-1);
49                 optind = skipped + cnt;
50         }
51         return ret;
52 }
53
54 static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
55 {
56         optarg = 0;
57         if (longopts && argv[optind][0] == '-' &&
58                 ((longonly && argv[optind][1] && argv[optind][1] != '-') ||
59                  (argv[optind][1] == '-' && argv[optind][2])))
60         {
61                 int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
62                 int i, cnt, match;
63                 char *arg, *opt, *start = argv[optind]+1;
64                 for (cnt=i=0; longopts[i].name; i++) {
65                         const char *name = longopts[i].name;
66                         opt = start;
67                         if (*opt == '-') opt++;
68                         while (*opt && *opt != '=' && *opt == *name)
69                                 name++, opt++;
70                         if (*opt && *opt != '=') continue;
71                         arg = opt;
72                         match = i;
73                         if (!*name) {
74                                 cnt = 1;
75                                 break;
76                         }
77                         cnt++;
78                 }
79                 if (cnt==1 && longonly && arg-start == mblen(start, MB_LEN_MAX)) {
80                         int l = arg-start;
81                         for (i=0; optstring[i]; i++) {
82                                 int j;
83                                 for (j=0; j<l && start[j]==optstring[i+j]; j++);
84                                 if (j==l) {
85                                         cnt++;
86                                         break;
87                                 }
88                         }
89                 }
90                 if (cnt==1) {
91                         i = match;
92                         opt = arg;
93                         optind++;
94                         if (*opt == '=') {
95                                 if (!longopts[i].has_arg) {
96                                         optopt = longopts[i].val;
97                                         if (colon || !opterr)
98                                                 return '?';
99                                         __getopt_msg(argv[0],
100                                                 ": option does not take an argument: ",
101                                                 longopts[i].name,
102                                                 strlen(longopts[i].name));
103                                         return '?';
104                                 }
105                                 optarg = opt+1;
106                         } else if (longopts[i].has_arg == required_argument) {
107                                 if (!(optarg = argv[optind])) {
108                                         optopt = longopts[i].val;
109                                         if (colon) return ':';
110                                         if (!opterr) return '?';
111                                         __getopt_msg(argv[0],
112                                                 ": option requires an argument: ",
113                                                 longopts[i].name,
114                                                 strlen(longopts[i].name));
115                                         return '?';
116                                 }
117                                 optind++;
118                         }
119                         if (idx) *idx = i;
120                         if (longopts[i].flag) {
121                                 *longopts[i].flag = longopts[i].val;
122                                 return 0;
123                         }
124                         return longopts[i].val;
125                 }
126                 if (argv[optind][1] == '-') {
127                         optopt = 0;
128                         if (!colon && opterr)
129                                 __getopt_msg(argv[0], cnt ?
130                                         ": option is ambiguous: " :
131                                         ": unrecognized option: ",
132                                         argv[optind]+2,
133                                         strlen(argv[optind]+2));
134                         optind++;
135                         return '?';
136                 }
137         }
138         return getopt(argc, argv, optstring);
139 }
140
141 int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
142 {
143         return __getopt_long(argc, argv, optstring, longopts, idx, 0);
144 }
145
146 int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
147 {
148         return __getopt_long(argc, argv, optstring, longopts, idx, 1);
149 }