Skip to content
Snippets Groups Projects
main.c 120 KiB
Newer Older
            url->flags |= GETOUT_NOUPLOAD;
          else {
            /* "-" equals stdin, but keep the string around for now */
            GetStr(&url->infile, nextarg);
          }
        }
      }
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'u':
      /* user:password  */
      GetStr(&config->userpwd, nextarg);
      checkpasswd("host", &config->userpwd);
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'U':
      /* Proxy user:password  */
      GetStr(&config->proxyuserpwd, nextarg);
      checkpasswd("proxy", &config->proxyuserpwd);
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'v':
      config->conf ^= CONF_VERBOSE; /* talk a lot */
      break;
    case 'V':
Daniel Stenberg's avatar
Daniel Stenberg committed
      printf(CURL_ID "%s\n", curl_version());
      if (curlinfo->protocols) {
        printf("Protocols: ");
        for (proto=curlinfo->protocols; *proto; ++proto) {
        puts(""); /* newline */
      }
      if(curlinfo->features) {
        unsigned int i;
        struct feat {
          const char *name;
          int bitmask;
        };
        static const struct feat feats[] = {
          {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
          {"Debug", CURL_VERSION_DEBUG},
          {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
          {"IDN", CURL_VERSION_IDN},
          {"IPv6", CURL_VERSION_IPV6},
          {"Largefile", CURL_VERSION_LARGEFILE},
          {"NTLM", CURL_VERSION_NTLM},
          {"SPNEGO", CURL_VERSION_SPNEGO},
          {"SSL",  CURL_VERSION_SSL},
          {"krb4", CURL_VERSION_KERBEROS4},
          {"libz", CURL_VERSION_LIBZ}
        };
        printf("Features: ");
        for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
          if(curlinfo->features & feats[i].bitmask)
            printf("%s ", feats[i].name);
        }
        puts(""); /* newline */
      if('@' == *nextarg) {
        /* the data begins with a '@' letter, it means that a file name
           or - (stdin) follows */
        FILE *file;
        nextarg++; /* pass the @ */
          file = fopen(nextarg, "r");
        config->writeout = file2string(file);
        if(file && (file != stdin))
        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 */
      if(str2num(&config->low_speed_time, nextarg))
        return PARAM_BAD_NUMERIC;
Daniel Stenberg's avatar
Daniel Stenberg committed
      if(!config->low_speed_limit)
        config->low_speed_limit = 1;
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'Y':
Daniel Stenberg's avatar
Daniel Stenberg committed
      /* low speed limit */
      if(str2num(&config->low_speed_limit, nextarg))
        return PARAM_BAD_NUMERIC;
Daniel Stenberg's avatar
Daniel Stenberg committed
      if(!config->low_speed_time)
        config->low_speed_time=30;
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'z': /* time condition coming up */
      switch(*nextarg) {
      case '+':
        nextarg++;
      default:
        /* If-Modified-Since: (section 14.28 in RFC2068) */
        config->timecond = CURL_TIMECOND_IFMODSINCE;
        break;
      case '-':
        /* If-Unmodified-Since:  (section 14.24 in RFC2068) */
        config->timecond = CURL_TIMECOND_IFUNMODSINCE;
        nextarg++;
        break;
      case '=':
        /* Last-Modified:  (section 14.29 in RFC2068) */
        config->timecond = CURL_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 = CURL_TIMECOND_NONE;
        }
        else {
          /* pull the time out from the file */
          config->condtime = statbuf.st_mtime;
        }
      }
      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

static void parseconfig(const char *filename,
                        struct Configurable *config)
Daniel Stenberg's avatar
Daniel Stenberg committed
{
  int res;
  FILE *file;
Daniel Stenberg's avatar
Daniel Stenberg committed
  bool usedarg;
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"

    filename = CURLRC;   /* sensible default */
    home = homedir();    /* portable homedir finder */
    if(home) {
      if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
        snprintf(filebuffer, sizeof(filebuffer),
                 "%s%s%s", home, DIR_CHAR, CURLRC);
Daniel Stenberg's avatar
Daniel Stenberg committed

      free(home); /* we've used it, now free it */
# else /* AmigaOS */
  /* On AmigaOS all the config files are into env:
   */
  filename = "ENV:" CURLRC;

#endif
Daniel Stenberg's avatar
Daniel Stenberg committed
  }

  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! */
        line++;

      switch(*line) {
      case '#':
      case '/':
      case '\r':
      case '\n':
      case '*':
      case '\0':
        free(aline);
Daniel Stenberg's avatar
Daniel Stenberg committed

      /* the option keywords starts here */
      option = line;
      while(*line && !isspace((int)*line) && !isseparator(*line))
      if(*line)
        *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(*line && (isspace((int)*line) || isseparator(*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
      }

      if (param && !*param) {
        /* do this so getparameter can check for required parameters.
           Otherwise it always thinks there's a parameter. */
        if (alloced_param)
          free(param);
        param = NULL;
      }

      fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
#endif
      res = getparameter(option, param, &usedarg, config);
        /* 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 = param2text(res);
          fprintf(stderr, "%s:%d: warning: '%s' %s\n",
                  filename, lineno, option, reason);
Daniel Stenberg's avatar
Daniel Stenberg committed
    }
    if(file != stdin)
      fclose(file);
  }
}

Daniel Stenberg's avatar
Daniel Stenberg committed
static void go_sleep(long ms)
{
Daniel Stenberg's avatar
Daniel Stenberg committed
  /* portable subsecond "sleep" */
  poll((void *)0, 0, (int)ms);
#else
  /* systems without poll() need other solutions */

#ifdef WIN32
  /* Windows offers a millisecond sleep */
  Sleep(ms);
#elif defined(__MSDOS__)
  delay(ms);
#else
  /* Other systems must use select() for this */
  struct timeval timeout;

  timeout.tv_usec = ms * 1000;

  select(0, NULL,  NULL, NULL, &timeout);
#endif

#endif
Daniel Stenberg's avatar
Daniel Stenberg committed
struct OutStruct {
  char *filename;
  FILE *stream;
  struct Configurable *config;
  curl_off_t bytes; /* amount written so far */
  curl_off_t init;  /* original size (non-zero when appending) */
static int my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
Daniel Stenberg's avatar
Daniel Stenberg committed
{
Daniel Stenberg's avatar
Daniel Stenberg committed
  struct OutStruct *out=(struct OutStruct *)stream;
Daniel Stenberg's avatar
Daniel Stenberg committed
  struct Configurable *config = out->config;
  curl_off_t size = (curl_off_t)(sz * nmemb); /* typecast to prevent
                                                 warnings when converting from
                                                 unsigned to signed */
Daniel Stenberg's avatar
Daniel Stenberg committed
  if(out && !out->stream) {
    /* open file for writing */
    out->stream=fopen(out->filename, "wb");
    if(!out->stream)
      return -1; /* failure */
  }
Daniel Stenberg's avatar
Daniel Stenberg committed

  if(config->recvpersecond) {
    /*
     * We know when we received data the previous time. We know how much data
     * we get now. Make sure that this is not faster than we are told to run.
     * If we're faster, sleep a while *before* doing the fwrite() here.
     */

    struct timeval now;
    long timediff;
    long sleep_time;
    now = curlx_tvnow();
    timediff = curlx_tvdiff(now, config->lastrecvtime); /* milliseconds */
    if((config->recvpersecond > CURL_MAX_WRITE_SIZE) && (timediff < 100) ) {
      /* If we allow a rather speedy transfer, add this amount for later
       * checking. Also, do not modify the lastrecvtime as we will use a
       * longer scope due to this addition.  We wait for at least 100 ms to
       * pass to get better values to do better math for the sleep. */
      addit += size;
    }
    else {
      size += addit; /* add up the possibly added bonus rounds from the
                        zero timediff calls */
      addit = 0; /* clear the addition pool */

      if( size*1000 > config->recvpersecond*timediff) {
        /* figure out how many milliseconds to rest */
        sleep_time = (long)(size*1000/config->recvpersecond - timediff);

        /*
         * Make sure we don't sleep for so long that we trigger the speed
         * limit.  This won't limit the bandwidth quite the way we've been
         * asked to, but at least the transfer has a chance.
         */
        if (config->low_speed_time > 0)
          sleep_time = MIN(sleep_time,(config->low_speed_time * 1000) / 2);
        if(sleep_time > 0) {
          go_sleep(sleep_time);
          now = curlx_tvnow();
        }
      }
      config->lastrecvtime = now;
  rc = fwrite(buffer, sz, nmemb, out->stream);
  if((int)(sz * nmemb) == rc) {
    /* we added this amount of data to the output */
    out->bytes += (sz * nmemb);
  }

  if(config->nobuffer)
    /* disable output buffering */
    fflush(out->stream);
Daniel Stenberg's avatar
Daniel Stenberg committed
struct InStruct {
  FILE *stream;
  struct Configurable *config;
};

static curlioerr my_ioctl(CURL *handle, curliocmd cmd, void *userp)
{
  struct InStruct *in=(struct InStruct *)userp;
  (void)handle; /* not used in here */

  switch(cmd) {
  case CURLIOCMD_RESTARTREAD:
    /* mr libcurl kindly asks as to rewind the read data stream to start */
    if(-1 == fseek(in->stream, 0, SEEK_SET))
      /* couldn't rewind, the reason is in errno but errno is just not
         portable enough and we don't actually care that much why we failed. */
      return CURLIOE_FAILRESTART;

    break;

  default: /* ignore unknown commands */
    return CURLIOE_UNKNOWNCMD;
  }
  return CURLIOE_OK;
}

static int my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
Daniel Stenberg's avatar
Daniel Stenberg committed
{
Daniel Stenberg's avatar
Daniel Stenberg committed
  struct InStruct *in=(struct InStruct *)userp;
  struct Configurable *config = in->config;
  curl_off_t size = (curl_off_t)(sz * nmemb);  /* typecast to prevent warnings
                                                  when converting from
                                                  unsigned to signed */
Daniel Stenberg's avatar
Daniel Stenberg committed

  if(config->sendpersecond) {
    /*
     * We know when we sent data the previous time. We know how much data
     * we sent. Make sure that this was not faster than we are told to run.
     * If we're faster, sleep a while *before* doing the fread() here.
     * Also, make no larger fread() than should be sent this second!
     */

    struct timeval now;
    long timediff;
    long sleep_time;
    static curl_off_t addit = 0;

    now = curlx_tvnow();
    timediff = curlx_tvdiff(now, config->lastsendtime); /* milliseconds */
    if((config->sendpersecond > CURL_MAX_WRITE_SIZE) &&
       (timediff < 100)) {
      /*
       * We allow very fast transfers, then allow at least 100 ms between
       * each sleeping mile-stone to create more accurate long-term rates.
       */
      addit += size;
    }
    else {
      /* If 'addit' is non-zero, it contains the total amount of bytes
         uploaded during the last 'timediff' milliseconds. If it is zero,
         we use the stored previous size. */
      curl_off_t xfered = addit?addit:(curl_off_t)config->lastsendsize;
      addit = 0; /* clear it for the next round */

      if( xfered*1000 > config->sendpersecond*timediff) {
        /* figure out how many milliseconds to rest */
        sleep_time = (long)(xfered*1000/config->sendpersecond - timediff);
        if(sleep_time > 0) {
          go_sleep (sleep_time);
          now = curlx_tvnow();
        }
      }
      config->lastsendtime = now;
      if(size > config->sendpersecond) {
        /* lower the size to actually read */
  rc = fread(buffer, sz, nmemb, in->stream);
#if 0
  fprintf(stderr, "CALLBACK returning %d bytes data\n", (int)rc);
#endif
  return rc;
  curl_off_t prev;
  FILE *out; /* where to write everything to */
  curl_off_t initial_size;
static int myprogress (void *clientp,
                       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 inherits some of his concepts. */
  char line[256];
  char outline[256];
  char format[40];
  int barwidth;
  int num;
  int i;

  struct ProgressData *bar = (struct ProgressData *)clientp;
  curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
    bar->initial_size; /* expected transfer size */
  curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
    bar->initial_size; /* we've come this far */
    curl_off_t prevblock = bar->prev / 1024;
    curl_off_t thisblock = point / 1024;
      fprintf( bar->out, "#" );
    frac = (double)point / (double)total;
    percent = frac * 100.0f;
    barwidth = bar->width - 7;
    num = (int) (((double)barwidth) * frac);
    i = 0;
    for ( i = 0; i < num; i++ ) {
      line[i] = '#';
    }
    line[i] = '\0';
    snprintf( format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth );
    snprintf( outline, sizeof(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));

  /* pass this through to progress function so
   * it can display progress towards total file
   * not just the part that's left. (21-may-03, dbyron) */
  if (config->use_resume)
    bar->initial_size = config->resume_from;

/* 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 */
  if (colp != NULL) {
    bar->width = atoi(colp);
    curl_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

          FILE *stream, unsigned char *ptr, size_t size,
          bool nohex)
  unsigned int width=0x10;

  if(nohex)
    /* without the hex output, we can fit more on screen */
    width = 0x40;
  fprintf(stream, "%s, %zd bytes (0x%zx)\n", text, size, size);
  for(i=0; i<size; i+= width) {
    if(!nohex) {
      /* hex not disabled, show it */
      for(c = 0; c < width; c++)
        if(i+c < size)
          fprintf(stream, "%02x ", ptr[i+c]);
        else
          fputs("   ", stream);
    }

    for(c = 0; (c < width) && (i+c < size); c++) {
      /* check for 0D0A; if found, skip past and start a new line of output */
      if (nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
        i+=(c+2-width);
        break;
      }
      fprintf(stream, "%c",
              (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
      /* check again for 0D0A, to avoid an extra \n if it's at width */
      if (nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
        i+=(c+3-width);
        break;
      }
    }
  fflush(stream);
}

static
int my_trace(CURL *handle, curl_infotype type,
             unsigned char *data, size_t size,
             void *userp)
{
  struct Configurable *config = (struct Configurable *)userp;
  FILE *output=config->errors;
  const char *text;
  (void)handle; /* prevent compiler warning */

  if(!config->trace_stream) {
    if(curlx_strequal("-", config->trace_dump))
      config->trace_stream = stdout;
    else {
      config->trace_stream = fopen(config->trace_dump, "w");
      config->trace_fopened = TRUE;
    }
  }

  if(config->trace_stream)
    output = config->trace_stream;

  switch (type) {
  case CURLINFO_TEXT:
    fprintf(output, "== Info: %s", data);
  default: /* in case a new one is introduced to shock us */
    return 0;

    text = "=> Send header";
    text = "=> Send data";
    text = "<= Recv header";
    text = "<= Recv data";
  case CURLINFO_SSL_DATA_IN:
    text = "<= Recv SSL data";
    break;
  case CURLINFO_SSL_DATA_OUT:
    text = "<= Send SSL data";
    break;

  dump(text, output, data, size, config->trace_ascii);
static 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->trace_dump)
    free(config->trace_dump);
  if(config->cipher_list)
    free(config->cipher_list);
  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->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);
  if(config->capath)
    free(config->capath);
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); /*  */
#if defined(WIN32) && !defined(__CYGWIN32__)

/* Function to find CACert bundle on a Win32 platform using SearchPath.
 * (SearchPath is defined in windows.h, which is #included into libcurl)
 * (Use the ASCII version instead of the unicode one!)
 * The order of the directories it searches is:
 *  1. application's directory
 *  2. current working directory
 *  3. Windows System directory (e.g. C:\windows\system32)
 *  4. Windows Directory (e.g. C:\windows)
 *  5. all directories along %PATH%
 */
static void FindWin32CACert(struct Configurable *config,
                            const char *bundle_file)
{
  /* only check for cert file if "we" support SSL */
  if(curlinfo->features & CURL_VERSION_SSL) {
    DWORD buflen;
    char *ptr = NULL;
    char *retval = (char *) malloc(sizeof (TCHAR) * (MAX_PATH + 1));
    if (!retval)
      return;
    retval[0] = '\0';
    buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
    if (buflen > 0) {
      GetStr(&config->cacert, retval);
    }
    free(retval);
  }
}

#endif
#define RETRY_SLEEP_DEFAULT 1000  /* ms */
#define RETRY_SLEEP_MAX     600000 /* ms == 10 minutes */

static int
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
  struct InStruct input;
Daniel Stenberg's avatar
Daniel Stenberg committed

  char *url = NULL;
Daniel Stenberg's avatar
Daniel Stenberg committed
  int urlnum;
  char *infiles; /* might a glob pattern */
  char *uploadfile=NULL; /* a single file, never a glob */

Daniel Stenberg's avatar
Daniel Stenberg committed
  int separator = 0;
Daniel Stenberg's avatar
Daniel Stenberg committed
  FILE *headerfilep = NULL;
  char *urlbuffer=NULL;
  curl_off_t uploadfilesize; /* -1 means unknown */
Daniel Stenberg's avatar
Daniel Stenberg committed
  bool stillflags=TRUE;

  bool allocuseragent=FALSE;

  CURL *curl;
Daniel Stenberg's avatar
Daniel Stenberg committed
  int i;
  int up; /* upload file counter within a single upload glob */
Daniel Stenberg's avatar
Daniel Stenberg committed
  long retry_sleep_default = config->retry_delay?
    config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */
Daniel Stenberg's avatar
Daniel Stenberg committed
  long retry_numretries;
  long retry_sleep = retry_sleep_default;
Daniel Stenberg's avatar
Daniel Stenberg committed
  struct timeval retrystart;
Daniel Stenberg's avatar
Daniel Stenberg committed

#ifdef CURLDEBUG
  /* this sends all memory debug messages to a logfile named memdump */
    curl_free(env);
  if(env) {
    curl_memlimit(atoi(env));
    curl_free(env);
  }
  memset(&outs,0,sizeof(outs));

  /* we get libcurl info right away */
  curlinfo = curl_version_info(CURLVERSION_NOW);

  errorbuffer[0]=0; /* prevent junk from being output */

  /* setup proper locale from environment */
#ifdef HAVE_SETLOCALE
  setlocale(LC_ALL, "");
#endif

  /* inits */
  if (main_init() != CURLE_OK) {
    helpf("error initializing curl library\n");
    return CURLE_FAILED_INIT;
  }
  config->showerror=TRUE;
  config->conf=CONF_DEFAULT;
  config->lastrecvtime = curlx_tvnow();
  config->lastsendtime = curlx_tvnow();
Daniel Stenberg's avatar
Daniel Stenberg committed

  if(argc>1 &&
     (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
Daniel Stenberg's avatar
Daniel Stenberg committed
     strchr(argv[1], 'q')) {
    /*
     * The first flag, that is not a verbose name, but a shortname
     * and it includes the 'q' flag!
     */
    ;
  }
  else {
    parseconfig(NULL, config);
  if ((argc < 2)  && !config->url_list) {
Daniel Stenberg's avatar
Daniel Stenberg committed
    helpf(NULL);
    return CURLE_FAILED_INIT;
Daniel Stenberg's avatar
Daniel Stenberg committed
  }

  /* Parse options */
  for (i = 1; i < argc; i++) {
    if(stillflags &&
       ('-' == argv[i][0])) {
      char *nextarg;
      bool passarg;
Daniel Stenberg's avatar
Daniel Stenberg committed

        /* this indicates the end of the flags and thus enables the
           following (URL) argument to start with -. */
        stillflags=FALSE;
Daniel Stenberg's avatar
Daniel Stenberg committed
      else {
        nextarg= (i < argc - 1)? argv[i+1]: NULL;
Daniel Stenberg's avatar
Daniel Stenberg committed

        res = getparameter(flag, nextarg, &passarg, config);
        if(res) {
          const char *reason = param2text(res);
          if(res != PARAM_HELP_REQUESTED)
            helpf("option %s: %s\n", origopt, reason);
          clean_getout(config);
          return CURLE_FAILED_INIT;
Daniel Stenberg's avatar
Daniel Stenberg committed

        if(passarg) /* we're supposed to skip this */
          i++;
Daniel Stenberg's avatar
Daniel Stenberg committed
      }
    }
    else {
      bool used;
      /* just add the URL please */
      res = getparameter((char *)"--url", argv[i], &used, config);
      if(res)
        return res;
  if((!config->url_list || !config->url_list->url) && !config->list_engines) {
Daniel Stenberg's avatar
Daniel Stenberg committed
    helpf("no URL specified!\n");
    return CURLE_FAILED_INIT;
Daniel Stenberg's avatar
Daniel Stenberg committed
  }
  if(NULL == config->useragent) {
    /* set non-zero default values: */
    snprintf(useragent, sizeof(useragent),
             CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
    config->useragent= useragent;
  else
    allocuseragent = TRUE;
Daniel Stenberg's avatar
Daniel Stenberg committed

  /* On WIN32 (non-cygwin), we can't set the path to curl-ca-bundle.crt
   * at compile time. So we look here for the file in two ways:
   * 1: look at the environment variable CURL_CA_BUNDLE for a path
   * 2: if #1 isn't found, use the windows API function SearchPath()
   *    to find it along the app's path (includes app's dir and CWD)
   *
   * We support the environment variable thing for non-Windows platforms
   * too. Just for the sake of it.
   */
  if (!config->cacert &&
      !config->capath &&
      !config->insecure_ok) {
      curl_free(env);
    }
#if defined(WIN32) && !defined(__CYGWIN32__)