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 = "<stdin>";
+ 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 */
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' */
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",
do {
/* we can loop here if we have multiple single-letters */
- char letter;
cmdline_t cmd;
if(!longopt && !a) {
break;
}
}
- letter = a->letter;
cmd = (cmdline_t)a->cmd;
if(ARGTYPE(a->desc) >= ARG_STRG) {
/* this option requires an extra parameter */
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 */
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;
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 */
}
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;
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 */
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 */
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 */
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 */
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 = "<stdin>";
- 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);
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;