perf tools: Show single option when failed to parse
authorNamhyung Kim <namhyung.kim@lge.com>
Fri, 1 Nov 2013 07:33:11 +0000 (16:33 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 4 Nov 2013 15:51:45 +0000 (12:51 -0300)
Current option parser outputs whole option help string when it failed to
parse an option.  However this is not good for user if the command has
many option, she might feel hard which one is related easily.

Fix it by just showing the help message of the given option only.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Requested-by: Ingo Molnar <mingo@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Ingo Molnar <mingo@kernel.org>
Enthusiastically-Supported-by: Ingo Molnar <mingo@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1383291195-24386-2-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/parse-options.c
tools/perf/util/parse-options.h

index 2bc9e70df7e2552ecc14857d1f26c2311bb2fde7..1caf7b9a01ee18192260ea15ae52ac58951da0d0 100644 (file)
@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                if (arg[1] != '-') {
                        ctx->opt = arg + 1;
                        if (internal_help && *ctx->opt == 'h')
-                               return parse_options_usage(usagestr, options);
+                               return usage_with_options_internal(usagestr, options, 0);
                        switch (parse_short_opt(ctx, options)) {
                        case -1:
-                               return parse_options_usage(usagestr, options);
+                               return parse_options_usage(usagestr, options, arg + 1, 1);
                        case -2:
                                goto unknown;
                        default:
@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                                check_typos(arg + 1, options);
                        while (ctx->opt) {
                                if (internal_help && *ctx->opt == 'h')
-                                       return parse_options_usage(usagestr, options);
+                                       return usage_with_options_internal(usagestr, options, 0);
+                               arg = ctx->opt;
                                switch (parse_short_opt(ctx, options)) {
                                case -1:
-                                       return parse_options_usage(usagestr, options);
+                                       return parse_options_usage(usagestr, options, arg, 1);
                                case -2:
                                        /* fake a short option thing to hide the fact that we may have
                                         * started to parse aggregated stuff
@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                if (internal_help && !strcmp(arg + 2, "help-all"))
                        return usage_with_options_internal(usagestr, options, 1);
                if (internal_help && !strcmp(arg + 2, "help"))
-                       return parse_options_usage(usagestr, options);
+                       return usage_with_options_internal(usagestr, options, 0);
                if (!strcmp(arg + 2, "list-opts"))
                        return PARSE_OPT_LIST;
                switch (parse_long_opt(ctx, arg + 2, options)) {
                case -1:
-                       return parse_options_usage(usagestr, options);
+                       return parse_options_usage(usagestr, options, arg + 2, 0);
                case -2:
                        goto unknown;
                default:
@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options,
 #define USAGE_OPTS_WIDTH 24
 #define USAGE_GAP         2
 
+static void print_option_help(const struct option *opts, int full)
+{
+       size_t pos;
+       int pad;
+
+       if (opts->type == OPTION_GROUP) {
+               fputc('\n', stderr);
+               if (*opts->help)
+                       fprintf(stderr, "%s\n", opts->help);
+               return;
+       }
+       if (!full && (opts->flags & PARSE_OPT_HIDDEN))
+               return;
+
+       pos = fprintf(stderr, "    ");
+       if (opts->short_name)
+               pos += fprintf(stderr, "-%c", opts->short_name);
+       else
+               pos += fprintf(stderr, "    ");
+
+       if (opts->long_name && opts->short_name)
+               pos += fprintf(stderr, ", ");
+       if (opts->long_name)
+               pos += fprintf(stderr, "--%s", opts->long_name);
+
+       switch (opts->type) {
+       case OPTION_ARGUMENT:
+               break;
+       case OPTION_LONG:
+       case OPTION_U64:
+       case OPTION_INTEGER:
+       case OPTION_UINTEGER:
+               if (opts->flags & PARSE_OPT_OPTARG)
+                       if (opts->long_name)
+                               pos += fprintf(stderr, "[=<n>]");
+                       else
+                               pos += fprintf(stderr, "[<n>]");
+               else
+                       pos += fprintf(stderr, " <n>");
+               break;
+       case OPTION_CALLBACK:
+               if (opts->flags & PARSE_OPT_NOARG)
+                       break;
+               /* FALLTHROUGH */
+       case OPTION_STRING:
+               if (opts->argh) {
+                       if (opts->flags & PARSE_OPT_OPTARG)
+                               if (opts->long_name)
+                                       pos += fprintf(stderr, "[=<%s>]", opts->argh);
+                               else
+                                       pos += fprintf(stderr, "[<%s>]", opts->argh);
+                       else
+                               pos += fprintf(stderr, " <%s>", opts->argh);
+               } else {
+                       if (opts->flags & PARSE_OPT_OPTARG)
+                               if (opts->long_name)
+                                       pos += fprintf(stderr, "[=...]");
+                               else
+                                       pos += fprintf(stderr, "[...]");
+                       else
+                               pos += fprintf(stderr, " ...");
+               }
+               break;
+       default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
+       case OPTION_END:
+       case OPTION_GROUP:
+       case OPTION_BIT:
+       case OPTION_BOOLEAN:
+       case OPTION_INCR:
+       case OPTION_SET_UINT:
+       case OPTION_SET_PTR:
+               break;
+       }
+
+       if (pos <= USAGE_OPTS_WIDTH)
+               pad = USAGE_OPTS_WIDTH - pos;
+       else {
+               fputc('\n', stderr);
+               pad = USAGE_OPTS_WIDTH;
+       }
+       fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+}
+
 int usage_with_options_internal(const char * const *usagestr,
                                const struct option *opts, int full)
 {
@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr,
        if (opts->type != OPTION_GROUP)
                fputc('\n', stderr);
 
-       for (; opts->type != OPTION_END; opts++) {
-               size_t pos;
-               int pad;
-
-               if (opts->type == OPTION_GROUP) {
-                       fputc('\n', stderr);
-                       if (*opts->help)
-                               fprintf(stderr, "%s\n", opts->help);
-                       continue;
-               }
-               if (!full && (opts->flags & PARSE_OPT_HIDDEN))
-                       continue;
-
-               pos = fprintf(stderr, "    ");
-               if (opts->short_name)
-                       pos += fprintf(stderr, "-%c", opts->short_name);
-               else
-                       pos += fprintf(stderr, "    ");
-
-               if (opts->long_name && opts->short_name)
-                       pos += fprintf(stderr, ", ");
-               if (opts->long_name)
-                       pos += fprintf(stderr, "--%s", opts->long_name);
+       for (  ; opts->type != OPTION_END; opts++)
+               print_option_help(opts, full);
 
-               switch (opts->type) {
-               case OPTION_ARGUMENT:
-                       break;
-               case OPTION_LONG:
-               case OPTION_U64:
-               case OPTION_INTEGER:
-               case OPTION_UINTEGER:
-                       if (opts->flags & PARSE_OPT_OPTARG)
-                               if (opts->long_name)
-                                       pos += fprintf(stderr, "[=<n>]");
-                               else
-                                       pos += fprintf(stderr, "[<n>]");
-                       else
-                               pos += fprintf(stderr, " <n>");
-                       break;
-               case OPTION_CALLBACK:
-                       if (opts->flags & PARSE_OPT_NOARG)
-                               break;
-                       /* FALLTHROUGH */
-               case OPTION_STRING:
-                       if (opts->argh) {
-                               if (opts->flags & PARSE_OPT_OPTARG)
-                                       if (opts->long_name)
-                                               pos += fprintf(stderr, "[=<%s>]", opts->argh);
-                                       else
-                                               pos += fprintf(stderr, "[<%s>]", opts->argh);
-                               else
-                                       pos += fprintf(stderr, " <%s>", opts->argh);
-                       } else {
-                               if (opts->flags & PARSE_OPT_OPTARG)
-                                       if (opts->long_name)
-                                               pos += fprintf(stderr, "[=...]");
-                                       else
-                                               pos += fprintf(stderr, "[...]");
-                               else
-                                       pos += fprintf(stderr, " ...");
-                       }
-                       break;
-               default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
-               case OPTION_END:
-               case OPTION_GROUP:
-               case OPTION_BIT:
-               case OPTION_BOOLEAN:
-               case OPTION_INCR:
-               case OPTION_SET_UINT:
-               case OPTION_SET_PTR:
-                       break;
-               }
-
-               if (pos <= USAGE_OPTS_WIDTH)
-                       pad = USAGE_OPTS_WIDTH - pos;
-               else {
-                       fputc('\n', stderr);
-                       pad = USAGE_OPTS_WIDTH;
-               }
-               fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
-       }
        fputc('\n', stderr);
 
        return PARSE_OPT_HELP;
@@ -559,9 +565,44 @@ void usage_with_options(const char * const *usagestr,
 }
 
 int parse_options_usage(const char * const *usagestr,
-                       const struct option *opts)
+                       const struct option *opts,
+                       const char *optstr, bool short_opt)
 {
-       return usage_with_options_internal(usagestr, opts, 0);
+       if (!usagestr)
+               return PARSE_OPT_HELP;
+
+       fprintf(stderr, "\n usage: %s\n", *usagestr++);
+       while (*usagestr && **usagestr)
+               fprintf(stderr, "    or: %s\n", *usagestr++);
+       while (*usagestr) {
+               fprintf(stderr, "%s%s\n",
+                               **usagestr ? "    " : "",
+                               *usagestr);
+               usagestr++;
+       }
+       fputc('\n', stderr);
+
+       for (  ; opts->type != OPTION_END; opts++) {
+               if (short_opt) {
+                       if (opts->short_name == *optstr)
+                               break;
+                       continue;
+               }
+
+               if (opts->long_name == NULL)
+                       continue;
+
+               if (!prefixcmp(optstr, opts->long_name))
+                       break;
+               if (!prefixcmp(optstr, "no-") &&
+                   !prefixcmp(optstr + 3, opts->long_name))
+                       break;
+       }
+
+       if (opts->type != OPTION_END)
+               print_option_help(opts, 0);
+
+       return PARSE_OPT_HELP;
 }
 
 
index 7bb5999940ca925f60482bbfa10aea1a6e685b10..b0241e28eaf7dd7b81469e22416e8f1e16e26c63 100644 (file)
@@ -158,7 +158,9 @@ struct parse_opt_ctx_t {
 };
 
 extern int parse_options_usage(const char * const *usagestr,
-                              const struct option *opts);
+                              const struct option *opts,
+                              const char *optstr,
+                              bool short_opt);
 
 extern void parse_options_start(struct parse_opt_ctx_t *ctx,
                                int argc, const char **argv, int flags);