From fc7934695d24ced6b7b5de5042b88bb001ab9eb8 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Thu, 14 Mar 2024 16:21:58 +0100 Subject: [PATCH] vsh: Allow one optional positional argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already allow a optional positional _ARGV argument but there's no reason why any other argument type could not be allowed this way. Add checks that there's just one such argument and it's placed after required positional arguments. Signed-off-by: Peter Krempa Reviewed-by: Ján Tomko --- tools/vsh.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tools/vsh.c b/tools/vsh.c index cbddc5ed92..80057654c8 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -249,6 +249,7 @@ vshCmddefCheckInternals(vshControl *ctl, { size_t i; bool seenOptionalOption = false; + const char *seenOptionalPositionalOption = NULL; g_auto(virBuffer) complbuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) posbuf = VIR_BUFFER_INITIALIZER; @@ -350,10 +351,21 @@ vshCmddefCheckInternals(vshControl *ctl, } } - /* require that positional non-argv options are required */ - if (opt->positional && !opt->required && opt->type != VSH_OT_ARGV) { - vshError(ctl, "positional argument '%s' of command '%s' must be required", - opt->name, cmd->name); + /* allow at most one optional positional option */ + if (opt->positional && !opt->required) { + if (seenOptionalPositionalOption) { + vshError(ctl, "multiple optional positional arguments (%s, %s) of command '%s' are not allowed", + seenOptionalPositionalOption, opt->name, cmd->name); + return -1; + } + + seenOptionalPositionalOption = opt->name; + } + + /* all optional positional arguments must be defined after the required ones */ + if (seenOptionalPositionalOption && opt->positional && opt->required) { + vshError(ctl, "required positional argument '%s' declared after an optional positional argument '%s' of command '%s'", + opt->name, seenOptionalPositionalOption, cmd->name); return -1; }