diff --git a/Makefile b/Makefile index 6ce44b3..f2ad017 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,9 @@ LIBIFUPDOWN_SRC = \ LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o} LIBIFUPDOWN_LIB = libifupdown.a -MULTICALL_SRC = cmd/multicall.c +MULTICALL_SRC = \ + cmd/multicall.c \ + cmd/multicall-options.c MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o} MULTICALL = ifupdown diff --git a/cmd/multicall-options.c b/cmd/multicall-options.c new file mode 100644 index 0000000..415d24a --- /dev/null +++ b/cmd/multicall-options.c @@ -0,0 +1,156 @@ +/* + * cmd/multicall-options.c + * Purpose: multi-call binary frontend -- option handling + * + * Copyright (c) 2020 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "cmd/multicall.h" + +static void +generic_usage(const struct if_applet *applet, int result) +{ + fprintf(stderr, "%s", applet->name); + if (applet->desc != NULL) + fprintf(stderr, " - %s", applet->desc); + + fprintf(stderr, "\n"); + + size_t iter; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + + fprintf(stderr, "\n%s:\n", group->desc); + + size_t group_iter; + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *opt = &group->group[group_iter]; + + fprintf(stderr, " "); + + if (opt->short_opt) + fprintf(stderr, "-%c", opt->short_opt); + else + fprintf(stderr, " "); + + if (opt->long_opt) + fprintf(stderr, "%c --%-30s", opt->short_opt ? ',' : ' ', + opt->long_opt); + else + fprintf(stderr, "%34s", ""); + + fprintf(stderr, "%s\n", opt->desc); + } + } + + exit(result); +} + +static void +generic_usage_request(int short_opt, const struct if_option *option, const char *opt_arg, const struct if_applet *applet) +{ + (void) short_opt; + (void) option; + (void) opt_arg; + + generic_usage(applet, EXIT_SUCCESS); +} + +static struct if_option global_options[] = { + {'h', "help", "displays program help", false, generic_usage_request}, + {'V', "version", "displays program version", false, (void *) lif_common_version}, +}; + +struct if_option_group global_option_group = { + .desc = "Global options", + .group_size = ARRAY_SIZE(global_options), + .group = global_options +}; + +const struct if_option * +lookup_option(const struct if_applet *applet, int opt) +{ + size_t iter; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + size_t group_iter; + + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *option = &group->group[group_iter]; + + if (option->short_opt == opt) + return option; + } + } + + return NULL; +} + +void +process_options(const struct if_applet *applet, int argc, char *argv[]) +{ + char short_opts[256] = {}, *p = short_opts; + struct option long_opts[256] = {}; + + size_t iter, long_opt_iter = 0; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + size_t group_iter; + + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *opt = &group->group[group_iter]; + + if (opt->short_opt) + { + *p++ = opt->short_opt; + if (opt->require_argument) + *p++ = ':'; + } + + if (opt->long_opt) + { + /* XXX: handle long-opts without short-opts */ + long_opts[long_opt_iter] = (struct option) { + .name = opt->long_opt, + .has_arg = opt->require_argument ? required_argument : no_argument, + .val = opt->short_opt + }; + + long_opt_iter++; + } + } + } + + for (;;) + { + int c = getopt_long(argc, argv, short_opts, long_opts, NULL); + if (c == -1) + break; + + const struct if_option *opt = lookup_option(applet, c); + if (opt == NULL) + break; + + opt->handle(c, opt, optarg, applet); + } +} diff --git a/cmd/multicall.c b/cmd/multicall.c index 65bd9e9..6121776 100644 --- a/cmd/multicall.c +++ b/cmd/multicall.c @@ -35,68 +35,6 @@ struct if_applet *applet_table[] = { &ifupdown_applet, }; -static void -generic_usage(const struct if_applet *applet, int result) -{ - fprintf(stderr, "%s", applet->name); - if (applet->desc != NULL) - fprintf(stderr, " - %s", applet->desc); - - fprintf(stderr, "\n"); - - size_t iter; - for (iter = 0; applet->groups[iter] != NULL; iter++) - { - const struct if_option_group *group = applet->groups[iter]; - - fprintf(stderr, "\n%s:\n", group->desc); - - size_t group_iter; - for (group_iter = 0; group_iter < group->group_size; group_iter++) - { - const struct if_option *opt = &group->group[group_iter]; - - fprintf(stderr, " "); - - if (opt->short_opt) - fprintf(stderr, "-%c", opt->short_opt); - else - fprintf(stderr, " "); - - if (opt->long_opt) - fprintf(stderr, "%c --%-30s", opt->short_opt ? ',' : ' ', - opt->long_opt); - else - fprintf(stderr, "%34s", ""); - - fprintf(stderr, "%s\n", opt->desc); - } - } - - exit(result); -} - -static void -generic_usage_request(int short_opt, const struct if_option *option, const char *opt_arg, const struct if_applet *applet) -{ - (void) short_opt; - (void) option; - (void) opt_arg; - - generic_usage(applet, EXIT_SUCCESS); -} - -static struct if_option global_options[] = { - {'h', "help", "displays program help", false, generic_usage_request}, - {'V', "version", "displays program version", false, (void *) lif_common_version}, -}; - -struct if_option_group global_option_group = { - .desc = "Global options", - .group_size = ARRAY_SIZE(global_options), - .group = global_options -}; - int applet_cmp(const void *a, const void *b) { @@ -108,78 +46,6 @@ applet_cmp(const void *a, const void *b) void multicall_usage(int status) __attribute__((noreturn)); -static const struct if_option * -lookup_option(const struct if_applet *applet, int opt) -{ - size_t iter; - for (iter = 0; applet->groups[iter] != NULL; iter++) - { - const struct if_option_group *group = applet->groups[iter]; - size_t group_iter; - - for (group_iter = 0; group_iter < group->group_size; group_iter++) - { - const struct if_option *option = &group->group[group_iter]; - - if (option->short_opt == opt) - return option; - } - } - - return NULL; -} - -static void -process_options(const struct if_applet *applet, int argc, char *argv[]) -{ - char short_opts[256] = {}, *p = short_opts; - struct option long_opts[256] = {}; - - size_t iter, long_opt_iter = 0; - for (iter = 0; applet->groups[iter] != NULL; iter++) - { - const struct if_option_group *group = applet->groups[iter]; - size_t group_iter; - - for (group_iter = 0; group_iter < group->group_size; group_iter++) - { - const struct if_option *opt = &group->group[group_iter]; - - if (opt->short_opt) - { - *p++ = opt->short_opt; - if (opt->require_argument) - *p++ = ':'; - } - - if (opt->long_opt) - { - /* XXX: handle long-opts without short-opts */ - long_opts[long_opt_iter] = (struct option) { - .name = opt->long_opt, - .has_arg = opt->require_argument ? required_argument : no_argument, - .val = opt->short_opt - }; - - long_opt_iter++; - } - } - } - - for (;;) - { - int c = getopt_long(argc, argv, short_opts, long_opts, NULL); - if (c == -1) - break; - - const struct if_option *opt = lookup_option(applet, c); - if (opt == NULL) - break; - - opt->handle(c, opt, optarg, applet); - } -} - int main(int argc, char *argv[]) { diff --git a/cmd/multicall.h b/cmd/multicall.h index 48deb26..97056a2 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -58,4 +58,7 @@ struct match_options { char *property; }; +extern void process_options(const struct if_applet *applet, int argc, char *argv[]); +extern const struct if_option *lookup_option(const struct if_applet *applet, int opt); + #endif