170c9b5e0c00d7c04f45ee0e34d4dc0d6b2a2dfd
[dpdk.git] / lib / librte_eal / windows / eal / getopt.c
1 /* SPDX-License-Identifier: ISC AND BSD-2-Clause
2  * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Sponsored in part by the Defense Advanced Research Projects
5  * Agency (DARPA) and Air Force Research Laboratory, Air Force
6  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
7  */
8 /*
9  * Copyright (c) 2000 The NetBSD Foundation, Inc.
10  * All rights reserved.
11  *
12  * This code is derived from software contributed to The NetBSD Foundation
13  * by Dieter Baron and Thomas Klausner.
14  */
15
16 #include <getopt.h>
17
18 #ifdef NEED_USUAL_GETOPT
19
20 #include <string.h>
21 #include <stdlib.h>
22
23 const char    *optarg;          /* argument associated with option */
24 int     opterr = 1;             /* if error message should be printed */
25 int     optind = 1;             /* index into parent argv vector */
26 int     optopt = '?';           /* character checked for validity */
27
28 static void pass(void) {}
29 #define warnx(a, ...) pass()
30
31 #define PRINT_ERROR     ((opterr) && (*options != ':'))
32
33 #define FLAG_PERMUTE    0x01    /* permute non-options to the end of argv */
34 #define FLAG_ALLARGS    0x02    /* treat non-options as args to option "-1" */
35 #define FLAG_LONGONLY   0x04    /* operate as getopt_long_only */
36
37 /* return values */
38 #define BADCH           ((int)'?')
39 #define BADARG          ((*options == ':') ? (int)':' : (int)'?')
40 #define INORDER         1
41
42 #define EMSG            ""
43
44 static const char *place = EMSG; /* option letter processing */
45
46 /* XXX: set optreset to 1 rather than these two */
47 static int nonopt_start = -1; /* first non option argument (for permute) */
48 static int nonopt_end = -1;   /* first option after non options (for permute) */
49
50 /* Error messages */
51 static const char recargchar[] = "option requires an argument -- %c";
52 static const char recargstring[] = "option requires an argument -- %s";
53 static const char ambig[] = "ambiguous option -- %.*s";
54 static const char noarg[] = "option doesn't take an argument -- %.*s";
55 static const char illoptchar[] = "unknown option -- %c";
56 static const char illoptstring[] = "unknown option -- %s";
57
58 /*
59  * Compute the greatest common divisor of a and b.
60  */
61 static int
62 gcd(int a, int b)
63 {
64         int c;
65
66         c = a % b;
67         while (c != 0) {
68                 a = b;
69                 b = c;
70                 c = a % b;
71         }
72
73         return (b);
74 }
75
76 /*
77  * Exchange the block from nonopt_start to nonopt_end with the block
78  * from nonopt_end to opt_end (keeping the same order of arguments
79  * in each block).
80  */
81 static void
82 permute_args(int panonopt_start, int panonopt_end, int opt_end,
83         char **nargv)
84 {
85         int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
86         char *swap;
87
88         /*
89          * compute lengths of blocks and number and size of cycles
90          */
91         nnonopts = panonopt_end - panonopt_start;
92         nopts = opt_end - panonopt_end;
93         ncycle = gcd(nnonopts, nopts);
94         cyclelen = (opt_end - panonopt_start) / ncycle;
95
96         for (i = 0; i < ncycle; i++) {
97                 cstart = panonopt_end+i;
98                 pos = cstart;
99                 for (j = 0; j < cyclelen; j++) {
100                         if (pos >= panonopt_end)
101                                 pos -= nnonopts;
102                         else
103                                 pos += nopts;
104                         swap = nargv[pos];
105                         /* LINTED const cast */
106                         ((char **) nargv)[pos] = nargv[cstart];
107                         /* LINTED const cast */
108                         ((char **)nargv)[cstart] = swap;
109                 }
110         }
111 }
112
113 /*
114  * parse_long_options --
115  *      Parse long options in argc/argv argument vector.
116  * Returns -1 if short_too is set and the option does not match long_options.
117  */
118 static int
119 parse_long_options(char **nargv, const char *options,
120         const struct option *long_options, int *idx, int short_too)
121 {
122         const char *current_argv;
123         char *has_equal;
124         size_t current_argv_len;
125         int i, match;
126
127         current_argv = place;
128         match = -1;
129
130         optind++;
131
132         has_equal = strchr(current_argv, '=');
133         if (has_equal != NULL) {
134                 /* argument found (--option=arg) */
135                 current_argv_len = has_equal - current_argv;
136                 has_equal++;
137         } else
138                 current_argv_len = strlen(current_argv);
139
140         for (i = 0; long_options[i].name; i++) {
141                 /* find matching long option */
142                 if (strncmp(current_argv, long_options[i].name,
143                     current_argv_len))
144                         continue;
145
146                 if (strlen(long_options[i].name) == current_argv_len) {
147                         /* exact match */
148                         match = i;
149                         break;
150                 }
151                 /*
152                  * If this is a known short option, don't allow
153                  * a partial match of a single character.
154                  */
155                 if (short_too && current_argv_len == 1)
156                         continue;
157
158                 if (match == -1)        /* partial match */
159                         match = i;
160                 else {
161                         /* ambiguous abbreviation */
162                         if (PRINT_ERROR)
163                                 warnx(ambig, (int)current_argv_len,
164                                      current_argv);
165                         optopt = 0;
166                         return BADCH;
167                 }
168         }
169         if (match != -1) {              /* option found */
170                 if (long_options[match].has_arg == no_argument
171                     && has_equal) {
172                         if (PRINT_ERROR)
173                                 warnx(noarg, (int)current_argv_len,
174                                      current_argv);
175                         /*
176                          * XXX: GNU sets optopt to val regardless of flag
177                          */
178                         if (long_options[match].flag == NULL)
179                                 optopt = long_options[match].val;
180                         else
181                                 optopt = 0;
182                         return BADARG;
183                 }
184                 if (long_options[match].has_arg == required_argument ||
185                     long_options[match].has_arg == optional_argument) {
186                         if (has_equal)
187                                 optarg = has_equal;
188                         else if (long_options[match].has_arg ==
189                             required_argument) {
190                                 /*
191                                  * optional argument doesn't use next nargv
192                                  */
193                                 optarg = nargv[optind++];
194                         }
195                 }
196                 if ((long_options[match].has_arg == required_argument)
197                     && (optarg == NULL)) {
198                         /*
199                          * Missing argument; leading ':' indicates no error
200                          * should be generated.
201                          */
202                         if (PRINT_ERROR)
203                                 warnx(recargstring,
204                                     current_argv);
205                         /*
206                          * XXX: GNU sets optopt to val regardless of flag
207                          */
208                         if (long_options[match].flag == NULL)
209                                 optopt = long_options[match].val;
210                         else
211                                 optopt = 0;
212                         --optind;
213                         return BADARG;
214                 }
215         } else {                        /* unknown option */
216                 if (short_too) {
217                         --optind;
218                         return (-1);
219                 }
220                 if (PRINT_ERROR)
221                         warnx(illoptstring, current_argv);
222                 optopt = 0;
223                 return BADCH;
224         }
225         if (idx)
226                 *idx = match;
227         if (long_options[match].flag) {
228                 *long_options[match].flag = long_options[match].val;
229                 return 0;
230         } else
231                 return (long_options[match].val);
232 }
233
234 /*
235  * getopt_internal --
236  *      Parse argc/argv argument vector.  Called by user level routines.
237  */
238 static int
239 getopt_internal(int nargc, char **nargv, const char *options,
240         const struct option *long_options, int *idx, int flags)
241 {
242         char *oli;                              /* option letter list index */
243         int optchar, short_too;
244         static int posixly_correct = -1;
245         char *buf;
246         size_t len;
247         int optreset = 0;
248
249         if (options == NULL)
250                 return (-1);
251
252         /*
253          * Disable GNU extensions if POSIXLY_CORRECT is set or options
254          * string begins with a '+'.
255          */
256         if (posixly_correct == -1)
257                 posixly_correct = _dupenv_s(&buf, &len, "POSIXLY_CORRECT");
258         if (!posixly_correct || *options == '+')
259                 flags &= ~FLAG_PERMUTE;
260         else if (*options == '-')
261                 flags |= FLAG_ALLARGS;
262         if (*options == '+' || *options == '-')
263                 options++;
264         if (!posixly_correct)
265                 free(buf);
266         /*
267          * reset if requested
268          */
269         if (optind == 0)
270                 optind = optreset = 1;
271
272         optarg = NULL;
273         if (optreset)
274                 nonopt_start = nonopt_end = -1;
275 start:
276         if (optreset || !*place) {              /* update scanning pointer */
277                 optreset = 0;
278                 if (optind >= nargc) {          /* end of argument vector */
279                         place = EMSG;
280                         if (nonopt_end != -1) {
281                                 /* do permutation, if we have to */
282                                 permute_args(nonopt_start, nonopt_end,
283                                     optind, nargv);
284                                 optind -= nonopt_end - nonopt_start;
285                         } else if (nonopt_start != -1) {
286                                 /*
287                                  * If we skipped non-options, set optind
288                                  * to the first of them.
289                                  */
290                                 optind = nonopt_start;
291                         }
292                         nonopt_start = nonopt_end = -1;
293                         return (-1);
294                 }
295                 place = nargv[optind];
296                 if (*place != '-' ||
297                     (place[1] == '\0' && strchr(options, '-') == NULL)) {
298                         place = EMSG;           /* found non-option */
299                         if (flags & FLAG_ALLARGS) {
300                                 /*
301                                  * GNU extension:
302                                  * return non-option as argument to option 1
303                                  */
304                                 optarg = nargv[optind++];
305                                 return INORDER;
306                         }
307                         if (!(flags & FLAG_PERMUTE)) {
308                                 /*
309                                  * If no permutation wanted, stop parsing
310                                  * at first non-option.
311                                  */
312                                 return (-1);
313                         }
314                         /* do permutation */
315                         if (nonopt_start == -1)
316                                 nonopt_start = optind;
317                         else if (nonopt_end != -1) {
318                                 permute_args(nonopt_start, nonopt_end,
319                                     optind, nargv);
320                                 nonopt_start = optind -
321                                     (nonopt_end - nonopt_start);
322                                 nonopt_end = -1;
323                         }
324                         optind++;
325                         /* process next argument */
326                         goto start;
327                 }
328                 if (nonopt_start != -1 && nonopt_end == -1)
329                         nonopt_end = optind;
330
331                 /*
332                  * If we have "-" do nothing, if "--" we are done.
333                  */
334                 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
335                         optind++;
336                         place = EMSG;
337                         /*
338                          * We found an option (--), so if we skipped
339                          * non-options, we have to permute.
340                          */
341                         if (nonopt_end != -1) {
342                                 permute_args(nonopt_start, nonopt_end,
343                                     optind, nargv);
344                                 optind -= nonopt_end - nonopt_start;
345                         }
346                         nonopt_start = nonopt_end = -1;
347                         return (-1);
348                 }
349         }
350
351         /*
352          * Check long options if:
353          *  1) we were passed some
354          *  2) the arg is not just "-"
355          *  3) either the arg starts with -- we are getopt_long_only()
356          */
357         if (long_options != NULL && place != nargv[optind] &&
358             (*place == '-' || (flags & FLAG_LONGONLY))) {
359                 short_too = 0;
360                 if (*place == '-')
361                         place++;                /* --foo long option */
362                 else if (*place != ':' && strchr(options, *place) != NULL)
363                         short_too = 1;          /* could be short option too */
364
365                 optchar = parse_long_options(nargv, options, long_options,
366                     idx, short_too);
367                 if (optchar != -1) {
368                         place = EMSG;
369                         return optchar;
370                 }
371         }
372
373         optchar = (int)*place++;
374         oli = strchr(options, optchar);
375         if (optchar == (int)':' ||
376             (optchar == (int)'-' && *place != '\0') ||
377             oli == NULL) {
378                 /*
379                  * If the user specified "-" and  '-' isn't listed in
380                  * options, return -1 (non-option) as per POSIX.
381                  * Otherwise, it is an unknown option character (or ':').
382                  */
383                 if (optchar == (int)'-' && *place == '\0')
384                         return (-1);
385                 if (!*place)
386                         ++optind;
387                 if (PRINT_ERROR)
388                         warnx(illoptchar, optchar);
389                 optopt = optchar;
390                 return BADCH;
391         }
392         if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
393                 /* -W long-option */
394                 if (*place)
395                         ;
396                 else if (++optind >= nargc) {   /* no arg */
397                         place = EMSG;
398                         if (PRINT_ERROR)
399                                 warnx(recargchar, optchar);
400                         optopt = optchar;
401                         return BADARG;
402                 }                               /* white space */
403                 place = nargv[optind];
404                 optchar = parse_long_options(nargv, options, long_options,
405                     idx, 0);
406                 place = EMSG;
407                 return optchar;
408         }
409         if (*++oli != ':') {                    /* doesn't take argument */
410                 if (!*place)
411                         ++optind;
412         } else {                                /* takes (optional) argument */
413                 optarg = NULL;
414                 if (*place)                     /* no white space */
415                         optarg = place;
416                 else if (oli[1] != ':') {       /* arg not optional */
417                         if (++optind >= nargc) {        /* no arg */
418                                 place = EMSG;
419                                 if (PRINT_ERROR)
420                                         warnx(recargchar, optchar);
421                                 optopt = optchar;
422                                 return BADARG;
423                         }
424                         optarg = nargv[optind];
425                 }
426                 place = EMSG;
427                 ++optind;
428         }
429         /* dump back option letter */
430         return optchar;
431 }
432
433 /*
434  * getopt --
435  *      Parse argc/argv argument vector.
436  */
437 int
438 getopt(int nargc, char *nargv[], const char *options)
439 {
440         return getopt_internal(nargc, nargv, options, NULL, NULL,
441                                FLAG_PERMUTE);
442 }
443
444 /*
445  * getopt_long --
446  *      Parse argc/argv argument vector.
447  */
448 int
449 getopt_long(int nargc, char *nargv[], const char *options,
450         const struct option *long_options, int *idx)
451 {
452
453         return (getopt_internal(nargc, nargv, options, long_options, idx,
454             FLAG_PERMUTE));
455 }
456
457 /*
458  * getopt_long_only --
459  *      Parse argc/argv argument vector.
460  */
461 int
462 getopt_long_only(int nargc, char *nargv[], const char *options,
463         const struct option *long_options, int *idx)
464 {
465
466         return (getopt_internal(nargc, nargv, options, long_options, idx,
467             FLAG_PERMUTE|FLAG_LONGONLY));
468 }
469
470 #endif /* NEED_USUAL_GETOPT */