1#define _GNU_SOURCE 2#include <getopt.h> 3#include <stddef.h> 4#include <stdio.h> 5#include <string.h> 6 7extern int __optpos, __optreset; 8 9static void permute(char* const* argv, int dest, int src) { 10 char** av = (char**)argv; 11 char* tmp = av[src]; 12 int i; 13 for (i = src; i > dest; i--) 14 av[i] = av[i - 1]; 15 av[dest] = tmp; 16} 17 18void __getopt_msg(const char*, const char*, const char*, size_t); 19 20static int __getopt_long_core(int argc, char* const* argv, const char* optstring, 21 const struct option* longopts, int* idx, int longonly); 22 23static int __getopt_long(int argc, char* const* argv, const char* optstring, 24 const struct option* longopts, int* idx, int longonly) { 25 int ret, skipped, resumed; 26 if (!optind || __optreset) { 27 __optreset = 0; 28 __optpos = 0; 29 optind = 1; 30 } 31 if (optind >= argc || !argv[optind]) 32 return -1; 33 skipped = optind; 34 if (optstring[0] != '+' && optstring[0] != '-') { 35 int i; 36 for (i = optind;; i++) { 37 if (i >= argc || !argv[i]) 38 return -1; 39 if (argv[i][0] == '-' && argv[i][1]) 40 break; 41 } 42 optind = i; 43 } 44 resumed = optind; 45 ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly); 46 if (resumed > skipped) { 47 int i, cnt = optind - resumed; 48 for (i = 0; i < cnt; i++) 49 permute(argv, skipped, optind - 1); 50 optind = skipped + cnt; 51 } 52 return ret; 53} 54 55static int __getopt_long_core(int argc, char* const* argv, const char* optstring, 56 const struct option* longopts, int* idx, int longonly) { 57 optarg = 0; 58 if (longopts && argv[optind][0] == '-' && 59 ((longonly && argv[optind][1]) || (argv[optind][1] == '-' && argv[optind][2]))) { 60 int colon = optstring[optstring[0] == '+' || optstring[0] == '-'] == ':'; 61 int i, cnt, match; 62 char* opt; 63 for (cnt = i = 0; longopts[i].name; i++) { 64 const char* name = longopts[i].name; 65 opt = argv[optind] + 1; 66 if (*opt == '-') 67 opt++; 68 for (; *name && *name == *opt; name++, opt++) 69 ; 70 if (*opt && *opt != '=') 71 continue; 72 match = i; 73 if (!*name) { 74 cnt = 1; 75 break; 76 } 77 cnt++; 78 } 79 if (cnt == 1) { 80 i = match; 81 optind++; 82 optopt = longopts[i].val; 83 if (*opt == '=') { 84 if (!longopts[i].has_arg) { 85 if (colon || !opterr) 86 return '?'; 87 __getopt_msg(argv[0], ": option does not take an argument: ", longopts[i].name, 88 strlen(longopts[i].name)); 89 return '?'; 90 } 91 optarg = opt + 1; 92 } else if (longopts[i].has_arg == required_argument) { 93 if (!(optarg = argv[optind])) { 94 if (colon) 95 return ':'; 96 if (!opterr) 97 return '?'; 98 __getopt_msg(argv[0], ": option requires an argument: ", longopts[i].name, 99 strlen(longopts[i].name)); 100 return '?'; 101 } 102 optind++; 103 } 104 if (idx) 105 *idx = i; 106 if (longopts[i].flag) { 107 *longopts[i].flag = longopts[i].val; 108 return 0; 109 } 110 return longopts[i].val; 111 } 112 if (argv[optind][1] == '-') { 113 if (!colon && opterr) 114 __getopt_msg(argv[0], cnt ? ": option is ambiguous: " : ": unrecognized option: ", 115 argv[optind] + 2, strlen(argv[optind] + 2)); 116 optind++; 117 return '?'; 118 } 119 } 120 return getopt(argc, argv, optstring); 121} 122 123int getopt_long(int argc, char* const* argv, const char* optstring, const struct option* longopts, 124 int* idx) { 125 return __getopt_long(argc, argv, optstring, longopts, idx, 0); 126} 127 128int getopt_long_only(int argc, char* const* argv, const char* optstring, 129 const struct option* longopts, int* idx) { 130 return __getopt_long(argc, argv, optstring, longopts, idx, 1); 131} 132