quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

tool_getparam.c (98831B)


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