diff --git a/src/tool_getparam.c b/src/tool_getparam.c index abae52bd96..7eb08cd097 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -1019,6 +1019,543 @@ const struct LongShort *findlongopt(const char *opt) sizeof(aliases[0]), findarg); } +static ParameterError parse_url(struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + struct getout *url; + + if(!config->url_get) + config->url_get = config->url_list; + + if(config->url_get) { + /* there is a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_get && (config->url_get->flags & GETOUT_URL)) + config->url_get = config->url_get->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_get) + /* existing node */ + url = config->url_get; + else + /* there was no free node, create one! */ + config->url_get = url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + else { + /* fill in the URL */ + err = getstr(&url->url, nextarg, DENY_BLANK); + url->flags |= GETOUT_URL; + } + return err; +} + +static ParameterError parse_localport(struct OperationConfig *config, + char *nextarg) +{ + int rc; + /* 16bit base 10 is 5 digits, but we allow 6 so that this catches + overflows, not just truncates */ + char lrange[7]=""; + char *p = nextarg; + while(ISDIGIT(*p)) + p++; + if(*p) { + /* if there is anything more than a plain decimal number */ + rc = sscanf(p, " - %6s", lrange); + *p = 0; /* null-terminate to make str2unum() work below */ + } + else + rc = 0; + + if(str2unum(&config->localport, nextarg) || + (config->localport > 65535)) + return PARAM_BAD_USE; + if(!rc) + config->localportrange = 1; /* default number of ports to try */ + else { + if(str2unum(&config->localportrange, lrange) || + (config->localportrange > 65535)) + return PARAM_BAD_USE; + else { + config->localportrange -= (config->localport-1); + if(config->localportrange < 1) + return PARAM_BAD_USE; + } + } + return PARAM_OK; +} + +static ParameterError parse_continue_at(struct GlobalConfig *global, + struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + if(config->range) { + errorf(global, "--continue-at is mutually exclusive with --range"); + return PARAM_BAD_USE; + } + if(config->rm_partial) { + errorf(config->global, + "--continue-at is mutually exclusive with --remove-on-error"); + return PARAM_BAD_USE; + } + if(config->file_clobber_mode == CLOBBER_NEVER) { + errorf(config->global, + "--continue-at is mutually exclusive with --no-clobber"); + return PARAM_BAD_USE; + } + /* This makes us continue an ftp transfer at given position */ + if(strcmp(nextarg, "-")) { + err = str2offset(&config->resume_from, nextarg); + config->resume_from_current = FALSE; + } + else { + config->resume_from_current = TRUE; + config->resume_from = 0; + } + config->use_resume = TRUE; + return err; +} + +static ParameterError parse_ech(struct GlobalConfig *global, + struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + if(!feature_ech) + err = PARAM_LIBCURL_DOESNT_SUPPORT; + else if(strlen(nextarg) > 4 && strncasecompare("pn:", nextarg, 3)) { + /* a public_name */ + err = getstr(&config->ech_public, nextarg, DENY_BLANK); + } + else if(strlen(nextarg) > 5 && strncasecompare("ecl:", nextarg, 4)) { + /* an ECHConfigList */ + if('@' != *(nextarg + 4)) { + err = getstr(&config->ech_config, nextarg, DENY_BLANK); + } + else { + /* Indirect case: @filename or @- for stdin */ + char *tmpcfg = NULL; + FILE *file; + + nextarg++; /* skip over '@' */ + if(!strcmp("-", nextarg)) { + file = stdin; + } + else { + file = fopen(nextarg, FOPEN_READTEXT); + } + if(!file) { + warnf(global, + "Couldn't read file \"%s\" " + "specified for \"--ech ecl:\" option", + nextarg); + return PARAM_BAD_USE; /* */ + } + err = file2string(&tmpcfg, file); + if(file != stdin) + fclose(file); + if(err) + return err; + config->ech_config = aprintf("ecl:%s",tmpcfg); + if(!config->ech_config) + return PARAM_NO_MEM; + free(tmpcfg); + } /* file done */ + } + else { + /* Simple case: just a string, with a keyword */ + err = getstr(&config->ech, nextarg, DENY_BLANK); + } + return err; +} + +static ParameterError parse_header(struct GlobalConfig *global, + struct OperationConfig *config, + cmdline_t cmd, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + + /* A custom header to append to a list */ + if(nextarg[0] == '@') { + /* read many headers from a file or stdin */ + char *string; + size_t len; + bool use_stdin = !strcmp(&nextarg[1], "-"); + FILE *file = use_stdin ? stdin : fopen(&nextarg[1], FOPEN_READTEXT); + if(!file) { + errorf(global, "Failed to open %s", &nextarg[1]); + err = PARAM_READ_ERROR; + } + else { + err = file2memory(&string, &len, file); + if(!err && string) { + /* Allow strtok() here since this is not used threaded */ + /* !checksrc! disable BANNEDFUNC 2 */ + char *h = strtok(string, "\r\n"); + while(h) { + if(cmd == C_PROXY_HEADER) /* --proxy-header */ + err = add2list(&config->proxyheaders, h); + else + err = add2list(&config->headers, h); + if(err) + break; + h = strtok(NULL, "\r\n"); + } + free(string); + } + if(!use_stdin) + fclose(file); + } + } + else { + if(cmd == C_PROXY_HEADER) /* --proxy-header */ + err = add2list(&config->proxyheaders, nextarg); + else + err = add2list(&config->headers, nextarg); + } + return err; +} + +static ParameterError parse_output(struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + struct getout *url; + + /* output file */ + if(!config->url_out) + config->url_out = config->url_list; + if(config->url_out) { + /* there is a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) + config->url_out = config->url_out->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_out) + /* existing node */ + url = config->url_out; + else { + /* there was no free node, create one! */ + config->url_out = url = new_getout(config); + } + + if(!url) + return PARAM_NO_MEM; + + /* fill in the outfile */ + err = getstr(&url->outfile, nextarg, DENY_BLANK); + url->flags &= ~GETOUT_USEREMOTE; /* switch off */ + url->flags |= GETOUT_OUTFILE; + return err; +} + +static ParameterError parse_remote_name(struct OperationConfig *config, + bool toggle) +{ + ParameterError err = PARAM_OK; + struct getout *url; + + if(!toggle && !config->default_node_flags) + return err; /* nothing to do */ + + /* output file */ + if(!config->url_out) + config->url_out = config->url_list; + if(config->url_out) { + /* there is a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) + config->url_out = config->url_out->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_out) + /* existing node */ + url = config->url_out; + else { + /* there was no free node, create one! */ + config->url_out = url = new_getout(config); + } + + if(!url) + return PARAM_NO_MEM; + + url->outfile = NULL; /* leave it */ + if(toggle) + url->flags |= GETOUT_USEREMOTE; /* switch on */ + else + url->flags &= ~GETOUT_USEREMOTE; /* switch off */ + url->flags |= GETOUT_OUTFILE; + return PARAM_OK; +} + +static ParameterError parse_quote(struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + + /* QUOTE command to send to FTP server */ + switch(nextarg[0]) { + case '-': + /* prefixed with a dash makes it a POST TRANSFER one */ + nextarg++; + err = add2list(&config->postquote, nextarg); + break; + case '+': + /* prefixed with a plus makes it a just-before-transfer one */ + nextarg++; + err = add2list(&config->prequote, nextarg); + break; + default: + err = add2list(&config->quote, nextarg); + break; + } + return err; +} + +static ParameterError parse_range(struct GlobalConfig *global, + struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + + if(config->use_resume) { + errorf(global, "--continue-at is mutually exclusive with --range"); + return PARAM_BAD_USE; + } + /* Specifying a range WITHOUT A DASH will create an illegal HTTP range + (and will not actually be range by definition). The manpage + previously claimed that to be a good way, why this code is added to + work-around it. */ + if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) { + char buffer[32]; + curl_off_t value; + if(curlx_strtoofft(nextarg, NULL, 10, &value)) { + warnf(global, "unsupported range point"); + err = PARAM_BAD_USE; + } + else { + warnf(global, + "A specified range MUST include at least one dash (-). " + "Appending one for you"); + msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", + value); + Curl_safefree(config->range); + config->range = strdup(buffer); + if(!config->range) + err = PARAM_NO_MEM; + } + } + else { + /* byte range requested */ + const char *tmp_range = nextarg; + while(*tmp_range) { + if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { + warnf(global, "Invalid character is found in given range. " + "A specified range MUST have only digits in " + "\'start\'-\'stop\'. The server's response to this " + "request is uncertain."); + break; + } + tmp_range++; + } + err = getstr(&config->range, nextarg, DENY_BLANK); + } + return err; +} + +static ParameterError parse_upload_file(struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + struct getout *url; + + /* we are uploading */ + if(!config->url_ul) + config->url_ul = config->url_list; + if(config->url_ul) { + /* there is a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD)) + config->url_ul = config->url_ul->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_ul) + /* existing node */ + url = config->url_ul; + else + /* there was no free node, create one! */ + config->url_ul = url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + + url->flags |= GETOUT_UPLOAD; /* mark -T used */ + if(!*nextarg) + url->flags |= GETOUT_NOUPLOAD; + else { + /* "-" equals stdin, but keep the string around for now */ + err = getstr(&url->infile, nextarg, DENY_BLANK); + } + return err; +} + +static ParameterError parse_verbose(struct GlobalConfig *global, + bool toggle, + size_t nopts) +{ + ParameterError err = PARAM_OK; + + /* This option is a super-boolean with side effect when applied + * more than once in the same argument flag, like `-vvv`. */ + if(!toggle) { + global->verbosity = 0; + if(set_trace_config(global, "-all")) + err = PARAM_NO_MEM; + global->tracetype = TRACE_NONE; + return err; + } + else if(!nopts) { + /* fist `-v` in an argument resets to base verbosity */ + global->verbosity = 0; + if(set_trace_config(global, "-all")) + return PARAM_NO_MEM; + } + /* the '%' thing here will cause the trace get sent to stderr */ + switch(global->verbosity) { + case 0: + global->verbosity = 1; + Curl_safefree(global->trace_dump); + global->trace_dump = strdup("%"); + if(!global->trace_dump) + err = PARAM_NO_MEM; + else { + if(global->tracetype && (global->tracetype != TRACE_PLAIN)) + warnf(global, + "-v, --verbose overrides an earlier trace option"); + global->tracetype = TRACE_PLAIN; + } + break; + case 1: + global->verbosity = 2; + if(set_trace_config(global, "ids,time,protocol")) + err = PARAM_NO_MEM; + break; + case 2: + global->verbosity = 3; + global->tracetype = TRACE_ASCII; + if(set_trace_config(global, "ssl,read,write")) + err = PARAM_NO_MEM; + break; + case 3: + global->verbosity = 4; + if(set_trace_config(global, "network")) + err = PARAM_NO_MEM; + break; + default: + /* no effect for now */ + break; + } + return err; +} + +static ParameterError parse_writeout(struct GlobalConfig *global, + struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + + /* get the output string */ + if('@' == *nextarg) { + /* the data begins with a '@' letter, it means that a filename + or - (stdin) follows */ + FILE *file; + const char *fname; + nextarg++; /* pass the @ */ + if(!strcmp("-", nextarg)) { + fname = ""; + file = stdin; + } + else { + fname = nextarg; + file = fopen(fname, FOPEN_READTEXT); + if(!file) { + errorf(global, "Failed to open %s", fname); + return PARAM_READ_ERROR; + } + } + Curl_safefree(config->writeout); + err = file2string(&config->writeout, file); + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + if(!config->writeout) + warnf(global, "Failed to read %s", fname); + } + else + err = getstr(&config->writeout, nextarg, ALLOW_BLANK); + + return err; +} + +static ParameterError parse_time_cond(struct GlobalConfig *global, + struct OperationConfig *config, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + + switch(*nextarg) { + case '+': + nextarg++; + FALLTHROUGH(); + default: + /* If-Modified-Since: (section 14.28 in RFC2068) */ + config->timecond = CURL_TIMECOND_IFMODSINCE; + break; + case '-': + /* If-Unmodified-Since: (section 14.24 in RFC2068) */ + config->timecond = CURL_TIMECOND_IFUNMODSINCE; + nextarg++; + break; + case '=': + /* Last-Modified: (section 14.29 in RFC2068) */ + config->timecond = CURL_TIMECOND_LASTMOD; + nextarg++; + break; + } + config->condtime = (curl_off_t)curl_getdate(nextarg, NULL); + if(-1 == config->condtime) { + curl_off_t value; + /* now let's see if it is a filename to get the time from instead! */ + int rc = getfiletime(nextarg, global, &value); + if(!rc) + /* pull the time out from the file */ + config->condtime = value; + else { + /* failed, remove time condition */ + config->timecond = CURL_TIMECOND_NONE; + warnf(global, + "Illegal date format for -z, --time-cond (and not " + "a filename). Disabling time condition. " + "See curl_getdate(3) for valid date syntax."); + } + } + return err; +} ParameterError getparameter(const char *flag, /* f or -long-flag */ char *nextarg, /* NULL if unset */ @@ -1028,7 +1565,6 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ struct GlobalConfig *global, struct OperationConfig *config) { - int rc; const char *parse = NULL; bool longopt = FALSE; bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ @@ -1037,7 +1573,6 @@ 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 */ - struct getout *url; static const char *redir_protos[] = { "http", "https", @@ -1114,7 +1649,6 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ do { /* we can loop here if we have multiple single-letters */ - char letter; cmdline_t cmd; if(!longopt && !a) { @@ -1124,7 +1658,6 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; } } - letter = a->letter; cmd = (cmdline_t)a->cmd; if(ARGTYPE(a->desc) >= ARG_STRG) { /* this option requires an extra parameter */ @@ -1380,32 +1913,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ config->xattr = toggle; break; case C_URL: /* --url */ - if(!config->url_get) - config->url_get = config->url_list; - - if(config->url_get) { - /* there is a node here, if it already is filled-in continue to find - an "empty" node */ - while(config->url_get && (config->url_get->flags & GETOUT_URL)) - config->url_get = config->url_get->next; - } - - /* now there might or might not be an available node to fill in! */ - - if(config->url_get) - /* existing node */ - url = config->url_get; - else - /* there was no free node, create one! */ - config->url_get = url = new_getout(config); - - if(!url) - err = PARAM_NO_MEM; - else { - /* fill in the URL */ - err = getstr(&url->url, nextarg, DENY_BLANK); - url->flags |= GETOUT_URL; - } + err = parse_url(config, nextarg); break; case C_FTP_SSL: /* --ftp-ssl */ case C_SSL: /* --ssl */ @@ -1509,40 +2017,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ case C_FTP_METHOD: /* --ftp-method */ config->ftp_filemethod = ftpfilemethod(config, nextarg); break; - case C_LOCAL_PORT: { /* --local-port */ - /* 16bit base 10 is 5 digits, but we allow 6 so that this catches - overflows, not just truncates */ - char lrange[7]=""; - char *p = nextarg; - while(ISDIGIT(*p)) - p++; - if(*p) { - /* if there is anything more than a plain decimal number */ - rc = sscanf(p, " - %6s", lrange); - *p = 0; /* null-terminate to make str2unum() work below */ - } - else - rc = 0; - - err = str2unum(&config->localport, nextarg); - if(err || (config->localport > 65535)) { - err = PARAM_BAD_USE; - break; - } - if(!rc) - config->localportrange = 1; /* default number of ports to try */ - else { - err = str2unum(&config->localportrange, lrange); - if(err || (config->localportrange > 65535)) - err = PARAM_BAD_USE; - else { - config->localportrange -= (config->localport-1); - if(config->localportrange < 1) - err = PARAM_BAD_USE; - } - } + case C_LOCAL_PORT: /* --local-port */ + err = parse_localport(config, nextarg); break; - } case C_FTP_ALTERNATIVE_TO_USER: /* --ftp-alternative-to-user */ err = getstr(&config->ftp_alternative_to_user, nextarg, DENY_BLANK); break; @@ -1845,30 +2322,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ err = getstr(&config->cookiejar, nextarg, DENY_BLANK); break; case C_CONTINUE_AT: /* --continue-at */ - if(config->range) { - errorf(global, "--continue-at is mutually exclusive with --range"); - return PARAM_BAD_USE; - } - if(config->rm_partial) { - errorf(config->global, - "--continue-at is mutually exclusive with --remove-on-error"); - return PARAM_BAD_USE; - } - if(config->file_clobber_mode == CLOBBER_NEVER) { - errorf(config->global, - "--continue-at is mutually exclusive with --no-clobber"); - return PARAM_BAD_USE; - } - /* This makes us continue an ftp transfer at given position */ - if(strcmp(nextarg, "-")) { - err = str2offset(&config->resume_from, nextarg); - config->resume_from_current = FALSE; - } - else { - config->resume_from_current = TRUE; - config->resume_from = 0; - } - config->use_resume = TRUE; + err = parse_continue_at(global, config, nextarg); break; case C_DATA: /* --data */ case C_DATA_ASCII: /* --data-ascii */ @@ -1935,52 +2389,8 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ } break; case C_ECH: /* --ech */ - if(!feature_ech) - err = PARAM_LIBCURL_DOESNT_SUPPORT; - else if(strlen(nextarg) > 4 && strncasecompare("pn:", nextarg, 3)) { - /* a public_name */ - err = getstr(&config->ech_public, nextarg, DENY_BLANK); - } - else if(strlen(nextarg) > 5 && strncasecompare("ecl:", nextarg, 4)) { - /* an ECHConfigList */ - if('@' != *(nextarg + 4)) { - err = getstr(&config->ech_config, nextarg, DENY_BLANK); - } - else { - /* Indirect case: @filename or @- for stdin */ - char *tmpcfg = NULL; - FILE *file; - - nextarg++; /* skip over '@' */ - if(!strcmp("-", nextarg)) { - file = stdin; - } - else { - file = fopen(nextarg, FOPEN_READTEXT); - } - if(!file) { - warnf(global, - "Couldn't read file \"%s\" " - "specified for \"--ech ecl:\" option", - nextarg); - return PARAM_BAD_USE; /* */ - } - err = file2string(&tmpcfg, file); - if(file != stdin) - fclose(file); - if(err) - return err; - config->ech_config = aprintf("ecl:%s",tmpcfg); - if(!config->ech_config) - return PARAM_NO_MEM; - free(tmpcfg); - } /* file done */ - } - else { - /* Simple case: just a string, with a keyword */ - err = getstr(&config->ech, nextarg, DENY_BLANK); - } - break; + err = parse_ech(global, config, nextarg); + break; case C_CAPATH: /* --capath */ err = getstr(&config->capath, nextarg, DENY_BLANK); break; @@ -2219,44 +2629,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; case C_HEADER: /* --header */ case C_PROXY_HEADER: /* --proxy-header */ - /* A custom header to append to a list */ - if(nextarg[0] == '@') { - /* read many headers from a file or stdin */ - char *string; - size_t len; - bool use_stdin = !strcmp(&nextarg[1], "-"); - FILE *file = use_stdin ? stdin : fopen(&nextarg[1], FOPEN_READTEXT); - if(!file) { - errorf(global, "Failed to open %s", &nextarg[1]); - err = PARAM_READ_ERROR; - } - else { - err = file2memory(&string, &len, file); - if(!err && string) { - /* Allow strtok() here since this is not used threaded */ - /* !checksrc! disable BANNEDFUNC 2 */ - char *h = strtok(string, "\r\n"); - while(h) { - if(cmd == C_PROXY_HEADER) /* --proxy-header */ - err = add2list(&config->proxyheaders, h); - else - err = add2list(&config->headers, h); - if(err) - break; - h = strtok(NULL, "\r\n"); - } - free(string); - } - if(!use_stdin) - fclose(file); - } - } - else { - if(cmd == C_PROXY_HEADER) /* --proxy-header */ - err = add2list(&config->proxyheaders, nextarg); - else - err = add2list(&config->headers, nextarg); - } + err = parse_header(global, config, cmd, nextarg); break; case C_INCLUDE: /* --include */ case C_SHOW_HEADERS: /* --show-headers */ @@ -2343,47 +2716,10 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER; break; case C_OUTPUT: /* --output */ + err = parse_output(config, nextarg); + break; case C_REMOTE_NAME: /* --remote-name */ - /* output file */ - if(!config->url_out) - config->url_out = config->url_list; - if(config->url_out) { - /* there is a node here, if it already is filled-in continue to find - an "empty" node */ - while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) - config->url_out = config->url_out->next; - } - - /* now there might or might not be an available node to fill in! */ - - if(config->url_out) - /* existing node */ - url = config->url_out; - else { - if(!toggle && !config->default_node_flags) - break; - /* there was no free node, create one! */ - config->url_out = url = new_getout(config); - } - - if(!url) { - err = PARAM_NO_MEM; - break; - } - - /* fill in the outfile */ - if('o' == letter) { - err = getstr(&url->outfile, nextarg, DENY_BLANK); - url->flags &= ~GETOUT_USEREMOTE; /* switch off */ - } - else { - url->outfile = NULL; /* leave it */ - if(toggle) - url->flags |= GETOUT_USEREMOTE; /* switch on */ - else - url->flags &= ~GETOUT_USEREMOTE; /* switch off */ - } - url->flags |= GETOUT_OUTFILE; + err = parse_remote_name(config, toggle); break; case C_FTP_PORT: /* --ftp-port */ /* This makes the FTP sessions use PORT instead of PASV */ @@ -2403,65 +2739,10 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ cause an error! */ break; case C_QUOTE: /* --quote */ - /* QUOTE command to send to FTP server */ - switch(nextarg[0]) { - case '-': - /* prefixed with a dash makes it a POST TRANSFER one */ - nextarg++; - err = add2list(&config->postquote, nextarg); - break; - case '+': - /* prefixed with a plus makes it a just-before-transfer one */ - nextarg++; - err = add2list(&config->prequote, nextarg); - break; - default: - err = add2list(&config->quote, nextarg); - break; - } + err = parse_quote(config, nextarg); break; case C_RANGE: /* --range */ - if(config->use_resume) { - errorf(global, "--continue-at is mutually exclusive with --range"); - return PARAM_BAD_USE; - } - /* Specifying a range WITHOUT A DASH will create an illegal HTTP range - (and will not actually be range by definition). The manpage - previously claimed that to be a good way, why this code is added to - work-around it. */ - if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) { - char buffer[32]; - if(curlx_strtoofft(nextarg, NULL, 10, &value)) { - warnf(global, "unsupported range point"); - err = PARAM_BAD_USE; - } - else { - warnf(global, - "A specified range MUST include at least one dash (-). " - "Appending one for you"); - msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", - value); - Curl_safefree(config->range); - config->range = strdup(buffer); - if(!config->range) - err = PARAM_NO_MEM; - } - } - else { - /* byte range requested */ - const char *tmp_range = nextarg; - while(*tmp_range) { - if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { - warnf(global, "Invalid character is found in given range. " - "A specified range MUST have only digits in " - "\'start\'-\'stop\'. The server's response to this " - "request is uncertain."); - break; - } - tmp_range++; - } - err = getstr(&config->range, nextarg, DENY_BLANK); - } + err = parse_range(global, config, nextarg); break; case C_REMOTE_TIME: /* --remote-time */ /* use remote file's time */ @@ -2481,37 +2762,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ err = add2list(&config->telnet_options, nextarg); break; case C_UPLOAD_FILE: /* --upload-file */ - /* we are uploading */ - if(!config->url_ul) - config->url_ul = config->url_list; - if(config->url_ul) { - /* there is a node here, if it already is filled-in continue to find - an "empty" node */ - while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD)) - config->url_ul = config->url_ul->next; - } - - /* now there might or might not be an available node to fill in! */ - - if(config->url_ul) - /* existing node */ - url = config->url_ul; - else - /* there was no free node, create one! */ - config->url_ul = url = new_getout(config); - - if(!url) { - err = PARAM_NO_MEM; - break; - } - - url->flags |= GETOUT_UPLOAD; /* mark -T used */ - if(!*nextarg) - url->flags |= GETOUT_NOUPLOAD; - else { - /* "-" equals stdin, but keep the string around for now */ - err = getstr(&url->infile, nextarg, DENY_BLANK); - } + err = parse_upload_file(config, nextarg); break; case C_USER: /* --user */ /* user:password */ @@ -2524,95 +2775,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ cleanarg(clearthis); break; case C_VERBOSE: /* --verbose */ - /* This option is a super-boolean with side effect when applied - * more than once in the same argument flag, like `-vvv`. */ - if(!toggle) { - global->verbosity = 0; - if(set_trace_config(global, "-all")) - err = PARAM_NO_MEM; - global->tracetype = TRACE_NONE; - break; - } - else if(!nopts) { - /* fist `-v` in an argument resets to base verbosity */ - global->verbosity = 0; - if(set_trace_config(global, "-all")) { - err = PARAM_NO_MEM; - break; - } - } - /* the '%' thing here will cause the trace get sent to stderr */ - switch(global->verbosity) { - case 0: - global->verbosity = 1; - Curl_safefree(global->trace_dump); - global->trace_dump = strdup("%"); - if(!global->trace_dump) - err = PARAM_NO_MEM; - else { - if(global->tracetype && (global->tracetype != TRACE_PLAIN)) - warnf(global, - "-v, --verbose overrides an earlier trace option"); - global->tracetype = TRACE_PLAIN; - } - break; - case 1: - global->verbosity = 2; - if(set_trace_config(global, "ids,time,protocol")) - err = PARAM_NO_MEM; - break; - case 2: - global->verbosity = 3; - global->tracetype = TRACE_ASCII; - if(set_trace_config(global, "ssl,read,write")) - err = PARAM_NO_MEM; - break; - case 3: - global->verbosity = 4; - if(set_trace_config(global, "network")) - err = PARAM_NO_MEM; - break; - default: - /* no effect for now */ - break; - } + err = parse_verbose(global, toggle, nopts); break; case C_VERSION: /* --version */ if(toggle) /* --no-version yields no output! */ err = PARAM_VERSION_INFO_REQUESTED; break; case C_WRITE_OUT: /* --write-out */ - /* get the output string */ - if('@' == *nextarg) { - /* the data begins with a '@' letter, it means that a filename - or - (stdin) follows */ - FILE *file; - const char *fname; - nextarg++; /* pass the @ */ - if(!strcmp("-", nextarg)) { - fname = ""; - file = stdin; - } - else { - fname = nextarg; - file = fopen(fname, FOPEN_READTEXT); - if(!file) { - errorf(global, "Failed to open %s", fname); - err = PARAM_READ_ERROR; - break; - } - } - Curl_safefree(config->writeout); - err = file2string(&config->writeout, file); - if(file && (file != stdin)) - fclose(file); - if(err) - break; - if(!config->writeout) - warnf(global, "Failed to read %s", fname); - } - else - err = getstr(&config->writeout, nextarg, ALLOW_BLANK); + err = parse_writeout(global, config, nextarg); break; case C_PREPROXY: /* --preproxy */ err = getstr(&config->preproxy, nextarg, DENY_BLANK); @@ -2659,41 +2829,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ global->parallel_connect = toggle; break; case C_TIME_COND: /* --time-cond */ - switch(*nextarg) { - case '+': - nextarg++; - FALLTHROUGH(); - default: - /* If-Modified-Since: (section 14.28 in RFC2068) */ - config->timecond = CURL_TIMECOND_IFMODSINCE; - break; - case '-': - /* If-Unmodified-Since: (section 14.24 in RFC2068) */ - config->timecond = CURL_TIMECOND_IFUNMODSINCE; - nextarg++; - break; - case '=': - /* Last-Modified: (section 14.29 in RFC2068) */ - config->timecond = CURL_TIMECOND_LASTMOD; - nextarg++; - break; - } - config->condtime = (curl_off_t)curl_getdate(nextarg, NULL); - if(-1 == config->condtime) { - /* now let's see if it is a filename to get the time from instead! */ - rc = getfiletime(nextarg, global, &value); - if(!rc) - /* pull the time out from the file */ - config->condtime = value; - else { - /* failed, remove time condition */ - config->timecond = CURL_TIMECOND_NONE; - warnf(global, - "Illegal date format for -z, --time-cond (and not " - "a filename). Disabling time condition. " - "See curl_getdate(3) for valid date syntax."); - } - } + err = parse_time_cond(global, config, nextarg); break; case C_MPTCP: /* --mptcp */ config->mptcp = TRUE;