diff options
author | Werner Koch <[email protected]> | 2024-02-06 13:53:59 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2024-02-06 13:53:59 +0000 |
commit | b113114c7498fc6c48065a8c4816c610c6f08198 (patch) | |
tree | 1970a988d092ca7dd82f7386125c393f15305862 | |
parent | gpgrt-config: Avoid warning about literals for curly braces. (diff) | |
download | libgpg-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-- | NEWS | 8 | ||||
-rw-r--r-- | src/argparse.c | 155 | ||||
-rw-r--r-- | src/gpg-error.h.in | 2 | ||||
-rw-r--r-- | tests/t-argparse.c | 16 | ||||
-rw-r--r-- | tests/t-argparse.conf | 5 |
5 files changed, 144 insertions, 42 deletions
@@ -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 |