diff options
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | NEWS | 12 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/argparse.c | 384 | ||||
-rw-r--r-- | src/gpg-error.def.in | 3 | ||||
-rw-r--r-- | src/gpg-error.h.in | 25 | ||||
-rw-r--r-- | src/gpg-error.vers | 2 | ||||
-rw-r--r-- | src/gpgrt-int.h | 3 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/versioninfo.rc.in | 2 | ||||
-rw-r--r-- | src/visibility.c | 12 | ||||
-rw-r--r-- | src/visibility.h | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/etc/t-argparse.conf | 36 | ||||
-rw-r--r-- | tests/t-argparse.c | 42 | ||||
-rw-r--r-- | tests/t-argparse.conf | 8 |
16 files changed, 520 insertions, 21 deletions
@@ -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 @@ -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 |