diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-10-25 04:40:31 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-10-25 04:40:31 -0400 |
commit | 4341801873e23bbecee76dabb7c111e3693b900f (patch) | |
tree | 473e96f38af8c9e5a6bfd99ef20c021584168343 /tools/perf/util/parse-options.c | |
parent | 80fcd45ee05b4ef05e61d37a5ffb70a67095a9f6 (diff) | |
parent | 161d9041782b86c5493481566539bfc058ceeaff (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements from Arnaldo Carvalho de Melo:
New user-visible features:
- Show ordered command line options when -h is used or when an
unknown option is specified. (Arnaldo Carvalho de Melo)
- If options are passed after -h, show just its descriptions, not
all options. (Arnaldo Carvalho de Melo)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util/parse-options.c')
-rw-r--r-- | tools/perf/util/parse-options.c | 90 |
1 files changed, 81 insertions, 9 deletions
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 8aa7922397a9..22c2806bda98 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "parse-options.h" | 2 | #include "parse-options.h" |
3 | #include "cache.h" | 3 | #include "cache.h" |
4 | #include "header.h" | 4 | #include "header.h" |
5 | #include <linux/string.h> | ||
5 | 6 | ||
6 | #define OPT_SHORT 1 | 7 | #define OPT_SHORT 1 |
7 | #define OPT_UNSET 2 | 8 | #define OPT_UNSET 2 |
@@ -372,7 +373,8 @@ void parse_options_start(struct parse_opt_ctx_t *ctx, | |||
372 | } | 373 | } |
373 | 374 | ||
374 | static int usage_with_options_internal(const char * const *, | 375 | static int usage_with_options_internal(const char * const *, |
375 | const struct option *, int); | 376 | const struct option *, int, |
377 | struct parse_opt_ctx_t *); | ||
376 | 378 | ||
377 | int parse_options_step(struct parse_opt_ctx_t *ctx, | 379 | int parse_options_step(struct parse_opt_ctx_t *ctx, |
378 | const struct option *options, | 380 | const struct option *options, |
@@ -396,8 +398,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
396 | 398 | ||
397 | if (arg[1] != '-') { | 399 | if (arg[1] != '-') { |
398 | ctx->opt = ++arg; | 400 | ctx->opt = ++arg; |
399 | if (internal_help && *ctx->opt == 'h') | 401 | if (internal_help && *ctx->opt == 'h') { |
400 | return usage_with_options_internal(usagestr, options, 0); | 402 | return usage_with_options_internal(usagestr, options, 0, ctx); |
403 | } | ||
401 | switch (parse_short_opt(ctx, options)) { | 404 | switch (parse_short_opt(ctx, options)) { |
402 | case -1: | 405 | case -1: |
403 | return parse_options_usage(usagestr, options, arg, 1); | 406 | return parse_options_usage(usagestr, options, arg, 1); |
@@ -412,7 +415,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
412 | check_typos(arg, options); | 415 | check_typos(arg, options); |
413 | while (ctx->opt) { | 416 | while (ctx->opt) { |
414 | if (internal_help && *ctx->opt == 'h') | 417 | if (internal_help && *ctx->opt == 'h') |
415 | return usage_with_options_internal(usagestr, options, 0); | 418 | return usage_with_options_internal(usagestr, options, 0, ctx); |
416 | arg = ctx->opt; | 419 | arg = ctx->opt; |
417 | switch (parse_short_opt(ctx, options)) { | 420 | switch (parse_short_opt(ctx, options)) { |
418 | case -1: | 421 | case -1: |
@@ -445,9 +448,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
445 | 448 | ||
446 | arg += 2; | 449 | arg += 2; |
447 | if (internal_help && !strcmp(arg, "help-all")) | 450 | if (internal_help && !strcmp(arg, "help-all")) |
448 | return usage_with_options_internal(usagestr, options, 1); | 451 | return usage_with_options_internal(usagestr, options, 1, ctx); |
449 | if (internal_help && !strcmp(arg, "help")) | 452 | if (internal_help && !strcmp(arg, "help")) |
450 | return usage_with_options_internal(usagestr, options, 0); | 453 | return usage_with_options_internal(usagestr, options, 0, ctx); |
451 | if (!strcmp(arg, "list-opts")) | 454 | if (!strcmp(arg, "list-opts")) |
452 | return PARSE_OPT_LIST_OPTS; | 455 | return PARSE_OPT_LIST_OPTS; |
453 | if (!strcmp(arg, "list-cmds")) | 456 | if (!strcmp(arg, "list-cmds")) |
@@ -642,9 +645,69 @@ static void print_option_help(const struct option *opts, int full) | |||
642 | fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); | 645 | fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); |
643 | } | 646 | } |
644 | 647 | ||
648 | static int option__cmp(const void *va, const void *vb) | ||
649 | { | ||
650 | const struct option *a = va, *b = vb; | ||
651 | int sa = tolower(a->short_name), sb = tolower(b->short_name), ret; | ||
652 | |||
653 | if (sa == 0) | ||
654 | sa = 'z' + 1; | ||
655 | if (sb == 0) | ||
656 | sb = 'z' + 1; | ||
657 | |||
658 | ret = sa - sb; | ||
659 | |||
660 | if (ret == 0) { | ||
661 | const char *la = a->long_name ?: "", | ||
662 | *lb = b->long_name ?: ""; | ||
663 | ret = strcmp(la, lb); | ||
664 | } | ||
665 | |||
666 | return ret; | ||
667 | } | ||
668 | |||
669 | static struct option *options__order(const struct option *opts) | ||
670 | { | ||
671 | int nr_opts = 0; | ||
672 | const struct option *o = opts; | ||
673 | struct option *ordered; | ||
674 | |||
675 | for (o = opts; o->type != OPTION_END; o++) | ||
676 | ++nr_opts; | ||
677 | |||
678 | ordered = memdup(opts, sizeof(*o) * (nr_opts + 1)); | ||
679 | if (ordered == NULL) | ||
680 | goto out; | ||
681 | |||
682 | qsort(ordered, nr_opts, sizeof(*o), option__cmp); | ||
683 | out: | ||
684 | return ordered; | ||
685 | } | ||
686 | |||
687 | static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx) | ||
688 | { | ||
689 | int i; | ||
690 | |||
691 | for (i = 1; i < ctx->argc; ++i) { | ||
692 | const char *arg = ctx->argv[i]; | ||
693 | |||
694 | if (arg[0] != '-') | ||
695 | continue; | ||
696 | |||
697 | if (arg[1] == opt->short_name || | ||
698 | (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0)) | ||
699 | return true; | ||
700 | } | ||
701 | |||
702 | return false; | ||
703 | } | ||
704 | |||
645 | int usage_with_options_internal(const char * const *usagestr, | 705 | int usage_with_options_internal(const char * const *usagestr, |
646 | const struct option *opts, int full) | 706 | const struct option *opts, int full, |
707 | struct parse_opt_ctx_t *ctx) | ||
647 | { | 708 | { |
709 | struct option *ordered; | ||
710 | |||
648 | if (!usagestr) | 711 | if (!usagestr) |
649 | return PARSE_OPT_HELP; | 712 | return PARSE_OPT_HELP; |
650 | 713 | ||
@@ -661,11 +724,20 @@ int usage_with_options_internal(const char * const *usagestr, | |||
661 | if (opts->type != OPTION_GROUP) | 724 | if (opts->type != OPTION_GROUP) |
662 | fputc('\n', stderr); | 725 | fputc('\n', stderr); |
663 | 726 | ||
664 | for ( ; opts->type != OPTION_END; opts++) | 727 | ordered = options__order(opts); |
728 | if (ordered) | ||
729 | opts = ordered; | ||
730 | |||
731 | for ( ; opts->type != OPTION_END; opts++) { | ||
732 | if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx)) | ||
733 | continue; | ||
665 | print_option_help(opts, full); | 734 | print_option_help(opts, full); |
735 | } | ||
666 | 736 | ||
667 | fputc('\n', stderr); | 737 | fputc('\n', stderr); |
668 | 738 | ||
739 | free(ordered); | ||
740 | |||
669 | return PARSE_OPT_HELP; | 741 | return PARSE_OPT_HELP; |
670 | } | 742 | } |
671 | 743 | ||
@@ -673,7 +745,7 @@ void usage_with_options(const char * const *usagestr, | |||
673 | const struct option *opts) | 745 | const struct option *opts) |
674 | { | 746 | { |
675 | exit_browser(false); | 747 | exit_browser(false); |
676 | usage_with_options_internal(usagestr, opts, 0); | 748 | usage_with_options_internal(usagestr, opts, 0, NULL); |
677 | exit(129); | 749 | exit(129); |
678 | } | 750 | } |
679 | 751 | ||