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