1 #include "lldb/Host/common/GetOptInc.h" 2 3 #if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || defined(REPLACE_GETOPT_LONG_ONLY) 4 5 // getopt.cpp 6 #include <errno.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #if defined(REPLACE_GETOPT) 11 int opterr = 1; /* if error message should be printed */ 12 int optind = 1; /* index into parent argv vector */ 13 int optopt = '?'; /* character checked for validity */ 14 int optreset; /* reset getopt */ 15 char *optarg; /* argument associated with option */ 16 #endif 17 18 #define PRINT_ERROR ((opterr) && (*options != ':')) 19 20 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ 21 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ 22 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ 23 24 /* return values */ 25 #define BADCH (int)'?' 26 #define BADARG ((*options == ':') ? (int)':' : (int)'?') 27 #define INORDER (int)1 28 29 #define EMSG "" 30 31 static int getopt_internal(int, char * const *, const char *, 32 const struct option *, int *, int); 33 static int parse_long_options(char * const *, const char *, 34 const struct option *, int *, int); 35 static int gcd(int, int); 36 static void permute_args(int, int, int, char * const *); 37 38 static const char *place = EMSG; /* option letter processing */ 39 40 /* XXX: set optreset to 1 rather than these two */ 41 static int nonopt_start = -1; /* first non option argument (for permute) */ 42 static int nonopt_end = -1; /* first option after non options (for permute) */ 43 44 /* 45 * Compute the greatest common divisor of a and b. 46 */ 47 static int 48 gcd(int a, int b) 49 { 50 int c; 51 52 c = a % b; 53 while (c != 0) { 54 a = b; 55 b = c; 56 c = a % b; 57 } 58 59 return (b); 60 } 61 62 static void pass() {} 63 #define warnx(a, ...) pass(); 64 65 /* 66 * Exchange the block from nonopt_start to nonopt_end with the block 67 * from nonopt_end to opt_end (keeping the same order of arguments 68 * in each block). 69 */ 70 static void 71 permute_args(int panonopt_start, int panonopt_end, int opt_end, 72 char * const *nargv) 73 { 74 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; 75 char *swap; 76 77 /* 78 * compute lengths of blocks and number and size of cycles 79 */ 80 nnonopts = panonopt_end - panonopt_start; 81 nopts = opt_end - panonopt_end; 82 ncycle = gcd(nnonopts, nopts); 83 cyclelen = (opt_end - panonopt_start) / ncycle; 84 85 for (i = 0; i < ncycle; i++) { 86 cstart = panonopt_end + i; 87 pos = cstart; 88 for (j = 0; j < cyclelen; j++) { 89 if (pos >= panonopt_end) 90 pos -= nnonopts; 91 else 92 pos += nopts; 93 swap = nargv[pos]; 94 /* LINTED const cast */ 95 ((char **)nargv)[pos] = nargv[cstart]; 96 /* LINTED const cast */ 97 ((char **)nargv)[cstart] = swap; 98 } 99 } 100 } 101 102 /* 103 * parse_long_options -- 104 * Parse long options in argc/argv argument vector. 105 * Returns -1 if short_too is set and the option does not match long_options. 106 */ 107 static int 108 parse_long_options(char * const *nargv, const char *options, 109 const struct option *long_options, int *idx, int short_too) 110 { 111 char *current_argv, *has_equal; 112 size_t current_argv_len; 113 int i, match; 114 115 current_argv = const_cast<char*>(place); 116 match = -1; 117 118 optind++; 119 120 if ((has_equal = strchr(current_argv, '=')) != NULL) { 121 /* argument found (--option=arg) */ 122 current_argv_len = has_equal - current_argv; 123 has_equal++; 124 } 125 else 126 current_argv_len = strlen(current_argv); 127 128 for (i = 0; long_options[i].name; i++) { 129 /* find matching long option */ 130 if (strncmp(current_argv, long_options[i].name, 131 current_argv_len)) 132 continue; 133 134 if (strlen(long_options[i].name) == current_argv_len) { 135 /* exact match */ 136 match = i; 137 break; 138 } 139 /* 140 * If this is a known short option, don't allow 141 * a partial match of a single character. 142 */ 143 if (short_too && current_argv_len == 1) 144 continue; 145 146 if (match == -1) /* partial match */ 147 match = i; 148 else { 149 /* ambiguous abbreviation */ 150 if (PRINT_ERROR) 151 warnx(ambig, (int)current_argv_len, 152 current_argv); 153 optopt = 0; 154 return (BADCH); 155 } 156 } 157 if (match != -1) { /* option found */ 158 if (long_options[match].has_arg == no_argument 159 && has_equal) { 160 if (PRINT_ERROR) 161 warnx(noarg, (int)current_argv_len, 162 current_argv); 163 /* 164 * XXX: GNU sets optopt to val regardless of flag 165 */ 166 if (long_options[match].flag == NULL) 167 optopt = long_options[match].val; 168 else 169 optopt = 0; 170 return (BADARG); 171 } 172 if (long_options[match].has_arg == required_argument || 173 long_options[match].has_arg == optional_argument) { 174 if (has_equal) 175 optarg = has_equal; 176 else if (long_options[match].has_arg == 177 required_argument) { 178 /* 179 * optional argument doesn't use next nargv 180 */ 181 optarg = nargv[optind++]; 182 } 183 } 184 if ((long_options[match].has_arg == required_argument) 185 && (optarg == NULL)) { 186 /* 187 * Missing argument; leading ':' indicates no error 188 * should be generated. 189 */ 190 if (PRINT_ERROR) 191 warnx(recargstring, 192 current_argv); 193 /* 194 * XXX: GNU sets optopt to val regardless of flag 195 */ 196 if (long_options[match].flag == NULL) 197 optopt = long_options[match].val; 198 else 199 optopt = 0; 200 --optind; 201 return (BADARG); 202 } 203 } 204 else { /* unknown option */ 205 if (short_too) { 206 --optind; 207 return (-1); 208 } 209 if (PRINT_ERROR) 210 warnx(illoptstring, current_argv); 211 optopt = 0; 212 return (BADCH); 213 } 214 if (idx) 215 *idx = match; 216 if (long_options[match].flag) { 217 *long_options[match].flag = long_options[match].val; 218 return (0); 219 } 220 else 221 return (long_options[match].val); 222 } 223 224 /* 225 * getopt_internal -- 226 * Parse argc/argv argument vector. Called by user level routines. 227 */ 228 static int 229 getopt_internal(int nargc, char * const *nargv, const char *options, 230 const struct option *long_options, int *idx, int flags) 231 { 232 const char *oli; /* option letter list index */ 233 int optchar, short_too; 234 static int posixly_correct = -1; 235 236 if (options == NULL) 237 return (-1); 238 239 /* 240 * XXX Some GNU programs (like cvs) set optind to 0 instead of 241 * XXX using optreset. Work around this braindamage. 242 */ 243 if (optind == 0) 244 optind = optreset = 1; 245 246 /* 247 * Disable GNU extensions if POSIXLY_CORRECT is set or options 248 * string begins with a '+'. 249 */ 250 if (posixly_correct == -1 || optreset) 251 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); 252 if (*options == '-') 253 flags |= FLAG_ALLARGS; 254 else if (posixly_correct || *options == '+') 255 flags &= ~FLAG_PERMUTE; 256 if (*options == '+' || *options == '-') 257 options++; 258 259 optarg = NULL; 260 if (optreset) 261 nonopt_start = nonopt_end = -1; 262 start: 263 if (optreset || !*place) { /* update scanning pointer */ 264 optreset = 0; 265 if (optind >= nargc) { /* end of argument vector */ 266 place = EMSG; 267 if (nonopt_end != -1) { 268 /* do permutation, if we have to */ 269 permute_args(nonopt_start, nonopt_end, 270 optind, nargv); 271 optind -= nonopt_end - nonopt_start; 272 } 273 else if (nonopt_start != -1) { 274 /* 275 * If we skipped non-options, set optind 276 * to the first of them. 277 */ 278 optind = nonopt_start; 279 } 280 nonopt_start = nonopt_end = -1; 281 return (-1); 282 } 283 if (*(place = nargv[optind]) != '-' || 284 (place[1] == '\0' && strchr(options, '-') == NULL)) { 285 place = EMSG; /* found non-option */ 286 if (flags & FLAG_ALLARGS) { 287 /* 288 * GNU extension: 289 * return non-option as argument to option 1 290 */ 291 optarg = nargv[optind++]; 292 return (INORDER); 293 } 294 if (!(flags & FLAG_PERMUTE)) { 295 /* 296 * If no permutation wanted, stop parsing 297 * at first non-option. 298 */ 299 return (-1); 300 } 301 /* do permutation */ 302 if (nonopt_start == -1) 303 nonopt_start = optind; 304 else if (nonopt_end != -1) { 305 permute_args(nonopt_start, nonopt_end, 306 optind, nargv); 307 nonopt_start = optind - 308 (nonopt_end - nonopt_start); 309 nonopt_end = -1; 310 } 311 optind++; 312 /* process next argument */ 313 goto start; 314 } 315 if (nonopt_start != -1 && nonopt_end == -1) 316 nonopt_end = optind; 317 318 /* 319 * If we have "-" do nothing, if "--" we are done. 320 */ 321 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { 322 optind++; 323 place = EMSG; 324 /* 325 * We found an option (--), so if we skipped 326 * non-options, we have to permute. 327 */ 328 if (nonopt_end != -1) { 329 permute_args(nonopt_start, nonopt_end, 330 optind, nargv); 331 optind -= nonopt_end - nonopt_start; 332 } 333 nonopt_start = nonopt_end = -1; 334 return (-1); 335 } 336 } 337 338 /* 339 * Check long options if: 340 * 1) we were passed some 341 * 2) the arg is not just "-" 342 * 3) either the arg starts with -- we are getopt_long_only() 343 */ 344 if (long_options != NULL && place != nargv[optind] && 345 (*place == '-' || (flags & FLAG_LONGONLY))) { 346 short_too = 0; 347 if (*place == '-') 348 place++; /* --foo long option */ 349 else if (*place != ':' && strchr(options, *place) != NULL) 350 short_too = 1; /* could be short option too */ 351 352 optchar = parse_long_options(nargv, options, long_options, 353 idx, short_too); 354 if (optchar != -1) { 355 place = EMSG; 356 return (optchar); 357 } 358 } 359 360 if ((optchar = (int)*place++) == (int)':' || 361 (optchar == (int)'-' && *place != '\0') || 362 (oli = strchr(options, optchar)) == NULL) { 363 /* 364 * If the user specified "-" and '-' isn't listed in 365 * options, return -1 (non-option) as per POSIX. 366 * Otherwise, it is an unknown option character (or ':'). 367 */ 368 if (optchar == (int)'-' && *place == '\0') 369 return (-1); 370 if (!*place) 371 ++optind; 372 if (PRINT_ERROR) 373 warnx(illoptchar, optchar); 374 optopt = optchar; 375 return (BADCH); 376 } 377 if (long_options != NULL && optchar == 'W' && oli[1] == ';') { 378 /* -W long-option */ 379 if (*place) /* no space */ 380 /* NOTHING */; 381 else if (++optind >= nargc) { /* no arg */ 382 place = EMSG; 383 if (PRINT_ERROR) 384 warnx(recargchar, optchar); 385 optopt = optchar; 386 return (BADARG); 387 } 388 else /* white space */ 389 place = nargv[optind]; 390 optchar = parse_long_options(nargv, options, long_options, 391 idx, 0); 392 place = EMSG; 393 return (optchar); 394 } 395 if (*++oli != ':') { /* doesn't take argument */ 396 if (!*place) 397 ++optind; 398 } 399 else { /* takes (optional) argument */ 400 optarg = NULL; 401 if (*place) /* no white space */ 402 optarg = const_cast<char*>(place); 403 else if (oli[1] != ':') { /* arg not optional */ 404 if (++optind >= nargc) { /* no arg */ 405 place = EMSG; 406 if (PRINT_ERROR) 407 warnx(recargchar, optchar); 408 optopt = optchar; 409 return (BADARG); 410 } 411 else 412 optarg = nargv[optind]; 413 } 414 place = EMSG; 415 ++optind; 416 } 417 /* dump back option letter */ 418 return (optchar); 419 } 420 421 /* 422 * getopt -- 423 * Parse argc/argv argument vector. 424 * 425 * [eventually this will replace the BSD getopt] 426 */ 427 #if defined(REPLACE_GETOPT) 428 int 429 getopt(int nargc, char * const *nargv, const char *options) 430 { 431 432 /* 433 * We don't pass FLAG_PERMUTE to getopt_internal() since 434 * the BSD getopt(3) (unlike GNU) has never done this. 435 * 436 * Furthermore, since many privileged programs call getopt() 437 * before dropping privileges it makes sense to keep things 438 * as simple (and bug-free) as possible. 439 */ 440 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); 441 } 442 #endif 443 444 /* 445 * getopt_long -- 446 * Parse argc/argv argument vector. 447 */ 448 #if defined(REPLACE_GETOPT_LONG) 449 int 450 getopt_long(int nargc, char * const *nargv, const char *options, 451 const struct option *long_options, int *idx) 452 { 453 return (getopt_internal(nargc, nargv, options, long_options, idx, 454 FLAG_PERMUTE)); 455 } 456 #endif 457 458 /* 459 * getopt_long_only -- 460 * Parse argc/argv argument vector. 461 */ 462 #if defined(REPLACE_GETOPT_LONG_ONLY) 463 int 464 getopt_long_only(int nargc, char * const *nargv, const char *options, 465 const struct option *long_options, int *idx) 466 { 467 468 return (getopt_internal(nargc, nargv, options, long_options, idx, 469 FLAG_PERMUTE | FLAG_LONGONLY)); 470 } 471 #endif 472 473 #endif 474