1 /* 2 * Copyright 2008-2009 Katholieke Universiteit Leuven 3 * 4 * Use of this software is governed by the MIT license 5 * 6 * Written by Sven Verdoolaege, K.U.Leuven, Departement 7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium 8 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <isl/arg.h> 15 #include <isl/ctx.h> 16 #include <isl_config.h> 17 18 static struct isl_arg help_arg[] = { 19 ISL_ARG_PHANTOM_BOOL('h', "help", NULL, "print this help, then exit") 20 { isl_arg_end } 21 }; 22 23 static void set_default_choice(struct isl_arg *arg, void *opt) 24 { 25 if (arg->offset == ISL_ARG_OFFSET_NONE) 26 return; 27 *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value; 28 } 29 30 static void set_default_flags(struct isl_arg *arg, void *opt) 31 { 32 *(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value; 33 } 34 35 static void set_default_bool(struct isl_arg *arg, void *opt) 36 { 37 if (arg->offset == ISL_ARG_OFFSET_NONE) 38 return; 39 *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value; 40 } 41 42 static void set_default_child(struct isl_arg *arg, void *opt) 43 { 44 void *child; 45 46 if (arg->offset == ISL_ARG_OFFSET_NONE) 47 child = opt; 48 else { 49 child = calloc(1, arg->u.child.child->options_size); 50 *(void **)(((char *)opt) + arg->offset) = child; 51 } 52 53 if (child) 54 isl_args_set_defaults(arg->u.child.child, child); 55 } 56 57 static void set_default_user(struct isl_arg *arg, void *opt) 58 { 59 arg->u.user.init(((char *)opt) + arg->offset); 60 } 61 62 static void set_default_int(struct isl_arg *arg, void *opt) 63 { 64 *(int *)(((char *)opt) + arg->offset) = arg->u.i.default_value; 65 } 66 67 static void set_default_long(struct isl_arg *arg, void *opt) 68 { 69 *(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value; 70 } 71 72 static void set_default_ulong(struct isl_arg *arg, void *opt) 73 { 74 *(unsigned long *)(((char *)opt) + arg->offset) = arg->u.ul.default_value; 75 } 76 77 static void set_default_str(struct isl_arg *arg, void *opt) 78 { 79 const char *str = NULL; 80 if (arg->u.str.default_value) 81 str = strdup(arg->u.str.default_value); 82 *(const char **)(((char *)opt) + arg->offset) = str; 83 } 84 85 static void set_default_str_list(struct isl_arg *arg, void *opt) 86 { 87 *(const char ***)(((char *) opt) + arg->offset) = NULL; 88 *(int *)(((char *) opt) + arg->u.str_list.offset_n) = 0; 89 } 90 91 void isl_args_set_defaults(struct isl_args *args, void *opt) 92 { 93 int i; 94 95 for (i = 0; args->args[i].type != isl_arg_end; ++i) { 96 switch (args->args[i].type) { 97 case isl_arg_choice: 98 set_default_choice(&args->args[i], opt); 99 break; 100 case isl_arg_flags: 101 set_default_flags(&args->args[i], opt); 102 break; 103 case isl_arg_bool: 104 set_default_bool(&args->args[i], opt); 105 break; 106 case isl_arg_child: 107 set_default_child(&args->args[i], opt); 108 break; 109 case isl_arg_user: 110 set_default_user(&args->args[i], opt); 111 break; 112 case isl_arg_int: 113 set_default_int(&args->args[i], opt); 114 break; 115 case isl_arg_long: 116 set_default_long(&args->args[i], opt); 117 break; 118 case isl_arg_ulong: 119 set_default_ulong(&args->args[i], opt); 120 break; 121 case isl_arg_arg: 122 case isl_arg_str: 123 set_default_str(&args->args[i], opt); 124 break; 125 case isl_arg_str_list: 126 set_default_str_list(&args->args[i], opt); 127 break; 128 case isl_arg_alias: 129 case isl_arg_footer: 130 case isl_arg_version: 131 case isl_arg_end: 132 break; 133 } 134 } 135 } 136 137 static void free_args(struct isl_arg *arg, void *opt); 138 139 static void free_child(struct isl_arg *arg, void *opt) 140 { 141 if (arg->offset == ISL_ARG_OFFSET_NONE) 142 free_args(arg->u.child.child->args, opt); 143 else 144 isl_args_free(arg->u.child.child, 145 *(void **)(((char *)opt) + arg->offset)); 146 } 147 148 static void free_str_list(struct isl_arg *arg, void *opt) 149 { 150 int i; 151 int n = *(int *)(((char *) opt) + arg->u.str_list.offset_n); 152 char **list = *(char ***)(((char *) opt) + arg->offset); 153 154 for (i = 0; i < n; ++i) 155 free(list[i]); 156 free(list); 157 } 158 159 static void free_user(struct isl_arg *arg, void *opt) 160 { 161 if (arg->u.user.clear) 162 arg->u.user.clear(((char *)opt) + arg->offset); 163 } 164 165 static void free_args(struct isl_arg *arg, void *opt) 166 { 167 int i; 168 169 for (i = 0; arg[i].type != isl_arg_end; ++i) { 170 switch (arg[i].type) { 171 case isl_arg_child: 172 free_child(&arg[i], opt); 173 break; 174 case isl_arg_arg: 175 case isl_arg_str: 176 free(*(char **)(((char *)opt) + arg[i].offset)); 177 break; 178 case isl_arg_str_list: 179 free_str_list(&arg[i], opt); 180 break; 181 case isl_arg_user: 182 free_user(&arg[i], opt); 183 break; 184 case isl_arg_alias: 185 case isl_arg_bool: 186 case isl_arg_choice: 187 case isl_arg_flags: 188 case isl_arg_int: 189 case isl_arg_long: 190 case isl_arg_ulong: 191 case isl_arg_version: 192 case isl_arg_footer: 193 case isl_arg_end: 194 break; 195 } 196 } 197 } 198 199 void isl_args_free(struct isl_args *args, void *opt) 200 { 201 if (!opt) 202 return; 203 204 free_args(args->args, opt); 205 206 free(opt); 207 } 208 209 /* Data structure for collecting the prefixes of ancestor nodes. 210 * 211 * n is the number of prefixes. 212 * prefix[i] for i < n is a prefix of an ancestor. 213 * len[i] for i < n is the length of prefix[i]. 214 */ 215 struct isl_prefixes { 216 int n; 217 const char *prefix[10]; 218 size_t len[10]; 219 }; 220 221 /* Add "prefix" to the list of prefixes and return the updated 222 * number of prefixes. 223 */ 224 static int add_prefix(struct isl_prefixes *prefixes, const char *prefix) 225 { 226 int n = prefixes->n; 227 228 if (!prefix) 229 return n; 230 231 if (prefixes->n >= 10) { 232 fprintf(stderr, "too many prefixes\n"); 233 exit(EXIT_FAILURE); 234 } 235 prefixes->len[prefixes->n] = strlen(prefix); 236 prefixes->prefix[prefixes->n] = prefix; 237 prefixes->n++; 238 239 return n; 240 } 241 242 /* Drop all prefixes starting at "first". 243 */ 244 static void drop_prefix(struct isl_prefixes *prefixes, int first) 245 { 246 prefixes->n = first; 247 } 248 249 /* Print the prefixes in "prefixes". 250 */ 251 static int print_prefixes(struct isl_prefixes *prefixes) 252 { 253 int i; 254 int len = 0; 255 256 if (!prefixes) 257 return 0; 258 259 for (i = 0; i < prefixes->n; ++i) { 260 printf("%s-", prefixes->prefix[i]); 261 len += strlen(prefixes->prefix[i]) + 1; 262 } 263 264 return len; 265 } 266 267 /* Check if "name" starts with one or more of the prefixes in "prefixes", 268 * starting at *first. If so, advance the pointer beyond the prefixes 269 * and return the updated pointer. Additionally, update *first to 270 * the index after the last prefix found. 271 */ 272 static const char *skip_prefixes(const char *name, 273 struct isl_prefixes *prefixes, int *first) 274 { 275 int i; 276 277 for (i = first ? *first : 0; i < prefixes->n; ++i) { 278 size_t len = prefixes->len[i]; 279 const char *prefix = prefixes->prefix[i]; 280 if (strncmp(name, prefix, len) == 0 && name[len] == '-') { 281 name += len + 1; 282 if (first) 283 *first = i + 1; 284 } 285 } 286 287 return name; 288 } 289 290 static int print_arg_help(struct isl_arg *decl, struct isl_prefixes *prefixes, 291 int no) 292 { 293 int len = 0; 294 295 if (!decl->long_name) { 296 printf(" -%c", decl->short_name); 297 return 4; 298 } 299 300 if (decl->short_name) { 301 printf(" -%c, --", decl->short_name); 302 len += 8; 303 } else if (decl->flags & ISL_ARG_SINGLE_DASH) { 304 printf(" -"); 305 len += 3; 306 } else { 307 printf(" --"); 308 len += 8; 309 } 310 311 if (no) { 312 printf("no-"); 313 len += 3; 314 } 315 len += print_prefixes(prefixes); 316 printf("%s", decl->long_name); 317 len += strlen(decl->long_name); 318 319 while ((++decl)->type == isl_arg_alias) { 320 printf(", --"); 321 len += 4; 322 if (no) { 323 printf("no-"); 324 len += 3; 325 } 326 printf("%s", decl->long_name); 327 len += strlen(decl->long_name); 328 } 329 330 return len; 331 } 332 333 const void *isl_memrchr(const void *s, int c, size_t n) 334 { 335 const char *p = s; 336 while (n-- > 0) 337 if (p[n] == c) 338 return p + n; 339 return NULL; 340 } 341 342 static int wrap_msg(const char *s, int indent, int pos) 343 { 344 int len; 345 int wrap_len = 75 - indent; 346 347 if (pos + 1 >= indent) 348 printf("\n%*s", indent, ""); 349 else 350 printf("%*s", indent - pos, ""); 351 352 len = strlen(s); 353 while (len > wrap_len) { 354 const char *space = isl_memrchr(s, ' ', wrap_len); 355 int l; 356 357 if (!space) 358 space = strchr(s + wrap_len, ' '); 359 if (!space) 360 break; 361 l = space - s; 362 printf("%.*s", l, s); 363 s = space + 1; 364 len -= l + 1; 365 printf("\n%*s", indent, ""); 366 } 367 368 printf("%s", s); 369 return len; 370 } 371 372 static int print_help_msg(struct isl_arg *decl, int pos) 373 { 374 if (!decl->help_msg) 375 return pos; 376 377 return wrap_msg(decl->help_msg, 30, pos); 378 } 379 380 static void print_default(struct isl_arg *decl, const char *def, int pos) 381 { 382 const char *default_prefix = "[default: "; 383 const char *default_suffix = "]"; 384 int len; 385 386 len = strlen(default_prefix) + strlen(def) + strlen(default_suffix); 387 388 if (!decl->help_msg) { 389 if (pos >= 29) 390 printf("\n%30s", ""); 391 else 392 printf("%*s", 30 - pos, ""); 393 } else { 394 if (pos + len >= 48) 395 printf("\n%30s", ""); 396 else 397 printf(" "); 398 } 399 printf("%s%s%s", default_prefix, def, default_suffix); 400 } 401 402 static void print_default_choice(struct isl_arg *decl, void *opt, int pos) 403 { 404 int i; 405 const char *s = "none"; 406 unsigned *p; 407 408 p = (unsigned *)(((char *) opt) + decl->offset); 409 for (i = 0; decl->u.choice.choice[i].name; ++i) 410 if (decl->u.choice.choice[i].value == *p) { 411 s = decl->u.choice.choice[i].name; 412 break; 413 } 414 415 print_default(decl, s, pos); 416 } 417 418 static void print_choice_help(struct isl_arg *decl, 419 struct isl_prefixes *prefixes, void *opt) 420 { 421 int i; 422 int pos; 423 424 pos = print_arg_help(decl, prefixes, 0); 425 printf("="); 426 pos++; 427 428 for (i = 0; decl->u.choice.choice[i].name; ++i) { 429 if (i) { 430 printf("|"); 431 pos++; 432 } 433 printf("%s", decl->u.choice.choice[i].name); 434 pos += strlen(decl->u.choice.choice[i].name); 435 } 436 437 pos = print_help_msg(decl, pos); 438 print_default_choice(decl, opt, pos); 439 440 printf("\n"); 441 } 442 443 static void print_default_flags(struct isl_arg *decl, void *opt, int pos) 444 { 445 int i, first; 446 const char *default_prefix = "[default: "; 447 const char *default_suffix = "]"; 448 int len = strlen(default_prefix) + strlen(default_suffix); 449 unsigned *p; 450 451 p = (unsigned *)(((char *) opt) + decl->offset); 452 for (i = 0; decl->u.flags.flags[i].name; ++i) 453 if ((*p & decl->u.flags.flags[i].mask) == 454 decl->u.flags.flags[i].value) 455 len += strlen(decl->u.flags.flags[i].name); 456 457 if (!decl->help_msg) { 458 if (pos >= 29) 459 printf("\n%30s", ""); 460 else 461 printf("%*s", 30 - pos, ""); 462 } else { 463 if (pos + len >= 48) 464 printf("\n%30s", ""); 465 else 466 printf(" "); 467 } 468 printf("%s", default_prefix); 469 470 for (first = 1, i = 0; decl->u.flags.flags[i].name; ++i) 471 if ((*p & decl->u.flags.flags[i].mask) == 472 decl->u.flags.flags[i].value) { 473 if (!first) 474 printf(","); 475 printf("%s", decl->u.flags.flags[i].name); 476 first = 0; 477 } 478 479 printf("%s", default_suffix); 480 } 481 482 static void print_flags_help(struct isl_arg *decl, 483 struct isl_prefixes *prefixes, void *opt) 484 { 485 int i, j; 486 int pos; 487 488 pos = print_arg_help(decl, prefixes, 0); 489 printf("="); 490 pos++; 491 492 for (i = 0; decl->u.flags.flags[i].name; ++i) { 493 if (i) { 494 printf(","); 495 pos++; 496 } 497 for (j = i; 498 decl->u.flags.flags[j].mask == decl->u.flags.flags[i].mask; 499 ++j) { 500 if (j != i) { 501 printf("|"); 502 pos++; 503 } 504 printf("%s", decl->u.flags.flags[j].name); 505 pos += strlen(decl->u.flags.flags[j].name); 506 } 507 i = j - 1; 508 } 509 510 pos = print_help_msg(decl, pos); 511 print_default_flags(decl, opt, pos); 512 513 printf("\n"); 514 } 515 516 static void print_bool_help(struct isl_arg *decl, 517 struct isl_prefixes *prefixes, void *opt) 518 { 519 int pos; 520 unsigned *p = opt ? (unsigned *)(((char *) opt) + decl->offset) : NULL; 521 int no = p ? *p == 1 : 0; 522 pos = print_arg_help(decl, prefixes, no); 523 pos = print_help_msg(decl, pos); 524 if (decl->offset != ISL_ARG_OFFSET_NONE) 525 print_default(decl, no ? "yes" : "no", pos); 526 printf("\n"); 527 } 528 529 static int print_argument_name(struct isl_arg *decl, const char *name, int pos) 530 { 531 printf("%c<%s>", decl->long_name ? '=' : ' ', name); 532 return pos + 3 + strlen(name); 533 } 534 535 static void print_int_help(struct isl_arg *decl, 536 struct isl_prefixes *prefixes, void *opt) 537 { 538 int pos; 539 char val[20]; 540 int *p = (int *)(((char *) opt) + decl->offset); 541 pos = print_arg_help(decl, prefixes, 0); 542 pos = print_argument_name(decl, decl->argument_name, pos); 543 pos = print_help_msg(decl, pos); 544 snprintf(val, sizeof(val), "%d", *p); 545 print_default(decl, val, pos); 546 printf("\n"); 547 } 548 549 static void print_long_help(struct isl_arg *decl, 550 struct isl_prefixes *prefixes, void *opt) 551 { 552 int pos; 553 long *p = (long *)(((char *) opt) + decl->offset); 554 pos = print_arg_help(decl, prefixes, 0); 555 if (*p != decl->u.l.default_selected) { 556 printf("["); 557 pos++; 558 } 559 printf("=long"); 560 pos += 5; 561 if (*p != decl->u.l.default_selected) { 562 printf("]"); 563 pos++; 564 } 565 print_help_msg(decl, pos); 566 printf("\n"); 567 } 568 569 static void print_ulong_help(struct isl_arg *decl, 570 struct isl_prefixes *prefixes) 571 { 572 int pos; 573 pos = print_arg_help(decl, prefixes, 0); 574 printf("=ulong"); 575 pos += 6; 576 print_help_msg(decl, pos); 577 printf("\n"); 578 } 579 580 static void print_str_help(struct isl_arg *decl, 581 struct isl_prefixes *prefixes, void *opt) 582 { 583 int pos; 584 const char *a = decl->argument_name ? decl->argument_name : "string"; 585 const char **p = (const char **)(((char *) opt) + decl->offset); 586 pos = print_arg_help(decl, prefixes, 0); 587 pos = print_argument_name(decl, a, pos); 588 pos = print_help_msg(decl, pos); 589 if (*p) 590 print_default(decl, *p, pos); 591 printf("\n"); 592 } 593 594 static void print_str_list_help(struct isl_arg *decl, 595 struct isl_prefixes *prefixes) 596 { 597 int pos; 598 const char *a = decl->argument_name ? decl->argument_name : "string"; 599 pos = print_arg_help(decl, prefixes, 0); 600 pos = print_argument_name(decl, a, pos); 601 pos = print_help_msg(decl, pos); 602 printf("\n"); 603 } 604 605 static void print_help(struct isl_arg *arg, 606 struct isl_prefixes *prefixes, void *opt) 607 { 608 int i; 609 int any = 0; 610 611 for (i = 0; arg[i].type != isl_arg_end; ++i) { 612 if (arg[i].flags & ISL_ARG_HIDDEN) 613 continue; 614 switch (arg[i].type) { 615 case isl_arg_flags: 616 print_flags_help(&arg[i], prefixes, opt); 617 any = 1; 618 break; 619 case isl_arg_choice: 620 print_choice_help(&arg[i], prefixes, opt); 621 any = 1; 622 break; 623 case isl_arg_bool: 624 print_bool_help(&arg[i], prefixes, opt); 625 any = 1; 626 break; 627 case isl_arg_int: 628 print_int_help(&arg[i], prefixes, opt); 629 any = 1; 630 break; 631 case isl_arg_long: 632 print_long_help(&arg[i], prefixes, opt); 633 any = 1; 634 break; 635 case isl_arg_ulong: 636 print_ulong_help(&arg[i], prefixes); 637 any = 1; 638 break; 639 case isl_arg_str: 640 print_str_help(&arg[i], prefixes, opt); 641 any = 1; 642 break; 643 case isl_arg_str_list: 644 print_str_list_help(&arg[i], prefixes); 645 any = 1; 646 break; 647 case isl_arg_alias: 648 case isl_arg_version: 649 case isl_arg_arg: 650 case isl_arg_footer: 651 case isl_arg_child: 652 case isl_arg_user: 653 case isl_arg_end: 654 break; 655 } 656 } 657 658 for (i = 0; arg[i].type != isl_arg_end; ++i) { 659 void *child; 660 int first; 661 662 if (arg[i].type != isl_arg_child) 663 continue; 664 if (arg[i].flags & ISL_ARG_HIDDEN) 665 continue; 666 667 if (any) 668 printf("\n"); 669 if (arg[i].help_msg) 670 printf(" %s\n", arg[i].help_msg); 671 if (arg[i].offset == ISL_ARG_OFFSET_NONE) 672 child = opt; 673 else 674 child = *(void **)(((char *) opt) + arg[i].offset); 675 first = add_prefix(prefixes, arg[i].long_name); 676 print_help(arg[i].u.child.child->args, prefixes, child); 677 drop_prefix(prefixes, first); 678 any = 1; 679 } 680 } 681 682 static const char *prog_name(const char *prog) 683 { 684 const char *slash; 685 686 slash = strrchr(prog, '/'); 687 if (slash) 688 prog = slash + 1; 689 if (strncmp(prog, "lt-", 3) == 0) 690 prog += 3; 691 692 return prog; 693 } 694 695 static int any_version(struct isl_arg *decl) 696 { 697 int i; 698 699 for (i = 0; decl[i].type != isl_arg_end; ++i) { 700 switch (decl[i].type) { 701 case isl_arg_version: 702 return 1; 703 case isl_arg_child: 704 if (any_version(decl[i].u.child.child->args)) 705 return 1; 706 break; 707 default: 708 break; 709 } 710 } 711 712 return 0; 713 } 714 715 static void print_help_and_exit(struct isl_arg *arg, const char *prog, 716 void *opt) 717 { 718 int i; 719 struct isl_prefixes prefixes = { 0 }; 720 721 printf("Usage: %s [OPTION...]", prog_name(prog)); 722 723 for (i = 0; arg[i].type != isl_arg_end; ++i) 724 if (arg[i].type == isl_arg_arg) 725 printf(" %s", arg[i].argument_name); 726 727 printf("\n\n"); 728 729 print_help(arg, &prefixes, opt); 730 printf("\n"); 731 if (any_version(arg)) 732 printf(" -V, --version\n"); 733 print_bool_help(help_arg, NULL, NULL); 734 735 for (i = 0; arg[i].type != isl_arg_end; ++i) { 736 if (arg[i].type != isl_arg_footer) 737 continue; 738 wrap_msg(arg[i].help_msg, 0, 0); 739 printf("\n"); 740 } 741 742 exit(0); 743 } 744 745 static int match_long_name(struct isl_arg *decl, 746 const char *start, const char *end) 747 { 748 do { 749 if (end - start == strlen(decl->long_name) && 750 !strncmp(start, decl->long_name, end - start)) 751 return 1; 752 } while ((++decl)->type == isl_arg_alias); 753 754 return 0; 755 } 756 757 static const char *skip_dash_dash(struct isl_arg *decl, const char *arg) 758 { 759 if (!strncmp(arg, "--", 2)) 760 return arg + 2; 761 if ((decl->flags & ISL_ARG_SINGLE_DASH) && arg[0] == '-') 762 return arg + 1; 763 return NULL; 764 } 765 766 static const char *skip_name(struct isl_arg *decl, const char *arg, 767 struct isl_prefixes *prefixes, int need_argument, int *has_argument) 768 { 769 const char *equal; 770 const char *name; 771 const char *end; 772 773 if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) { 774 if (need_argument && !arg[2]) 775 return NULL; 776 if (has_argument) 777 *has_argument = arg[2] != '\0'; 778 return arg + 2; 779 } 780 if (!decl->long_name) 781 return NULL; 782 783 name = skip_dash_dash(decl, arg); 784 if (!name) 785 return NULL; 786 787 equal = strchr(name, '='); 788 if (need_argument && !equal) 789 return NULL; 790 791 if (has_argument) 792 *has_argument = !!equal; 793 end = equal ? equal : name + strlen(name); 794 795 name = skip_prefixes(name, prefixes, NULL); 796 797 if (!match_long_name(decl, name, end)) 798 return NULL; 799 800 return equal ? equal + 1 : end; 801 } 802 803 static int parse_choice_option(struct isl_arg *decl, char **arg, 804 struct isl_prefixes *prefixes, void *opt) 805 { 806 int i; 807 int has_argument; 808 const char *choice; 809 810 choice = skip_name(decl, arg[0], prefixes, 0, &has_argument); 811 if (!choice) 812 return 0; 813 814 if (!has_argument && (!arg[1] || arg[1][0] == '-')) { 815 unsigned u = decl->u.choice.default_selected; 816 if (decl->offset != ISL_ARG_OFFSET_NONE) 817 *(unsigned *)(((char *)opt) + decl->offset) = u; 818 if (decl->u.choice.set) 819 decl->u.choice.set(opt, u); 820 821 return 1; 822 } 823 824 if (!has_argument) 825 choice = arg[1]; 826 827 for (i = 0; decl->u.choice.choice[i].name; ++i) { 828 unsigned u; 829 830 if (strcmp(choice, decl->u.choice.choice[i].name)) 831 continue; 832 833 u = decl->u.choice.choice[i].value; 834 if (decl->offset != ISL_ARG_OFFSET_NONE) 835 *(unsigned *)(((char *)opt) + decl->offset) = u; 836 if (decl->u.choice.set) 837 decl->u.choice.set(opt, u); 838 839 return has_argument ? 1 : 2; 840 } 841 842 return 0; 843 } 844 845 static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag, 846 size_t len) 847 { 848 int i; 849 850 for (i = 0; decl->u.flags.flags[i].name; ++i) { 851 if (strncmp(flag, decl->u.flags.flags[i].name, len)) 852 continue; 853 854 *val &= ~decl->u.flags.flags[i].mask; 855 *val |= decl->u.flags.flags[i].value; 856 857 return 1; 858 } 859 860 return 0; 861 } 862 863 static int parse_flags_option(struct isl_arg *decl, char **arg, 864 struct isl_prefixes *prefixes, void *opt) 865 { 866 int has_argument; 867 const char *flags; 868 const char *comma; 869 unsigned val; 870 871 flags = skip_name(decl, arg[0], prefixes, 0, &has_argument); 872 if (!flags) 873 return 0; 874 875 if (!has_argument && !arg[1]) 876 return 0; 877 878 if (!has_argument) 879 flags = arg[1]; 880 881 val = 0; 882 883 while ((comma = strchr(flags, ',')) != NULL) { 884 if (!set_flag(decl, &val, flags, comma - flags)) 885 return 0; 886 flags = comma + 1; 887 } 888 if (!set_flag(decl, &val, flags, strlen(flags))) 889 return 0; 890 891 *(unsigned *)(((char *)opt) + decl->offset) = val; 892 893 return has_argument ? 1 : 2; 894 } 895 896 static int parse_bool_option(struct isl_arg *decl, char **arg, 897 struct isl_prefixes *prefixes, void *opt) 898 { 899 const char *name; 900 unsigned *p = (unsigned *)(((char *)opt) + decl->offset); 901 int next_prefix; 902 903 if (skip_name(decl, arg[0], prefixes, 0, NULL)) { 904 if ((decl->flags & ISL_ARG_BOOL_ARG) && arg[1]) { 905 char *endptr; 906 int val = strtol(arg[1], &endptr, 0); 907 if (*endptr == '\0' && (val == 0 || val == 1)) { 908 if (decl->offset != ISL_ARG_OFFSET_NONE) 909 *p = val; 910 if (decl->u.b.set) 911 decl->u.b.set(opt, val); 912 return 2; 913 } 914 } 915 if (decl->offset != ISL_ARG_OFFSET_NONE) 916 *p = 1; 917 if (decl->u.b.set) 918 decl->u.b.set(opt, 1); 919 920 return 1; 921 } 922 923 if (!decl->long_name) 924 return 0; 925 926 name = skip_dash_dash(decl, arg[0]); 927 if (!name) 928 return 0; 929 930 next_prefix = 0; 931 name = skip_prefixes(name, prefixes, &next_prefix); 932 933 if (strncmp(name, "no-", 3)) 934 return 0; 935 name += 3; 936 937 name = skip_prefixes(name, prefixes, &next_prefix); 938 939 if (match_long_name(decl, name, name + strlen(name))) { 940 if (decl->offset != ISL_ARG_OFFSET_NONE) 941 *p = 0; 942 if (decl->u.b.set) 943 decl->u.b.set(opt, 0); 944 945 return 1; 946 } 947 948 return 0; 949 } 950 951 static int parse_str_option(struct isl_arg *decl, char **arg, 952 struct isl_prefixes *prefixes, void *opt) 953 { 954 int has_argument; 955 const char *s; 956 char **p = (char **)(((char *)opt) + decl->offset); 957 958 s = skip_name(decl, arg[0], prefixes, 0, &has_argument); 959 if (!s) 960 return 0; 961 962 if (has_argument) { 963 free(*p); 964 *p = strdup(s); 965 return 1; 966 } 967 968 if (arg[1]) { 969 free(*p); 970 *p = strdup(arg[1]); 971 return 2; 972 } 973 974 return 0; 975 } 976 977 static int isl_arg_str_list_append(struct isl_arg *decl, void *opt, 978 const char *s) 979 { 980 int *n = (int *)(((char *) opt) + decl->u.str_list.offset_n); 981 char **list = *(char ***)(((char *) opt) + decl->offset); 982 983 list = realloc(list, (*n + 1) * sizeof(char *)); 984 if (!list) 985 return -1; 986 *(char ***)(((char *) opt) + decl->offset) = list; 987 list[*n] = strdup(s); 988 (*n)++; 989 return 0; 990 } 991 992 static int parse_str_list_option(struct isl_arg *decl, char **arg, 993 struct isl_prefixes *prefixes, void *opt) 994 { 995 int has_argument; 996 const char *s; 997 998 s = skip_name(decl, arg[0], prefixes, 0, &has_argument); 999 if (!s) 1000 return 0; 1001 1002 if (has_argument) { 1003 isl_arg_str_list_append(decl, opt, s); 1004 return 1; 1005 } 1006 1007 if (arg[1]) { 1008 isl_arg_str_list_append(decl, opt, arg[1]); 1009 return 2; 1010 } 1011 1012 return 0; 1013 } 1014 1015 static int parse_int_option(struct isl_arg *decl, char **arg, 1016 struct isl_prefixes *prefixes, void *opt) 1017 { 1018 int has_argument; 1019 const char *val; 1020 char *endptr; 1021 int *p = (int *)(((char *)opt) + decl->offset); 1022 1023 val = skip_name(decl, arg[0], prefixes, 0, &has_argument); 1024 if (!val) 1025 return 0; 1026 1027 if (has_argument) { 1028 *p = atoi(val); 1029 return 1; 1030 } 1031 1032 if (arg[1]) { 1033 int i = strtol(arg[1], &endptr, 0); 1034 if (*endptr == '\0') { 1035 *p = i; 1036 return 2; 1037 } 1038 } 1039 1040 return 0; 1041 } 1042 1043 static int parse_long_option(struct isl_arg *decl, char **arg, 1044 struct isl_prefixes *prefixes, void *opt) 1045 { 1046 int has_argument; 1047 const char *val; 1048 char *endptr; 1049 long *p = (long *)(((char *)opt) + decl->offset); 1050 1051 val = skip_name(decl, arg[0], prefixes, 0, &has_argument); 1052 if (!val) 1053 return 0; 1054 1055 if (has_argument) { 1056 long l = strtol(val, NULL, 0); 1057 *p = l; 1058 if (decl->u.l.set) 1059 decl->u.l.set(opt, l); 1060 return 1; 1061 } 1062 1063 if (arg[1]) { 1064 long l = strtol(arg[1], &endptr, 0); 1065 if (*endptr == '\0') { 1066 *p = l; 1067 if (decl->u.l.set) 1068 decl->u.l.set(opt, l); 1069 return 2; 1070 } 1071 } 1072 1073 if (decl->u.l.default_value != decl->u.l.default_selected) { 1074 *p = decl->u.l.default_selected; 1075 if (decl->u.l.set) 1076 decl->u.l.set(opt, decl->u.l.default_selected); 1077 return 1; 1078 } 1079 1080 return 0; 1081 } 1082 1083 static int parse_ulong_option(struct isl_arg *decl, char **arg, 1084 struct isl_prefixes *prefixes, void *opt) 1085 { 1086 int has_argument; 1087 const char *val; 1088 char *endptr; 1089 unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset); 1090 1091 val = skip_name(decl, arg[0], prefixes, 0, &has_argument); 1092 if (!val) 1093 return 0; 1094 1095 if (has_argument) { 1096 *p = strtoul(val, NULL, 0); 1097 return 1; 1098 } 1099 1100 if (arg[1]) { 1101 unsigned long ul = strtoul(arg[1], &endptr, 0); 1102 if (*endptr == '\0') { 1103 *p = ul; 1104 return 2; 1105 } 1106 } 1107 1108 return 0; 1109 } 1110 1111 static int parse_option(struct isl_arg *decl, char **arg, 1112 struct isl_prefixes *prefixes, void *opt); 1113 1114 static int parse_child_option(struct isl_arg *decl, char **arg, 1115 struct isl_prefixes *prefixes, void *opt) 1116 { 1117 void *child; 1118 int first, parsed; 1119 1120 if (decl->offset == ISL_ARG_OFFSET_NONE) 1121 child = opt; 1122 else 1123 child = *(void **)(((char *)opt) + decl->offset); 1124 1125 first = add_prefix(prefixes, decl->long_name); 1126 parsed = parse_option(decl->u.child.child->args, arg, prefixes, child); 1127 drop_prefix(prefixes, first); 1128 1129 return parsed; 1130 } 1131 1132 static int parse_option(struct isl_arg *decl, char **arg, 1133 struct isl_prefixes *prefixes, void *opt) 1134 { 1135 int i; 1136 1137 for (i = 0; decl[i].type != isl_arg_end; ++i) { 1138 int parsed = 0; 1139 switch (decl[i].type) { 1140 case isl_arg_choice: 1141 parsed = parse_choice_option(&decl[i], arg, 1142 prefixes, opt); 1143 break; 1144 case isl_arg_flags: 1145 parsed = parse_flags_option(&decl[i], arg, 1146 prefixes, opt); 1147 break; 1148 case isl_arg_int: 1149 parsed = parse_int_option(&decl[i], arg, prefixes, opt); 1150 break; 1151 case isl_arg_long: 1152 parsed = parse_long_option(&decl[i], arg, 1153 prefixes, opt); 1154 break; 1155 case isl_arg_ulong: 1156 parsed = parse_ulong_option(&decl[i], arg, 1157 prefixes, opt); 1158 break; 1159 case isl_arg_bool: 1160 parsed = parse_bool_option(&decl[i], arg, 1161 prefixes, opt); 1162 break; 1163 case isl_arg_str: 1164 parsed = parse_str_option(&decl[i], arg, prefixes, opt); 1165 break; 1166 case isl_arg_str_list: 1167 parsed = parse_str_list_option(&decl[i], arg, prefixes, 1168 opt); 1169 break; 1170 case isl_arg_child: 1171 parsed = parse_child_option(&decl[i], arg, 1172 prefixes, opt); 1173 break; 1174 case isl_arg_alias: 1175 case isl_arg_arg: 1176 case isl_arg_footer: 1177 case isl_arg_user: 1178 case isl_arg_version: 1179 case isl_arg_end: 1180 break; 1181 } 1182 if (parsed) 1183 return parsed; 1184 } 1185 1186 return 0; 1187 } 1188 1189 static void print_version(struct isl_arg *decl) 1190 { 1191 int i; 1192 1193 for (i = 0; decl[i].type != isl_arg_end; ++i) { 1194 switch (decl[i].type) { 1195 case isl_arg_version: 1196 decl[i].u.version.print_version(); 1197 break; 1198 case isl_arg_child: 1199 print_version(decl[i].u.child.child->args); 1200 break; 1201 default: 1202 break; 1203 } 1204 } 1205 } 1206 1207 static void print_version_and_exit(struct isl_arg *decl) 1208 { 1209 print_version(decl); 1210 1211 exit(0); 1212 } 1213 1214 static int drop_argument(int argc, char **argv, int drop, int n) 1215 { 1216 for (; drop + n < argc; ++drop) 1217 argv[drop] = argv[drop + n]; 1218 1219 return argc - n; 1220 } 1221 1222 static int n_arg(struct isl_arg *arg) 1223 { 1224 int i; 1225 int n_arg = 0; 1226 1227 for (i = 0; arg[i].type != isl_arg_end; ++i) 1228 if (arg[i].type == isl_arg_arg) 1229 n_arg++; 1230 1231 return n_arg; 1232 } 1233 1234 static int next_arg(struct isl_arg *arg, int a) 1235 { 1236 for (++a; arg[a].type != isl_arg_end; ++a) 1237 if (arg[a].type == isl_arg_arg) 1238 return a; 1239 1240 return -1; 1241 } 1242 1243 /* Unless ISL_ARG_SKIP_HELP is set, check if "arg" is 1244 * equal to "--help" or "-h" and if so call print_help_and_exit. 1245 */ 1246 static void check_help(struct isl_args *args, char *arg, char *prog, void *opt, 1247 unsigned flags) 1248 { 1249 if (ISL_FL_ISSET(flags, ISL_ARG_SKIP_HELP)) 1250 return; 1251 1252 if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) 1253 print_help_and_exit(args->args, prog, opt); 1254 } 1255 1256 int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt, 1257 unsigned flags) 1258 { 1259 int a = -1; 1260 int skip = 0; 1261 int i; 1262 int n; 1263 struct isl_prefixes prefixes = { 0 }; 1264 1265 n = n_arg(args->args); 1266 1267 for (i = 1; i < argc; ++i) { 1268 if ((strcmp(argv[i], "--version") == 0 || 1269 strcmp(argv[i], "-V") == 0) && any_version(args->args)) 1270 print_version_and_exit(args->args); 1271 } 1272 1273 while (argc > 1 + skip) { 1274 int parsed; 1275 if (argv[1 + skip][0] != '-') { 1276 a = next_arg(args->args, a); 1277 if (a >= 0) { 1278 char **p; 1279 p = (char **)(((char *)opt)+args->args[a].offset); 1280 free(*p); 1281 *p = strdup(argv[1 + skip]); 1282 argc = drop_argument(argc, argv, 1 + skip, 1); 1283 --n; 1284 } else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) { 1285 fprintf(stderr, "%s: extra argument: %s\n", 1286 prog_name(argv[0]), argv[1 + skip]); 1287 exit(-1); 1288 } else 1289 ++skip; 1290 continue; 1291 } 1292 check_help(args, argv[1 + skip], argv[0], opt, flags); 1293 parsed = parse_option(args->args, &argv[1 + skip], 1294 &prefixes, opt); 1295 if (parsed) 1296 argc = drop_argument(argc, argv, 1 + skip, parsed); 1297 else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) { 1298 fprintf(stderr, "%s: unrecognized option: %s\n", 1299 prog_name(argv[0]), argv[1 + skip]); 1300 exit(-1); 1301 } else 1302 ++skip; 1303 } 1304 1305 if (n > 0) { 1306 fprintf(stderr, "%s: expecting %d more argument(s)\n", 1307 prog_name(argv[0]), n); 1308 exit(-1); 1309 } 1310 1311 return argc; 1312 } 1313