diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-07-20 19:56:14 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-07-20 19:56:14 +0300 |
commit | 5f4189763ed01c32035701c0c198181456b1f3c3 (patch) | |
tree | 5ae2423d7241311b1fd0f5d488865d9f27fccf60 | |
parent | 81d07acbbfbc7ebb897edef9aa7c1b2f24272ae4 (diff) | |
download | mailutils-5f4189763ed01c32035701c0c198181456b1f3c3.tar.gz mailutils-5f4189763ed01c32035701c0c198181456b1f3c3.tar.bz2 |
New simplified interface to command line option parser.
* include/mailutils/cli.h (MU_CLI_OPTION_): New constants.
(mu_cli_simple): New proto.
* libmailutils/cli/simple.c: New file.
* libmailutils/cli/Makefile.am: Add new source.
* libmailutils/cli/cli.c (mu_cli_ext): Take into account po_special_flags
in hints. Honor MU_PARSEOPT_HELP_HOOK and MU_PARSEOPT_EXIT_ERROR set in
hints.
* libmailutils/opt/opt.c (parseopt_init): Fix improper use of
MU_PARSEOPT_PACKAGE_URL instead of MU_PARSEOPT_DATA.
-rw-r--r-- | include/mailutils/cli.h | 219 | ||||
-rw-r--r-- | libmailutils/cli/Makefile.am | 1 | ||||
-rw-r--r-- | libmailutils/cli/cli.c | 27 | ||||
-rw-r--r-- | libmailutils/cli/simple.c | 226 | ||||
-rw-r--r-- | libmailutils/opt/opt.c | 2 |
5 files changed, 469 insertions, 6 deletions
diff --git a/include/mailutils/cli.h b/include/mailutils/cli.h index 06c864464..9d2afc806 100644 --- a/include/mailutils/cli.h +++ b/include/mailutils/cli.h @@ -74,5 +74,224 @@ void mu_cli_ext (int argc, char **argv, char *mu_site_config_file (void); void mu_acl_cfg_init (void); + +/* Simplified interface */ +enum + { + MU_CLI_OPTION_END = -1, /* End of options */ + + /* Argument: struct mu_option * + * Description: Supplies the array of options. Can be given mupliple + * times. + * Ref: optv in struct mu_cli_setup. + */ + MU_CLI_OPTION_OPTIONS, + + /* Argument: struct mu_cfg_param * + * Description: Supplies configuration definitions. + * Ref: cfg in struct mu_cli_setup + */ + MU_CLI_OPTION_CONFIG, + + /* Argument: char ** + * Description: NULL-terminated array of capability strings. + * Ref: capa argument to mu_cli and mu_cli_ext. + */ + MU_CLI_OPTION_CAPABILITIES, + + /* Argument: int + * Description: Exit code to use on usage errors (default: EX_USAGE). + * Ref: ex_usage member of struct mu_cli_setup. + */ + MU_CLI_OPTION_EX_USAGE, + + /* Argument: int + * Description: Exit code to use on configuration errors (default: + * EX_CONFIG). + * Ref: ex_config member of struct mu_cli_setup. + */ + MU_CLI_OPTION_EX_CONFIG, + + /* Argument: none + * Description: Ignore usage errors. + * Ref: MU_PARSEOPT_IGNORE_ERRORS flag in opt.h + */ + MU_CLI_OPTION_IGNORE_ERRORS, + + /* Argument: int * + * Description: A pointer to store the number of command line + * arguments in. + * Ref: ret_argc argument in mu_cli and mu_cli_ext. + */ + MU_CLI_OPTION_RETURN_ARGC, + + /* Argument: char *** + * Description: A pointer to store the address of the array of + * command line arguments. + * Ref: ret_argv argument in mu_cli and mu_cli_ext. + */ + MU_CLI_OPTION_RETURN_ARGV, + + /* Argument: none + * Description: Do not reorder options and arguments. + * Ref: The inorder member of struct mu_cli_setup and + * MU_PARSEOPT_IN_ORDER flag in opt.h + */ + MU_CLI_OPTION_IN_ORDER, + + /* Argument: none + * Description: Don't provide standard options: -h, --help, --usage, + * --version. + * Ref: MU_PARSEOPT_NO_STDOPT flag in opt.h + */ + MU_CLI_OPTION_NO_STDOPT, + + /* Argument: none + * Description: Don't exit on errors + * Ref: MU_PARSEOPT_NO_ERREXIT flag in opt.h + */ + MU_CLI_OPTION_NO_ERREXIT, + + /* Argument: none + * Description: Apply all options immediately. + * Ref: MU_PARSEOPT_IMMEDIATE + */ + MU_CLI_OPTION_IMMEDIATE, + + /* Argument: none + * Description: Don't sort options in help output. + * Ref: MU_PARSEOPT_NO_SORT flag in opt.h. + */ + MU_CLI_OPTION_NO_SORT, + + /* Argument: char const * + * Description: Override the name of the program to use in error + * messages. + * Ref: MU_PARSEOPT_PROG_NAME flag in opt.h + */ + MU_CLI_OPTION_PROG_NAME, + + /* Argument: char const * + * Description: Documentation string for the program. It will be + * displayed on the line following the usage summary. + * Ref: MU_PARSEOPT_PROG_DOC + */ + MU_CLI_OPTION_PROG_DOC, + + /* Argument: char const * + * Description: Names of arguments for the program. These are + * displayed in the constructed usage summary. For example, if + * this keyword is set tp "A B" and the program name is "foo", then + * the help output will begin with + * Usage: foo A B + * + * Multiple instances are allowed. + * Ref: MU_PARSEOPT_PROG_ARGS flag in opt.h + */ + MU_CLI_OPTION_PROG_ARGS, + + /* Argument: char const * + * Description: Bug address for the package. + * Ref: MU_PARSEOPT_BUG_ADDRESS in opt.h + */ + MU_CLI_OPTION_BUG_ADDRESS, + + /* Argument: char const * + * Description: Sets the PACKAGE_NAME. + * Ref: MU_PARSEOPT_PACKAGE_NAME in opt.h + */ + MU_CLI_OPTION_PACKAGE_NAME, + + /* Argument: char const * + * Description: URL of the package. + * Ref: MU_PARSEOPT_PACKAGE_URL in opt.h + */ + MU_CLI_OPTION_PACKAGE_URL, + + /* Argument: char const * + * Description: Extra help information. This will be displayed after + * the option list. + * Ref: MU_PARSEOPT_EXTRA_INFO in opt.h + */ + MU_CLI_OPTION_EXTRA_INFO, + + /* Argument: void (*) (struct mu_parseopt *, mu_stream_t) + * Description: Pointer to a function to be called as a part of the + * --help option handling, after outputting the option list. + * Ref: po_help_hook member of struct mu_parseopt and the + * MU_PARSEOPT_HELP_HOOK flag in opt.h + */ + MU_CLI_OPTION_HELP_HOOK, + + /* Argument: void * + * Description: Call-specific configuration data. This will be passed + * as the last argument to mu_cfg_tree_reduce. + * + * Ref: mu_cfg_tree_reduce + */ + MU_CLI_OPTION_DATA, + + /* Argument: void (*) (struct mu_parseopt *, mu_stream_t) + * Description: User function to be called on --version. + * Ref: po_version_hook member of struct mu_parseopt and the + * MU_PARSEOPT_VERSION_HOOK flag in opt.h + */ + MU_CLI_OPTION_VERSION_HOOK, + + /* Argument: void (*) (struct mu_parseopt *, mu_stream_t) + * Description: Pointer to a function to be called as a part of the + * --help option handling. This function will be called after printing + * initial program description (see MU_CLI_OPTION_PROG_DOC) and before + * printing the option summary. + * Ref: + */ + MU_CLI_OPTION_PROG_DOC_HOOK, + + /* Argument: none + * Description: Long options start with single dash (a la find). Thid + * Disables recognition of traditional short options. + * Ref: MU_PARSEOPT_SINGLE_DASH flag in opt.h + */ + MU_CLI_OPTION_SINGLE_DASH, + + /* Argument: char const * + * Description: Prefix that negates the value of a boolean option. + * Ref: po_negation member of struct mu_parseopt and the + * MU_PARSEOPT_NEGATION flag in opt.h + */ + MU_CLI_OPTION_NEGATION, + + /* Argument: char const * + * Description: Descriptive names of special arguments. If given, this + * will be printed in short usage summary after the regular options. + * Ref: The po_special_args member of struct mu_parseopt and the + * MU_PARSEOPT_SPECIAL_ARGS flag in opt.h + */ + MU_CLI_OPTION_SPECIAL_ARGS, + + + /* Argument: char const * + * Description: Name of site-wide configuration file to parse. If NULL, + * the default site-wide configuration is assumed. + * Ref: The site_file member of struct mu_cfg_parse_hints and the + * MU_CFHINT_SITE_FILE flag in cfg.h + */ + MU_CLI_OPTION_CONF_SITE_FILE, + + /* Argument: none + * Description: Enable the use of per-user configuration files. + * Ref: MU_CFHINT_PER_USER_FILE flag in cfg.h + */ + MU_CLI_OPTION_CONF_PER_USER_FILE, + + /* Argument: none + * Description: Don't allow users to overide configuration settings + * from the command line. + * Ref: MU_CFHINT_NO_CONFIG_OVERRIDE flag in cfg.h + */ + MU_CLI_OPTION_CONF_NO_OVERRIDE + }; + +void mu_cli_simple (int argc, char **argv, ...); #endif diff --git a/libmailutils/cli/Makefile.am b/libmailutils/cli/Makefile.am index d600c1ae2..17b2384ef 100644 --- a/libmailutils/cli/Makefile.am +++ b/libmailutils/cli/Makefile.am @@ -21,6 +21,7 @@ libcli_la_SOURCES = \ acl.c\ capa.c\ cli.c\ + simple.c\ stdcapa.c AM_CPPFLAGS = \ diff --git a/libmailutils/cli/cli.c b/libmailutils/cli/cli.c index a4c54edf8..e048995f6 100644 --- a/libmailutils/cli/cli.c +++ b/libmailutils/cli/cli.c @@ -488,7 +488,8 @@ run_commit (void *item, void *data) | MU_PARSEOPT_EXTRA_INFO \ | MU_PARSEOPT_VERSION_HOOK \ | MU_PARSEOPT_PROG_NAME \ - | MU_PARSEOPT_NEGATION) + | MU_PARSEOPT_NEGATION \ + | MU_PARSEOPT_SPECIAL_ARGS ) void mu_cli_ext (int argc, char **argv, @@ -591,7 +592,12 @@ mu_cli_ext (int argc, char **argv, po.po_help_hook = extra_help_hook; flags |= MU_PARSEOPT_HELP_HOOK; } - + else if (pohint->po_flags & MU_PARSEOPT_HELP_HOOK) + { + po.po_help_hook = pohint->po_help_hook; + flags |= MU_PARSEOPT_HELP_HOOK; + } + if (setup->prog_doc_hook) { po.po_prog_doc_hook = prog_doc_hook; @@ -622,7 +628,20 @@ mu_cli_ext (int argc, char **argv, po.po_negation = pohint->po_negation; if (flags & MU_PARSEOPT_PROG_NAME) po.po_prog_name = pohint->po_prog_name; - + if (flags & MU_PARSEOPT_SPECIAL_ARGS) + po.po_special_args = pohint->po_special_args; + + if (setup->ex_usage) + { + po.po_exit_error = setup->ex_usage; + flags |= MU_PARSEOPT_EXIT_ERROR; + } + else if (pohint->po_flags & MU_PARSEOPT_EXIT_ERROR) + { + po.po_exit_error = pohint->po_exit_error; + flags |= MU_PARSEOPT_EXIT_ERROR; + } + appd.setup = setup; appd.hints = &hints; appd.append_tree = NULL; @@ -630,8 +649,6 @@ mu_cli_ext (int argc, char **argv, po.po_data = &appd; flags |= MU_PARSEOPT_DATA; - po.po_exit_error = setup->ex_usage; - mu_opool_create (&pool, MU_OPOOL_ENOMEMABRT); optv = init_options (pool, capa, setup, &hints, &com_list); diff --git a/libmailutils/cli/simple.c b/libmailutils/cli/simple.c new file mode 100644 index 000000000..0daef170d --- /dev/null +++ b/libmailutils/cli/simple.c @@ -0,0 +1,226 @@ +/* cli.c -- Command line interface for GNU Mailutils + Copyright (C) 2016-2020 Free Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or (at + your option) any later version. + + GNU Mailutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <mailutils/cfg.h> +#include <mailutils/opt.h> +#include <mailutils/cli.h> +#include <mailutils/nls.h> + +void +mu_cli_simple (int argc, char **argv, ...) +{ + struct mu_cli_setup setup; + struct mu_parseopt pohint; + struct mu_cfg_parse_hints cfhint; + char **capa = NULL; + void *data = NULL; + int *ret_argc = NULL; + char ***ret_argv = NULL; + + mu_opool_t args_pool = NULL, optv_pool = NULL; + + va_list ap; + int opt; + + memset (&setup, 0, sizeof (setup)); + memset (&pohint, 0, sizeof (pohint)); + memset (&cfhint, 0, sizeof (cfhint)); + + va_start (ap, argv); + while ((opt = va_arg (ap, int)) != MU_CLI_OPTION_END) + { + switch (opt) + { + case MU_CLI_OPTION_OPTIONS: + { + struct mu_option *p; + if (!optv_pool) + mu_opool_create (&optv_pool, MU_OPOOL_ENOMEMABRT); + p = va_arg (ap, struct mu_option *); + mu_opool_append (optv_pool, &p, sizeof p); + } + break; + + case MU_CLI_OPTION_CONFIG: + setup.cfg = va_arg (ap, struct mu_cfg_param *); + break; + + case MU_CLI_OPTION_CAPABILITIES: + capa = va_arg (ap, char **); + break; + + case MU_CLI_OPTION_EX_USAGE: + setup.ex_usage = va_arg (ap, int); + break; + + case MU_CLI_OPTION_EX_CONFIG: + setup.ex_config = va_arg (ap, int); + break; + + case MU_CLI_OPTION_DATA: + data = va_arg (ap, void *); + break; + + case MU_CLI_OPTION_IN_ORDER: + setup.inorder = 1; + break; + + case MU_CLI_OPTION_RETURN_ARGC: + ret_argc = va_arg (ap, int *); + break; + + case MU_CLI_OPTION_RETURN_ARGV: + ret_argv = va_arg (ap, char ***); + break; + + case MU_CLI_OPTION_IGNORE_ERRORS: + pohint.po_flags |= MU_PARSEOPT_IGNORE_ERRORS; + break; + + case MU_CLI_OPTION_NO_STDOPT: + pohint.po_flags |= MU_PARSEOPT_NO_STDOPT; + break; + + case MU_CLI_OPTION_NO_ERREXIT: + pohint.po_flags |= MU_PARSEOPT_NO_ERREXIT; + break; + + case MU_CLI_OPTION_IMMEDIATE: + pohint.po_flags |= MU_PARSEOPT_IMMEDIATE; + break; + + case MU_CLI_OPTION_NO_SORT: + pohint.po_flags |= MU_PARSEOPT_NO_SORT; + break; + + case MU_CLI_OPTION_SINGLE_DASH: + pohint.po_flags |= MU_PARSEOPT_SINGLE_DASH; + break; + + case MU_CLI_OPTION_PROG_NAME: + pohint.po_flags |= MU_PARSEOPT_PROG_NAME; + pohint.po_prog_name = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_PROG_DOC: + pohint.po_flags |= MU_PARSEOPT_PROG_DOC; + pohint.po_prog_doc = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_PROG_ARGS: + { + char *p; + if (!args_pool) + mu_opool_create (&args_pool, MU_OPOOL_ENOMEMABRT); + p = va_arg (ap, char *); + mu_opool_append (args_pool, &p, sizeof p); + } + break; + + case MU_CLI_OPTION_BUG_ADDRESS: + pohint.po_flags |= MU_PARSEOPT_BUG_ADDRESS; + pohint.po_bug_address = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_PACKAGE_NAME: + pohint.po_flags |= MU_PARSEOPT_PACKAGE_NAME; + pohint.po_package_name = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_PACKAGE_URL: + pohint.po_flags |= MU_PARSEOPT_PACKAGE_URL; + pohint.po_package_url = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_EXTRA_INFO: + pohint.po_flags |= MU_PARSEOPT_EXTRA_INFO; + pohint.po_extra_info = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_HELP_HOOK: + pohint.po_flags |= MU_PARSEOPT_HELP_HOOK; + pohint.po_help_hook = + va_arg (ap, void (*) (struct mu_parseopt *, mu_stream_t)); + break; + + case MU_CLI_OPTION_VERSION_HOOK: + pohint.po_flags |= MU_PARSEOPT_VERSION_HOOK; + pohint.po_version_hook = + va_arg (ap, void (*) (struct mu_parseopt *, mu_stream_t)); + break; + + case MU_CLI_OPTION_PROG_DOC_HOOK: + pohint.po_flags |= MU_PARSEOPT_PROG_DOC_HOOK; + pohint.po_prog_doc_hook = + va_arg (ap, void (*) (struct mu_parseopt *, mu_stream_t)); + break; + + case MU_CLI_OPTION_NEGATION: + pohint.po_flags |= MU_PARSEOPT_NEGATION; + pohint.po_negation = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_SPECIAL_ARGS: + pohint.po_flags |= MU_PARSEOPT_SPECIAL_ARGS; + pohint.po_special_args = va_arg (ap, char *); + break; + + case MU_CLI_OPTION_CONF_SITE_FILE: + if ((cfhint.site_file = va_arg (ap, char *)) == NULL) + cfhint.site_file = mu_site_config_file (); + cfhint.flags = MU_CFHINT_SITE_FILE; + break; + + case MU_CLI_OPTION_CONF_PER_USER_FILE: + cfhint.flags |= MU_CFHINT_PER_USER_FILE; + break; + + case MU_CLI_OPTION_CONF_NO_OVERRIDE: + cfhint.flags |= MU_CFHINT_NO_CONFIG_OVERRIDE; + break; + + default: + mu_diag_output (MU_DIAG_CRIT, + _("%s:%d: INTERNAL ERROR: unrecognized mu_cli_simple option"), + __FILE__, __LINE__); + abort (); + } + } + if (optv_pool) + { + struct mu_option *p = NULL; + mu_opool_append (optv_pool, &p, sizeof p); + setup.optv = mu_opool_finish (optv_pool, NULL); + } + if (args_pool) + { + char *p = NULL; + mu_opool_append (args_pool, &p, sizeof p); + pohint.po_prog_args = mu_opool_finish (args_pool, NULL); + pohint.po_flags |= MU_PARSEOPT_PROG_ARGS; + } + mu_cli_ext (argc, argv, &setup, &pohint, &cfhint, capa, data, + ret_argc, ret_argv); + mu_opool_destroy (&args_pool); + mu_opool_destroy (&optv_pool); + va_end (ap); +} diff --git a/libmailutils/opt/opt.c b/libmailutils/opt/opt.c index ab598bbbf..8f5be3b9b 100644 --- a/libmailutils/opt/opt.c +++ b/libmailutils/opt/opt.c @@ -659,7 +659,7 @@ parseopt_init (struct mu_parseopt *po, struct mu_option **options, po->po_package_name = NULL; if (!(flags & MU_PARSEOPT_PACKAGE_URL)) po->po_package_url = NULL; - if (!(flags & MU_PARSEOPT_PACKAGE_URL)) + if (!(flags & MU_PARSEOPT_DATA)) po->po_data = NULL; if (!(flags & MU_PARSEOPT_EXTRA_INFO)) po->po_extra_info = NULL; |