tool_getparam: add support for --longopt=value

If the long option name ends with an equals sign (`=`), the argument is
the text following on its right side.

This makes the command line parser accept this common style in addition
to the existing way to accept option arguments more similar to how other
command line tools do.

Example: `curl --user-agent=curl-2000 https://example.com/`

Change a few existing tests to use this syntax: 206, 1333, 1335, 1442

Closes #17789
This commit is contained in:
Daniel Stenberg 2025-06-30 23:53:29 +02:00
parent 378713deb2
commit 9f9fecc724
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
6 changed files with 29 additions and 6 deletions

View file

@ -24,6 +24,9 @@ When --next is used, it resets the parser state and you start again with a
clean option state, except for the options that are global. Global options
retain their values and meaning even after --next.
If the long option name ends with an equals sign (`=`), the argument is the
text following on its right side. (Added in 8.16.0)
The first argument that is exactly two dashes (`--`), marks the end of
options; any argument after the end of options is interpreted as a URL
argument even if it starts with a dash.

View file

@ -2803,6 +2803,9 @@ static ParameterError opt_filestring(struct OperationConfig *config,
return err;
}
/* the longest command line option, excluding the leading -- */
#define MAX_OPTION_LEN 26
ParameterError getparameter(const char *flag, /* f or -long-flag */
const char *nextarg, /* NULL if unset */
bool *usedarg, /* set to TRUE if the arg
@ -2816,6 +2819,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
by using --OPTION or --no-OPTION */
bool nextalloc = FALSE; /* if nextarg is allocated */
bool consumearg = TRUE; /* the argument comes separate */
const struct LongShort *a = NULL;
struct GlobalConfig *global = config->global;
verbose_nopts = 0; /* options processed in `flag`*/
@ -2827,6 +2831,8 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
const char *word = ('-' == flag[0]) ? flag + 2 : flag;
bool noflagged = FALSE;
bool expand = FALSE;
const char *p;
struct Curl_str out;
if(!strncmp(word, "no-", 3)) {
/* disable this option but ignore the "no-" part when looking for it */
@ -2840,7 +2846,21 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
expand = TRUE;
}
a = findlongopt(word);
p = word;
/* is there an '=' ? */
if(!curlx_str_until(&p, &out, MAX_OPTION_LEN, '=') &&
!curlx_str_single(&p, '=') ) {
/* there's an equal sign */
char tempword[MAX_OPTION_LEN + 1];
memcpy(tempword, curlx_str(&out), curlx_strlen(&out));
tempword[curlx_strlen(&out)] = 0;
a = findlongopt(tempword);
nextarg = p;
consumearg = FALSE; /* it is not separate */
}
else
a = findlongopt(word);
if(a) {
longopt = TRUE;
}
@ -2910,7 +2930,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
}
else {
*usedarg = TRUE; /* mark it as used */
*usedarg = consumearg; /* mark it as used */
}
if(a->desc & ARG_DEPR) {
opt_depr(global, a);

View file

@ -31,7 +31,7 @@ http
HTTP POST zero length, chunked-encoded
</name>
<command>
-d "" --header "Transfer-Encoding: chunked" http://%HOSTIP:%HTTPPORT/%TESTNUMBER
-d "" --header="Transfer-Encoding: chunked" http://%HOSTIP:%HTTPPORT/%TESTNUMBER
</command>
</client>

View file

@ -30,7 +30,7 @@ http
HTTP GET with -O without Content-Disposition, -D stdout
</name>
<command option="no-output,no-include">
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - --output-dir %LOGDIR
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - --output-dir="%LOGDIR"
</command>
</client>

View file

@ -19,7 +19,7 @@ file
Check --write-out with trailing \
</name>
<command>
file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt --write-out '\'
file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt --write-out='\'
</command>
</client>

View file

@ -80,7 +80,7 @@ digest
HTTP proxy CONNECT auth Digest
</name>
<command>
http://test.remote.haxx.se.%TESTNUMBER:8990/path/%TESTNUMBER0002 --proxy http://%HOSTIP:%HTTPPORT --proxy-user silly:person --proxy-digest --proxytunnel
http://test.remote.haxx.se.%TESTNUMBER:8990/path/%TESTNUMBER0002 --proxy=http://%HOSTIP:%HTTPPORT --proxy-user=silly:person --proxy-digest --proxytunnel
</command>
</client>