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