/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2021 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 . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include "mh.h"
#include
#include
#include
#include
#include
struct getopt_data
{
char *extra_doc;
};
static void
mh_extra_help_hook (struct mu_parseopt *po, mu_stream_t stream)
{
struct getopt_data *data = po->po_data;
char const *extra_doc = gettext (data->extra_doc);
while (*extra_doc)
{
size_t len = strcspn (extra_doc, "\n");
unsigned margin = strspn (extra_doc, " \t");
mu_stream_ioctl (stream, MU_IOCTL_WORDWRAPSTREAM,
MU_IOCTL_WORDWRAP_SET_MARGIN, &margin);
extra_doc += margin;
len -= margin;
mu_stream_write (stream, extra_doc, len, NULL);
mu_stream_write (stream, "\n", 1, NULL);
extra_doc += len;
if (*extra_doc)
extra_doc++;
}
}
static void
augment_argv (int *pargc, char ***pargv)
{
int argc;
char **argv;
int i, j;
struct mu_wordsplit ws;
char const *val = mh_global_profile_get (mu_program_name, NULL);
if (!val)
return;
if (mu_wordsplit (val, &ws, MU_WRDSF_DEFFLAGS))
{
mu_error (_("cannot split line `%s': %s"), val,
mu_wordsplit_strerror (&ws));
exit (1);
}
argc = *pargc + ws.ws_wordc;
argv = calloc (argc + 1, sizeof *argv);
if (!argv)
mh_err_memory (1);
i = 0;
argv[i++] = (*pargv)[0];
for (j = 0; j < ws.ws_wordc; i++, j++)
argv[i] = ws.ws_wordv[j];
for (j = 1; i < argc; i++, j++)
argv[i] = (*pargv)[j];
argv[i] = NULL;
ws.ws_wordc = 0;
mu_wordsplit_free (&ws);
*pargc = argc;
*pargv = argv;
}
static void
process_std_options (int argc, char **argv, struct mu_parseopt *po)
{
if (argc != 1)
return;
if (strcmp (argv[0], "--help") == 0)
{
mu_program_help (po, mu_strout);
exit (0);
}
if (strcmp (argv[0], "--version") == 0)
{
mu_version_hook (po, mu_strout);
exit (0);
}
}
static void
process_folder_arg (int *pargc, char **argv, struct mu_parseopt *po)
{
int i, j;
int argc = *pargc;
struct mu_option *opt;
/* Find folder option */
for (i = 0; ; i++)
{
if (!po->po_optv[i])
return; /* Nothing to do */
if (MU_OPTION_IS_VALID_LONG_OPTION (po->po_optv[i])
&& strcmp (po->po_optv[i]->opt_long, "folder") == 0)
break;
}
opt = po->po_optv[i];
for (i = j = 0; i < argc; i++)
{
if (argv[i][0] == '+')
{
opt->opt_set (po, opt, argv[i] + 1);
}
else
argv[j++] = argv[i];
}
argv[j] = NULL;
*pargc = j;
}
void
mh_opt_set_folder (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
mh_set_current_folder (arg);
}
static struct mu_option folder_option[] = {
{ "folder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
N_("set current folder"),
mu_c_string, NULL, mh_opt_set_folder },
MU_OPTION_END
};
void
mh_version_hook (struct mu_parseopt *po, mu_stream_t stream)
{
mu_stream_printf (stream, "%s (%s %s)\n", mu_program_name,
PACKAGE_NAME, PACKAGE_VERSION);
#if MU_GIT_COMMIT_DISTANCE > 0
mu_stream_printf (stream, "version: %s %s-%d [%s]\n",
PACKAGE_NAME, PACKAGE_VERSION,
MU_GIT_COMMIT_DISTANCE,
MU_GIT_DESCRIBE_STRING);
#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. */
mu_stream_printf (stream, mu_version_copyright, _("(C)"));
mu_stream_printf (stream, _("\
\n\
License GPLv3+: GNU GPL version 3 or later \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\
"));
}
static int
has_folder_option (struct mu_option *opt)
{
while (!MU_OPTION_IS_END (opt))
{
if (MU_OPTION_IS_VALID_LONG_OPTION (opt)
&& strcmp (opt->opt_long, "folder") == 0)
return 1;
++opt;
}
return 0;
}
static void
opt_init (struct mu_parseopt *po,
struct mu_option **optv, struct mh_optinit *optinit)
{
if (!optinit)
return;
for (; optinit->opt; optinit++)
{
size_t i;
for (i = 0; optv[i]; i++)
{
struct mu_option *opt;
for (opt = optv[i]; !MU_OPTION_IS_END (opt); opt++)
{
if (strcmp (opt->opt_long, optinit->opt) == 0)
{
char const *val = mh_global_profile_get (optinit->var, NULL);
if (val)
{
(opt->opt_set ?
opt->opt_set : mu_option_set_value) (po, opt, val);
}
break;
}
}
}
}
}
void
mh_getopt_ext (int *pargc, char ***pargv, struct mu_option *options,
int mhflags, struct mh_optinit *optinit,
char *argdoc, char *progdoc, char *extradoc)
{
int argc = *pargc;
char **argv = *pargv;
struct mu_parseopt po;
struct mu_option *optv[3];
struct getopt_data getopt_data;
char const *args[3];
int flags = MU_PARSEOPT_SINGLE_DASH | MU_PARSEOPT_IMMEDIATE;
int i;
/* Native Language Support */
MU_APP_INIT_NLS ();
po.po_negation = "no";
flags |= MU_PARSEOPT_NEGATION;
if ((mhflags & MH_GETOPT_DEFAULT_FOLDER) || has_folder_option (options))
{
po.po_special_args = N_("[+FOLDER]");
flags |= MU_PARSEOPT_SPECIAL_ARGS;
}
if (argdoc)
{
args[0] = argdoc;
args[1] = NULL;
po.po_prog_args = args;
flags |= MU_PARSEOPT_PROG_ARGS;
}
if (progdoc)
{
po.po_prog_doc = progdoc;
flags |= MU_PARSEOPT_PROG_DOC;
}
getopt_data.extra_doc = extradoc;
if (extradoc)
{
po.po_help_hook = mh_extra_help_hook;
flags |= MU_PARSEOPT_HELP_HOOK;
}
po.po_data = &getopt_data;
flags |= MU_PARSEOPT_DATA;
po.po_exit_error = 1;
flags |= MU_PARSEOPT_EXIT_ERROR;
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 = mh_version_hook;
flags |= MU_PARSEOPT_VERSION_HOOK;
mu_set_program_name (argv[0]);
mh_init ();
augment_argv (&argc, &argv);
i = 0;
if (mhflags & MH_GETOPT_DEFAULT_FOLDER)
optv[i++] = folder_option;
if (options)
optv[i++] = options;
optv[i] = NULL;
opt_init (&po, optv, optinit);
if (mu_parseopt (&po, argc, argv, optv, flags))
exit (po.po_exit_error);
argc -= po.po_arg_start;
argv += po.po_arg_start;
process_std_options (argc, argv, &po);
process_folder_arg (&argc, argv, &po);
if (!argdoc && argc)
{
mu_diag_init ();
mu_stream_printf (mu_strerr, "\033s<%d>", MU_DIAG_ERROR);
mu_stream_printf (mu_strerr, "%s", _("unrecognized extra arguments:"));
for (i = 0; i < argc; i++)
mu_stream_printf (mu_strerr, " %s", argv[i]);
mu_stream_write (mu_strerr, "\n", 1, NULL);
exit (1);
}
*pargc = argc;
*pargv = argv;
mh_init2 ();
}
void
mh_getopt (int *pargc, char ***pargv, struct mu_option *options,
int mhflags, char *argdoc, char *progdoc, char *extradoc)
{
mh_getopt_ext (pargc, pargv, options, mhflags, NULL, argdoc, progdoc,
extradoc);
}
void
mh_opt_notimpl (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
mu_error (_("option is not yet implemented: %s"), opt->opt_long);
exit (1);
}
void
mh_opt_notimpl_warning (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
if (opt->opt_type == mu_c_bool)
{
int val;
if (mu_str_to_c (arg, opt->opt_type, &val, NULL) == 0 && !val)
return;
}
mu_error (_("ignoring not implemented option %s"), opt->opt_long);
}
void
mh_opt_clear_string (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
char **sptr = opt->opt_ptr;
free (*sptr);
*sptr = NULL;
}
void
mh_opt_find_file (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
mh_find_file (arg, opt->opt_ptr);
}
void
mh_opt_read_formfile (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
mh_read_formfile (arg, opt->opt_ptr);
}
void
mh_opt_parse_formfile (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
mh_format_destroy ((mh_format_t*) opt->opt_ptr);
if (mh_format_file_parse (opt->opt_ptr, arg, MH_FMT_PARSE_DEFAULT))
exit (1);
}
void
mh_opt_parse_format (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
mh_format_destroy ((mh_format_t*) opt->opt_ptr);
if (mh_format_string_parse (opt->opt_ptr, arg, NULL, MH_FMT_PARSE_DEFAULT))
exit (1);
}