summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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