blob: 5703bc93994bae28a17d7c6d57eac7f693bb37fd [file] [log] [blame]
#define _GNU_SOURCE
#include <getopt.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
extern int __optpos, __optreset;
static void permute(char* const* argv, int dest, int src) {
char** av = (char**)argv;
char* tmp = av[src];
int i;
for (i = src; i > dest; i--)
av[i] = av[i - 1];
av[dest] = tmp;
}
void __getopt_msg(const char*, const char*, const char*, size_t);
static int __getopt_long_core(int argc, char* const* argv, const char* optstring,
const struct option* longopts, int* idx, int longonly);
static int __getopt_long(int argc, char* const* argv, const char* optstring,
const struct option* longopts, int* idx, int longonly) {
int ret, skipped, resumed;
if (!optind || __optreset) {
__optreset = 0;
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind])
return -1;
skipped = optind;
if (optstring[0] != '+' && optstring[0] != '-') {
int i;
for (i = optind;; i++) {
if (i >= argc || !argv[i])
return -1;
if (argv[i][0] == '-' && argv[i][1])
break;
}
optind = i;
}
resumed = optind;
ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
if (resumed > skipped) {
int i, cnt = optind - resumed;
for (i = 0; i < cnt; i++)
permute(argv, skipped, optind - 1);
optind = skipped + cnt;
}
return ret;
}
static int __getopt_long_core(int argc, char* const* argv, const char* optstring,
const struct option* longopts, int* idx, int longonly) {
optarg = 0;
if (longopts && argv[optind][0] == '-' &&
((longonly && argv[optind][1]) || (argv[optind][1] == '-' && argv[optind][2]))) {
int colon = optstring[optstring[0] == '+' || optstring[0] == '-'] == ':';
int i, cnt, match;
char* opt;
for (cnt = i = 0; longopts[i].name; i++) {
const char* name = longopts[i].name;
opt = argv[optind] + 1;
if (*opt == '-')
opt++;
for (; *name && *name == *opt; name++, opt++)
;
if (*opt && *opt != '=')
continue;
match = i;
if (!*name) {
cnt = 1;
break;
}
cnt++;
}
if (cnt == 1) {
i = match;
optind++;
optopt = longopts[i].val;
if (*opt == '=') {
if (!longopts[i].has_arg) {
if (colon || !opterr)
return '?';
__getopt_msg(argv[0], ": option does not take an argument: ", longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optarg = opt + 1;
} else if (longopts[i].has_arg == required_argument) {
if (!(optarg = argv[optind])) {
if (colon)
return ':';
if (!opterr)
return '?';
__getopt_msg(argv[0], ": option requires an argument: ", longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optind++;
}
if (idx)
*idx = i;
if (longopts[i].flag) {
*longopts[i].flag = longopts[i].val;
return 0;
}
return longopts[i].val;
}
if (argv[optind][1] == '-') {
if (!colon && opterr)
__getopt_msg(argv[0],
cnt ? ": option is ambiguous: " : ": unrecognized option: ", argv[optind] + 2,
strlen(argv[optind] + 2));
optind++;
return '?';
}
}
return getopt(argc, argv, optstring);
}
int getopt_long(int argc, char* const* argv, const char* optstring, const struct option* longopts,
int* idx) {
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}
int getopt_long_only(int argc, char* const* argv, const char* optstring,
const struct option* longopts, int* idx) {
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
}