tool_operate: split create_single into smaller sub functions
No binary (build failed)
—
(log yok)
| @@ -847,38 +847,40 @@ static CURLcode append2query(struct OperationConfig *config, | |
| const char *q) | |
| { | |
| CURLcode result = CURLE_OK; | |
| - | CURLU *uh = curl_url(); |
| - | if(uh) { |
| - | CURLUcode uerr; |
| - | uerr = curl_url_set(uh, CURLUPART_URL, per->url, CURLU_GUESS_SCHEME); |
| - | if(uerr) { |
| - | result = urlerr_cvt(uerr); |
| - | errorf("(%d) Could not parse the URL, " |
| - | "failed to set query", result); |
| - | config->synthetic_error = TRUE; |
| - | } |
| - | else { |
| - | char *updated = NULL; |
| - | uerr = curl_url_set(uh, CURLUPART_QUERY, q, CURLU_APPENDQUERY); |
| - | if(!uerr) |
| - | uerr = curl_url_get(uh, CURLUPART_URL, &updated, |
| - | CURLU_NO_GUESS_SCHEME); |
| - | if(uerr) |
| + | if(q) { |
| + | CURLU *uh = curl_url(); |
| + | if(uh) { |
| + | CURLUcode uerr; |
| + | uerr = curl_url_set(uh, CURLUPART_URL, per->url, CURLU_GUESS_SCHEME); |
| + | if(uerr) { |
| result = urlerr_cvt(uerr); | |
| + | errorf("(%d) Could not parse the URL, " |
| + | "failed to set query", result); |
| + | config->synthetic_error = TRUE; |
| + | } |
| else { | |
| - | /* use our new URL instead! */ |
| - | curlx_free(per->url); /* free previous URL */ |
| - | /* make it allocated by tool memory */ |
| - | per->url = curlx_strdup(updated); |
| - | curl_free(updated); |
| - | if(!per->url) |
| - | result = CURLE_OUT_OF_MEMORY; |
| + | char *updated = NULL; |
| + | uerr = curl_url_set(uh, CURLUPART_QUERY, q, CURLU_APPENDQUERY); |
| + | if(!uerr) |
| + | uerr = curl_url_get(uh, CURLUPART_URL, &updated, |
| + | CURLU_NO_GUESS_SCHEME); |
| + | if(uerr) |
| + | result = urlerr_cvt(uerr); |
| + | else { |
| + | /* use our new URL instead! */ |
| + | curlx_free(per->url); /* free previous URL */ |
| + | /* make it allocated by tool memory */ |
| + | per->url = curlx_strdup(updated); |
| + | curl_free(updated); |
| + | if(!per->url) |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | } |
| } | |
| + | curl_url_cleanup(uh); |
| } | |
| - | curl_url_cleanup(uh); |
| + | else |
| + | result = CURLE_OUT_OF_MEMORY; |
| } | |
| - | else |
| - | result = CURLE_OUT_OF_MEMORY; |
| return result; | |
| } | |
| @@ -965,67 +967,76 @@ static CURLcode setup_headerfile(struct OperationConfig *config, | |
| struct per_transfer *per, | |
| struct OutStruct *heads) | |
| { | |
| - | /* open file for output: */ |
| - | if(!strcmp(config->headerfile, "%")) { |
| - | heads->stream = stderr; |
| - | /* use binary mode for protocol header output */ |
| - | CURL_BINMODE(heads->stream); |
| - | } |
| - | else if(strcmp(config->headerfile, "-")) { |
| - | FILE *newfile; |
| - | |
| - | /* |
| - | * Since every transfer has its own file handle for dumping |
| - | * the headers, we need to open it in append mode, since transfers |
| - | * might finish in any order. |
| - | * The first transfer clears the file. |
| - | * |
| - | * Consider placing the file handle inside the OperationConfig, so |
| - | * that it does not need to be opened/closed for every transfer. |
| - | */ |
| - | if(config->create_dirs) { |
| - | CURLcode result = create_dir_hierarchy(config->headerfile); |
| - | /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */ |
| - | if(result) |
| - | return result; |
| - | } |
| - | if(!per->prev || per->prev->config != config) { |
| - | newfile = curlx_fopen(config->headerfile, "wb"); |
| - | if(newfile) |
| - | curlx_fclose(newfile); |
| + | if(config->headerfile) { |
| + | /* open file for output: */ |
| + | if(!strcmp(config->headerfile, "%")) { |
| + | heads->stream = stderr; |
| + | /* use binary mode for protocol header output */ |
| + | CURL_BINMODE(heads->stream); |
| } | |
| - | newfile = curlx_fopen(config->headerfile, "ab"); |
| + | else if(strcmp(config->headerfile, "-")) { |
| + | FILE *newfile; |
| - | if(!newfile) { |
| - | errorf("Failed to open %s", config->headerfile); |
| - | return CURLE_WRITE_ERROR; |
| + | /* |
| + | * Since every transfer has its own file handle for dumping |
| + | * the headers, we need to open it in append mode, since transfers |
| + | * might finish in any order. |
| + | * The first transfer clears the file. |
| + | * |
| + | * Consider placing the file handle inside the OperationConfig, so |
| + | * that it does not need to be opened/closed for every transfer. |
| + | */ |
| + | if(config->create_dirs) { |
| + | CURLcode result = create_dir_hierarchy(config->headerfile); |
| + | /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */ |
| + | if(result) |
| + | return result; |
| + | } |
| + | if(!per->prev || per->prev->config != config) { |
| + | newfile = curlx_fopen(config->headerfile, "wb"); |
| + | if(newfile) |
| + | curlx_fclose(newfile); |
| + | } |
| + | newfile = curlx_fopen(config->headerfile, "ab"); |
| + | |
| + | if(!newfile) { |
| + | errorf("Failed to open %s", config->headerfile); |
| + | return CURLE_WRITE_ERROR; |
| + | } |
| + | else { |
| + | heads->filename = config->headerfile; |
| + | heads->regular_file = TRUE; |
| + | heads->fopened = TRUE; |
| + | heads->stream = newfile; |
| + | } |
| } | |
| else { | |
| - | heads->filename = config->headerfile; |
| - | heads->regular_file = TRUE; |
| - | heads->fopened = TRUE; |
| - | heads->stream = newfile; |
| + | /* always use binary mode for protocol header output */ |
| + | CURL_BINMODE(heads->stream); |
| } | |
| } | |
| - | else { |
| - | /* always use binary mode for protocol header output */ |
| - | CURL_BINMODE(heads->stream); |
| - | } |
| return CURLE_OK; | |
| } | |
| + | /* figure out and populate per->outfile */ |
| static CURLcode setup_outfile(struct OperationConfig *config, | |
| struct per_transfer *per, | |
| + | struct getout *u, |
| struct OutStruct *outs, | |
| bool *skipped) | |
| { | |
| - | /* |
| - | * We have specified a filename to store the result in, or we have |
| - | * decided we want to use the remote filename. |
| - | */ |
| struct State *state = &global->state; | |
| - | if(!per->outfile) { |
| + | outs->out_null = u->out_null; |
| + | /* if --out-null or output to stdout, return */ |
| + | if(outs->out_null || |
| + | (!u->useremote && (!u->outfile || !strcmp("-", u->outfile)))) { |
| + | per->outfile = u->outfile; |
| + | u->outfile = NULL; |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | if(!u->outfile) { |
| SANITIZEcode sc; | |
| /* extract the filename from the URL */ | |
| CURLcode result = get_url_file_name(&per->outfile, per->url, &sc); | |
| @@ -1037,18 +1048,16 @@ static CURLcode setup_outfile(struct OperationConfig *config, | |
| return result; | |
| } | |
| else if(result) { | |
| - | errorf("Failed to extract a filename" |
| - | " from the URL to use for storage"); |
| + | errorf("Failed to extract a filename from the URL to use for storage"); |
| return result; | |
| } | |
| } | |
| else if(glob_inuse(&state->urlglob)) { | |
| /* fill '#1' ... '#9' terms from URL pattern */ | |
| - | char *storefile = per->outfile; |
| SANITIZEcode sc; | |
| CURLcode result = | |
| - | glob_match_url(&per->outfile, storefile, &state->urlglob, &sc); |
| - | curlx_safefree(storefile); |
| + | glob_match_url(&per->outfile, u->outfile, &state->urlglob, &sc); |
| + | |
| if(sc) { | |
| if(sc == SANITIZE_ERR_OUT_OF_MEMORY) | |
| return CURLE_OUT_OF_MEMORY; | |
| @@ -1066,6 +1075,11 @@ static CURLcode setup_outfile(struct OperationConfig *config, | |
| return CURLE_WRITE_ERROR; | |
| } | |
| } | |
| + | else { |
| + | per->outfile = u->outfile; |
| + | u->outfile = NULL; |
| + | } |
| + | |
| DEBUGASSERT(per->outfile); | |
| if(config->output_dir && *config->output_dir) { | |
| @@ -1211,6 +1225,110 @@ static void setup_header_cb(struct OperationConfig *config, | |
| hdrcbdata->config = config; | |
| } | |
| + | static CURLcode setup_input_file(struct OperationConfig *config, |
| + | struct State *state, struct getout *u, |
| + | FILE *err) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | if(u->infile) { |
| + | if(!config->globoff && !glob_inuse(&state->inglob)) |
| + | result = glob_url(&state->inglob, u->infile, &state->upnum, err); |
| + | if(!result && !state->uploadfile) { |
| + | if(glob_inuse(&state->inglob)) |
| + | result = glob_next_url(&state->uploadfile, &state->inglob); |
| + | else if(!state->upidx) { |
| + | /* copy the allocated string */ |
| + | state->uploadfile = u->infile; |
| + | u->infile = NULL; |
| + | } |
| + | } |
| + | } |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode setup_url_pattern(struct OperationConfig *config, |
| + | struct State *state, struct getout *u, |
| + | FILE *err) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | if(!state->urlnum) { |
| + | if(!config->globoff && !u->noglob) { |
| + | /* Unless explicitly shut off, we expand '{...}' and '[...]' |
| + | expressions and return total number of URLs in pattern set */ |
| + | result = glob_url(&state->urlglob, u->url, &state->urlnum, err); |
| + | } |
| + | else |
| + | state->urlnum = 1; /* without globbing, this is a single URL */ |
| + | } |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode setup_etag_files(struct OperationConfig *config, |
| + | struct OutStruct *etag_save, |
| + | bool *break_loop) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | *break_loop = FALSE; |
| + | |
| + | /* --etag-save */ |
| + | memset(etag_save, 0, sizeof(*etag_save)); |
| + | etag_save->stream = stdout; |
| + | |
| + | /* --etag-compare */ |
| + | if(config->etag_compare_file) { |
| + | result = etag_compare(config); |
| + | if(result) |
| + | return result; |
| + | } |
| + | |
| + | if(config->etag_save_file) { |
| + | bool badetag = FALSE; |
| + | result = etag_store(config, etag_save, &badetag); |
| + | if(result || badetag) { |
| + | *break_loop = TRUE; |
| + | return result; |
| + | } |
| + | } |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode select_next_url(struct State *state, |
| + | struct getout *u, |
| + | char **url) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | if(glob_inuse(&state->urlglob)) |
| + | result = glob_next_url(url, &state->urlglob); |
| + | else if(!state->urlidx) { |
| + | *url = curlx_strdup(u->url); |
| + | if(!*url) |
| + | result = CURLE_OUT_OF_MEMORY; |
| + | } |
| + | else |
| + | *url = NULL; |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode setup_transfer_upload(struct OperationConfig *config, |
| + | struct per_transfer *per) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | if(per->uploadfile) { |
| + | if(stdin_upload(per->uploadfile)) |
| + | check_stdin_upload(config, per); |
| + | else { |
| + | /* We have specified a file to upload and it is not "-" */ |
| + | result = add_file_name_to_url(per->curl, &per->url, per->uploadfile); |
| + | if(result) |
| + | return result; |
| + | } |
| + | |
| + | if(config->resume_from_current) |
| + | config->resume_from = -1; /* -1 then forces get-it-yourself */ |
| + | } |
| + | return result; |
| + | } |
| + | |
| /* create a transfer */ | |
| static CURLcode create_single(struct OperationConfig *config, | |
| CURLSH *share, struct State *state, | |
| @@ -1227,27 +1345,17 @@ static CURLcode create_single(struct OperationConfig *config, | |
| CURL *curl; | |
| struct getout *u = state->urlnode; | |
| FILE *err = (!global->silent || global->showerror) ? tool_stderr : NULL; | |
| + | bool break_loop = FALSE; |
| if(!u->url) { | |
| /* This node has no URL. End of the road. */ | |
| warnf("Got more output options than URLs"); | |
| break; | |
| } | |
| - | if(u->infile) { |
| - | if(!config->globoff && !glob_inuse(&state->inglob)) |
| - | result = glob_url(&state->inglob, u->infile, &state->upnum, err); |
| - | if(!result && !state->uploadfile) { |
| - | if(glob_inuse(&state->inglob)) |
| - | result = glob_next_url(&state->uploadfile, &state->inglob); |
| - | else if(!state->upidx) { |
| - | /* copy the allocated string */ |
| - | state->uploadfile = u->infile; |
| - | u->infile = NULL; |
| - | } |
| - | } |
| - | if(result) |
| - | return result; |
| - | } |
| + | |
| + | result = setup_input_file(config, state, u, err); |
| + | if(result) |
| + | return result; |
| if(state->upidx >= state->upnum) { | |
| state->urlnum = 0; | |
| @@ -1258,35 +1366,13 @@ static CURLcode create_single(struct OperationConfig *config, | |
| continue; | |
| } | |
| - | if(!state->urlnum) { |
| - | if(!config->globoff && !u->noglob) { |
| - | /* Unless explicitly shut off, we expand '{...}' and '[...]' |
| - | expressions and return total number of URLs in pattern set */ |
| - | result = glob_url(&state->urlglob, u->url, &state->urlnum, err); |
| - | if(result) |
| - | return result; |
| - | } |
| - | else |
| - | state->urlnum = 1; /* without globbing, this is a single URL */ |
| - | } |
| - | |
| - | /* --etag-save */ |
| - | memset(&etag_first, 0, sizeof(etag_first)); |
| - | etag_first.stream = stdout; |
| - | |
| - | /* --etag-compare */ |
| - | if(config->etag_compare_file) { |
| - | result = etag_compare(config); |
| - | if(result) |
| - | return result; |
| - | } |
| + | result = setup_url_pattern(config, state, u, err); |
| + | if(result) |
| + | return result; |
| - | if(config->etag_save_file) { |
| - | bool badetag = FALSE; |
| - | result = etag_store(config, &etag_first, &badetag); |
| - | if(result || badetag) |
| - | break; |
| - | } |
| + | result = setup_etag_files(config, &etag_first, &break_loop); |
| + | if(result || break_loop) |
| + | return result; |
| curl = curl_easy_init(); | |
| if(curl) | |
| @@ -1318,64 +1404,30 @@ static CURLcode create_single(struct OperationConfig *config, | |
| heads->stream = stdout; | |
| /* Single header file for all URLs */ | |
| - | if(config->headerfile) { |
| - | result = setup_headerfile(config, per, heads); |
| - | if(result) |
| - | return result; |
| - | } |
| + | result = setup_headerfile(config, per, heads); |
| + | if(result) |
| + | return result; |
| outs = &per->outs; | |
| - | per->outfile = NULL; |
| per->infdopen = FALSE; | |
| per->infd = STDIN_FILENO; | |
| /* default output stream is stdout */ | |
| outs->stream = stdout; | |
| - | if(glob_inuse(&state->urlglob)) |
| - | result = glob_next_url(&per->url, &state->urlglob); |
| - | else if(!state->urlidx) { |
| - | per->url = curlx_strdup(u->url); |
| - | if(!per->url) |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | } |
| - | else { |
| - | per->url = NULL; |
| - | break; |
| - | } |
| + | result = select_next_url(state, u, &per->url); |
| if(result) | |
| return result; | |
| + | if(!per->url) |
| + | break; |
| - | if(u->outfile) { |
| - | per->outfile = curlx_strdup(u->outfile); |
| - | if(!per->outfile) |
| - | return CURLE_OUT_OF_MEMORY; |
| - | } |
| - | |
| - | outs->out_null = u->out_null; |
| - | if(!outs->out_null && |
| - | (u->useremote || (per->outfile && strcmp("-", per->outfile)))) { |
| - | result = setup_outfile(config, per, outs, skipped); |
| - | if(result) |
| - | return result; |
| - | } |
| - | |
| - | if(per->uploadfile) { |
| - | |
| - | if(stdin_upload(per->uploadfile)) |
| - | check_stdin_upload(config, per); |
| - | else { |
| - | /* |
| - | * We have specified a file to upload and it is not "-". |
| - | */ |
| - | result = add_file_name_to_url(per->curl, &per->url, per->uploadfile); |
| - | if(result) |
| - | return result; |
| - | } |
| + | result = setup_outfile(config, per, u, outs, skipped); |
| + | if(result) |
| + | return result; |
| - | if(config->resume_from_current) |
| - | config->resume_from = -1; /* -1 then forces get-it-yourself */ |
| - | } |
| + | result = setup_transfer_upload(config, per); |
| + | if(result) |
| + | return result; |
| if(!outs->out_null && output_expected(per->url, per->uploadfile) && | |
| outs->stream && isatty(fileno(outs->stream))) | |
| @@ -1383,17 +1435,14 @@ static CURLcode create_single(struct OperationConfig *config, | |
| meter */ | |
| per->noprogress = global->noprogress = global->isatty = TRUE; | |
| else { | |
| - | /* progress meter is per download, so restore config |
| - | values */ |
| + | /* progress meter is per download, so restore config values */ |
| per->noprogress = global->noprogress = orig_noprogress; | |
| global->isatty = orig_isatty; | |
| } | |
| - | if(config->httpgetfields) { |
| - | result = append2query(config, per, config->httpgetfields); |
| - | if(result) |
| - | return result; |
| - | } |
| + | result = append2query(config, per, config->httpgetfields); |
| + | if(result) |
| + | return result; |
| if((!per->outfile || !strcmp(per->outfile, "-")) && | |
| !config->use_ascii) { | |