• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 #include "tool_setup.h"
25 
26 #include "strcase.h"
27 
28 #define ENABLE_CURLX_PRINTF
29 /* use our own printf() functions */
30 #include "curlx.h"
31 
32 #include "tool_binmode.h"
33 #include "tool_cfgable.h"
34 #include "tool_cb_prg.h"
35 #include "tool_filetime.h"
36 #include "tool_formparse.h"
37 #include "tool_getparam.h"
38 #include "tool_helpers.h"
39 #include "tool_libinfo.h"
40 #include "tool_msgs.h"
41 #include "tool_paramhlp.h"
42 #include "tool_parsecfg.h"
43 #include "tool_main.h"
44 #include "dynbuf.h"
45 #include "tool_stderr.h"
46 #include "var.h"
47 
48 #include "memdebug.h" /* keep this as LAST include */
49 
50 #ifdef MSDOS
51 #  define USE_WATT32
52 #endif
53 
54 #define ALLOW_BLANK TRUE
55 #define DENY_BLANK FALSE
56 
getstr(char ** str,const char * val,bool allowblank)57 static ParameterError getstr(char **str, const char *val, bool allowblank)
58 {
59   if(*str) {
60     free(*str);
61     *str = NULL;
62   }
63   if(val) {
64     if(!allowblank && !val[0])
65       return PARAM_BLANK_STRING;
66 
67     *str = strdup(val);
68     if(!*str)
69       return PARAM_NO_MEM;
70   }
71   return PARAM_OK;
72 }
73 
74 /* one enum for every command line option. The name is the verbatim long
75    option name, but in uppercase with periods and minuses replaced with
76    underscores using a "C_" prefix. */
77 typedef enum {
78   C_ABSTRACT_UNIX_SOCKET,
79   C_ALPN,
80   C_ALT_SVC,
81   C_ANYAUTH,
82   C_APPEND,
83   C_AWS_SIGV4,
84   C_BASIC,
85   C_BUFFER,
86   C_CA_NATIVE,
87   C_CACERT,
88   C_CAPATH,
89   C_CERT,
90   C_CERT_STATUS,
91   C_CERT_TYPE,
92   C_CIPHERS,
93   C_CLOBBER,
94   C_COMPRESSED,
95   C_COMPRESSED_SSH,
96   C_CONFIG,
97   C_CONNECT_TIMEOUT,
98   C_CONNECT_TO,
99   C_CONTINUE_AT,
100   C_COOKIE,
101   C_COOKIE_JAR,
102   C_CREATE_DIRS,
103   C_CREATE_FILE_MODE,
104   C_CRLF,
105   C_CRLFILE,
106   C_CURVES,
107   C_DATA,
108   C_DATA_ASCII,
109   C_DATA_BINARY,
110   C_DATA_RAW,
111   C_DATA_URLENCODE,
112   C_DELEGATION,
113   C_DIGEST,
114   C_DISABLE,
115   C_DISABLE_EPRT,
116   C_DISABLE_EPSV,
117   C_DISALLOW_USERNAME_IN_URL,
118   C_DNS_INTERFACE,
119   C_DNS_IPV4_ADDR,
120   C_DNS_IPV6_ADDR,
121   C_DNS_SERVERS,
122   C_DOH_CERT_STATUS,
123   C_DOH_INSECURE,
124   C_DOH_URL,
125   C_DUMP_HEADER,
126   C_ECH,
127   C_EGD_FILE,
128   C_ENGINE,
129   C_EPRT,
130   C_EPSV,
131   C_ETAG_COMPARE,
132   C_ETAG_SAVE,
133   C_EXPECT100_TIMEOUT,
134   C_FAIL,
135   C_FAIL_EARLY,
136   C_FAIL_WITH_BODY,
137   C_FALSE_START,
138   C_FORM,
139   C_FORM_ESCAPE,
140   C_FORM_STRING,
141   C_FTP_ACCOUNT,
142   C_FTP_ALTERNATIVE_TO_USER,
143   C_FTP_CREATE_DIRS,
144   C_FTP_METHOD,
145   C_FTP_PASV,
146   C_FTP_PORT,
147   C_FTP_PRET,
148   C_FTP_SKIP_PASV_IP,
149   C_FTP_SSL,
150   C_FTP_SSL_CCC,
151   C_FTP_SSL_CCC_MODE,
152   C_FTP_SSL_CONTROL,
153   C_FTP_SSL_REQD,
154   C_GET,
155   C_GLOBOFF,
156   C_HAPPY_EYEBALLS_TIMEOUT_MS,
157   C_HAPROXY_CLIENTIP,
158   C_HAPROXY_PROTOCOL,
159   C_HEAD,
160   C_HEADER,
161   C_HELP,
162   C_HOSTPUBMD5,
163   C_HOSTPUBSHA256,
164   C_HSTS,
165   C_HTTP0_9,
166   C_HTTP1_0,
167   C_HTTP1_1,
168   C_HTTP2,
169   C_HTTP2_PRIOR_KNOWLEDGE,
170   C_HTTP3,
171   C_HTTP3_ONLY,
172   C_IGNORE_CONTENT_LENGTH,
173   C_INCLUDE,
174   C_INSECURE,
175   C_INTERFACE,
176   C_IPFS_GATEWAY,
177   C_IPV4,
178   C_IPV6,
179   C_JSON,
180   C_JUNK_SESSION_COOKIES,
181   C_KEEPALIVE,
182   C_KEEPALIVE_TIME,
183   C_KEY,
184   C_KEY_TYPE,
185   C_KRB,
186   C_KRB4,
187   C_LIBCURL,
188   C_LIMIT_RATE,
189   C_LIST_ONLY,
190   C_LOCAL_PORT,
191   C_LOCATION,
192   C_LOCATION_TRUSTED,
193   C_LOGIN_OPTIONS,
194   C_MAIL_AUTH,
195   C_MAIL_FROM,
196   C_MAIL_RCPT,
197   C_MAIL_RCPT_ALLOWFAILS,
198   C_MANUAL,
199   C_MAX_FILESIZE,
200   C_MAX_REDIRS,
201   C_MAX_TIME,
202   C_METALINK,
203   C_NEGOTIATE,
204   C_NETRC,
205   C_NETRC_FILE,
206   C_NETRC_OPTIONAL,
207   C_NEXT,
208   C_NOPROXY,
209   C_NPN,
210   C_NTLM,
211   C_NTLM_WB,
212   C_OAUTH2_BEARER,
213   C_OUTPUT,
214   C_OUTPUT_DIR,
215   C_PARALLEL,
216   C_PARALLEL_IMMEDIATE,
217   C_PARALLEL_MAX,
218   C_PASS,
219   C_PATH_AS_IS,
220   C_PINNEDPUBKEY,
221   C_POST301,
222   C_POST302,
223   C_POST303,
224   C_PREPROXY,
225   C_PROGRESS_BAR,
226   C_PROGRESS_METER,
227   C_PROTO,
228   C_PROTO_DEFAULT,
229   C_PROTO_REDIR,
230   C_PROXY,
231   C_PROXY_ANYAUTH,
232   C_PROXY_BASIC,
233   C_PROXY_CA_NATIVE,
234   C_PROXY_CACERT,
235   C_PROXY_CAPATH,
236   C_PROXY_CERT,
237   C_PROXY_CERT_TYPE,
238   C_PROXY_CIPHERS,
239   C_PROXY_CRLFILE,
240   C_PROXY_DIGEST,
241   C_PROXY_HEADER,
242   C_PROXY_HTTP2,
243   C_PROXY_INSECURE,
244   C_PROXY_KEY,
245   C_PROXY_KEY_TYPE,
246   C_PROXY_NEGOTIATE,
247   C_PROXY_NTLM,
248   C_PROXY_PASS,
249   C_PROXY_PINNEDPUBKEY,
250   C_PROXY_SERVICE_NAME,
251   C_PROXY_SSL_ALLOW_BEAST,
252   C_PROXY_SSL_AUTO_CLIENT_CERT,
253   C_PROXY_TLS13_CIPHERS,
254   C_PROXY_TLSAUTHTYPE,
255   C_PROXY_TLSPASSWORD,
256   C_PROXY_TLSUSER,
257   C_PROXY_TLSV1,
258   C_PROXY_USER,
259   C_PROXY1_0,
260   C_PROXYTUNNEL,
261   C_PUBKEY,
262   C_QUOTE,
263   C_RANDOM_FILE,
264   C_RANGE,
265   C_RATE,
266   C_RAW,
267   C_REFERER,
268   C_REMOTE_HEADER_NAME,
269   C_REMOTE_NAME,
270   C_REMOTE_NAME_ALL,
271   C_REMOTE_TIME,
272   C_REMOVE_ON_ERROR,
273   C_REQUEST,
274   C_REQUEST_TARGET,
275   C_RESOLVE,
276   C_RETRY,
277   C_RETRY_ALL_ERRORS,
278   C_RETRY_CONNREFUSED,
279   C_RETRY_DELAY,
280   C_RETRY_MAX_TIME,
281   C_SASL_AUTHZID,
282   C_SASL_IR,
283   C_SERVICE_NAME,
284   C_SESSIONID,
285   C_SHOW_ERROR,
286   C_SILENT,
287   C_SOCKS4,
288   C_SOCKS4A,
289   C_SOCKS5,
290   C_SOCKS5_BASIC,
291   C_SOCKS5_GSSAPI,
292   C_SOCKS5_GSSAPI_NEC,
293   C_SOCKS5_GSSAPI_SERVICE,
294   C_SOCKS5_HOSTNAME,
295   C_SPEED_LIMIT,
296   C_SPEED_TIME,
297   C_SSL,
298   C_SSL_ALLOW_BEAST,
299   C_SSL_AUTO_CLIENT_CERT,
300   C_SSL_NO_REVOKE,
301   C_SSL_REQD,
302   C_SSL_REVOKE_BEST_EFFORT,
303   C_SSLV2,
304   C_SSLV3,
305   C_STDERR,
306   C_STYLED_OUTPUT,
307   C_SUPPRESS_CONNECT_HEADERS,
308   C_TCP_FASTOPEN,
309   C_TCP_NODELAY,
310   C_TELNET_OPTION,
311   C_TEST_EVENT,
312   C_TFTP_BLKSIZE,
313   C_TFTP_NO_OPTIONS,
314   C_TIME_COND,
315   C_TLS_MAX,
316   C_TLS13_CIPHERS,
317   C_TLSAUTHTYPE,
318   C_TLSPASSWORD,
319   C_TLSUSER,
320   C_TLSV1,
321   C_TLSV1_0,
322   C_TLSV1_1,
323   C_TLSV1_2,
324   C_TLSV1_3,
325   C_TR_ENCODING,
326   C_TRACE,
327   C_TRACE_ASCII,
328   C_TRACE_CONFIG,
329   C_TRACE_IDS,
330   C_TRACE_TIME,
331   C_UNIX_SOCKET,
332   C_UPLOAD_FILE,
333   C_URL,
334   C_URL_QUERY,
335   C_USE_ASCII,
336   C_USER,
337   C_USER_AGENT,
338   C_VARIABLE,
339   C_VERBOSE,
340   C_VERSION,
341   C_WDEBUG,
342   C_WRITE_OUT,
343   C_XATTR
344 } cmdline_t;
345 
346 struct LongShort {
347   const char *lname;  /* long name option */
348   enum {
349     ARG_NONE, /* stand-alone but not a boolean */
350     ARG_BOOL, /* accepts a --no-[name] prefix */
351     ARG_STRG, /* requires an argument */
352     ARG_FILE  /* requires an argument, usually a file name */
353   } desc;
354   char letter;  /* short name option or ' ' */
355   cmdline_t cmd;
356 };
357 
358 /* this array MUST be alphasorted based on the 'lname' */
359 static const struct LongShort aliases[]= {
360   {"abstract-unix-socket",       ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET},
361   {"alpn",                       ARG_BOOL, ' ', C_ALPN},
362   {"alt-svc",                    ARG_STRG, ' ', C_ALT_SVC},
363   {"anyauth",                    ARG_BOOL, ' ', C_ANYAUTH},
364   {"append",                     ARG_BOOL, 'a', C_APPEND},
365   {"aws-sigv4",                  ARG_STRG, ' ', C_AWS_SIGV4},
366   {"basic",                      ARG_BOOL, ' ', C_BASIC},
367   {"buffer",                     ARG_BOOL, 'N', C_BUFFER},
368   {"ca-native",                  ARG_BOOL, ' ', C_CA_NATIVE},
369   {"cacert",                     ARG_FILE, ' ', C_CACERT},
370   {"capath",                     ARG_FILE, ' ', C_CAPATH},
371   {"cert",                       ARG_FILE, 'E', C_CERT},
372   {"cert-status",                ARG_BOOL, ' ', C_CERT_STATUS},
373   {"cert-type",                  ARG_STRG, ' ', C_CERT_TYPE},
374   {"ciphers",                    ARG_STRG, ' ', C_CIPHERS},
375   {"clobber",                    ARG_BOOL, ' ', C_CLOBBER},
376   {"compressed",                 ARG_BOOL, ' ', C_COMPRESSED},
377   {"compressed-ssh",             ARG_BOOL, ' ', C_COMPRESSED_SSH},
378   {"config",                     ARG_FILE, 'K', C_CONFIG},
379   {"connect-timeout",            ARG_STRG, ' ', C_CONNECT_TIMEOUT},
380   {"connect-to",                 ARG_STRG, ' ', C_CONNECT_TO},
381   {"continue-at",                ARG_STRG, 'C', C_CONTINUE_AT},
382   {"cookie",                     ARG_STRG, 'b', C_COOKIE},
383   {"cookie-jar",                 ARG_STRG, 'c', C_COOKIE_JAR},
384   {"create-dirs",                ARG_BOOL, ' ', C_CREATE_DIRS},
385   {"create-file-mode",           ARG_STRG, ' ', C_CREATE_FILE_MODE},
386   {"crlf",                       ARG_BOOL, ' ', C_CRLF},
387   {"crlfile",                    ARG_FILE, ' ', C_CRLFILE},
388   {"curves",                     ARG_STRG, ' ', C_CURVES},
389   {"data",                       ARG_STRG, 'd', C_DATA},
390   {"data-ascii",                 ARG_STRG, ' ', C_DATA_ASCII},
391   {"data-binary",                ARG_STRG, ' ', C_DATA_BINARY},
392   {"data-raw",                   ARG_STRG, ' ', C_DATA_RAW},
393   {"data-urlencode",             ARG_STRG, ' ', C_DATA_URLENCODE},
394   {"delegation",                 ARG_STRG, ' ', C_DELEGATION},
395   {"digest",                     ARG_BOOL, ' ', C_DIGEST},
396   {"disable",                    ARG_BOOL, 'q', C_DISABLE},
397   {"disable-eprt",               ARG_BOOL, ' ', C_DISABLE_EPRT},
398   {"disable-epsv",               ARG_BOOL, ' ', C_DISABLE_EPSV},
399   {"disallow-username-in-url",   ARG_BOOL, ' ', C_DISALLOW_USERNAME_IN_URL},
400   {"dns-interface",              ARG_STRG, ' ', C_DNS_INTERFACE},
401   {"dns-ipv4-addr",              ARG_STRG, ' ', C_DNS_IPV4_ADDR},
402   {"dns-ipv6-addr",              ARG_STRG, ' ', C_DNS_IPV6_ADDR},
403   {"dns-servers",                ARG_STRG, ' ', C_DNS_SERVERS},
404   {"doh-cert-status",            ARG_BOOL, ' ', C_DOH_CERT_STATUS},
405   {"doh-insecure",               ARG_BOOL, ' ', C_DOH_INSECURE},
406   {"doh-url"        ,            ARG_STRG, ' ', C_DOH_URL},
407   {"dump-header",                ARG_FILE, 'D', C_DUMP_HEADER},
408   {"ech",                        ARG_STRG, ' ', C_ECH},
409   {"egd-file",                   ARG_STRG, ' ', C_EGD_FILE},
410   {"engine",                     ARG_STRG, ' ', C_ENGINE},
411   {"eprt",                       ARG_BOOL, ' ', C_EPRT},
412   {"epsv",                       ARG_BOOL, ' ', C_EPSV},
413   {"etag-compare",               ARG_FILE, ' ', C_ETAG_COMPARE},
414   {"etag-save",                  ARG_FILE, ' ', C_ETAG_SAVE},
415   {"expect100-timeout",          ARG_STRG, ' ', C_EXPECT100_TIMEOUT},
416   {"fail",                       ARG_BOOL, 'f', C_FAIL},
417   {"fail-early",                 ARG_BOOL, ' ', C_FAIL_EARLY},
418   {"fail-with-body",             ARG_BOOL, ' ', C_FAIL_WITH_BODY},
419   {"false-start",                ARG_BOOL, ' ', C_FALSE_START},
420   {"form",                       ARG_STRG, 'F', C_FORM},
421   {"form-escape",                ARG_BOOL, ' ', C_FORM_ESCAPE},
422   {"form-string",                ARG_STRG, ' ', C_FORM_STRING},
423   {"ftp-account",                ARG_STRG, ' ', C_FTP_ACCOUNT},
424   {"ftp-alternative-to-user",    ARG_STRG, ' ', C_FTP_ALTERNATIVE_TO_USER},
425   {"ftp-create-dirs",            ARG_BOOL, ' ', C_FTP_CREATE_DIRS},
426   {"ftp-method",                 ARG_STRG, ' ', C_FTP_METHOD},
427   {"ftp-pasv",                   ARG_BOOL, ' ', C_FTP_PASV},
428   {"ftp-port",                   ARG_STRG, 'P', C_FTP_PORT},
429   {"ftp-pret",                   ARG_BOOL, ' ', C_FTP_PRET},
430   {"ftp-skip-pasv-ip",           ARG_BOOL, ' ', C_FTP_SKIP_PASV_IP},
431   {"ftp-ssl",                    ARG_BOOL, ' ', C_FTP_SSL},
432   {"ftp-ssl-ccc",                ARG_BOOL, ' ', C_FTP_SSL_CCC},
433   {"ftp-ssl-ccc-mode",           ARG_STRG, ' ', C_FTP_SSL_CCC_MODE},
434   {"ftp-ssl-control",            ARG_BOOL, ' ', C_FTP_SSL_CONTROL},
435   {"ftp-ssl-reqd",               ARG_BOOL, ' ', C_FTP_SSL_REQD},
436   {"get",                        ARG_BOOL, 'G', C_GET},
437   {"globoff",                    ARG_BOOL, 'g', C_GLOBOFF},
438   {"happy-eyeballs-timeout-ms",  ARG_STRG, ' ', C_HAPPY_EYEBALLS_TIMEOUT_MS},
439   {"haproxy-clientip",           ARG_STRG, ' ', C_HAPROXY_CLIENTIP},
440   {"haproxy-protocol",           ARG_BOOL, ' ', C_HAPROXY_PROTOCOL},
441   {"head",                       ARG_BOOL, 'I', C_HEAD},
442   {"header",                     ARG_STRG, 'H', C_HEADER},
443   {"help",                       ARG_BOOL, 'h', C_HELP},
444   {"hostpubmd5",                 ARG_STRG, ' ', C_HOSTPUBMD5},
445   {"hostpubsha256",              ARG_STRG, ' ', C_HOSTPUBSHA256},
446   {"hsts",                       ARG_STRG, ' ', C_HSTS},
447   {"http0.9",                    ARG_BOOL, ' ', C_HTTP0_9},
448   {"http1.0",                    ARG_NONE, '0', C_HTTP1_0},
449   {"http1.1",                    ARG_NONE, ' ', C_HTTP1_1},
450   {"http2",                      ARG_NONE, ' ', C_HTTP2},
451   {"http2-prior-knowledge",      ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE},
452   {"http3",                      ARG_NONE, ' ', C_HTTP3},
453   {"http3-only",                 ARG_NONE, ' ', C_HTTP3_ONLY},
454   {"ignore-content-length",      ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH},
455   {"include",                    ARG_BOOL, 'i', C_INCLUDE},
456   {"insecure",                   ARG_BOOL, 'k', C_INSECURE},
457   {"interface",                  ARG_STRG, ' ', C_INTERFACE},
458   {"ipfs-gateway",               ARG_STRG, ' ', C_IPFS_GATEWAY},
459   {"ipv4",                       ARG_NONE, '4', C_IPV4},
460   {"ipv6",                       ARG_NONE, '6', C_IPV6},
461   {"json",                       ARG_STRG, ' ', C_JSON},
462   {"junk-session-cookies",       ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES},
463   {"keepalive",                  ARG_BOOL, ' ', C_KEEPALIVE},
464   {"keepalive-time",             ARG_STRG, ' ', C_KEEPALIVE_TIME},
465   {"key",                        ARG_FILE, ' ', C_KEY},
466   {"key-type",                   ARG_STRG, ' ', C_KEY_TYPE},
467   {"krb",                        ARG_STRG, ' ', C_KRB},
468   {"krb4",                       ARG_STRG, ' ', C_KRB4},
469   {"libcurl",                    ARG_STRG, ' ', C_LIBCURL},
470   {"limit-rate",                 ARG_STRG, ' ', C_LIMIT_RATE},
471   {"list-only",                  ARG_BOOL, 'l', C_LIST_ONLY},
472   {"local-port",                 ARG_STRG, ' ', C_LOCAL_PORT},
473   {"location",                   ARG_BOOL, 'L', C_LOCATION},
474   {"location-trusted",           ARG_BOOL, ' ', C_LOCATION_TRUSTED},
475   {"login-options",              ARG_STRG, ' ', C_LOGIN_OPTIONS},
476   {"mail-auth",                  ARG_STRG, ' ', C_MAIL_AUTH},
477   {"mail-from",                  ARG_STRG, ' ', C_MAIL_FROM},
478   {"mail-rcpt",                  ARG_STRG, ' ', C_MAIL_RCPT},
479   {"mail-rcpt-allowfails",       ARG_BOOL, ' ', C_MAIL_RCPT_ALLOWFAILS},
480   {"manual",                     ARG_BOOL, 'M', C_MANUAL},
481   {"max-filesize",               ARG_STRG, ' ', C_MAX_FILESIZE},
482   {"max-redirs",                 ARG_STRG, ' ', C_MAX_REDIRS},
483   {"max-time",                   ARG_STRG, 'm', C_MAX_TIME},
484   {"metalink",                   ARG_BOOL, ' ', C_METALINK},
485   {"negotiate",                  ARG_BOOL, ' ', C_NEGOTIATE},
486   {"netrc",                      ARG_BOOL, 'n', C_NETRC},
487   {"netrc-file",                 ARG_FILE, ' ', C_NETRC_FILE},
488   {"netrc-optional",             ARG_BOOL, ' ', C_NETRC_OPTIONAL},
489   {"next",                       ARG_NONE, ':', C_NEXT},
490   {"noproxy",                    ARG_STRG, ' ', C_NOPROXY},
491   {"npn",                        ARG_BOOL, ' ', C_NPN},
492   {"ntlm",                       ARG_BOOL, ' ', C_NTLM},
493   {"ntlm-wb",                    ARG_BOOL, ' ', C_NTLM_WB},
494   {"oauth2-bearer",              ARG_STRG, ' ', C_OAUTH2_BEARER},
495   {"output",                     ARG_FILE, 'o', C_OUTPUT},
496   {"output-dir",                 ARG_STRG, ' ', C_OUTPUT_DIR},
497   {"parallel",                   ARG_BOOL, 'Z', C_PARALLEL},
498   {"parallel-immediate",         ARG_BOOL, ' ', C_PARALLEL_IMMEDIATE},
499   {"parallel-max",               ARG_STRG, ' ', C_PARALLEL_MAX},
500   {"pass",                       ARG_STRG, ' ', C_PASS},
501   {"path-as-is",                 ARG_BOOL, ' ', C_PATH_AS_IS},
502   {"pinnedpubkey",               ARG_STRG, ' ', C_PINNEDPUBKEY},
503   {"post301",                    ARG_BOOL, ' ', C_POST301},
504   {"post302",                    ARG_BOOL, ' ', C_POST302},
505   {"post303",                    ARG_BOOL, ' ', C_POST303},
506   {"preproxy",                   ARG_STRG, ' ', C_PREPROXY},
507   {"progress-bar",               ARG_BOOL, '#', C_PROGRESS_BAR},
508   {"progress-meter",             ARG_BOOL, ' ', C_PROGRESS_METER},
509   {"proto",                      ARG_STRG, ' ', C_PROTO},
510   {"proto-default",              ARG_STRG, ' ', C_PROTO_DEFAULT},
511   {"proto-redir",                ARG_STRG, ' ', C_PROTO_REDIR},
512   {"proxy",                      ARG_STRG, 'x', C_PROXY},
513   {"proxy-anyauth",              ARG_BOOL, ' ', C_PROXY_ANYAUTH},
514   {"proxy-basic",                ARG_BOOL, ' ', C_PROXY_BASIC},
515   {"proxy-ca-native",            ARG_BOOL, ' ', C_PROXY_CA_NATIVE},
516   {"proxy-cacert",               ARG_FILE, ' ', C_PROXY_CACERT},
517   {"proxy-capath",               ARG_FILE, ' ', C_PROXY_CAPATH},
518   {"proxy-cert",                 ARG_FILE, ' ', C_PROXY_CERT},
519   {"proxy-cert-type",            ARG_STRG, ' ', C_PROXY_CERT_TYPE},
520   {"proxy-ciphers",              ARG_STRG, ' ', C_PROXY_CIPHERS},
521   {"proxy-crlfile",              ARG_FILE, ' ', C_PROXY_CRLFILE},
522   {"proxy-digest",               ARG_BOOL, ' ', C_PROXY_DIGEST},
523   {"proxy-header",               ARG_STRG, ' ', C_PROXY_HEADER},
524   {"proxy-http2",                ARG_BOOL, ' ', C_PROXY_HTTP2},
525   {"proxy-insecure",             ARG_BOOL, ' ', C_PROXY_INSECURE},
526   {"proxy-key",                  ARG_FILE, ' ', C_PROXY_KEY},
527   {"proxy-key-type",             ARG_STRG, ' ', C_PROXY_KEY_TYPE},
528   {"proxy-negotiate",            ARG_BOOL, ' ', C_PROXY_NEGOTIATE},
529   {"proxy-ntlm",                 ARG_BOOL, ' ', C_PROXY_NTLM},
530   {"proxy-pass",                 ARG_STRG, ' ', C_PROXY_PASS},
531   {"proxy-pinnedpubkey",         ARG_STRG, ' ', C_PROXY_PINNEDPUBKEY},
532   {"proxy-service-name",         ARG_STRG, ' ', C_PROXY_SERVICE_NAME},
533   {"proxy-ssl-allow-beast",      ARG_BOOL, ' ', C_PROXY_SSL_ALLOW_BEAST},
534   {"proxy-ssl-auto-client-cert", ARG_BOOL, ' ', C_PROXY_SSL_AUTO_CLIENT_CERT},
535   {"proxy-tls13-ciphers",        ARG_STRG, ' ', C_PROXY_TLS13_CIPHERS},
536   {"proxy-tlsauthtype",          ARG_STRG, ' ', C_PROXY_TLSAUTHTYPE},
537   {"proxy-tlspassword",          ARG_STRG, ' ', C_PROXY_TLSPASSWORD},
538   {"proxy-tlsuser",              ARG_STRG, ' ', C_PROXY_TLSUSER},
539   {"proxy-tlsv1",                ARG_NONE, ' ', C_PROXY_TLSV1},
540   {"proxy-user",                 ARG_STRG, 'U', C_PROXY_USER},
541   {"proxy1.0",                   ARG_STRG, ' ', C_PROXY1_0},
542   {"proxytunnel",                ARG_BOOL, 'p', C_PROXYTUNNEL},
543   {"pubkey",                     ARG_STRG, ' ', C_PUBKEY},
544   {"quote",                      ARG_STRG, 'Q', C_QUOTE},
545   {"random-file",                ARG_FILE, ' ', C_RANDOM_FILE},
546   {"range",                      ARG_STRG, 'r', C_RANGE},
547   {"rate",                       ARG_STRG, ' ', C_RATE},
548   {"raw",                        ARG_BOOL, ' ', C_RAW},
549   {"referer",                    ARG_STRG, 'e', C_REFERER},
550   {"remote-header-name",         ARG_BOOL, 'J', C_REMOTE_HEADER_NAME},
551   {"remote-name",                ARG_BOOL, 'O', C_REMOTE_NAME},
552   {"remote-name-all",            ARG_BOOL, ' ', C_REMOTE_NAME_ALL},
553   {"remote-time",                ARG_BOOL, 'R', C_REMOTE_TIME},
554   {"remove-on-error",            ARG_BOOL, ' ', C_REMOVE_ON_ERROR},
555   {"request",                    ARG_STRG, 'X', C_REQUEST},
556   {"request-target",             ARG_STRG, ' ', C_REQUEST_TARGET},
557   {"resolve",                    ARG_STRG, ' ', C_RESOLVE},
558   {"retry",                      ARG_STRG, ' ', C_RETRY},
559   {"retry-all-errors",           ARG_BOOL, ' ', C_RETRY_ALL_ERRORS},
560   {"retry-connrefused",          ARG_BOOL, ' ', C_RETRY_CONNREFUSED},
561   {"retry-delay",                ARG_STRG, ' ', C_RETRY_DELAY},
562   {"retry-max-time",             ARG_STRG, ' ', C_RETRY_MAX_TIME},
563   {"sasl-authzid",               ARG_STRG, ' ', C_SASL_AUTHZID},
564   {"sasl-ir",                    ARG_BOOL, ' ', C_SASL_IR},
565   {"service-name",               ARG_STRG, ' ', C_SERVICE_NAME},
566   {"sessionid",                  ARG_BOOL, ' ', C_SESSIONID},
567   {"show-error",                 ARG_BOOL, 'S', C_SHOW_ERROR},
568   {"silent",                     ARG_BOOL, 's', C_SILENT},
569   {"socks4",                     ARG_STRG, ' ', C_SOCKS4},
570   {"socks4a",                    ARG_STRG, ' ', C_SOCKS4A},
571   {"socks5",                     ARG_STRG, ' ', C_SOCKS5},
572   {"socks5-basic",               ARG_BOOL, ' ', C_SOCKS5_BASIC},
573   {"socks5-gssapi",              ARG_BOOL, ' ', C_SOCKS5_GSSAPI},
574   {"socks5-gssapi-nec",          ARG_BOOL, ' ', C_SOCKS5_GSSAPI_NEC},
575   {"socks5-gssapi-service",      ARG_STRG, ' ', C_SOCKS5_GSSAPI_SERVICE},
576   {"socks5-hostname",            ARG_STRG, ' ', C_SOCKS5_HOSTNAME},
577   {"speed-limit",                ARG_STRG, 'Y', C_SPEED_LIMIT},
578   {"speed-time",                 ARG_STRG, 'y', C_SPEED_TIME},
579   {"ssl",                        ARG_BOOL, ' ', C_SSL},
580   {"ssl-allow-beast",            ARG_BOOL, ' ', C_SSL_ALLOW_BEAST},
581   {"ssl-auto-client-cert",       ARG_BOOL, ' ', C_SSL_AUTO_CLIENT_CERT},
582   {"ssl-no-revoke",              ARG_BOOL, ' ', C_SSL_NO_REVOKE},
583   {"ssl-reqd",                   ARG_BOOL, ' ', C_SSL_REQD},
584   {"ssl-revoke-best-effort",     ARG_BOOL, ' ', C_SSL_REVOKE_BEST_EFFORT},
585   {"sslv2",                      ARG_NONE, '2', C_SSLV2},
586   {"sslv3",                      ARG_NONE, '3', C_SSLV3},
587   {"stderr",                     ARG_FILE, ' ', C_STDERR},
588   {"styled-output",              ARG_BOOL, ' ', C_STYLED_OUTPUT},
589   {"suppress-connect-headers",   ARG_BOOL, ' ', C_SUPPRESS_CONNECT_HEADERS},
590   {"tcp-fastopen",               ARG_BOOL, ' ', C_TCP_FASTOPEN},
591   {"tcp-nodelay",                ARG_BOOL, ' ', C_TCP_NODELAY},
592   {"telnet-option",              ARG_STRG, 't', C_TELNET_OPTION},
593   {"test-event",                 ARG_BOOL, ' ', C_TEST_EVENT},
594   {"tftp-blksize",               ARG_STRG, ' ', C_TFTP_BLKSIZE},
595   {"tftp-no-options",            ARG_BOOL, ' ', C_TFTP_NO_OPTIONS},
596   {"time-cond",                  ARG_STRG, 'z', C_TIME_COND},
597   {"tls-max",                    ARG_STRG, ' ', C_TLS_MAX},
598   {"tls13-ciphers",              ARG_STRG, ' ', C_TLS13_CIPHERS},
599   {"tlsauthtype",                ARG_STRG, ' ', C_TLSAUTHTYPE},
600   {"tlspassword",                ARG_STRG, ' ', C_TLSPASSWORD},
601   {"tlsuser",                    ARG_STRG, ' ', C_TLSUSER},
602   {"tlsv1",                      ARG_NONE, '1', C_TLSV1},
603   {"tlsv1.0",                    ARG_NONE, ' ', C_TLSV1_0},
604   {"tlsv1.1",                    ARG_NONE, ' ', C_TLSV1_1},
605   {"tlsv1.2",                    ARG_NONE, ' ', C_TLSV1_2},
606   {"tlsv1.3",                    ARG_NONE, ' ', C_TLSV1_3},
607   {"tr-encoding",                ARG_BOOL, ' ', C_TR_ENCODING},
608   {"trace",                      ARG_FILE, ' ', C_TRACE},
609   {"trace-ascii",                ARG_FILE, ' ', C_TRACE_ASCII},
610   {"trace-config",               ARG_STRG, ' ', C_TRACE_CONFIG},
611   {"trace-ids",                  ARG_BOOL, ' ', C_TRACE_IDS},
612   {"trace-time",                 ARG_BOOL, ' ', C_TRACE_TIME},
613   {"unix-socket",                ARG_FILE, ' ', C_UNIX_SOCKET},
614   {"upload-file",                ARG_FILE, 'T', C_UPLOAD_FILE},
615   {"url",                        ARG_STRG, ' ', C_URL},
616   {"url-query",                  ARG_STRG, ' ', C_URL_QUERY},
617   {"use-ascii",                  ARG_BOOL, 'B', C_USE_ASCII},
618   {"user",                       ARG_STRG, 'u', C_USER},
619   {"user-agent",                 ARG_STRG, 'A', C_USER_AGENT},
620   {"variable",                   ARG_STRG, ' ', C_VARIABLE},
621   {"verbose",                    ARG_BOOL, 'v', C_VERBOSE},
622   {"version",                    ARG_BOOL, 'V', C_VERSION},
623 #ifdef USE_WATT32
624   {"wdebug",                     ARG_BOOL, ' ', C_WDEBUG},
625 #endif
626   {"write-out",                  ARG_STRG, 'w', C_WRITE_OUT},
627   {"xattr",                      ARG_BOOL, ' ', C_XATTR},
628 };
629 
630 /* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
631  * We allow ':' and '\' to be escaped by '\' so that we can use certificate
632  * nicknames containing ':'.  See <https://sourceforge.net/p/curl/bugs/1196/>
633  * for details. */
634 #ifndef UNITTESTS
635 static
636 #endif
parse_cert_parameter(const char * cert_parameter,char ** certname,char ** passphrase)637 void parse_cert_parameter(const char *cert_parameter,
638                           char **certname,
639                           char **passphrase)
640 {
641   size_t param_length = strlen(cert_parameter);
642   size_t span;
643   const char *param_place = NULL;
644   char *certname_place = NULL;
645   *certname = NULL;
646   *passphrase = NULL;
647 
648   /* most trivial assumption: cert_parameter is empty */
649   if(param_length == 0)
650     return;
651 
652   /* next less trivial: cert_parameter starts 'pkcs11:' and thus
653    * looks like a RFC7512 PKCS#11 URI which can be used as-is.
654    * Also if cert_parameter contains no colon nor backslash, this
655    * means no passphrase was given and no characters escaped */
656   if(curl_strnequal(cert_parameter, "pkcs11:", 7) ||
657      !strpbrk(cert_parameter, ":\\")) {
658     *certname = strdup(cert_parameter);
659     return;
660   }
661   /* deal with escaped chars; find unescaped colon if it exists */
662   certname_place = malloc(param_length + 1);
663   if(!certname_place)
664     return;
665 
666   *certname = certname_place;
667   param_place = cert_parameter;
668   while(*param_place) {
669     span = strcspn(param_place, ":\\");
670     strncpy(certname_place, param_place, span);
671     param_place += span;
672     certname_place += span;
673     /* we just ate all the non-special chars. now we're on either a special
674      * char or the end of the string. */
675     switch(*param_place) {
676     case '\0':
677       break;
678     case '\\':
679       param_place++;
680       switch(*param_place) {
681         case '\0':
682           *certname_place++ = '\\';
683           break;
684         case '\\':
685           *certname_place++ = '\\';
686           param_place++;
687           break;
688         case ':':
689           *certname_place++ = ':';
690           param_place++;
691           break;
692         default:
693           *certname_place++ = '\\';
694           *certname_place++ = *param_place;
695           param_place++;
696           break;
697       }
698       break;
699     case ':':
700       /* Since we live in a world of weirdness and confusion, the win32
701          dudes can use : when using drive letters and thus c:\file:password
702          needs to work. In order not to break compatibility, we still use : as
703          separator, but we try to detect when it is used for a file name! On
704          windows. */
705 #ifdef _WIN32
706       if((param_place == &cert_parameter[1]) &&
707          (cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
708          (ISALPHA(cert_parameter[0])) ) {
709         /* colon in the second column, followed by a backslash, and the
710            first character is an alphabetic letter:
711 
712            this is a drive letter colon */
713         *certname_place++ = ':';
714         param_place++;
715         break;
716       }
717 #endif
718       /* escaped colons and Windows drive letter colons were handled
719        * above; if we're still here, this is a separating colon */
720       param_place++;
721       if(*param_place) {
722         *passphrase = strdup(param_place);
723       }
724       goto done;
725     }
726   }
727 done:
728   *certname_place = '\0';
729 }
730 
731 /* Replace (in-place) '%20' by '+' according to RFC1866 */
replace_url_encoded_space_by_plus(char * url)732 static size_t replace_url_encoded_space_by_plus(char *url)
733 {
734   size_t orig_len = strlen(url);
735   size_t orig_index = 0;
736   size_t new_index = 0;
737 
738   while(orig_index < orig_len) {
739     if((url[orig_index] == '%') &&
740        (url[orig_index + 1] == '2') &&
741        (url[orig_index + 2] == '0')) {
742       url[new_index] = '+';
743       orig_index += 3;
744     }
745     else{
746       if(new_index != orig_index) {
747         url[new_index] = url[orig_index];
748       }
749       orig_index++;
750     }
751     new_index++;
752   }
753 
754   url[new_index] = 0; /* terminate string */
755 
756   return new_index; /* new size */
757 }
758 
759 static void
GetFileAndPassword(char * nextarg,char ** file,char ** password)760 GetFileAndPassword(char *nextarg, char **file, char **password)
761 {
762   char *certname, *passphrase;
763   if(nextarg) {
764     parse_cert_parameter(nextarg, &certname, &passphrase);
765     Curl_safefree(*file);
766     *file = certname;
767     if(passphrase) {
768       Curl_safefree(*password);
769       *password = passphrase;
770     }
771   }
772 }
773 
774 /* Get a size parameter for '--limit-rate' or '--max-filesize'.
775  * We support a 'G', 'M' or 'K' suffix too.
776   */
GetSizeParameter(struct GlobalConfig * global,const char * arg,const char * which,curl_off_t * value_out)777 static ParameterError GetSizeParameter(struct GlobalConfig *global,
778                                        const char *arg,
779                                        const char *which,
780                                        curl_off_t *value_out)
781 {
782   char *unit;
783   curl_off_t value;
784 
785   if(curlx_strtoofft(arg, &unit, 10, &value)) {
786     warnf(global, "invalid number specified for %s", which);
787     return PARAM_BAD_USE;
788   }
789 
790   if(!*unit)
791     unit = (char *)"b";
792   else if(strlen(unit) > 1)
793     unit = (char *)"w"; /* unsupported */
794 
795   switch(*unit) {
796   case 'G':
797   case 'g':
798     if(value > (CURL_OFF_T_MAX / (1024*1024*1024)))
799       return PARAM_NUMBER_TOO_LARGE;
800     value *= 1024*1024*1024;
801     break;
802   case 'M':
803   case 'm':
804     if(value > (CURL_OFF_T_MAX / (1024*1024)))
805       return PARAM_NUMBER_TOO_LARGE;
806     value *= 1024*1024;
807     break;
808   case 'K':
809   case 'k':
810     if(value > (CURL_OFF_T_MAX / 1024))
811       return PARAM_NUMBER_TOO_LARGE;
812     value *= 1024;
813     break;
814   case 'b':
815   case 'B':
816     /* for plain bytes, leave as-is */
817     break;
818   default:
819     warnf(global, "unsupported %s unit. Use G, M, K or B", which);
820     return PARAM_BAD_USE;
821   }
822   *value_out = value;
823   return PARAM_OK;
824 }
825 
826 #ifdef HAVE_WRITABLE_ARGV
cleanarg(argv_item_t str)827 static void cleanarg(argv_item_t str)
828 {
829   /* now that getstr has copied the contents of nextarg, wipe the next
830    * argument out so that the username:password isn't displayed in the
831    * system process list */
832   if(str) {
833     size_t len = strlen(str);
834     memset(str, ' ', len);
835   }
836 }
837 #else
838 #define cleanarg(x)
839 #endif
840 
841 /* --data-urlencode */
data_urlencode(struct GlobalConfig * global,char * nextarg,char ** postp,size_t * lenp)842 static ParameterError data_urlencode(struct GlobalConfig *global,
843                                      char *nextarg,
844                                      char **postp,
845                                      size_t *lenp)
846 {
847   /* [name]=[content], we encode the content part only
848    * [name]@[file name]
849    *
850    * Case 2: we first load the file using that name and then encode
851    * the content.
852    */
853   ParameterError err;
854   const char *p = strchr(nextarg, '=');
855   size_t nlen;
856   char is_file;
857   char *postdata = NULL;
858   size_t size = 0;
859   if(!p)
860     /* there was no '=' letter, check for a '@' instead */
861     p = strchr(nextarg, '@');
862   if(p) {
863     nlen = p - nextarg; /* length of the name part */
864     is_file = *p++; /* pass the separator */
865   }
866   else {
867     /* neither @ nor =, so no name and it isn't a file */
868     nlen = 0;
869     is_file = 0;
870     p = nextarg;
871   }
872   if('@' == is_file) {
873     FILE *file;
874     /* a '@' letter, it means that a file name or - (stdin) follows */
875     if(!strcmp("-", p)) {
876       file = stdin;
877       set_binmode(stdin);
878     }
879     else {
880       file = fopen(p, "rb");
881       if(!file) {
882         errorf(global, "Failed to open %s", p);
883         return PARAM_READ_ERROR;
884       }
885     }
886 
887     err = file2memory(&postdata, &size, file);
888 
889     if(file && (file != stdin))
890       fclose(file);
891     if(err)
892       return err;
893   }
894   else {
895     err = getstr(&postdata, p, ALLOW_BLANK);
896     if(err)
897       goto error;
898     size = strlen(postdata);
899   }
900 
901   if(!postdata) {
902     /* no data from the file, point to a zero byte string to make this
903        get sent as a POST anyway */
904     postdata = strdup("");
905     if(!postdata)
906       return PARAM_NO_MEM;
907     size = 0;
908   }
909   else {
910     char *enc = curl_easy_escape(NULL, postdata, (int)size);
911     Curl_safefree(postdata); /* no matter if it worked or not */
912     if(enc) {
913       char *n;
914       replace_url_encoded_space_by_plus(enc);
915       if(nlen > 0) { /* only append '=' if we have a name */
916         n = aprintf("%.*s=%s", (int)nlen, nextarg, enc);
917         curl_free(enc);
918         if(!n)
919           return PARAM_NO_MEM;
920       }
921       else
922         n = enc;
923 
924       size = strlen(n);
925       postdata = n;
926     }
927     else
928       return PARAM_NO_MEM;
929   }
930   *postp = postdata;
931   *lenp = size;
932   return PARAM_OK;
933 error:
934   return err;
935 }
936 
sethttpver(struct GlobalConfig * global,struct OperationConfig * config,long httpversion)937 static void sethttpver(struct GlobalConfig *global,
938                        struct OperationConfig *config,
939                        long httpversion)
940 {
941   if(config->httpversion &&
942      (config->httpversion != httpversion))
943     warnf(global, "Overrides previous HTTP version option");
944 
945   config->httpversion = httpversion;
946 }
947 
set_trace_config(struct GlobalConfig * global,const char * config)948 static CURLcode set_trace_config(struct GlobalConfig *global,
949                                  const char *config)
950 {
951   CURLcode result = CURLE_OK;
952   char *token, *tmp, *name;
953   bool toggle;
954 
955   tmp = strdup(config);
956   if(!tmp)
957     return CURLE_OUT_OF_MEMORY;
958 
959   /* Allow strtok() here since this isn't used threaded */
960   /* !checksrc! disable BANNEDFUNC 2 */
961   token = strtok(tmp, ", ");
962   while(token) {
963     switch(*token) {
964       case '-':
965         toggle = FALSE;
966         name = token + 1;
967         break;
968       case '+':
969         toggle = TRUE;
970         name = token + 1;
971         break;
972       default:
973         toggle = TRUE;
974         name = token;
975         break;
976     }
977 
978     if(strcasecompare(name, "all")) {
979       global->traceids = toggle;
980       global->tracetime = toggle;
981       result = curl_global_trace(token);
982       if(result)
983         goto out;
984     }
985     else if(strcasecompare(name, "ids")) {
986       global->traceids = toggle;
987     }
988     else if(strcasecompare(name, "time")) {
989       global->tracetime = toggle;
990     }
991     else {
992       result = curl_global_trace(token);
993       if(result)
994         goto out;
995     }
996     token = strtok(NULL, ", ");
997   }
998 out:
999   free(tmp);
1000   return result;
1001 }
1002 
findarg(const void * a,const void * b)1003 static int findarg(const void *a, const void *b)
1004 {
1005   const struct LongShort *aa = a;
1006   const struct LongShort *bb = b;
1007   return strcmp(aa->lname, bb->lname);
1008 }
1009 
single(char letter)1010 static const struct LongShort *single(char letter)
1011 {
1012   static const struct LongShort *singles[128 - ' ']; /* ASCII => pointer */
1013   static bool singles_done = FALSE;
1014   if((letter >= 127) || (letter <= ' '))
1015     return NULL;
1016 
1017   if(!singles_done) {
1018     unsigned int j;
1019     for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
1020       if(aliases[j].letter != ' ') {
1021         unsigned char l = (unsigned char)aliases[j].letter;
1022         singles[l - ' '] = &aliases[j];
1023       }
1024     }
1025     singles_done = TRUE;
1026   }
1027   return singles[letter - ' '];
1028 }
1029 
1030 #define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
url_query(char * nextarg,struct GlobalConfig * global,struct OperationConfig * config)1031 static ParameterError url_query(char *nextarg,
1032                                 struct GlobalConfig *global,
1033                                 struct OperationConfig *config)
1034 {
1035   size_t size = 0;
1036   ParameterError err = PARAM_OK;
1037   char *query;
1038   struct curlx_dynbuf dyn;
1039   curlx_dyn_init(&dyn, MAX_QUERY_LEN);
1040 
1041   if(*nextarg == '+') {
1042     /* use without encoding */
1043     query = strdup(&nextarg[1]);
1044     if(!query)
1045       err = PARAM_NO_MEM;
1046   }
1047   else
1048     err = data_urlencode(global, nextarg, &query, &size);
1049 
1050   if(!err) {
1051     if(config->query) {
1052       CURLcode result = curlx_dyn_addf(&dyn, "%s&%s", config->query, query);
1053       free(query);
1054       if(result)
1055         err = PARAM_NO_MEM;
1056       else {
1057         free(config->query);
1058         config->query = curlx_dyn_ptr(&dyn);
1059       }
1060     }
1061     else
1062       config->query = query;
1063   }
1064   return err;
1065 }
1066 
set_data(cmdline_t cmd,char * nextarg,struct GlobalConfig * global,struct OperationConfig * config)1067 static ParameterError set_data(cmdline_t cmd,
1068                                char *nextarg,
1069                                struct GlobalConfig *global,
1070                                struct OperationConfig *config)
1071 {
1072   char *postdata = NULL;
1073   FILE *file;
1074   size_t size = 0;
1075   ParameterError err = PARAM_OK;
1076 
1077   if(cmd == C_DATA_URLENCODE) { /* --data-urlencode */
1078     err = data_urlencode(global, nextarg, &postdata, &size);
1079     if(err)
1080       return err;
1081   }
1082   else if('@' == *nextarg && (cmd != C_DATA_RAW)) {
1083     /* the data begins with a '@' letter, it means that a file name
1084        or - (stdin) follows */
1085     nextarg++; /* pass the @ */
1086 
1087     if(!strcmp("-", nextarg)) {
1088       file = stdin;
1089       if(cmd == C_DATA_BINARY) /* forced data-binary */
1090         set_binmode(stdin);
1091     }
1092     else {
1093       file = fopen(nextarg, "rb");
1094       if(!file) {
1095         errorf(global, "Failed to open %s", nextarg);
1096         return PARAM_READ_ERROR;
1097       }
1098     }
1099 
1100     if((cmd == C_DATA_BINARY) || /* --data-binary */
1101        (cmd == C_JSON) /* --json */)
1102       /* forced binary */
1103       err = file2memory(&postdata, &size, file);
1104     else {
1105       err = file2string(&postdata, file);
1106       if(postdata)
1107         size = strlen(postdata);
1108     }
1109 
1110     if(file && (file != stdin))
1111       fclose(file);
1112     if(err)
1113       return err;
1114 
1115     if(!postdata) {
1116       /* no data from the file, point to a zero byte string to make this
1117          get sent as a POST anyway */
1118       postdata = strdup("");
1119       if(!postdata)
1120         return PARAM_NO_MEM;
1121     }
1122   }
1123   else {
1124     err = getstr(&postdata, nextarg, ALLOW_BLANK);
1125     if(err)
1126       return err;
1127     size = strlen(postdata);
1128   }
1129   if(cmd == C_JSON)
1130     config->jsoned = TRUE;
1131 
1132   if(curlx_dyn_len(&config->postdata)) {
1133     /* skip separator append for --json */
1134     if(!err && (cmd != C_JSON)  &&
1135        curlx_dyn_addn(&config->postdata, "&", 1))
1136       err = PARAM_NO_MEM;
1137   }
1138 
1139   if(!err && curlx_dyn_addn(&config->postdata, postdata, size))
1140     err = PARAM_NO_MEM;
1141 
1142   Curl_safefree(postdata);
1143 
1144   config->postfields = curlx_dyn_ptr(&config->postdata);
1145   return err;
1146 }
1147 
set_rate(struct GlobalConfig * global,char * nextarg)1148 static ParameterError set_rate(struct GlobalConfig *global,
1149                                char *nextarg)
1150 {
1151   /* --rate */
1152   /* support a few different suffixes, extract the suffix first, then
1153      get the number and convert to per hour.
1154      /s == per second
1155      /m == per minute
1156      /h == per hour (default)
1157      /d == per day (24 hours)
1158   */
1159   ParameterError err = PARAM_OK;
1160   char *div = strchr(nextarg, '/');
1161   char number[26];
1162   long denominator;
1163   long numerator = 60*60*1000; /* default per hour */
1164   size_t numlen = div ? (size_t)(div - nextarg) : strlen(nextarg);
1165   if(numlen > sizeof(number) -1)
1166     return PARAM_NUMBER_TOO_LARGE;
1167 
1168   strncpy(number, nextarg, numlen);
1169   number[numlen] = 0;
1170   err = str2unum(&denominator, number);
1171   if(err)
1172     return err;
1173 
1174   if(denominator < 1)
1175     return PARAM_BAD_USE;
1176 
1177   if(div) {
1178     char unit = div[1];
1179     switch(unit) {
1180     case 's': /* per second */
1181       numerator = 1000;
1182       break;
1183     case 'm': /* per minute */
1184       numerator = 60*1000;
1185       break;
1186     case 'h': /* per hour */
1187       break;
1188     case 'd': /* per day */
1189       numerator = 24*60*60*1000;
1190       break;
1191     default:
1192       errorf(global, "unsupported --rate unit");
1193       err = PARAM_BAD_USE;
1194       break;
1195     }
1196   }
1197 
1198   if(err)
1199     ;
1200   else if(denominator > numerator)
1201     err = PARAM_NUMBER_TOO_LARGE;
1202   else
1203     global->ms_per_transfer = numerator/denominator;
1204 
1205   return err;
1206 }
1207 
1208 
getparameter(const char * flag,char * nextarg,argv_item_t cleararg,bool * usedarg,struct GlobalConfig * global,struct OperationConfig * config)1209 ParameterError getparameter(const char *flag, /* f or -long-flag */
1210                             char *nextarg,    /* NULL if unset */
1211                             argv_item_t cleararg,
1212                             bool *usedarg,    /* set to TRUE if the arg
1213                                                  has been used */
1214                             struct GlobalConfig *global,
1215                             struct OperationConfig *config)
1216 {
1217   int rc;
1218   const char *parse = NULL;
1219   time_t now;
1220   bool longopt = FALSE;
1221   bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
1222   ParameterError err = PARAM_OK;
1223   bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
1224                          by using --OPTION or --no-OPTION */
1225   bool nextalloc = FALSE; /* if nextarg is allocated */
1226   struct getout *url;
1227   static const char *redir_protos[] = {
1228     "http",
1229     "https",
1230     "ftp",
1231     "ftps",
1232     NULL
1233   };
1234   const struct LongShort *a = NULL;
1235   curl_off_t value;
1236 #ifdef HAVE_WRITABLE_ARGV
1237   argv_item_t clearthis = NULL;
1238 #else
1239   (void)cleararg;
1240 #endif
1241 
1242   *usedarg = FALSE; /* default is that we don't use the arg */
1243 
1244   if(('-' != flag[0]) || ('-' == flag[1])) {
1245     /* this should be a long name */
1246     const char *word = ('-' == flag[0]) ? flag + 2 : flag;
1247     bool noflagged = FALSE;
1248     bool expand = FALSE;
1249     struct LongShort key;
1250 
1251     if(!strncmp(word, "no-", 3)) {
1252       /* disable this option but ignore the "no-" part when looking for it */
1253       word += 3;
1254       toggle = FALSE;
1255       noflagged = TRUE;
1256     }
1257     else if(!strncmp(word, "expand-", 7)) {
1258       /* variable expansions is to be done on the argument */
1259       word += 7;
1260       expand = TRUE;
1261     }
1262     key.lname = word;
1263 
1264     a = bsearch(&key, aliases, sizeof(aliases)/sizeof(aliases[0]),
1265                 sizeof(aliases[0]), findarg);
1266     if(a) {
1267       longopt = TRUE;
1268     }
1269     else {
1270       err = PARAM_OPTION_UNKNOWN;
1271       goto error;
1272     }
1273     if(noflagged && (a->desc != ARG_BOOL)) {
1274       /* --no- prefixed an option that isn't boolean! */
1275       err = PARAM_NO_NOT_BOOLEAN;
1276       goto error;
1277     }
1278     else if(expand && nextarg) {
1279       struct curlx_dynbuf nbuf;
1280       bool replaced;
1281 
1282       if((a->desc != ARG_STRG) &&
1283          (a->desc != ARG_FILE)) {
1284         /* --expand on an option that isn't a string or a filename */
1285         err = PARAM_EXPAND_ERROR;
1286         goto error;
1287       }
1288       err = varexpand(global, nextarg, &nbuf, &replaced);
1289       if(err) {
1290         curlx_dyn_free(&nbuf);
1291         goto error;
1292       }
1293       if(replaced) {
1294         nextarg = curlx_dyn_ptr(&nbuf);
1295         nextalloc = TRUE;
1296       }
1297     }
1298   }
1299   else {
1300     flag++; /* prefixed with one dash, pass it */
1301     parse = flag;
1302   }
1303 
1304   do {
1305     /* we can loop here if we have multiple single-letters */
1306     char letter;
1307     cmdline_t cmd;
1308 
1309     if(!longopt && !a) {
1310       a = single(*parse);
1311       if(!a) {
1312         err = PARAM_OPTION_UNKNOWN;
1313         break;
1314       }
1315     }
1316     letter = a->letter;
1317     cmd = a->cmd;
1318     if(a->desc >= ARG_STRG) {
1319       /* this option requires an extra parameter */
1320       if(!longopt && parse[1]) {
1321         nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
1322         singleopt = TRUE;   /* don't loop anymore after this */
1323       }
1324       else if(!nextarg) {
1325         err = PARAM_REQUIRES_PARAMETER;
1326         break;
1327       }
1328       else {
1329 #ifdef HAVE_WRITABLE_ARGV
1330         clearthis = cleararg;
1331 #endif
1332         *usedarg = TRUE; /* mark it as used */
1333       }
1334 
1335       if((a->desc == ARG_FILE) &&
1336          (nextarg[0] == '-') && nextarg[1]) {
1337         /* if the file name looks like a command line option */
1338         warnf(global, "The file name argument '%s' looks like a flag.",
1339               nextarg);
1340       }
1341       else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) {
1342         warnf(global, "The argument '%s' starts with a unicode quote where "
1343               "maybe an ASCII \" was intended?",
1344               nextarg);
1345       }
1346     }
1347     else if((a->desc == ARG_NONE) && !toggle) {
1348       err = PARAM_NO_PREFIX;
1349       break;
1350     }
1351 
1352     if(!nextarg)
1353       /* this is a precaution mostly to please scan-build, as all arguments
1354          that use nextarg should be marked as such and they will check that
1355          nextarg is set before continuing, but code analyzers are not always
1356          that aware of that state */
1357       nextarg = (char *)"";
1358 
1359     switch(cmd) {
1360     case C_RANDOM_FILE: /* --random-file */
1361     case C_EGD_FILE: /* --egd-file */
1362     case C_NTLM_WB: /* --ntlm-wb */
1363       warnf(global, "--%s is deprecated and has no function anymore",
1364             a->lname);
1365       break;
1366     case C_DNS_IPV4_ADDR: /* --dns-ipv4-addr */
1367       if(!curlinfo->ares_num) /* c-ares is needed for this */
1368         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1369       else
1370         /* addr in dot notation */
1371         err = getstr(&config->dns_ipv4_addr, nextarg, DENY_BLANK);
1372       break;
1373     case C_DNS_IPV6_ADDR: /* --dns-ipv6-addr */
1374       if(!curlinfo->ares_num) /* c-ares is needed for this */
1375         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1376       else
1377         /* addr in dot notation */
1378         err = getstr(&config->dns_ipv6_addr, nextarg, DENY_BLANK);
1379       break;
1380     case C_OAUTH2_BEARER: /* --oauth2-bearer */
1381       err = getstr(&config->oauth_bearer, nextarg, DENY_BLANK);
1382       if(!err) {
1383         cleanarg(clearthis);
1384         config->authtype |= CURLAUTH_BEARER;
1385       }
1386       break;
1387     case C_CONNECT_TIMEOUT: /* --connect-timeout */
1388       err = secs2ms(&config->connecttimeout_ms, nextarg);
1389       break;
1390     case C_DOH_URL: /* --doh-url */
1391       err = getstr(&config->doh_url, nextarg, ALLOW_BLANK);
1392       if(!err && config->doh_url && !config->doh_url[0])
1393         /* if given a blank string, make it NULL again */
1394         Curl_safefree(config->doh_url);
1395       break;
1396     case C_CIPHERS: /* -- ciphers */
1397       err = getstr(&config->cipher_list, nextarg, DENY_BLANK);
1398       break;
1399     case C_DNS_INTERFACE: /* --dns-interface */
1400       if(!curlinfo->ares_num) /* c-ares is needed for this */
1401         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1402       else
1403         /* interface name */
1404         err = getstr(&config->dns_interface, nextarg, DENY_BLANK);
1405       break;
1406     case C_DISABLE_EPSV: /* --disable-epsv */
1407       config->disable_epsv = toggle;
1408       break;
1409     case C_DISALLOW_USERNAME_IN_URL: /* --disallow-username-in-url */
1410       config->disallow_username_in_url = toggle;
1411       break;
1412     case C_EPSV: /* --epsv */
1413       config->disable_epsv = (!toggle)?TRUE:FALSE;
1414       break;
1415     case C_DNS_SERVERS: /* --dns-servers */
1416       if(!curlinfo->ares_num) /* c-ares is needed for this */
1417         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1418       else
1419         /* IP addrs of DNS servers */
1420         err = getstr(&config->dns_servers, nextarg, DENY_BLANK);
1421       break;
1422     case C_TRACE: /* --trace */
1423       err = getstr(&global->trace_dump, nextarg, DENY_BLANK);
1424       if(!err) {
1425         if(global->tracetype && (global->tracetype != TRACE_BIN))
1426           warnf(global, "--trace overrides an earlier trace/verbose option");
1427         global->tracetype = TRACE_BIN;
1428       }
1429       break;
1430     case C_NPN: /* --npn */
1431       warnf(global, "--npn is no longer supported");
1432       break;
1433     case C_TRACE_ASCII: /* --trace-ascii */
1434       err = getstr(&global->trace_dump, nextarg, DENY_BLANK);
1435       if(!err) {
1436         if(global->tracetype && (global->tracetype != TRACE_ASCII))
1437           warnf(global,
1438                 "--trace-ascii overrides an earlier trace/verbose option");
1439         global->tracetype = TRACE_ASCII;
1440       }
1441       break;
1442     case C_ALPN: /* --alpn */
1443       config->noalpn = (!toggle)?TRUE:FALSE;
1444       break;
1445     case C_LIMIT_RATE: /* --limit-rate */
1446       err = GetSizeParameter(global, nextarg, "rate", &value);
1447       if(!err) {
1448         config->recvpersecond = value;
1449         config->sendpersecond = value;
1450       }
1451       break;
1452     case C_RATE:
1453       err = set_rate(global, nextarg);
1454       break;
1455     case C_COMPRESSED: /* --compressed */
1456       if(toggle && !(feature_libz || feature_brotli || feature_zstd))
1457         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1458       else
1459         config->encoding = toggle;
1460       break;
1461     case C_TR_ENCODING: /* --tr-encoding */
1462       config->tr_encoding = toggle;
1463       break;
1464     case C_DIGEST: /* --digest */
1465       if(toggle)
1466         config->authtype |= CURLAUTH_DIGEST;
1467       else
1468         config->authtype &= ~CURLAUTH_DIGEST;
1469       break;
1470     case C_NEGOTIATE: /* --negotiate */
1471       if(!toggle)
1472         config->authtype &= ~CURLAUTH_NEGOTIATE;
1473       else if(feature_spnego)
1474         config->authtype |= CURLAUTH_NEGOTIATE;
1475       else
1476         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1477       break;
1478     case C_NTLM: /* --ntlm */
1479       if(!toggle)
1480         config->authtype &= ~CURLAUTH_NTLM;
1481       else if(feature_ntlm)
1482         config->authtype |= CURLAUTH_NTLM;
1483       else
1484         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1485       break;
1486     case C_BASIC: /* --basic */
1487       if(toggle)
1488         config->authtype |= CURLAUTH_BASIC;
1489       else
1490         config->authtype &= ~CURLAUTH_BASIC;
1491       break;
1492     case C_ANYAUTH: /* --anyauth */
1493       if(toggle)
1494         config->authtype = CURLAUTH_ANY;
1495       /* --no-anyauth simply doesn't touch it */
1496       break;
1497 #ifdef USE_WATT32
1498     case C_WDEBUG: /* --wdebug */
1499       dbug_init();
1500       break;
1501 #endif
1502     case C_FTP_CREATE_DIRS: /* --ftp-create-dirs */
1503       config->ftp_create_dirs = toggle;
1504       break;
1505     case C_CREATE_DIRS: /* --create-dirs */
1506       config->create_dirs = toggle;
1507       break;
1508     case C_CREATE_FILE_MODE: /* --create-file-mode */
1509       err = oct2nummax(&config->create_file_mode, nextarg, 0777);
1510       break;
1511     case C_MAX_REDIRS: /* --max-redirs */
1512       /* specified max no of redirects (http(s)), this accepts -1 as a
1513          special condition */
1514       err = str2num(&config->maxredirs, nextarg);
1515       if(!err && (config->maxredirs < -1))
1516         err = PARAM_BAD_NUMERIC;
1517       break;
1518     case C_IPFS_GATEWAY: /* --ipfs-gateway */
1519       err = getstr(&config->ipfs_gateway, nextarg, DENY_BLANK);
1520       break;
1521     case C_PROXY_NTLM: /* --proxy-ntlm */
1522       if(!feature_ntlm)
1523         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1524       else
1525         config->proxyntlm = toggle;
1526       break;
1527     case C_CRLF: /* --crlf */
1528       /* LF -> CRLF conversion? */
1529       config->crlf = toggle;
1530       break;
1531     case C_AWS_SIGV4: /* --aws-sigv4 */
1532       config->authtype |= CURLAUTH_AWS_SIGV4;
1533       err = getstr(&config->aws_sigv4, nextarg, DENY_BLANK);
1534       break;
1535     case C_STDERR: /* --stderr */
1536       tool_set_stderr_file(global, nextarg);
1537       break;
1538     case C_INTERFACE: /* --interface */
1539       /* interface */
1540       err = getstr(&config->iface, nextarg, DENY_BLANK);
1541       break;
1542     case C_KRB: /* --krb */
1543       /* kerberos level string */
1544       if(!feature_spnego)
1545         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1546       else
1547         err = getstr(&config->krblevel, nextarg, DENY_BLANK);
1548       break;
1549     case C_HAPROXY_PROTOCOL: /* --haproxy-protocol */
1550       config->haproxy_protocol = toggle;
1551       break;
1552     case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */
1553       err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK);
1554       break;
1555     case C_MAX_FILESIZE: /* --max-filesize */
1556       err = GetSizeParameter(global, nextarg, "max-filesize", &value);
1557       if(!err)
1558         config->max_filesize = value;
1559       break;
1560     case C_DISABLE_EPRT: /* --disable-eprt */
1561       config->disable_eprt = toggle;
1562       break;
1563     case C_EPRT: /* --eprt */
1564       config->disable_eprt = (!toggle)?TRUE:FALSE;
1565       break;
1566     case C_XATTR: /* --xattr */
1567       config->xattr = toggle;
1568       break;
1569     case C_URL: /* --url */
1570       if(!config->url_get)
1571         config->url_get = config->url_list;
1572 
1573       if(config->url_get) {
1574         /* there's a node here, if it already is filled-in continue to find
1575            an "empty" node */
1576         while(config->url_get && (config->url_get->flags & GETOUT_URL))
1577           config->url_get = config->url_get->next;
1578       }
1579 
1580       /* now there might or might not be an available node to fill in! */
1581 
1582       if(config->url_get)
1583         /* existing node */
1584         url = config->url_get;
1585       else
1586         /* there was no free node, create one! */
1587         config->url_get = url = new_getout(config);
1588 
1589       if(!url)
1590         err = PARAM_NO_MEM;
1591       else {
1592         /* fill in the URL */
1593         err = getstr(&url->url, nextarg, DENY_BLANK);
1594         url->flags |= GETOUT_URL;
1595       }
1596       break;
1597     case C_FTP_SSL: /* --ftp-ssl */
1598     case C_SSL: /* --ssl */
1599       if(toggle && !feature_ssl)
1600         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1601       else {
1602         config->ftp_ssl = toggle;
1603         if(config->ftp_ssl)
1604           warnf(global,
1605                 "--%s is an insecure option, consider --ssl-reqd instead",
1606                 a->lname);
1607       }
1608       break;
1609     case C_FTP_PASV: /* --ftp-pasv */
1610       Curl_safefree(config->ftpport);
1611       break;
1612     case C_SOCKS5: /* --socks5 */
1613       /*  socks5 proxy to use, and resolves the name locally and passes on the
1614           resolved address */
1615       err = getstr(&config->proxy, nextarg, DENY_BLANK);
1616       config->proxyver = CURLPROXY_SOCKS5;
1617       break;
1618     case C_SOCKS4: /* --socks4 */
1619       err = getstr(&config->proxy, nextarg, DENY_BLANK);
1620       config->proxyver = CURLPROXY_SOCKS4;
1621       break;
1622     case C_SOCKS4A: /* --socks4a */
1623       err = getstr(&config->proxy, nextarg, DENY_BLANK);
1624       config->proxyver = CURLPROXY_SOCKS4A;
1625       break;
1626     case C_SOCKS5_HOSTNAME: /* --socks5-hostname */
1627       err = getstr(&config->proxy, nextarg, DENY_BLANK);
1628       config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
1629       break;
1630     case C_TCP_NODELAY: /* --tcp-nodelay */
1631       config->tcp_nodelay = toggle;
1632       break;
1633     case C_PROXY_DIGEST: /* --proxy-digest */
1634       config->proxydigest = toggle;
1635       break;
1636     case C_PROXY_BASIC: /* --proxy-basic */
1637       config->proxybasic = toggle;
1638       break;
1639     case C_RETRY: /* --retry */
1640       err = str2unum(&config->req_retry, nextarg);
1641       break;
1642     case C_RETRY_CONNREFUSED: /* --retry-connrefused */
1643       config->retry_connrefused = toggle;
1644       break;
1645     case C_RETRY_DELAY: /* --retry-delay */
1646       err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000);
1647       break;
1648     case C_RETRY_MAX_TIME: /* --retry-max-time */
1649       err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000);
1650       break;
1651     case C_RETRY_ALL_ERRORS: /* --retry-all-errors */
1652       config->retry_all_errors = toggle;
1653       break;
1654     case C_PROXY_NEGOTIATE: /* --proxy-negotiate */
1655       if(!feature_spnego)
1656         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1657       else
1658         config->proxynegotiate = toggle;
1659       break;
1660     case C_FORM_ESCAPE: /* --form-escape */
1661       config->mime_options &= ~CURLMIMEOPT_FORMESCAPE;
1662       if(toggle)
1663         config->mime_options |= CURLMIMEOPT_FORMESCAPE;
1664       break;
1665     case C_FTP_ACCOUNT: /* --ftp-account */
1666       err = getstr(&config->ftp_account, nextarg, DENY_BLANK);
1667       break;
1668     case C_PROXY_ANYAUTH: /* --proxy-anyauth */
1669       config->proxyanyauth = toggle;
1670       break;
1671     case C_TRACE_TIME: /* --trace-time */
1672       global->tracetime = toggle;
1673       break;
1674     case C_IGNORE_CONTENT_LENGTH: /* --ignore-content-length */
1675       config->ignorecl = toggle;
1676       break;
1677     case C_FTP_SKIP_PASV_IP: /* --ftp-skip-pasv-ip */
1678       config->ftp_skip_ip = toggle;
1679       break;
1680     case C_FTP_METHOD: /* --ftp-method */
1681       config->ftp_filemethod = ftpfilemethod(config, nextarg);
1682       break;
1683     case C_LOCAL_PORT: { /* --local-port */
1684       /* 16bit base 10 is 5 digits, but we allow 6 so that this catches
1685          overflows, not just truncates */
1686       char lrange[7]="";
1687       char *p = nextarg;
1688       while(ISDIGIT(*p))
1689         p++;
1690       if(*p) {
1691         /* if there's anything more than a plain decimal number */
1692         rc = sscanf(p, " - %6s", lrange);
1693         *p = 0; /* null-terminate to make str2unum() work below */
1694       }
1695       else
1696         rc = 0;
1697 
1698       err = str2unum(&config->localport, nextarg);
1699       if(err || (config->localport > 65535)) {
1700         err = PARAM_BAD_USE;
1701         break;
1702       }
1703       if(!rc)
1704         config->localportrange = 1; /* default number of ports to try */
1705       else {
1706         err = str2unum(&config->localportrange, lrange);
1707         if(err || (config->localportrange > 65535))
1708           err = PARAM_BAD_USE;
1709         else {
1710           config->localportrange -= (config->localport-1);
1711           if(config->localportrange < 1)
1712             err = PARAM_BAD_USE;
1713         }
1714       }
1715       break;
1716     }
1717     case C_FTP_ALTERNATIVE_TO_USER: /* --ftp-alternative-to-user */
1718       err = getstr(&config->ftp_alternative_to_user, nextarg, DENY_BLANK);
1719       break;
1720     case C_FTP_SSL_REQD: /* --ftp-ssl-reqd */
1721     case C_SSL_REQD: /* --ssl-reqd */
1722       if(toggle && !feature_ssl) {
1723         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1724         break;
1725       }
1726       config->ftp_ssl_reqd = toggle;
1727       break;
1728     case C_SESSIONID: /* --sessionid */
1729       config->disable_sessionid = (!toggle)?TRUE:FALSE;
1730       break;
1731     case C_FTP_SSL_CONTROL: /* --ftp-ssl-control */
1732       if(toggle && !feature_ssl)
1733         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1734       else
1735         config->ftp_ssl_control = toggle;
1736       break;
1737     case C_FTP_SSL_CCC: /* --ftp-ssl-ccc */
1738       config->ftp_ssl_ccc = toggle;
1739       if(!config->ftp_ssl_ccc_mode)
1740         config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
1741       break;
1742     case C_FTP_SSL_CCC_MODE: /* --ftp-ssl-ccc-mode */
1743       config->ftp_ssl_ccc = TRUE;
1744       config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
1745       break;
1746     case C_LIBCURL: /* --libcurl */
1747 #ifdef CURL_DISABLE_LIBCURL_OPTION
1748       warnf(global,
1749             "--libcurl option was disabled at build-time");
1750       err = PARAM_OPTION_UNKNOWN;
1751 #else
1752       err = getstr(&global->libcurl, nextarg, DENY_BLANK);
1753 #endif
1754       break;
1755     case C_RAW: /* --raw */
1756       config->raw = toggle;
1757       break;
1758     case C_KEEPALIVE: /* --keepalive */
1759       config->nokeepalive = (!toggle)?TRUE:FALSE;
1760       break;
1761     case C_KEEPALIVE_TIME: /* --keepalive-time */
1762       err = str2unum(&config->alivetime, nextarg);
1763       break;
1764     case C_POST301: /* --post301 */
1765       config->post301 = toggle;
1766       break;
1767     case C_POST302: /* --post302 */
1768       config->post302 = toggle;
1769       break;
1770     case C_POST303: /* --post303 */
1771       config->post303 = toggle;
1772       break;
1773     case C_NOPROXY: /* --noproxy */
1774       /* This specifies the noproxy list */
1775       err = getstr(&config->noproxy, nextarg, ALLOW_BLANK);
1776       break;
1777     case C_SOCKS5_GSSAPI_NEC: /* --socks5-gssapi-nec */
1778       config->socks5_gssapi_nec = toggle;
1779       break;
1780     case C_PROXY1_0: /* --proxy1.0 */
1781       /* http 1.0 proxy */
1782       err = getstr(&config->proxy, nextarg, DENY_BLANK);
1783       config->proxyver = CURLPROXY_HTTP_1_0;
1784       break;
1785     case C_TFTP_BLKSIZE: /* --tftp-blksize */
1786       err = str2unum(&config->tftp_blksize, nextarg);
1787       break;
1788     case C_MAIL_FROM: /* --mail-from */
1789       err = getstr(&config->mail_from, nextarg, DENY_BLANK);
1790       break;
1791     case C_MAIL_RCPT: /* --mail-rcpt */
1792       /* append receiver to a list */
1793       err = add2list(&config->mail_rcpt, nextarg);
1794       break;
1795     case C_FTP_PRET: /* --ftp-pret */
1796       config->ftp_pret = toggle;
1797       break;
1798     case C_PROTO: /* --proto */
1799       config->proto_present = TRUE;
1800       err = proto2num(config, built_in_protos, &config->proto_str, nextarg);
1801       break;
1802     case C_PROTO_REDIR: /* --proto-redir */
1803       config->proto_redir_present = TRUE;
1804       if(proto2num(config, redir_protos, &config->proto_redir_str,
1805                    nextarg))
1806         err = PARAM_BAD_USE;
1807       break;
1808     case C_RESOLVE: /* --resolve */
1809       err = add2list(&config->resolve, nextarg);
1810       break;
1811     case C_DELEGATION: /* --delegation */
1812       config->gssapi_delegation = delegation(config, nextarg);
1813       break;
1814     case C_MAIL_AUTH: /* --mail-auth */
1815       err = getstr(&config->mail_auth, nextarg, DENY_BLANK);
1816       break;
1817     case C_METALINK: /* --metalink */
1818       errorf(global, "--metalink is disabled");
1819       err = PARAM_BAD_USE;
1820       break;
1821     case C_SASL_AUTHZID: /* --sasl-authzid */
1822       err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK);
1823       break;
1824     case C_SASL_IR: /* --sasl-ir */
1825       config->sasl_ir = toggle;
1826       break;
1827     case C_TEST_EVENT: /* --test-event */
1828 #ifdef CURLDEBUG
1829       global->test_event_based = toggle;
1830 #else
1831       warnf(global, "--test-event is ignored unless a debug build");
1832 #endif
1833       break;
1834     case C_UNIX_SOCKET: /* --unix-socket */
1835       config->abstract_unix_socket = FALSE;
1836       err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK);
1837       break;
1838     case C_PATH_AS_IS: /* --path-as-is */
1839       config->path_as_is = toggle;
1840       break;
1841     case C_PROXY_SERVICE_NAME: /* --proxy-service-name */
1842       err = getstr(&config->proxy_service_name, nextarg, DENY_BLANK);
1843       break;
1844     case C_SERVICE_NAME: /* --service-name */
1845       err = getstr(&config->service_name, nextarg, DENY_BLANK);
1846       break;
1847     case C_PROTO_DEFAULT: /* --proto-default */
1848       err = getstr(&config->proto_default, nextarg, DENY_BLANK);
1849       if(!err)
1850         err = check_protocol(config->proto_default);
1851       break;
1852     case C_EXPECT100_TIMEOUT: /* --expect100-timeout */
1853       err = secs2ms(&config->expect100timeout_ms, nextarg);
1854       break;
1855     case C_TFTP_NO_OPTIONS: /* --tftp-no-options */
1856       config->tftp_no_options = toggle;
1857       break;
1858     case C_CONNECT_TO: /* --connect-to */
1859       err = add2list(&config->connect_to, nextarg);
1860       break;
1861     case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */
1862       config->abstract_unix_socket = TRUE;
1863       err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK);
1864       break;
1865     case C_TLS_MAX: /* --tls-max */
1866       err = str2tls_max(&config->ssl_version_max, nextarg);
1867       break;
1868     case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */
1869       config->suppress_connect_headers = toggle;
1870       break;
1871     case C_COMPRESSED_SSH: /* --compressed-ssh */
1872       config->ssh_compression = toggle;
1873       break;
1874     case C_HAPPY_EYEBALLS_TIMEOUT_MS: /* --happy-eyeballs-timeout-ms */
1875       err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg);
1876       /* 0 is a valid value for this timeout */
1877       break;
1878     case C_TRACE_IDS: /* --trace-ids */
1879       global->traceids = toggle;
1880       break;
1881     case C_TRACE_CONFIG: /* --trace-config */
1882       if(set_trace_config(global, nextarg))
1883         err = PARAM_NO_MEM;
1884       break;
1885     case C_PROGRESS_METER: /* --progress-meter */
1886       global->noprogress = !toggle;
1887       break;
1888     case C_PROGRESS_BAR: /* --progress-bar */
1889       global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS;
1890       break;
1891     case C_VARIABLE: /* --Variable */
1892       err = setvariable(global, nextarg);
1893       break;
1894     case C_NEXT: /* --next */
1895       err = PARAM_NEXT_OPERATION;
1896       break;
1897     case C_HTTP1_0: /* --http1.0 */
1898       /* HTTP version 1.0 */
1899       sethttpver(global, config, CURL_HTTP_VERSION_1_0);
1900       break;
1901     case C_HTTP1_1: /* --http1.1 */
1902       /* HTTP version 1.1 */
1903       sethttpver(global, config, CURL_HTTP_VERSION_1_1);
1904       break;
1905     case C_HTTP2: /* --http2 */
1906       /* HTTP version 2.0 */
1907       if(!feature_http2)
1908         return PARAM_LIBCURL_DOESNT_SUPPORT;
1909       sethttpver(global, config, CURL_HTTP_VERSION_2_0);
1910       break;
1911     case C_HTTP2_PRIOR_KNOWLEDGE: /* --http2-prior-knowledge */
1912       /* HTTP version 2.0 over clean TCP */
1913       if(!feature_http2)
1914         return PARAM_LIBCURL_DOESNT_SUPPORT;
1915       sethttpver(global, config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
1916       break;
1917     case C_HTTP3: /* --http3: */
1918       /* Try HTTP/3, allow fallback */
1919       if(!feature_http3)
1920         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1921       else
1922         sethttpver(global, config, CURL_HTTP_VERSION_3);
1923       break;
1924     case C_HTTP3_ONLY: /* --http3-only */
1925       /* Try HTTP/3 without fallback */
1926       if(!feature_http3)
1927         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1928       else
1929         sethttpver(global, config, CURL_HTTP_VERSION_3ONLY);
1930       break;
1931     case C_HTTP0_9: /* --http0.9 */
1932       /* Allow HTTP/0.9 responses! */
1933       config->http09_allowed = toggle;
1934       break;
1935     case C_PROXY_HTTP2: /* --proxy-http2 */
1936       if(!feature_httpsproxy || !feature_http2)
1937         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1938       else
1939         config->proxyver = CURLPROXY_HTTPS2;
1940       break;
1941     case C_TLSV1: /* --tlsv1 */
1942       config->ssl_version = CURL_SSLVERSION_TLSv1;
1943       break;
1944     case C_TLSV1_0: /* --tlsv1.0 */
1945       config->ssl_version = CURL_SSLVERSION_TLSv1_0;
1946       break;
1947     case C_TLSV1_1: /* --tlsv1.1 */
1948       config->ssl_version = CURL_SSLVERSION_TLSv1_1;
1949       break;
1950     case C_TLSV1_2: /* --tlsv1.2 */
1951       config->ssl_version = CURL_SSLVERSION_TLSv1_2;
1952       break;
1953     case C_TLSV1_3: /* --tlsv1.3 */
1954       config->ssl_version = CURL_SSLVERSION_TLSv1_3;
1955       break;
1956     case C_TLS13_CIPHERS: /* --tls13-ciphers */
1957       err = getstr(&config->cipher13_list, nextarg, DENY_BLANK);
1958       break;
1959     case C_PROXY_TLS13_CIPHERS: /* --proxy-tls13-ciphers */
1960       err = getstr(&config->proxy_cipher13_list, nextarg, DENY_BLANK);
1961       break;
1962     case C_SSLV2: /* --sslv2 */
1963       warnf(global, "Ignores instruction to use SSLv2");
1964       break;
1965     case C_SSLV3: /* --sslv3 */
1966       warnf(global, "Ignores instruction to use SSLv3");
1967       break;
1968     case C_IPV4: /* --ipv4 */
1969       config->ip_version = CURL_IPRESOLVE_V4;
1970       break;
1971     case C_IPV6: /* --ipv6 */
1972       config->ip_version = CURL_IPRESOLVE_V6;
1973       break;
1974     case C_APPEND: /* --append */
1975       /* This makes the FTP sessions use APPE instead of STOR */
1976       config->ftp_append = toggle;
1977       break;
1978     case C_USER_AGENT: /* --user-agent */
1979       err = getstr(&config->useragent, nextarg, ALLOW_BLANK);
1980       break;
1981     case C_ALT_SVC: /* --alt-svc */
1982       if(!feature_altsvc)
1983         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1984       else
1985         err = getstr(&config->altsvc, nextarg, ALLOW_BLANK);
1986       break;
1987     case C_HSTS: /* --hsts */
1988       if(!feature_hsts)
1989         err = PARAM_LIBCURL_DOESNT_SUPPORT;
1990       else
1991         err = getstr(&config->hsts, nextarg, ALLOW_BLANK);
1992       break;
1993     case C_COOKIE: /* --cookie */
1994       if(strchr(nextarg, '=')) {
1995         /* A cookie string must have a =-letter */
1996         err = add2list(&config->cookies, nextarg);
1997         break;
1998       }
1999       else {
2000         /* We have a cookie file to read from! */
2001         err = add2list(&config->cookiefiles, nextarg);
2002       }
2003       break;
2004     case C_USE_ASCII: /* --use-ascii */
2005       config->use_ascii = toggle;
2006       break;
2007     case C_COOKIE_JAR: /* --cookie-jar */
2008       err = getstr(&config->cookiejar, nextarg, DENY_BLANK);
2009       break;
2010     case C_CONTINUE_AT: /* --continue-at */
2011       /* This makes us continue an ftp transfer at given position */
2012       if(strcmp(nextarg, "-")) {
2013         err = str2offset(&config->resume_from, nextarg);
2014         config->resume_from_current = FALSE;
2015       }
2016       else {
2017         config->resume_from_current = TRUE;
2018         config->resume_from = 0;
2019       }
2020       config->use_resume = TRUE;
2021       break;
2022     case C_DATA: /* --data */
2023     case C_DATA_ASCII:  /* --data-ascii */
2024     case C_DATA_BINARY:  /* --data-binary */
2025     case C_DATA_URLENCODE:  /* --data-urlencode */
2026     case C_JSON:  /* --json */
2027     case C_DATA_RAW:  /* --data-raw */
2028       err = set_data(cmd, nextarg, global, config);
2029       break;
2030     case C_URL_QUERY:  /* --url-query */
2031       err = url_query(nextarg, global, config);
2032       break;
2033     case C_DUMP_HEADER: /* --dump-header */
2034       err = getstr(&config->headerfile, nextarg, DENY_BLANK);
2035       break;
2036     case C_REFERER: { /* --referer */
2037       char *ptr = strstr(nextarg, ";auto");
2038       if(ptr) {
2039         /* Automatic referer requested, this may be combined with a
2040            set initial one */
2041         config->autoreferer = TRUE;
2042         *ptr = 0; /* null-terminate here */
2043       }
2044       else
2045         config->autoreferer = FALSE;
2046       ptr = *nextarg ? nextarg : NULL;
2047       err = getstr(&config->referer, ptr, ALLOW_BLANK);
2048     }
2049       break;
2050     case C_CERT: /* --cert */
2051       cleanarg(clearthis);
2052       GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
2053       break;
2054     case C_CACERT: /* --cacert */
2055       err = getstr(&config->cacert, nextarg, DENY_BLANK);
2056       break;
2057     case C_CA_NATIVE: /* --ca-native */
2058       config->native_ca_store = toggle;
2059       break;
2060     case C_PROXY_CA_NATIVE: /* --proxy-ca-native */
2061       config->proxy_native_ca_store = toggle;
2062       break;
2063     case C_CERT_TYPE: /* --cert-type */
2064       err = getstr(&config->cert_type, nextarg, DENY_BLANK);
2065       break;
2066     case C_KEY: /* --key */
2067       err = getstr(&config->key, nextarg, DENY_BLANK);
2068       break;
2069     case C_KEY_TYPE: /* --key-type */
2070       err = getstr(&config->key_type, nextarg, DENY_BLANK);
2071       break;
2072     case C_PASS: /* --pass */
2073       err = getstr(&config->key_passwd, nextarg, DENY_BLANK);
2074       cleanarg(clearthis);
2075       break;
2076     case C_ENGINE: /* --engine */
2077       err = getstr(&config->engine, nextarg, DENY_BLANK);
2078       if(!err &&
2079          config->engine && !strcmp(config->engine, "list")) {
2080         err = PARAM_ENGINES_REQUESTED;
2081       }
2082       break;
2083 #ifndef USE_ECH
2084     case C_ECH: /* --ech, not implemented by default */
2085       err = PARAM_LIBCURL_DOESNT_SUPPORT;
2086       break;
2087 #else
2088     case C_ECH: /* --ech */
2089       if(strlen(nextarg) > 4 && strncasecompare("pn:", nextarg, 3)) {
2090         /* a public_name */
2091         err = getstr(&config->ech_public, nextarg, DENY_BLANK);
2092       }
2093       else if(strlen(nextarg) > 5 && strncasecompare("ecl:", nextarg, 4)) {
2094         /* an ECHConfigList */
2095         if('@' != *(nextarg + 4)) {
2096           err = getstr(&config->ech_config, nextarg, DENY_BLANK);
2097         }
2098         else {
2099           /* Indirect case: @filename or @- for stdin */
2100           char *tmpcfg = NULL;
2101           FILE *file;
2102 
2103           nextarg++;        /* skip over '@' */
2104           if(!strcmp("-", nextarg)) {
2105             file = stdin;
2106           }
2107           else {
2108             file = fopen(nextarg, FOPEN_READTEXT);
2109           }
2110           if(!file) {
2111             warnf(global,
2112                   "Couldn't read file \"%s\" "
2113                   "specified for \"--ech ecl:\" option",
2114                   nextarg);
2115             return PARAM_BAD_USE; /*  */
2116           }
2117           err = file2string(&tmpcfg, file);
2118           if(file != stdin)
2119             fclose(file);
2120           if(err)
2121             return err;
2122           config->ech_config = aprintf("ecl:%s",tmpcfg);
2123           if(!config->ech_config)
2124             return PARAM_NO_MEM;
2125           free(tmpcfg);
2126       } /* file done */
2127     }
2128     else {
2129       /* Simple case: just a string, with a keyword */
2130       err = getstr(&config->ech, nextarg, DENY_BLANK);
2131     }
2132     break;
2133 #endif
2134     case C_CAPATH: /* --capath */
2135       err = getstr(&config->capath, nextarg, DENY_BLANK);
2136       break;
2137     case C_PUBKEY: /* --pubkey */
2138       err = getstr(&config->pubkey, nextarg, DENY_BLANK);
2139       break;
2140     case C_HOSTPUBMD5: /* --hostpubmd5 */
2141       err = getstr(&config->hostpubmd5, nextarg, DENY_BLANK);
2142       if(!err) {
2143         if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
2144           err = PARAM_BAD_USE;
2145       }
2146       break;
2147     case C_HOSTPUBSHA256: /* --hostpubsha256 */
2148       err = getstr(&config->hostpubsha256, nextarg, DENY_BLANK);
2149       break;
2150     case C_CRLFILE: /* --crlfile */
2151       err = getstr(&config->crlfile, nextarg, DENY_BLANK);
2152       break;
2153     case C_TLSUSER: /* --tlsuser */
2154       if(!feature_tls_srp)
2155         err = PARAM_LIBCURL_DOESNT_SUPPORT;
2156       else
2157         err = getstr(&config->tls_username, nextarg, DENY_BLANK);
2158       cleanarg(clearthis);
2159       break;
2160     case C_TLSPASSWORD: /* --tlspassword */
2161       if(!feature_tls_srp)
2162         err = PARAM_LIBCURL_DOESNT_SUPPORT;
2163       else
2164         err = getstr(&config->tls_password, nextarg, ALLOW_BLANK);
2165       cleanarg(clearthis);
2166       break;
2167     case C_TLSAUTHTYPE: /* --tlsauthtype */
2168       if(!feature_tls_srp)
2169         err = PARAM_LIBCURL_DOESNT_SUPPORT;
2170       else {
2171         err = getstr(&config->tls_authtype, nextarg, DENY_BLANK);
2172         if(!err && strcmp(config->tls_authtype, "SRP"))
2173           err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
2174       }
2175       break;
2176     case C_SSL_ALLOW_BEAST: /* --ssl-allow-beast */
2177       if(feature_ssl)
2178         config->ssl_allow_beast = toggle;
2179       break;
2180     case C_SSL_AUTO_CLIENT_CERT: /* --ssl-auto-client-cert */
2181       if(feature_ssl)
2182         config->ssl_auto_client_cert = toggle;
2183       break;
2184     case C_PROXY_SSL_AUTO_CLIENT_CERT: /* --proxy-ssl-auto-client-cert */
2185       if(feature_ssl)
2186         config->proxy_ssl_auto_client_cert = toggle;
2187       break;
2188     case C_PINNEDPUBKEY: /* --pinnedpubkey */
2189       err = getstr(&config->pinnedpubkey, nextarg, DENY_BLANK);
2190       break;
2191     case C_PROXY_PINNEDPUBKEY: /* --proxy-pinnedpubkey */
2192       err = getstr(&config->proxy_pinnedpubkey, nextarg, DENY_BLANK);
2193       break;
2194     case C_CERT_STATUS: /* --cert-status */
2195       config->verifystatus = TRUE;
2196       break;
2197     case C_DOH_CERT_STATUS: /* --doh-cert-status */
2198       config->doh_verifystatus = TRUE;
2199       break;
2200     case C_FALSE_START: /* --false-start */
2201       config->falsestart = TRUE;
2202       break;
2203     case C_SSL_NO_REVOKE: /* --ssl-no-revoke */
2204       if(feature_ssl)
2205         config->ssl_no_revoke = TRUE;
2206       break;
2207     case C_SSL_REVOKE_BEST_EFFORT: /* --ssl-revoke-best-effort */
2208       if(feature_ssl)
2209         config->ssl_revoke_best_effort = TRUE;
2210       break;
2211     case C_TCP_FASTOPEN: /* --tcp-fastopen */
2212       config->tcp_fastopen = TRUE;
2213       break;
2214     case C_PROXY_TLSUSER: /* --proxy-tlsuser */
2215       cleanarg(clearthis);
2216       if(!feature_tls_srp)
2217         err = PARAM_LIBCURL_DOESNT_SUPPORT;
2218       else
2219         err = getstr(&config->proxy_tls_username, nextarg, ALLOW_BLANK);
2220       break;
2221     case C_PROXY_TLSPASSWORD: /* --proxy-tlspassword */
2222       cleanarg(clearthis);
2223       if(!feature_tls_srp)
2224         err = PARAM_LIBCURL_DOESNT_SUPPORT;
2225       else
2226         err = getstr(&config->proxy_tls_password, nextarg, DENY_BLANK);
2227       break;
2228     case C_PROXY_TLSAUTHTYPE: /* --proxy-tlsauthtype */
2229       if(!feature_tls_srp)
2230         err = PARAM_LIBCURL_DOESNT_SUPPORT;
2231       else {
2232         err = getstr(&config->proxy_tls_authtype, nextarg, DENY_BLANK);
2233         if(!err && strcmp(config->proxy_tls_authtype, "SRP"))
2234           err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
2235       }
2236       break;
2237     case C_PROXY_CERT: /* --proxy-cert */
2238       cleanarg(clearthis);
2239       GetFileAndPassword(nextarg, &config->proxy_cert,
2240                          &config->proxy_key_passwd);
2241       break;
2242     case C_PROXY_CERT_TYPE: /* --proxy-cert-type */
2243       err = getstr(&config->proxy_cert_type, nextarg, DENY_BLANK);
2244       break;
2245     case C_PROXY_KEY: /* --proxy-key */
2246       err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK);
2247       break;
2248     case C_PROXY_KEY_TYPE: /* --proxy-key-type */
2249       err = getstr(&config->proxy_key_type, nextarg, DENY_BLANK);
2250       break;
2251     case C_PROXY_PASS: /* --proxy-pass */
2252       err = getstr(&config->proxy_key_passwd, nextarg, ALLOW_BLANK);
2253       cleanarg(clearthis);
2254       break;
2255     case C_PROXY_CIPHERS: /* --proxy-ciphers */
2256       err = getstr(&config->proxy_cipher_list, nextarg, DENY_BLANK);
2257       break;
2258     case C_PROXY_CRLFILE: /* --proxy-crlfile */
2259       err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK);
2260       break;
2261     case C_PROXY_SSL_ALLOW_BEAST: /* --proxy-ssl-allow-beast */
2262       if(feature_ssl)
2263         config->proxy_ssl_allow_beast = toggle;
2264       break;
2265     case C_LOGIN_OPTIONS: /* --login-options */
2266       err = getstr(&config->login_options, nextarg, ALLOW_BLANK);
2267       break;
2268     case C_PROXY_CACERT: /* --proxy-cacert */
2269       err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK);
2270       break;
2271     case C_PROXY_CAPATH: /* --proxy-capath */
2272       err = getstr(&config->proxy_capath, nextarg, DENY_BLANK);
2273       break;
2274     case C_PROXY_INSECURE: /* --proxy-insecure */
2275       config->proxy_insecure_ok = toggle;
2276       break;
2277     case C_PROXY_TLSV1: /* --proxy-tlsv1 */
2278       /* TLS version 1 for proxy */
2279       config->proxy_ssl_version = CURL_SSLVERSION_TLSv1;
2280       break;
2281     case C_SOCKS5_BASIC: /* --socks5-basic */
2282       if(toggle)
2283         config->socks5_auth |= CURLAUTH_BASIC;
2284       else
2285         config->socks5_auth &= ~CURLAUTH_BASIC;
2286       break;
2287     case C_SOCKS5_GSSAPI: /* --socks5-gssapi */
2288       if(toggle)
2289         config->socks5_auth |= CURLAUTH_GSSAPI;
2290       else
2291         config->socks5_auth &= ~CURLAUTH_GSSAPI;
2292       break;
2293     case C_ETAG_SAVE: /* --etag-save */
2294       err = getstr(&config->etag_save_file, nextarg, DENY_BLANK);
2295       break;
2296     case C_ETAG_COMPARE: /* --etag-compare */
2297       err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK);
2298       break;
2299     case C_CURVES: /* --curves */
2300       err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK);
2301       break;
2302     case C_FAIL_EARLY: /* --fail-early */
2303       global->fail_early = toggle;
2304       break;
2305     case C_STYLED_OUTPUT: /* --styled-output */
2306       global->styled_output = toggle;
2307       break;
2308     case C_MAIL_RCPT_ALLOWFAILS: /* --mail-rcpt-allowfails */
2309       config->mail_rcpt_allowfails = toggle;
2310       break;
2311     case C_FAIL_WITH_BODY: /* --fail-with-body */
2312       config->failwithbody = toggle;
2313       if(config->failonerror && config->failwithbody) {
2314         errorf(config->global, "You must select either --fail or "
2315                "--fail-with-body, not both.");
2316         err = PARAM_BAD_USE;
2317       }
2318       break;
2319     case C_REMOVE_ON_ERROR: /* --remove-on-error */
2320       config->rm_partial = toggle;
2321       break;
2322     case C_FAIL: /* --fail */
2323       config->failonerror = toggle;
2324       if(config->failonerror && config->failwithbody) {
2325         errorf(config->global, "You must select either --fail or "
2326                "--fail-with-body, not both.");
2327         err = PARAM_BAD_USE;
2328       }
2329       break;
2330     case C_FORM: /* --form */
2331     case C_FORM_STRING: /* --form-string */
2332       /* "form data" simulation, this is a little advanced so lets do our best
2333          to sort this out slowly and carefully */
2334       if(formparse(config,
2335                    nextarg,
2336                    &config->mimeroot,
2337                    &config->mimecurrent,
2338                    (cmd == C_FORM_STRING)?TRUE:FALSE)) /* literal string */
2339         err = PARAM_BAD_USE;
2340       else if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq))
2341         err = PARAM_BAD_USE;
2342       break;
2343     case C_GLOBOFF: /* --globoff */
2344       config->globoff = toggle;
2345       break;
2346     case C_GET: /* --get */
2347       config->use_httpget = toggle;
2348       break;
2349     case C_REQUEST_TARGET: /* --request-target */
2350       err = getstr(&config->request_target, nextarg, DENY_BLANK);
2351       break;
2352     case C_HELP: /* --help */
2353       if(toggle) {
2354         if(*nextarg) {
2355           global->help_category = strdup(nextarg);
2356           if(!global->help_category) {
2357             err = PARAM_NO_MEM;
2358             break;
2359           }
2360         }
2361         err = PARAM_HELP_REQUESTED;
2362       }
2363       /* we now actually support --no-help too! */
2364       break;
2365     case C_HEADER: /* --header */
2366     case C_PROXY_HEADER: /* --proxy-header */
2367       /* A custom header to append to a list */
2368       if(nextarg[0] == '@') {
2369         /* read many headers from a file or stdin */
2370         char *string;
2371         size_t len;
2372         bool use_stdin = !strcmp(&nextarg[1], "-");
2373         FILE *file = use_stdin?stdin:fopen(&nextarg[1], FOPEN_READTEXT);
2374         if(!file) {
2375           errorf(global, "Failed to open %s", &nextarg[1]);
2376           err = PARAM_READ_ERROR;
2377         }
2378         else {
2379           err = file2memory(&string, &len, file);
2380           if(!err && string) {
2381             /* Allow strtok() here since this isn't used threaded */
2382             /* !checksrc! disable BANNEDFUNC 2 */
2383             char *h = strtok(string, "\r\n");
2384             while(h) {
2385               if(cmd == C_PROXY_HEADER) /* --proxy-header */
2386                 err = add2list(&config->proxyheaders, h);
2387               else
2388                 err = add2list(&config->headers, h);
2389               if(err)
2390                 break;
2391               h = strtok(NULL, "\r\n");
2392             }
2393             free(string);
2394           }
2395           if(!use_stdin)
2396             fclose(file);
2397         }
2398       }
2399       else {
2400         if(cmd == C_PROXY_HEADER) /* --proxy-header */
2401           err = add2list(&config->proxyheaders, nextarg);
2402         else
2403           err = add2list(&config->headers, nextarg);
2404       }
2405       break;
2406     case C_INCLUDE: /* --include */
2407       config->show_headers = toggle; /* show the headers as well in the
2408                                         general output stream */
2409       break;
2410     case C_JUNK_SESSION_COOKIES: /* --junk-session-cookies */
2411       config->cookiesession = toggle;
2412       break;
2413     case C_HEAD: /* --head */
2414       config->no_body = toggle;
2415       config->show_headers = toggle;
2416       if(SetHTTPrequest(config,
2417                         (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
2418                         &config->httpreq))
2419         err = PARAM_BAD_USE;
2420       break;
2421     case C_REMOTE_HEADER_NAME: /* --remote-header-name */
2422       config->content_disposition = toggle;
2423       break;
2424     case C_INSECURE: /* --insecure */
2425       config->insecure_ok = toggle;
2426       break;
2427     case C_DOH_INSECURE: /* --doh-insecure */
2428       config->doh_insecure_ok = toggle;
2429       break;
2430     case C_CONFIG: /* --config */
2431       if(parseconfig(nextarg, global)) {
2432         errorf(global, "cannot read config from '%s'", nextarg);
2433         err = PARAM_READ_ERROR;
2434       }
2435       break;
2436     case C_LIST_ONLY: /* --list-only */
2437       config->dirlistonly = toggle; /* only list the names of the FTP dir */
2438       break;
2439     case C_LOCATION_TRUSTED: /* --location-trusted */
2440       /* Continue to send authentication (user+password) when following
2441        * locations, even when hostname changed */
2442       config->unrestricted_auth = toggle;
2443       FALLTHROUGH();
2444     case C_LOCATION: /* --location */
2445       config->followlocation = toggle; /* Follow Location: HTTP headers */
2446       break;
2447     case C_MAX_TIME: /* --max-time */
2448       /* specified max time */
2449       err = secs2ms(&config->timeout_ms, nextarg);
2450       break;
2451     case C_MANUAL: /* --manual */
2452       if(toggle) { /* --no-manual shows no manual... */
2453 #ifndef USE_MANUAL
2454         warnf(global,
2455               "built-in manual was disabled at build-time");
2456 #endif
2457         err = PARAM_MANUAL_REQUESTED;
2458       }
2459       break;
2460     case C_NETRC_OPTIONAL: /* --netrc-optional */
2461       config->netrc_opt = toggle;
2462       break;
2463     case C_NETRC_FILE: /* --netrc-file */
2464       err = getstr(&config->netrc_file, nextarg, DENY_BLANK);
2465       break;
2466     case C_NETRC: /* --netrc */
2467       /* pick info from .netrc, if this is used for http, curl will
2468          automatically enforce user+password with the request */
2469       config->netrc = toggle;
2470       break;
2471     case C_BUFFER: /* --buffer */
2472       /* disable the output I/O buffering. note that the option is called
2473          --buffer but is mostly used in the negative form: --no-buffer */
2474       config->nobuffer = longopt ? !toggle : TRUE;
2475       break;
2476     case C_REMOTE_NAME_ALL: /* --remote-name-all */
2477       config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
2478       break;
2479     case C_OUTPUT_DIR: /* --output-dir */
2480       err = getstr(&config->output_dir, nextarg, DENY_BLANK);
2481       break;
2482     case C_CLOBBER: /* --clobber */
2483       config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER;
2484       break;
2485     case C_OUTPUT: /* --output */
2486     case C_REMOTE_NAME: /* --remote-name */
2487       /* output file */
2488       if(!config->url_out)
2489         config->url_out = config->url_list;
2490       if(config->url_out) {
2491         /* there's a node here, if it already is filled-in continue to find
2492            an "empty" node */
2493         while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
2494           config->url_out = config->url_out->next;
2495       }
2496 
2497       /* now there might or might not be an available node to fill in! */
2498 
2499       if(config->url_out)
2500         /* existing node */
2501         url = config->url_out;
2502       else {
2503         if(!toggle && !config->default_node_flags)
2504           break;
2505         /* there was no free node, create one! */
2506         config->url_out = url = new_getout(config);
2507       }
2508 
2509       if(!url) {
2510         err = PARAM_NO_MEM;
2511         break;
2512       }
2513 
2514       /* fill in the outfile */
2515       if('o' == letter) {
2516         err = getstr(&url->outfile, nextarg, DENY_BLANK);
2517         url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2518       }
2519       else {
2520         url->outfile = NULL; /* leave it */
2521         if(toggle)
2522           url->flags |= GETOUT_USEREMOTE;  /* switch on */
2523         else
2524           url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2525       }
2526       url->flags |= GETOUT_OUTFILE;
2527       break;
2528     case C_FTP_PORT: /* --ftp-port */
2529       /* This makes the FTP sessions use PORT instead of PASV */
2530       /* use <eth0> or <192.168.10.10> style addresses. Anything except
2531          this will make us try to get the "default" address.
2532          NOTE: this is a changed behavior since the released 4.1!
2533       */
2534       err = getstr(&config->ftpport, nextarg, DENY_BLANK);
2535       break;
2536     case C_PROXYTUNNEL: /* --proxytunnel */
2537       /* proxy tunnel for non-http protocols */
2538       config->proxytunnel = toggle;
2539       break;
2540 
2541     case C_DISABLE: /* --disable */
2542       /* if used first, already taken care of, we do it like this so we don't
2543          cause an error! */
2544       break;
2545     case C_QUOTE: /* --quote */
2546       /* QUOTE command to send to FTP server */
2547       switch(nextarg[0]) {
2548       case '-':
2549         /* prefixed with a dash makes it a POST TRANSFER one */
2550         nextarg++;
2551         err = add2list(&config->postquote, nextarg);
2552         break;
2553       case '+':
2554         /* prefixed with a plus makes it a just-before-transfer one */
2555         nextarg++;
2556         err = add2list(&config->prequote, nextarg);
2557         break;
2558       default:
2559         err = add2list(&config->quote, nextarg);
2560         break;
2561       }
2562       break;
2563     case C_RANGE: /* --range */
2564       /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
2565          (and won't actually be range by definition). The man page previously
2566          claimed that to be a good way, why this code is added to work-around
2567          it. */
2568       if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
2569         char buffer[32];
2570         if(curlx_strtoofft(nextarg, NULL, 10, &value)) {
2571           warnf(global, "unsupported range point");
2572           err = PARAM_BAD_USE;
2573         }
2574         else {
2575           warnf(global,
2576                 "A specified range MUST include at least one dash (-). "
2577                 "Appending one for you");
2578           msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-",
2579                     value);
2580           Curl_safefree(config->range);
2581           config->range = strdup(buffer);
2582           if(!config->range)
2583             err = PARAM_NO_MEM;
2584         }
2585       }
2586       else {
2587         /* byte range requested */
2588         const char *tmp_range = nextarg;
2589         while(*tmp_range) {
2590           if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
2591             warnf(global, "Invalid character is found in given range. "
2592                   "A specified range MUST have only digits in "
2593                   "\'start\'-\'stop\'. The server's response to this "
2594                   "request is uncertain.");
2595             break;
2596           }
2597           tmp_range++;
2598         }
2599         err = getstr(&config->range, nextarg, DENY_BLANK);
2600       }
2601       break;
2602     case C_REMOTE_TIME: /* --remote-time */
2603       /* use remote file's time */
2604       config->remote_time = toggle;
2605       break;
2606     case C_SILENT: /* --silent */
2607       global->silent = toggle;
2608       break;
2609     case C_SHOW_ERROR: /* --show-error */
2610       global->showerror = toggle;
2611       break;
2612     case C_TELNET_OPTION: /* --telnet-option */
2613       /* Telnet options */
2614       err = add2list(&config->telnet_options, nextarg);
2615       break;
2616     case C_UPLOAD_FILE: /* --upload-file */
2617       /* we are uploading */
2618       if(!config->url_ul)
2619         config->url_ul = config->url_list;
2620       if(config->url_ul) {
2621         /* there's a node here, if it already is filled-in continue to find
2622            an "empty" node */
2623         while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD))
2624           config->url_ul = config->url_ul->next;
2625       }
2626 
2627       /* now there might or might not be an available node to fill in! */
2628 
2629       if(config->url_ul)
2630         /* existing node */
2631         url = config->url_ul;
2632       else
2633         /* there was no free node, create one! */
2634         config->url_ul = url = new_getout(config);
2635 
2636       if(!url) {
2637         err = PARAM_NO_MEM;
2638         break;
2639       }
2640 
2641       url->flags |= GETOUT_UPLOAD; /* mark -T used */
2642       if(!*nextarg)
2643         url->flags |= GETOUT_NOUPLOAD;
2644       else {
2645         /* "-" equals stdin, but keep the string around for now */
2646         err = getstr(&url->infile, nextarg, DENY_BLANK);
2647       }
2648       break;
2649     case C_USER: /* --user */
2650       /* user:password  */
2651       err = getstr(&config->userpwd, nextarg, ALLOW_BLANK);
2652       cleanarg(clearthis);
2653       break;
2654     case C_PROXY_USER: /* --proxy-user */
2655       /* Proxy user:password  */
2656       err = getstr(&config->proxyuserpwd, nextarg, ALLOW_BLANK);
2657       cleanarg(clearthis);
2658       break;
2659     case C_VERBOSE: /* --verbose */
2660       if(toggle) {
2661         /* the '%' thing here will cause the trace get sent to stderr */
2662         Curl_safefree(global->trace_dump);
2663         global->trace_dump = strdup("%");
2664         if(!global->trace_dump)
2665           err = PARAM_NO_MEM;
2666         else {
2667           if(global->tracetype && (global->tracetype != TRACE_PLAIN))
2668             warnf(global,
2669                   "-v, --verbose overrides an earlier trace/verbose option");
2670           global->tracetype = TRACE_PLAIN;
2671         }
2672       }
2673       else
2674         /* verbose is disabled here */
2675         global->tracetype = TRACE_NONE;
2676       break;
2677     case C_VERSION: /* --version */
2678       if(toggle)    /* --no-version yields no output! */
2679         err = PARAM_VERSION_INFO_REQUESTED;
2680       break;
2681     case C_WRITE_OUT: /* --write-out */
2682       /* get the output string */
2683       if('@' == *nextarg) {
2684         /* the data begins with a '@' letter, it means that a file name
2685            or - (stdin) follows */
2686         FILE *file;
2687         const char *fname;
2688         nextarg++; /* pass the @ */
2689         if(!strcmp("-", nextarg)) {
2690           fname = "<stdin>";
2691           file = stdin;
2692         }
2693         else {
2694           fname = nextarg;
2695           file = fopen(fname, FOPEN_READTEXT);
2696           if(!file) {
2697             errorf(global, "Failed to open %s", fname);
2698             err = PARAM_READ_ERROR;
2699             break;
2700           }
2701         }
2702         Curl_safefree(config->writeout);
2703         err = file2string(&config->writeout, file);
2704         if(file && (file != stdin))
2705           fclose(file);
2706         if(err)
2707           break;
2708         if(!config->writeout)
2709           warnf(global, "Failed to read %s", fname);
2710       }
2711       else
2712         err = getstr(&config->writeout, nextarg, ALLOW_BLANK);
2713       break;
2714     case C_PREPROXY: /* --preproxy */
2715       err = getstr(&config->preproxy, nextarg, DENY_BLANK);
2716       break;
2717     case C_PROXY: /* --proxy */
2718       /* --proxy */
2719       err = getstr(&config->proxy, nextarg, ALLOW_BLANK);
2720       if(config->proxyver != CURLPROXY_HTTPS2)
2721         config->proxyver = CURLPROXY_HTTP;
2722       break;
2723     case C_REQUEST: /* --request */
2724       /* set custom request */
2725       err = getstr(&config->customrequest, nextarg, DENY_BLANK);
2726       break;
2727     case C_SPEED_TIME: /* --speed-time */
2728       /* low speed time */
2729       err = str2unum(&config->low_speed_time, nextarg);
2730       if(!err && !config->low_speed_limit)
2731         config->low_speed_limit = 1;
2732       break;
2733     case C_SPEED_LIMIT: /* --speed-limit */
2734       /* low speed limit */
2735       err = str2unum(&config->low_speed_limit, nextarg);
2736       if(!err && !config->low_speed_time)
2737         config->low_speed_time = 30;
2738       break;
2739     case C_PARALLEL: /* --parallel */
2740       global->parallel = toggle;
2741       break;
2742     case C_PARALLEL_MAX: {  /* --parallel-max */
2743       long val;
2744       err = str2unum(&val, nextarg);
2745       if(err)
2746         break;
2747       if(val > MAX_PARALLEL)
2748         global->parallel_max = MAX_PARALLEL;
2749       else if(val < 1)
2750         global->parallel_max = PARALLEL_DEFAULT;
2751       else
2752         global->parallel_max = (unsigned short)val;
2753       break;
2754     }
2755     case C_PARALLEL_IMMEDIATE:   /* --parallel-immediate */
2756       global->parallel_connect = toggle;
2757       break;
2758     case C_TIME_COND: /* --time-cond */
2759       switch(*nextarg) {
2760       case '+':
2761         nextarg++;
2762         FALLTHROUGH();
2763       default:
2764         /* If-Modified-Since: (section 14.28 in RFC2068) */
2765         config->timecond = CURL_TIMECOND_IFMODSINCE;
2766         break;
2767       case '-':
2768         /* If-Unmodified-Since:  (section 14.24 in RFC2068) */
2769         config->timecond = CURL_TIMECOND_IFUNMODSINCE;
2770         nextarg++;
2771         break;
2772       case '=':
2773         /* Last-Modified:  (section 14.29 in RFC2068) */
2774         config->timecond = CURL_TIMECOND_LASTMOD;
2775         nextarg++;
2776         break;
2777       }
2778       now = time(NULL);
2779       config->condtime = (curl_off_t)curl_getdate(nextarg, &now);
2780       if(-1 == config->condtime) {
2781         /* now let's see if it is a file name to get the time from instead! */
2782         rc = getfiletime(nextarg, global, &value);
2783         if(!rc)
2784           /* pull the time out from the file */
2785           config->condtime = value;
2786         else {
2787           /* failed, remove time condition */
2788           config->timecond = CURL_TIMECOND_NONE;
2789           warnf(global,
2790                 "Illegal date format for -z, --time-cond (and not "
2791                 "a file name). Disabling time condition. "
2792                 "See curl_getdate(3) for valid date syntax.");
2793         }
2794       }
2795       break;
2796     default: /* unknown flag */
2797       err = PARAM_OPTION_UNKNOWN;
2798       break;
2799     }
2800     a = NULL;
2801 
2802   } while(!longopt && !singleopt && *++parse && !*usedarg && !err);
2803 
2804 error:
2805   if(nextalloc)
2806     free(nextarg);
2807   return err;
2808 }
2809 
parse_args(struct GlobalConfig * global,int argc,argv_item_t argv[])2810 ParameterError parse_args(struct GlobalConfig *global, int argc,
2811                           argv_item_t argv[])
2812 {
2813   int i;
2814   bool stillflags;
2815   char *orig_opt = NULL;
2816   ParameterError result = PARAM_OK;
2817   struct OperationConfig *config = global->first;
2818 
2819   for(i = 1, stillflags = TRUE; i < argc && !result; i++) {
2820     orig_opt = curlx_convert_tchar_to_UTF8(argv[i]);
2821     if(!orig_opt)
2822       return PARAM_NO_MEM;
2823 
2824     if(stillflags && ('-' == orig_opt[0])) {
2825       bool passarg;
2826 
2827       if(!strcmp("--", orig_opt))
2828         /* This indicates the end of the flags and thus enables the
2829            following (URL) argument to start with -. */
2830         stillflags = FALSE;
2831       else {
2832         char *nextarg = NULL;
2833         if(i < (argc - 1)) {
2834           nextarg = curlx_convert_tchar_to_UTF8(argv[i + 1]);
2835           if(!nextarg) {
2836             curlx_unicodefree(orig_opt);
2837             return PARAM_NO_MEM;
2838           }
2839         }
2840 
2841         result = getparameter(orig_opt, nextarg, argv[i + 1], &passarg,
2842                               global, config);
2843 
2844         curlx_unicodefree(nextarg);
2845         config = global->last;
2846         if(result == PARAM_NEXT_OPERATION) {
2847           /* Reset result as PARAM_NEXT_OPERATION is only used here and not
2848              returned from this function */
2849           result = PARAM_OK;
2850 
2851           if(config->url_list && config->url_list->url) {
2852             /* Allocate the next config */
2853             config->next = malloc(sizeof(struct OperationConfig));
2854             if(config->next) {
2855               /* Initialise the newly created config */
2856               config_init(config->next);
2857 
2858               /* Set the global config pointer */
2859               config->next->global = global;
2860 
2861               /* Update the last config pointer */
2862               global->last = config->next;
2863 
2864               /* Move onto the new config */
2865               config->next->prev = config;
2866               config = config->next;
2867             }
2868             else
2869               result = PARAM_NO_MEM;
2870           }
2871           else {
2872             errorf(global, "missing URL before --next");
2873             result = PARAM_BAD_USE;
2874           }
2875         }
2876         else if(!result && passarg)
2877           i++; /* we're supposed to skip this */
2878       }
2879     }
2880     else {
2881       bool used;
2882 
2883       /* Just add the URL please */
2884       result = getparameter("--url", orig_opt, argv[i], &used, global, config);
2885     }
2886 
2887     if(!result)
2888       curlx_unicodefree(orig_opt);
2889   }
2890 
2891   if(!result && config->content_disposition) {
2892     if(config->show_headers)
2893       result = PARAM_CONTDISP_SHOW_HEADER;
2894     else if(config->resume_from_current)
2895       result = PARAM_CONTDISP_RESUME_FROM;
2896   }
2897 
2898   if(result && result != PARAM_HELP_REQUESTED &&
2899      result != PARAM_MANUAL_REQUESTED &&
2900      result != PARAM_VERSION_INFO_REQUESTED &&
2901      result != PARAM_ENGINES_REQUESTED) {
2902     const char *reason = param2text(result);
2903 
2904     if(orig_opt && strcmp(":", orig_opt))
2905       helpf(tool_stderr, "option %s: %s", orig_opt, reason);
2906     else
2907       helpf(tool_stderr, "%s", reason);
2908   }
2909 
2910   curlx_unicodefree(orig_opt);
2911   return result;
2912 }
2913