GetOptInc.cpp revision 292932
1292932Sdim#include "lldb/Host/common/GetOptInc.h" 2292932Sdim 3292932Sdim#if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || defined(REPLACE_GETOPT_LONG_ONLY) 4292932Sdim 5292932Sdim// getopt.cpp 6292932Sdim#include <errno.h> 7292932Sdim#include <stdlib.h> 8292932Sdim#include <string.h> 9292932Sdim 10292932Sdim#if defined(REPLACE_GETOPT) 11292932Sdimint opterr = 1; /* if error message should be printed */ 12292932Sdimint optind = 1; /* index into parent argv vector */ 13292932Sdimint optopt = '?'; /* character checked for validity */ 14292932Sdimint optreset; /* reset getopt */ 15292932Sdimchar *optarg; /* argument associated with option */ 16292932Sdim#endif 17292932Sdim 18292932Sdim#define PRINT_ERROR ((opterr) && (*options != ':')) 19292932Sdim 20292932Sdim#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ 21292932Sdim#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ 22292932Sdim#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ 23292932Sdim 24292932Sdim/* return values */ 25292932Sdim#define BADCH (int)'?' 26292932Sdim#define BADARG ((*options == ':') ? (int)':' : (int)'?') 27292932Sdim#define INORDER (int)1 28292932Sdim 29292932Sdim#define EMSG "" 30292932Sdim 31292932Sdimstatic int getopt_internal(int, char * const *, const char *, 32292932Sdim const struct option *, int *, int); 33292932Sdimstatic int parse_long_options(char * const *, const char *, 34292932Sdim const struct option *, int *, int); 35292932Sdimstatic int gcd(int, int); 36292932Sdimstatic void permute_args(int, int, int, char * const *); 37292932Sdim 38292932Sdimstatic const char *place = EMSG; /* option letter processing */ 39292932Sdim 40292932Sdim/* XXX: set optreset to 1 rather than these two */ 41292932Sdimstatic int nonopt_start = -1; /* first non option argument (for permute) */ 42292932Sdimstatic int nonopt_end = -1; /* first option after non options (for permute) */ 43292932Sdim 44292932Sdim/* 45292932Sdim* Compute the greatest common divisor of a and b. 46292932Sdim*/ 47292932Sdimstatic int 48292932Sdimgcd(int a, int b) 49292932Sdim{ 50292932Sdim int c; 51292932Sdim 52292932Sdim c = a % b; 53292932Sdim while (c != 0) { 54292932Sdim a = b; 55292932Sdim b = c; 56292932Sdim c = a % b; 57292932Sdim } 58292932Sdim 59292932Sdim return (b); 60292932Sdim} 61292932Sdim 62292932Sdimstatic void pass() {} 63292932Sdim#define warnx(a, ...) pass(); 64292932Sdim 65292932Sdim/* 66292932Sdim* Exchange the block from nonopt_start to nonopt_end with the block 67292932Sdim* from nonopt_end to opt_end (keeping the same order of arguments 68292932Sdim* in each block). 69292932Sdim*/ 70292932Sdimstatic void 71292932Sdimpermute_args(int panonopt_start, int panonopt_end, int opt_end, 72292932Sdimchar * const *nargv) 73292932Sdim{ 74292932Sdim int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; 75292932Sdim char *swap; 76292932Sdim 77292932Sdim /* 78292932Sdim * compute lengths of blocks and number and size of cycles 79292932Sdim */ 80292932Sdim nnonopts = panonopt_end - panonopt_start; 81292932Sdim nopts = opt_end - panonopt_end; 82292932Sdim ncycle = gcd(nnonopts, nopts); 83292932Sdim cyclelen = (opt_end - panonopt_start) / ncycle; 84292932Sdim 85292932Sdim for (i = 0; i < ncycle; i++) { 86292932Sdim cstart = panonopt_end + i; 87292932Sdim pos = cstart; 88292932Sdim for (j = 0; j < cyclelen; j++) { 89292932Sdim if (pos >= panonopt_end) 90292932Sdim pos -= nnonopts; 91292932Sdim else 92292932Sdim pos += nopts; 93292932Sdim swap = nargv[pos]; 94292932Sdim /* LINTED const cast */ 95292932Sdim ((char **)nargv)[pos] = nargv[cstart]; 96292932Sdim /* LINTED const cast */ 97292932Sdim ((char **)nargv)[cstart] = swap; 98292932Sdim } 99292932Sdim } 100292932Sdim} 101292932Sdim 102292932Sdim/* 103292932Sdim* parse_long_options -- 104292932Sdim* Parse long options in argc/argv argument vector. 105292932Sdim* Returns -1 if short_too is set and the option does not match long_options. 106292932Sdim*/ 107292932Sdimstatic int 108292932Sdimparse_long_options(char * const *nargv, const char *options, 109292932Sdimconst struct option *long_options, int *idx, int short_too) 110292932Sdim{ 111292932Sdim char *current_argv, *has_equal; 112292932Sdim size_t current_argv_len; 113292932Sdim int i, match; 114292932Sdim 115292932Sdim current_argv = const_cast<char*>(place); 116292932Sdim match = -1; 117292932Sdim 118292932Sdim optind++; 119292932Sdim 120292932Sdim if ((has_equal = strchr(current_argv, '=')) != NULL) { 121292932Sdim /* argument found (--option=arg) */ 122292932Sdim current_argv_len = has_equal - current_argv; 123292932Sdim has_equal++; 124292932Sdim } 125292932Sdim else 126292932Sdim current_argv_len = strlen(current_argv); 127292932Sdim 128292932Sdim for (i = 0; long_options[i].name; i++) { 129292932Sdim /* find matching long option */ 130292932Sdim if (strncmp(current_argv, long_options[i].name, 131292932Sdim current_argv_len)) 132292932Sdim continue; 133292932Sdim 134292932Sdim if (strlen(long_options[i].name) == current_argv_len) { 135292932Sdim /* exact match */ 136292932Sdim match = i; 137292932Sdim break; 138292932Sdim } 139292932Sdim /* 140292932Sdim * If this is a known short option, don't allow 141292932Sdim * a partial match of a single character. 142292932Sdim */ 143292932Sdim if (short_too && current_argv_len == 1) 144292932Sdim continue; 145292932Sdim 146292932Sdim if (match == -1) /* partial match */ 147292932Sdim match = i; 148292932Sdim else { 149292932Sdim /* ambiguous abbreviation */ 150292932Sdim if (PRINT_ERROR) 151292932Sdim warnx(ambig, (int)current_argv_len, 152292932Sdim current_argv); 153292932Sdim optopt = 0; 154292932Sdim return (BADCH); 155292932Sdim } 156292932Sdim } 157292932Sdim if (match != -1) { /* option found */ 158292932Sdim if (long_options[match].has_arg == no_argument 159292932Sdim && has_equal) { 160292932Sdim if (PRINT_ERROR) 161292932Sdim warnx(noarg, (int)current_argv_len, 162292932Sdim current_argv); 163292932Sdim /* 164292932Sdim * XXX: GNU sets optopt to val regardless of flag 165292932Sdim */ 166292932Sdim if (long_options[match].flag == NULL) 167292932Sdim optopt = long_options[match].val; 168292932Sdim else 169292932Sdim optopt = 0; 170292932Sdim return (BADARG); 171292932Sdim } 172292932Sdim if (long_options[match].has_arg == required_argument || 173292932Sdim long_options[match].has_arg == optional_argument) { 174292932Sdim if (has_equal) 175292932Sdim optarg = has_equal; 176292932Sdim else if (long_options[match].has_arg == 177292932Sdim required_argument) { 178292932Sdim /* 179292932Sdim * optional argument doesn't use next nargv 180292932Sdim */ 181292932Sdim optarg = nargv[optind++]; 182292932Sdim } 183292932Sdim } 184292932Sdim if ((long_options[match].has_arg == required_argument) 185292932Sdim && (optarg == NULL)) { 186292932Sdim /* 187292932Sdim * Missing argument; leading ':' indicates no error 188292932Sdim * should be generated. 189292932Sdim */ 190292932Sdim if (PRINT_ERROR) 191292932Sdim warnx(recargstring, 192292932Sdim current_argv); 193292932Sdim /* 194292932Sdim * XXX: GNU sets optopt to val regardless of flag 195292932Sdim */ 196292932Sdim if (long_options[match].flag == NULL) 197292932Sdim optopt = long_options[match].val; 198292932Sdim else 199292932Sdim optopt = 0; 200292932Sdim --optind; 201292932Sdim return (BADARG); 202292932Sdim } 203292932Sdim } 204292932Sdim else { /* unknown option */ 205292932Sdim if (short_too) { 206292932Sdim --optind; 207292932Sdim return (-1); 208292932Sdim } 209292932Sdim if (PRINT_ERROR) 210292932Sdim warnx(illoptstring, current_argv); 211292932Sdim optopt = 0; 212292932Sdim return (BADCH); 213292932Sdim } 214292932Sdim if (idx) 215292932Sdim *idx = match; 216292932Sdim if (long_options[match].flag) { 217292932Sdim *long_options[match].flag = long_options[match].val; 218292932Sdim return (0); 219292932Sdim } 220292932Sdim else 221292932Sdim return (long_options[match].val); 222292932Sdim} 223292932Sdim 224292932Sdim/* 225292932Sdim* getopt_internal -- 226292932Sdim* Parse argc/argv argument vector. Called by user level routines. 227292932Sdim*/ 228292932Sdimstatic int 229292932Sdimgetopt_internal(int nargc, char * const *nargv, const char *options, 230292932Sdimconst struct option *long_options, int *idx, int flags) 231292932Sdim{ 232292932Sdim const char *oli; /* option letter list index */ 233292932Sdim int optchar, short_too; 234292932Sdim static int posixly_correct = -1; 235292932Sdim 236292932Sdim if (options == NULL) 237292932Sdim return (-1); 238292932Sdim 239292932Sdim /* 240292932Sdim * XXX Some GNU programs (like cvs) set optind to 0 instead of 241292932Sdim * XXX using optreset. Work around this braindamage. 242292932Sdim */ 243292932Sdim if (optind == 0) 244292932Sdim optind = optreset = 1; 245292932Sdim 246292932Sdim /* 247292932Sdim * Disable GNU extensions if POSIXLY_CORRECT is set or options 248292932Sdim * string begins with a '+'. 249292932Sdim */ 250292932Sdim if (posixly_correct == -1 || optreset) 251292932Sdim posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); 252292932Sdim if (*options == '-') 253292932Sdim flags |= FLAG_ALLARGS; 254292932Sdim else if (posixly_correct || *options == '+') 255292932Sdim flags &= ~FLAG_PERMUTE; 256292932Sdim if (*options == '+' || *options == '-') 257292932Sdim options++; 258292932Sdim 259292932Sdim optarg = NULL; 260292932Sdim if (optreset) 261292932Sdim nonopt_start = nonopt_end = -1; 262292932Sdimstart: 263292932Sdim if (optreset || !*place) { /* update scanning pointer */ 264292932Sdim optreset = 0; 265292932Sdim if (optind >= nargc) { /* end of argument vector */ 266292932Sdim place = EMSG; 267292932Sdim if (nonopt_end != -1) { 268292932Sdim /* do permutation, if we have to */ 269292932Sdim permute_args(nonopt_start, nonopt_end, 270292932Sdim optind, nargv); 271292932Sdim optind -= nonopt_end - nonopt_start; 272292932Sdim } 273292932Sdim else if (nonopt_start != -1) { 274292932Sdim /* 275292932Sdim * If we skipped non-options, set optind 276292932Sdim * to the first of them. 277292932Sdim */ 278292932Sdim optind = nonopt_start; 279292932Sdim } 280292932Sdim nonopt_start = nonopt_end = -1; 281292932Sdim return (-1); 282292932Sdim } 283292932Sdim if (*(place = nargv[optind]) != '-' || 284292932Sdim (place[1] == '\0' && strchr(options, '-') == NULL)) { 285292932Sdim place = EMSG; /* found non-option */ 286292932Sdim if (flags & FLAG_ALLARGS) { 287292932Sdim /* 288292932Sdim * GNU extension: 289292932Sdim * return non-option as argument to option 1 290292932Sdim */ 291292932Sdim optarg = nargv[optind++]; 292292932Sdim return (INORDER); 293292932Sdim } 294292932Sdim if (!(flags & FLAG_PERMUTE)) { 295292932Sdim /* 296292932Sdim * If no permutation wanted, stop parsing 297292932Sdim * at first non-option. 298292932Sdim */ 299292932Sdim return (-1); 300292932Sdim } 301292932Sdim /* do permutation */ 302292932Sdim if (nonopt_start == -1) 303292932Sdim nonopt_start = optind; 304292932Sdim else if (nonopt_end != -1) { 305292932Sdim permute_args(nonopt_start, nonopt_end, 306292932Sdim optind, nargv); 307292932Sdim nonopt_start = optind - 308292932Sdim (nonopt_end - nonopt_start); 309292932Sdim nonopt_end = -1; 310292932Sdim } 311292932Sdim optind++; 312292932Sdim /* process next argument */ 313292932Sdim goto start; 314292932Sdim } 315292932Sdim if (nonopt_start != -1 && nonopt_end == -1) 316292932Sdim nonopt_end = optind; 317292932Sdim 318292932Sdim /* 319292932Sdim * If we have "-" do nothing, if "--" we are done. 320292932Sdim */ 321292932Sdim if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { 322292932Sdim optind++; 323292932Sdim place = EMSG; 324292932Sdim /* 325292932Sdim * We found an option (--), so if we skipped 326292932Sdim * non-options, we have to permute. 327292932Sdim */ 328292932Sdim if (nonopt_end != -1) { 329292932Sdim permute_args(nonopt_start, nonopt_end, 330292932Sdim optind, nargv); 331292932Sdim optind -= nonopt_end - nonopt_start; 332292932Sdim } 333292932Sdim nonopt_start = nonopt_end = -1; 334292932Sdim return (-1); 335292932Sdim } 336292932Sdim } 337292932Sdim 338292932Sdim /* 339292932Sdim * Check long options if: 340292932Sdim * 1) we were passed some 341292932Sdim * 2) the arg is not just "-" 342292932Sdim * 3) either the arg starts with -- we are getopt_long_only() 343292932Sdim */ 344292932Sdim if (long_options != NULL && place != nargv[optind] && 345292932Sdim (*place == '-' || (flags & FLAG_LONGONLY))) { 346292932Sdim short_too = 0; 347292932Sdim if (*place == '-') 348292932Sdim place++; /* --foo long option */ 349292932Sdim else if (*place != ':' && strchr(options, *place) != NULL) 350292932Sdim short_too = 1; /* could be short option too */ 351292932Sdim 352292932Sdim optchar = parse_long_options(nargv, options, long_options, 353292932Sdim idx, short_too); 354292932Sdim if (optchar != -1) { 355292932Sdim place = EMSG; 356292932Sdim return (optchar); 357292932Sdim } 358292932Sdim } 359292932Sdim 360292932Sdim if ((optchar = (int)*place++) == (int)':' || 361292932Sdim (optchar == (int)'-' && *place != '\0') || 362292932Sdim (oli = strchr(options, optchar)) == NULL) { 363292932Sdim /* 364292932Sdim * If the user specified "-" and '-' isn't listed in 365292932Sdim * options, return -1 (non-option) as per POSIX. 366292932Sdim * Otherwise, it is an unknown option character (or ':'). 367292932Sdim */ 368292932Sdim if (optchar == (int)'-' && *place == '\0') 369292932Sdim return (-1); 370292932Sdim if (!*place) 371292932Sdim ++optind; 372292932Sdim if (PRINT_ERROR) 373292932Sdim warnx(illoptchar, optchar); 374292932Sdim optopt = optchar; 375292932Sdim return (BADCH); 376292932Sdim } 377292932Sdim if (long_options != NULL && optchar == 'W' && oli[1] == ';') { 378292932Sdim /* -W long-option */ 379292932Sdim if (*place) /* no space */ 380292932Sdim /* NOTHING */; 381292932Sdim else if (++optind >= nargc) { /* no arg */ 382292932Sdim place = EMSG; 383292932Sdim if (PRINT_ERROR) 384292932Sdim warnx(recargchar, optchar); 385292932Sdim optopt = optchar; 386292932Sdim return (BADARG); 387292932Sdim } 388292932Sdim else /* white space */ 389292932Sdim place = nargv[optind]; 390292932Sdim optchar = parse_long_options(nargv, options, long_options, 391292932Sdim idx, 0); 392292932Sdim place = EMSG; 393292932Sdim return (optchar); 394292932Sdim } 395292932Sdim if (*++oli != ':') { /* doesn't take argument */ 396292932Sdim if (!*place) 397292932Sdim ++optind; 398292932Sdim } 399292932Sdim else { /* takes (optional) argument */ 400292932Sdim optarg = NULL; 401292932Sdim if (*place) /* no white space */ 402292932Sdim optarg = const_cast<char*>(place); 403292932Sdim else if (oli[1] != ':') { /* arg not optional */ 404292932Sdim if (++optind >= nargc) { /* no arg */ 405292932Sdim place = EMSG; 406292932Sdim if (PRINT_ERROR) 407292932Sdim warnx(recargchar, optchar); 408292932Sdim optopt = optchar; 409292932Sdim return (BADARG); 410292932Sdim } 411292932Sdim else 412292932Sdim optarg = nargv[optind]; 413292932Sdim } 414292932Sdim place = EMSG; 415292932Sdim ++optind; 416292932Sdim } 417292932Sdim /* dump back option letter */ 418292932Sdim return (optchar); 419292932Sdim} 420292932Sdim 421292932Sdim/* 422292932Sdim* getopt -- 423292932Sdim* Parse argc/argv argument vector. 424292932Sdim* 425292932Sdim* [eventually this will replace the BSD getopt] 426292932Sdim*/ 427292932Sdim#if defined(REPLACE_GETOPT) 428292932Sdimint 429292932Sdimgetopt(int nargc, char * const *nargv, const char *options) 430292932Sdim{ 431292932Sdim 432292932Sdim /* 433292932Sdim * We don't pass FLAG_PERMUTE to getopt_internal() since 434292932Sdim * the BSD getopt(3) (unlike GNU) has never done this. 435292932Sdim * 436292932Sdim * Furthermore, since many privileged programs call getopt() 437292932Sdim * before dropping privileges it makes sense to keep things 438292932Sdim * as simple (and bug-free) as possible. 439292932Sdim */ 440292932Sdim return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); 441292932Sdim} 442292932Sdim#endif 443292932Sdim 444292932Sdim/* 445292932Sdim* getopt_long -- 446292932Sdim* Parse argc/argv argument vector. 447292932Sdim*/ 448292932Sdim#if defined(REPLACE_GETOPT_LONG) 449292932Sdimint 450292932Sdimgetopt_long(int nargc, char * const *nargv, const char *options, 451292932Sdimconst struct option *long_options, int *idx) 452292932Sdim{ 453292932Sdim return (getopt_internal(nargc, nargv, options, long_options, idx, 454292932Sdim FLAG_PERMUTE)); 455292932Sdim} 456292932Sdim#endif 457292932Sdim 458292932Sdim/* 459292932Sdim* getopt_long_only -- 460292932Sdim* Parse argc/argv argument vector. 461292932Sdim*/ 462292932Sdim#if defined(REPLACE_GETOPT_LONG_ONLY) 463292932Sdimint 464292932Sdimgetopt_long_only(int nargc, char * const *nargv, const char *options, 465292932Sdimconst struct option *long_options, int *idx) 466292932Sdim{ 467292932Sdim 468292932Sdim return (getopt_internal(nargc, nargv, options, long_options, idx, 469292932Sdim FLAG_PERMUTE | FLAG_LONGONLY)); 470292932Sdim} 471292932Sdim#endif 472292932Sdim 473292932Sdim#endif 474