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