Message ID | 1302205647-7435-2-git-send-email-prasadjoshi124@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 04/07/11 13:47, Prasad Joshi wrote: > - parse-options.[ch] has argument processing code. > > - types.h: Additional types for argument processing. > > - strbuf.[ch]: Added a function prefixcmp to compare string prefix Rather than copy perf code, how about a tools/lib? David > > Signed-off-by: Prasad Joshi <prasadjoshi124@gmail.com> > --- > tools/kvm/include/kvm/parse-options.h | 161 ++++++++++ > tools/kvm/include/kvm/strbuf.h | 6 + > tools/kvm/include/kvm/util.h | 8 + > tools/kvm/include/linux/types.h | 12 + > tools/kvm/util/parse-options.c | 560 +++++++++++++++++++++++++++++++++ > tools/kvm/util/strbuf.c | 13 + > 6 files changed, 760 insertions(+), 0 deletions(-) > create mode 100644 tools/kvm/include/kvm/parse-options.h > create mode 100644 tools/kvm/include/kvm/strbuf.h > create mode 100644 tools/kvm/util/parse-options.c > create mode 100644 tools/kvm/util/strbuf.c > > diff --git a/tools/kvm/include/kvm/parse-options.h b/tools/kvm/include/kvm/parse-options.h > new file mode 100644 > index 0000000..b59220d > --- /dev/null > +++ b/tools/kvm/include/kvm/parse-options.h > @@ -0,0 +1,161 @@ > +#ifndef __PARSE_OPTIONS_H__ > +#define __PARSE_OPTIONS_H__ > + > +enum parse_opt_type { > + /* special types */ > + OPTION_END, > + OPTION_ARGUMENT, > + OPTION_GROUP, > + /* options with no arguments */ > + OPTION_BIT, > + OPTION_BOOLEAN, > + OPTION_INCR, > + OPTION_SET_UINT, > + OPTION_SET_PTR, > + /* options with arguments (usually) */ > + OPTION_STRING, > + OPTION_INTEGER, > + OPTION_LONG, > + OPTION_CALLBACK, > + OPTION_U64, > + OPTION_UINTEGER, > +}; > + > +enum parse_opt_flags { > + PARSE_OPT_KEEP_DASHDASH = 1, > + PARSE_OPT_STOP_AT_NON_OPTION = 2, > + PARSE_OPT_KEEP_ARGV0 = 4, > + PARSE_OPT_KEEP_UNKNOWN = 8, > + PARSE_OPT_NO_INTERNAL_HELP = 16, > +}; > + > +enum parse_opt_option_flags { > + PARSE_OPT_OPTARG = 1, > + PARSE_OPT_NOARG = 2, > + PARSE_OPT_NONEG = 4, > + PARSE_OPT_HIDDEN = 8, > + PARSE_OPT_LASTARG_DEFAULT = 16, > +}; > + > +struct option; > +typedef int parse_opt_cb(const struct option *, const char *arg, int unset); > +/* > + * `type`:: > + * holds the type of the option, you must have an OPTION_END last in your > + * array. > + * > + * `short_name`:: > + * the character to use as a short option name, '\0' if none. > + * > + * `long_name`:: > + * the long option name, without the leading dashes, NULL if none. > + * > + * `value`:: > + * stores pointers to the values to be filled. > + * > + * `argh`:: > + * token to explain the kind of argument this option wants. Keep it > + * homogenous across the repository. > + * > + * `help`:: > + * the short help associated to what the option does. > + * Must never be NULL (except for OPTION_END). > + * OPTION_GROUP uses this pointer to store the group header. > + * > + * `flags`:: > + * mask of parse_opt_option_flags. > + * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs) > + * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs > + * PARSE_OPT_NONEG: says that this option cannot be negated > + * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in > + * the long one. > + * > + * `callback`:: > + * pointer to the callback to use for OPTION_CALLBACK. > + * > + * `defval`:: > + * default value to fill (*->value) with for PARSE_OPT_OPTARG. > + * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in > + * the value when met. > + * CALLBACKS can use it like they want. > + */ > +struct option { > +enum parse_opt_type type; > +int short_name; > +const char *long_name; > +void *value; > +const char *argh; > +const char *help; > + > +int flags; > +parse_opt_cb *callback; > +intptr_t defval; > +}; > + > +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) > +#define check_vtype(v, type) \ > + (BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v) > + > +#define OPT_INTEGER(s, l, v, h) \ > +{ \ > + .type = OPTION_INTEGER, \ > + .short_name = (s), \ > + .long_name = (l), \ > + .value = check_vtype(v, int *), \ > + .help = (h) \ > +} > + > +#define OPT_U64(s, l, v, h) \ > +{ \ > + .type = OPTION_U64, \ > + .short_name = (s), \ > + .long_name = (l), \ > + .value = check_vtype(v, u64 *), \ > + .help = (h) \ > +} > + > +#define OPT_STRING(s, l, v, a, h) \ > +{ \ > + .type = OPTION_STRING, \ > + .short_name = (s), \ > + .long_name = (l), \ > + .value = check_vtype(v, const char **), (a), \ > + .help = (h) \ > +} > + > +#define OPT_BOOLEAN(s, l, v, h) \ > +{ \ > + .type = OPTION_BOOLEAN, \ > + .short_name = (s), \ > + .long_name = (l), \ > + .value = check_vtype(v, bool *), \ > + .help = (h) \ > +} > + > +#define OPT_END() { .type = OPTION_END } > + > +enum { > + PARSE_OPT_HELP = -1, > + PARSE_OPT_DONE, > + PARSE_OPT_UNKNOWN, > +}; > + > +/* > + * It's okay for the caller to consume argv/argc in the usual way. > + * Other fields of that structure are private to parse-options and should not > + * be modified in any way. > + **/ > +struct parse_opt_ctx_t { > + const char **argv; > + const char **out; > + int argc, cpidx; > + const char *opt; > + int flags; > +}; > + > +/* global functions */ > +void usage_with_options(const char * const *usagestr, > + const struct option *opts); > +int parse_options(int argc, const char **argv, const struct option *options, > + const char * const usagestr[], int flags); > +#endif > diff --git a/tools/kvm/include/kvm/strbuf.h b/tools/kvm/include/kvm/strbuf.h > new file mode 100644 > index 0000000..e67ca20 > --- /dev/null > +++ b/tools/kvm/include/kvm/strbuf.h > @@ -0,0 +1,6 @@ > +#ifndef __STRBUF_H__ > +#define __STRBUF_H__ > + > +int prefixcmp(const char *str, const char *prefix); > + > +#endif > diff --git a/tools/kvm/include/kvm/util.h b/tools/kvm/include/kvm/util.h > index 8c80777..ae033cc 100644 > --- a/tools/kvm/include/kvm/util.h > +++ b/tools/kvm/include/kvm/util.h > @@ -48,4 +48,12 @@ do { \ > > extern size_t strlcat(char *dest, const char *src, size_t count); > > +/* some inline functions */ > + > +static inline const char *skip_prefix(const char *str, const char *prefix) > +{ > + size_t len = strlen(prefix); > + return strncmp(str, prefix, len) ? NULL : str + len; > +} > + > #endif /* KVM__UTIL_H */ > diff --git a/tools/kvm/include/linux/types.h b/tools/kvm/include/linux/types.h > index 70e2546..b989d2a 100644 > --- a/tools/kvm/include/linux/types.h > +++ b/tools/kvm/include/linux/types.h > @@ -15,4 +15,16 @@ > #define __s64 int64_t > #define __u64 uint64_t > > +typedef __u64 u64; > +typedef __s64 s64; > + > +typedef __u32 u32; > +typedef __s32 s32; > + > +typedef __u16 u16; > +typedef __s16 s16; > + > +typedef __u8 u8; > +typedef __s8 s8; > + > #endif /* LINUX_TYPES_H */ > diff --git a/tools/kvm/util/parse-options.c b/tools/kvm/util/parse-options.c > new file mode 100644 > index 0000000..3065c50 > --- /dev/null > +++ b/tools/kvm/util/parse-options.c > @@ -0,0 +1,560 @@ > +#include <stdio.h> > +#include <string.h> > +#include <unistd.h> > +#include <stdint.h> > + > +#include <stdbool.h> > + > +/* user defined includes */ > +#include <linux/types.h> > +#include <kvm/util.h> > +#include <kvm/parse-options.h> > +#include <kvm/strbuf.h> > + > +#define OPT_SHORT 1 > +#define OPT_UNSET 2 > + > +static int opterror(const struct option *opt, const char *reason, int flags) > +{ > + if (flags & OPT_SHORT) > + return error("switch `%c' %s", opt->short_name, reason); > + if (flags & OPT_UNSET) > + return error("option `no-%s' %s", opt->long_name, reason); > + return error("option `%s' %s", opt->long_name, reason); > +} > + > +static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, > + int flags, const char **arg) > +{ > + if (p->opt) { > + *arg = p->opt; > + p->opt = NULL; > + } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 || > + **(p->argv + 1) == '-')) { > + *arg = (const char *)opt->defval; > + } else if (p->argc > 1) { > + p->argc--; > + *arg = *++p->argv; > + } else > + return opterror(opt, "requires a value", flags); > + return 0; > +} > + > +static int get_value(struct parse_opt_ctx_t *p, > + const struct option *opt, int flags) > +{ > + const char *s, *arg = NULL; > + const int unset = flags & OPT_UNSET; > + > + if (unset && p->opt) > + return opterror(opt, "takes no value", flags); > + if (unset && (opt->flags & PARSE_OPT_NONEG)) > + return opterror(opt, "isn't available", flags); > + > + if (!(flags & OPT_SHORT) && p->opt) { > + switch (opt->type) { > + case OPTION_CALLBACK: > + if (!(opt->flags & PARSE_OPT_NOARG)) > + break; > + /* FALLTHROUGH */ > + case OPTION_BOOLEAN: > + case OPTION_INCR: > + case OPTION_BIT: > + case OPTION_SET_UINT: > + case OPTION_SET_PTR: > + return opterror(opt, "takes no value", flags); > + case OPTION_END: > + case OPTION_ARGUMENT: > + case OPTION_GROUP: > + case OPTION_STRING: > + case OPTION_INTEGER: > + case OPTION_UINTEGER: > + case OPTION_LONG: > + case OPTION_U64: > + default: > + break; > + } > + } > + > + switch (opt->type) { > + case OPTION_BIT: > + if (unset) > + *(int *)opt->value &= ~opt->defval; > + else > + *(int *)opt->value |= opt->defval; > + return 0; > + > + case OPTION_BOOLEAN: > + *(bool *)opt->value = unset ? false : true; > + return 0; > + > + case OPTION_INCR: > + *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; > + return 0; > + > + case OPTION_SET_UINT: > + *(unsigned int *)opt->value = unset ? 0 : opt->defval; > + return 0; > + > + case OPTION_SET_PTR: > + *(void **)opt->value = unset ? NULL : (void *)opt->defval; > + return 0; > + > + case OPTION_STRING: > + if (unset) > + *(const char **)opt->value = NULL; > + else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) > + *(const char **)opt->value = (const char *)opt->defval; > + else > + return get_arg(p, opt, flags, (const char **)opt->value); > + return 0; > + > + case OPTION_CALLBACK: > + if (unset) > + return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; > + if (opt->flags & PARSE_OPT_NOARG) > + return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; > + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) > + return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; > + if (get_arg(p, opt, flags, &arg)) > + return -1; > + return (*opt->callback)(opt, arg, 0) ? (-1) : 0; > + > + case OPTION_INTEGER: > + if (unset) { > + *(int *)opt->value = 0; > + return 0; > + } > + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { > + *(int *)opt->value = opt->defval; > + return 0; > + } > + if (get_arg(p, opt, flags, &arg)) > + return -1; > + *(int *)opt->value = strtol(arg, (char **)&s, 10); > + if (*s) > + return opterror(opt, "expects a numerical value", flags); > + return 0; > + > + case OPTION_UINTEGER: > + if (unset) { > + *(unsigned int *)opt->value = 0; > + return 0; > + } > + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { > + *(unsigned int *)opt->value = opt->defval; > + return 0; > + } > + if (get_arg(p, opt, flags, &arg)) > + return -1; > + *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10); > + if (*s) > + return opterror(opt, "expects a numerical value", flags); > + return 0; > + > + case OPTION_LONG: > + if (unset) { > + *(long *)opt->value = 0; > + return 0; > + } > + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { > + *(long *)opt->value = opt->defval; > + return 0; > + } > + if (get_arg(p, opt, flags, &arg)) > + return -1; > + *(long *)opt->value = strtol(arg, (char **)&s, 10); > + if (*s) > + return opterror(opt, "expects a numerical value", flags); > + return 0; > + > + case OPTION_U64: > + if (unset) { > + *(u64 *)opt->value = 0; > + return 0; > + } > + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { > + *(u64 *)opt->value = opt->defval; > + return 0; > + } > + if (get_arg(p, opt, flags, &arg)) > + return -1; > + *(u64 *)opt->value = strtoull(arg, (char **)&s, 10); > + if (*s) > + return opterror(opt, "expects a numerical value", flags); > + return 0; > + > + case OPTION_END: > + case OPTION_ARGUMENT: > + case OPTION_GROUP: > + default: > + die("should not happen, someone must be hit on the forehead"); > + } > +} > + > +#define USAGE_OPTS_WIDTH 24 > +#define USAGE_GAP 2 > + > +static int usage_with_options_internal(const char * const *usagestr, > + const struct option *opts, int full) > +{ > + 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++; > + } > + > + 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); > + > + 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; > +} > + > +void usage_with_options(const char * const *usagestr, > + const struct option *opts) > +{ > + usage_with_options_internal(usagestr, opts, 0); > + exit(129); > +} > + > +static void check_typos(const char *arg, const struct option *options) > +{ > + if (strlen(arg) < 3) > + return; > + > + if (!prefixcmp(arg, "no-")) { > + error ("did you mean `--%s` (with two dashes ?)", arg); > + exit(129); > + } > + > + for (; options->type != OPTION_END; options++) { > + if (!options->long_name) > + continue; > + if (!prefixcmp(options->long_name, arg)) { > + error ("did you mean `--%s` (with two dashes ?)", arg); > + exit(129); > + } > + } > +} > + > +static int parse_options_usage(const char * const *usagestr, > + const struct option *opts) > +{ > + return usage_with_options_internal(usagestr, opts, 0); > +} > + > +static int parse_short_opt(struct parse_opt_ctx_t *p, > + const struct option *options) > +{ > + for (; options->type != OPTION_END; options++) { > + if (options->short_name == *p->opt) { > + p->opt = p->opt[1] ? p->opt + 1 : NULL; > + return get_value(p, options, OPT_SHORT); > + } > + } > + return -2; > +} > + > +static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, > + const struct option *options) > +{ > + const char *arg_end = strchr(arg, '='); > + const struct option *abbrev_option = NULL, *ambiguous_option = NULL; > + int abbrev_flags = 0, ambiguous_flags = 0; > + > + if (!arg_end) > + arg_end = arg + strlen(arg); > + > + for (; options->type != OPTION_END; options++) { > + const char *rest; > + int flags = 0; > + > + if (!options->long_name) > + continue; > + > + rest = skip_prefix(arg, options->long_name); > + if (options->type == OPTION_ARGUMENT) { > + if (!rest) > + continue; > + if (*rest == '=') > + return opterror(options, "takes no value", flags); > + if (*rest) > + continue; > + p->out[p->cpidx++] = arg - 2; > + return 0; > + } > + if (!rest) { > + /* abbreviated? */ > + if (!strncmp(options->long_name, arg, arg_end - arg)) { > +is_abbreviated: > + if (abbrev_option) { > + /* > + * If this is abbreviated, it is > + * ambiguous. So when there is no > + * exact match later, we need to > + * error out. > + */ > + ambiguous_option = abbrev_option; > + ambiguous_flags = abbrev_flags; > + } > + if (!(flags & OPT_UNSET) && *arg_end) > + p->opt = arg_end + 1; > + abbrev_option = options; > + abbrev_flags = flags; > + continue; > + } > + /* negated and abbreviated very much? */ > + if (!prefixcmp("no-", arg)) { > + flags |= OPT_UNSET; > + goto is_abbreviated; > + } > + /* negated? */ > + if (strncmp(arg, "no-", 3)) > + continue; > + flags |= OPT_UNSET; > + rest = skip_prefix(arg + 3, options->long_name); > + /* abbreviated and negated? */ > + if (!rest && !prefixcmp(options->long_name, arg + 3)) > + goto is_abbreviated; > + if (!rest) > + continue; > + } > + if (*rest) { > + if (*rest != '=') > + continue; > + p->opt = rest + 1; > + } > + return get_value(p, options, flags); > + } > + > + if (ambiguous_option) > + return error("Ambiguous option: %s " > + "(could be --%s%s or --%s%s)", > + arg, > + (ambiguous_flags & OPT_UNSET) ? "no-" : "", > + ambiguous_option->long_name, > + (abbrev_flags & OPT_UNSET) ? "no-" : "", > + abbrev_option->long_name); > + if (abbrev_option) > + return get_value(p, abbrev_option, abbrev_flags); > + return -2; > +} > + > + > +static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, > + const char **argv, int flags) > +{ > + memset(ctx, 0, sizeof(*ctx)); > + ctx->argc = argc; > + ctx->argv = argv; > + ctx->out = argv; > + ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); > + ctx->flags = flags; > + if ((flags & PARSE_OPT_KEEP_UNKNOWN) && > + (flags & PARSE_OPT_STOP_AT_NON_OPTION)) > + die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); > +} > + > +static int parse_options_end(struct parse_opt_ctx_t *ctx) > +{ > + memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); > + ctx->out[ctx->cpidx + ctx->argc] = NULL; > + return ctx->cpidx + ctx->argc; > +} > + > + > +static int parse_options_step(struct parse_opt_ctx_t *ctx, > + const struct option *options, const char * const usagestr[]) > +{ > + int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); > + > + /* we must reset ->opt, unknown short option leave it dangling */ > + ctx->opt = NULL; > + > + for (; ctx->argc; ctx->argc--, ctx->argv++) { > + const char *arg = ctx->argv[0]; > + > + if (*arg != '-' || !arg[1]) { > + if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) > + break; > + ctx->out[ctx->cpidx++] = ctx->argv[0]; > + continue; > + } > + > + if (arg[1] != '-') { > + ctx->opt = arg + 1; > + if (internal_help && *ctx->opt == 'h') > + return parse_options_usage(usagestr, options); > + switch (parse_short_opt(ctx, options)) { > + case -1: > + return parse_options_usage(usagestr, options); > + case -2: > + goto unknown; > + default: > + break; > + } > + if (ctx->opt) > + check_typos(arg + 1, options); > + while (ctx->opt) { > + if (internal_help && *ctx->opt == 'h') > + return parse_options_usage(usagestr, options); > + switch (parse_short_opt(ctx, options)) { > + case -1: > + return parse_options_usage(usagestr, options); > + case -2: > + /* fake a short option thing to hide the fact that we may have > + * started to parse aggregated stuff > + * > + * This is leaky, too bad. > + */ > + ctx->argv[0] = strdup(ctx->opt - 1); > + *(char *)ctx->argv[0] = '-'; > + goto unknown; > + default: > + break; > + } > + } > + continue; > + } > + > + if (!arg[2]) { /* "--" */ > + if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { > + ctx->argc--; > + ctx->argv++; > + } > + break; > + } > + > + 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); > + switch (parse_long_opt(ctx, arg + 2, options)) { > + case -1: > + return parse_options_usage(usagestr, options); > + case -2: > + goto unknown; > + default: > + break; > + } > + continue; > +unknown: > + if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) > + return PARSE_OPT_UNKNOWN; > + ctx->out[ctx->cpidx++] = ctx->argv[0]; > + ctx->opt = NULL; > + } > + return PARSE_OPT_DONE; > +} > + > +int parse_options(int argc, const char **argv, const struct option *options, > + const char * const usagestr[], int flags) > +{ > + struct parse_opt_ctx_t ctx; > + > + parse_options_start(&ctx, argc, argv, flags); > + switch (parse_options_step(&ctx, options, usagestr)) { > + case PARSE_OPT_HELP: > + exit(129); > + case PARSE_OPT_DONE: > + break; > + default: /* PARSE_OPT_UNKNOWN */ > + if (ctx.argv[0][1] == '-') { > + error("unknown option `%s'", ctx.argv[0] + 2); > + } else { > + error("unknown switch `%c'", *ctx.opt); > + } > + usage_with_options(usagestr, options); > + } > + > + return parse_options_end(&ctx); > +} > diff --git a/tools/kvm/util/strbuf.c b/tools/kvm/util/strbuf.c > new file mode 100644 > index 0000000..ec77ab1 > --- /dev/null > +++ b/tools/kvm/util/strbuf.c > @@ -0,0 +1,13 @@ > + > +/* user defined headers */ > +#include <kvm/strbuf.h> > + > +int prefixcmp(const char *str, const char *prefix) > +{ > + for (; ; str++, prefix++) { > + if (!*prefix) > + return 0; > + else if (*str != *prefix) > + return (unsigned char)*prefix - (unsigned char)*str; > + } > +} -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 04/07/11 13:47, Prasad Joshi wrote: > > - parse-options.[ch] has argument processing code. > > > > - types.h: Additional types for argument processing. > > > > - strbuf.[ch]: Added a function prefixcmp to compare string prefix On Thu, 2011-04-07 at 14:17 -0600, David Ahern wrote: > Rather than copy perf code, how about a tools/lib? It's a good idea but lets not do it in our tree. We're still trying to keep things well-contained under 'tools/kvm' for merge reasons. You could try to do the cleanup in perf tree if you're interested and when that hits mainline, we can pull the bits from there and clean up our tree. Pekka -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
* Pekka Enberg <penberg@kernel.org> wrote: > On 04/07/11 13:47, Prasad Joshi wrote: > > > - parse-options.[ch] has argument processing code. > > > > > > - types.h: Additional types for argument processing. > > > > > > - strbuf.[ch]: Added a function prefixcmp to compare string prefix > > On Thu, 2011-04-07 at 14:17 -0600, David Ahern wrote: > > Rather than copy perf code, how about a tools/lib? > > It's a good idea but lets not do it in our tree. We're still trying to keep > things well-contained under 'tools/kvm' for merge reasons. Agreed. > You could try to do the cleanup in perf tree if you're interested and when > that hits mainline, we can pull the bits from there and clean up our tree. Yes, that ordering would make sense - the perf copies of Git code are also much more complete. Thanks, Ingo -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/tools/kvm/include/kvm/parse-options.h b/tools/kvm/include/kvm/parse-options.h new file mode 100644 index 0000000..b59220d --- /dev/null +++ b/tools/kvm/include/kvm/parse-options.h @@ -0,0 +1,161 @@ +#ifndef __PARSE_OPTIONS_H__ +#define __PARSE_OPTIONS_H__ + +enum parse_opt_type { + /* special types */ + OPTION_END, + OPTION_ARGUMENT, + OPTION_GROUP, + /* options with no arguments */ + OPTION_BIT, + OPTION_BOOLEAN, + OPTION_INCR, + OPTION_SET_UINT, + OPTION_SET_PTR, + /* options with arguments (usually) */ + OPTION_STRING, + OPTION_INTEGER, + OPTION_LONG, + OPTION_CALLBACK, + OPTION_U64, + OPTION_UINTEGER, +}; + +enum parse_opt_flags { + PARSE_OPT_KEEP_DASHDASH = 1, + PARSE_OPT_STOP_AT_NON_OPTION = 2, + PARSE_OPT_KEEP_ARGV0 = 4, + PARSE_OPT_KEEP_UNKNOWN = 8, + PARSE_OPT_NO_INTERNAL_HELP = 16, +}; + +enum parse_opt_option_flags { + PARSE_OPT_OPTARG = 1, + PARSE_OPT_NOARG = 2, + PARSE_OPT_NONEG = 4, + PARSE_OPT_HIDDEN = 8, + PARSE_OPT_LASTARG_DEFAULT = 16, +}; + +struct option; +typedef int parse_opt_cb(const struct option *, const char *arg, int unset); +/* + * `type`:: + * holds the type of the option, you must have an OPTION_END last in your + * array. + * + * `short_name`:: + * the character to use as a short option name, '\0' if none. + * + * `long_name`:: + * the long option name, without the leading dashes, NULL if none. + * + * `value`:: + * stores pointers to the values to be filled. + * + * `argh`:: + * token to explain the kind of argument this option wants. Keep it + * homogenous across the repository. + * + * `help`:: + * the short help associated to what the option does. + * Must never be NULL (except for OPTION_END). + * OPTION_GROUP uses this pointer to store the group header. + * + * `flags`:: + * mask of parse_opt_option_flags. + * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs) + * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs + * PARSE_OPT_NONEG: says that this option cannot be negated + * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in + * the long one. + * + * `callback`:: + * pointer to the callback to use for OPTION_CALLBACK. + * + * `defval`:: + * default value to fill (*->value) with for PARSE_OPT_OPTARG. + * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in + * the value when met. + * CALLBACKS can use it like they want. + */ +struct option { +enum parse_opt_type type; +int short_name; +const char *long_name; +void *value; +const char *argh; +const char *help; + +int flags; +parse_opt_cb *callback; +intptr_t defval; +}; + +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) +#define check_vtype(v, type) \ + (BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v) + +#define OPT_INTEGER(s, l, v, h) \ +{ \ + .type = OPTION_INTEGER, \ + .short_name = (s), \ + .long_name = (l), \ + .value = check_vtype(v, int *), \ + .help = (h) \ +} + +#define OPT_U64(s, l, v, h) \ +{ \ + .type = OPTION_U64, \ + .short_name = (s), \ + .long_name = (l), \ + .value = check_vtype(v, u64 *), \ + .help = (h) \ +} + +#define OPT_STRING(s, l, v, a, h) \ +{ \ + .type = OPTION_STRING, \ + .short_name = (s), \ + .long_name = (l), \ + .value = check_vtype(v, const char **), (a), \ + .help = (h) \ +} + +#define OPT_BOOLEAN(s, l, v, h) \ +{ \ + .type = OPTION_BOOLEAN, \ + .short_name = (s), \ + .long_name = (l), \ + .value = check_vtype(v, bool *), \ + .help = (h) \ +} + +#define OPT_END() { .type = OPTION_END } + +enum { + PARSE_OPT_HELP = -1, + PARSE_OPT_DONE, + PARSE_OPT_UNKNOWN, +}; + +/* + * It's okay for the caller to consume argv/argc in the usual way. + * Other fields of that structure are private to parse-options and should not + * be modified in any way. + **/ +struct parse_opt_ctx_t { + const char **argv; + const char **out; + int argc, cpidx; + const char *opt; + int flags; +}; + +/* global functions */ +void usage_with_options(const char * const *usagestr, + const struct option *opts); +int parse_options(int argc, const char **argv, const struct option *options, + const char * const usagestr[], int flags); +#endif diff --git a/tools/kvm/include/kvm/strbuf.h b/tools/kvm/include/kvm/strbuf.h new file mode 100644 index 0000000..e67ca20 --- /dev/null +++ b/tools/kvm/include/kvm/strbuf.h @@ -0,0 +1,6 @@ +#ifndef __STRBUF_H__ +#define __STRBUF_H__ + +int prefixcmp(const char *str, const char *prefix); + +#endif diff --git a/tools/kvm/include/kvm/util.h b/tools/kvm/include/kvm/util.h index 8c80777..ae033cc 100644 --- a/tools/kvm/include/kvm/util.h +++ b/tools/kvm/include/kvm/util.h @@ -48,4 +48,12 @@ do { \ extern size_t strlcat(char *dest, const char *src, size_t count); +/* some inline functions */ + +static inline const char *skip_prefix(const char *str, const char *prefix) +{ + size_t len = strlen(prefix); + return strncmp(str, prefix, len) ? NULL : str + len; +} + #endif /* KVM__UTIL_H */ diff --git a/tools/kvm/include/linux/types.h b/tools/kvm/include/linux/types.h index 70e2546..b989d2a 100644 --- a/tools/kvm/include/linux/types.h +++ b/tools/kvm/include/linux/types.h @@ -15,4 +15,16 @@ #define __s64 int64_t #define __u64 uint64_t +typedef __u64 u64; +typedef __s64 s64; + +typedef __u32 u32; +typedef __s32 s32; + +typedef __u16 u16; +typedef __s16 s16; + +typedef __u8 u8; +typedef __s8 s8; + #endif /* LINUX_TYPES_H */ diff --git a/tools/kvm/util/parse-options.c b/tools/kvm/util/parse-options.c new file mode 100644 index 0000000..3065c50 --- /dev/null +++ b/tools/kvm/util/parse-options.c @@ -0,0 +1,560 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdint.h> + +#include <stdbool.h> + +/* user defined includes */ +#include <linux/types.h> +#include <kvm/util.h> +#include <kvm/parse-options.h> +#include <kvm/strbuf.h> + +#define OPT_SHORT 1 +#define OPT_UNSET 2 + +static int opterror(const struct option *opt, const char *reason, int flags) +{ + if (flags & OPT_SHORT) + return error("switch `%c' %s", opt->short_name, reason); + if (flags & OPT_UNSET) + return error("option `no-%s' %s", opt->long_name, reason); + return error("option `%s' %s", opt->long_name, reason); +} + +static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, + int flags, const char **arg) +{ + if (p->opt) { + *arg = p->opt; + p->opt = NULL; + } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 || + **(p->argv + 1) == '-')) { + *arg = (const char *)opt->defval; + } else if (p->argc > 1) { + p->argc--; + *arg = *++p->argv; + } else + return opterror(opt, "requires a value", flags); + return 0; +} + +static int get_value(struct parse_opt_ctx_t *p, + const struct option *opt, int flags) +{ + const char *s, *arg = NULL; + const int unset = flags & OPT_UNSET; + + if (unset && p->opt) + return opterror(opt, "takes no value", flags); + if (unset && (opt->flags & PARSE_OPT_NONEG)) + return opterror(opt, "isn't available", flags); + + if (!(flags & OPT_SHORT) && p->opt) { + switch (opt->type) { + case OPTION_CALLBACK: + if (!(opt->flags & PARSE_OPT_NOARG)) + break; + /* FALLTHROUGH */ + case OPTION_BOOLEAN: + case OPTION_INCR: + case OPTION_BIT: + case OPTION_SET_UINT: + case OPTION_SET_PTR: + return opterror(opt, "takes no value", flags); + case OPTION_END: + case OPTION_ARGUMENT: + case OPTION_GROUP: + case OPTION_STRING: + case OPTION_INTEGER: + case OPTION_UINTEGER: + case OPTION_LONG: + case OPTION_U64: + default: + break; + } + } + + switch (opt->type) { + case OPTION_BIT: + if (unset) + *(int *)opt->value &= ~opt->defval; + else + *(int *)opt->value |= opt->defval; + return 0; + + case OPTION_BOOLEAN: + *(bool *)opt->value = unset ? false : true; + return 0; + + case OPTION_INCR: + *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; + return 0; + + case OPTION_SET_UINT: + *(unsigned int *)opt->value = unset ? 0 : opt->defval; + return 0; + + case OPTION_SET_PTR: + *(void **)opt->value = unset ? NULL : (void *)opt->defval; + return 0; + + case OPTION_STRING: + if (unset) + *(const char **)opt->value = NULL; + else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) + *(const char **)opt->value = (const char *)opt->defval; + else + return get_arg(p, opt, flags, (const char **)opt->value); + return 0; + + case OPTION_CALLBACK: + if (unset) + return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; + if (opt->flags & PARSE_OPT_NOARG) + return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) + return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; + if (get_arg(p, opt, flags, &arg)) + return -1; + return (*opt->callback)(opt, arg, 0) ? (-1) : 0; + + case OPTION_INTEGER: + if (unset) { + *(int *)opt->value = 0; + return 0; + } + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { + *(int *)opt->value = opt->defval; + return 0; + } + if (get_arg(p, opt, flags, &arg)) + return -1; + *(int *)opt->value = strtol(arg, (char **)&s, 10); + if (*s) + return opterror(opt, "expects a numerical value", flags); + return 0; + + case OPTION_UINTEGER: + if (unset) { + *(unsigned int *)opt->value = 0; + return 0; + } + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { + *(unsigned int *)opt->value = opt->defval; + return 0; + } + if (get_arg(p, opt, flags, &arg)) + return -1; + *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10); + if (*s) + return opterror(opt, "expects a numerical value", flags); + return 0; + + case OPTION_LONG: + if (unset) { + *(long *)opt->value = 0; + return 0; + } + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { + *(long *)opt->value = opt->defval; + return 0; + } + if (get_arg(p, opt, flags, &arg)) + return -1; + *(long *)opt->value = strtol(arg, (char **)&s, 10); + if (*s) + return opterror(opt, "expects a numerical value", flags); + return 0; + + case OPTION_U64: + if (unset) { + *(u64 *)opt->value = 0; + return 0; + } + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { + *(u64 *)opt->value = opt->defval; + return 0; + } + if (get_arg(p, opt, flags, &arg)) + return -1; + *(u64 *)opt->value = strtoull(arg, (char **)&s, 10); + if (*s) + return opterror(opt, "expects a numerical value", flags); + return 0; + + case OPTION_END: + case OPTION_ARGUMENT: + case OPTION_GROUP: + default: + die("should not happen, someone must be hit on the forehead"); + } +} + +#define USAGE_OPTS_WIDTH 24 +#define USAGE_GAP 2 + +static int usage_with_options_internal(const char * const *usagestr, + const struct option *opts, int full) +{ + 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++; + } + + 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); + + 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; +} + +void usage_with_options(const char * const *usagestr, + const struct option *opts) +{ + usage_with_options_internal(usagestr, opts, 0); + exit(129); +} + +static void check_typos(const char *arg, const struct option *options) +{ + if (strlen(arg) < 3) + return; + + if (!prefixcmp(arg, "no-")) { + error ("did you mean `--%s` (with two dashes ?)", arg); + exit(129); + } + + for (; options->type != OPTION_END; options++) { + if (!options->long_name) + continue; + if (!prefixcmp(options->long_name, arg)) { + error ("did you mean `--%s` (with two dashes ?)", arg); + exit(129); + } + } +} + +static int parse_options_usage(const char * const *usagestr, + const struct option *opts) +{ + return usage_with_options_internal(usagestr, opts, 0); +} + +static int parse_short_opt(struct parse_opt_ctx_t *p, + const struct option *options) +{ + for (; options->type != OPTION_END; options++) { + if (options->short_name == *p->opt) { + p->opt = p->opt[1] ? p->opt + 1 : NULL; + return get_value(p, options, OPT_SHORT); + } + } + return -2; +} + +static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, + const struct option *options) +{ + const char *arg_end = strchr(arg, '='); + const struct option *abbrev_option = NULL, *ambiguous_option = NULL; + int abbrev_flags = 0, ambiguous_flags = 0; + + if (!arg_end) + arg_end = arg + strlen(arg); + + for (; options->type != OPTION_END; options++) { + const char *rest; + int flags = 0; + + if (!options->long_name) + continue; + + rest = skip_prefix(arg, options->long_name); + if (options->type == OPTION_ARGUMENT) { + if (!rest) + continue; + if (*rest == '=') + return opterror(options, "takes no value", flags); + if (*rest) + continue; + p->out[p->cpidx++] = arg - 2; + return 0; + } + if (!rest) { + /* abbreviated? */ + if (!strncmp(options->long_name, arg, arg_end - arg)) { +is_abbreviated: + if (abbrev_option) { + /* + * If this is abbreviated, it is + * ambiguous. So when there is no + * exact match later, we need to + * error out. + */ + ambiguous_option = abbrev_option; + ambiguous_flags = abbrev_flags; + } + if (!(flags & OPT_UNSET) && *arg_end) + p->opt = arg_end + 1; + abbrev_option = options; + abbrev_flags = flags; + continue; + } + /* negated and abbreviated very much? */ + if (!prefixcmp("no-", arg)) { + flags |= OPT_UNSET; + goto is_abbreviated; + } + /* negated? */ + if (strncmp(arg, "no-", 3)) + continue; + flags |= OPT_UNSET; + rest = skip_prefix(arg + 3, options->long_name); + /* abbreviated and negated? */ + if (!rest && !prefixcmp(options->long_name, arg + 3)) + goto is_abbreviated; + if (!rest) + continue; + } + if (*rest) { + if (*rest != '=') + continue; + p->opt = rest + 1; + } + return get_value(p, options, flags); + } + + if (ambiguous_option) + return error("Ambiguous option: %s " + "(could be --%s%s or --%s%s)", + arg, + (ambiguous_flags & OPT_UNSET) ? "no-" : "", + ambiguous_option->long_name, + (abbrev_flags & OPT_UNSET) ? "no-" : "", + abbrev_option->long_name); + if (abbrev_option) + return get_value(p, abbrev_option, abbrev_flags); + return -2; +} + + +static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, + const char **argv, int flags) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->argc = argc; + ctx->argv = argv; + ctx->out = argv; + ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); + ctx->flags = flags; + if ((flags & PARSE_OPT_KEEP_UNKNOWN) && + (flags & PARSE_OPT_STOP_AT_NON_OPTION)) + die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); +} + +static int parse_options_end(struct parse_opt_ctx_t *ctx) +{ + memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); + ctx->out[ctx->cpidx + ctx->argc] = NULL; + return ctx->cpidx + ctx->argc; +} + + +static int parse_options_step(struct parse_opt_ctx_t *ctx, + const struct option *options, const char * const usagestr[]) +{ + int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); + + /* we must reset ->opt, unknown short option leave it dangling */ + ctx->opt = NULL; + + for (; ctx->argc; ctx->argc--, ctx->argv++) { + const char *arg = ctx->argv[0]; + + if (*arg != '-' || !arg[1]) { + if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) + break; + ctx->out[ctx->cpidx++] = ctx->argv[0]; + continue; + } + + if (arg[1] != '-') { + ctx->opt = arg + 1; + if (internal_help && *ctx->opt == 'h') + return parse_options_usage(usagestr, options); + switch (parse_short_opt(ctx, options)) { + case -1: + return parse_options_usage(usagestr, options); + case -2: + goto unknown; + default: + break; + } + if (ctx->opt) + check_typos(arg + 1, options); + while (ctx->opt) { + if (internal_help && *ctx->opt == 'h') + return parse_options_usage(usagestr, options); + switch (parse_short_opt(ctx, options)) { + case -1: + return parse_options_usage(usagestr, options); + case -2: + /* fake a short option thing to hide the fact that we may have + * started to parse aggregated stuff + * + * This is leaky, too bad. + */ + ctx->argv[0] = strdup(ctx->opt - 1); + *(char *)ctx->argv[0] = '-'; + goto unknown; + default: + break; + } + } + continue; + } + + if (!arg[2]) { /* "--" */ + if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { + ctx->argc--; + ctx->argv++; + } + break; + } + + 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); + switch (parse_long_opt(ctx, arg + 2, options)) { + case -1: + return parse_options_usage(usagestr, options); + case -2: + goto unknown; + default: + break; + } + continue; +unknown: + if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) + return PARSE_OPT_UNKNOWN; + ctx->out[ctx->cpidx++] = ctx->argv[0]; + ctx->opt = NULL; + } + return PARSE_OPT_DONE; +} + +int parse_options(int argc, const char **argv, const struct option *options, + const char * const usagestr[], int flags) +{ + struct parse_opt_ctx_t ctx; + + parse_options_start(&ctx, argc, argv, flags); + switch (parse_options_step(&ctx, options, usagestr)) { + case PARSE_OPT_HELP: + exit(129); + case PARSE_OPT_DONE: + break; + default: /* PARSE_OPT_UNKNOWN */ + if (ctx.argv[0][1] == '-') { + error("unknown option `%s'", ctx.argv[0] + 2); + } else { + error("unknown switch `%c'", *ctx.opt); + } + usage_with_options(usagestr, options); + } + + return parse_options_end(&ctx); +} diff --git a/tools/kvm/util/strbuf.c b/tools/kvm/util/strbuf.c new file mode 100644 index 0000000..ec77ab1 --- /dev/null +++ b/tools/kvm/util/strbuf.c @@ -0,0 +1,13 @@ + +/* user defined headers */ +#include <kvm/strbuf.h> + +int prefixcmp(const char *str, const char *prefix) +{ + for (; ; str++, prefix++) { + if (!*prefix) + return 0; + else if (*str != *prefix) + return (unsigned char)*prefix - (unsigned char)*str; + } +}
- parse-options.[ch] has argument processing code. - types.h: Additional types for argument processing. - strbuf.[ch]: Added a function prefixcmp to compare string prefix Signed-off-by: Prasad Joshi <prasadjoshi124@gmail.com> --- tools/kvm/include/kvm/parse-options.h | 161 ++++++++++ tools/kvm/include/kvm/strbuf.h | 6 + tools/kvm/include/kvm/util.h | 8 + tools/kvm/include/linux/types.h | 12 + tools/kvm/util/parse-options.c | 560 +++++++++++++++++++++++++++++++++ tools/kvm/util/strbuf.c | 13 + 6 files changed, 760 insertions(+), 0 deletions(-) create mode 100644 tools/kvm/include/kvm/parse-options.h create mode 100644 tools/kvm/include/kvm/strbuf.h create mode 100644 tools/kvm/util/parse-options.c create mode 100644 tools/kvm/util/strbuf.c