From 257e35ee2e21659207412d7602673e2fc9044730 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 May 2024 13:30:48 +0200 Subject: [PATCH] trurl: support ?= for set, to only do it if not already set Idea-by: @emanuele6 in #296 Due to missing support in the libcurl URL API, this is not really working for the scheme component right now, as that will always be considered set once a URL has been parsed. The scheme guessing the parser does sets it internally and there is currently no way provided by the API to figure that out. --- tests.json | 28 ++++++++++++++++++++++++++++ trurl.1 | 5 +++++ trurl.c | 39 ++++++++++++++++++++++++++++++++------- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/tests.json b/tests.json index 4eb55de8..4d81c814 100644 --- a/tests.json +++ b/tests.json @@ -2484,5 +2484,33 @@ "stderr": "", "returncode": 0 } + }, + { + "input": { + "arguments": [ + "example.com:88", + "--set", + "port?=99" + ] + }, + "expected": { + "stdout": "http://example.com:88/\n", + "stderr": "", + "returncode": 0 + } + }, + { + "input": { + "arguments": [ + "example.com", + "--set", + "port?=99" + ] + }, + "expected": { + "stdout": "http://example.com:99/\n", + "stderr": "", + "returncode": 0 + } } ] diff --git a/trurl.1 b/trurl.1 index a492885d..85b1525d 100644 --- a/trurl.1 +++ b/trurl.1 @@ -217,6 +217,11 @@ options, host, port, path, query, fragment and zoneid. If a simple "="-assignment is used, the data is URL encoded when applied. If ":=" is used, the data is assumed to already be URL encoded and stored as-is. +If "?=" is used, the set is only performed if the component is not already +set. It avoids overwriting any already set data. + +You can also combine : and ? into "?:=" if desired. + If no URL or \fI--url-file\fP argument is provided, trurl tries to create a URL using the components provided by the \fI--set\fP options. If not enough components are specified, this fails. diff --git a/trurl.c b/trurl.c index 43142fcf..b9bd3ab4 100644 --- a/trurl.c +++ b/trurl.c @@ -899,20 +899,45 @@ static const struct var *setone(CURLU *uh, const char *setline, if(ptr && (ptr > setline)) { size_t vlen = ptr - setline; bool urlencode = true; + bool conditional = false; bool found = false; - if(ptr[-1] == ':') { - urlencode = false; - vlen--; + if(vlen) { + int back = -1; + size_t reqlen = 1; + while(vlen > reqlen) { + if(ptr[back] == ':') { + urlencode = false; + vlen--; + } + else if(ptr[back] == '?') { + conditional = true; + vlen--; + } + else + break; + reqlen++; + back--; + } } v = comp2var(setline, vlen); if(v) { - CURLUcode rc; + CURLUcode rc = CURLUE_OK; + bool skip = false; if((v->part == CURLUPART_HOST) && ('[' == ptr[1])) /* when setting an IPv6 numerical address, disable URL encoding */ urlencode = false; - rc = curl_url_set(uh, v->part, ptr[1] ? &ptr[1] : NULL, - (o->curl ? 0 : CURLU_NON_SUPPORT_SCHEME)| - (urlencode ? CURLU_URLENCODE : 0) ); + + if(conditional) { + char *piece; + rc = curl_url_get(uh, v->part, &piece, 0); + if(!rc) + skip = true; + } + + if(!skip) + rc = curl_url_set(uh, v->part, ptr[1] ? &ptr[1] : NULL, + (o->curl ? 0 : CURLU_NON_SUPPORT_SCHEME)| + (urlencode ? CURLU_URLENCODE : 0) ); if(rc) warnf("Error setting %s: %s", v->name, curl_url_strerror(rc)); found = true;