Commit 87ef8884 87ef8884693eb0cdcdafa2365c86709f33e3a375 by Sergey Poznyakoff

Add generic library for option parsing.

* configure.ac: Build libmailutils/opt
* include/mailutils/Makefile.am: Add opt.h
* include/mailutils/opt.h: New file.
* include/mailutils/util.h (mu_c_type_t): New datatype.
(mu_str_to_c): New proto.
* libmailutils/Makefile.am: Add opt to subdirs.

* libmailutils/opt/Makefile.am: New file.
* libmailutils/opt/help.c: New file.
* libmailutils/opt/opt.c: New file.
* libmailutils/opt/progname.c: New file.

* libmailutils/string/Makefile.am: Add new files.
* libmailutils/string/str_to_c.c: New file.
* libmailutils/string/to_sn.c: New file.
* libmailutils/string/to_un.c: New file.

* libmailutils/tests/.gitignore: Update.
* libmailutils/tests/Makefile.am: Update.
* libmailutils/tests/parseopt.c: New file.
1 parent 8b8f29eb
......@@ -1519,6 +1519,7 @@ AC_CONFIG_FILES([
libmailutils/mailer/Makefile
libmailutils/mime/Makefile
libmailutils/msgset/Makefile
libmailutils/opt/Makefile
libmailutils/property/Makefile
libmailutils/server/Makefile
libmailutils/string/Makefile
......
......@@ -79,6 +79,7 @@ pkginclude_HEADERS = \
nntp.h\
observer.h\
opool.h\
opt.h\
pam.h\
parse822.h\
pop3.h\
......
/* opt.h -- general-purpose command line option parser
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/>.
*/
#ifndef _MAILUTILS_OPT_H
#define _MAILUTILS_OPT_H
#include <stdio.h>
#include <mailutils/types.h>
#include <mailutils/list.h>
#include <mailutils/util.h>
#include <mailutils/cctype.h>
extern char *mu_progname;
extern char *mu_absprogname;
void mu_set_progname (char const *arg);
#define MU_OPTION_DEFAULT 0
#define MU_OPTION_ARG_OPTIONAL 0x01
#define MU_OPTION_HIDDEN 0x02
#define MU_OPTION_ALIAS 0x04
#define MU_OPTION_IMMEDIATE 0x08
struct mu_parseopt;
struct mu_option
{
char *opt_long; /* Long option name */
int opt_short; /* Short option character */
char *opt_arg; /* Argument name */
int opt_flags; /* Flags (see above) */
char *opt_doc; /* Human-readable documentation */
mu_c_type_t opt_type; /* Option type */
void *opt_ptr; /* Data pointer */
void (*opt_set) (struct mu_parseopt *, struct mu_option *, char const *);
/* Function to set the option */
};
#define MU_OPTION_GROUP(text) { NULL, 0, NULL, 0, text }
#define MU_OPTION_END { NULL, 0, NULL, 0, NULL }
#define MU_OPTION_IS_END(opt) \
(!(opt)->opt_long && !(opt)->opt_short && !(opt)->opt_doc)
#define MU_OPTION_IS_OPTION(opt) \
((opt)->opt_short || (opt)->opt_long)
#define MU_OPTION_IS_GROUP_HEADER(opt) \
(!MU_OPTION_IS_OPTION(opt) && (opt)->opt_doc)
#define MU_OPTION_IS_VALID_SHORT_OPTION(opt) \
((opt)->opt_short > 0 && (opt)->opt_short < 127 && \
mu_isalnum ((opt)->opt_short))
#define MU_OPTION_IS_VALID_LONG_OPTION(opt) \
((opt)->opt_long != NULL)
typedef struct mu_option_cache *mu_option_cache_ptr_t;
struct mu_option_cache
{
struct mu_option *cache_opt;
char *cache_arg;
};
#define MU_PARSEOPT_DEFAULT 0
/* Don't ignore the first element of ARGV. By default it is the program
name */
#define MU_PARSEOPT_ARGV0 0x00000001
/* Ignore command line errors. */
#define MU_PARSEOPT_IGNORE_ERRORS 0x00000002
/* Don't order arguments so that options come first. */
#define MU_PARSEOPT_IN_ORDER 0x00000004
/* Don't provide standard options: -h, --help, --usage, --version */
#define MU_PARSEOPT_NO_STDOPT 0x00000008
/* Don't exit on errors */
#define MU_PARSEOPT_NO_ERREXIT 0x00000010
/* Apply all options immediately */
#define MU_PARSEOPT_IMMEDIATE 0x00000020
/* Don't sort options */
#define MU_PARSEOPT_NO_SORT 0x00001000
#define MU_PARSEOPT_PROG_NAME 0x00002000
#define MU_PARSEOPT_PROG_DOC 0x00004000
#define MU_PARSEOPT_PROG_ARGS 0x00008000
#define MU_PARSEOPT_BUG_ADDRESS 0x00010000
#define MU_PARSEOPT_PACKAGE_NAME 0x00020000
#define MU_PARSEOPT_PACKAGE_URL 0x00040000
#define MU_PARSEOPT_DATA 0x00080000
#define MU_PARSEOPT_HELP_HOOK 0x00100000
/* Reuse mu_parseopt struct initialized previously */
#define MU_PARSEOPT_REUSE 0x80000000
/* Mask for immutable flag bits */
#define MU_PARSEOPT_IMMUTABLE_MASK 0xFFFFF000
struct mu_parseopt
{
/* Input data: */
int po_argc; /* Number of argiments */
char **po_argv; /* Array of arguments */
size_t po_optc; /* Number of elements in optv */
struct mu_option **po_optv; /* Array of ptrs to option structures */
int po_flags;
char *po_data; /* Call-specific data */
/* Informational: */
char const *po_prog_name;
char const *po_prog_doc;
char const *po_prog_args;
char const *po_bug_address;
char const *po_package_name;
char const *po_package_url;
void (*po_help_hook) (FILE *stream); /* FIXME: should take mu_Stream_t ?*/
/* Output data */
int po_ind; /* Index of the next option */
int po_opterr; /* Index of the element in po_argv that
caused last error, or -1 if no errors */
mu_list_t po_optlist;
/* Auxiliary data */
char *po_cur; /* Points to the next character */
int po_chr; /* Single-char option */
/* The following two keep the position of the first non-optional argument
and the number of contiguous non-optional arguments after it.
Obviously, the following holds true:
arg_start + arg_count == opt_ind
If permutation is not allowed (MU_OPTION_PARSE_IN_ORDER flag is set),
arg_count is always 0.
*/
int po_arg_start;
int po_arg_count;
};
int mu_parseopt (struct mu_parseopt *p,
int argc, char **argv, struct mu_option **optv,
int flags);
int mu_parseopt_apply (struct mu_parseopt *p);
void mu_parseopt_free (struct mu_parseopt *p);
void mu_option_describe_options (struct mu_option **optbuf, size_t optcnt);
void mu_program_help (struct mu_parseopt *p);
void mu_program_usage (struct mu_parseopt *p);
void mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt,
char const *arg);
#endif
......@@ -152,6 +152,35 @@ int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt,
char **passptr);
/* ----------------------- */
/* String conversions. */
/* ----------------------- */
enum mu_c_type
{
mu_c_string,
mu_c_short,
mu_c_ushort,
mu_c_int,
mu_c_uint,
mu_c_long,
mu_c_ulong,
mu_c_size,
mu_c_off,
mu_c_time,
mu_c_bool,
mu_c_ipv4,
mu_c_cidr,
mu_c_host,
mu_c_incr, /* C int value, incremented each time mu_str_to_c is
invoked */
};
typedef enum mu_c_type mu_c_type_t;
int mu_str_to_c (char const *string, mu_c_type_t type, void *tgt,
char **errmsg);
/* ----------------------- */
/* Assorted functions. */
/* ----------------------- */
int mu_getmaxfd (void);
......@@ -208,7 +237,6 @@ int mu_file_safety_compose (int *res, const char *name, int defval);
int mu_file_mode_to_safety_criteria (int mode);
int mu_safety_criteria_to_file_mode (int crit);
#ifdef __cplusplus
}
#endif
......
......@@ -18,7 +18,7 @@
SUBDIRS = \
auth base address list sockaddr cidr cfg diag\
filter mailbox mailer mime msgset server string stream stdstream\
filter mailbox mailer mime msgset opt server string stream stdstream\
property url imapio datetime . tests
lib_LTLIBRARIES = libmailutils.la
......@@ -42,6 +42,7 @@ libmailutils_la_LIBADD = \
mailer/libmailer.la\
mime/libmime.la\
msgset/libmsgset.la\
opt/libopt.la\
property/libproperty.la\
server/libserver.la\
string/libstring.la\
......
# 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 = libopt.la
libopt_la_SOURCES = \
opt.c\
help.c\
progname.c
AM_CPPFLAGS = \
@MU_LIB_COMMON_INCLUDES@ -I/libmailutils
/* help.c -- general-purpose command line option parser
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/alloc.h>
#include <mailutils/opt.h>
#include <mailutils/cctype.h>
#include <mailutils/nls.h>
#define LMARGIN 2
#define DESCRCOLUMN 30
#define RMARGIN 79
#define GROUPCOLUMN 2
#define USAGECOLUMN 13
static void
indent (size_t start, size_t col)
{
for (; start < col; start++)
putchar (' ');
}
static void
print_option_descr (const char *descr, size_t lmargin, size_t rmargin)
{
while (*descr)
{
size_t s = 0;
size_t i;
size_t width = rmargin - lmargin;
for (i = 0; ; i++)
{
if (descr[i] == 0 || descr[i] == ' ' || descr[i] == '\t')
{
if (i > width)
break;
s = i;
if (descr[i] == 0)
break;
}
}
fwrite (descr, 1, s, stdout);
fputc ('\n', stdout);
descr += s;
if (*descr)
{
indent (0, lmargin);
descr++;
}
}
}
static size_t
print_option (struct mu_option **optbuf, size_t optcnt, size_t num,
int *argsused)
{
struct mu_option *opt = optbuf[num];
size_t next, i;
int delim;
int w;
if (MU_OPTION_IS_GROUP_HEADER (opt))
{
if (num)
putchar ('\n');
indent (0, GROUPCOLUMN);
print_option_descr (gettext (opt->opt_doc), GROUPCOLUMN, RMARGIN);
putchar ('\n');
return num + 1;
}
/* count aliases */
for (next = num + 1;
next < optcnt && optbuf[next]->opt_flags & MU_OPTION_ALIAS;
next++);
if (opt->opt_flags & MU_OPTION_HIDDEN)
return next;
w = 0;
for (i = num; i < next; i++)
{
if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]))
{
if (w == 0)
{
indent (0, LMARGIN);
w = LMARGIN;
}
else
w += printf (", ");
w += printf ("-%c", optbuf[i]->opt_short);
delim = ' ';
}
}
for (i = num; i < next; i++)
{
if (MU_OPTION_IS_VALID_LONG_OPTION (optbuf[i]))
{
if (w == 0)
{
indent (0, LMARGIN);
w = LMARGIN;
}
else
w += printf (", ");
w += printf ("--%s", optbuf[i]->opt_long);
delim = '=';
}
}
if (opt->opt_arg)
{
*argsused = 1;
w += printf ("%c%s", delim, gettext (opt->opt_arg));
}
if (w >= DESCRCOLUMN)
{
putchar ('\n');
w = 0;
}
indent (w, DESCRCOLUMN);
print_option_descr (gettext (opt->opt_doc), DESCRCOLUMN, RMARGIN);
return next;
}
void
mu_option_describe_options (struct mu_option **optbuf, size_t optcnt)
{
unsigned i;
int argsused = 0;
for (i = 0; i < optcnt; )
i = print_option (optbuf, optcnt, i, &argsused);
putchar ('\n');
if (argsused)
{
print_option_descr (_("Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options."), 0, RMARGIN);
putchar ('\n');
}
}
void
mu_program_help (struct mu_parseopt *po)
{
printf ("%s", _("Usage:"));
if (po->po_prog_name)
printf (" %s", po->po_prog_name);
printf (" [%s]...", _("OPTION"));
if (po->po_prog_args)
printf (" %s", gettext (po->po_prog_args));
putchar ('\n');
if (po->po_prog_doc)
print_option_descr (gettext (po->po_prog_doc), 0, RMARGIN);
putchar ('\n');
mu_option_describe_options (po->po_optv, po->po_optc);
if (po->po_help_hook)
po->po_help_hook (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);
if (po->po_package_name && po->po_package_url)
printf (_("%s home page: <%s>\n"),
po->po_package_name, po->po_package_url);
}
static struct mu_option **option_tab;
static int
cmpidx_short (const void *a, const void *b)
{
unsigned const *ai = (unsigned const *)a;
unsigned const *bi = (unsigned const *)b;
return option_tab[*ai]->opt_short - option_tab[*bi]->opt_short;
}
static int
cmpidx_long (const void *a, const void *b)
{
unsigned const *ai = (unsigned const *)a;
unsigned const *bi = (unsigned const *)b;
struct mu_option const *ap = option_tab[*ai];
struct mu_option const *bp = option_tab[*bi];
return strcmp (ap->opt_long, bp->opt_long);
}
void
mu_program_usage (struct mu_parseopt *po)
{
unsigned i;
unsigned n;
char buf[RMARGIN+1];
unsigned *idxbuf;
unsigned nidx;
struct mu_option **optbuf = po->po_optv;
size_t optcnt = po->po_optc;
#define FLUSH \
do \
{ \
buf[n] = 0; \
printf ("%s\n", buf); \
n = USAGECOLUMN; \
memset (buf, ' ', n); \
} \
while (0)
#define ADDC(c) \
do \
{ \
if (n == RMARGIN) FLUSH; \
buf[n++] = c; \
} \
while (0)
option_tab = optbuf;
idxbuf = mu_calloc (optcnt, sizeof (idxbuf[0]));
n = snprintf (buf, sizeof buf, "%s %s ", _("Usage:"), mu_progname);
/* Print a list of short options without arguments. */
for (i = nidx = 0; i < optcnt; i++)
if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && !optbuf[i]->opt_arg)
idxbuf[nidx++] = i;
if (nidx)
{
qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short);
ADDC ('[');
ADDC ('-');
for (i = 0; i < nidx; i++)
{
ADDC (optbuf[idxbuf[i]]->opt_short);
}
ADDC (']');
}
/* Print a list of short options with arguments. */
for (i = nidx = 0; i < optcnt; i++)
{
if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && optbuf[i]->opt_arg)
idxbuf[nidx++] = i;
}
if (nidx)
{
qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short);
for (i = 0; i < nidx; i++)
{
struct mu_option *opt = optbuf[idxbuf[i]];
const char *arg = gettext (opt->opt_arg);
size_t len = 5 + strlen (arg) + 1;
if (n + len > RMARGIN) FLUSH;
buf[n++] = ' ';
buf[n++] = '[';
buf[n++] = '-';
buf[n++] = opt->opt_short;
buf[n++] = ' ';
strcpy (&buf[n], arg);
n += strlen (arg);
buf[n++] = ']';
}
}
/* Print a list of long options */
for (i = nidx = 0; i < optcnt; i++)
{
if (MU_OPTION_IS_VALID_LONG_OPTION (optbuf[i]))
idxbuf[nidx++] = i;
}
if (nidx)
{
qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_long);
for (i = 0; i < nidx; i++)
{
struct mu_option *opt = optbuf[idxbuf[i]];
const char *arg = opt->opt_arg ? gettext (opt->opt_arg) : NULL;
size_t len = 3 + strlen (opt->opt_long)
+ (arg ? 1 + strlen (arg) : 0);
if (n + len > RMARGIN) FLUSH;
buf[n++] = ' ';
buf[n++] = '[';
buf[n++] = '-';
buf[n++] = '-';
strcpy (&buf[n], opt->opt_long);
n += strlen (opt->opt_long);
if (opt->opt_arg)
{
buf[n++] = '=';
strcpy (&buf[n], arg);
n += strlen (arg);
}
buf[n++] = ']';
}
}
FLUSH;
free (idxbuf);
}
/* help.c -- general-purpose command line option parser
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/alloc.h>
#include <mailutils/opt.h>
char *mu_progname;
char *mu_absprogname;
void
mu_set_progname (char const *arg)
{
char *p;
free (mu_absprogname);
mu_absprogname = mu_strdup (arg);
p = strrchr (arg, '/');
if (p)
++p;
else
p = (char*) arg;
free (mu_progname);
mu_progname = mu_strdup (p);
}
......@@ -25,6 +25,7 @@ libstring_la_SOURCES = \
cstrupper.c\
hexstr.c\
stpcpy.c\
str_to_c.c\
strltrim.c\
strskip.c\
stripws.c\
......@@ -40,4 +41,6 @@ libstring_la_SOURCES = \
wordsplit.c\
xdecode.c
AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
EXTRA_DIST=to_sn.c to_un.c
AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils -I${srcdir}
......
/* 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/>. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <inttypes.h>
#include <limits.h>
#include <string.h>
#include <mailutils/cidr.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/util.h>
#include <mailutils/alloc.h>
#include <mailutils/cctype.h>
#include <mailutils/io.h>
#include <mailutils/nls.h>
typedef int (*str_to_c_t) (void *tgt, char const *string, char **errmsg);
static int
to_string (void *tgt, char const *string, char **errmsg)
{
char **cptr = tgt;
if (string)
{
*cptr = mu_strdup (string);
if (!*cptr)
return errno;
}
else
*cptr = NULL;
return 0;
}
#define STR_TO_FUN to_short
#define STR_TO_TYPE signed short
#define STR_TO_MIN SHRT_MIN
#define STR_TO_MAX SHRT_MAX
#include "to_sn.c"
#define STR_TO_FUN to_ushort
#define STR_TO_TYPE unsigned short
#define STR_TO_MAX USHRT_MAX
#include "to_un.c"
#define STR_TO_FUN to_int
#define STR_TO_TYPE signed int
#define STR_TO_MIN INT_MIN
#define STR_TO_MAX INT_MAX
#include "to_sn.c"
#define STR_TO_FUN to_uint
#define STR_TO_TYPE unsigned int
#define STR_TO_MAX UINT_MAX
#include "to_un.c"
#define STR_TO_FUN to_long
#define STR_TO_TYPE signed long
#define STR_TO_MIN LONG_MIN
#define STR_TO_MAX LONG_MAX
#include "to_sn.c"
#define STR_TO_FUN to_ulong
#define STR_TO_TYPE unsigned long
#define STR_TO_MAX ULONG_MAX
#include "to_un.c"
#define STR_TO_FUN to_size_t
#define STR_TO_TYPE size_t
#define STR_TO_MAX ((size_t)-1)
#include "to_un.c"
static int
time_multiplier (const char *str, unsigned *m, unsigned *plen)
{
static struct timetab
{
char *name;
unsigned mul;
} tab[] = {
{ "seconds", 1 },
{ "minutes", 60 },
{ "hours", 60*60 },
{ "days", 24*60*60 },
{ "weeks", 7*24*60*60 },
{ "months", 31*7*24*60*60 },
{ NULL }
};
struct timetab *p;
int slen;
for (slen = 0; str[slen]; slen++)
if (mu_isspace (str[slen]))
break;
for (p = tab; p->name; p++)
{
if (p->name[0] == mu_tolower (str[0]))
{
int nlen = strlen (p->name);
if (nlen > slen)
nlen = slen;
if (strncasecmp (p->name, str, nlen) == 0) {
*m = p->mul;
if (plen)
*plen = nlen;
return 0;
}
}
}
return 1;
}
static int
to_time_t (void *tgt, char const *string, char **errmsg)
{
time_t *ptr = tgt;
int rc = 0;
time_t interval = 0;
while (*string)
{
char *p;
unsigned long n;
unsigned mul, len;
while (*string && mu_isspace (*string))
string++;
if (!mu_isdigit (*string) && time_multiplier (string, &mul, &len) == 0)
{
n = 1;
string += len;
}
else
{
n = strtoul (string, &p, 10);
if (*p && !mu_isspace (*p))
{
string = p;
rc = 1;
break;
}
while (*p && mu_isspace (*p))
p++;
string = p;
if (*string)
{
if ((rc = time_multiplier (string, &mul, &len)))
break;
string += len;
}
else
mul = 1;
}
interval += n * mul;
}
if (rc)
{
mu_asprintf (errmsg, _("invalid time specification near %s"), string);
return EINVAL;
}
*ptr = interval;
return 0;
}
static int
to_bool (void *tgt, char const *string, char **errmsg)
{
int *ptr = tgt;
if (strcmp (string, "yes") == 0
|| strcmp (string, "on") == 0
|| strcmp (string, "t") == 0
|| strcmp (string, "true") == 0
|| strcmp (string, "1") == 0)
*ptr = 1;
else if (strcmp (string, "no") == 0
|| strcmp (string, "off") == 0
|| strcmp (string, "nil") == 0
|| strcmp (string, "false") == 0
|| strcmp (string, "0") == 0)
*ptr = 0;
else
return EINVAL;
return 0;
}
#if 0
static int
to_ipv4 (void *tgt, char const *string, char **errmsg)
{
struct in_addr *ptr = tgt;
struct in_addr addr;
if (inet_aton (string, &addr) == 0)
{
mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, _("not an IPv4"));
mu_cfg_error_count++;
return 1;
}
addr.s_addr = ntohl (addr.s_addr);
*ptr = addr;
return 0;
}
#endif
static int
to_cidr (void *tgt, char const *string, char **errmsg)
{
struct mu_cidr *ptr = tgt;
return mu_cidr_from_string (ptr, string);
}
static int
to_incr (void *tgt, char const *string, char **errmsg)
{
++*(int*)tgt;
return 0;
}
static str_to_c_t str_to_c[] = {
[mu_c_string] = to_string,
[mu_c_short] = to_short,
[mu_c_ushort] = to_ushort,
[mu_c_int] = to_int,
[mu_c_uint] = to_uint,
[mu_c_long] = to_long,
[mu_c_ulong] = to_ulong,
[mu_c_size] = to_size_t,
/* FIXME [mu_c_off] = { to_off, generic_dealloc }, */
[mu_c_time] = to_time_t,
[mu_c_bool] = to_bool,
/* FIXME [mu_c_ipv4] = to_ipv4, */
[mu_c_cidr] = to_cidr,
/* FIXME [mu_c_host] = { to_host, generic_dealloc } */
[mu_c_incr] = to_incr
};
int
mu_str_to_c (char const *string, enum mu_c_type type, void *tgt, char **errmsg)
{
*errmsg = NULL;
if ((size_t)type >= sizeof (str_to_c) / sizeof (str_to_c[0]))
return EINVAL;
if (!str_to_c[type])
return ENOSYS;
return str_to_c[type] (tgt, string, errmsg);
}
#ifndef STR_TO_FUN
# error "STR_TO_FUN not defined"
#endif
#ifndef STR_TO_TYPE
# error "STR_TO_TYPE not defined"
#endif
#ifndef STR_TO_MIN
# error "STR_TO_MIN not defined"
#endif
#ifndef STR_TO_MAX
# error "STR_TO_MAX not defined"
#endif
static int
STR_TO_FUN (void *tgt, char const *string, char **errmsg)
{
STR_TO_TYPE *ptr = tgt;
intmax_t v;
char *p;
errno = 0;
v = strtoimax (string, &p, 10);
if (errno)
return errno;
if (*p)
return EINVAL;
if (STR_TO_MIN <= v && v <= STR_TO_MAX)
{
*ptr = (STR_TO_TYPE) v;
return 0;
}
return ERANGE;
}
#undef STR_TO_FUN
#undef STR_TO_TYPE
#undef STR_TO_MIN
#undef STR_TO_MAX
#ifndef STR_TO_FUN
# error "STR_TO_FUN not defined"
#endif
#ifndef STR_TO_TYPE
# error "STR_TO_TYPE not defined"
#endif
#ifndef STR_TO_MAX
# error "STR_TO_MAX not defined"
#endif
static int
STR_TO_FUN (void *tgt, char const *string, char **errmsg)
{
STR_TO_TYPE *ptr = tgt;
uintmax_t v;
char *p;
errno = 0;
v = strtoumax (string, &p, 10);
if (errno)
return errno;
if (*p)
return EINVAL;
if (v <= STR_TO_MAX)
{
*ptr = (STR_TO_TYPE) v;
return 0;
}
return ERANGE;
}
#undef STR_TO_FUN
#undef STR_TO_TYPE
#undef STR_TO_MAX
......@@ -20,6 +20,7 @@ mailcap
mimehdr
modtofsaf
msgset
parseopt
prop
scantime
strftime
......
......@@ -56,6 +56,7 @@ noinst_PROGRAMS = \
modtofsaf\
msgset\
modmesg\
parseopt\
prop\
scantime\
strftime\
......
/* 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/opt.h>
char *file_name;
char *find_value;
char *opt_value = "initial";
int jobs = 0;
int x_option;
int a_option;
int d_option;
struct mu_option group_a[] = {
MU_OPTION_GROUP("Group A"),
{ "file", 'f', "FILE", MU_OPTION_DEFAULT,
"set file name",
mu_c_string, &file_name
},
{ "find", 'F', "VALUE", MU_OPTION_DEFAULT,
"find VALUE",
mu_c_string, &find_value },
{ "optional", 'o', "FILE", MU_OPTION_ARG_OPTIONAL,
"optional argument",
mu_c_string, &opt_value },
{ NULL, 'x', NULL, MU_OPTION_DEFAULT,
"short-only option",
mu_c_incr, &x_option },
{ "all", 'a', NULL, MU_OPTION_DEFAULT,
"no arguments to this one",
mu_c_bool, &a_option },
MU_OPTION_END
};
struct mu_option group_b[] = {
MU_OPTION_GROUP("Group B"),
{ "debug", 'd', NULL, MU_OPTION_DEFAULT,
"another option",
mu_c_incr, &d_option },
{ "verbose", 'v', NULL, MU_OPTION_ALIAS },
{ "jobs", 'j', "N", MU_OPTION_DEFAULT,
"sets numeric value",
mu_c_int, &jobs },
MU_OPTION_END
};
struct mu_option *optv[] = { group_a, group_b, NULL };
#define S(s) ((s)?(s):"(null)")
int
main (int argc, char *argv[])
{
struct mu_parseopt po;
int rc;
int i;
mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
rc = mu_parseopt (&po, argc, argv, optv, MU_PARSEOPT_DEFAULT);
printf ("rc=%d\n", rc);
mu_parseopt_apply (&po);
argc -= po.po_ind;
argv += po.po_ind;
mu_parseopt_free (&po);
printf ("file_name=%s\n", S(file_name));
printf ("find_value=%s\n", S(find_value));
printf ("opt_value=%s\n", S(opt_value));
printf ("x_option=%d\n", x_option);
printf ("a_option=%d\n", a_option);
printf ("d_option=%d\n", d_option);
printf ("jobs=%d\n", jobs);
printf ("argv:\n");
for (i = 0; i < argc; i++)
{
printf ("%d: %s\n", i, argv[i]);
}
return 0;
}