#include #include #include #include #include #include #include #define REPLACE_GETOPT #define _DIAGASSERT(x) do {} while (0) #ifdef REPLACE_GETOPT #ifdef __weak_alias __weak_alias(getopt,_getopt) #endif int opterr = 1; int optind = 1; int optopt = '?'; int optreset; char *optarg; #endif #ifdef __weak_alias __weak_alias(getopt_long,_getopt_long) #endif #ifndef __CYGWIN__ #define __progname __argv[0] #else extern char __declspec(dllimport) *__progname; #endif #define IGNORE_FIRST (*options == '-' || *options == '+') #define PRINT_ERROR ((opterr) && ((*options != ':') || (IGNORE_FIRST && options[1] != ':'))) #ifndef IS_POSIXLY_CORRECT #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) #endif #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') #define BADCH (int)'?' #define BADARG ((IGNORE_FIRST && options[1] == ':') || (*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 static char EMSG[1]; static int getopt_internal (int,char * const *,const char *); static int gcd (int,int); static void permute_args (int,int,int,char * const *); static char *place = EMSG; static int nonopt_start = -1; static int nonopt_end = -1; static const char recargchar[] = "option requires an argument -- %c"; static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; static void _vwarnx(const char *fmt,va_list ap) { (void)fprintf(stderr,"%s: ",__progname); if (fmt != NULL) (void)vfprintf(stderr,fmt,ap); (void)fprintf(stderr,"\n"); } static void warnx(const char *fmt,...) { va_list ap; va_start(ap,fmt); _vwarnx(fmt,ap); va_end(ap); } static int gcd(a,b) int a; int b; { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return b; } static void permute_args(panonopt_start,panonopt_end,opt_end,nargv) int panonopt_start; int panonopt_end; int opt_end; char * const *nargv; { int cstart,cyclelen,i,j,ncycle,nnonopts,nopts,pos; char *swap; _DIAGASSERT(nargv != NULL); 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]; ((char **) nargv)[pos] = nargv[cstart]; ((char **)nargv)[cstart] = swap; } } } static int getopt_internal(nargc,nargv,options) int nargc; char * const *nargv; const char *options; { char *oli; int optchar; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); optarg = NULL; if (optind == 0) optind = 1; 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')) { place = EMSG; if (IN_ORDER) { optarg = nargv[optind++]; return INORDER; } if (!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] && *++place == '-') { place++; return -2; } } if ((optchar = (int)*place++) == (int)':' || (oli = strchr(options + (IGNORE_FIRST ? 1 : 0),optchar)) == NULL) { if (!*place) ++optind; if (PRINT_ERROR) warnx(illoptchar,optchar); optopt = optchar; return BADCH; } if (optchar == 'W' && oli[1] == ';') { if (*place) return -2; if (++optind >= nargc) { place = EMSG; if (PRINT_ERROR) warnx(recargchar,optchar); optopt = optchar; return BADARG; } else place = nargv[optind]; return -2; } if (*++oli != ':') { if (!*place) ++optind; } else { optarg = NULL; if (*place) optarg = 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; } #ifdef REPLACE_GETOPT int getopt(nargc,nargv,options) int nargc; char * const *nargv; const char *options; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); if ((retval = getopt_internal(nargc,nargv,options)) == -2) { ++optind; if (nonopt_end != -1) { permute_args(nonopt_start,nonopt_end,optind,nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; retval = -1; } return retval; } #endif int getopt_long(nargc,nargv,options,long_options,idx) int nargc; char * const *nargv; const char *options; const struct option *long_options; int *idx; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); _DIAGASSERT(long_options != NULL); if ((retval = getopt_internal(nargc,nargv,options)) == -2) { char *current_argv,*has_equal; size_t current_argv_len; int i,match; current_argv = place; match = -1; optind++; place = EMSG; if (*current_argv == '\0') { 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 ((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) == (unsigned)current_argv_len) { match = i; break; } 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 (PRINT_ERROR) warnx(illoptstring,current_argv); optopt = 0; return BADCH; } if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; retval = 0; } else retval = long_options[match].val; if (idx) *idx = match; } return retval; }