Skip to content
Snippets Groups Projects
main.c 74.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"T", "upload-file", TRUE},
        {"u", "user",        TRUE},
        {"U", "proxy-user",  TRUE},
        {"v", "verbose",     FALSE},
        {"V", "version",     FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"x", "proxy",       TRUE},
        {"X", "request",     TRUE},
        {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
    
        {"Y", "speed-limit",  TRUE},
        {"y", "speed-time", TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"z", "time-cond",   TRUE},
    
        {"Z", "max-redirs",   TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"#", "progress-bar",FALSE},
      };
    
    
      if(('-' != flag[0]) ||
         (('-' == flag[0]) && ('-' == flag[1]))) {
        /* this should be a long name */
        char *word=('-' == flag[0])?flag+2:flag;
        int fnam=strlen(word);
    
        int numhits=0;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
    
          if(strnequal(aliases[j].lname, word, fnam)) {
    
            longopt = TRUE;
    
            if(strequal(aliases[j].lname, word)) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              parse = aliases[j].letter;
              hit = j;
    
              numhits = 1; /* a single unique hit */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              break;
            }
    	parse = aliases[j].letter;
    	hit = j;
          }
        }
    
        if(numhits>1) {
          /* this is at least the second match! */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if(hit < 0) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }    
      }
      else {
    
        flag++; /* prefixed with one dash, pass it */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        hit=-1;
        parse = flag;
      }
    
      do {
        /* we can loop here if we have multiple single-letters */
    
    
        if(!longopt)
          letter = parse?*parse:'\0';
        else {
          letter = parse[0];
          subletter = parse[1];
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        *usedarg = FALSE; /* default is that we don't use the arg */
    
    #if 0
        fprintf(stderr, "OPTION: %c %s\n", letter, nextarg?nextarg:"<null>");
    #endif
        if(hit < 0) {
          for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
    
    	if(letter == aliases[j].letter[0]) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	  hit = j;
    	  break;
    	}
          }
          if(hit < 0) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
        }
        if(hit < 0) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }    
    
        if(!longopt && aliases[hit].extraparam && parse[1]) {
    
          nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
    
          singleopt=TRUE;   /* don't loop anymore after this */
        }
        else if((!nextarg || !*nextarg) && aliases[hit].extraparam) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        else if(nextarg && aliases[hit].extraparam)
          *usedarg = TRUE; /* mark it as used */
    
        switch(letter) {
        case '9': /* there is no short letter for this */
          /* LF -> CRLF conversinon? */
          config->crlf = TRUE;
          break;
        case '8': /* there is no short letter for this */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            config->errors = fopen(nextarg, "wt");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          else
            config->errors = stdout;
          break;
    
        case '7': /* there is no short letter for this */
          /* interface */
    
          GetStr(&config->iface, nextarg);
          break;
        case '6': /* there is no short letter for this */
          /* krb4 level string */
          GetStr(&config->krb4level, nextarg);
          break;
    
          switch(subletter) {
          case 'a': /* random-file */
            GetStr(&config->random_file, nextarg);
            break;
          case 'b': /* egd-file */
            GetStr(&config->egd_file, nextarg);
            break;
    
          case 'c': /* connect-timeout */
            config->connecttimeout=atoi(nextarg);
            break;
    
          case 'd': /* ciphers */
            GetStr(&config->cipher_list, nextarg);
            break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          case 'e': /* --disable-epsv */
            config->disable_epsv ^= TRUE;
            break;
    
          default: /* the URL! */
            {
              struct getout *url;
              if(config->url_get || (config->url_get=config->url_list)) {
                /* there's a node here, if it already is filled-in continue to find
                   an "empty" node */
                while(config->url_get && (config->url_get->flags&GETOUT_URL))
                  config->url_get = config->url_get->next;
              }
    
              /* now there might or might not be an available node to fill in! */
    
              if(config->url_get)
                /* existing node */
                url = config->url_get;
              else
                /* there was no free node, create one! */
                url=new_getout(config);
              
              if(url) {
                /* fill in the URL */
                GetStr(&url->url, nextarg);
                url->flags |= GETOUT_URL;
              }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case '#': /* added 19990617 larsa */
          config->progressmode ^= CURL_PROGRESS_BAR;
          break;
    
        case '0': 
          /* HTTP version 1.0 */
          config->httpversion = CURL_HTTP_VERSION_1_0;
          break;
    
        case '1':
          /* TLS version 1 */
          config->ssl_version = CURL_SSLVERSION_TLSv1;
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case '2': 
          /* SSL version 2 */
    
          config->ssl_version = CURL_SSLVERSION_SSLv2;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case '3': 
    
          /* SSL version 3 */
          config->ssl_version = CURL_SSLVERSION_SSLv3;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'a':
          /* This makes the FTP sessions use APPE instead of STOR */
          config->conf ^= CONF_FTPAPPEND;
          break;
        case 'A':
          /* This specifies the User-Agent name */
          GetStr(&config->useragent, nextarg);
          break;
        case 'b': /* cookie string coming up: */
    
          if(nextarg[0] == '@') {
            nextarg++;
          }
          else if(strchr(nextarg, '=')) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            /* A cookie string must have a =-letter */
            GetStr(&config->cookie, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
          /* We have a cookie file to read from! */
          GetStr(&config->cookiefile, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'B':
    
          /* use ASCII/text when transfering */
          config->conf ^= CONF_GETTEXT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'c':
    
          /* get the file name to dump all cookies in */
          GetStr(&config->cookiejar, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'C':
          /* This makes us continue an ftp transfer at given position */
    
            config->resume_from= atoi(nextarg);
    
            config->resume_from_current = FALSE;
          }
          else {
            config->resume_from_current = TRUE;
            config->resume_from = 0;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          config->use_resume=TRUE;
          break;
        case 'd':
          /* postfield data */
    
          {
            char *postdata=NULL;
    
            if('@' == *nextarg) {
              /* the data begins with a '@' letter, it means that a file name
                 or - (stdin) follows */
              FILE *file;
    
              nextarg++; /* pass the @ */
    
              if(strequal("-", nextarg))
                file = stdin;
              else 
    
    
              if(subletter == 'b') /* forced binary */
                postdata = file2memory(file, &config->postfieldsize);
              else
                postdata = file2string(file);
              if(file && (file != stdin))
                fclose(stdin);
            }
            else {
              GetStr(&postdata, nextarg);
            }
    
            if(config->postfields && *config->postfields) {
              /* we already have a string, we append this one
                 with a separating &-letter */
              char *oldpost=config->postfields;
    
              config->postfields=aprintf("%s&%s", oldpost, postdata);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
          /*
            We can't set the request type here, as this data might be used in
            a simple GET if -G is used. Already or soon.
    
            if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
              return PARAM_BAD_USE;
          */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'D':
          /* dump-header to given file name */
          GetStr(&config->headerfile, nextarg);
          break;
        case 'e':
    
          {
            char *ptr = strstr(nextarg, ";auto");
            if(ptr) {
              /* Automatic referer requested, this may be combined with a
                 set initial one */
              config->conf |= CONF_AUTO_REFERER;
              *ptr = 0; /* zero terminate here */
            }
            GetStr(&config->referer, nextarg);
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'E':
    
          switch(subletter) {
          case 'a': /* CA info PEM file */
    
            /* CA info PEM file */
            GetStr(&config->cacert, nextarg);
    
            break;
          case 'b': /* cert file type */
            GetStr(&config->cert_type, nextarg);
            break;
          case 'c': /* private key file */
            GetStr(&config->key, nextarg);
            break;
          case 'd': /* private key file type */
            GetStr(&config->key_type, nextarg);
            break;
          case 'e': /* private key passphrase */
            GetStr(&config->key_passwd, nextarg);
            break;
          case 'f': /* crypto engine */
            GetStr(&config->engine, nextarg);
            break;
          default: /* certificate file */
            {
              char *ptr = strchr(nextarg, ':');
              /* Since we live in a world of weirdness and confusion, the win32
                 dudes can use : when using drive letters and thus
                 c:\file:password needs to work. In order not to break
                 compatibility, we still use : as separator, but we try to detect
                 when it is used for a file name! On windows. */
    
              if(ptr &&
                 (ptr == &nextarg[1]) &&
                 (nextarg[2] == '\\') &&
                 (isalpha((int)nextarg[0])) )
                 /* colon in the second column, followed by a backslash, and the
                    first character is an alphabetic letter:
    
                    this is a drive letter colon */
                ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
    
              if(ptr) {
                /* we have a password too */
                *ptr=0;
                ptr++;
                GetStr(&config->key_passwd, ptr);
              }
              GetStr(&config->cert, nextarg);
            }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
          break;
        case 'f':
          /* fail hard on errors  */
          config->conf ^= CONF_FAILONERROR;
          break;
        case 'F':
          /* "form data" simulation, this is a little advanced so lets do our best
    	 to sort this out slowly and carefully */
    
          if(formparse(nextarg,
                       &config->httppost,
                       &config->last_post))
    
          if(SetHTTPrequest(HTTPREQ_POST, &config->httpreq))
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
    
        case 'g': /* g disables URLglobbing */
          config->globoff ^= TRUE;
          break;
    
    
        case 'G': /* HTTP GET */
          config->use_httpget = TRUE;
          break;
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'h': /* h for help */
          help();
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'H':
    
          /* A custom header to append to a list */
          config->headers = curl_slist_append(config->headers, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'i':
          config->conf ^= CONF_HEADER; /* include the HTTP header as well */
          break;
        case 'I':
    
          /*
           * This is a bit tricky. We either SET both bits, or we clear both
           * bits. Let's not make any other outcomes from this.
           */
          if((CONF_HEADER|CONF_NOBODY) !=
             (config->conf&(CONF_HEADER|CONF_NOBODY)) ) {
            /* one of them weren't set, set both */
            config->conf |= (CONF_HEADER|CONF_NOBODY);
            if(SetHTTPrequest(HTTPREQ_HEAD, &config->httpreq))
              return PARAM_BAD_USE;
          }
          else {
            /* both were set, clear both */
            config->conf &= ~(CONF_HEADER|CONF_NOBODY);
            if(SetHTTPrequest(HTTPREQ_GET, &config->httpreq))
              return PARAM_BAD_USE;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'K':
          res = parseconfig(nextarg, config);
          config->configread = TRUE;
          if(res)
    	return res;
          break;
        case 'l':
          config->conf ^= CONF_FTPLISTONLY; /* only list the names of the FTP dir */
          break;
        case 'L':
          config->conf ^= CONF_FOLLOWLOCATION; /* Follow Location: HTTP headers */
          break;
        case 'm':
          /* specified max time */
          config->timeout = atoi(nextarg);
          break;
        case 'M': /* M for manual, huge help */
          hugehelp();
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'n':
          /* pick info from .netrc, if this is used for http, curl will
    	 automatically enfore user+password with the request */
          config->conf ^= CONF_NETRC;
          break;
    
        case 'N':
          /* disable the output I/O buffering */
          config->nobuffer ^= 1;
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'o':
        case 'O':
          /* output file */
    
          {
            struct getout *url;
            if(config->url_out || (config->url_out=config->url_list)) {
              /* there's a node here, if it already is filled-in continue to find
                 an "empty" node */
              while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
                config->url_out = config->url_out->next;
            }
    
            /* now there might or might not be an available node to fill in! */
    
            if(config->url_out)
              /* existing node */
              url = config->url_out;
            else
              /* there was no free node, create one! */
              url=new_getout(config);
    
            if(url) {
              /* fill in the outfile */
              if('o' == letter)
                GetStr(&url->outfile, nextarg);
              else {
                url->outfile=NULL; /* leave it */
                url->flags |= GETOUT_USEREMOTE;
              }
              url->flags |= GETOUT_OUTFILE;
            }
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'P':
          /* This makes the FTP sessions use PORT instead of PASV */
          /* use <eth0> or <192.168.10.10> style addresses. Anything except
    	 this will make us try to get the "default" address.
    	 NOTE: this is a changed behaviour since the released 4.1!
    	 */
          GetStr(&config->ftpport, nextarg);
          break;
        case 'p':
    
          /* proxy tunnel for non-http protocols */
          config->proxytunnel ^= TRUE;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'q': /* if used first, already taken care of, we do it like
    		 this so we don't cause an error! */
          break;
        case 'Q':
          /* QUOTE command to send to FTP server */
    
          switch(nextarg[0]) {
          case '-':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            /* prefixed with a dash makes it a POST TRANSFER one */
            nextarg++;
            config->postquote = curl_slist_append(config->postquote, nextarg);
    
            break;
          case '+':
            /* prefixed with a plus makes it a just-before-transfer one */
            nextarg++;
            config->prequote = curl_slist_append(config->prequote, nextarg);
            break;
          default:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            config->quote = curl_slist_append(config->quote, nextarg);
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'r':
          /* byte range requested */
          GetStr(&config->range, nextarg);
          break;
    
        case 'R':
          /* use remote file's time */
          config->remote_time ^= TRUE;
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 's':
          /* don't show progress meter, don't show errors : */
          config->conf |= (CONF_MUTE|CONF_NOPROGRESS);
          config->showerror ^= TRUE; /* toggle off */
          break;
        case 'S':
          /* show errors */
          config->showerror ^= TRUE; /* toggle on if used with -s */
          break;
        case 't':
    
          /* Telnet options */
          config->telnet_options = curl_slist_append(config->telnet_options, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'T':
          /* we are uploading */
          config->conf |= CONF_UPLOAD;
    
          if(!strequal("-", nextarg))
            /* make - equal stdin */
            GetStr(&config->infile, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'u':
          /* user:password  */
          GetStr(&config->userpwd, nextarg);
          break;
        case 'U':
          /* Proxy user:password  */
          GetStr(&config->proxyuserpwd, nextarg);
          break;
        case 'v':
          config->conf ^= CONF_VERBOSE; /* talk a lot */
          break;
        case 'V':
          printf(CURL_ID "%s\n", curl_version());
    
          if('@' == *nextarg) {
            /* the data begins with a '@' letter, it means that a file name
               or - (stdin) follows */
            FILE *file;
            nextarg++; /* pass the @ */
            if(strequal("-", nextarg))
              file = stdin;
            else 
              file = fopen(nextarg, "r");
            config->writeout = file2string(file);
            if(file && (file != stdin))
              fclose(stdin);
          }
          else 
            GetStr(&config->writeout, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'x':
          /* proxy */
    
          GetStr(&config->proxy, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'X':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          GetStr(&config->customrequest, nextarg);
          break;
    
        case 'y':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* low speed time */
          config->low_speed_time = atoi(nextarg);
          if(!config->low_speed_limit)
    	config->low_speed_limit = 1;
          break;
    
        case 'Y':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* low speed limit */
          config->low_speed_limit = atoi(nextarg);
          if(!config->low_speed_time)
    	config->low_speed_time=30;
          break;
    
        case 'z': /* time condition coming up */
          switch(*nextarg) {
          case '+':
            nextarg++;
          default:
            /* If-Modified-Since: (section 14.28 in RFC2068) */
            config->timecond = TIMECOND_IFMODSINCE;
            break;
          case '-':
            /* If-Unmodified-Since:  (section 14.24 in RFC2068) */
            config->timecond = TIMECOND_IFUNMODSINCE;
            nextarg++;
            break;
          case '=':
            /* Last-Modified:  (section 14.29 in RFC2068) */
            config->timecond = TIMECOND_LASTMOD;
            nextarg++;
            break;
          }
          now=time(NULL);
          config->condtime=curl_getdate(nextarg, &now);
    
          if(-1 == (int)config->condtime) {
    
            /* now let's see if it is a file name to get the time from instead! */
            struct stat statbuf;
            if(-1 == stat(nextarg, &statbuf)) {
              /* failed, remove time condition */
              config->timecond = TIMECOND_NONE;
            }
            else {
              /* pull the time out from the file */
              config->condtime = statbuf.st_mtime;
            }
          }
          break;
        case 'Z':
          /* specified max no of redirects (http(s)) */
          config->maxredirs = atoi(nextarg);
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
        default: /* unknown flag */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        hit = -1;
    
    
      } while(!longopt && !singleopt && *++parse && !*usedarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    }
    
    
    static int parseconfig(char *filename,
    		       struct Configurable *config)
    {
      int res;
      FILE *file;
      char filebuffer[256];
      bool usedarg;
    
      char *home=NULL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      
      if(!filename || !*filename) {
        /* NULL or no file name attempts to load .curlrc from the homedir! */
    
    #define CURLRC DOT_CHAR "curlrc"
    
    
        home = curl_getenv("HOME"); /* portable environment reader */
    
        if(strlen(home)>(sizeof(filebuffer)-strlen(CURLRC))) {
          free(home);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
        sprintf(filebuffer, "%s%s%s", home, DIR_CHAR, CURLRC);
    
        filename = filebuffer;
      }
    
      if(strcmp(filename,"-"))
        file = fopen(filename, "r");
      else
        file = stdin;
      
    
        char *aline;
        char *option;
        char *param;
        int lineno=0;
        bool alloced_param;
    
    #define isseparator(x) (((x)=='=') || ((x) == ':'))
    
        while (NULL != (aline = my_get_line(file))) {
          lineno++;
          line = aline;
          alloced_param=FALSE;
    
    
          /* lines with # in the fist column is a comment! */
    
          while(isspace((int)*line))
    
            line++;
    
          switch(*line) {
          case '#':
          case '/':
          case '\r':
          case '\n':
          case '*':
          case '\0':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
          /* the option keywords starts here */
          option = line;
    
          while(*line && !isspace((int)*line) && !isseparator(*line))
    
            line++;
          /* ... and has ended here */
    
          *line++=0; /* zero terminate, we have a local copy of the data */
    
    #ifdef DEBUG_CONFIG
          fprintf(stderr, "GOT: %s\n", option);
    #endif
    
          /* pass spaces and separator(s) */
    
          while(isspace((int)*line) || isseparator(*line))
    
            line++;
          
          /* the parameter starts here (unless quoted) */
          if(*line == '\"') {
            char *ptr;
            /* quoted parameter, do the qoute dance */
            line++;
            param=strdup(line); /* parameter */
            alloced_param=TRUE;
    
            ptr=param;
            while(*line && (*line != '\"')) {
              if(*line == '\\') {
    
    
                /* default is to output the letter after the backslah */
                switch(out = *line) {
                case '\0':
                  continue; /* this'll break out of the loop */
                case 't':
                  out='\t';
                  break;
                case 'n':
                  out='\n';
                  break;
                case 'r':
                  out='\r';
                  break;
                case 'v':
                  out='\v';
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
          else {
            param=line; /* parameter starts here */
    
            while(*line && !isspace((int)*line))
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
    #ifdef DEBUG_CONFIG
          fprintf(stderr, "PARAM: \"%s\"\n", param);
    #endif
          res = getparameter(option, param, &usedarg, config);
    
          if(*param && !usedarg)
            /* we passed in a parameter that wasn't used! */
            res = PARAM_GOT_EXTRA_PARAMETER;
    
          if(res != PARAM_OK) {
            /* the help request isn't really an error */
            if(!strcmp(filename, "-")) {
    
              filename=(char *)"<stdin>";
    
              const char *reason;
    
              switch(res) {
              default:
              case PARAM_GOT_EXTRA_PARAMETER:
                reason = "had unsupported trailing garbage";
                break;
              case PARAM_OPTION_UNKNOWN:
                reason = "is unknown";
                break;
              case PARAM_OPTION_AMBIGUOUS:
                reason = "is ambiguous";
                break;
              case PARAM_REQUIRES_PARAMETER:
                reason = "requires parameter";
                break;
              case PARAM_BAD_USE:
                reason = "is badly used here";
    
              fprintf(stderr, "%s:%d: warning: '%s' %s\n",
                      filename, lineno, option, reason);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        if(file != stdin)
          fclose(file);
      }
    
      if(home)
        free(home);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    }
    
    struct OutStruct {
      char *filename;
      FILE *stream;
    
      struct Configurable *config;
    
    int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
      struct OutStruct *out=(struct OutStruct *)stream;
      if(out && !out->stream) {
        /* open file for writing */
        out->stream=fopen(out->filename, "wb");
        if(!out->stream)
          return -1; /* failure */
    
        if(out->config->nobuffer) {
    
          /* disable output buffering */
    #ifdef HAVE_SETVBUF
          setvbuf(out->stream, NULL, _IONBF, 0);
    #endif
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
      return fwrite(buffer, size, nmemb, out->stream);
    }
    
    
      FILE *out; /* where to write everything to */
    
                    double dltotal,
                    double dlnow,
                    double ultotal,
                    double ulnow)
    
    {
      /* The original progress-bar source code was written for curl by Lars Aas,
         and this new edition inherites some of his concepts. */
      
      char line[256];
      char outline[256];
      char format[40];
      float frac;
      float percent;
      int barwidth;
      int num;
      int i;
    
      struct ProgressData *bar = (struct ProgressData *)clientp;
      size_t total = dltotal + ultotal;
    
      bar->point = dlnow + ulnow; /* we've come this far */
    
    
      if(0 == total) {
        int prevblock = bar->prev / 1024;
        int thisblock = bar->point / 1024;
        while ( thisblock > prevblock ) {
    
          fprintf( bar->out, "#" );
    
          prevblock++;
        }
      }
      else {
        frac = (float) bar->point / (float) total;
        percent = frac * 100.0f;
        barwidth = bar->width - 7;
        num = (int) (((float)barwidth) * frac);
        i = 0;
        for ( i = 0; i < num; i++ ) {
          line[i] = '#';
        }
        line[i] = '\0';
        sprintf( format, "%%-%ds %%5.1f%%%%", barwidth );
        sprintf( outline, format, line, percent );
    
        fprintf( bar->out, "\r%s", outline );
    
    static
    void progressbarinit(struct ProgressData *bar,
                         struct Configurable *config)
    
    {
    #ifdef __EMX__
      /* 20000318 mgs */
      int scr_size [2];
    #endif
      char *colp;
    
      memset(bar, 0, sizeof(struct ProgressData));
    
    /* TODO: get terminal width through ansi escapes or something similar.
             try to update width when xterm is resized... - 19990617 larsa */
    #ifndef __EMX__
      /* 20000318 mgs
       * OS/2 users most likely won't have this env var set, and besides that
       * we're using our own way to determine screen width */
      colp = curl_getenv("COLUMNS");
      if (colp != NULL) {
        bar->width = atoi(colp);
        free(colp);
      }
      else
        bar->width = 79;
    #else
      /* 20000318 mgs
       * We use this emx library call to get the screen width, and subtract
       * one from what we got in order to avoid a problem with the cursor
       * advancing to the next line if we print a string that is as long as
       * the screen is wide. */
     
      _scrsize(scr_size);
      bar->width = scr_size[0] - 1;
    #endif
    
    
      bar->out = config->errors;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    void free_config_fields(struct Configurable *config)
    
      if(config->random_file)
        free(config->random_file);
      if(config->egd_file)
        free(config->egd_file);
    
      if(config->userpwd)
        free(config->userpwd);
      if(config->postfields)
        free(config->postfields);
      if(config->proxy)
        free(config->proxy);
      if(config->proxyuserpwd)
        free(config->proxyuserpwd);
      if(config->cookie)
        free(config->cookie);
      if(config->cookiefile)
        free(config->cookiefile);
      if(config->krb4level)
        free(config->krb4level);
      if(config->headerfile)
        free(config->headerfile);
      if(config->ftpport)
        free(config->ftpport);
      if(config->infile)
        free(config->infile);
      if(config->range)
        free(config->range);
      if(config->customrequest)
        free(config->customrequest);
      if(config->writeout)
        free(config->writeout);
      if(config->httppost)
        curl_formfree(config->httppost);
      if(config->cacert)
        free(config->cacert);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(config->cookiejar)
        free(config->cookiejar);
    
    
      curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
      curl_slist_free_all(config->postquote); /*  */
      curl_slist_free_all(config->headers); /*  */
    
    operate(struct Configurable *config, int argc, char *argv[])
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      char errorbuffer[CURL_ERROR_SIZE];
    
      char useragent[128]; /* buah, we don't want a larger default user agent */
    
      struct getout *urlnode;
      struct getout *nextnode;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      struct OutStruct outs;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      char *url = NULL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int urlnum;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int separator = 0;
      
      FILE *infd = stdin;
      FILE *headerfilep = NULL;
      char *urlbuffer=NULL;
      int infilesize=-1; /* -1 means unknown */
      bool stillflags=TRUE;
    
    
      bool allocuseragent=FALSE;
    
    
      CURL *curl;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int i;
    
    
    #ifdef MALLOCDEBUG
      /* this sends all memory debug messages to a logfile named memdump */
    
      char *env;
      env = curl_getenv("CURL_MEMDEBUG");
      if(env) {
        free(env);
        curl_memdebug("memdump");
      }
    
      errorbuffer[0]=0; /* prevent junk from being output */
    
    
      config->showerror=TRUE;
      config->conf=CONF_DEFAULT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      if(argc>1 &&
         (!strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
         strchr(argv[1], 'q')) {