From 6fc2d7cb8ce9e08cb189608466803ee7c8eb6930 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Feb 2020 21:03:32 +0100 Subject: core: Add parser for meta commands to gpgrt_argparser. * src/gpg-error.h.in (ARGPARSE_INVALID_META): New (ARGPARSE_UNKNOWN_META, ARGPARSE_UNEXPECTED_META): New. * src/argparse.c (struct _gpgrt_argparse_internal_s): Add flag insysconfig. (initialize): Init flag. Add error strings. (_gpgrt_argparser): Set that flag. (_gpgrt_argparse): Add parsing of meta commands. * tests/etc/t-argparse.conf: Add some test cases. * tests/t-argparse.conf: Ditto. * tests/t-argparse.c (main): Die only after printing all warnings. -- Noe that this is just the framework to add meta commands to the global config file. We also need to get away from fixes test config files and create them on the fly to that we are able to test also errors. GnuPG-bug-id: 4788 --- NEWS | 3 ++ src/argparse.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-- src/gpg-error.h.in | 3 ++ tests/etc/t-argparse.conf | 42 +++++++++++++++++++-------- tests/t-argparse.c | 5 ++-- tests/t-argparse.conf | 3 ++ 6 files changed, 113 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 1309dcf..d212f39 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ Noteworthy changes in version 1.38 (unreleased) [C28/A28/R_] ARGPARSE_CONFFILE NEW. ARGPARSE_OPT_CONFFILE NEW. ARGPARSE_PERMISSION_ERROR NEW. + ARGPARSE_INVALID_META NEW. + ARGPARSE_UNKNOWN_META NEW. + ARGPARSE_UNEXPECTED_META NEW. ARGPARSE_conffile NEW. ARGPARSE_noconffile NEW. GPGRT_CONFDIR_USER NEW. diff --git a/src/argparse.c b/src/argparse.c index 6f6431d..765c96c 100644 --- a/src/argparse.c +++ b/src/argparse.c @@ -86,6 +86,7 @@ struct _gpgrt_argparse_internal_s int idx; /* Note that this is saved and restored in _gpgrt_argparser. */ int inarg; int stopped; + int insysconfig; /* Processing global config file. */ 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. */ @@ -278,6 +279,7 @@ 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->insysconfig = 0; arg->internal->explicit_confopt = 0; arg->internal->explicit_conffile = NULL; arg->internal->opt_flags = 0; @@ -393,6 +395,12 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp) s = _("out of core"); else if ( arg->r_opt == ARGPARSE_NO_CONFFILE ) s = NULL; /* Error has already been printed. */ + else if ( arg->r_opt == ARGPARSE_INVALID_META ) + s = _("invalid meta command"); + else if ( arg->r_opt == ARGPARSE_UNKNOWN_META ) + s = _("unknown meta command"); + else if ( arg->r_opt == ARGPARSE_UNEXPECTED_META ) + s = _("unexpected meta command"); else s = _("invalid option"); if (s) @@ -422,6 +430,12 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp) _gpgrt_log_error ("%s\n", _("permission error")); else if ( arg->r_opt == ARGPARSE_NO_CONFFILE) ; /* Error has already been printed. */ + else if ( arg->r_opt == ARGPARSE_INVALID_META ) + _gpgrt_log_error ("%s\n", _("invalid meta command")); + else if ( arg->r_opt == ARGPARSE_UNKNOWN_META ) + _gpgrt_log_error ("%s\n", _("unknown meta command")); + else if ( arg->r_opt == ARGPARSE_UNEXPECTED_META ) + _gpgrt_log_error ("%s\n",_("unexpected meta command")); else _gpgrt_log_error (_("invalid option \"%.50s\"\n"), s); } @@ -593,6 +607,10 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) Acopyarg, /* Copy the argument. */ Akeyword_eol, /* Got keyword at end of line. */ Akeyword_spc, /* Got keyword at space. */ + Acopymetacmd, /* Copy a meta command. */ + Askipmetacmd, /* Skip spaces after metacmd. */ + Askipmetacmd2,/* Skip comment after metacmd. */ + Ametacmd, /* Process the metacmd. */ Askipandleave /* Skip the rest of the line and then leave. */ } state; gpgrt_opt_t **opts; @@ -718,6 +736,24 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) goto leave; } } /* (end state Akeyword_eol/Akeyword_spc) */ + else if (state == Ametacmd) + { + gpgrt_assert (*keyword == '['); + trim_spaces (keyword+1); + if (!keyword[1]) + { + arg->r_opt = ARGPARSE_INVALID_META; /* Empty. */ + goto leave; + } + if (!arg->internal->insysconfig) + { + arg->r_opt = ARGPARSE_UNEXPECTED_META; + goto leave; + } + /* _gpgrt_log_debug ("Got meta command '%s'\n", keyword+1); */ + state = Ainit; + i = 0; + } /* Get the next character from the line. */ if (unread_buf_count) @@ -737,6 +773,16 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) state = Akeyword_eol; goto nextstate; } + else if (state == Acopymetacmd) + { + arg->r_opt = ARGPARSE_INVALID_META; /* "]" missing */ + goto leave; + } + else if (state == Askipmetacmd || state == Askipmetacmd2) + { + state = Ametacmd; + goto nextstate; + } else if (state == Awaitarg) { /* No argument found at the end of the line. */ @@ -833,14 +879,30 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) ; /* Skip leading white space. */ else if (state == Ainit && c == '#' ) state = Acomment; /* Start of a comment. */ - else if (state == Acomment) + else if (state == Acomment || state == Askipmetacmd2) ; /* Skip comments. */ + else if (state == Askipmetacmd) + { + if (c == '#') + state = Askipmetacmd2; + else if (!(isascii (c) && isspace(c))) + { + arg->r_opt = ARGPARSE_INVALID_META; + state = Askipandleave; + } + } else if (state == Acopykeyword && isascii (c) && isspace(c)) { keyword[i] = 0; state = Akeyword_spc; goto nextstate; } + else if (state == Acopymetacmd && c == ']') + { + keyword[i] = 0; + state = Askipmetacmd; + goto nextstate; + } else if (state == Awaitarg) { /* Skip leading spaces of the argument. */ @@ -902,10 +964,14 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG; state = Askipandleave; /* Skip rest of line and leave. */ } + else if (!i) + { + state = c == '[' ? Acopymetacmd : Acopykeyword; + keyword[i++] = c; + } else { keyword[i++] = c; - state = Acopykeyword; } } @@ -1173,6 +1239,7 @@ _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, _gpgrt_log_info (_("reading options from '%s'\n"), arg->internal->confname); arg->internal->state = STATE_read_sys; + arg->internal->insysconfig = 1; arg->r.ret_str = xtrystrdup (arg->internal->confname); if (!arg->r.ret_str) arg->r_opt = ARGPARSE_OUT_OF_CORE; @@ -1237,6 +1304,7 @@ _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, arg->internal->idx = 0; arg->internal->stopped = 0; arg->internal->inarg = 0; + arg->internal->insysconfig = 0; _gpgrt_fclose (arg->internal->conffp); arg->internal->conffp = _gpgrt_fopen (arg->internal->confname, "r"); if (!arg->internal->conffp) @@ -1280,6 +1348,7 @@ _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, arg->internal->idx = 0; arg->internal->stopped = 0; arg->internal->inarg = 0; + arg->internal->insysconfig = 0; if (!arg->argc || !arg->argv || !*arg->argv) { /* No or empty argument vector - don't bother to parse things. */ diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in index e353700..165881b 100644 --- a/src/gpg-error.h.in +++ b/src/gpg-error.h.in @@ -1206,6 +1206,9 @@ typedef struct #define ARGPARSE_PERMISSION_ERROR (-13) #define ARGPARSE_NO_CONFFILE (-14) #define ARGPARSE_CONFFILE (-15) +#define ARGPARSE_INVALID_META (-16) +#define ARGPARSE_UNKNOWN_META (-17) +#define ARGPARSE_UNEXPECTED_META (-18) /* Flags for the option descriptor (gpgrt_opt_t)->flags. Note that * a TYPE constant may be or-ed with the OPT constants. */ diff --git a/tests/etc/t-argparse.conf b/tests/etc/t-argparse.conf index 87bff72..0852e71 100644 --- a/tests/etc/t-argparse.conf +++ b/tests/etc/t-argparse.conf @@ -3,33 +3,51 @@ # 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] +[group :staff] +# These option are applied to all users of the group staff up until +# the next [group] or [user] statement. -#[+force] +[+force] +# All following option are forced and thus ignored when set in user +# config files. Valid until the next [user] statement. Take care +# that there are often "no-", "disable-", or "enable-" versions of +# options; these should be explictly marked as ignored so that they +# can't be used to override the force attribute. -#[ignore] +[ignore] # The compliance is set immutable for these users verbose +# The next shall raise an error due to the garpage at the end. +#[+ignore] fooo + + +#[+ignore-all] +# All options are ignored. + + +[-ignore] # Comment at line end +# Options wich shall not be ignored. */ #no-verbose -# (parsing does not stop for a group) -#[user wk] -# Options for user wk +[user john ] +# Options for user john -# Change the immutable flag back to mutable. -#[] compliance gnupg +# Change the immutable attribute back to mutable. +[-force] +#compliance gnupg -# Default key for wk +# Default key for user john my-option 42 # Parsing stops for user WK here. -#[user *] +[group * ] +# Options for all group which have no specific group sections above + +[user *] # Options for all users which have no specific user sections above # The default algorithm for new keys is set to this. diff --git a/tests/t-argparse.c b/tests/t-argparse.c index b2b6e51..4719819 100644 --- a/tests/t-argparse.c +++ b/tests/t-argparse.c @@ -88,6 +88,7 @@ main (int argc, char **argv) ) }; int i; const char *srcdir; + int any_warn = 0; gpgrt_set_strusage (my_strusage); srcdir = getenv ("srcdir"); @@ -120,7 +121,7 @@ main (int argc, char **argv) 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; case 500: opt.a_long_one++; break; - default : pargs.err = ARGPARSE_PRINT_ERROR; break; + default : pargs.err = ARGPARSE_PRINT_WARNING; any_warn = 1; break; } } for (i=0; i < argc; i++ ) @@ -148,5 +149,5 @@ main (int argc, char **argv) (void)fail; (void)die; - return 0; + return !!any_warn; } diff --git a/tests/t-argparse.conf b/tests/t-argparse.conf index 0bbdd3e..e2c96e2 100644 --- a/tests/t-argparse.conf +++ b/tests/t-argparse.conf @@ -3,6 +3,9 @@ # Options applied to all user's config files echo +# The next should be flagged as unexpected meta command. +#[ignore] + my-option 4711 verbose -- cgit v1.2.3