tool_getparam: make --url support a file with URLs

It implies -O used for each URL.

Mention in the --url documentation.

Test 488 and 489 verify.

Closes #16099
This commit is contained in:
Daniel Stenberg 2025-02-22 10:36:10 +01:00
parent 5addb3e1cc
commit 6306476fc3
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
8 changed files with 238 additions and 36 deletions

View file

@ -1020,9 +1020,10 @@ const struct LongShort *findlongopt(const char *opt)
sizeof(aliases[0]), findarg);
}
static ParameterError parse_url(struct GlobalConfig *global,
struct OperationConfig *config,
const char *nextarg)
static ParameterError add_url(struct GlobalConfig *global,
struct OperationConfig *config,
const char *thisurl,
int extraflags)
{
ParameterError err = PARAM_OK;
struct getout *url;
@ -1050,10 +1051,10 @@ static ParameterError parse_url(struct GlobalConfig *global,
return PARAM_NO_MEM;
else {
/* fill in the URL */
err = getstr(&url->url, nextarg, DENY_BLANK);
url->flags |= GETOUT_URL;
if(!err && (++config->num_urls > 1) && (config->etag_save_file ||
config->etag_compare_file)) {
err = getstr(&url->url, thisurl, DENY_BLANK);
url->flags |= GETOUT_URL | extraflags;
if(!err && (++config->num_urls > 1) &&
(config->etag_save_file || config->etag_compare_file)) {
errorf(global, "The etag options only work on a single URL");
return PARAM_BAD_USE;
}
@ -1061,6 +1062,65 @@ static ParameterError parse_url(struct GlobalConfig *global,
return err;
}
static ParameterError parse_url(struct GlobalConfig *global,
struct OperationConfig *config,
const char *nextarg)
{
if(nextarg && (nextarg[0] == '@')) {
/* read URLs from a file, treat all as -O */
struct curlx_dynbuf line;
ParameterError err = PARAM_OK;
bool error = FALSE;
bool fromstdin = !strcmp("-", &nextarg[1]);
FILE *f;
if(fromstdin)
f = stdin;
else
f = fopen(&nextarg[1], FOPEN_READTEXT);
if(f) {
curlx_dyn_init(&line, 8092);
while(my_get_line(f, &line, &error)) {
/* every line has a newline that we strip off */
size_t len = curlx_dyn_len(&line);
const char *ptr;
if(len)
curlx_dyn_setlen(&line, len - 1);
ptr = curlx_dyn_ptr(&line);
/* line with # in the first non-blank column is a comment! */
while(*ptr && ISSPACE(*ptr))
ptr++;
switch(*ptr) {
case '#':
case '/':
case '\r':
case '\n':
case '*':
case '\0':
/* comment or weird line, skip it */
break;
default:
err = add_url(global, config, ptr, GETOUT_USEREMOTE | GETOUT_NOGLOB);
break;
}
if(err)
break;
curlx_dyn_reset(&line);
}
if(!fromstdin)
fclose(f);
curlx_dyn_free(&line);
if(error || err)
return PARAM_READ_ERROR;
return PARAM_OK;
}
return PARAM_READ_ERROR; /* file not found */
}
return add_url(global, config, nextarg, 0);
}
static ParameterError parse_localport(struct OperationConfig *config,
char *nextarg)
{

View file

@ -808,8 +808,8 @@ const struct helptxt helptext[] = {
{"-T, --upload-file <file>",
"Transfer local FILE to destination",
CURLHELP_IMPORTANT | CURLHELP_UPLOAD},
{" --url <url>",
"URL to work with",
{" --url <url/file>",
"URL(s) to work with",
CURLHELP_CURL},
{" --url-query <data>",
"Add a URL query part",

View file

@ -1889,7 +1889,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
}
if(!state->urlnum) {
if(!config->globoff) {
if(!config->globoff && !(urlnode->flags & GETOUT_NOGLOB)) {
/* Unless explicitly shut off, we expand '{...}' and '[...]'
expressions and return total number of URLs in pattern set */
result = glob_url(&state->urls, urlnode->url, &state->urlnum,

View file

@ -96,6 +96,7 @@ struct getout {
#define GETOUT_USEREMOTE (1<<2) /* use remote filename locally */
#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
#define GETOUT_NOGLOB (1<<5) /* disable globbing for this URL */
/*
* 'trace' enumeration represents curl's output look'n feel possibilities.