tool_getparam.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 #include "tool_setup.h"
00023 
00024 #include "strcase.h"
00025 
00026 #define ENABLE_CURLX_PRINTF
00027 /* use our own printf() functions */
00028 #include "curlx.h"
00029 
00030 #include "tool_binmode.h"
00031 #include "tool_cfgable.h"
00032 #include "tool_cb_prg.h"
00033 #include "tool_formparse.h"
00034 #include "tool_getparam.h"
00035 #include "tool_helpers.h"
00036 #include "tool_libinfo.h"
00037 #include "tool_metalink.h"
00038 #include "tool_msgs.h"
00039 #include "tool_paramhlp.h"
00040 #include "tool_parsecfg.h"
00041 
00042 #include "memdebug.h" /* keep this as LAST include */
00043 
00044 #ifdef MSDOS
00045 #  define USE_WATT32
00046 #endif
00047 
00048 #define GetStr(str,val) do { \
00049   if(*(str)) { \
00050     free(*(str)); \
00051     *(str) = NULL; \
00052   } \
00053   if((val)) {              \
00054     *(str) = strdup((val)); \
00055     if(!(*(str)))          \
00056       return PARAM_NO_MEM; \
00057   } \
00058 } WHILE_FALSE
00059 
00060 struct LongShort {
00061   const char *letter; /* short name option */
00062   const char *lname;  /* long name option */
00063   bool extraparam;    /* whether it takes an additional argument */
00064 };
00065 
00066 static const struct LongShort aliases[]= {
00067   /* 'letter' strings with more than one character have *no* short option to
00068      mention. */
00069   {"*@", "url",                      TRUE},
00070   {"*4", "dns-ipv4-addr",            TRUE},
00071   {"*6", "dns-ipv6-addr",            TRUE},
00072   {"*a", "random-file",              TRUE},
00073   {"*b", "egd-file",                 TRUE},
00074   {"*B", "oauth2-bearer",             TRUE},
00075   {"*c", "connect-timeout",          TRUE},
00076   {"*d", "ciphers",                  TRUE},
00077   {"*D", "dns-interface",            TRUE},
00078   {"*e", "disable-epsv",             FALSE},
00079   {"*E", "epsv",                     FALSE},
00080          /* 'epsv' made like this to make --no-epsv and --epsv to work
00081              although --disable-epsv is the documented option */
00082 #ifdef USE_ENVIRONMENT
00083   {"*f", "environment",              FALSE},
00084 #endif
00085   {"*F", "dns-servers",              TRUE},
00086   {"*g", "trace",                    TRUE},
00087   {"*G", "npn",                      FALSE},
00088   {"*h", "trace-ascii",              TRUE},
00089   {"*H", "alpn",                     FALSE},
00090   {"*i", "limit-rate",               TRUE},
00091   {"*j", "compressed",               FALSE},
00092   {"*J", "tr-encoding",              FALSE},
00093   {"*k", "digest",                   FALSE},
00094   {"*l", "negotiate",                FALSE},
00095   {"*m", "ntlm",                     FALSE},
00096   {"*M", "ntlm-wb",                  FALSE},
00097   {"*n", "basic",                    FALSE},
00098   {"*o", "anyauth",                  FALSE},
00099 #ifdef USE_WATT32
00100   {"*p", "wdebug",                   FALSE},
00101 #endif
00102   {"*q", "ftp-create-dirs",          FALSE},
00103   {"*r", "create-dirs",              FALSE},
00104   {"*s", "max-redirs",               TRUE},
00105   {"*t", "proxy-ntlm",               FALSE},
00106   {"*u", "crlf",                     FALSE},
00107   {"*v", "stderr",                   TRUE},
00108   {"*w", "interface",                TRUE},
00109   {"*x", "krb",                      TRUE},
00110   {"*x", "krb4",                     TRUE},
00111          /* 'krb4' is the previous name */
00112   {"*y", "max-filesize",             TRUE},
00113   {"*z", "disable-eprt",             FALSE},
00114   {"*Z", "eprt",                     FALSE},
00115          /* 'eprt' made like this to make --no-eprt and --eprt to work
00116              although --disable-eprt is the documented option */
00117   {"*~", "xattr",                    FALSE},
00118   {"$a", "ftp-ssl",                  FALSE},
00119          /* 'ftp-ssl' deprecated name since 7.20.0 */
00120   {"$a", "ssl",                      FALSE},
00121          /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */
00122   {"$b", "ftp-pasv",                 FALSE},
00123   {"$c", "socks5",                   TRUE},
00124   {"$d", "tcp-nodelay",              FALSE},
00125   {"$e", "proxy-digest",             FALSE},
00126   {"$f", "proxy-basic",              FALSE},
00127   {"$g", "retry",                    TRUE},
00128   {"$V", "retry-connrefused",        FALSE},
00129   {"$h", "retry-delay",              TRUE},
00130   {"$i", "retry-max-time",           TRUE},
00131   {"$k", "proxy-negotiate",          FALSE},
00132   {"$m", "ftp-account",              TRUE},
00133   {"$n", "proxy-anyauth",            FALSE},
00134   {"$o", "trace-time",               FALSE},
00135   {"$p", "ignore-content-length",    FALSE},
00136   {"$q", "ftp-skip-pasv-ip",         FALSE},
00137   {"$r", "ftp-method",               TRUE},
00138   {"$s", "local-port",               TRUE},
00139   {"$t", "socks4",                   TRUE},
00140   {"$T", "socks4a",                  TRUE},
00141   {"$u", "ftp-alternative-to-user",  TRUE},
00142   {"$v", "ftp-ssl-reqd",             FALSE},
00143          /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */
00144   {"$v", "ssl-reqd",                 FALSE},
00145          /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */
00146   {"$w", "sessionid",                FALSE},
00147          /* 'sessionid' listed as --no-sessionid in the help */
00148   {"$x", "ftp-ssl-control",          FALSE},
00149   {"$y", "ftp-ssl-ccc",              FALSE},
00150   {"$j", "ftp-ssl-ccc-mode",         TRUE},
00151   {"$z", "libcurl",                  TRUE},
00152   {"$#", "raw",                      FALSE},
00153   {"$0", "post301",                  FALSE},
00154   {"$1", "keepalive",                FALSE},
00155          /* 'keepalive' listed as --no-keepalive in the help */
00156   {"$2", "socks5-hostname",          TRUE},
00157   {"$3", "keepalive-time",           TRUE},
00158   {"$4", "post302",                  FALSE},
00159   {"$5", "noproxy",                  TRUE},
00160   {"$7", "socks5-gssapi-nec",        FALSE},
00161   {"$8", "proxy1.0",                 TRUE},
00162   {"$9", "tftp-blksize",             TRUE},
00163   {"$A", "mail-from",                TRUE},
00164   {"$B", "mail-rcpt",                TRUE},
00165   {"$C", "ftp-pret",                 FALSE},
00166   {"$D", "proto",                    TRUE},
00167   {"$E", "proto-redir",              TRUE},
00168   {"$F", "resolve",                  TRUE},
00169   {"$G", "delegation",               TRUE},
00170   {"$H", "mail-auth",                TRUE},
00171   {"$I", "post303",                  FALSE},
00172   {"$J", "metalink",                 FALSE},
00173   {"$K", "sasl-ir",                  FALSE},
00174   {"$L", "test-event",               FALSE},
00175   {"$M", "unix-socket",              TRUE},
00176   {"$N", "path-as-is",               FALSE},
00177   {"$O", "socks5-gssapi-service",    TRUE},
00178          /* 'socks5-gssapi-service' merged with'proxy-service-name' and
00179             deprecated since 7.49.0 */
00180   {"$O", "proxy-service-name",       TRUE},
00181   {"$P", "service-name",             TRUE},
00182   {"$Q", "proto-default",            TRUE},
00183   {"$R", "expect100-timeout",        TRUE},
00184   {"$S", "tftp-no-options",          FALSE},
00185   {"$U", "connect-to",               TRUE},
00186   {"0",   "http1.0",                 FALSE},
00187   {"01",  "http1.1",                 FALSE},
00188   {"02",  "http2",                   FALSE},
00189   {"03",  "http2-prior-knowledge",   FALSE},
00190   {"1",  "tlsv1",                    FALSE},
00191   {"10",  "tlsv1.0",                 FALSE},
00192   {"11",  "tlsv1.1",                 FALSE},
00193   {"12",  "tlsv1.2",                 FALSE},
00194   {"13",  "tlsv1.3",                 FALSE},
00195   {"2",  "sslv2",                    FALSE},
00196   {"3",  "sslv3",                    FALSE},
00197   {"4",  "ipv4",                     FALSE},
00198   {"6",  "ipv6",                     FALSE},
00199   {"a",  "append",                   FALSE},
00200   {"A",  "user-agent",               TRUE},
00201   {"b",  "cookie",                   TRUE},
00202   {"B",  "use-ascii",                FALSE},
00203   {"c",  "cookie-jar",               TRUE},
00204   {"C",  "continue-at",              TRUE},
00205   {"d",  "data",                     TRUE},
00206   {"dr", "data-raw",                 TRUE},
00207   {"da", "data-ascii",               TRUE},
00208   {"db", "data-binary",              TRUE},
00209   {"de", "data-urlencode",           TRUE},
00210   {"D",  "dump-header",              TRUE},
00211   {"e",  "referer",                  TRUE},
00212   {"E",  "cert",                     TRUE},
00213   {"Ea", "cacert",                   TRUE},
00214   {"Eb", "cert-type",                TRUE},
00215   {"Ec", "key",                      TRUE},
00216   {"Ed", "key-type",                 TRUE},
00217   {"Ee", "pass",                     TRUE},
00218   {"Ef", "engine",                   TRUE},
00219   {"Eg", "capath",                   TRUE},
00220   {"Eh", "pubkey",                   TRUE},
00221   {"Ei", "hostpubmd5",               TRUE},
00222   {"Ej", "crlfile",                  TRUE},
00223   {"Ek", "tlsuser",                  TRUE},
00224   {"El", "tlspassword",              TRUE},
00225   {"Em", "tlsauthtype",              TRUE},
00226   {"En", "ssl-allow-beast",          FALSE},
00227   {"Eo", "login-options",            TRUE},
00228   {"Ep", "pinnedpubkey",             TRUE},
00229   {"Eq", "cert-status",              FALSE},
00230   {"Er", "false-start",              FALSE},
00231   {"Es", "ssl-no-revoke",            FALSE},
00232   {"Et", "tcp-fastopen",             FALSE},
00233   {"Eu", "proxy-tlsuser",            TRUE},
00234   {"Ev", "proxy-tlspassword",        TRUE},
00235   {"Ew", "proxy-tlsauthtype",        TRUE},
00236   {"Ex", "proxy-cert",               TRUE},
00237   {"Ey", "proxy-cert-type",          TRUE},
00238   {"Ez", "proxy-key",                TRUE},
00239   {"E0", "proxy-key-type",           TRUE},
00240   {"E1", "proxy-pass",               TRUE},
00241   {"E2", "proxy-ciphers",            TRUE},
00242   {"E3", "proxy-crlfile",            TRUE},
00243   {"E4", "proxy-ssl-allow-beast",    FALSE},
00244   {"E5", "login-options",            TRUE},
00245   {"E6", "proxy-cacert",             TRUE},
00246   {"E7", "proxy-capath",             TRUE},
00247   {"E8", "proxy-insecure",           FALSE},
00248   {"E9", "proxy-tlsv1",              FALSE},
00249   {"f",  "fail",                     FALSE},
00250   {"fa", "fail-early",               FALSE},
00251   {"F",  "form",                     TRUE},
00252   {"Fs", "form-string",              TRUE},
00253   {"g",  "globoff",                  FALSE},
00254   {"G",  "get",                      FALSE},
00255   {"h",  "help",                     FALSE},
00256   {"H",  "header",                   TRUE},
00257   {"Hp", "proxy-header",             TRUE},
00258   {"i",  "include",                  FALSE},
00259   {"I",  "head",                     FALSE},
00260   {"j",  "junk-session-cookies",     FALSE},
00261   {"J",  "remote-header-name",       FALSE},
00262   {"k",  "insecure",                 FALSE},
00263   {"K",  "config",                   TRUE},
00264   {"l",  "list-only",                FALSE},
00265   {"L",  "location",                 FALSE},
00266   {"Lt", "location-trusted",         FALSE},
00267   {"m",  "max-time",                 TRUE},
00268   {"M",  "manual",                   FALSE},
00269   {"n",  "netrc",                    FALSE},
00270   {"no", "netrc-optional",           FALSE},
00271   {"ne", "netrc-file",               TRUE},
00272   {"N",  "buffer",                   FALSE},
00273          /* 'buffer' listed as --no-buffer in the help */
00274   {"o",  "output",                   TRUE},
00275   {"O",  "remote-name",              FALSE},
00276   {"Oa", "remote-name-all",          FALSE},
00277   {"p",  "proxytunnel",              FALSE},
00278   {"P",  "ftp-port",                 TRUE},
00279   {"q",  "disable",                  FALSE},
00280   {"Q",  "quote",                    TRUE},
00281   {"r",  "range",                    TRUE},
00282   {"R",  "remote-time",              FALSE},
00283   {"s",  "silent",                   FALSE},
00284   {"S",  "show-error",               FALSE},
00285   {"t",  "telnet-option",            TRUE},
00286   {"T",  "upload-file",              TRUE},
00287   {"u",  "user",                     TRUE},
00288   {"U",  "proxy-user",               TRUE},
00289   {"v",  "verbose",                  FALSE},
00290   {"V",  "version",                  FALSE},
00291   {"w",  "write-out",                TRUE},
00292   {"x",  "proxy",                    TRUE},
00293   {"xa", "preproxy",                 TRUE},
00294   {"X",  "request",                  TRUE},
00295   {"Y",  "speed-limit",              TRUE},
00296   {"y",  "speed-time",               TRUE},
00297   {"z",  "time-cond",                TRUE},
00298   {"#",  "progress-bar",             FALSE},
00299   {":",  "next",                     FALSE},
00300 };
00301 
00302 /* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
00303  * We allow ':' and '\' to be escaped by '\' so that we can use certificate
00304  * nicknames containing ':'.  See <https://sourceforge.net/p/curl/bugs/1196/>
00305  * for details. */
00306 #ifndef UNITTESTS
00307 static
00308 #endif
00309 void parse_cert_parameter(const char *cert_parameter,
00310                           char **certname,
00311                           char **passphrase)
00312 {
00313   size_t param_length = strlen(cert_parameter);
00314   size_t span;
00315   const char *param_place = NULL;
00316   char *certname_place = NULL;
00317   *certname = NULL;
00318   *passphrase = NULL;
00319 
00320   /* most trivial assumption: cert_parameter is empty */
00321   if(param_length == 0)
00322     return;
00323 
00324   /* next less trivial: cert_parameter starts 'pkcs11:' and thus
00325    * looks like a RFC7512 PKCS#11 URI which can be used as-is.
00326    * Also if cert_parameter contains no colon nor backslash, this
00327    * means no passphrase was given and no characters escaped */
00328   if(!strncmp(cert_parameter, "pkcs11:", 7) ||
00329      !strpbrk(cert_parameter, ":\\")) {
00330     *certname = strdup(cert_parameter);
00331     return;
00332   }
00333   /* deal with escaped chars; find unescaped colon if it exists */
00334   certname_place = malloc(param_length + 1);
00335   if(!certname_place)
00336     return;
00337 
00338   *certname = certname_place;
00339   param_place = cert_parameter;
00340   while(*param_place) {
00341     span = strcspn(param_place, ":\\");
00342     strncpy(certname_place, param_place, span);
00343     param_place += span;
00344     certname_place += span;
00345     /* we just ate all the non-special chars. now we're on either a special
00346      * char or the end of the string. */
00347     switch(*param_place) {
00348     case '\0':
00349       break;
00350     case '\\':
00351       param_place++;
00352       switch(*param_place) {
00353         case '\0':
00354           *certname_place++ = '\\';
00355           break;
00356         case '\\':
00357           *certname_place++ = '\\';
00358           param_place++;
00359           break;
00360         case ':':
00361           *certname_place++ = ':';
00362           param_place++;
00363           break;
00364         default:
00365           *certname_place++ = '\\';
00366           *certname_place++ = *param_place;
00367           param_place++;
00368           break;
00369       }
00370       break;
00371     case ':':
00372       /* Since we live in a world of weirdness and confusion, the win32
00373          dudes can use : when using drive letters and thus c:\file:password
00374          needs to work. In order not to break compatibility, we still use : as
00375          separator, but we try to detect when it is used for a file name! On
00376          windows. */
00377 #ifdef WIN32
00378       if(param_place &&
00379           (param_place == &cert_parameter[1]) &&
00380           (cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
00381           (ISALPHA(cert_parameter[0])) ) {
00382         /* colon in the second column, followed by a backslash, and the
00383            first character is an alphabetic letter:
00384 
00385            this is a drive letter colon */
00386         *certname_place++ = ':';
00387         param_place++;
00388         break;
00389       }
00390 #endif
00391       /* escaped colons and Windows drive letter colons were handled
00392        * above; if we're still here, this is a separating colon */
00393       param_place++;
00394       if(strlen(param_place) > 0) {
00395         *passphrase = strdup(param_place);
00396       }
00397       goto done;
00398     }
00399   }
00400 done:
00401   *certname_place = '\0';
00402 }
00403 
00404 static void
00405 GetFileAndPassword(char *nextarg, char **file, char **password)
00406 {
00407   char *certname, *passphrase;
00408   parse_cert_parameter(nextarg, &certname, &passphrase);
00409   Curl_safefree(*file);
00410   *file = certname;
00411   if(passphrase) {
00412     Curl_safefree(*password);
00413     *password = passphrase;
00414   }
00415   cleanarg(nextarg);
00416 }
00417 
00418 ParameterError getparameter(char *flag,    /* f or -long-flag */
00419                             char *nextarg, /* NULL if unset */
00420                             bool *usedarg, /* set to TRUE if the arg
00421                                               has been used */
00422                             struct GlobalConfig *global,
00423                             struct OperationConfig *config)
00424 {
00425   char letter;
00426   char subletter = '\0'; /* subletters can only occur on long options */
00427   int rc;
00428   const char *parse = NULL;
00429   unsigned int j;
00430   time_t now;
00431   int hit = -1;
00432   bool longopt = FALSE;
00433   bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
00434   ParameterError err;
00435   bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
00436                          by using --OPTION or --no-OPTION */
00437 
00438 
00439   if(('-' != flag[0]) ||
00440      (('-' == flag[0]) && ('-' == flag[1]))) {
00441     /* this should be a long name */
00442     char *word = ('-' == flag[0]) ? flag+2 : flag;
00443     size_t fnam = strlen(word);
00444     int numhits = 0;
00445 
00446     if(!strncmp(word, "no-", 3)) {
00447       /* disable this option but ignore the "no-" part when looking for it */
00448       word += 3;
00449       toggle = FALSE;
00450     }
00451 
00452     for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
00453       if(curl_strnequal(aliases[j].lname, word, fnam)) {
00454         longopt = TRUE;
00455         numhits++;
00456         if(curl_strequal(aliases[j].lname, word)) {
00457           parse = aliases[j].letter;
00458           hit = j;
00459           numhits = 1; /* a single unique hit */
00460           break;
00461         }
00462         parse = aliases[j].letter;
00463         hit = j;
00464       }
00465     }
00466     if(numhits > 1) {
00467       /* this is at least the second match! */
00468       return PARAM_OPTION_AMBIGUOUS;
00469     }
00470     if(hit < 0) {
00471       return PARAM_OPTION_UNKNOWN;
00472     }
00473   }
00474   else {
00475     flag++; /* prefixed with one dash, pass it */
00476     hit = -1;
00477     parse = flag;
00478   }
00479 
00480   do {
00481     /* we can loop here if we have multiple single-letters */
00482 
00483     if(!longopt) {
00484       letter = (char)*parse;
00485       subletter='\0';
00486     }
00487     else {
00488       letter = parse[0];
00489       subletter = parse[1];
00490     }
00491     *usedarg = FALSE; /* default is that we don't use the arg */
00492 
00493     if(hit < 0) {
00494       for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
00495         if(letter == aliases[j].letter[0]) {
00496           hit = j;
00497           break;
00498         }
00499       }
00500       if(hit < 0) {
00501         return PARAM_OPTION_UNKNOWN;
00502       }
00503     }
00504 
00505     if(aliases[hit].extraparam) {
00506       /* this option requires an extra parameter */
00507       if(!longopt && parse[1]) {
00508         nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
00509         singleopt = TRUE;   /* don't loop anymore after this */
00510       }
00511       else if(!nextarg)
00512         return PARAM_REQUIRES_PARAMETER;
00513       else
00514         *usedarg = TRUE; /* mark it as used */
00515     }
00516 
00517     switch(letter) {
00518     case '*': /* options without a short option */
00519       switch(subletter) {
00520       case '4': /* --dns-ipv4-addr */
00521         /* addr in dot notation */
00522         GetStr(&config->dns_ipv4_addr, nextarg);
00523         break;
00524       case '6': /* --dns-ipv6-addr */
00525         /* addr in dot notation */
00526         GetStr(&config->dns_ipv6_addr, nextarg);
00527         break;
00528       case 'a': /* random-file */
00529         GetStr(&config->random_file, nextarg);
00530         break;
00531       case 'b': /* egd-file */
00532         GetStr(&config->egd_file, nextarg);
00533         break;
00534       case 'B': /* OAuth 2.0 bearer token */
00535         GetStr(&config->oauth_bearer, nextarg);
00536         break;
00537       case 'c': /* connect-timeout */
00538         err = str2udouble(&config->connecttimeout, nextarg);
00539         if(err)
00540           return err;
00541         break;
00542       case 'd': /* ciphers */
00543         GetStr(&config->cipher_list, nextarg);
00544         break;
00545       case 'D': /* --dns-interface */
00546         /* interface name */
00547         GetStr(&config->dns_interface, nextarg);
00548         break;
00549       case 'e': /* --disable-epsv */
00550         config->disable_epsv = toggle;
00551         break;
00552       case 'E': /* --epsv */
00553         config->disable_epsv = (!toggle)?TRUE:FALSE;
00554         break;
00555 #ifdef USE_ENVIRONMENT
00556       case 'f':
00557         config->writeenv = toggle;
00558         break;
00559 #endif
00560       case 'F': /* --dns-servers */
00561         /* IP addrs of DNS servers */
00562         GetStr(&config->dns_servers, nextarg);
00563         break;
00564       case 'g': /* --trace */
00565         GetStr(&global->trace_dump, nextarg);
00566         if(global->tracetype && (global->tracetype != TRACE_BIN))
00567           warnf(global, "--trace overrides an earlier trace/verbose option\n");
00568         global->tracetype = TRACE_BIN;
00569         break;
00570       case 'G': /* --npn */
00571         config->nonpn = (!toggle)?TRUE:FALSE;
00572         break;
00573       case 'h': /* --trace-ascii */
00574         GetStr(&global->trace_dump, nextarg);
00575         if(global->tracetype && (global->tracetype != TRACE_ASCII))
00576           warnf(global,
00577                 "--trace-ascii overrides an earlier trace/verbose option\n");
00578         global->tracetype = TRACE_ASCII;
00579         break;
00580       case 'H': /* --alpn */
00581         config->noalpn = (!toggle)?TRUE:FALSE;
00582         break;
00583       case 'i': /* --limit-rate */
00584       {
00585         /* We support G, M, K too */
00586         char *unit;
00587         curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
00588 
00589         if(!*unit)
00590           unit = (char *)"b";
00591         else if(strlen(unit) > 1)
00592           unit = (char *)"w"; /* unsupported */
00593 
00594         switch(*unit) {
00595         case 'G':
00596         case 'g':
00597           value *= 1024*1024*1024;
00598           break;
00599         case 'M':
00600         case 'm':
00601           value *= 1024*1024;
00602           break;
00603         case 'K':
00604         case 'k':
00605           value *= 1024;
00606           break;
00607         case 'b':
00608         case 'B':
00609           /* for plain bytes, leave as-is */
00610           break;
00611         default:
00612           warnf(global, "unsupported rate unit. Use G, M, K or B!\n");
00613           return PARAM_BAD_USE;
00614         }
00615         config->recvpersecond = value;
00616         config->sendpersecond = value;
00617       }
00618       break;
00619 
00620       case 'j': /* --compressed */
00621         if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ))
00622           return PARAM_LIBCURL_DOESNT_SUPPORT;
00623         config->encoding = toggle;
00624         break;
00625 
00626       case 'J': /* --tr-encoding */
00627         config->tr_encoding = toggle;
00628         break;
00629 
00630       case 'k': /* --digest */
00631         if(toggle)
00632           config->authtype |= CURLAUTH_DIGEST;
00633         else
00634           config->authtype &= ~CURLAUTH_DIGEST;
00635         break;
00636 
00637       case 'l': /* --negotiate */
00638         if(toggle) {
00639           if(curlinfo->features & CURL_VERSION_SPNEGO)
00640             config->authtype |= CURLAUTH_NEGOTIATE;
00641           else
00642             return PARAM_LIBCURL_DOESNT_SUPPORT;
00643         }
00644         else
00645           config->authtype &= ~CURLAUTH_NEGOTIATE;
00646         break;
00647 
00648       case 'm': /* --ntlm */
00649         if(toggle) {
00650           if(curlinfo->features & CURL_VERSION_NTLM)
00651             config->authtype |= CURLAUTH_NTLM;
00652           else
00653             return PARAM_LIBCURL_DOESNT_SUPPORT;
00654         }
00655         else
00656           config->authtype &= ~CURLAUTH_NTLM;
00657         break;
00658 
00659       case 'M': /* --ntlm-wb */
00660         if(toggle) {
00661           if(curlinfo->features & CURL_VERSION_NTLM_WB)
00662             config->authtype |= CURLAUTH_NTLM_WB;
00663           else
00664             return PARAM_LIBCURL_DOESNT_SUPPORT;
00665         }
00666         else
00667           config->authtype &= ~CURLAUTH_NTLM_WB;
00668         break;
00669 
00670       case 'n': /* --basic for completeness */
00671         if(toggle)
00672           config->authtype |= CURLAUTH_BASIC;
00673         else
00674           config->authtype &= ~CURLAUTH_BASIC;
00675         break;
00676 
00677       case 'o': /* --anyauth, let libcurl pick it */
00678         if(toggle)
00679           config->authtype = CURLAUTH_ANY;
00680         /* --no-anyauth simply doesn't touch it */
00681         break;
00682 
00683 #ifdef USE_WATT32
00684       case 'p': /* --wdebug */
00685         dbug_init();
00686         break;
00687 #endif
00688       case 'q': /* --ftp-create-dirs */
00689         config->ftp_create_dirs = toggle;
00690         break;
00691 
00692       case 'r': /* --create-dirs */
00693         config->create_dirs = toggle;
00694         break;
00695 
00696       case 's': /* --max-redirs */
00697         /* specified max no of redirects (http(s)), this accepts -1 as a
00698            special condition */
00699         err = str2num(&config->maxredirs, nextarg);
00700         if(err)
00701           return err;
00702         if(config->maxredirs < -1)
00703           return PARAM_BAD_NUMERIC;
00704         break;
00705 
00706       case 't': /* --proxy-ntlm */
00707         if(curlinfo->features & CURL_VERSION_NTLM)
00708           config->proxyntlm = toggle;
00709         else
00710           return PARAM_LIBCURL_DOESNT_SUPPORT;
00711         break;
00712 
00713       case 'u': /* --crlf */
00714         /* LF -> CRLF conversion? */
00715         config->crlf = toggle;
00716         break;
00717 
00718       case 'v': /* --stderr */
00719         if(strcmp(nextarg, "-")) {
00720           FILE *newfile = fopen(nextarg, FOPEN_WRITETEXT);
00721           if(!newfile)
00722             warnf(global, "Failed to open %s!\n", nextarg);
00723           else {
00724             if(global->errors_fopened)
00725               fclose(global->errors);
00726             global->errors = newfile;
00727             global->errors_fopened = TRUE;
00728           }
00729         }
00730         else
00731           global->errors = stdout;
00732         break;
00733       case 'w': /* --interface */
00734         /* interface */
00735         GetStr(&config->iface, nextarg);
00736         break;
00737       case 'x': /* --krb */
00738         /* kerberos level string */
00739         if(curlinfo->features & CURL_VERSION_KERBEROS4)
00740           GetStr(&config->krblevel, nextarg);
00741         else
00742           return PARAM_LIBCURL_DOESNT_SUPPORT;
00743         break;
00744       case 'y': /* --max-filesize */
00745         err = str2offset(&config->max_filesize, nextarg);
00746         if(err)
00747           return err;
00748         break;
00749       case 'z': /* --disable-eprt */
00750         config->disable_eprt = toggle;
00751         break;
00752       case 'Z': /* --eprt */
00753         config->disable_eprt = (!toggle)?TRUE:FALSE;
00754         break;
00755       case '~': /* --xattr */
00756         config->xattr = toggle;
00757         break;
00758       case '@': /* the URL! */
00759       {
00760         struct getout *url;
00761 
00762         if(!config->url_get)
00763           config->url_get = config->url_list;
00764 
00765         if(config->url_get) {
00766           /* there's a node here, if it already is filled-in continue to find
00767              an "empty" node */
00768           while(config->url_get && (config->url_get->flags & GETOUT_URL))
00769             config->url_get = config->url_get->next;
00770         }
00771 
00772         /* now there might or might not be an available node to fill in! */
00773 
00774         if(config->url_get)
00775           /* existing node */
00776           url = config->url_get;
00777         else
00778           /* there was no free node, create one! */
00779           url = new_getout(config);
00780 
00781         if(!url)
00782           return PARAM_NO_MEM;
00783         else {
00784           /* fill in the URL */
00785           GetStr(&url->url, nextarg);
00786           url->flags |= GETOUT_URL;
00787         }
00788       }
00789       }
00790       break;
00791     case '$': /* more options without a short option */
00792       switch(subletter) {
00793       case 'a': /* --ssl */
00794         if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
00795           return PARAM_LIBCURL_DOESNT_SUPPORT;
00796         config->ftp_ssl = toggle;
00797         break;
00798       case 'b': /* --ftp-pasv */
00799         Curl_safefree(config->ftpport);
00800         break;
00801       case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
00802                    the name locally and passes on the resolved address */
00803         GetStr(&config->proxy, nextarg);
00804         config->proxyver = CURLPROXY_SOCKS5;
00805         break;
00806       case 't': /* --socks4 specifies a socks4 proxy to use */
00807         GetStr(&config->proxy, nextarg);
00808         config->proxyver = CURLPROXY_SOCKS4;
00809         break;
00810       case 'T': /* --socks4a specifies a socks4a proxy to use */
00811         GetStr(&config->proxy, nextarg);
00812         config->proxyver = CURLPROXY_SOCKS4A;
00813         break;
00814       case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
00815                    resolving with the proxy */
00816         GetStr(&config->proxy, nextarg);
00817         config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
00818         break;
00819       case 'd': /* --tcp-nodelay option */
00820         config->tcp_nodelay = toggle;
00821         break;
00822       case 'e': /* --proxy-digest */
00823         config->proxydigest = toggle;
00824         break;
00825       case 'f': /* --proxy-basic */
00826         config->proxybasic = toggle;
00827         break;
00828       case 'g': /* --retry */
00829         err = str2unum(&config->req_retry, nextarg);
00830         if(err)
00831           return err;
00832         break;
00833       case 'V': /* --retry-connrefused */
00834         config->retry_connrefused = toggle;
00835         break;
00836       case 'h': /* --retry-delay */
00837         err = str2unum(&config->retry_delay, nextarg);
00838         if(err)
00839           return err;
00840         break;
00841       case 'i': /* --retry-max-time */
00842         err = str2unum(&config->retry_maxtime, nextarg);
00843         if(err)
00844           return err;
00845         break;
00846 
00847       case 'k': /* --proxy-negotiate */
00848         if(curlinfo->features & CURL_VERSION_SPNEGO)
00849           config->proxynegotiate = toggle;
00850         else
00851           return PARAM_LIBCURL_DOESNT_SUPPORT;
00852         break;
00853 
00854       case 'm': /* --ftp-account */
00855         GetStr(&config->ftp_account, nextarg);
00856         break;
00857       case 'n': /* --proxy-anyauth */
00858         config->proxyanyauth = toggle;
00859         break;
00860       case 'o': /* --trace-time */
00861         global->tracetime = toggle;
00862         break;
00863       case 'p': /* --ignore-content-length */
00864         config->ignorecl = toggle;
00865         break;
00866       case 'q': /* --ftp-skip-pasv-ip */
00867         config->ftp_skip_ip = toggle;
00868         break;
00869       case 'r': /* --ftp-method (undocumented at this point) */
00870         config->ftp_filemethod = ftpfilemethod(config, nextarg);
00871         break;
00872       case 's': /* --local-port */
00873         rc = sscanf(nextarg, "%d - %d",
00874                     &config->localport,
00875                     &config->localportrange);
00876         if(!rc)
00877           return PARAM_BAD_USE;
00878         else if(rc == 1)
00879           config->localportrange = 1; /* default number of ports to try */
00880         else {
00881           config->localportrange -= config->localport;
00882           if(config->localportrange < 1) {
00883             warnf(global, "bad range input\n");
00884             return PARAM_BAD_USE;
00885           }
00886         }
00887         break;
00888       case 'u': /* --ftp-alternative-to-user */
00889         GetStr(&config->ftp_alternative_to_user, nextarg);
00890         break;
00891       case 'v': /* --ssl-reqd */
00892         if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
00893           return PARAM_LIBCURL_DOESNT_SUPPORT;
00894         config->ftp_ssl_reqd = toggle;
00895         break;
00896       case 'w': /* --no-sessionid */
00897         config->disable_sessionid = (!toggle)?TRUE:FALSE;
00898         break;
00899       case 'x': /* --ftp-ssl-control */
00900         if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
00901           return PARAM_LIBCURL_DOESNT_SUPPORT;
00902         config->ftp_ssl_control = toggle;
00903         break;
00904       case 'y': /* --ftp-ssl-ccc */
00905         config->ftp_ssl_ccc = toggle;
00906         if(!config->ftp_ssl_ccc_mode)
00907           config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
00908         break;
00909       case 'j': /* --ftp-ssl-ccc-mode */
00910         config->ftp_ssl_ccc = TRUE;
00911         config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
00912         break;
00913       case 'z': /* --libcurl */
00914 #ifdef CURL_DISABLE_LIBCURL_OPTION
00915         warnf(global,
00916               "--libcurl option was disabled at build-time!\n");
00917         return PARAM_OPTION_UNKNOWN;
00918 #else
00919         GetStr(&global->libcurl, nextarg);
00920         break;
00921 #endif
00922       case '#': /* --raw */
00923         config->raw = toggle;
00924         break;
00925       case '0': /* --post301 */
00926         config->post301 = toggle;
00927         break;
00928       case '1': /* --no-keepalive */
00929         config->nokeepalive = (!toggle)?TRUE:FALSE;
00930         break;
00931       case '3': /* --keepalive-time */
00932         err = str2unum(&config->alivetime, nextarg);
00933         if(err)
00934           return err;
00935         break;
00936       case '4': /* --post302 */
00937         config->post302 = toggle;
00938         break;
00939       case 'I': /* --post303 */
00940         config->post303 = toggle;
00941         break;
00942       case '5': /* --noproxy */
00943         /* This specifies the noproxy list */
00944         GetStr(&config->noproxy, nextarg);
00945         break;
00946        case '7': /* --socks5-gssapi-nec*/
00947         config->socks5_gssapi_nec = toggle;
00948         break;
00949       case '8': /* --proxy1.0 */
00950         /* http 1.0 proxy */
00951         GetStr(&config->proxy, nextarg);
00952         config->proxyver = CURLPROXY_HTTP_1_0;
00953         break;
00954       case '9': /* --tftp-blksize */
00955         err = str2unum(&config->tftp_blksize, nextarg);
00956         if(err)
00957           return err;
00958         break;
00959       case 'A': /* --mail-from */
00960         GetStr(&config->mail_from, nextarg);
00961         break;
00962       case 'B': /* --mail-rcpt */
00963         /* append receiver to a list */
00964         err = add2list(&config->mail_rcpt, nextarg);
00965         if(err)
00966           return err;
00967         break;
00968       case 'C': /* --ftp-pret */
00969         config->ftp_pret = toggle;
00970         break;
00971       case 'D': /* --proto */
00972         config->proto_present = TRUE;
00973         if(proto2num(config, &config->proto, nextarg))
00974           return PARAM_BAD_USE;
00975         break;
00976       case 'E': /* --proto-redir */
00977         config->proto_redir_present = TRUE;
00978         if(proto2num(config, &config->proto_redir, nextarg))
00979           return PARAM_BAD_USE;
00980         break;
00981       case 'F': /* --resolve */
00982         err = add2list(&config->resolve, nextarg);
00983         if(err)
00984           return err;
00985         break;
00986       case 'G': /* --delegation LEVEL */
00987         config->gssapi_delegation = delegation(config, nextarg);
00988         break;
00989       case 'H': /* --mail-auth */
00990         GetStr(&config->mail_auth, nextarg);
00991         break;
00992       case 'J': /* --metalink */
00993         {
00994 #ifdef USE_METALINK
00995           int mlmaj, mlmin, mlpatch;
00996           metalink_get_version(&mlmaj, &mlmin, &mlpatch);
00997           if((mlmaj*10000)+(mlmin*100)+mlpatch < CURL_REQ_LIBMETALINK_VERS) {
00998             warnf(global,
00999                   "--metalink option cannot be used because the version of "
01000                   "the linked libmetalink library is too old. "
01001                   "Required: %d.%d.%d, found %d.%d.%d\n",
01002                   CURL_REQ_LIBMETALINK_MAJOR,
01003                   CURL_REQ_LIBMETALINK_MINOR,
01004                   CURL_REQ_LIBMETALINK_PATCH,
01005                   mlmaj, mlmin, mlpatch);
01006             return PARAM_BAD_USE;
01007           }
01008           else
01009             config->use_metalink = toggle;
01010 #else
01011           warnf(global, "--metalink option is ignored because the binary is "
01012                 "built without the Metalink support.\n");
01013 #endif
01014           break;
01015         }
01016       case 'K': /* --sasl-ir */
01017         config->sasl_ir = toggle;
01018         break;
01019       case 'L': /* --test-event */
01020 #ifdef CURLDEBUG
01021         config->test_event_based = toggle;
01022 #else
01023         warnf(global, "--test-event is ignored unless a debug build!\n");
01024 #endif
01025         break;
01026       case 'M': /* --unix-socket */
01027         GetStr(&config->unix_socket_path, nextarg);
01028         break;
01029       case 'N': /* --path-as-is */
01030         config->path_as_is = toggle;
01031         break;
01032       case 'O': /* --proxy-service-name */
01033         GetStr(&config->proxy_service_name, nextarg);
01034         break;
01035       case 'P': /* --service-name */
01036         GetStr(&config->service_name, nextarg);
01037         break;
01038       case 'Q': /* --proto-default */
01039         GetStr(&config->proto_default, nextarg);
01040         err = check_protocol(config->proto_default);
01041         if(err)
01042           return err;
01043         break;
01044       case 'R': /* --expect100-timeout */
01045         err = str2udouble(&config->expect100timeout, nextarg);
01046         if(err)
01047           return err;
01048         break;
01049       case 'S': /* --tftp-no-options */
01050         config->tftp_no_options = toggle;
01051         break;
01052       case 'U': /* --connect-to */
01053         err = add2list(&config->connect_to, nextarg);
01054         if(err)
01055           return err;
01056         break;
01057       }
01058       break;
01059     case '#': /* --progress-bar */
01060       if(toggle)
01061         global->progressmode = CURL_PROGRESS_BAR;
01062       else
01063         global->progressmode = CURL_PROGRESS_STATS;
01064       break;
01065     case ':': /* --next */
01066       return PARAM_NEXT_OPERATION;
01067     case '0': /* --http* options */
01068       switch(subletter) {
01069       case '\0':
01070         /* HTTP version 1.0 */
01071         config->httpversion = CURL_HTTP_VERSION_1_0;
01072         break;
01073       case '1':
01074         /* HTTP version 1.1 */
01075         config->httpversion = CURL_HTTP_VERSION_1_1;
01076         break;
01077       case '2':
01078         /* HTTP version 2.0 */
01079         config->httpversion = CURL_HTTP_VERSION_2_0;
01080         break;
01081       case '3':
01082         /* HTTP version 2.0 over clean TCP*/
01083         config->httpversion = CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE;
01084         break;
01085       }
01086       break;
01087     case '1': /* --tlsv1* options */
01088       switch(subletter) {
01089       case '\0':
01090         /* TLS version 1.x */
01091         config->ssl_version = CURL_SSLVERSION_TLSv1;
01092         break;
01093       case '0':
01094         /* TLS version 1.0 */
01095         config->ssl_version = CURL_SSLVERSION_TLSv1_0;
01096         break;
01097       case '1':
01098         /* TLS version 1.1 */
01099         config->ssl_version = CURL_SSLVERSION_TLSv1_1;
01100         break;
01101       case '2':
01102         /* TLS version 1.2 */
01103         config->ssl_version = CURL_SSLVERSION_TLSv1_2;
01104         break;
01105       case '3':
01106         /* TLS version 1.3 */
01107         config->ssl_version = CURL_SSLVERSION_TLSv1_3;
01108         break;
01109       }
01110       break;
01111     case '2':
01112       /* SSL version 2 */
01113       config->ssl_version = CURL_SSLVERSION_SSLv2;
01114       break;
01115     case '3':
01116       /* SSL version 3 */
01117       config->ssl_version = CURL_SSLVERSION_SSLv3;
01118       break;
01119     case '4':
01120       /* IPv4 */
01121       config->ip_version = 4;
01122       break;
01123     case '6':
01124       /* IPv6 */
01125       config->ip_version = 6;
01126       break;
01127     case 'a':
01128       /* This makes the FTP sessions use APPE instead of STOR */
01129       config->ftp_append = toggle;
01130       break;
01131     case 'A':
01132       /* This specifies the User-Agent name */
01133       GetStr(&config->useragent, nextarg);
01134       break;
01135     case 'b': /* cookie string coming up: */
01136       if(nextarg[0] == '@') {
01137         nextarg++;
01138       }
01139       else if(strchr(nextarg, '=')) {
01140         /* A cookie string must have a =-letter */
01141         GetStr(&config->cookie, nextarg);
01142         break;
01143       }
01144       /* We have a cookie file to read from! */
01145       GetStr(&config->cookiefile, nextarg);
01146       break;
01147     case 'B':
01148       /* use ASCII/text when transferring */
01149       config->use_ascii = toggle;
01150       break;
01151     case 'c':
01152       /* get the file name to dump all cookies in */
01153       GetStr(&config->cookiejar, nextarg);
01154       break;
01155     case 'C':
01156       /* This makes us continue an ftp transfer at given position */
01157       if(strcmp(nextarg, "-")) {
01158         err = str2offset(&config->resume_from, nextarg);
01159         if(err)
01160           return err;
01161         config->resume_from_current = FALSE;
01162       }
01163       else {
01164         config->resume_from_current = TRUE;
01165         config->resume_from = 0;
01166       }
01167       config->use_resume=TRUE;
01168       break;
01169     case 'd':
01170       /* postfield data */
01171     {
01172       char *postdata = NULL;
01173       FILE *file;
01174       size_t size = 0;
01175       bool raw_mode = (subletter == 'r');
01176 
01177       if(subletter == 'e') { /* --data-urlencode*/
01178         /* [name]=[content], we encode the content part only
01179          * [name]@[file name]
01180          *
01181          * Case 2: we first load the file using that name and then encode
01182          * the content.
01183          */
01184         const char *p = strchr(nextarg, '=');
01185         size_t nlen;
01186         char is_file;
01187         if(!p)
01188           /* there was no '=' letter, check for a '@' instead */
01189           p = strchr(nextarg, '@');
01190         if(p) {
01191           nlen = p - nextarg; /* length of the name part */
01192           is_file = *p++; /* pass the separator */
01193         }
01194         else {
01195           /* neither @ nor =, so no name and it isn't a file */
01196           nlen = is_file = 0;
01197           p = nextarg;
01198         }
01199         if('@' == is_file) {
01200           /* a '@' letter, it means that a file name or - (stdin) follows */
01201           if(!strcmp("-", p)) {
01202             file = stdin;
01203             set_binmode(stdin);
01204           }
01205           else {
01206             file = fopen(p, "rb");
01207             if(!file)
01208               warnf(global,
01209                     "Couldn't read data from file \"%s\", this makes "
01210                     "an empty POST.\n", nextarg);
01211           }
01212 
01213           err = file2memory(&postdata, &size, file);
01214 
01215           if(file && (file != stdin))
01216             fclose(file);
01217           if(err)
01218             return err;
01219         }
01220         else {
01221           GetStr(&postdata, p);
01222           if(postdata)
01223             size = strlen(postdata);
01224         }
01225 
01226         if(!postdata) {
01227           /* no data from the file, point to a zero byte string to make this
01228              get sent as a POST anyway */
01229           postdata = strdup("");
01230           if(!postdata)
01231             return PARAM_NO_MEM;
01232           size = 0;
01233         }
01234         else {
01235           char *enc = curl_easy_escape(config->easy, postdata, (int)size);
01236           Curl_safefree(postdata); /* no matter if it worked or not */
01237           if(enc) {
01238             /* now make a string with the name from above and append the
01239                encoded string */
01240             size_t outlen = nlen + strlen(enc) + 2;
01241             char *n = malloc(outlen);
01242             if(!n) {
01243               curl_free(enc);
01244               return PARAM_NO_MEM;
01245             }
01246             if(nlen > 0) { /* only append '=' if we have a name */
01247               snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
01248               size = outlen-1;
01249             }
01250             else {
01251               strcpy(n, enc);
01252               size = outlen-2; /* since no '=' was inserted */
01253             }
01254             curl_free(enc);
01255             postdata = n;
01256           }
01257           else
01258             return PARAM_NO_MEM;
01259         }
01260       }
01261       else if('@' == *nextarg && !raw_mode) {
01262         /* the data begins with a '@' letter, it means that a file name
01263            or - (stdin) follows */
01264         nextarg++; /* pass the @ */
01265 
01266         if(!strcmp("-", nextarg)) {
01267           file = stdin;
01268           if(subletter == 'b') /* forced data-binary */
01269             set_binmode(stdin);
01270         }
01271         else {
01272           file = fopen(nextarg, "rb");
01273           if(!file)
01274             warnf(global, "Couldn't read data from file \"%s\", this makes "
01275                   "an empty POST.\n", nextarg);
01276         }
01277 
01278         if(subletter == 'b')
01279           /* forced binary */
01280           err = file2memory(&postdata, &size, file);
01281         else {
01282           err = file2string(&postdata, file);
01283           if(postdata)
01284             size = strlen(postdata);
01285         }
01286 
01287         if(file && (file != stdin))
01288           fclose(file);
01289         if(err)
01290           return err;
01291 
01292         if(!postdata) {
01293           /* no data from the file, point to a zero byte string to make this
01294              get sent as a POST anyway */
01295           postdata = strdup("");
01296           if(!postdata)
01297             return PARAM_NO_MEM;
01298         }
01299       }
01300       else {
01301         GetStr(&postdata, nextarg);
01302         if(postdata)
01303           size = strlen(postdata);
01304       }
01305 
01306 #ifdef CURL_DOES_CONVERSIONS
01307       if(subletter != 'b') {
01308         /* NOT forced binary, convert to ASCII */
01309         if(convert_to_network(postdata, strlen(postdata))) {
01310           Curl_safefree(postdata);
01311           return PARAM_NO_MEM;
01312         }
01313       }
01314 #endif
01315 
01316       if(config->postfields) {
01317         /* we already have a string, we append this one with a separating
01318            &-letter */
01319         char *oldpost = config->postfields;
01320         curl_off_t oldlen = config->postfieldsize;
01321         curl_off_t newlen = oldlen + curlx_uztoso(size) + 2;
01322         config->postfields = malloc((size_t)newlen);
01323         if(!config->postfields) {
01324           Curl_safefree(oldpost);
01325           Curl_safefree(postdata);
01326           return PARAM_NO_MEM;
01327         }
01328         memcpy(config->postfields, oldpost, (size_t)oldlen);
01329         /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */
01330         config->postfields[oldlen] = '\x26';
01331         memcpy(&config->postfields[oldlen+1], postdata, size);
01332         config->postfields[oldlen+1+size] = '\0';
01333         Curl_safefree(oldpost);
01334         Curl_safefree(postdata);
01335         config->postfieldsize += size+1;
01336       }
01337       else {
01338         config->postfields = postdata;
01339         config->postfieldsize = curlx_uztoso(size);
01340       }
01341     }
01342     /*
01343       We can't set the request type here, as this data might be used in
01344       a simple GET if -G is used. Already or soon.
01345 
01346       if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) {
01347         Curl_safefree(postdata);
01348         return PARAM_BAD_USE;
01349       }
01350     */
01351     break;
01352     case 'D':
01353       /* dump-header to given file name */
01354       GetStr(&config->headerfile, nextarg);
01355       break;
01356     case 'e':
01357     {
01358       char *ptr = strstr(nextarg, ";auto");
01359       if(ptr) {
01360         /* Automatic referer requested, this may be combined with a
01361            set initial one */
01362         config->autoreferer = TRUE;
01363         *ptr = 0; /* zero terminate here */
01364       }
01365       else
01366         config->autoreferer = FALSE;
01367       GetStr(&config->referer, nextarg);
01368     }
01369     break;
01370     case 'E':
01371       switch(subletter) {
01372       case '\0': /* certificate file */
01373         GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
01374         break;
01375       case 'a': /* CA info PEM file */
01376         /* CA info PEM file */
01377         GetStr(&config->cacert, nextarg);
01378         break;
01379       case 'b': /* cert file type */
01380         GetStr(&config->cert_type, nextarg);
01381         break;
01382       case 'c': /* private key file */
01383         GetStr(&config->key, nextarg);
01384         break;
01385       case 'd': /* private key file type */
01386         GetStr(&config->key_type, nextarg);
01387         break;
01388       case 'e': /* private key passphrase */
01389         GetStr(&config->key_passwd, nextarg);
01390         cleanarg(nextarg);
01391         break;
01392       case 'f': /* crypto engine */
01393         GetStr(&config->engine, nextarg);
01394         if(config->engine && curl_strequal(config->engine, "list"))
01395           return PARAM_ENGINES_REQUESTED;
01396         break;
01397       case 'g': /* CA info PEM file */
01398         /* CA cert directory */
01399         GetStr(&config->capath, nextarg);
01400         break;
01401       case 'h': /* --pubkey public key file */
01402         GetStr(&config->pubkey, nextarg);
01403         break;
01404       case 'i': /* --hostpubmd5 md5 of the host public key */
01405         GetStr(&config->hostpubmd5, nextarg);
01406         if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
01407           return PARAM_BAD_USE;
01408         break;
01409       case 'j': /* CRL info PEM file */
01410         /* CRL file */
01411         GetStr(&config->crlfile, nextarg);
01412         break;
01413       case 'k': /* TLS username */
01414         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
01415           GetStr(&config->tls_username, nextarg);
01416         else
01417           return PARAM_LIBCURL_DOESNT_SUPPORT;
01418         break;
01419       case 'l': /* TLS password */
01420         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
01421           GetStr(&config->tls_password, nextarg);
01422         else
01423           return PARAM_LIBCURL_DOESNT_SUPPORT;
01424         break;
01425       case 'm': /* TLS authentication type */
01426         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
01427           GetStr(&config->tls_authtype, nextarg);
01428           if(!curl_strequal(config->tls_authtype, "SRP"))
01429             return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
01430         }
01431         else
01432           return PARAM_LIBCURL_DOESNT_SUPPORT;
01433         break;
01434       case 'n': /* no empty SSL fragments, --ssl-allow-beast */
01435         if(curlinfo->features & CURL_VERSION_SSL)
01436           config->ssl_allow_beast = toggle;
01437         break;
01438 
01439       case 'o': /* --login-options */
01440         GetStr(&config->login_options, nextarg);
01441         break;
01442 
01443       case 'p': /* Pinned public key DER file */
01444         /* Pinned public key DER file */
01445         GetStr(&config->pinnedpubkey, nextarg);
01446         break;
01447 
01448       case 'q': /* --cert-status */
01449         config->verifystatus = TRUE;
01450         break;
01451 
01452       case 'r': /* --false-start */
01453         config->falsestart = TRUE;
01454         break;
01455 
01456       case 's': /* --ssl-no-revoke */
01457         if(curlinfo->features & CURL_VERSION_SSL)
01458           config->ssl_no_revoke = TRUE;
01459         break;
01460 
01461       case 't': /* --tcp-fastopen */
01462         config->tcp_fastopen = TRUE;
01463         break;
01464 
01465       case 'u': /* TLS username for proxy */
01466         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
01467           GetStr(&config->proxy_tls_username, nextarg);
01468         else
01469           return PARAM_LIBCURL_DOESNT_SUPPORT;
01470         break;
01471 
01472       case 'v': /* TLS password for proxy */
01473         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
01474           GetStr(&config->proxy_tls_password, nextarg);
01475         else
01476           return PARAM_LIBCURL_DOESNT_SUPPORT;
01477         break;
01478 
01479       case 'w': /* TLS authentication type for proxy */
01480         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
01481           GetStr(&config->proxy_tls_authtype, nextarg);
01482           if(!curl_strequal(config->proxy_tls_authtype, "SRP"))
01483             return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
01484         }
01485         else
01486           return PARAM_LIBCURL_DOESNT_SUPPORT;
01487         break;
01488 
01489       case 'x': /* certificate file for proxy */
01490         GetFileAndPassword(nextarg, &config->proxy_cert,
01491                            &config->proxy_key_passwd);
01492         break;
01493 
01494       case 'y': /* cert file type for proxy */
01495         GetStr(&config->proxy_cert_type, nextarg);
01496         break;
01497 
01498       case 'z': /* private key file for proxy */
01499         GetStr(&config->proxy_key, nextarg);
01500         break;
01501 
01502       case '0': /* private key file type for proxy */
01503         GetStr(&config->proxy_key_type, nextarg);
01504         break;
01505 
01506       case '1': /* private key passphrase for proxy */
01507         GetStr(&config->proxy_key_passwd, nextarg);
01508         cleanarg(nextarg);
01509         break;
01510 
01511       case '2': /* ciphers for proxy */
01512         GetStr(&config->proxy_cipher_list, nextarg);
01513         break;
01514 
01515       case '3': /* CRL info PEM file for proxy */
01516         /* CRL file */
01517         GetStr(&config->proxy_crlfile, nextarg);
01518         break;
01519 
01520       case '4': /* no empty SSL fragments for proxy */
01521         if(curlinfo->features & CURL_VERSION_SSL)
01522           config->proxy_ssl_allow_beast = toggle;
01523         break;
01524 
01525       case '5': /* --login-options */
01526         GetStr(&config->login_options, nextarg);
01527         break;
01528 
01529       case '6': /* CA info PEM file for proxy */
01530         /* CA info PEM file */
01531         GetStr(&config->proxy_cacert, nextarg);
01532         break;
01533 
01534       case '7': /* CA info PEM file for proxy */
01535         /* CA cert directory */
01536         GetStr(&config->proxy_capath, nextarg);
01537         break;
01538 
01539       case '8': /* allow insecure SSL connects for proxy */
01540         config->proxy_insecure_ok = toggle;
01541         break;
01542 
01543       case '9':
01544         /* TLS version 1 for proxy */
01545         config->proxy_ssl_version = CURL_SSLVERSION_TLSv1;
01546         break;
01547 
01548       default: /* unknown flag */
01549         return PARAM_OPTION_UNKNOWN;
01550       }
01551       break;
01552     case 'f':
01553       switch(subletter) {
01554       case 'a': /* --fail-early */
01555         global->fail_early = toggle;
01556         break;
01557       default:
01558         /* fail hard on errors  */
01559         config->failonerror = toggle;
01560       }
01561       break;
01562     case 'F':
01563       /* "form data" simulation, this is a little advanced so lets do our best
01564          to sort this out slowly and carefully */
01565       if(formparse(config,
01566                    nextarg,
01567                    &config->httppost,
01568                    &config->last_post,
01569                    (subletter=='s')?TRUE:FALSE)) /* 's' means literal string */
01570         return PARAM_BAD_USE;
01571       if(SetHTTPrequest(config, HTTPREQ_FORMPOST, &config->httpreq))
01572         return PARAM_BAD_USE;
01573       break;
01574 
01575     case 'g': /* g disables URLglobbing */
01576       config->globoff = toggle;
01577       break;
01578 
01579     case 'G': /* HTTP GET */
01580       config->use_httpget = TRUE;
01581       break;
01582 
01583     case 'h': /* h for help */
01584       if(toggle) {
01585         return PARAM_HELP_REQUESTED;
01586       }
01587       /* we now actually support --no-help too! */
01588       break;
01589     case 'H':
01590       /* A custom header to append to a list */
01591       if(subletter == 'p') /* --proxy-header */
01592         err = add2list(&config->proxyheaders, nextarg);
01593       else
01594         err = add2list(&config->headers, nextarg);
01595       if(err)
01596         return err;
01597       break;
01598     case 'i':
01599       config->include_headers = toggle; /* include the headers as well in the
01600                                            general output stream */
01601       break;
01602     case 'j':
01603       config->cookiesession = toggle;
01604       break;
01605     case 'I':
01606       /*
01607        * no_body will imply include_headers later on
01608        */
01609       config->no_body = toggle;
01610       if(SetHTTPrequest(config,
01611                         (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
01612                         &config->httpreq))
01613         return PARAM_BAD_USE;
01614       break;
01615     case 'J': /* --remote-header-name */
01616       if(config->include_headers) {
01617         warnf(global,
01618               "--include and --remote-header-name cannot be combined.\n");
01619         return PARAM_BAD_USE;
01620       }
01621       config->content_disposition = toggle;
01622       break;
01623     case 'k': /* allow insecure SSL connects */
01624       config->insecure_ok = toggle;
01625       break;
01626     case 'K': /* parse config file */
01627       if(parseconfig(nextarg, global))
01628         warnf(global, "error trying read config from the '%s' file\n",
01629               nextarg);
01630       break;
01631     case 'l':
01632       config->dirlistonly = toggle; /* only list the names of the FTP dir */
01633       break;
01634     case 'L':
01635       config->followlocation = toggle; /* Follow Location: HTTP headers */
01636       switch(subletter) {
01637       case 't':
01638         /* Continue to send authentication (user+password) when following
01639          * locations, even when hostname changed */
01640         config->unrestricted_auth = toggle;
01641         break;
01642       }
01643       break;
01644     case 'm':
01645       /* specified max time */
01646       err = str2udouble(&config->timeout, nextarg);
01647       if(err)
01648         return err;
01649       break;
01650     case 'M': /* M for manual, huge help */
01651       if(toggle) { /* --no-manual shows no manual... */
01652 #ifdef USE_MANUAL
01653         return PARAM_MANUAL_REQUESTED;
01654 #else
01655         warnf(global,
01656               "built-in manual was disabled at build-time!\n");
01657         return PARAM_OPTION_UNKNOWN;
01658 #endif
01659       }
01660       break;
01661     case 'n':
01662       switch(subletter) {
01663       case 'o': /* CA info PEM file */
01664         /* use .netrc or URL */
01665         config->netrc_opt = toggle;
01666         break;
01667       case 'e': /* netrc-file */
01668         GetStr(&config->netrc_file, nextarg);
01669         break;
01670       default:
01671         /* pick info from .netrc, if this is used for http, curl will
01672            automatically enfore user+password with the request */
01673         config->netrc = toggle;
01674         break;
01675       }
01676       break;
01677     case 'N':
01678       /* disable the output I/O buffering. note that the option is called
01679          --buffer but is mostly used in the negative form: --no-buffer */
01680       if(longopt)
01681         config->nobuffer = (!toggle)?TRUE:FALSE;
01682       else
01683         config->nobuffer = toggle;
01684       break;
01685     case 'O': /* --remote-name */
01686       if(subletter == 'a') { /* --remote-name-all */
01687         config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
01688         break;
01689       }
01690       /* fall-through! */
01691     case 'o': /* --output */
01692       /* output file */
01693     {
01694       struct getout *url;
01695       if(!config->url_out)
01696         config->url_out = config->url_list;
01697       if(config->url_out) {
01698         /* there's a node here, if it already is filled-in continue to find
01699            an "empty" node */
01700         while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
01701           config->url_out = config->url_out->next;
01702       }
01703 
01704       /* now there might or might not be an available node to fill in! */
01705 
01706       if(config->url_out)
01707         /* existing node */
01708         url = config->url_out;
01709       else
01710         /* there was no free node, create one! */
01711         url = new_getout(config);
01712 
01713       if(!url)
01714         return PARAM_NO_MEM;
01715       else {
01716         /* fill in the outfile */
01717         if('o' == letter) {
01718           GetStr(&url->outfile, nextarg);
01719           url->flags &= ~GETOUT_USEREMOTE; /* switch off */
01720         }
01721         else {
01722           url->outfile = NULL; /* leave it */
01723           if(toggle)
01724             url->flags |= GETOUT_USEREMOTE;  /* switch on */
01725           else
01726             url->flags &= ~GETOUT_USEREMOTE; /* switch off */
01727         }
01728         url->flags |= GETOUT_OUTFILE;
01729       }
01730     }
01731     break;
01732     case 'P':
01733       /* This makes the FTP sessions use PORT instead of PASV */
01734       /* use <eth0> or <192.168.10.10> style addresses. Anything except
01735          this will make us try to get the "default" address.
01736          NOTE: this is a changed behaviour since the released 4.1!
01737       */
01738       GetStr(&config->ftpport, nextarg);
01739       break;
01740     case 'p':
01741       /* proxy tunnel for non-http protocols */
01742       config->proxytunnel = toggle;
01743       break;
01744 
01745     case 'q': /* if used first, already taken care of, we do it like
01746                  this so we don't cause an error! */
01747       break;
01748     case 'Q':
01749       /* QUOTE command to send to FTP server */
01750       switch(nextarg[0]) {
01751       case '-':
01752         /* prefixed with a dash makes it a POST TRANSFER one */
01753         nextarg++;
01754         err = add2list(&config->postquote, nextarg);
01755         break;
01756       case '+':
01757         /* prefixed with a plus makes it a just-before-transfer one */
01758         nextarg++;
01759         err = add2list(&config->prequote, nextarg);
01760         break;
01761       default:
01762         err = add2list(&config->quote, nextarg);
01763         break;
01764       }
01765       if(err)
01766         return err;
01767       break;
01768     case 'r':
01769       /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
01770          (and won't actually be range by definition). The man page previously
01771          claimed that to be a good way, why this code is added to work-around
01772          it. */
01773       if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
01774         char buffer[32];
01775         curl_off_t off;
01776         warnf(global,
01777               "A specified range MUST include at least one dash (-). "
01778               "Appending one for you!\n");
01779         off = curlx_strtoofft(nextarg, NULL, 10);
01780         snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
01781         Curl_safefree(config->range);
01782         config->range = strdup(buffer);
01783         if(!config->range)
01784           return PARAM_NO_MEM;
01785       }
01786       {
01787         /* byte range requested */
01788         char *tmp_range;
01789         tmp_range = nextarg;
01790         while(*tmp_range != '\0') {
01791           if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
01792             warnf(global, "Invalid character is found in given range. "
01793                   "A specified range MUST have only digits in "
01794                   "\'start\'-\'stop\'. The server's response to this "
01795                   "request is uncertain.\n");
01796             break;
01797           }
01798           tmp_range++;
01799         }
01800         /* byte range requested */
01801         GetStr(&config->range, nextarg);
01802       }
01803       break;
01804     case 'R':
01805       /* use remote file's time */
01806       config->remote_time = toggle;
01807       break;
01808     case 's':
01809       /* don't show progress meter, don't show errors : */
01810       if(toggle)
01811         global->mute = global->noprogress = TRUE;
01812       else
01813         global->mute = global->noprogress = FALSE;
01814       if(global->showerror < 0)
01815         /* if still on the default value, set showerror to the reverse of
01816            toggle. This is to allow -S and -s to be used in an independent
01817            order but still have the same effect. */
01818         global->showerror = (!toggle)?TRUE:FALSE; /* toggle off */
01819       break;
01820     case 'S':
01821       /* show errors */
01822       global->showerror = toggle?1:0; /* toggle on if used with -s */
01823       break;
01824     case 't':
01825       /* Telnet options */
01826       err = add2list(&config->telnet_options, nextarg);
01827       if(err)
01828         return err;
01829       break;
01830     case 'T':
01831       /* we are uploading */
01832     {
01833       struct getout *url;
01834       if(!config->url_out)
01835         config->url_out = config->url_list;
01836       if(config->url_out) {
01837         /* there's a node here, if it already is filled-in continue to find
01838            an "empty" node */
01839         while(config->url_out && (config->url_out->flags & GETOUT_UPLOAD))
01840           config->url_out = config->url_out->next;
01841       }
01842 
01843       /* now there might or might not be an available node to fill in! */
01844 
01845       if(config->url_out)
01846         /* existing node */
01847         url = config->url_out;
01848       else
01849         /* there was no free node, create one! */
01850         url = new_getout(config);
01851 
01852       if(!url)
01853         return PARAM_NO_MEM;
01854       else {
01855         url->flags |= GETOUT_UPLOAD; /* mark -T used */
01856         if(!*nextarg)
01857           url->flags |= GETOUT_NOUPLOAD;
01858         else {
01859           /* "-" equals stdin, but keep the string around for now */
01860           GetStr(&url->infile, nextarg);
01861         }
01862       }
01863     }
01864     break;
01865     case 'u':
01866       /* user:password  */
01867       GetStr(&config->userpwd, nextarg);
01868       cleanarg(nextarg);
01869       break;
01870     case 'U':
01871       /* Proxy user:password  */
01872       GetStr(&config->proxyuserpwd, nextarg);
01873       cleanarg(nextarg);
01874       break;
01875     case 'v':
01876       if(toggle) {
01877         /* the '%' thing here will cause the trace get sent to stderr */
01878         Curl_safefree(global->trace_dump);
01879         global->trace_dump = strdup("%");
01880         if(!global->trace_dump)
01881           return PARAM_NO_MEM;
01882         if(global->tracetype && (global->tracetype != TRACE_PLAIN))
01883           warnf(global,
01884                 "-v, --verbose overrides an earlier trace/verbose option\n");
01885         global->tracetype = TRACE_PLAIN;
01886       }
01887       else
01888         /* verbose is disabled here */
01889         global->tracetype = TRACE_NONE;
01890       break;
01891     case 'V':
01892       if(toggle)    /* --no-version yields no output! */
01893         return PARAM_VERSION_INFO_REQUESTED;
01894       break;
01895 
01896     case 'w':
01897       /* get the output string */
01898       if('@' == *nextarg) {
01899         /* the data begins with a '@' letter, it means that a file name
01900            or - (stdin) follows */
01901         FILE *file;
01902         const char *fname;
01903         nextarg++; /* pass the @ */
01904         if(!strcmp("-", nextarg)) {
01905           fname = "<stdin>";
01906           file = stdin;
01907         }
01908         else {
01909           fname = nextarg;
01910           file = fopen(nextarg, FOPEN_READTEXT);
01911         }
01912         err = file2string(&config->writeout, file);
01913         if(file && (file != stdin))
01914           fclose(file);
01915         if(err)
01916           return err;
01917         if(!config->writeout)
01918           warnf(global, "Failed to read %s", fname);
01919       }
01920       else
01921         GetStr(&config->writeout, nextarg);
01922       break;
01923     case 'x':
01924       switch(subletter) {
01925       case 'a': /* --preproxy */
01926         GetStr(&config->preproxy, nextarg);
01927         break;
01928       default:
01929         /* --proxy */
01930         GetStr(&config->proxy, nextarg);
01931         config->proxyver = CURLPROXY_HTTP;
01932         break;
01933       }
01934       break;
01935     case 'X':
01936       /* set custom request */
01937       GetStr(&config->customrequest, nextarg);
01938       break;
01939     case 'y':
01940       /* low speed time */
01941       err = str2unum(&config->low_speed_time, nextarg);
01942       if(err)
01943         return err;
01944       if(!config->low_speed_limit)
01945         config->low_speed_limit = 1;
01946       break;
01947     case 'Y':
01948       /* low speed limit */
01949       err = str2unum(&config->low_speed_limit, nextarg);
01950       if(err)
01951         return err;
01952       if(!config->low_speed_time)
01953         config->low_speed_time = 30;
01954       break;
01955     case 'z': /* time condition coming up */
01956       switch(*nextarg) {
01957       case '+':
01958         nextarg++;
01959         /* FALLTHROUGH */
01960       default:
01961         /* If-Modified-Since: (section 14.28 in RFC2068) */
01962         config->timecond = CURL_TIMECOND_IFMODSINCE;
01963         break;
01964       case '-':
01965         /* If-Unmodified-Since:  (section 14.24 in RFC2068) */
01966         config->timecond = CURL_TIMECOND_IFUNMODSINCE;
01967         nextarg++;
01968         break;
01969       case '=':
01970         /* Last-Modified:  (section 14.29 in RFC2068) */
01971         config->timecond = CURL_TIMECOND_LASTMOD;
01972         nextarg++;
01973         break;
01974       }
01975       now = time(NULL);
01976       config->condtime=curl_getdate(nextarg, &now);
01977       if(-1 == (int)config->condtime) {
01978         /* now let's see if it is a file name to get the time from instead! */
01979         struct_stat statbuf;
01980         if(-1 == stat(nextarg, &statbuf)) {
01981           /* failed, remove time condition */
01982           config->timecond = CURL_TIMECOND_NONE;
01983           warnf(global,
01984                 "Illegal date format for -z, --timecond (and not "
01985                 "a file name). Disabling time condition. "
01986                 "See curl_getdate(3) for valid date syntax.\n");
01987         }
01988         else {
01989           /* pull the time out from the file */
01990           config->condtime = statbuf.st_mtime;
01991         }
01992       }
01993       break;
01994     default: /* unknown flag */
01995       return PARAM_OPTION_UNKNOWN;
01996     }
01997     hit = -1;
01998 
01999   } while(!longopt && !singleopt && *++parse && !*usedarg);
02000 
02001   return PARAM_OK;
02002 }
02003 
02004 ParameterError parse_args(struct GlobalConfig *config, int argc,
02005                           argv_item_t argv[])
02006 {
02007   int i;
02008   bool stillflags;
02009   char *orig_opt = NULL;
02010   ParameterError result = PARAM_OK;
02011   struct OperationConfig *operation = config->first;
02012 
02013   for(i = 1, stillflags = TRUE; i < argc && !result; i++) {
02014     orig_opt = argv[i];
02015 
02016     if(stillflags && ('-' == argv[i][0])) {
02017       char *nextarg;
02018       bool passarg;
02019       char *flag = argv[i];
02020 
02021       if(!strcmp("--", argv[i]))
02022         /* This indicates the end of the flags and thus enables the
02023            following (URL) argument to start with -. */
02024         stillflags = FALSE;
02025       else {
02026         nextarg = (i < (argc - 1)) ? argv[i + 1] : NULL;
02027 
02028         result = getparameter(flag, nextarg, &passarg, config, operation);
02029         if(result == PARAM_NEXT_OPERATION) {
02030           /* Reset result as PARAM_NEXT_OPERATION is only used here and not
02031              returned from this function */
02032           result = PARAM_OK;
02033 
02034           if(operation->url_list && operation->url_list->url) {
02035             /* Allocate the next config */
02036             operation->next = malloc(sizeof(struct OperationConfig));
02037             if(operation->next) {
02038               /* Initialise the newly created config */
02039               config_init(operation->next);
02040 
02041               /* Copy the easy handle */
02042               operation->next->easy = config->easy;
02043 
02044               /* Set the global config pointer */
02045               operation->next->global = config;
02046 
02047               /* Update the last operation pointer */
02048               config->last = operation->next;
02049 
02050               /* Move onto the new config */
02051               operation->next->prev = operation;
02052               operation = operation->next;
02053             }
02054             else
02055               result = PARAM_NO_MEM;
02056           }
02057         }
02058         else if(!result && passarg)
02059           i++; /* we're supposed to skip this */
02060       }
02061     }
02062     else {
02063       bool used;
02064 
02065       /* Just add the URL please */
02066       result = getparameter((char *)"--url", argv[i], &used, config,
02067                             operation);
02068     }
02069   }
02070 
02071   if(result && result != PARAM_HELP_REQUESTED &&
02072      result != PARAM_MANUAL_REQUESTED &&
02073      result != PARAM_VERSION_INFO_REQUESTED &&
02074      result != PARAM_ENGINES_REQUESTED) {
02075     const char *reason = param2text(result);
02076 
02077     if(orig_opt && strcmp(":", orig_opt))
02078       helpf(config->errors, "option %s: %s\n", orig_opt, reason);
02079     else
02080       helpf(config->errors, "%s\n", reason);
02081   }
02082 
02083   return result;
02084 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:07