Root/tools/perf/util/parse-options.c

1#include "util.h"
2#include "parse-options.h"
3#include "cache.h"
4
5#define OPT_SHORT 1
6#define OPT_UNSET 2
7
8static int opterror(const struct option *opt, const char *reason, int flags)
9{
10    if (flags & OPT_SHORT)
11        return error("switch `%c' %s", opt->short_name, reason);
12    if (flags & OPT_UNSET)
13        return error("option `no-%s' %s", opt->long_name, reason);
14    return error("option `%s' %s", opt->long_name, reason);
15}
16
17static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
18           int flags, const char **arg)
19{
20    if (p->opt) {
21        *arg = p->opt;
22        p->opt = NULL;
23    } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
24            **(p->argv + 1) == '-')) {
25        *arg = (const char *)opt->defval;
26    } else if (p->argc > 1) {
27        p->argc--;
28        *arg = *++p->argv;
29    } else
30        return opterror(opt, "requires a value", flags);
31    return 0;
32}
33
34static int get_value(struct parse_opt_ctx_t *p,
35             const struct option *opt, int flags)
36{
37    const char *s, *arg = NULL;
38    const int unset = flags & OPT_UNSET;
39
40    if (unset && p->opt)
41        return opterror(opt, "takes no value", flags);
42    if (unset && (opt->flags & PARSE_OPT_NONEG))
43        return opterror(opt, "isn't available", flags);
44
45    if (!(flags & OPT_SHORT) && p->opt) {
46        switch (opt->type) {
47        case OPTION_CALLBACK:
48            if (!(opt->flags & PARSE_OPT_NOARG))
49                break;
50            /* FALLTHROUGH */
51        case OPTION_BOOLEAN:
52        case OPTION_BIT:
53        case OPTION_SET_INT:
54        case OPTION_SET_PTR:
55            return opterror(opt, "takes no value", flags);
56        case OPTION_END:
57        case OPTION_ARGUMENT:
58        case OPTION_GROUP:
59        case OPTION_STRING:
60        case OPTION_INTEGER:
61        case OPTION_LONG:
62        default:
63            break;
64        }
65    }
66
67    switch (opt->type) {
68    case OPTION_BIT:
69        if (unset)
70            *(int *)opt->value &= ~opt->defval;
71        else
72            *(int *)opt->value |= opt->defval;
73        return 0;
74
75    case OPTION_BOOLEAN:
76        *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
77        return 0;
78
79    case OPTION_SET_INT:
80        *(int *)opt->value = unset ? 0 : opt->defval;
81        return 0;
82
83    case OPTION_SET_PTR:
84        *(void **)opt->value = unset ? NULL : (void *)opt->defval;
85        return 0;
86
87    case OPTION_STRING:
88        if (unset)
89            *(const char **)opt->value = NULL;
90        else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
91            *(const char **)opt->value = (const char *)opt->defval;
92        else
93            return get_arg(p, opt, flags, (const char **)opt->value);
94        return 0;
95
96    case OPTION_CALLBACK:
97        if (unset)
98            return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
99        if (opt->flags & PARSE_OPT_NOARG)
100            return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
101        if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
102            return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
103        if (get_arg(p, opt, flags, &arg))
104            return -1;
105        return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
106
107    case OPTION_INTEGER:
108        if (unset) {
109            *(int *)opt->value = 0;
110            return 0;
111        }
112        if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
113            *(int *)opt->value = opt->defval;
114            return 0;
115        }
116        if (get_arg(p, opt, flags, &arg))
117            return -1;
118        *(int *)opt->value = strtol(arg, (char **)&s, 10);
119        if (*s)
120            return opterror(opt, "expects a numerical value", flags);
121        return 0;
122
123    case OPTION_LONG:
124        if (unset) {
125            *(long *)opt->value = 0;
126            return 0;
127        }
128        if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
129            *(long *)opt->value = opt->defval;
130            return 0;
131        }
132        if (get_arg(p, opt, flags, &arg))
133            return -1;
134        *(long *)opt->value = strtol(arg, (char **)&s, 10);
135        if (*s)
136            return opterror(opt, "expects a numerical value", flags);
137        return 0;
138
139    case OPTION_END:
140    case OPTION_ARGUMENT:
141    case OPTION_GROUP:
142    default:
143        die("should not happen, someone must be hit on the forehead");
144    }
145}
146
147static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
148{
149    for (; options->type != OPTION_END; options++) {
150        if (options->short_name == *p->opt) {
151            p->opt = p->opt[1] ? p->opt + 1 : NULL;
152            return get_value(p, options, OPT_SHORT);
153        }
154    }
155    return -2;
156}
157
158static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
159                          const struct option *options)
160{
161    const char *arg_end = strchr(arg, '=');
162    const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
163    int abbrev_flags = 0, ambiguous_flags = 0;
164
165    if (!arg_end)
166        arg_end = arg + strlen(arg);
167
168    for (; options->type != OPTION_END; options++) {
169        const char *rest;
170        int flags = 0;
171
172        if (!options->long_name)
173            continue;
174
175        rest = skip_prefix(arg, options->long_name);
176        if (options->type == OPTION_ARGUMENT) {
177            if (!rest)
178                continue;
179            if (*rest == '=')
180                return opterror(options, "takes no value", flags);
181            if (*rest)
182                continue;
183            p->out[p->cpidx++] = arg - 2;
184            return 0;
185        }
186        if (!rest) {
187            /* abbreviated? */
188            if (!strncmp(options->long_name, arg, arg_end - arg)) {
189is_abbreviated:
190                if (abbrev_option) {
191                    /*
192                     * If this is abbreviated, it is
193                     * ambiguous. So when there is no
194                     * exact match later, we need to
195                     * error out.
196                     */
197                    ambiguous_option = abbrev_option;
198                    ambiguous_flags = abbrev_flags;
199                }
200                if (!(flags & OPT_UNSET) && *arg_end)
201                    p->opt = arg_end + 1;
202                abbrev_option = options;
203                abbrev_flags = flags;
204                continue;
205            }
206            /* negated and abbreviated very much? */
207            if (!prefixcmp("no-", arg)) {
208                flags |= OPT_UNSET;
209                goto is_abbreviated;
210            }
211            /* negated? */
212            if (strncmp(arg, "no-", 3))
213                continue;
214            flags |= OPT_UNSET;
215            rest = skip_prefix(arg + 3, options->long_name);
216            /* abbreviated and negated? */
217            if (!rest && !prefixcmp(options->long_name, arg + 3))
218                goto is_abbreviated;
219            if (!rest)
220                continue;
221        }
222        if (*rest) {
223            if (*rest != '=')
224                continue;
225            p->opt = rest + 1;
226        }
227        return get_value(p, options, flags);
228    }
229
230    if (ambiguous_option)
231        return error("Ambiguous option: %s "
232            "(could be --%s%s or --%s%s)",
233            arg,
234            (ambiguous_flags & OPT_UNSET) ? "no-" : "",
235            ambiguous_option->long_name,
236            (abbrev_flags & OPT_UNSET) ? "no-" : "",
237            abbrev_option->long_name);
238    if (abbrev_option)
239        return get_value(p, abbrev_option, abbrev_flags);
240    return -2;
241}
242
243static void check_typos(const char *arg, const struct option *options)
244{
245    if (strlen(arg) < 3)
246        return;
247
248    if (!prefixcmp(arg, "no-")) {
249        error ("did you mean `--%s` (with two dashes ?)", arg);
250        exit(129);
251    }
252
253    for (; options->type != OPTION_END; options++) {
254        if (!options->long_name)
255            continue;
256        if (!prefixcmp(options->long_name, arg)) {
257            error ("did you mean `--%s` (with two dashes ?)", arg);
258            exit(129);
259        }
260    }
261}
262
263void parse_options_start(struct parse_opt_ctx_t *ctx,
264             int argc, const char **argv, int flags)
265{
266    memset(ctx, 0, sizeof(*ctx));
267    ctx->argc = argc - 1;
268    ctx->argv = argv + 1;
269    ctx->out = argv;
270    ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
271    ctx->flags = flags;
272    if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
273        (flags & PARSE_OPT_STOP_AT_NON_OPTION))
274        die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
275}
276
277static int usage_with_options_internal(const char * const *,
278                       const struct option *, int);
279
280int parse_options_step(struct parse_opt_ctx_t *ctx,
281               const struct option *options,
282               const char * const usagestr[])
283{
284    int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
285
286    /* we must reset ->opt, unknown short option leave it dangling */
287    ctx->opt = NULL;
288
289    for (; ctx->argc; ctx->argc--, ctx->argv++) {
290        const char *arg = ctx->argv[0];
291
292        if (*arg != '-' || !arg[1]) {
293            if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
294                break;
295            ctx->out[ctx->cpidx++] = ctx->argv[0];
296            continue;
297        }
298
299        if (arg[1] != '-') {
300            ctx->opt = arg + 1;
301            if (internal_help && *ctx->opt == 'h')
302                return parse_options_usage(usagestr, options);
303            switch (parse_short_opt(ctx, options)) {
304            case -1:
305                return parse_options_usage(usagestr, options);
306            case -2:
307                goto unknown;
308            default:
309                break;
310            }
311            if (ctx->opt)
312                check_typos(arg + 1, options);
313            while (ctx->opt) {
314                if (internal_help && *ctx->opt == 'h')
315                    return parse_options_usage(usagestr, options);
316                switch (parse_short_opt(ctx, options)) {
317                case -1:
318                    return parse_options_usage(usagestr, options);
319                case -2:
320                    /* fake a short option thing to hide the fact that we may have
321                     * started to parse aggregated stuff
322                     *
323                     * This is leaky, too bad.
324                     */
325                    ctx->argv[0] = strdup(ctx->opt - 1);
326                    *(char *)ctx->argv[0] = '-';
327                    goto unknown;
328                default:
329                    break;
330                }
331            }
332            continue;
333        }
334
335        if (!arg[2]) { /* "--" */
336            if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
337                ctx->argc--;
338                ctx->argv++;
339            }
340            break;
341        }
342
343        if (internal_help && !strcmp(arg + 2, "help-all"))
344            return usage_with_options_internal(usagestr, options, 1);
345        if (internal_help && !strcmp(arg + 2, "help"))
346            return parse_options_usage(usagestr, options);
347        switch (parse_long_opt(ctx, arg + 2, options)) {
348        case -1:
349            return parse_options_usage(usagestr, options);
350        case -2:
351            goto unknown;
352        default:
353            break;
354        }
355        continue;
356unknown:
357        if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
358            return PARSE_OPT_UNKNOWN;
359        ctx->out[ctx->cpidx++] = ctx->argv[0];
360        ctx->opt = NULL;
361    }
362    return PARSE_OPT_DONE;
363}
364
365int parse_options_end(struct parse_opt_ctx_t *ctx)
366{
367    memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
368    ctx->out[ctx->cpidx + ctx->argc] = NULL;
369    return ctx->cpidx + ctx->argc;
370}
371
372int parse_options(int argc, const char **argv, const struct option *options,
373          const char * const usagestr[], int flags)
374{
375    struct parse_opt_ctx_t ctx;
376
377    parse_options_start(&ctx, argc, argv, flags);
378    switch (parse_options_step(&ctx, options, usagestr)) {
379    case PARSE_OPT_HELP:
380        exit(129);
381    case PARSE_OPT_DONE:
382        break;
383    default: /* PARSE_OPT_UNKNOWN */
384        if (ctx.argv[0][1] == '-') {
385            error("unknown option `%s'", ctx.argv[0] + 2);
386        } else {
387            error("unknown switch `%c'", *ctx.opt);
388        }
389        usage_with_options(usagestr, options);
390    }
391
392    return parse_options_end(&ctx);
393}
394
395#define USAGE_OPTS_WIDTH 24
396#define USAGE_GAP 2
397
398int usage_with_options_internal(const char * const *usagestr,
399                const struct option *opts, int full)
400{
401    if (!usagestr)
402        return PARSE_OPT_HELP;
403
404    fprintf(stderr, "\n usage: %s\n", *usagestr++);
405    while (*usagestr && **usagestr)
406        fprintf(stderr, " or: %s\n", *usagestr++);
407    while (*usagestr) {
408        fprintf(stderr, "%s%s\n",
409                **usagestr ? " " : "",
410                *usagestr);
411        usagestr++;
412    }
413
414    if (opts->type != OPTION_GROUP)
415        fputc('\n', stderr);
416
417    for (; opts->type != OPTION_END; opts++) {
418        size_t pos;
419        int pad;
420
421        if (opts->type == OPTION_GROUP) {
422            fputc('\n', stderr);
423            if (*opts->help)
424                fprintf(stderr, "%s\n", opts->help);
425            continue;
426        }
427        if (!full && (opts->flags & PARSE_OPT_HIDDEN))
428            continue;
429
430        pos = fprintf(stderr, " ");
431        if (opts->short_name)
432            pos += fprintf(stderr, "-%c", opts->short_name);
433        else
434            pos += fprintf(stderr, " ");
435
436        if (opts->long_name && opts->short_name)
437            pos += fprintf(stderr, ", ");
438        if (opts->long_name)
439            pos += fprintf(stderr, "--%s", opts->long_name);
440
441        switch (opts->type) {
442        case OPTION_ARGUMENT:
443            break;
444        case OPTION_INTEGER:
445            if (opts->flags & PARSE_OPT_OPTARG)
446                if (opts->long_name)
447                    pos += fprintf(stderr, "[=<n>]");
448                else
449                    pos += fprintf(stderr, "[<n>]");
450            else
451                pos += fprintf(stderr, " <n>");
452            break;
453        case OPTION_CALLBACK:
454            if (opts->flags & PARSE_OPT_NOARG)
455                break;
456            /* FALLTHROUGH */
457        case OPTION_STRING:
458            if (opts->argh) {
459                if (opts->flags & PARSE_OPT_OPTARG)
460                    if (opts->long_name)
461                        pos += fprintf(stderr, "[=<%s>]", opts->argh);
462                    else
463                        pos += fprintf(stderr, "[<%s>]", opts->argh);
464                else
465                    pos += fprintf(stderr, " <%s>", opts->argh);
466            } else {
467                if (opts->flags & PARSE_OPT_OPTARG)
468                    if (opts->long_name)
469                        pos += fprintf(stderr, "[=...]");
470                    else
471                        pos += fprintf(stderr, "[...]");
472                else
473                    pos += fprintf(stderr, " ...");
474            }
475            break;
476        default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
477        case OPTION_END:
478        case OPTION_GROUP:
479        case OPTION_BIT:
480        case OPTION_BOOLEAN:
481        case OPTION_SET_INT:
482        case OPTION_SET_PTR:
483        case OPTION_LONG:
484            break;
485        }
486
487        if (pos <= USAGE_OPTS_WIDTH)
488            pad = USAGE_OPTS_WIDTH - pos;
489        else {
490            fputc('\n', stderr);
491            pad = USAGE_OPTS_WIDTH;
492        }
493        fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
494    }
495    fputc('\n', stderr);
496
497    return PARSE_OPT_HELP;
498}
499
500void usage_with_options(const char * const *usagestr,
501            const struct option *opts)
502{
503    usage_with_options_internal(usagestr, opts, 0);
504    exit(129);
505}
506
507int parse_options_usage(const char * const *usagestr,
508            const struct option *opts)
509{
510    return usage_with_options_internal(usagestr, opts, 0);
511}
512
513
514int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
515               int unset)
516{
517    int *target = opt->value;
518
519    if (unset)
520        /* --no-quiet, --no-verbose */
521        *target = 0;
522    else if (opt->short_name == 'v') {
523        if (*target >= 0)
524            (*target)++;
525        else
526            *target = 1;
527    } else {
528        if (*target <= 0)
529            (*target)--;
530        else
531            *target = -1;
532    }
533    return 0;
534}
535

Archive Download this file



interactive