1313 lines · c
1/*2 * Copyright 2008-2009 Katholieke Universiteit Leuven3 *4 * Use of this software is governed by the MIT license5 *6 * Written by Sven Verdoolaege, K.U.Leuven, Departement7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium8 */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 18static struct isl_arg help_arg[] = {19ISL_ARG_PHANTOM_BOOL('h', "help", NULL, "print this help, then exit")20{ isl_arg_end }21};22 23static 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 30static void set_default_flags(struct isl_arg *arg, void *opt)31{32 *(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value;33}34 35static 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 42static 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 57static void set_default_user(struct isl_arg *arg, void *opt)58{59 arg->u.user.init(((char *)opt) + arg->offset);60}61 62static void set_default_int(struct isl_arg *arg, void *opt)63{64 *(int *)(((char *)opt) + arg->offset) = arg->u.i.default_value;65}66 67static void set_default_long(struct isl_arg *arg, void *opt)68{69 *(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value;70}71 72static 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 77static 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 85static 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 91void 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 137static void free_args(struct isl_arg *arg, void *opt);138 139static 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 else144 isl_args_free(arg->u.child.child,145 *(void **)(((char *)opt) + arg->offset));146}147 148static 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 159static 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 165static 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 199void 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 */215struct 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 updated222 * number of prefixes.223 */224static 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 */244static void drop_prefix(struct isl_prefixes *prefixes, int first)245{246 prefixes->n = first;247}248 249/* Print the prefixes in "prefixes".250 */251static 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 prefixes269 * and return the updated pointer. Additionally, update *first to270 * the index after the last prefix found.271 */272static 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 290static 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 333const 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 342static 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 else350 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 372static 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 380static 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 else392 printf("%*s", 30 - pos, "");393 } else {394 if (pos + len >= 48)395 printf("\n%30s", "");396 else397 printf(" ");398 }399 printf("%s%s%s", default_prefix, def, default_suffix);400}401 402static 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 418static 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 443static 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 else461 printf("%*s", 30 - pos, "");462 } else {463 if (pos + len >= 48)464 printf("\n%30s", "");465 else466 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 482static 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 516static 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 529static 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 535static 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 549static 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 569static 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 580static 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 594static 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 605static 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 else674 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 682static 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 695static 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 715static 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 745static 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 757static 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 766static 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 803static 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 845static 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 863static 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 896static 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 951static 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 977static 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 992static 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 1015static 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 1043static 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 1083static 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 1111static int parse_option(struct isl_arg *decl, char **arg,1112 struct isl_prefixes *prefixes, void *opt);1113 1114static 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 else1123 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 1132static 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 1189static 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 1207static void print_version_and_exit(struct isl_arg *decl)1208{1209 print_version(decl);1210 1211 exit(0);1212}1213 1214static 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 1222static 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 1234static 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" is1244 * equal to "--help" or "-h" and if so call print_help_and_exit.1245 */1246static 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 1256int 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 } else1289 ++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 } else1302 ++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