#include "lldb/Host/common/GetOptInc.h"
#if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || \
defined(REPLACE_GETOPT_LONG_ONLY)
#include <cerrno>
#include <cstdlib>
#include <cstring>
#if defined(REPLACE_GETOPT)
int opterr = 1;
int optind = 1;
int optopt = '?';
int optreset;
char *optarg;
#endif
#define PRINT_ERROR …
#define FLAG_PERMUTE …
#define FLAG_ALLARGS …
#define FLAG_LONGONLY …
#define BADCH …
#define BADARG …
#define INORDER …
#define EMSG …
static int getopt_internal(int, char *const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char *const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char *const *);
static const char *place = EMSG;
static int nonopt_start = -1;
static int nonopt_end = -1;
static int gcd(int a, int b) {
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
static void pass() {}
#define warnx …
static void permute_args(int panonopt_start, int panonopt_end, int opt_end,
char *const *nargv) {
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end + i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
const_cast<char **>(nargv)[pos] = nargv[cstart];
const_cast<char **>(nargv)[cstart] = swap;
}
}
}
static int parse_long_options(char *const *nargv, const char *options,
const struct option *long_options, int *idx,
int short_too) {
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = const_cast<char *>(place);
match = -1;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
if (strncmp(current_argv, long_options[i].name, current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
match = i;
break;
}
if (short_too && current_argv_len == 1)
continue;
if (match == -1)
match = i;
else {
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len, current_argv);
optopt = 0;
return (BADCH);
}
}
if (match != -1) {
if (long_options[match].has_arg == no_argument && has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len, current_argv);
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg == required_argument) {
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument) &&
(optarg == NULL)) {
if (PRINT_ERROR)
warnx(recargstring, current_argv);
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else {
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
static int getopt_internal(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx,
int flags) {
const char *oli;
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
if (optind == 0)
optind = optreset = 1;
if (posixly_correct == -1 || optreset)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) {
optreset = 0;
if (optind >= nargc) {
place = EMSG;
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind, nargv);
optind -= nonopt_end - nonopt_start;
} else if (nonopt_start != -1) {
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG;
if (flags & FLAG_ALLARGS) {
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
return (-1);
}
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind, nargv);
nonopt_start = optind - (nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++;
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1;
optchar = parse_long_options(nargv, options, long_options, idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
if (*place)
;
else if (++optind >= nargc) {
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options, idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') {
if (!*place)
++optind;
} else {
optarg = NULL;
if (*place)
optarg = const_cast<char *>(place);
else if (oli[1] != ':') {
if (++optind >= nargc) {
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
return (optchar);
}
#if defined(REPLACE_GETOPT)
int getopt(int nargc, char *const *nargv, const char *options) {
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif
#if defined(REPLACE_GETOPT_LONG)
int getopt_long(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx) {
return (
getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE));
}
#endif
#if defined(REPLACE_GETOPT_LONG_ONLY)
int getopt_long_only(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx) {
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE | FLAG_LONGONLY));
}
#endif
#endif