1dda28197Spatrick //===-- GetOptInc.cpp -----------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Host/common/GetOptInc.h"
10061da546Spatrick
11061da546Spatrick #if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || \
12061da546Spatrick defined(REPLACE_GETOPT_LONG_ONLY)
13061da546Spatrick
14061da546Spatrick // getopt.cpp
15*be691f3bSpatrick #include <cerrno>
16*be691f3bSpatrick #include <cstdlib>
17*be691f3bSpatrick #include <cstring>
18061da546Spatrick
19061da546Spatrick #if defined(REPLACE_GETOPT)
20061da546Spatrick int opterr = 1; /* if error message should be printed */
21061da546Spatrick int optind = 1; /* index into parent argv vector */
22061da546Spatrick int optopt = '?'; /* character checked for validity */
23061da546Spatrick int optreset; /* reset getopt */
24061da546Spatrick char *optarg; /* argument associated with option */
25061da546Spatrick #endif
26061da546Spatrick
27061da546Spatrick #define PRINT_ERROR ((opterr) && (*options != ':'))
28061da546Spatrick
29061da546Spatrick #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
30061da546Spatrick #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
31061da546Spatrick #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
32061da546Spatrick
33061da546Spatrick /* return values */
34061da546Spatrick #define BADCH (int)'?'
35061da546Spatrick #define BADARG ((*options == ':') ? (int)':' : (int)'?')
36061da546Spatrick #define INORDER (int)1
37061da546Spatrick
38061da546Spatrick #define EMSG ""
39061da546Spatrick
40061da546Spatrick static int getopt_internal(int, char *const *, const char *,
41061da546Spatrick const struct option *, int *, int);
42061da546Spatrick static int parse_long_options(char *const *, const char *,
43061da546Spatrick const struct option *, int *, int);
44061da546Spatrick static int gcd(int, int);
45061da546Spatrick static void permute_args(int, int, int, char *const *);
46061da546Spatrick
47061da546Spatrick static const char *place = EMSG; /* option letter processing */
48061da546Spatrick
49061da546Spatrick /* XXX: set optreset to 1 rather than these two */
50061da546Spatrick static int nonopt_start = -1; /* first non option argument (for permute) */
51061da546Spatrick static int nonopt_end = -1; /* first option after non options (for permute) */
52061da546Spatrick
53061da546Spatrick /*
54061da546Spatrick * Compute the greatest common divisor of a and b.
55061da546Spatrick */
gcd(int a,int b)56061da546Spatrick static int gcd(int a, int b) {
57061da546Spatrick int c;
58061da546Spatrick
59061da546Spatrick c = a % b;
60061da546Spatrick while (c != 0) {
61061da546Spatrick a = b;
62061da546Spatrick b = c;
63061da546Spatrick c = a % b;
64061da546Spatrick }
65061da546Spatrick
66061da546Spatrick return (b);
67061da546Spatrick }
68061da546Spatrick
pass()69061da546Spatrick static void pass() {}
70061da546Spatrick #define warnx(a, ...) pass();
71061da546Spatrick
72061da546Spatrick /*
73061da546Spatrick * Exchange the block from nonopt_start to nonopt_end with the block
74061da546Spatrick * from nonopt_end to opt_end (keeping the same order of arguments
75061da546Spatrick * in each block).
76061da546Spatrick */
permute_args(int panonopt_start,int panonopt_end,int opt_end,char * const * nargv)77061da546Spatrick static void permute_args(int panonopt_start, int panonopt_end, int opt_end,
78061da546Spatrick char *const *nargv) {
79061da546Spatrick int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
80061da546Spatrick char *swap;
81061da546Spatrick
82061da546Spatrick /*
83061da546Spatrick * compute lengths of blocks and number and size of cycles
84061da546Spatrick */
85061da546Spatrick nnonopts = panonopt_end - panonopt_start;
86061da546Spatrick nopts = opt_end - panonopt_end;
87061da546Spatrick ncycle = gcd(nnonopts, nopts);
88061da546Spatrick cyclelen = (opt_end - panonopt_start) / ncycle;
89061da546Spatrick
90061da546Spatrick for (i = 0; i < ncycle; i++) {
91061da546Spatrick cstart = panonopt_end + i;
92061da546Spatrick pos = cstart;
93061da546Spatrick for (j = 0; j < cyclelen; j++) {
94061da546Spatrick if (pos >= panonopt_end)
95061da546Spatrick pos -= nnonopts;
96061da546Spatrick else
97061da546Spatrick pos += nopts;
98061da546Spatrick swap = nargv[pos];
99061da546Spatrick /* LINTED const cast */
100061da546Spatrick const_cast<char **>(nargv)[pos] = nargv[cstart];
101061da546Spatrick /* LINTED const cast */
102061da546Spatrick const_cast<char **>(nargv)[cstart] = swap;
103061da546Spatrick }
104061da546Spatrick }
105061da546Spatrick }
106061da546Spatrick
107061da546Spatrick /*
108061da546Spatrick * parse_long_options --
109061da546Spatrick * Parse long options in argc/argv argument vector.
110061da546Spatrick * Returns -1 if short_too is set and the option does not match long_options.
111061da546Spatrick */
parse_long_options(char * const * nargv,const char * options,const struct option * long_options,int * idx,int short_too)112061da546Spatrick static int parse_long_options(char *const *nargv, const char *options,
113061da546Spatrick const struct option *long_options, int *idx,
114061da546Spatrick int short_too) {
115061da546Spatrick char *current_argv, *has_equal;
116061da546Spatrick size_t current_argv_len;
117061da546Spatrick int i, match;
118061da546Spatrick
119061da546Spatrick current_argv = const_cast<char *>(place);
120061da546Spatrick match = -1;
121061da546Spatrick
122061da546Spatrick optind++;
123061da546Spatrick
124061da546Spatrick if ((has_equal = strchr(current_argv, '=')) != NULL) {
125061da546Spatrick /* argument found (--option=arg) */
126061da546Spatrick current_argv_len = has_equal - current_argv;
127061da546Spatrick has_equal++;
128061da546Spatrick } else
129061da546Spatrick current_argv_len = strlen(current_argv);
130061da546Spatrick
131061da546Spatrick for (i = 0; long_options[i].name; i++) {
132061da546Spatrick /* find matching long option */
133061da546Spatrick if (strncmp(current_argv, long_options[i].name, current_argv_len))
134061da546Spatrick continue;
135061da546Spatrick
136061da546Spatrick if (strlen(long_options[i].name) == current_argv_len) {
137061da546Spatrick /* exact match */
138061da546Spatrick match = i;
139061da546Spatrick break;
140061da546Spatrick }
141061da546Spatrick /*
142061da546Spatrick * If this is a known short option, don't allow
143061da546Spatrick * a partial match of a single character.
144061da546Spatrick */
145061da546Spatrick if (short_too && current_argv_len == 1)
146061da546Spatrick continue;
147061da546Spatrick
148061da546Spatrick if (match == -1) /* partial match */
149061da546Spatrick match = i;
150061da546Spatrick else {
151061da546Spatrick /* ambiguous abbreviation */
152061da546Spatrick if (PRINT_ERROR)
153061da546Spatrick warnx(ambig, (int)current_argv_len, current_argv);
154061da546Spatrick optopt = 0;
155061da546Spatrick return (BADCH);
156061da546Spatrick }
157061da546Spatrick }
158061da546Spatrick if (match != -1) { /* option found */
159061da546Spatrick if (long_options[match].has_arg == no_argument && has_equal) {
160061da546Spatrick if (PRINT_ERROR)
161061da546Spatrick warnx(noarg, (int)current_argv_len, current_argv);
162061da546Spatrick /*
163061da546Spatrick * XXX: GNU sets optopt to val regardless of flag
164061da546Spatrick */
165061da546Spatrick if (long_options[match].flag == NULL)
166061da546Spatrick optopt = long_options[match].val;
167061da546Spatrick else
168061da546Spatrick optopt = 0;
169061da546Spatrick return (BADARG);
170061da546Spatrick }
171061da546Spatrick if (long_options[match].has_arg == required_argument ||
172061da546Spatrick long_options[match].has_arg == optional_argument) {
173061da546Spatrick if (has_equal)
174061da546Spatrick optarg = has_equal;
175061da546Spatrick else if (long_options[match].has_arg == required_argument) {
176061da546Spatrick /*
177061da546Spatrick * optional argument doesn't use next nargv
178061da546Spatrick */
179061da546Spatrick optarg = nargv[optind++];
180061da546Spatrick }
181061da546Spatrick }
182061da546Spatrick if ((long_options[match].has_arg == required_argument) &&
183061da546Spatrick (optarg == NULL)) {
184061da546Spatrick /*
185061da546Spatrick * Missing argument; leading ':' indicates no error
186061da546Spatrick * should be generated.
187061da546Spatrick */
188061da546Spatrick if (PRINT_ERROR)
189061da546Spatrick warnx(recargstring, current_argv);
190061da546Spatrick /*
191061da546Spatrick * XXX: GNU sets optopt to val regardless of flag
192061da546Spatrick */
193061da546Spatrick if (long_options[match].flag == NULL)
194061da546Spatrick optopt = long_options[match].val;
195061da546Spatrick else
196061da546Spatrick optopt = 0;
197061da546Spatrick --optind;
198061da546Spatrick return (BADARG);
199061da546Spatrick }
200061da546Spatrick } else { /* unknown option */
201061da546Spatrick if (short_too) {
202061da546Spatrick --optind;
203061da546Spatrick return (-1);
204061da546Spatrick }
205061da546Spatrick if (PRINT_ERROR)
206061da546Spatrick warnx(illoptstring, current_argv);
207061da546Spatrick optopt = 0;
208061da546Spatrick return (BADCH);
209061da546Spatrick }
210061da546Spatrick if (idx)
211061da546Spatrick *idx = match;
212061da546Spatrick if (long_options[match].flag) {
213061da546Spatrick *long_options[match].flag = long_options[match].val;
214061da546Spatrick return (0);
215061da546Spatrick } else
216061da546Spatrick return (long_options[match].val);
217061da546Spatrick }
218061da546Spatrick
219061da546Spatrick /*
220061da546Spatrick * getopt_internal --
221061da546Spatrick * Parse argc/argv argument vector. Called by user level routines.
222061da546Spatrick */
getopt_internal(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx,int flags)223061da546Spatrick static int getopt_internal(int nargc, char *const *nargv, const char *options,
224061da546Spatrick const struct option *long_options, int *idx,
225061da546Spatrick int flags) {
226061da546Spatrick const char *oli; /* option letter list index */
227061da546Spatrick int optchar, short_too;
228061da546Spatrick static int posixly_correct = -1;
229061da546Spatrick
230061da546Spatrick if (options == NULL)
231061da546Spatrick return (-1);
232061da546Spatrick
233061da546Spatrick /*
234061da546Spatrick * XXX Some GNU programs (like cvs) set optind to 0 instead of
235061da546Spatrick * XXX using optreset. Work around this braindamage.
236061da546Spatrick */
237061da546Spatrick if (optind == 0)
238061da546Spatrick optind = optreset = 1;
239061da546Spatrick
240061da546Spatrick /*
241061da546Spatrick * Disable GNU extensions if POSIXLY_CORRECT is set or options
242061da546Spatrick * string begins with a '+'.
243061da546Spatrick */
244061da546Spatrick if (posixly_correct == -1 || optreset)
245061da546Spatrick posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
246061da546Spatrick if (*options == '-')
247061da546Spatrick flags |= FLAG_ALLARGS;
248061da546Spatrick else if (posixly_correct || *options == '+')
249061da546Spatrick flags &= ~FLAG_PERMUTE;
250061da546Spatrick if (*options == '+' || *options == '-')
251061da546Spatrick options++;
252061da546Spatrick
253061da546Spatrick optarg = NULL;
254061da546Spatrick if (optreset)
255061da546Spatrick nonopt_start = nonopt_end = -1;
256061da546Spatrick start:
257061da546Spatrick if (optreset || !*place) { /* update scanning pointer */
258061da546Spatrick optreset = 0;
259061da546Spatrick if (optind >= nargc) { /* end of argument vector */
260061da546Spatrick place = EMSG;
261061da546Spatrick if (nonopt_end != -1) {
262061da546Spatrick /* do permutation, if we have to */
263061da546Spatrick permute_args(nonopt_start, nonopt_end, optind, nargv);
264061da546Spatrick optind -= nonopt_end - nonopt_start;
265061da546Spatrick } else if (nonopt_start != -1) {
266061da546Spatrick /*
267061da546Spatrick * If we skipped non-options, set optind
268061da546Spatrick * to the first of them.
269061da546Spatrick */
270061da546Spatrick optind = nonopt_start;
271061da546Spatrick }
272061da546Spatrick nonopt_start = nonopt_end = -1;
273061da546Spatrick return (-1);
274061da546Spatrick }
275061da546Spatrick if (*(place = nargv[optind]) != '-' ||
276061da546Spatrick (place[1] == '\0' && strchr(options, '-') == NULL)) {
277061da546Spatrick place = EMSG; /* found non-option */
278061da546Spatrick if (flags & FLAG_ALLARGS) {
279061da546Spatrick /*
280061da546Spatrick * GNU extension:
281061da546Spatrick * return non-option as argument to option 1
282061da546Spatrick */
283061da546Spatrick optarg = nargv[optind++];
284061da546Spatrick return (INORDER);
285061da546Spatrick }
286061da546Spatrick if (!(flags & FLAG_PERMUTE)) {
287061da546Spatrick /*
288061da546Spatrick * If no permutation wanted, stop parsing
289061da546Spatrick * at first non-option.
290061da546Spatrick */
291061da546Spatrick return (-1);
292061da546Spatrick }
293061da546Spatrick /* do permutation */
294061da546Spatrick if (nonopt_start == -1)
295061da546Spatrick nonopt_start = optind;
296061da546Spatrick else if (nonopt_end != -1) {
297061da546Spatrick permute_args(nonopt_start, nonopt_end, optind, nargv);
298061da546Spatrick nonopt_start = optind - (nonopt_end - nonopt_start);
299061da546Spatrick nonopt_end = -1;
300061da546Spatrick }
301061da546Spatrick optind++;
302061da546Spatrick /* process next argument */
303061da546Spatrick goto start;
304061da546Spatrick }
305061da546Spatrick if (nonopt_start != -1 && nonopt_end == -1)
306061da546Spatrick nonopt_end = optind;
307061da546Spatrick
308061da546Spatrick /*
309061da546Spatrick * If we have "-" do nothing, if "--" we are done.
310061da546Spatrick */
311061da546Spatrick if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
312061da546Spatrick optind++;
313061da546Spatrick place = EMSG;
314061da546Spatrick /*
315061da546Spatrick * We found an option (--), so if we skipped
316061da546Spatrick * non-options, we have to permute.
317061da546Spatrick */
318061da546Spatrick if (nonopt_end != -1) {
319061da546Spatrick permute_args(nonopt_start, nonopt_end, optind, nargv);
320061da546Spatrick optind -= nonopt_end - nonopt_start;
321061da546Spatrick }
322061da546Spatrick nonopt_start = nonopt_end = -1;
323061da546Spatrick return (-1);
324061da546Spatrick }
325061da546Spatrick }
326061da546Spatrick
327061da546Spatrick /*
328061da546Spatrick * Check long options if:
329061da546Spatrick * 1) we were passed some
330061da546Spatrick * 2) the arg is not just "-"
331061da546Spatrick * 3) either the arg starts with -- we are getopt_long_only()
332061da546Spatrick */
333061da546Spatrick if (long_options != NULL && place != nargv[optind] &&
334061da546Spatrick (*place == '-' || (flags & FLAG_LONGONLY))) {
335061da546Spatrick short_too = 0;
336061da546Spatrick if (*place == '-')
337061da546Spatrick place++; /* --foo long option */
338061da546Spatrick else if (*place != ':' && strchr(options, *place) != NULL)
339061da546Spatrick short_too = 1; /* could be short option too */
340061da546Spatrick
341061da546Spatrick optchar = parse_long_options(nargv, options, long_options, idx, short_too);
342061da546Spatrick if (optchar != -1) {
343061da546Spatrick place = EMSG;
344061da546Spatrick return (optchar);
345061da546Spatrick }
346061da546Spatrick }
347061da546Spatrick
348061da546Spatrick if ((optchar = (int)*place++) == (int)':' ||
349061da546Spatrick (optchar == (int)'-' && *place != '\0') ||
350061da546Spatrick (oli = strchr(options, optchar)) == NULL) {
351061da546Spatrick /*
352061da546Spatrick * If the user specified "-" and '-' isn't listed in
353061da546Spatrick * options, return -1 (non-option) as per POSIX.
354061da546Spatrick * Otherwise, it is an unknown option character (or ':').
355061da546Spatrick */
356061da546Spatrick if (optchar == (int)'-' && *place == '\0')
357061da546Spatrick return (-1);
358061da546Spatrick if (!*place)
359061da546Spatrick ++optind;
360061da546Spatrick if (PRINT_ERROR)
361061da546Spatrick warnx(illoptchar, optchar);
362061da546Spatrick optopt = optchar;
363061da546Spatrick return (BADCH);
364061da546Spatrick }
365061da546Spatrick if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
366061da546Spatrick /* -W long-option */
367061da546Spatrick if (*place) /* no space */
368061da546Spatrick /* NOTHING */;
369061da546Spatrick else if (++optind >= nargc) { /* no arg */
370061da546Spatrick place = EMSG;
371061da546Spatrick if (PRINT_ERROR)
372061da546Spatrick warnx(recargchar, optchar);
373061da546Spatrick optopt = optchar;
374061da546Spatrick return (BADARG);
375061da546Spatrick } else /* white space */
376061da546Spatrick place = nargv[optind];
377061da546Spatrick optchar = parse_long_options(nargv, options, long_options, idx, 0);
378061da546Spatrick place = EMSG;
379061da546Spatrick return (optchar);
380061da546Spatrick }
381061da546Spatrick if (*++oli != ':') { /* doesn't take argument */
382061da546Spatrick if (!*place)
383061da546Spatrick ++optind;
384061da546Spatrick } else { /* takes (optional) argument */
385061da546Spatrick optarg = NULL;
386061da546Spatrick if (*place) /* no white space */
387061da546Spatrick optarg = const_cast<char *>(place);
388061da546Spatrick else if (oli[1] != ':') { /* arg not optional */
389061da546Spatrick if (++optind >= nargc) { /* no arg */
390061da546Spatrick place = EMSG;
391061da546Spatrick if (PRINT_ERROR)
392061da546Spatrick warnx(recargchar, optchar);
393061da546Spatrick optopt = optchar;
394061da546Spatrick return (BADARG);
395061da546Spatrick } else
396061da546Spatrick optarg = nargv[optind];
397061da546Spatrick }
398061da546Spatrick place = EMSG;
399061da546Spatrick ++optind;
400061da546Spatrick }
401061da546Spatrick /* dump back option letter */
402061da546Spatrick return (optchar);
403061da546Spatrick }
404061da546Spatrick
405061da546Spatrick /*
406061da546Spatrick * getopt --
407061da546Spatrick * Parse argc/argv argument vector.
408061da546Spatrick *
409061da546Spatrick * [eventually this will replace the BSD getopt]
410061da546Spatrick */
411061da546Spatrick #if defined(REPLACE_GETOPT)
getopt(int nargc,char * const * nargv,const char * options)412061da546Spatrick int getopt(int nargc, char *const *nargv, const char *options) {
413061da546Spatrick
414061da546Spatrick /*
415061da546Spatrick * We don't pass FLAG_PERMUTE to getopt_internal() since
416061da546Spatrick * the BSD getopt(3) (unlike GNU) has never done this.
417061da546Spatrick *
418061da546Spatrick * Furthermore, since many privileged programs call getopt()
419061da546Spatrick * before dropping privileges it makes sense to keep things
420061da546Spatrick * as simple (and bug-free) as possible.
421061da546Spatrick */
422061da546Spatrick return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
423061da546Spatrick }
424061da546Spatrick #endif
425061da546Spatrick
426061da546Spatrick /*
427061da546Spatrick * getopt_long --
428061da546Spatrick * Parse argc/argv argument vector.
429061da546Spatrick */
430061da546Spatrick #if defined(REPLACE_GETOPT_LONG)
getopt_long(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)431061da546Spatrick int getopt_long(int nargc, char *const *nargv, const char *options,
432061da546Spatrick const struct option *long_options, int *idx) {
433061da546Spatrick return (
434061da546Spatrick getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE));
435061da546Spatrick }
436061da546Spatrick #endif
437061da546Spatrick
438061da546Spatrick /*
439061da546Spatrick * getopt_long_only --
440061da546Spatrick * Parse argc/argv argument vector.
441061da546Spatrick */
442061da546Spatrick #if defined(REPLACE_GETOPT_LONG_ONLY)
getopt_long_only(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)443061da546Spatrick int getopt_long_only(int nargc, char *const *nargv, const char *options,
444061da546Spatrick const struct option *long_options, int *idx) {
445061da546Spatrick
446061da546Spatrick return (getopt_internal(nargc, nargv, options, long_options, idx,
447061da546Spatrick FLAG_PERMUTE | FLAG_LONGONLY));
448061da546Spatrick }
449061da546Spatrick #endif
450061da546Spatrick
451061da546Spatrick #endif
452