aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2024-02-06 13:53:59 +0000
committerWerner Koch <[email protected]>2024-02-06 13:53:59 +0000
commitb113114c7498fc6c48065a8c4816c610c6f08198 (patch)
tree1970a988d092ca7dd82f7386125c393f15305862
parentgpgrt-config: Avoid warning about literals for curly braces. (diff)
downloadlibgpg-error-b113114c7498fc6c48065a8c4816c610c6f08198.tar.gz
libgpg-error-b113114c7498fc6c48065a8c4816c610c6f08198.zip
argparser: Implement a command mode.
* src/gpg-error.h.in (ARGPARSE_FLAG_COMMAND): New. * src/argparse.c (struct _gpgrt_argparse_internal_s): Add flags explicit_cmd_mode, cmd_mode, and command_seen. (initialize): Init them. Mark default commands as commands. (handle_meta_command): New. (handle_metacmd): Add "command-mode" and "-command-mode". (find_long_option): Add arg only_commands. (arg_parse): Factor some code out to ... (handle_special_commands): new. (arg_parse): Implement the command-mode. * tests/t-argparse.c (main): Add some testing code. -- GnuPG-bug-id: 6978
-rw-r--r--NEWS8
-rw-r--r--src/argparse.c155
-rw-r--r--src/gpg-error.h.in2
-rw-r--r--tests/t-argparse.c16
-rw-r--r--tests/t-argparse.conf5
5 files changed, 144 insertions, 42 deletions
diff --git a/NEWS b/NEWS
index 3679581..a8b60f4 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,14 @@ Noteworthy changes in version 1.48 (unreleased) [C34/A34/R_]
* New configure option --with-libtool-modification. [T6619]
+ * New option parser flag to detect commands given without a double
+ dash. There is also the new meta command [command-mode] to set
+ this flag via a config file. [T6978]
+
+ * Interface changes relative to the 1.47 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ARGPARSE_FLAG_COMMAND NEW.
+
Release-info: https://dev.gnupg.org/T6441
diff --git a/src/argparse.c b/src/argparse.c
index 2399c43..bd44aef 100644
--- a/src/argparse.c
+++ b/src/argparse.c
@@ -117,14 +117,17 @@ struct _gpgrt_argparse_internal_s
unsigned int in_sysconf:1; /* Processing global config file. */
unsigned int mark_forced:1; /* Mark options as forced. */
unsigned int mark_ignore:1; /* Mark options as to be ignored. */
- unsigned int explicit_ignore:1; /* Option has explicitly been set
- * to ignore or unignore. */
+ unsigned int explicit_ignore:1; /* Option has explicitly been set */
+ /* to be ignored or un-ignoref. */
+ unsigned int command_seen:1; /* A command option has been seen. */
unsigned int ignore_all_seen:1; /* [ignore-all] has been seen. */
unsigned int user_seen:1; /* A [user] has been seen. */
unsigned int user_wildcard:1; /* A [user *] has been seen. */
unsigned int user_any_active:1; /* Any user section was active. */
unsigned int user_active:1; /* User section active. */
unsigned int expand:1; /* Expand vars in option values. */
+ unsigned int explicit_cmd_mode:1;/* Command mode set via config. */
+ unsigned int cmd_mode:1; /* Command mode according to config. */
unsigned int explicit_confopt:1; /* A conffile option has been given. */
char *explicit_conffile; /* Malloced name of an explicit
* conffile. */
@@ -336,6 +339,9 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
arg->internal->inarg = 0;
arg->internal->stopped = 0;
arg->internal->in_sysconf = 0;
+ arg->internal->command_seen = 0;
+ arg->internal->explicit_cmd_mode = 0;
+ arg->internal->cmd_mode = 0;
arg->internal->user_seen = 0;
arg->internal->user_wildcard = 0;
arg->internal->user_any_active = 0;
@@ -425,7 +431,7 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
if (!seen_help)
{
arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_HELP;
- arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].flags = ARGPARSE_OPT_COMMAND;
arg->internal->opts[i].long_opt = "help";
arg->internal->opts[i].description = "@";
arg->internal->opts[i].ordinal = i;
@@ -434,7 +440,7 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
if (!seen_version)
{
arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_VERSION;
- arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].flags = ARGPARSE_OPT_COMMAND;
arg->internal->opts[i].long_opt = "version";
arg->internal->opts[i].description = "@";
arg->internal->opts[i].ordinal = i;
@@ -444,7 +450,7 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
if (!seen_warranty)
{
arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_WARRANTY;
- arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].flags = ARGPARSE_OPT_COMMAND;
arg->internal->opts[i].long_opt = "warranty";
arg->internal->opts[i].description = "@";
arg->internal->opts[i].ordinal = i;
@@ -454,7 +460,7 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
if (!seen_dump_option_table)
{
arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_DUMP_OPTTBL;
- arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].flags = ARGPARSE_OPT_COMMAND;
arg->internal->opts[i].long_opt = "dump-option-table";
arg->internal->opts[i].description = "@";
arg->internal->opts[i].ordinal = i;
@@ -464,7 +470,7 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
if (!seen_dump_options)
{
arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_DUMP_OPTIONS;
- arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].flags = ARGPARSE_OPT_COMMAND;
arg->internal->opts[i].long_opt = "dump-options";
arg->internal->opts[i].description = "@";
arg->internal->opts[i].ordinal = i;
@@ -1369,6 +1375,21 @@ handle_meta_verbose (gpgrt_argparse_t *arg, unsigned int alternate, char *args)
return 0;
}
+/* Implementation of the "command-mode" command. ARG is the context. If
+ * ALTERNATE is true the command mode is disabled. ARGS is not used. */
+static int
+handle_meta_command (gpgrt_argparse_t *arg, unsigned int alternate, char *args)
+{
+ (void)args;
+
+ arg->internal->explicit_cmd_mode = 1;
+ if (alternate)
+ arg->internal->cmd_mode = 0;
+ else
+ arg->internal->cmd_mode = 1;
+ return 0;
+}
+
/* Implementation of the "expand" command. ARG is the context. If
* ALTERNATE is true expand is reset. ARGS is not used. */
@@ -1422,6 +1443,9 @@ handle_metacmd (gpgrt_argparse_t *arg, char *keyword)
{ "verbose", 0, 0, 1, 1, handle_meta_verbose },
{ "+verbose", 0, 0, 1, 1, handle_meta_verbose },
{ "-verbose", 1, 0, 1, 1, handle_meta_verbose },
+ { "command-mode", 0,0, 1, 0, handle_meta_command },
+ { "+command-mode",0,0, 1, 0, handle_meta_command },
+ { "-command-mode",1,0, 1, 0, handle_meta_command },
{ "echo", 0, 1, 1, 1, handle_meta_echo },
{ "-echo", 1, 1, 1, 1, handle_meta_echo },
{ "info", 0, 1, 1, 0, handle_meta_echo },
@@ -2479,9 +2503,10 @@ _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts,
/* Given the list of options in ARG and a keyword, return the index of
* the long option matching KEYWORD. On error -1 is returned for not
- * found or -2 for ambigious keyword. */
+ * found or -2 for ambiguous keyword. If ONLY_COMMANDS is set only
+ * options marked as commands are considere. */
static int
-find_long_option (gpgrt_argparse_t *arg, const char *keyword)
+find_long_option (gpgrt_argparse_t *arg, const char *keyword, int only_commands)
{
int i;
size_t n;
@@ -2495,9 +2520,24 @@ find_long_option (gpgrt_argparse_t *arg, const char *keyword)
* done. */
if (!*keyword)
return -1;
- for (i=0; i < nopts; i++ )
- if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
- return i;
+ if (only_commands)
+ {
+ /* Note that we consider only options which have just the
+ * command flag set and ignore all option which falsely have
+ * other bits set. */
+ for (i=0; i < nopts; i++ )
+ if (opts[i].flags == ARGPARSE_OPT_COMMAND
+ && opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
+ return i;
+ return -1; /* Not found (no abbreviations in this mode). */
+ }
+ else
+ {
+ for (i=0; i < nopts; i++ )
+ if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
+ return i;
+ }
+
#if 0
{
ALIAS_DEF a;
@@ -2536,6 +2576,48 @@ find_long_option (gpgrt_argparse_t *arg, const char *keyword)
}
+/* Handle special commands like "help" and "version". All of these
+ * commands call exit and thus this function does not return if such a
+ * command was found at IDX. */
+static void
+handle_special_commands (gpgrt_argparse_t *arg, int idx)
+{
+ int i = idx;
+ opttable_t *opts = arg->internal->opts;
+ unsigned int nopts = arg->internal->nopts;
+
+ if (i >= 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_HELP)
+ {
+ show_help (opts, nopts, arg->flags);
+ my_exit (arg, 0);
+ }
+ else if (i >= 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_VERSION)
+ {
+ if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
+ {
+ show_version ();
+ my_exit (arg, 0);
+ }
+ }
+ else if (i >= 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_WARRANTY)
+ {
+ writestrings (0, _gpgrt_strusage (16), "\n", NULL);
+ my_exit (arg, 0);
+ }
+ else if (i >= 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTTBL)
+ dump_option_table (arg);
+ else if (i >= 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS)
+ {
+ for (i=0; i < nopts; i++ )
+ {
+ if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
+ writestrings (0, "--", opts[i].long_opt, "\n", NULL);
+ }
+ my_exit (arg, 0);
+ }
+}
+
+
/* The option parser for command line options. */
static int
arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init)
@@ -2606,39 +2688,11 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init)
argpos = strchr( s+2, '=' );
if ( argpos )
*argpos = 0;
- i = find_long_option (arg, s+2);
+ i = find_long_option (arg, s+2, 0);
if ( argpos )
*argpos = '=';
- if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_HELP)
- {
- show_help (opts, nopts, arg->flags);
- my_exit (arg, 0);
- }
- else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_VERSION)
- {
- if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
- {
- show_version ();
- my_exit (arg, 0);
- }
- }
- else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_WARRANTY)
- {
- writestrings (0, _gpgrt_strusage (16), "\n", NULL);
- my_exit (arg, 0);
- }
- else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTTBL)
- dump_option_table (arg);
- else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS)
- {
- for (i=0; i < nopts; i++ )
- {
- if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
- writestrings (0, "--", opts[i].long_opt, "\n", NULL);
- }
- my_exit (arg, 0);
- }
+ handle_special_commands (arg, i);
if ( i == -2 )
arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
@@ -2650,6 +2704,9 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init)
else
arg->r_opt = opts[i].short_opt;
+ if (i >= 0 && (opts[i].flags & ARGPARSE_OPT_COMMAND))
+ arg->internal->command_seen = 1;
+
if ( i < 0 )
;
else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
@@ -2793,6 +2850,20 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init)
argc--; argv++; idx++;
}
}
+ else if (!arg->internal->command_seen
+ && ((!arg->internal->explicit_cmd_mode
+ && arg->flags & ARGPARSE_FLAG_COMMAND)
+ || (arg->internal->explicit_cmd_mode
+ && arg->internal->cmd_mode))
+ && (i = find_long_option (arg, s, 1)) >= 0)
+ {
+ handle_special_commands (arg, i);
+ arg->internal->opt_flags = opts[i].flags;
+ arg->internal->command_seen = 1;
+ arg->r_opt = opts[i].short_opt;
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ argc--; argv++; idx++; /* Set to next one. */
+ }
else if ( arg->flags & ARGPARSE_FLAG_MIXED )
{
arg->r_opt = ARGPARSE_IS_ARG;
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index bce028e..969076c 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -1200,6 +1200,8 @@ typedef struct
#define ARGPARSE_FLAG_USERVERS 8192 /* Try version-ed user config files. */
#define ARGPARSE_FLAG_WITHATTR 16384 /* Return attribute bits. (Make sure */
/* to act upon ARGPARSE_OPT_IGNORE.) */
+#define ARGPARSE_FLAG_COMMAND 32768 /* Allow commands w/o leading dashes. */
+
/* Constants for (gpgrt_argparse_t).err. */
#define ARGPARSE_PRINT_WARNING 1 /* Print a diagnostic. */
diff --git a/tests/t-argparse.c b/tests/t-argparse.c
index 4d24e5f..6085066 100644
--- a/tests/t-argparse.c
+++ b/tests/t-argparse.c
@@ -68,6 +68,9 @@ main (int argc, char **argv)
{
gpgrt_opt_t opts[] = {
ARGPARSE_verbatim("Now for the options:\n"),
+ ARGPARSE_c (601, "foo", "Command FOO"),
+ ARGPARSE_c (602, "bar", "Command BAR"),
+ ARGPARSE_c (603, "foobar", "Command FOOBAR"),
ARGPARSE_x ('v', "verbose", NONE, 0, "Laut sein"),
ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
"was wir eingegeben haben")),
@@ -96,6 +99,10 @@ main (int argc, char **argv)
int i;
const char *srcdir;
int any_warn = 0;
+ int command = -1;
+
+ if (getenv ("argparse_flag_command"))
+ pargs.flags |= ARGPARSE_FLAG_COMMAND;
gpgrt_set_strusage (my_strusage);
srcdir = getenv ("srcdir");
@@ -139,11 +146,20 @@ main (int argc, char **argv)
case 'M': opt.myopt = 0; break;
case 's': opt.street = pargs.r.ret_str; break;
case 500: opt.a_long_one++; break;
+
+ case 601:
+ case 602:
+ case 603:
+ command = pargs.r_opt;
+ break;
+
default : pargs.err = ARGPARSE_PRINT_WARNING; any_warn = 1; break;
}
}
for (i=0; i < argc; i++ )
printf ("%3d -> (%s)\n", i, argv[i] );
+ if (command >= 0)
+ printf ("Command: %d\n", command);
if (opt.verbose)
puts ("Options:");
if (opt.verbose)
diff --git a/tests/t-argparse.conf b/tests/t-argparse.conf
index a42d1a1..2691553 100644
--- a/tests/t-argparse.conf
+++ b/tests/t-argparse.conf
@@ -8,6 +8,11 @@ echo
# The next should be flagged as unexpected meta command.
#<off>[ignore]
+# The command mode enables git style commands. As usual it can be
+# prefixed with a + to enable or a with a - to disable this feature.
+# The last seen in any config file is used.
+#<off>[command-mode]
+
my-option 4711
not-my-option