author | Sergey Poznyakoff <gray@gnu.org> | 2016-10-11 14:20:38 (GMT) |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-10-11 14:36:10 (GMT) |
commit | bc73fc65600b6021dfe7a9fa1fba7e9b823993e2 (patch) (side-by-side diff) | |
tree | 934b239ddd68b1bc91a42b66ddccfe3bcf01accf /libmailutils | |
parent | 6e8147334cf9ffe36367760c06002a1e5b7ae0d5 (diff) | |
download | mailutils-bc73fc65600b6021dfe7a9fa1fba7e9b823993e2.tar.gz mailutils-bc73fc65600b6021dfe7a9fa1fba7e9b823993e2.tar.bz2 |
Introduce new CLI/configuration code for mailutils applications.
The new API is to replace libmu_cfg and libmu_argp. A smooth transition
is scheduled, during which the two APIs will coexist,
* configure.ac: Build libmailutils/cli/Makefile
* include/mailutils/cli.h: New file.
* include/mailutils/Makefile.am: Add cli.h
* libmailutils/cli/Makefile.am: New file.
* libmailutils/cli/capa.c: New file.
* libmailutils/cli/cli.c: New file.
* libmailutils/cli/stdcapa.c: New file.
* libmailutils/Makefile.am (SUBDIRS): Add cli.
* include/mailutils/cfg.h (mu_cfg_parse_hints): New members: append_tree
and data.
(MU_PARSE_CONFIG_LINT): New flag.
* include/mailutils/diag.h (mu_program_name)
(mu_full_program_name): Remove const qualifier.
* include/mailutils/locker.h (mu_locker_set_default_external_program):
Argument is const.
* libmailutils/base/locker.c: Likewise.
* include/mailutils/opt.h (mu_progname, mu_absprogname): Replace
with mu_program_name and mu_full_program_name.
(mu_set_progname): Rename to mu_set_program_name.
(mu_parseopt) <po_data>: Change type to void *.
(po_help_hook, po_version_hook): Change signatures.
(mu_parseopt_error): New function.
* libmailutils/opt/progname.c (mu_progname, mu_absprogname): Replace
with mu_program_name and mu_full_program_name.
(mu_set_progname): Rename to mu_set_program_name.
* libmailutils/opt/help.c: Minor changes
* libmailutils/opt/opt.c (parse_error): Rename to mu_parse_error (extern).
(next_opt): Fix permutations.
* libmailutils/tests/parseopt.c: Reflect changes.
* libmailutils/tests/parseopt17.at: Improve test case
* libmailutils/tests/parseopt_help05.at: Reflect changes.
* libmailutils/tests/parseopt_help07.at: Reflect changes.
* include/mailutils/stdstream.h (mu_program_name): Remove qualifier.
* libmailutils/cfg/driver.c (mu_cfg_tree_reduce): Remove useless condition
* libmailutils/cfg/lexer.l (mu_cfg_parse_file): Additional info messages.
* libmailutils/cfg/parser.y (mu_cfg_parse_config): Join in
the append_tree.
* libmailutils/diag/diag.c (mu_program_name, mu_full_program_name)
(mu_set_program_name): Remove. Declared elsewhere.
* libmu_sieve/conf.c: Add new configuration code. Mark old text for
removal.
* libmailutils/tests/tcli.c: New program.
* libmailutils/tests/Makefile.am: Add tcli.c
-rw-r--r-- | libmailutils/Makefile.am | 3 | ||||
-rw-r--r-- | libmailutils/base/locker.c | 2 | ||||
-rw-r--r-- | libmailutils/cfg/driver.c | 12 | ||||
-rw-r--r-- | libmailutils/cfg/lexer.l | 6 | ||||
-rw-r--r-- | libmailutils/cfg/parser.y | 5 | ||||
-rw-r--r-- | libmailutils/cli/Makefile.am | 26 | ||||
-rw-r--r-- | libmailutils/cli/capa.c | 96 | ||||
-rw-r--r-- | libmailutils/cli/cli.c | 420 | ||||
-rw-r--r-- | libmailutils/cli/stdcapa.c | 466 | ||||
-rw-r--r-- | libmailutils/diag/diag.c | 26 | ||||
-rw-r--r-- | libmailutils/opt/help.c | 8 | ||||
-rw-r--r-- | libmailutils/opt/opt.c | 24 | ||||
-rw-r--r-- | libmailutils/opt/progname.c | 14 | ||||
-rw-r--r-- | libmailutils/tests/.gitignore | 1 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 1 | ||||
-rw-r--r-- | libmailutils/tests/parseopt.c | 4 | ||||
-rw-r--r-- | libmailutils/tests/parseopt17.at | 20 | ||||
-rw-r--r-- | libmailutils/tests/parseopt_help05.at | 2 | ||||
-rw-r--r-- | libmailutils/tests/parseopt_help07.at | 2 | ||||
-rw-r--r-- | libmailutils/tests/tcli.c | 75 |
20 files changed, 1149 insertions, 64 deletions
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index 7a5270c..82550c2 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -17,7 +17,7 @@ # <http://www.gnu.org/licenses/>. SUBDIRS = \ - auth base address list sockaddr cidr cfg diag\ + auth base address list sockaddr cidr cfg cli diag\ filter mailbox mailer mime msgset opt server string stream stdstream\ property url imapio datetime . tests @@ -33,6 +33,7 @@ libmailutils_la_LIBADD = \ sockaddr/libsockaddr.la\ cidr/libcidr.la\ cfg/libcfg.la\ + cli/libcli.la\ datetime/libdatetime.la\ diag/libdiag.la\ filter/libfilter.la\ diff --git a/libmailutils/base/locker.c b/libmailutils/base/locker.c index b4663b9..c4fe993 100644 --- a/libmailutils/base/locker.c +++ b/libmailutils/base/locker.c @@ -242,7 +242,7 @@ mu_locker_set_default_expire_timeout (time_t t) } int -mu_locker_set_default_external_program (char *path) +mu_locker_set_default_external_program (char const *path) { char *p = strdup (path); if (!p) diff --git a/libmailutils/cfg/driver.c b/libmailutils/cfg/driver.c index c0cd2d5..f2a43a3 100644 --- a/libmailutils/cfg/driver.c +++ b/libmailutils/cfg/driver.c @@ -463,7 +463,7 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, void *target_ptr) { int rc = 0; - + struct mu_cfg_cont *cont; if (!parse_tree) return 0; if (hints && (hints->flags & MU_PARSE_CONFIG_DUMP)) @@ -477,13 +477,9 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, mu_stream_destroy (&stream); } - if (root_container) - { - struct mu_cfg_cont *cont = mu_build_container (progparam); - rc = mu_cfg_scan_tree (parse_tree, &cont->v.section, target_ptr, - NULL); - mu_config_destroy_container (&cont); - } + cont = mu_build_container (progparam); + rc = mu_cfg_scan_tree (parse_tree, &cont->v.section, target_ptr, NULL); + mu_config_destroy_container (&cont); return rc; } diff --git a/libmailutils/cfg/lexer.l b/libmailutils/cfg/lexer.l index 40598a1..b6c49ec 100644 --- a/libmailutils/cfg/lexer.l +++ b/libmailutils/cfg/lexer.l @@ -330,10 +330,16 @@ mu_cfg_parse_file (mu_cfg_tree_t **return_tree, const char *file, int flags) int rc; char *full_name = mu_tilde_expansion (file, MU_HIERARCHY_DELIMITER, NULL); + if (flags & MU_PARSE_CONFIG_VERBOSE) + mu_diag_output (MU_DIAG_INFO, _("opening configuration file %s"), + full_name); if (stat (full_name, &st)) { if (errno != ENOENT) mu_error (_("cannot stat `%s': %s"), full_name, mu_strerror (errno)); + else if (flags & MU_PARSE_CONFIG_VERBOSE) + mu_diag_output (MU_DIAG_INFO, _("configuration file %s doesn't exist"), + full_name); free (full_name); return ENOENT; } diff --git a/libmailutils/cfg/parser.y b/libmailutils/cfg/parser.y index e36b513..043f7e0 100644 --- a/libmailutils/cfg/parser.y +++ b/libmailutils/cfg/parser.y @@ -1589,7 +1589,10 @@ mu_cfg_parse_config (mu_cfg_tree_t **ptree, struct mu_cfg_parse_hints *hints) mu_cfg_tree_union (&tree, &tmp); } } - + + if (hints->append_tree) + mu_cfg_tree_union (&tree, &hints->append_tree); + *ptree = tree; return rc; } diff --git a/libmailutils/cli/Makefile.am b/libmailutils/cli/Makefile.am new file mode 100644 index 0000000..48770e8 --- a/dev/null +++ b/libmailutils/cli/Makefile.am @@ -0,0 +1,26 @@ +# GNU Mailutils -- a suite of utilities for electronic mail +# Copyright (C) 2016 Free Software Foundation, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General +# Public License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +noinst_LTLIBRARIES = libcli.la + +libcli_la_SOURCES = \ + capa.c\ + cli.c\ + stdcapa.c + +AM_CPPFLAGS = \ + @MU_LIB_COMMON_INCLUDES@ -I/libmailutils diff --git a/libmailutils/cli/capa.c b/libmailutils/cli/capa.c new file mode 100644 index 0000000..bd5c557 --- a/dev/null +++ b/libmailutils/cli/capa.c @@ -0,0 +1,96 @@ +/* capa.c -- CLI capabilities for GNU Mailutils + Copyright (C) 2016 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 <string.h> +#include <mailutils/cli.h> +#include <mailutils/list.h> +#include <mailutils/alloc.h> +#include <mailutils/nls.h> + +static mu_list_t capa_list; + +static void +capa_free (void *ptr) +{ + struct mu_cli_capa *cp = ptr; + free (cp->name); + free (cp); +} + +void +mu_cli_capa_register (struct mu_cli_capa *capa) +{ + struct mu_cli_capa *cp = mu_alloc (sizeof (*cp)); + cp->name = mu_strdup (capa->name); + cp->opt = capa->opt; + cp->cfg = capa->cfg; + cp->parser = capa->parser; + cp->commit = capa->commit; + if (!capa_list) + { + mu_list_create (&capa_list); + mu_list_set_destroy_item (capa_list, capa_free); + } + mu_list_append (capa_list, cp); +} + +struct capa_apply +{ + char const *name; + mu_list_t opts; + mu_list_t commits; + int found; +}; + +static int +capa_apply (void *item, void *data) +{ + struct mu_cli_capa *cp = item; + struct capa_apply *ap = data; + + if (strcmp (cp->name, ap->name) == 0) + { + ap->found = 1; + if (cp->opt) + mu_list_append (ap->opts, cp->opt); + if (cp->commit) + mu_list_append (ap->commits, cp->commit); + if (cp->parser || cp->cfg) + mu_config_root_register_section (NULL, cp->name, NULL, + cp->parser, cp->cfg); + } + return 0; +} + +void +mu_cli_capa_apply (char const *name, mu_list_t opts, mu_list_t commits) +{ + struct capa_apply app; + app.name = name; + app.opts = opts; + app.commits = commits; + app.found = 0; + mu_list_foreach (capa_list, capa_apply, &app); + if (!app.found) + mu_error (_("INTERNAL ERROR at %s:%d: unknown standard capability `%s'"), + __FILE__, __LINE__, name); +} + + diff --git a/libmailutils/cli/cli.c b/libmailutils/cli/cli.c new file mode 100644 index 0000000..2be1af8 --- a/dev/null +++ b/libmailutils/cli/cli.c @@ -0,0 +1,420 @@ +/* cli.c -- Command line interface for GNU Mailutils + Copyright (C) 2016 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 <sysexits.h> +#include <mailutils/cfg.h> +#include <mailutils/opt.h> +#include <mailutils/cli.h> +#include <mailutils/list.h> +#include <mailutils/alloc.h> +#include <mailutils/nls.h> +#include <mailutils/errno.h> +#include <mailutils/version.h> +#include <mailutils/stream.h> +#include <mailutils/stdstream.h> +#include <mailutils/io.h> +#include <mailutils/syslog.h> + +#ifndef MU_SITE_CONFIG_FILE +# define MU_SITE_CONFIG_FILE SYSCONFDIR "/mailutils.rc" +#endif + +char * +mu_site_config_file (void) +{ + char *p = getenv ("MU_SITE_CONFIG_FILE"); + if (p) + return p; + return MU_SITE_CONFIG_FILE; +} + + +const char mu_version_copyright[] = + /* Do *not* mark this string for translation. %s is a copyright + symbol suitable for this locale, and %d is the copyright + year. */ + "Copyright %s 2007-2016 Free Software Foundation, inc."; + +void +mu_version_func (struct mu_parseopt *po, FILE *stream) +{ +#ifdef GIT_DESCRIBE + fprintf (stream, "%s (%s) %s [%s]\n", + mu_program_name, PACKAGE_NAME, PACKAGE_VERSION, GIT_DESCRIBE); +#else + fprintf (stream, "%s (%s) %s\n", mu_program_name, + PACKAGE_NAME, PACKAGE_VERSION); +#endif + /* TRANSLATORS: Translate "(C)" to the copyright symbol + (C-in-a-circle), if this symbol is available in the user's + locale. Otherwise, do not translate "(C)"; leave it as-is. */ + fprintf (stream, mu_version_copyright, _("(C)")); + fputs (_("\ +\n\ +License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\n\ +\n\ +"), + stream); +} + +static char gnu_general_help_url[] = + N_("General help using GNU software: <http://www.gnu.org/gethelp/>"); + + +static void +change_progname (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + po->po_prog_name = mu_strdup (arg); +} + +static void +no_user_config (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + struct mu_cfg_parse_hints *hints = po->po_data; + hints->flags &= ~MU_CFG_PARSE_PROGRAM; +} + +static void +no_site_config (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + struct mu_cfg_parse_hints *hints = po->po_data; + hints->flags &= ~MU_CFG_PARSE_SITE_RCFILE; +} + +static void +config_file (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + struct mu_cfg_parse_hints *hints = po->po_data; + hints->flags |= MU_CFG_PARSE_CUSTOM_RCFILE; + hints->custom_rcfile = mu_strdup (arg); +} + +static void +config_verbose (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + struct mu_cfg_parse_hints *hints = po->po_data; + if (hints->flags & MU_PARSE_CONFIG_VERBOSE) + hints->flags |= MU_PARSE_CONFIG_DUMP; + else + hints->flags |= MU_PARSE_CONFIG_VERBOSE; +} + +static void +config_lint (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + struct mu_cfg_parse_hints *hints = po->po_data; + hints->flags |= MU_PARSE_CONFIG_VERBOSE|MU_PARSE_CONFIG_LINT; +} + +static void +param_set (struct mu_parseopt *po, struct mu_option *opt, char const *arg) +{ + struct mu_cfg_parse_hints *hints = po->po_data; + mu_cfg_node_t *node; + int rc = mu_cfg_create_subtree (arg, &node); + if (rc) + mu_parseopt_error (po, "%s: cannot create node: %s", + arg, mu_strerror (rc)); + if (!hints->append_tree) + mu_cfg_tree_create (&hints->append_tree); + mu_cfg_tree_add_node (hints->append_tree, node); +} + +struct mu_option mu_common_options[] = { + MU_OPTION_GROUP(N_("Common options")), + { "program-name", 0, N_("NAME"), MU_OPTION_IMMEDIATE|MU_OPTION_HIDDEN, + N_("set program name"), + mu_c_string, NULL, change_progname }, + + { "no-user-config", 0, NULL, MU_OPTION_IMMEDIATE, + N_("do not load user configuration file"), + mu_c_string, NULL, no_user_config }, + { "no-user-rcfile", 0, NULL, MU_OPTION_ALIAS }, + + { "no-site-config", 0, NULL, MU_OPTION_IMMEDIATE, + N_("do not load user configuration file"), + mu_c_string, NULL, no_site_config }, + { "no-site-rcfile", 0, NULL, MU_OPTION_ALIAS }, + + { "config-file", 0, N_("FILE"), MU_OPTION_IMMEDIATE, + N_("load this configuration file"), + mu_c_string, NULL, config_file }, + { "rcfile", 0, NULL, MU_OPTION_ALIAS }, + + { "config-verbose", 0, NULL, MU_OPTION_IMMEDIATE, + N_("verbosely log parsing of the configuration files"), + mu_c_string, NULL, config_verbose }, + { "rcfile-verbose", 0, NULL, MU_OPTION_ALIAS }, + + { "config-lint", 0, NULL, MU_OPTION_IMMEDIATE, + N_("check configuration file syntax and exit"), + mu_c_string, NULL, config_lint }, + { "rcfile-lint", 0, NULL, MU_OPTION_ALIAS }, + + { "set", 0, N_("PARAM=VALUE"), MU_OPTION_IMMEDIATE, + N_("set configuration parameter"), + mu_c_string, NULL, param_set }, + + MU_OPTION_END +}; + +static void +show_comp_defaults (struct mu_parseopt *po, struct mu_option *opt, + char const *unused) +{ + mu_print_options (); + exit (0); +} + +static void +show_config_help (struct mu_parseopt *po, struct mu_option *opt, + char const *unused) +{ + struct mu_cfg_parse_hints *hints = po->po_data; + + char *comment; + mu_stream_t stream; + struct mu_cfg_cont *cont; + static struct mu_cfg_param dummy_include_param[] = { + { "include", mu_c_string, NULL, 0, NULL, + N_("Include contents of the given file. If a directory is given, " + "include contents of the file <file>/<program>, where " + "<program> is the name of the program. This latter form is " + "allowed only in the site-wide configuration file."), + N_("file-or-directory") }, + { NULL } + }; + + mu_stdio_stream_create (&stream, MU_STDOUT_FD, 0); + + mu_asprintf (&comment, + "Configuration file structure for %s utility.", + po->po_prog_name); + mu_cfg_format_docstring (stream, comment, 0); + free (comment); + + mu_asprintf (&comment, + "For use in global configuration file (%s), enclose it " + "in `program %s { ... };", + mu_site_config_file (), + po->po_prog_name); + mu_cfg_format_docstring (stream, comment, 0); + free (comment); + + /* FIXME: %s should be replaced by the canonical utility name */ + mu_asprintf (&comment, "For more information, use `info %s'.", + po->po_prog_name); + mu_cfg_format_docstring (stream, comment, 0); + free (comment); + + cont = mu_config_clone_root_container (); + mu_config_container_register_section (&cont, NULL, NULL, NULL, NULL, + dummy_include_param, NULL); + if (hints->data) + mu_config_container_register_section (&cont, NULL, NULL, NULL, NULL, + hints->data, NULL); + mu_cfg_format_container (stream, cont); + mu_config_destroy_container (&cont); + + mu_stream_destroy (&stream); + exit (0); +} + +struct mu_option mu_extra_help_options[] = { + MU_OPTION_GROUP (N_("Informational options")), + { "show-config-options", 0, NULL, MU_OPTION_IMMEDIATE, + N_("show compilation options"), + mu_c_string, NULL, show_comp_defaults }, + { "config-help", 0, NULL, MU_OPTION_IMMEDIATE, + N_("show configuration file summary"), + mu_c_string, NULL, show_config_help }, + MU_OPTION_END +}; + + +static int +add_opt_group (void *item, void *data) +{ + struct mu_parseopt *po = data; + struct mu_option *opt = item; + po->po_optv[po->po_optc++] = opt; + return 0; +} + +/* Build the list of option groups and configuration sections */ +static struct mu_option ** +init_options (char **capa, struct mu_cli_setup *setup, + mu_list_t *ret_comlist) +{ + size_t i, s; + mu_list_t oplist; + struct mu_parseopt po; + + mu_list_create (&oplist); + if (setup->optv) + { + for (i = 0; setup->optv[i]; i++) + mu_list_append (oplist, setup->optv[i]); + } + if (capa) + { + mu_list_t comlist; + mu_list_create (&comlist); + for (i = 0; capa[i]; i++) + mu_cli_capa_apply (capa[i], oplist, comlist); + *ret_comlist = comlist; + } + else + *ret_comlist = NULL; + + mu_list_append (oplist, mu_common_options); + mu_list_append (oplist, mu_extra_help_options); + + mu_list_count (oplist, &s); + + po.po_optv = mu_calloc (s + 1, sizeof (po.po_optv[0])); + po.po_optc = 0; + mu_list_foreach (oplist, add_opt_group, &po); + if (po.po_optc != s) + abort (); + po.po_optv[po.po_optc] = NULL; + mu_list_destroy (&oplist); + return po.po_optv; +} + +static int +run_commit (void *item, void *data) +{ + mu_cli_capa_commit_fp commit = item; + commit (data); + return 0; +} + +void +mu_cli (int argc, char **argv, struct mu_cli_setup *setup, char **capa, + void *data, + int *ret_argc, char ***ret_argv) +{ + struct mu_parseopt po; + int flags = 0; + struct mu_cfg_tree *parse_tree = NULL; + struct mu_cfg_parse_hints hints; + struct mu_option **optv; + mu_list_t com_list; + + /* Set program name */ + mu_set_program_name (argv[0]); + + if (!mu_log_tag) + mu_log_tag = (char*)mu_program_name; + + /* Initialize standard streams */ + mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); + + /* Initialize standard capabilities */ + mu_cli_capa_init (); + + /* Initialize hints */ + memset (&hints, 0, sizeof (hints)); + hints.flags |= MU_CFG_PARSE_SITE_RCFILE; + hints.site_rcfile = mu_site_config_file (); + + hints.flags |= MU_CFG_PARSE_PROGRAM; + hints.program = (char*) mu_program_name; + + hints.data = setup->cfg; + + /* Initialize po */ + if (setup->prog_doc) + { + po.po_prog_doc = setup->prog_doc; + flags |= MU_PARSEOPT_PROG_DOC; + } + + if (setup->prog_args) + { + po.po_prog_args = setup->prog_args; + flags |= MU_PARSEOPT_PROG_ARGS; + } + + po.po_package_name = PACKAGE_NAME; + flags |= MU_PARSEOPT_PACKAGE_NAME; + + po.po_package_url = PACKAGE_URL; + flags |= MU_PARSEOPT_PACKAGE_URL; + + po.po_bug_address = PACKAGE_BUGREPORT; + flags |= MU_PARSEOPT_BUG_ADDRESS; + + po.po_extra_info = gnu_general_help_url; + flags |= MU_PARSEOPT_EXTRA_INFO; + + po.po_version_hook = mu_version_func; + flags |= MU_PARSEOPT_VERSION_HOOK; + + po.po_data = &hints; + flags |= MU_PARSEOPT_DATA; + + po.po_exit_error = EX_USAGE; + + optv = init_options (capa, setup, &com_list); + + if (mu_parseopt (&po, argc, argv, optv, flags)) + exit (EX_USAGE); + + argc -= po.po_arg_start; + argv += po.po_arg_start; + + if (ret_argc) + { + *ret_argc = argc; + *ret_argv = argv; + } + else if (argc) + mu_parseopt_error (&po, "%s", _("unexpected arguments")); + + if (mu_cfg_parse_config (&parse_tree, &hints)) + exit (EX_CONFIG); + + if (mu_cfg_tree_reduce (parse_tree, &hints, setup->cfg, data)) + exit (EX_CONFIG); + + if (mu_cfg_error_count) //FIXME + exit (EX_CONFIG); + + mu_parseopt_apply (&po); + + mu_list_foreach (com_list, run_commit, NULL); + mu_list_destroy (&com_list); + + if (hints.flags & MU_PARSE_CONFIG_LINT) + exit (0); + + mu_cfg_destroy_tree (&parse_tree); + free (optv); + mu_parseopt_free (&po); +} diff --git a/libmailutils/cli/stdcapa.c b/libmailutils/cli/stdcapa.c new file mode 100644 index 0000000..3b1cabe --- a/dev/null +++ b/libmailutils/cli/stdcapa.c @@ -0,0 +1,466 @@ +/* stdcapa.c -- Standard CLI capabilities for GNU Mailutils + Copyright (C) 2016 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 <mailutils/cli.h> +#include <mailutils/cfg.h> +#include <mailutils/nls.h> +#include <mailutils/syslog.h> +#include <mailutils/stdstream.h> +#include <mailutils/mailer.h> +#include <mailutils/errno.h> +#include <mailutils/mailbox.h> +#include <mailutils/registrar.h> +#include <mailutils/locker.h> + +/* ************************************************************************* + * Logging section + * ************************************************************************* */ +static void +cli_log_facility (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + if (mu_string_to_syslog_facility (arg, &mu_log_facility)) + mu_parseopt_error (po, _("unknown syslog facility `%s'"), arg); +} + +static int +cb_facility (void *data, mu_config_value_t *val) +{ + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + + if (mu_string_to_syslog_facility (val->v.string, &mu_log_facility)) + { + mu_error (_("unknown syslog facility `%s'"), val->v.string); + return 1; + } + return 0; +} + +static int +cb_severity (void *data, mu_config_value_t *val) +{ + unsigned n; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + if (mu_severity_from_string (val->v.string, &n)) + { + mu_error (_("unknown severity `%s'"), val->v.string); + return 1; + } + mu_log_severity_threshold = n; + return 0; +} + +static struct mu_cfg_param logging_cfg[] = { + { "syslog", mu_c_bool, &mu_log_syslog, 0, NULL, + N_("Send diagnostics to syslog.") }, + { "print-severity", mu_c_bool, &mu_log_print_severity, 0, NULL, + N_("Print message severity levels.") }, + { "severity", mu_cfg_callback, NULL, 0, cb_severity, + N_("Output only messages with a severity equal to or greater than " + "this one."), + N_("arg: string")}, + { "facility", mu_cfg_callback, NULL, 0, cb_facility, + N_("Set syslog facility. Arg is one of the following: user, daemon, " + "auth, authpriv, mail, cron, local0 through local7 (case-insensitive), " + "or a facility number."), + N_("arg: string") }, + { "session-id", mu_c_bool, &mu_log_session_id, 0, NULL, + N_("Log session ID") }, + { "tag", mu_c_string, &mu_log_tag, 0, NULL, + N_("Tag syslog messages with this string.") }, + { NULL } +}; + +static struct mu_option logging_option[] = { + { "log-facility", 0, N_("FACILITY"), MU_OPTION_DEFAULT, + N_("output logs to syslog FACILITY"), + mu_c_int, &mu_log_facility, cli_log_facility }, + MU_OPTION_END +}; + +static void +logging_commit (void *unused) +{ + if (mu_log_syslog >= 0) + mu_stdstream_strerr_setup (mu_log_syslog ? + MU_STRERR_SYSLOG : MU_STRERR_STDERR); +} + +/* ************************************************************************* + * Mailer + * ************************************************************************* */ +static void +cli_mailer (struct mu_parseopt *po, struct mu_option *opt, char const *arg) +{ + int rc = mu_mailer_set_url_default (arg); + if (rc != 0) + mu_parseopt_error (po, _("invalid mailer URL `%s': %s"), + arg, mu_strerror (rc)); +} + +static struct mu_option mailer_option[] = { + { "mailer", 'M', N_("MAILER"), MU_OPTION_DEFAULT, + N_("use specified URL as the default mailer"), + mu_c_string, NULL, cli_mailer }, + MU_OPTION_END +}; + +static int +cb_mailer (void *data, mu_config_value_t *val) +{ + int rc; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + rc = mu_mailer_set_url_default (val->v.string); + if (rc != 0) + mu_error (_("%s: invalid mailer URL: %s"), + val->v.string, mu_strerror (rc)); + return rc; +} + +static struct mu_cfg_param mailer_cfg[] = { + { "url", mu_cfg_callback, NULL, 0, cb_mailer, + N_("Use this URL as the default mailer"), + N_("url: string") }, + { NULL } +}; + +/* ************************************************************************* + * Debugging + * ************************************************************************* */ +static void +cli_debug_level (struct mu_parseopt *po, struct mu_option *opt, + char const *arg) +{ + mu_debug_clear_all (); + mu_debug_parse_spec (arg); + /* FIXME: Error handling */ +} + +static struct mu_option debug_option[] = { + MU_OPTION_GROUP (N_("Global debugging settings")), + { "debug-level", 0, N_("LEVEL"), MU_OPTION_DEFAULT, + N_("set Mailutils debugging level"), + mu_c_string, NULL, cli_debug_level }, + { "debug-line-info", 0, NULL, MU_OPTION_DEFAULT, + N_("show source info with debugging messages"), + mu_c_bool, &mu_debug_line_info }, + MU_OPTION_END +}; + +static int +cb_debug_level (void *data, mu_config_value_t *val) +{ + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + mu_debug_parse_spec (val->v.string); + return 0; +} + +static struct mu_cfg_param debug_cfg[] = { + { "level", mu_cfg_callback, NULL, 0, &cb_debug_level, + N_("Set Mailutils debugging level. Argument is a colon-separated list " + "of debugging specifications in the form:\n" + " <object: string>[[:]=<level: number>]."), + N_("arg: string") }, + { "line-info", mu_c_bool, &mu_debug_line_info, 0, NULL, + N_("Prefix debug messages with Mailutils source locations.") }, + { NULL } +}; + +/* ************************************************************************* * + * Mailbox * + * ************************************************************************* */ + +static int +cb_mail_spool (void *data, mu_config_value_t *val) +{ + int rc; + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + rc = mu_set_mail_directory (val->v.string); + if (rc) + mu_error (_("cannot set mail directory name to `%s': %s"), + val->v.string, mu_strerror (rc)); + return rc; +} + +static int +cb_mailbox_pattern (void *data, mu_config_value_t *val) +{ + int rc; + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + + rc = mu_set_mailbox_pattern (val->v.string); + if (rc) + mu_error (_("cannot set mailbox pattern to `%s': %s"), + val->v.string, mu_strerror (rc)); + return rc; +} + +static int +cb_mailbox_type (void *data, mu_config_value_t *val) +{ + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + if (mu_registrar_set_default_scheme (val->v.string)) + mu_error (_("invalid mailbox type: %s"), val->v.string); + return 0; +} + +static int +cb_folder (void *data, mu_config_value_t *val) +{ + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + mu_set_folder_directory (val->v.string); + return 0; +} + +static struct mu_cfg_param mailbox_cfg[] = { + { "mail-spool", mu_cfg_callback, NULL, 0, cb_mail_spool, + N_("Use specified URL as a mailspool directory."), + N_("url: string") }, + { "mailbox-pattern", mu_cfg_callback, NULL, 0, cb_mailbox_pattern, + N_("Create mailbox URL using <pattern>."), + N_("pattern: string") }, + { "mailbox-type", mu_cfg_callback, NULL, 0, cb_mailbox_type, + N_("Default mailbox type."), + N_("protocol: string") }, + { "folder", mu_cfg_callback, NULL, 0, cb_folder, + N_("Default user mail folder"), + N_("dir: string") }, + { NULL } +}; + +/* ************************************************************************* * + * Locking * + * ************************************************************************* */ +static int +cb_locker_flags (void *data, mu_config_value_t *val) +{ + int flags = 0; + char const *s; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + + for (s = val->v.string; *s; s++) + { + switch (*s) + { + case 'E': + flags |= MU_LOCKER_EXTERNAL; + break; + + case 'R': + flags |= MU_LOCKER_RETRY; + break; + + case 'T': + flags |= MU_LOCKER_TIME; + break; + + case 'P': + flags |= MU_LOCKER_PID; + break; + + default: + mu_error (_("invalid lock flag `%c'"), *s); + } + } + mu_locker_set_default_flags (flags, mu_locker_assign); + return 0; +} + +static int +cb_locker_retry_timeout (void *data, mu_config_value_t *val) +{ + int rc; + time_t t; + char *errmsg; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + rc = mu_str_to_c (val->v.string, mu_c_time, &t, &errmsg); + if (rc) + { + mu_error (_("conversion failed: %s"), errmsg ? errmsg : + mu_strerror (rc)); + free (errmsg); + } + else + { + mu_locker_set_default_retry_timeout (t); + mu_locker_set_default_flags (MU_LOCKER_RETRY, mu_locker_set_bit); + } + return 0; +} + +static int +cb_locker_retry_count (void *data, mu_config_value_t *val) +{ + int rc; + size_t n; + char *errmsg; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + rc = mu_str_to_c (val->v.string, mu_c_size, &n, &errmsg); + if (rc) + { + mu_error (_("conversion failed: %s"), errmsg ? errmsg : + mu_strerror (rc)); + free (errmsg); + } + else + { + mu_locker_set_default_retry_count (n); + mu_locker_set_default_flags (MU_LOCKER_RETRY, mu_locker_set_bit); + } + return 0; +} + +static int +cb_locker_expire_timeout (void *data, mu_config_value_t *val) +{ + int rc; + time_t t; + char *errmsg; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + rc = mu_str_to_c (val->v.string, mu_c_time, &t, &errmsg); + if (rc) + { + mu_error (_("conversion failed: %s"), errmsg ? errmsg : + mu_strerror (rc)); + free (errmsg); + } + else + { + mu_locker_set_default_expire_timeout (t); + mu_locker_set_default_flags (MU_LOCKER_EXTERNAL, mu_locker_set_bit); + } + return 0; +} + +static int +cb_locker_external (void *data, mu_config_value_t *val) +{ + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + mu_locker_set_default_external_program (val->v.string); + mu_locker_set_default_flags (MU_LOCKER_TIME, mu_locker_set_bit); + return 0; +} + +static struct mu_cfg_param locking_cfg[] = { + /* FIXME: Flags are superfluous. */ + { "flags", mu_cfg_callback, NULL, 0, cb_locker_flags, + N_("Default locker flags (E=external, R=retry, T=time, P=pid)."), + N_("arg: string") }, + { "retry-timeout", mu_cfg_callback, NULL, 0, cb_locker_retry_timeout, + N_("Set timeout for acquiring the lock."), + N_("arg: interval")}, + { "retry-count", mu_cfg_callback, NULL, 0, cb_locker_retry_count, + N_("Set the maximum number of times to retry acquiring the lock."), + N_("arg: integer") }, + { "expire-timeout", mu_cfg_callback, NULL, 0, cb_locker_expire_timeout, + N_("Expire locks older than this amount of time."), + N_("arg: interval")}, + { "external-locker", mu_cfg_callback, NULL, 0, cb_locker_external, + N_("Use external locker program."), + N_("prog: string") }, + { NULL, } +}; + +/* ************************************************************************* * + * Address * + * ************************************************************************* */ +static int +cb_email_addr (void *data, mu_config_value_t *val) +{ + int rc; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + + rc = mu_set_user_email (val->v.string); + if (rc) + mu_error (_("invalid email address `%s': %s"), + val->v.string, mu_strerror (rc)); + return 0; +} + +static int +cb_email_domain (void *data, mu_config_value_t *val) +{ + int rc; + + if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) + return 1; + + rc = mu_set_user_email_domain (val->v.string); + if (rc) + mu_error (_("invalid email domain `%s': %s"), + val->v.string, mu_strerror (rc)); + return 0; +} + +static struct mu_cfg_param address_cfg[] = { + { "email-addr", mu_cfg_callback, NULL, 0, cb_email_addr, + N_("Set the current user email address (default is " + "loginname@defaultdomain)."), + N_("email: address") }, + { "email-domain", mu_cfg_callback, NULL, 0, cb_email_domain, + N_("Set e-mail domain for unqualified user names (default is this host)"), + N_("domain: string") }, + { NULL } +}; + + +/* ************************************************************************* * + * Registry of standard mailutils' capabilities * + * ************************************************************************* */ +struct mu_cli_capa mu_cli_std_capa[] = { + { "mailutils" }, /* Dummy */ + { "logging", logging_option, logging_cfg, NULL, logging_commit }, + { "mailer", mailer_option, mailer_cfg, NULL, NULL }, + { "debug", debug_option, debug_cfg, NULL, NULL }, + { "mailbox", NULL, mailbox_cfg, NULL, NULL }, + { "locking", NULL, locking_cfg, NULL, NULL }, + { "address", NULL, address_cfg, NULL, NULL }, + { NULL } +}; + +void +mu_cli_capa_init (void) +{ + size_t i; + + for (i = 0; mu_cli_std_capa[i].name; i++) + mu_cli_capa_register (&mu_cli_std_capa[i]); +} diff --git a/libmailutils/diag/diag.c b/libmailutils/diag/diag.c index ba055b2..3f10356 100644 --- a/libmailutils/diag/diag.c +++ b/libmailutils/diag/diag.c @@ -30,32 +30,6 @@ #include <mailutils/stdstream.h> #include <mailutils/stream.h> -const char *mu_program_name; -const char *mu_full_program_name; - -void -mu_set_program_name (const char *name) -{ - const char *progname; - - mu_full_program_name = name; - if (!name) - progname = name; - else - { - progname = strrchr (name, '/'); - if (progname) - progname++; - else - progname = name; - - if (strlen (progname) > 3 && memcmp (progname, "lt-", 3) == 0) - progname += 3; - } - - mu_program_name = progname; -} - void mu_diag_init () { diff --git a/libmailutils/opt/help.c b/libmailutils/opt/help.c index b106d9a..f91c126 100644 --- a/libmailutils/opt/help.c +++ b/libmailutils/opt/help.c @@ -155,7 +155,7 @@ init_usage_vars (struct mu_parseopt *po) fmt = getenv ("ARGP_HELP_FMT"); if (!fmt) return; - ws.ws_delim=","; + ws.ws_delim = ","; if (mu_wordsplit (fmt, &ws, MU_WRDSF_DELIM | MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | MU_WRDSF_WS | MU_WRDSF_SHOWERR)) @@ -346,20 +346,20 @@ mu_program_help (struct mu_parseopt *po) mu_option_describe_options (po->po_optv, po->po_optc); if (po->po_help_hook) - po->po_help_hook (stdout); + po->po_help_hook (po, stdout); if (po->po_bug_address) /* TRANSLATORS: The placeholder indicates the bug-reporting address for this package. Please add _another line_ saying "Report translation bugs to <...>\n" with the address for translation bugs (typically your translation team's web or email address). */ - printf (_("Report bugs to %s.\n"), po->po_bug_address); + printf (_("Report bugs to <%s>.\n"), po->po_bug_address); if (po->po_package_name && po->po_package_url) printf (_("%s home page: <%s>\n"), po->po_package_name, po->po_package_url); if (po->po_flags & MU_PARSEOPT_EXTRA_INFO) - print_option_descr (po->po_extra_info, 0, rmargin); + print_option_descr (_(po->po_extra_info), 0, rmargin); } static struct mu_option **option_tab; diff --git a/libmailutils/opt/opt.c b/libmailutils/opt/opt.c index 61bd00f..ae269db 100644 --- a/libmailutils/opt/opt.c +++ b/libmailutils/opt/opt.c @@ -85,7 +85,7 @@ fn_usage (struct mu_parseopt *po, struct mu_option *opt, char const *unused) static void fn_version (struct mu_parseopt *po, struct mu_option *opt, char const *unused) { - po->po_version_hook (stdout); + po->po_version_hook (po, stdout); exit (EXIT_SUCCESS); } @@ -107,8 +107,8 @@ struct mu_option mu_version_options[] = { }; /* Output error message */ -static void -parse_error (struct mu_parseopt *po, char const *fmt, ...) +void +mu_parseopt_error (struct mu_parseopt *po, char const *fmt, ...) { va_list ap; @@ -176,7 +176,7 @@ find_short_option (struct mu_parseopt *po, int chr) && po->po_optv[i]->opt_short == chr) return option_unalias (po, i); } - parse_error (po, _("unrecognized option '-%c'"), chr); + mu_parseopt_error (po, _("unrecognized option '-%c'"), chr); return NULL; } @@ -209,7 +209,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, case 1: if (po->po_flags & MU_PARSEOPT_IGNORE_ERRORS) return NULL; - parse_error (po, + mu_parseopt_error (po, _("option '--%*.*s' is ambiguous; possibilities:"), optlen, optlen, optstr); fprintf (stderr, "--%s\n", po->po_optv[ind]->opt_long); @@ -224,7 +224,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, switch (found) { case 0: - parse_error (po, _("unrecognized option '--%s'"), optstr); + mu_parseopt_error (po, _("unrecognized option '--%s'"), optstr); break; case 1: @@ -303,7 +303,7 @@ next_opt (struct mu_parseopt *po) break; if (!(po->po_flags & MU_PARSEOPT_IN_ORDER)) { - if (!po->po_permuted) + if (!po->po_permuted && po->po_arg_count == 0) po->po_arg_start = po->po_ind - 1; po->po_arg_count++; continue; @@ -405,11 +405,11 @@ parse (struct mu_parseopt *po) else { if (long_opt) - parse_error (po, + mu_parseopt_error (po, _("option '--%s' requires an argument"), long_opt); else - parse_error (po, + mu_parseopt_error (po, _("option '-%c' requires an argument"), po->po_chr); po->po_opterr = po->po_ind; @@ -428,7 +428,7 @@ parse (struct mu_parseopt *po) && po->po_cur[0] && !(po->po_flags & MU_OPTION_ARG_OPTIONAL)) { - parse_error (po, + mu_parseopt_error (po, _("option '--%s' doesn't allow an argument"), long_opt); po->po_opterr = po->po_ind; @@ -661,9 +661,9 @@ mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, errtext = mu_strerror (rc); if (opt->opt_long) - parse_error (po, "--%s: %s", opt->opt_long, errtext); + mu_parseopt_error (po, "--%s: %s", opt->opt_long, errtext); else - parse_error (po, "-%c: %s", opt->opt_short, errtext); + mu_parseopt_error (po, "-%c: %s", opt->opt_short, errtext); free (errmsg); if (!(po->po_flags & MU_PARSEOPT_NO_ERREXIT)) diff --git a/libmailutils/opt/progname.c b/libmailutils/opt/progname.c index 19d430e..0d19773 100644 --- a/libmailutils/opt/progname.c +++ b/libmailutils/opt/progname.c @@ -22,16 +22,16 @@ #include <mailutils/alloc.h> #include <mailutils/opt.h> -char *mu_progname; -char *mu_absprogname; +char *mu_program_name; +char *mu_full_program_name; void -mu_set_progname (char const *arg) +mu_set_program_name (const char *arg) { char *p; - free (mu_absprogname); - mu_absprogname = mu_strdup (arg); + free (mu_full_program_name); + mu_full_program_name = mu_strdup (arg); p = strrchr (arg, '/'); if (p) @@ -40,6 +40,6 @@ mu_set_progname (char const *arg) p = (char*) arg; if (strlen (p) > 3 && memcmp (p, "lt-", 3) == 0) p += 3; - free (mu_progname); - mu_progname = mu_strdup (p); + free (mu_program_name); + mu_program_name = mu_strdup (p); } diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore index 51e4e68..62b06b4 100644 --- a/libmailutils/tests/.gitignore +++ b/libmailutils/tests/.gitignore @@ -27,6 +27,7 @@ strftime strin strout strtoc +tcli tempfile url-comp url-parse diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am index 349eb24..728eaec 100644 --- a/libmailutils/tests/Makefile.am +++ b/libmailutils/tests/Makefile.am @@ -64,6 +64,7 @@ noinst_PROGRAMS = \ strout\ strtoc\ tempfile\ + tcli\ url-comp\ url-parse\ wicket\ diff --git a/libmailutils/tests/parseopt.c b/libmailutils/tests/parseopt.c index bef57ee..f25aabf 100644 --- a/libmailutils/tests/parseopt.c +++ b/libmailutils/tests/parseopt.c @@ -64,7 +64,7 @@ struct mu_option group_b[] = { struct mu_option *optv[] = { group_a, group_b, NULL }; static void -version_func (FILE *fp) +version_hook (struct mu_parseopt *po, FILE *fp) { fputs ("version hook called\n", fp); } @@ -144,7 +144,7 @@ main (int argc, char *argv[]) } } if (flags & MU_PARSEOPT_VERSION_HOOK) - po.po_version_hook = version_func; + po.po_version_hook = version_hook; } rc = mu_parseopt (&po, argc, argv, optv, flags); diff --git a/libmailutils/tests/parseopt17.at b/libmailutils/tests/parseopt17.at index 2823e0a..b57a070 100644 --- a/libmailutils/tests/parseopt17.at +++ b/libmailutils/tests/parseopt17.at @@ -35,4 +35,24 @@ argv: 2: follow 3: options ]) + +AT_CHECK([ +PARSEOPT_DEFAULT +parseopt --file=file more arguments follow -x -o options +], +[0], +[rc=0 +file_name=file +opt_value=(null) +x_option=1 +a_option=0 +find_value=(null) +d_option=0 +jobs=0 +argv: +0: more +1: arguments +2: follow +3: options +]) AT_CLEANUP diff --git a/libmailutils/tests/parseopt_help05.at b/libmailutils/tests/parseopt_help05.at index 9a0c1ed..4fe6960 100644 --- a/libmailutils/tests/parseopt_help05.at +++ b/libmailutils/tests/parseopt_help05.at @@ -18,7 +18,7 @@ AT_SETUP([MU_PARSEOPT_BUG_ADDRESS]) AT_KEYWORDS([parseopt parseopt_help parseopt_help05]) AT_CHECK([ PARSEOPT_DEFAULT -MU_PARSEOPT_BUG_ADDRESS='<gray@gnu.org>' parseopt --help +MU_PARSEOPT_BUG_ADDRESS='gray@gnu.org' parseopt --help ], [0], [Usage: parseopt [[OPTION]]... diff --git a/libmailutils/tests/parseopt_help07.at b/libmailutils/tests/parseopt_help07.at index 265acb4..91c3c19 100644 --- a/libmailutils/tests/parseopt_help07.at +++ b/libmailutils/tests/parseopt_help07.at @@ -20,7 +20,7 @@ AT_CHECK([ PARSEOPT_DEFAULT MU_PARSEOPT_PROG_DOC="Tests option parsing"\ MU_PARSEOPT_PROG_ARGS="SOME MORE ARGS"\ - MU_PARSEOPT_BUG_ADDRESS='<gray@gnu.org>'\ + MU_PARSEOPT_BUG_ADDRESS='gray@gnu.org'\ MU_PARSEOPT_PACKAGE_NAME='GNU Mailutils'\ MU_PARSEOPT_PACKAGE_URL='http://mailutils.org'\ MU_PARSEOPT_EXTRA_INFO='General help using GNU software: <http://www.gnu.org/gethelp/>'\ diff --git a/libmailutils/tests/tcli.c b/libmailutils/tests/tcli.c new file mode 100644 index 0000000..9a640d5 --- a/dev/null +++ b/libmailutils/tests/tcli.c @@ -0,0 +1,75 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2016 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 <mailutils/mailutils.h> +#include <mailutils/cli.h> + +int dtrt_option; + +struct mu_option group_a[] = { + { "dtrt", 'd', "VALUE", MU_OPTION_DEFAULT, + "do the right thing", + mu_c_int, &dtrt_option }, + MU_OPTION_END +}; + +struct mu_option *options[] = { group_a, NULL }; + +static struct mu_cfg_param config[] = { + { "do-the-right-thing", mu_c_int, &dtrt_option, 0, NULL, + "do the right thing" }, + { NULL } +}; + +struct mu_cli_setup cli = { + options, + config, + "Tests standard command line interface", + "ARGUMENTS" +}; + +static char ** +getcapa (void) +{ + struct mu_wordsplit ws; + char *p; + + p = getenv ("MU_CLI_CAPA"); + if (!p) + return NULL; + ws.ws_delim = ","; + if (mu_wordsplit (p, &ws, + MU_WRDSF_DELIM | MU_WRDSF_NOVAR | MU_WRDSF_NOCMD + | MU_WRDSF_WS | MU_WRDSF_SHOWERR)) + exit (1); + return ws.ws_wordv; +} + +int +main (int argc, char **argv) +{ + int i; + + mu_cli (argc, argv, &cli, getcapa (), NULL, &argc, &argv); + printf ("DTRT=%d\n", dtrt_option); + printf ("%d arguments:\n", argc); + for (i = 0; i < argc; i++) + printf ("%d: %s\n", i, argv[i]); + return 0; +} |