1*ab8db090SAndroid Build Coastguard Worker #include <stdio.h>
2*ab8db090SAndroid Build Coastguard Worker
3*ab8db090SAndroid Build Coastguard Worker #include "cmdopt.h"
4*ab8db090SAndroid Build Coastguard Worker
5*ab8db090SAndroid Build Coastguard Worker #ifdef __cplusplus
6*ab8db090SAndroid Build Coastguard Worker extern "C" {
7*ab8db090SAndroid Build Coastguard Worker #endif // __cplusplus
8*ab8db090SAndroid Build Coastguard Worker
9*ab8db090SAndroid Build Coastguard Worker // Moves `optind' to the end and shifts other arguments.
cmdopt_shift(cmdopt_t * h)10*ab8db090SAndroid Build Coastguard Worker static void cmdopt_shift(cmdopt_t *h) {
11*ab8db090SAndroid Build Coastguard Worker int i;
12*ab8db090SAndroid Build Coastguard Worker char *tmp;
13*ab8db090SAndroid Build Coastguard Worker
14*ab8db090SAndroid Build Coastguard Worker tmp = h->argv[h->optind];
15*ab8db090SAndroid Build Coastguard Worker for (i = h->optind; i < h->argc - 1; i++) {
16*ab8db090SAndroid Build Coastguard Worker h->argv[i] = h->argv[i + 1];
17*ab8db090SAndroid Build Coastguard Worker }
18*ab8db090SAndroid Build Coastguard Worker h->argv[i] = tmp;
19*ab8db090SAndroid Build Coastguard Worker
20*ab8db090SAndroid Build Coastguard Worker h->nextchar = NULL;
21*ab8db090SAndroid Build Coastguard Worker h->optnum--;
22*ab8db090SAndroid Build Coastguard Worker }
23*ab8db090SAndroid Build Coastguard Worker
24*ab8db090SAndroid Build Coastguard Worker // Moves to the next argument.
cmdopt_next(cmdopt_t * h)25*ab8db090SAndroid Build Coastguard Worker static void cmdopt_next(cmdopt_t *h) {
26*ab8db090SAndroid Build Coastguard Worker h->optind++;
27*ab8db090SAndroid Build Coastguard Worker h->nextchar = NULL;
28*ab8db090SAndroid Build Coastguard Worker }
29*ab8db090SAndroid Build Coastguard Worker
30*ab8db090SAndroid Build Coastguard Worker // Checks if the current argument is an option or not.
cmdopt_check(cmdopt_t * h)31*ab8db090SAndroid Build Coastguard Worker static int cmdopt_check(cmdopt_t *h) {
32*ab8db090SAndroid Build Coastguard Worker int ret = 1;
33*ab8db090SAndroid Build Coastguard Worker const char *arg = h->argv[h->optind];
34*ab8db090SAndroid Build Coastguard Worker
35*ab8db090SAndroid Build Coastguard Worker if (*arg++ != '-') {
36*ab8db090SAndroid Build Coastguard Worker return 0;
37*ab8db090SAndroid Build Coastguard Worker }
38*ab8db090SAndroid Build Coastguard Worker
39*ab8db090SAndroid Build Coastguard Worker if (*arg == '-') {
40*ab8db090SAndroid Build Coastguard Worker arg++;
41*ab8db090SAndroid Build Coastguard Worker ret++;
42*ab8db090SAndroid Build Coastguard Worker }
43*ab8db090SAndroid Build Coastguard Worker
44*ab8db090SAndroid Build Coastguard Worker return ret - (*arg == '\0');
45*ab8db090SAndroid Build Coastguard Worker }
46*ab8db090SAndroid Build Coastguard Worker
47*ab8db090SAndroid Build Coastguard Worker // Gets an argument of the current option.
cmdopt_getopt(cmdopt_t * h)48*ab8db090SAndroid Build Coastguard Worker static void cmdopt_getopt(cmdopt_t *h) {
49*ab8db090SAndroid Build Coastguard Worker // Moves to the next argument if the current argument has no more characters.
50*ab8db090SAndroid Build Coastguard Worker if (*h->nextchar == '\0') {
51*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
52*ab8db090SAndroid Build Coastguard Worker h->nextchar = h->argv[h->optind];
53*ab8db090SAndroid Build Coastguard Worker }
54*ab8db090SAndroid Build Coastguard Worker
55*ab8db090SAndroid Build Coastguard Worker // Checks whether the current option has an argument or not.
56*ab8db090SAndroid Build Coastguard Worker if (h->optind < h->optnum) {
57*ab8db090SAndroid Build Coastguard Worker h->optarg = h->nextchar;
58*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
59*ab8db090SAndroid Build Coastguard Worker } else {
60*ab8db090SAndroid Build Coastguard Worker h->optarg = NULL;
61*ab8db090SAndroid Build Coastguard Worker }
62*ab8db090SAndroid Build Coastguard Worker }
63*ab8db090SAndroid Build Coastguard Worker
64*ab8db090SAndroid Build Coastguard Worker // Searches an option.
cmdopt_search(cmdopt_t * h)65*ab8db090SAndroid Build Coastguard Worker static int cmdopt_search(cmdopt_t *h) {
66*ab8db090SAndroid Build Coastguard Worker const char *ptr;
67*ab8db090SAndroid Build Coastguard Worker
68*ab8db090SAndroid Build Coastguard Worker // Updates an option character.
69*ab8db090SAndroid Build Coastguard Worker h->optopt = *h->nextchar++;
70*ab8db090SAndroid Build Coastguard Worker
71*ab8db090SAndroid Build Coastguard Worker for (ptr = h->optstring; *ptr != '\0'; ptr++) {
72*ab8db090SAndroid Build Coastguard Worker if (*ptr == h->optopt) {
73*ab8db090SAndroid Build Coastguard Worker // Gets an option argument if required.
74*ab8db090SAndroid Build Coastguard Worker if (ptr[1] == ':') {
75*ab8db090SAndroid Build Coastguard Worker cmdopt_getopt(h);
76*ab8db090SAndroid Build Coastguard Worker
77*ab8db090SAndroid Build Coastguard Worker // Returns ':' if there is no argument.
78*ab8db090SAndroid Build Coastguard Worker if (h->optarg == NULL && ptr[2] != ':') {
79*ab8db090SAndroid Build Coastguard Worker return ':';
80*ab8db090SAndroid Build Coastguard Worker }
81*ab8db090SAndroid Build Coastguard Worker }
82*ab8db090SAndroid Build Coastguard Worker return h->optopt;
83*ab8db090SAndroid Build Coastguard Worker }
84*ab8db090SAndroid Build Coastguard Worker }
85*ab8db090SAndroid Build Coastguard Worker
86*ab8db090SAndroid Build Coastguard Worker if (h->optopt == '-') {
87*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
88*ab8db090SAndroid Build Coastguard Worker while (h->optind < h->optnum) {
89*ab8db090SAndroid Build Coastguard Worker cmdopt_shift(h);
90*ab8db090SAndroid Build Coastguard Worker }
91*ab8db090SAndroid Build Coastguard Worker return -1;
92*ab8db090SAndroid Build Coastguard Worker }
93*ab8db090SAndroid Build Coastguard Worker
94*ab8db090SAndroid Build Coastguard Worker // Returns '?' if the option character is undefined.
95*ab8db090SAndroid Build Coastguard Worker return '?';
96*ab8db090SAndroid Build Coastguard Worker }
97*ab8db090SAndroid Build Coastguard Worker
98*ab8db090SAndroid Build Coastguard Worker // Compares a long option with an argument and returns the length of the
99*ab8db090SAndroid Build Coastguard Worker // matched prefix.
cmdopt_match_len(const char * opt,const char * arg)100*ab8db090SAndroid Build Coastguard Worker static int cmdopt_match_len(const char *opt, const char *arg) {
101*ab8db090SAndroid Build Coastguard Worker int len = 0;
102*ab8db090SAndroid Build Coastguard Worker
103*ab8db090SAndroid Build Coastguard Worker // Returns 0 if there is a mismatch.
104*ab8db090SAndroid Build Coastguard Worker while ((*arg != '\0') && (*arg != '=')) {
105*ab8db090SAndroid Build Coastguard Worker if (*arg++ != *opt++) {
106*ab8db090SAndroid Build Coastguard Worker return 0;
107*ab8db090SAndroid Build Coastguard Worker }
108*ab8db090SAndroid Build Coastguard Worker len++;
109*ab8db090SAndroid Build Coastguard Worker }
110*ab8db090SAndroid Build Coastguard Worker
111*ab8db090SAndroid Build Coastguard Worker // Returns a negative value in case of a perfect match.
112*ab8db090SAndroid Build Coastguard Worker if ((*arg == '\0') || (*arg == '=')) {
113*ab8db090SAndroid Build Coastguard Worker return -len;
114*ab8db090SAndroid Build Coastguard Worker }
115*ab8db090SAndroid Build Coastguard Worker
116*ab8db090SAndroid Build Coastguard Worker return len;
117*ab8db090SAndroid Build Coastguard Worker }
118*ab8db090SAndroid Build Coastguard Worker
119*ab8db090SAndroid Build Coastguard Worker // Checks long options.
cmdopt_match(cmdopt_t * h)120*ab8db090SAndroid Build Coastguard Worker static int cmdopt_match(cmdopt_t *h) {
121*ab8db090SAndroid Build Coastguard Worker int i, len;
122*ab8db090SAndroid Build Coastguard Worker int max = 0, max_optind = -1;
123*ab8db090SAndroid Build Coastguard Worker
124*ab8db090SAndroid Build Coastguard Worker // Returns -1 if there are no long options.
125*ab8db090SAndroid Build Coastguard Worker if (h->longopts == NULL) {
126*ab8db090SAndroid Build Coastguard Worker return max_optind;
127*ab8db090SAndroid Build Coastguard Worker }
128*ab8db090SAndroid Build Coastguard Worker
129*ab8db090SAndroid Build Coastguard Worker for (i = 0; h->longopts[i].name != NULL; i++) {
130*ab8db090SAndroid Build Coastguard Worker len = cmdopt_match_len(h->longopts[i].name, h->nextchar);
131*ab8db090SAndroid Build Coastguard Worker if (len < 0) {
132*ab8db090SAndroid Build Coastguard Worker // In case of a perfect match.
133*ab8db090SAndroid Build Coastguard Worker h->nextchar -= len;
134*ab8db090SAndroid Build Coastguard Worker return i;
135*ab8db090SAndroid Build Coastguard Worker } else if (len > max) {
136*ab8db090SAndroid Build Coastguard Worker // In case of a prefix match.
137*ab8db090SAndroid Build Coastguard Worker max = len;
138*ab8db090SAndroid Build Coastguard Worker max_optind = i;
139*ab8db090SAndroid Build Coastguard Worker } else if (len == max) {
140*ab8db090SAndroid Build Coastguard Worker // There are other candidates.
141*ab8db090SAndroid Build Coastguard Worker max_optind = -1;
142*ab8db090SAndroid Build Coastguard Worker }
143*ab8db090SAndroid Build Coastguard Worker }
144*ab8db090SAndroid Build Coastguard Worker
145*ab8db090SAndroid Build Coastguard Worker // If there is no perfect match, adopts the longest one.
146*ab8db090SAndroid Build Coastguard Worker h->nextchar += max;
147*ab8db090SAndroid Build Coastguard Worker return max_optind;
148*ab8db090SAndroid Build Coastguard Worker }
149*ab8db090SAndroid Build Coastguard Worker
150*ab8db090SAndroid Build Coastguard Worker // Gets an argument of a long option.
cmdopt_getopt_long(cmdopt_t * h)151*ab8db090SAndroid Build Coastguard Worker static void cmdopt_getopt_long(cmdopt_t *h) {
152*ab8db090SAndroid Build Coastguard Worker if (*h->nextchar == '=') {
153*ab8db090SAndroid Build Coastguard Worker h->optarg = h->nextchar + 1;
154*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
155*ab8db090SAndroid Build Coastguard Worker } else {
156*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
157*ab8db090SAndroid Build Coastguard Worker
158*ab8db090SAndroid Build Coastguard Worker // Checks whether there are more options or not.
159*ab8db090SAndroid Build Coastguard Worker if (h->optind < h->optnum) {
160*ab8db090SAndroid Build Coastguard Worker h->optarg = h->argv[h->optind];
161*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
162*ab8db090SAndroid Build Coastguard Worker } else {
163*ab8db090SAndroid Build Coastguard Worker h->optarg = NULL;
164*ab8db090SAndroid Build Coastguard Worker }
165*ab8db090SAndroid Build Coastguard Worker }
166*ab8db090SAndroid Build Coastguard Worker }
167*ab8db090SAndroid Build Coastguard Worker
168*ab8db090SAndroid Build Coastguard Worker // Searches long options.
cmdopt_search_long(cmdopt_t * h)169*ab8db090SAndroid Build Coastguard Worker static int cmdopt_search_long(cmdopt_t *h) {
170*ab8db090SAndroid Build Coastguard Worker const cmdopt_option *option;
171*ab8db090SAndroid Build Coastguard Worker
172*ab8db090SAndroid Build Coastguard Worker // Keeps the long option.
173*ab8db090SAndroid Build Coastguard Worker h->optlong = h->argv[h->optind];
174*ab8db090SAndroid Build Coastguard Worker
175*ab8db090SAndroid Build Coastguard Worker // Gets the next option.
176*ab8db090SAndroid Build Coastguard Worker h->longindex = cmdopt_match(h);
177*ab8db090SAndroid Build Coastguard Worker if (h->longindex < 0) {
178*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
179*ab8db090SAndroid Build Coastguard Worker return '?';
180*ab8db090SAndroid Build Coastguard Worker }
181*ab8db090SAndroid Build Coastguard Worker
182*ab8db090SAndroid Build Coastguard Worker // Gets an argument if required.
183*ab8db090SAndroid Build Coastguard Worker option = h->longopts + h->longindex;
184*ab8db090SAndroid Build Coastguard Worker if (option->has_arg) {
185*ab8db090SAndroid Build Coastguard Worker cmdopt_getopt_long(h);
186*ab8db090SAndroid Build Coastguard Worker
187*ab8db090SAndroid Build Coastguard Worker // Return ':' if there are no more arguments.
188*ab8db090SAndroid Build Coastguard Worker if (h->optarg == NULL) {
189*ab8db090SAndroid Build Coastguard Worker return ':';
190*ab8db090SAndroid Build Coastguard Worker }
191*ab8db090SAndroid Build Coastguard Worker } else if (*h->nextchar == '=') {
192*ab8db090SAndroid Build Coastguard Worker // Returns '?' for an extra option argument.
193*ab8db090SAndroid Build Coastguard Worker cmdopt_getopt_long(h);
194*ab8db090SAndroid Build Coastguard Worker return '?';
195*ab8db090SAndroid Build Coastguard Worker }
196*ab8db090SAndroid Build Coastguard Worker
197*ab8db090SAndroid Build Coastguard Worker // Overwrites a variable if specified in settings.
198*ab8db090SAndroid Build Coastguard Worker if (option->flag != NULL) {
199*ab8db090SAndroid Build Coastguard Worker *option->flag = option->val;
200*ab8db090SAndroid Build Coastguard Worker return 0;
201*ab8db090SAndroid Build Coastguard Worker }
202*ab8db090SAndroid Build Coastguard Worker
203*ab8db090SAndroid Build Coastguard Worker return option->val;
204*ab8db090SAndroid Build Coastguard Worker }
205*ab8db090SAndroid Build Coastguard Worker
206*ab8db090SAndroid Build Coastguard Worker // Analyze command line option.
cmdopt_main(cmdopt_t * h)207*ab8db090SAndroid Build Coastguard Worker static int cmdopt_main(cmdopt_t *h) {
208*ab8db090SAndroid Build Coastguard Worker int type;
209*ab8db090SAndroid Build Coastguard Worker
210*ab8db090SAndroid Build Coastguard Worker // Initializes the internal state.
211*ab8db090SAndroid Build Coastguard Worker h->optopt = 0;
212*ab8db090SAndroid Build Coastguard Worker h->optlong = NULL;
213*ab8db090SAndroid Build Coastguard Worker h->optarg = NULL;
214*ab8db090SAndroid Build Coastguard Worker h->longindex = 0;
215*ab8db090SAndroid Build Coastguard Worker
216*ab8db090SAndroid Build Coastguard Worker while (h->optind < h->optnum) {
217*ab8db090SAndroid Build Coastguard Worker if (h->nextchar == NULL) {
218*ab8db090SAndroid Build Coastguard Worker // Checks whether the next argument is an option or not.
219*ab8db090SAndroid Build Coastguard Worker type = cmdopt_check(h);
220*ab8db090SAndroid Build Coastguard Worker if (type == 0) {
221*ab8db090SAndroid Build Coastguard Worker cmdopt_shift(h);
222*ab8db090SAndroid Build Coastguard Worker } else {
223*ab8db090SAndroid Build Coastguard Worker h->nextchar = h->argv[h->optind] + type;
224*ab8db090SAndroid Build Coastguard Worker if (type == 2) {
225*ab8db090SAndroid Build Coastguard Worker return cmdopt_search_long(h);
226*ab8db090SAndroid Build Coastguard Worker }
227*ab8db090SAndroid Build Coastguard Worker }
228*ab8db090SAndroid Build Coastguard Worker } else {
229*ab8db090SAndroid Build Coastguard Worker if (*h->nextchar == '\0') {
230*ab8db090SAndroid Build Coastguard Worker cmdopt_next(h);
231*ab8db090SAndroid Build Coastguard Worker continue;
232*ab8db090SAndroid Build Coastguard Worker }
233*ab8db090SAndroid Build Coastguard Worker // Searches an option string.
234*ab8db090SAndroid Build Coastguard Worker return cmdopt_search(h);
235*ab8db090SAndroid Build Coastguard Worker }
236*ab8db090SAndroid Build Coastguard Worker }
237*ab8db090SAndroid Build Coastguard Worker
238*ab8db090SAndroid Build Coastguard Worker return -1;
239*ab8db090SAndroid Build Coastguard Worker }
240*ab8db090SAndroid Build Coastguard Worker
241*ab8db090SAndroid Build Coastguard Worker // cmdopt_init() initializes a cmdopt_t for successive cmdopt_get()s.
cmdopt_init(cmdopt_t * h,int argc,char ** argv,const char * optstring,const cmdopt_option * longopts)242*ab8db090SAndroid Build Coastguard Worker void cmdopt_init(cmdopt_t *h, int argc, char **argv,
243*ab8db090SAndroid Build Coastguard Worker const char *optstring, const cmdopt_option *longopts) {
244*ab8db090SAndroid Build Coastguard Worker static const char empty_optstring[] = "";
245*ab8db090SAndroid Build Coastguard Worker
246*ab8db090SAndroid Build Coastguard Worker h->argc = argc;
247*ab8db090SAndroid Build Coastguard Worker h->argv = argv;
248*ab8db090SAndroid Build Coastguard Worker h->optnum = h->argc;
249*ab8db090SAndroid Build Coastguard Worker
250*ab8db090SAndroid Build Coastguard Worker h->longopts = longopts;
251*ab8db090SAndroid Build Coastguard Worker h->optstring = (optstring != NULL) ? optstring : empty_optstring;
252*ab8db090SAndroid Build Coastguard Worker
253*ab8db090SAndroid Build Coastguard Worker h->optind = 1;
254*ab8db090SAndroid Build Coastguard Worker h->nextchar = NULL;
255*ab8db090SAndroid Build Coastguard Worker h->optarg = NULL;
256*ab8db090SAndroid Build Coastguard Worker h->optopt = 0;
257*ab8db090SAndroid Build Coastguard Worker h->optlong = NULL;
258*ab8db090SAndroid Build Coastguard Worker h->opterr = 1;
259*ab8db090SAndroid Build Coastguard Worker h->longindex = 0;
260*ab8db090SAndroid Build Coastguard Worker }
261*ab8db090SAndroid Build Coastguard Worker
262*ab8db090SAndroid Build Coastguard Worker // cmdopt_get() analyzes command line arguments and gets the next option.
cmdopt_get(cmdopt_t * h)263*ab8db090SAndroid Build Coastguard Worker int cmdopt_get(cmdopt_t *h) {
264*ab8db090SAndroid Build Coastguard Worker int value = cmdopt_main(h);
265*ab8db090SAndroid Build Coastguard Worker
266*ab8db090SAndroid Build Coastguard Worker // Prints a warning to the standard error stream if enabled.
267*ab8db090SAndroid Build Coastguard Worker if (h->opterr) {
268*ab8db090SAndroid Build Coastguard Worker if (value == ':') {
269*ab8db090SAndroid Build Coastguard Worker // Warning for a lack of an option argument.
270*ab8db090SAndroid Build Coastguard Worker if (h->optlong == NULL) {
271*ab8db090SAndroid Build Coastguard Worker fprintf(stderr, "option requires an argument -- %c\n", h->optopt);
272*ab8db090SAndroid Build Coastguard Worker } else {
273*ab8db090SAndroid Build Coastguard Worker fprintf(stderr, "option `--%s' requires an argument\n",
274*ab8db090SAndroid Build Coastguard Worker h->longopts[h->longindex].name);
275*ab8db090SAndroid Build Coastguard Worker }
276*ab8db090SAndroid Build Coastguard Worker } else if (value == '?') {
277*ab8db090SAndroid Build Coastguard Worker // Warning for an invalid option.
278*ab8db090SAndroid Build Coastguard Worker if (h->optlong == NULL) {
279*ab8db090SAndroid Build Coastguard Worker fprintf(stderr, "invalid option -- %c\n", h->optopt);
280*ab8db090SAndroid Build Coastguard Worker } else {
281*ab8db090SAndroid Build Coastguard Worker fprintf(stderr, "unrecognized option `%s'\n", h->optlong);
282*ab8db090SAndroid Build Coastguard Worker }
283*ab8db090SAndroid Build Coastguard Worker } else if ((value != -1) && (h->opterr == 2)) {
284*ab8db090SAndroid Build Coastguard Worker // Actually this is not for warning, but for debugging.
285*ab8db090SAndroid Build Coastguard Worker if (h->optlong == NULL) {
286*ab8db090SAndroid Build Coastguard Worker fprintf(stderr, "option with `%s' -- %c\n", h->optarg, h->optopt);
287*ab8db090SAndroid Build Coastguard Worker } else {
288*ab8db090SAndroid Build Coastguard Worker fprintf(stderr, "option `--%s' with `%s'\n",
289*ab8db090SAndroid Build Coastguard Worker h->longopts[h->longindex].name, h->optarg);
290*ab8db090SAndroid Build Coastguard Worker }
291*ab8db090SAndroid Build Coastguard Worker }
292*ab8db090SAndroid Build Coastguard Worker }
293*ab8db090SAndroid Build Coastguard Worker return value;
294*ab8db090SAndroid Build Coastguard Worker }
295*ab8db090SAndroid Build Coastguard Worker
296*ab8db090SAndroid Build Coastguard Worker #ifdef __cplusplus
297*ab8db090SAndroid Build Coastguard Worker } // extern "C"
298*ab8db090SAndroid Build Coastguard Worker #endif // __cplusplus
299