From 9f9fecc7244ff2da52e338f844ed898f836a0508 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 30 Jun 2025 23:53:29 +0200 Subject: [PATCH] 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 --- docs/cmdline-opts/_OPTIONS.md | 3 +++ src/tool_getparam.c | 24 ++++++++++++++++++++++-- tests/data/test1333 | 2 +- tests/data/test1335 | 2 +- tests/data/test1442 | 2 +- tests/data/test206 | 2 +- 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/docs/cmdline-opts/_OPTIONS.md b/docs/cmdline-opts/_OPTIONS.md index f1067377c8..2b7cb80f49 100644 --- a/docs/cmdline-opts/_OPTIONS.md +++ b/docs/cmdline-opts/_OPTIONS.md @@ -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. diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 3a1cc57fdd..c78494f76d 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -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); diff --git a/tests/data/test1333 b/tests/data/test1333 index e6dbb73a62..5a5dd63a2d 100644 --- a/tests/data/test1333 +++ b/tests/data/test1333 @@ -31,7 +31,7 @@ http HTTP POST zero length, chunked-encoded --d "" --header "Transfer-Encoding: chunked" http://%HOSTIP:%HTTPPORT/%TESTNUMBER +-d "" --header="Transfer-Encoding: chunked" http://%HOSTIP:%HTTPPORT/%TESTNUMBER diff --git a/tests/data/test1335 b/tests/data/test1335 index a0b3aae65e..146ff6d918 100644 --- a/tests/data/test1335 +++ b/tests/data/test1335 @@ -30,7 +30,7 @@ http HTTP GET with -O without Content-Disposition, -D stdout -http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - --output-dir %LOGDIR +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - --output-dir="%LOGDIR" diff --git a/tests/data/test1442 b/tests/data/test1442 index 0825a1e028..2293fdf2f7 100644 --- a/tests/data/test1442 +++ b/tests/data/test1442 @@ -19,7 +19,7 @@ file Check --write-out with trailing \ -file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt --write-out '\' +file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt --write-out='\' diff --git a/tests/data/test206 b/tests/data/test206 index 99a9493023..2ff05075c7 100644 --- a/tests/data/test206 +++ b/tests/data/test206 @@ -80,7 +80,7 @@ digest HTTP proxy CONNECT auth Digest -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 -- 2.47.2