aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-02-18 15:47:05 +0000
committerWerner Koch <[email protected]>2020-02-18 15:50:46 +0000
commit933eb9346a84c87f83f77d990be2f66e2f7b62e7 (patch)
tree4560fa9440d0e98f8662eb737c56d40d4499dab9
parentcore: Add gpgrt_fnameconcat and gpgrt_absfnameconcat. (diff)
downloadlibgpg-error-933eb9346a84c87f83f77d990be2f66e2f7b62e7.tar.gz
libgpg-error-933eb9346a84c87f83f77d990be2f66e2f7b62e7.zip
core: Add a high level option/argument parser.
* gpg-error.h.in (GPGRT_CONFDIR_USER, GPGRT_CONFDIR_SYS): New consts. (ARGPARSE_FLAG_SYS, ARGPARSE_FLAG_USER, ARGPARSE_FLAG_VERBOSE) (ARGPARSE_NO_CONFFILE, ARGPARSE_CONFFILE, ARGPARSE_OPT_CONFFILE): New consts. (ARGPARSE_conffile, ARGPARSE_noconffile): New macros. (gpgrt_set_confdir): New func. (gpgrt_argparser): New func. * src/argparse.c (confdir): New var. (enum argparser_states): New. (struct _gpgrt_argparse_internal_s): Add a couple of new fields. (initialize): Init them. (any_opt_conffile): New. (_gpgrt_argparser): New. (_gpgrt_set_confdir): New. * src/visibility.c (gpgrt_argparser): New. (gpgrt_set_confdir): New. * src/gpg-error.def.in, src/gpg-error.vers: Add those functions. * tests/t-argparse.c (main): Reworked. * tests/etc/t-argparse.conf: New file. * tests/t-argparse.conf: New file. -- gpgrt_argparser is a high level version of gpgrt_argparse. It handles reading of configuration files internally and allows allows for a global configuration file. The design is so that it minimizes the work to replace the existing option parsing in gpg and friends by this one and to allow global configuration files for them. This is the just the basic code which should allow replacement of the parsers. A forthcoming patch will implement flags for options given in the global config file. GnuPG-bug-id: 4788 Signed-off-by: Werner Koch <[email protected]>
-rw-r--r--AUTHORS2
-rw-r--r--NEWS12
-rw-r--r--configure.ac2
-rw-r--r--src/argparse.c384
-rw-r--r--src/gpg-error.def.in3
-rw-r--r--src/gpg-error.h.in25
-rw-r--r--src/gpg-error.vers2
-rw-r--r--src/gpgrt-int.h3
-rw-r--r--src/version.c2
-rw-r--r--src/versioninfo.rc.in2
-rw-r--r--src/visibility.c12
-rw-r--r--src/visibility.h4
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/etc/t-argparse.conf36
-rw-r--r--tests/t-argparse.c42
-rw-r--r--tests/t-argparse.conf8
16 files changed, 520 insertions, 21 deletions
diff --git a/AUTHORS b/AUTHORS
index 6c73617..71dd5d3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -16,7 +16,7 @@ listed individually.
List of Copyright holders
=========================
- Copyright (C) 2001-2019 g10 Code GmbH
+ Copyright (C) 2001-2020 g10 Code GmbH
Copyright (C) 1995-2017 Free Software Foundation, Inc.
Copyright (C) 1998-2006, 2008-2017 Werner Koch
Copyright (C) 2014 Jedi Lin
diff --git a/NEWS b/NEWS
index a60af93..fc91b90 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,18 @@ Noteworthy changes in version 1.38 (unreleased) [C28/A28/R_]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgrt_fnameconcat NEW.
gpgrt_absfnameconcat NEW.
+ gpgrt_set_confdir NEW.
+ gpgrt_argparser NEW.
+ ARGPARSE_FLAG_SYS NEW.
+ ARGPARSE_FLAG_USER NEW.
+ ARGPARSE_FLAG_VERBOSE NEW.
+ ARGPARSE_NO_CONFFILE NEW.
+ ARGPARSE_CONFFILE NEW.
+ ARGPARSE_OPT_CONFFILE NEW.
+ ARGPARSE_conffile NEW.
+ ARGPARSE_noconffile NEW.
+ GPGRT_CONFDIR_USER NEW.
+ GPGRT_CONFDIR_SYS NEW.
Release-info: https://dev.gnupg.org/T
diff --git a/configure.ac b/configure.ac
index ceace2d..bfebf37 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
# configure.ac for libgpg-error
-# Copyright (C) 2003, 2004, 2006, 2010, 2013-2017 g10 Code GmbH
+# Copyright (C) 2003, 2004, 2006, 2010, 2013-2020 g10 Code GmbH
#
# This file is part of libgpg-error.
#
diff --git a/src/argparse.c b/src/argparse.c
index fecd3b5..10e18c0 100644
--- a/src/argparse.c
+++ b/src/argparse.c
@@ -1,7 +1,7 @@
/* argparse.c - Argument Parser for option handling
* Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch
* Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
- * Copyright (C) 2015-2018 g10 Code GmbH
+ * Copyright (C) 2015-2020 g10 Code GmbH
*
* This file is part of Libgpg-error.
*
@@ -36,6 +36,15 @@
#include "gpgrt-int.h"
+
+/* The malloced configuration directories or NULL. */
+static struct
+{
+ char *user;
+ char *sys;
+} confdir;
+
+
/* Special short options which are auto-inserterd. */
#define ARGPARSE_SHORTOPT_HELP 32768
#define ARGPARSE_SHORTOPT_VERSION 32769
@@ -45,16 +54,36 @@
/* A mask for the types. */
#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values. */
+/* The states for the gpgrt_argparser machinery. */
+enum argparser_states
+ {
+ STATE_init = 0,
+ STATE_open_sys,
+ STATE_open_user,
+ STATE_open_cmdline,
+ STATE_read_sys,
+ STATE_read_user,
+ STATE_read_cmdline,
+ STATE_finished
+ };
+
+
/* Internal object of the public gpgrt_argparse_t object. */
struct _gpgrt_argparse_internal_s
{
- int idx;
+ int idx; /* Note that this is saved and restored in _gpgrt_argparser. */
int inarg;
int stopped;
+ int explicit_confopt; /* A conffile option has been given. */
+ char *explicit_conffile; /* Malloced name of an explicit conffile. */
+ unsigned int opt_flags; /* Current option flags. */
+ enum argparser_states state; /* of gpgrt_argparser. */
const char *last;
void *aliases;
const void *cur_alias;
void *iio_list;
+ estream_t conffp;
+ char *confname;
gpgrt_opt_t **opts; /* Malloced array of pointer to user provided opts. */
};
@@ -189,6 +218,7 @@ deinitialize (gpgrt_argparse_t *arg)
{
if (arg->internal)
{
+ xfree (arg->internal->explicit_conffile);
xfree (arg->internal->opts);
xfree (arg->internal);
arg->internal = NULL;
@@ -228,9 +258,15 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
arg->internal->last = NULL;
arg->internal->inarg = 0;
arg->internal->stopped = 0;
+ arg->internal->explicit_confopt = 0;
+ arg->internal->explicit_conffile = NULL;
+ arg->internal->opt_flags = 0;
+ arg->internal->state = STATE_init;
arg->internal->aliases = NULL;
arg->internal->cur_alias = NULL;
arg->internal->iio_list = NULL;
+ arg->internal->conffp = NULL;
+ arg->internal->confname = NULL;
/* Clear the copy of the option list. */
/* Clear the error indicator. */
@@ -240,7 +276,7 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
* However, we do not open the stream and thus we have no way to
* know the current lineno. Using this flag we can allow the
* user to provide a lineno which we don't reset. */
- if (fp || !(arg->flags & ARGPARSE_FLAG_NOLINENO))
+ if (fp || arg->internal->conffp || !(arg->flags & ARGPARSE_FLAG_NOLINENO))
arg->lineno = 0;
/* Need to clear the reset request. */
@@ -312,6 +348,9 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
/* Last option was erroneous. */
const char *s;
+ if (!fp && arg->internal->conffp)
+ fp = arg->internal->conffp;
+
if (fp)
{
if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
@@ -330,10 +369,13 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
s = _("invalid alias definition");
else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
s = _("out of core");
+ else if ( arg->r_opt == ARGPARSE_NO_CONFFILE )
+ s = NULL; /* Error has already been printed. */
else
s = _("invalid option");
- _gpgrt_log_error ("%s:%u: %s\n",
- _gpgrt_fname_get (fp), arg->lineno, s);
+ if (s)
+ _gpgrt_log_error ("%s:%u: %s\n",
+ _gpgrt_fname_get (fp), arg->lineno, s);
}
else
{
@@ -353,7 +395,9 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
_gpgrt_log_error (_("command \"%.50s\" is ambiguous\n"),s );
else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
- _gpgrt_log_error ("%s\n", _("out of core\n"));
+ _gpgrt_log_error ("%s\n", _("out of core"));
+ else if ( arg->r_opt == ARGPARSE_NO_CONFFILE)
+ ; /* Error has already been printed. */
else
_gpgrt_log_error (_("invalid option \"%.50s\"\n"), s);
}
@@ -824,6 +868,281 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig)
}
+/* Return true if the list of options OPTS has any option marked with
+ * ARGPARSE_OPT_CONFFILE. */
+static int
+any_opt_conffile (gpgrt_opt_t *opts)
+{
+ int i;
+
+ for (i=0; opts[i].short_opt; i++ )
+ if ((opts[i].flags & ARGPARSE_OPT_CONFFILE))
+ return 1;
+ return 0;
+}
+
+
+/* The full arg parser which handles option files and command line
+ * arguments. The behaviour depends on the combinations of CONFNAME
+ * and the ARGPARSE_FLAG_xxx values:
+ *
+ * | CONFNAME | SYS | USER | Action |
+ * |----------+-----+------+--------------------|
+ * | NULL | - | - | cmdline |
+ * | string | 0 | 1 | user, cmdline |
+ * | string | 1 | 0 | sys, cmdline |
+ * | string | 1 | 1 | sys, user, cmdline |
+ *
+ * Note that if an option has been flagged with ARGPARSE_OPT_CONFFILE
+ * and a type of ARGPARSE_TYPE_STRING that option is not returned but
+ * the specified configuration file is processed directly; if
+ * ARGPARSE_TYPE_NONE is used no user configuration files are
+ * processed and from the system configuration files only those which
+ * are immutable are processed. The string values for CONFNAME shall
+ * not include a directory part, because that is taken from the values
+ * set by gpgrt_set_confdir.
+ */
+int
+_gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts,
+ const char *confname)
+{
+ /* First check whether releasing the resources has been requested. */
+ if (arg && !opts)
+ {
+ deinitialize (arg);
+ return 0;
+ }
+
+ /* Make sure that the internal data object is ready and also print
+ * warnings or errors from the last iteration. */
+ if (initialize (arg, opts, NULL))
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
+ next_state:
+ switch (arg->internal->state)
+ {
+ case STATE_init:
+ if (any_opt_conffile (opts))
+ {
+ /* The list of option allow for conf files
+ * (e.g. gpg's "--option FILE" and "--no-options")
+ * Now check whether one was really given on the
+ * command line. */
+ int *save_argc = arg->argc;
+ char ***save_argv = arg->argv;
+ unsigned int save_flags = arg->flags;
+ int save_idx = arg->internal->idx;
+ int any_no_conffile = 0;
+
+ arg->flags = (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
+ while (arg_parse (arg, opts))
+ {
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ {
+ arg->internal->explicit_confopt = 1;
+ if (arg->r_type == ARGPARSE_TYPE_STRING
+ && !arg->internal->explicit_conffile)
+ {
+ /* Store the first conffile name. All further
+ * conf file options are not handled. */
+ arg->internal->explicit_conffile
+ = xtrystrdup (arg->r.ret_str);
+ if (!arg->internal->explicit_conffile)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
+ }
+ else if (arg->r_type == ARGPARSE_TYPE_NONE)
+ any_no_conffile = 1;
+ }
+ }
+ if (any_no_conffile)
+ {
+ /* A NoConffile option overrides any other conf file option. */
+ xfree (arg->internal->explicit_conffile);
+ arg->internal->explicit_conffile = NULL;
+ }
+ /* Restore parser. */
+ arg->argc = save_argc;
+ arg->argv = save_argv;
+ arg->flags = save_flags;
+ arg->internal->idx = save_idx;
+
+ }
+
+ if (confname && *confname)
+ {
+ if ((arg->flags & ARGPARSE_FLAG_SYS))
+ arg->internal->state = STATE_open_sys;
+ else if ((arg->flags & ARGPARSE_FLAG_USER))
+ arg->internal->state = STATE_open_user;
+ else
+ return (arg->r_opt = ARGPARSE_INVALID_ARG);
+ }
+ else
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+
+ case STATE_open_sys:
+ xfree (arg->internal->confname);
+ arg->internal->confname = _gpgrt_fnameconcat
+ (confdir.sys? confdir.sys : "/etc", confname, NULL);
+ arg->lineno = 0;
+ _gpgrt_fclose (arg->internal->conffp);
+ arg->internal->conffp = _gpgrt_fopen (arg->internal->confname, "r");
+ /* FIXME: Add a callback. */
+ /* if (arg->internal->conffp && is_secured_file (fileno (configfp)))*/
+ /* { */
+ /* es_fclose (arg->internal->conffp); */
+ /* arg->internal->conffp = NULL; */
+ /* gpg_err_set_errno (EPERM); */
+ /* } */
+ if (!arg->internal->conffp)
+ {
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE))
+ _gpgrt_log_info (_("Note: no default option file '%s'\n"),
+ arg->internal->confname);
+ if ((arg->flags & ARGPARSE_FLAG_USER))
+ arg->internal->state = STATE_open_user;
+ else
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+ }
+
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE))
+ _gpgrt_log_info (_("reading options from '%s'\n"),
+ arg->internal->confname);
+ arg->internal->state = STATE_read_sys;
+ arg->r.ret_str = xtrystrdup (arg->internal->confname);
+ if (!arg->r.ret_str)
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ else
+ {
+ gpgrt_annotate_leaked_object (arg->r.ret_str);
+ arg->r_opt = ARGPARSE_CONFFILE;
+ arg->r_type = ARGPARSE_TYPE_STRING;
+ }
+ break;
+
+ case STATE_open_user:
+ if (arg->internal->explicit_confopt
+ && arg->internal->explicit_conffile)
+ {
+ /* An explict option to use a specific configuration file
+ * has been given - use that one. */
+ xfree (arg->internal->confname);
+ arg->internal->confname
+ = xtrystrdup (arg->internal->explicit_conffile);
+ if (!arg->internal->confname)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+ }
+ else if (arg->internal->explicit_confopt)
+ {
+ /* An explict option not to use a configuration file has
+ * been given - leap direct to command line reading. */
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+ }
+ else
+ {
+ /* Use the standard configure file. */
+ xfree (arg->internal->confname);
+ arg->internal->confname = _gpgrt_fnameconcat
+ (confdir.user? confdir.user : "/FIXME", confname, NULL);
+ }
+ arg->lineno = 0;
+ _gpgrt_fclose (arg->internal->conffp);
+ arg->internal->conffp = _gpgrt_fopen (arg->internal->confname, "r");
+ /* FIXME: Add a callback. */
+ /* if (arg->internal->conffp && is_secured_file (fileno (configfp)))*/
+ /* { */
+ /* es_fclose (arg->internal->conffp); */
+ /* arg->internal->conffp = NULL; */
+ /* gpg_err_set_errno (EPERM); */
+ /* } */
+ if (!arg->internal->conffp)
+ {
+ arg->internal->state = STATE_open_cmdline;
+ if (arg->internal->explicit_confopt)
+ {
+ _gpgrt_log_error (_("option file '%s': %s\n"),
+ arg->internal->confname, strerror (errno));
+ return (arg->r_opt = ARGPARSE_NO_CONFFILE);
+ }
+ else
+ {
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE))
+ _gpgrt_log_info (_("Note: no default option file '%s'\n"),
+ arg->internal->confname);
+ goto next_state;
+ }
+ }
+
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE))
+ _gpgrt_log_info (_("reading options from '%s'\n"),
+ arg->internal->confname);
+ arg->internal->state = STATE_read_user;
+ arg->r.ret_str = xtrystrdup (arg->internal->confname);
+ if (!arg->r.ret_str)
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ else
+ {
+ gpgrt_annotate_leaked_object (arg->r.ret_str);
+ arg->r_opt = ARGPARSE_CONFFILE;
+ arg->r_type = ARGPARSE_TYPE_STRING;
+ }
+ break;
+
+ case STATE_open_cmdline:
+ xfree (arg->internal->confname);
+ arg->internal->confname = NULL;
+ arg->r_opt = ARGPARSE_CONFFILE;
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ arg->r.ret_str = NULL;
+ arg->internal->state = STATE_read_cmdline;
+ break;
+
+ case STATE_read_sys:
+ arg->r_opt = _gpgrt_argparse (arg->internal->conffp, arg, opts);
+ if (!arg->r_opt)
+ {
+ arg->internal->state = STATE_open_user;
+ goto next_state;
+ }
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ goto next_state; /* Already handled - again. */
+ break;
+
+ case STATE_read_user:
+ arg->r_opt = _gpgrt_argparse (arg->internal->conffp, arg, opts);
+ if (!arg->r_opt)
+ {
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+ }
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ goto next_state; /* Already handled - again. */
+ break;
+
+ case STATE_read_cmdline:
+ arg->r_opt = _gpgrt_argparse (arg->internal->conffp, arg, opts);
+ if (!arg->r_opt)
+ {
+ arg->internal->state = STATE_finished;
+ goto next_state;
+ }
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ goto next_state; /* Already handled - again. */
+ break;
+
+ case STATE_finished:
+ arg->r_opt = 0;
+ break;
+ }
+
+ return arg->r_opt;
+}
+
+
/* Given the list of options OPTS and a keyword, return the index of
* the long option macthing KEYWORD. On error -1 is retruned for not
* found or -2 for ambigious keyword. */
@@ -1149,6 +1468,7 @@ set_opt_arg (gpgrt_argparse_t *arg, unsigned flags, char *s)
int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
long l;
+ arg->internal->opt_flags = flags;
switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
{
case ARGPARSE_TYPE_LONG:
@@ -1591,3 +1911,55 @@ _gpgrt_set_fixed_string_mapper (const char *(*f)(const char*))
{
fixed_string_mapper = f;
}
+
+
+/* Register a configuration directory for use by the argparse
+ * functions. The defined values for WHAT are:
+ *
+ * GPGRT_CONFDIR_SYS The systems's configuration dir.
+ * The default is /etc
+ *
+ * GPGRT_CONFDIR_USER The user's configuration directory.
+ * The default is $HOME.
+ *
+ * A trailing slash is ignored; to have the function lookup
+ * configuration files in the current directory, use ".". There is no
+ * error return; more configuraion values may be added in future
+ * revisions of this library.
+ */
+void
+_gpgrt_set_confdir (int what, const char *name)
+{
+ char *buf, *p;
+
+ if (what == GPGRT_CONFDIR_SYS)
+ {
+ _gpgrt_free (confdir.sys);
+ buf = confdir.sys = _gpgrt_strdup (name);
+ }
+ else if (what == GPGRT_CONFDIR_USER)
+ {
+ _gpgrt_free (confdir.user);
+ buf = confdir.user = _gpgrt_strdup (name);
+ }
+ else
+ return;
+
+ if (!buf)
+ _gpgrt_log_fatal ("out of core in %s\n", __func__);
+#ifdef HAVE_W32_SYSTEM
+ for (p=buf; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+#endif
+ /* Strip trailing slashes unless buf is "/" or any other single char
+ * string. */
+ if (*buf)
+ {
+ for (p=buf + strlen (buf)-1; p > buf; p--)
+ if (*p == '/')
+ *p = 0;
+ else
+ break;
+ }
+}
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index 4e3b5d7..537d3cf 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -229,6 +229,9 @@ EXPORTS
gpgrt_add_emergency_cleanup @174
gpgrt_abort @175
+ gpgrt_set_confdir @176
+ gpgrt_argparse @177
+
gpgrt_fnameconcat @178
gpgrt_absfnameconcat @179
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index 470021d..d812326 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -1,5 +1,5 @@
/* gpg-error.h or gpgrt.h - Common code for GnuPG and others. -*- c -*-
- * Copyright (C) 2001-2019 g10 Code GmbH
+ * Copyright (C) 2001-2020 g10 Code GmbH
*
* This file is part of libgpg-error (aka libgpgrt).
*
@@ -1180,7 +1180,10 @@ typedef struct
#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
#define ARGPARSE_FLAG_RESET 128 /* Request to reset the internal state. */
#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */
-#define ARGPARSE_FLAG_NOLINENO 512 /* Do not zero the lineno field. */
+#define ARGPARSE_FLAG_NOLINENO 512 /* Do not zero the lineno field. */
+#define ARGPARSE_FLAG_SYS 1024 /* Use system config file. */
+#define ARGPARSE_FLAG_USER 2048 /* Use user config file. */
+#define ARGPARSE_FLAG_VERBOSE 4096 /* Print additional argparser info. */
/* Constants for (gpgrt_argparse_t).err. */
#define ARGPARSE_PRINT_WARNING 1 /* Print a diagnostic. */
@@ -1199,6 +1202,8 @@ typedef struct
#define ARGPARSE_INVALID_ALIAS (-10)
#define ARGPARSE_OUT_OF_CORE (-11)
#define ARGPARSE_INVALID_ARG (-12)
+#define ARGPARSE_NO_CONFFILE (-14)
+#define ARGPARSE_CONFFILE (-15)
/* Flags for the option descriptor (gpgrt_opt_t)->flags. Note that
* a TYPE constant may be or-ed with the OPT constants. */
@@ -1211,6 +1216,7 @@ typedef struct
#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */
#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */
+#define ARGPARSE_OPT_CONFFILE (1<<8) /* The value is a conffile. */
/* A set of macros to make option definitions easier to read. */
#define ARGPARSE_x(s,l,t,f,d) \
@@ -1277,7 +1283,13 @@ typedef struct
#define ARGPARSE_c(s,l,d) \
{ (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
-#define ARGPARSE_ignore(s,l) \
+#define ARGPARSE_conffile(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING|ARGPARSE_OPT_CONFFILE), (d) }
+
+#define ARGPARSE_noconffile(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE|ARGPARSE_OPT_CONFFILE), (d) }
+
+#define ARGPARSE_ignore(s,l) \
{ (s), (l), (ARGPARSE_OPT_IGNORE), "@" }
#define ARGPARSE_group(s,d) \
@@ -1289,16 +1301,23 @@ typedef struct
#endif /* GPGRT_ENABLE_ARGPARSE_MACROS */
+/* Values used for gpgrt_set_confdir. */
+#define GPGRT_CONFDIR_USER 1 /* The user's configuration dir. */
+#define GPGRT_CONFDIR_SYS 2 /* The systems's configuration dir. */
+
/* Take care: gpgrt_argparse keeps state in ARG and requires that
* either ARGPARSE_FLAG_RESET is used after OPTS has been changed or
* gpgrt_argparse (NULL, ARG, NULL) is called first. */
int gpgrt_argparse (gpgrt_stream_t fp,
gpgrt_argparse_t *arg, gpgrt_opt_t *opts);
+int gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts,
+ const char *confname);
void gpgrt_usage (int level);
const char *gpgrt_strusage (int level);
void gpgrt_set_strusage (const char *(*f)(int));
void gpgrt_set_usage_outfnc (int (*f)(int, const char *));
void gpgrt_set_fixed_string_mapper (const char *(*f)(const char*));
+void gpgrt_set_confdir (int what, const char *name);
/*
diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index 594342b..347235f 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -180,11 +180,13 @@ GPG_ERROR_1.0 {
# gpgrt_release_process;
gpgrt_argparse;
+ gpgrt_argparser;
gpgrt_usage;
gpgrt_strusage;
gpgrt_set_strusage;
gpgrt_set_usage_outfnc;
gpgrt_set_fixed_string_mapper;
+ gpgrt_set_confdir;
gpgrt_b64enc_start;
gpgrt_b64enc_write;
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index 97f0533..beb55ac 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -749,11 +749,14 @@ void _gpgrt_release_process (pid_t pid);
* Local prototypes for argparse.
*/
int _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts);
+int _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts,
+ const char *confname);
void _gpgrt_usage (int level);
const char *_gpgrt_strusage (int level);
void _gpgrt_set_strusage (const char *(*f)(int));
void _gpgrt_set_usage_outfnc (int (*fnc)(int, const char *));
void _gpgrt_set_fixed_string_mapper (const char *(*f)(const char*));
+void _gpgrt_set_confdir (int what, const char *name);
/*
diff --git a/src/version.c b/src/version.c
index c65f5e9..276ee04 100644
--- a/src/version.c
+++ b/src/version.c
@@ -39,7 +39,7 @@ cright_blurb (void)
static const char blurb[] =
"\n\n"
"This is Libgpg-error " PACKAGE_VERSION " - A runtime library\n"
- "Copyright 2001-2019 g10 Code GmbH\n"
+ "Copyright 2001-2020 g10 Code GmbH\n"
"\n"
"(" BUILD_REVISION " " BUILD_TIMESTAMP ")\n"
"\n\n";
diff --git a/src/versioninfo.rc.in b/src/versioninfo.rc.in
index 30aab66..d42d8fe 100644
--- a/src/versioninfo.rc.in
+++ b/src/versioninfo.rc.in
@@ -40,7 +40,7 @@ BEGIN
VALUE "FileDescription", "libgpg-error - Common error codes\0"
VALUE "FileVersion", "@LIBGPG_ERROR_LT_CURRENT@.@LIBGPG_ERROR_LT_AGE@.@LIBGPG_ERROR_LT_REVISION@.@BUILD_REVISION@\0"
VALUE "InternalName", "libgpg-error\0"
- VALUE "LegalCopyright", "Copyright � 2019 g10 Code GmbH\0"
+ VALUE "LegalCopyright", "Copyright � 2020 g10 Code GmbH\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "libgpg-error.dll\0"
VALUE "PrivateBuild", "\0"
diff --git a/src/visibility.c b/src/visibility.c
index 5f88aad..ea55d54 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1139,6 +1139,12 @@ gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts)
return _gpgrt_argparse (fp, arg, opts);
}
+int
+gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, const char *name)
+{
+ return _gpgrt_argparser (arg, opts, name);
+}
+
void
gpgrt_usage (int level)
{
@@ -1169,6 +1175,12 @@ gpgrt_set_fixed_string_mapper (const char *(*f)(const char*))
_gpgrt_set_fixed_string_mapper (f);
}
+void
+gpgrt_set_confdir (int what, const char *name)
+{
+ _gpgrt_set_confdir (what, name);
+}
+
/* Compare program versions. */
diff --git a/src/visibility.h b/src/visibility.h
index 192f733..0759d2f 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -208,11 +208,13 @@ MARK_VISIBLE (gpgrt_release_process)
#endif
MARK_VISIBLE (gpgrt_argparse)
+MARK_VISIBLE (gpgrt_argparser)
MARK_VISIBLE (gpgrt_usage)
MARK_VISIBLE (gpgrt_strusage)
MARK_VISIBLE (gpgrt_set_strusage)
MARK_VISIBLE (gpgrt_set_fixed_string_mapper);
MARK_VISIBLE (gpgrt_set_usage_outfnc);
+MARK_VISIBLE (gpgrt_set_confdir);
MARK_VISIBLE (gpgrt_cmp_version);
@@ -389,11 +391,13 @@ MARK_VISIBLE (gpgrt_absfnameconcat);
#define gpgrt_release_process _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_argparse _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_argparser _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_usage _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_set_strusage _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_strusage _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_set_usage_outfnc _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_set_fixed_string_mapper _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_set_confdir _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_cmp_version _gpgrt_USE_UNDERSCORED_FUNCTION
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 39ca241..2d199da 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -25,6 +25,8 @@ else
extra_includes =
endif
+EXTRA_DIST = t-argparse.conf etc/t-argparse.conf
+
gpg_error_lib = ../src/libgpg-error.la
TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll t-b64 \
diff --git a/tests/etc/t-argparse.conf b/tests/etc/t-argparse.conf
new file mode 100644
index 0000000..87bff72
--- /dev/null
+++ b/tests/etc/t-argparse.conf
@@ -0,0 +1,36 @@
+# Global test config file for t-argparse
+
+# Options applied to all user's config files
+#verbose
+
+#[user :staff]
+# These option are applied to all users the group staff up until the
+# next [user statement]
+
+#[+force]
+
+#[ignore]
+
+# The compliance is set immutable for these users
+verbose
+
+#no-verbose
+
+
+# (parsing does not stop for a group)
+#[user wk]
+# Options for user wk
+
+# Change the immutable flag back to mutable.
+#[] compliance gnupg
+
+# Default key for wk
+my-option 42
+
+# Parsing stops for user WK here.
+
+#[user *]
+# Options for all users which have no specific user sections above
+
+# The default algorithm for new keys is set to this.
+a-long-option
diff --git a/tests/t-argparse.c b/tests/t-argparse.c
index 277d860..b2b6e51 100644
--- a/tests/t-argparse.c
+++ b/tests/t-argparse.c
@@ -1,5 +1,5 @@
/* t-argparse.c - Check the argparse API
- * Copyright (C) 2018 g10 Code GmbH
+ * Copyright (C) 2018, 2020 g10 Code GmbH
*
* This file is part of Libgpg-error.
*
@@ -27,7 +27,8 @@
#include <string.h>
#include <assert.h>
-#include "../src/gpg-error.h"
+#define PGM "t-argparse"
+#include "t-common.h"
static struct {
@@ -49,7 +50,7 @@ my_strusage (int level)
switch (level)
{
- case 9: p = "GPL-2.0-or-later"; break;
+ case 9: p = "LGPL-2.1-or-later"; break;
case 11: p = "t-argparse"; break;
@@ -74,26 +75,47 @@ main (int argc, char **argv)
ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
ARGPARSE_o_i('m', "my-option", 0),
ARGPARSE_s_n(500, "a-long-option", 0 ),
+ ARGPARSE_conffile(501, "options", "|FILE|read options from FILE"),
+ ARGPARSE_noconffile(502, "no-options", "Ignore conf files"),
ARGPARSE_end()
};
gpgrt_argparse_t pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
| ARGPARSE_FLAG_MIXED
- | ARGPARSE_FLAG_ONEDASH) };
+ | ARGPARSE_FLAG_ONEDASH
+ | ARGPARSE_FLAG_SYS
+ | ARGPARSE_FLAG_USER
+ /* | ARGPARSE_FLAG_VERBOSE */
+ ) };
int i;
+ const char *srcdir;
gpgrt_set_strusage (my_strusage);
-
-
- while (gpgrt_argparse (NULL, &pargs, opts))
+ srcdir = getenv ("srcdir");
+ if (!srcdir)
+ srcdir = ".";
+ gpgrt_set_confdir (GPGRT_CONFDIR_USER, srcdir);
+ {
+ char *p = gpgrt_fnameconcat (srcdir, "etc", NULL);
+ gpgrt_set_confdir (GPGRT_CONFDIR_SYS, p);
+ xfree (p);
+ }
+
+ while (gpgrt_argparser (&pargs, opts, PGM".conf"))
{
+ /* printf ("got option %d\n", pargs.r_opt); */
switch (pargs.r_opt)
{
+ case ARGPARSE_CONFFILE:
+ printf ("current conffile='%s'\n",
+ pargs.r.ret_str? pargs.r.ret_str: "[cmdline]");
+ break;
case ARGPARSE_IS_ARG :
printf ("arg='%s'\n", pargs.r.ret_str);
break;
+
case 'v': opt.verbose++; break;
case 'e': opt.echo++; break;
- case 'd': opt.debug++; break;
+ case 'd': opt.debug++; debug=1;break;
case 'o': opt.outfile = pargs.r.ret_str; break;
case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
@@ -122,5 +144,9 @@ main (int argc, char **argv)
gpgrt_argparse (NULL, &pargs, NULL);
+ (void)show;
+ (void)fail;
+ (void)die;
+
return 0;
}
diff --git a/tests/t-argparse.conf b/tests/t-argparse.conf
new file mode 100644
index 0000000..0bbdd3e
--- /dev/null
+++ b/tests/t-argparse.conf
@@ -0,0 +1,8 @@
+# User test config file for t-argparse
+
+# Options applied to all user's config files
+echo
+
+my-option 4711
+
+verbose