#define _GNU_SOURCE #include #include #include #include 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); }