Commit 93a29c3c authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Now offering support for multiple -T on the same command line, just make

sure you have one URL for each -T. A -T file name can also be "globbed"
like -T "{file1,file2}".

Test case 149 verifies this functionality.
parent e92b7c73
Loading
Loading
Loading
Loading
+509 −436
Original line number Diff line number Diff line
@@ -143,7 +143,6 @@ typedef enum {
#define CONF_NOPROGRESS (1<<10) /* shut off the progress meter */
#define CONF_NOBODY   (1<<11) /* use HEAD to get http document */
#define CONF_FAILONERROR (1<<12) /* no output on http error codes >= 300 */
#define CONF_UPLOAD   (1<<14) /* this is an upload */
#define CONF_FTPLISTONLY (1<<16) /* Use NLST when listing ftp dir */
#define CONF_FTPAPPEND (1<<20) /* Append instead of overwrite on upload! */
#define CONF_NETRC    (1<<22)  /* read user+password from .netrc */
@@ -353,14 +352,18 @@ static void helpf(const char *fmt, ...)
 * contents.
 */
struct getout {
  struct getout *next;
  char *url;
  char *outfile;
  int flags;
  struct getout *next; /* next one */
  char *url;     /* the URL we deal with */
  char *outfile; /* where to store the output */
  char *infile;  /* file to upload, if GETOUT_UPLOAD is set */
  int flags;     /* options */
};
#define GETOUT_OUTFILE (1<<0)   /* set when outfile is deemed done */
#define GETOUT_URL     (1<<1)   /* set when URL is deemed done */
#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
#define GETOUT_UPLOAD  (1<<3)   /* if set, -T has been used */
#define GETOUT_NOUPLOAD  (1<<4) /* if set, -T "" has been used */


static void help(void)
{
@@ -508,7 +511,6 @@ struct Configurable {
  int low_speed_limit;
  int low_speed_time;
  bool showerror;
  char *infile;
  char *userpwd;
  char *proxyuserpwd;
  char *proxy;
@@ -675,6 +677,8 @@ void clean_getout(struct Configurable *config)
      free(node->url);
    if(node->outfile)
      free(node->outfile);
    if(node->infile)
      free(node->infile);
    free(node);

    node = next; /* GOTO next */
@@ -1756,10 +1760,34 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
      break;
    case 'T':
      /* we are uploading */
      config->conf |= CONF_UPLOAD;
      if(!curl_strequal("-", nextarg))
        /* make - equal stdin */
        GetStr(&config->infile, nextarg);
      {
        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_UPLOAD))
            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) {
          url->flags |= GETOUT_UPLOAD; /* mark -T used */
          if(!*nextarg)
            url->flags |= GETOUT_NOUPLOAD;
          else {
            /* "-" equals stdin, but keep the string around for now */
            GetStr(&url->infile, nextarg);
          }
        }
      }
      break;
    case 'u':
      /* user:password  */
@@ -2408,8 +2436,6 @@ void free_config_fields(struct Configurable *config)
    free(config->headerfile);
  if(config->ftpport)
    free(config->ftpport);
  if(config->infile)
    free(config->infile);
  if(config->range)
    free(config->range);
  if(config->customrequest)
@@ -2479,14 +2505,20 @@ operate(struct Configurable *config, int argc, char *argv[])
  char *url = NULL;

  URLGlob *urls=NULL;
  URLGlob *inglob=NULL;
  int urlnum;
  int infilenum;
  char *outfiles;
  char *infiles; /* might a glob pattern */
  char *uploadfile=NULL; /* a single file, never a glob */

  int separator = 0;
  
  FILE *infd = stdin;
  FILE *infd;
  bool infdfopen;
  FILE *headerfilep = NULL;
  char *urlbuffer=NULL;
  long infilesize=-1; /* -1 means unknown */
  long uploadfilesize; /* -1 means unknown */
  bool stillflags=TRUE;

  bool allocuseragent=FALSE;
@@ -2496,6 +2528,7 @@ operate(struct Configurable *config, int argc, char *argv[])
  CURL *curl;
  int res = 0;
  int i;
  int up; /* upload file counter within a single upload glob */

  char *env;
#ifdef CURLDEBUG
@@ -2678,9 +2711,12 @@ operate(struct Configurable *config, int argc, char *argv[])

  /* loop through the list of given URLs */
  while(urlnode && !res) {
    char *dourl;

    /* get the full URL (it might be NULL) */
    url=urlnode->url;
    dourl=urlnode->url;

    url = dourl;

    if(NULL == url) {
      /* This node had no URL, skip it and continue to the next */
@@ -2698,10 +2734,14 @@ operate(struct Configurable *config, int argc, char *argv[])
    outs.stream = stdout;
    outs.config = config;

    if(!config->globoff) {
      /* Unless explicitly shut off, we expand '{...}' and '[...]' expressions
         and return total number of URLs in pattern set */
      res = glob_url(&urls, url, &urlnum,
    /* save outfile pattern before expansion */
    outfiles = urlnode->outfile?strdup(urlnode->outfile):NULL;

    infiles = urlnode->infile;

    if(!config->globoff && infiles) {
      /* Unless explicitly shut off */
      res = glob_url(&inglob, infiles, &infilenum,
                     config->showerror?
                     (config->errors?config->errors:stderr):NULL);
      if(res != CURLE_OK) {
@@ -2710,14 +2750,31 @@ operate(struct Configurable *config, int argc, char *argv[])
      }
    }

    /* Here's the loop for uploading multiple files within the same
       single globbed string. If no upload, we enter the loop once anyway. */
    for(up = 0;
        (!up && !infiles) ||
          (uploadfile = inglob?
           glob_next_url(inglob):
           (!up?strdup(infiles):NULL));
        up++) {
      uploadfilesize=-1;

    /* save outfile pattern before expansion */
    outfiles = urlnode->outfile?strdup(urlnode->outfile):NULL;

    if ((!outfiles || curl_strequal(outfiles, "-")) && urlnum > 1) {
      /* multiple files extracted to stdout, insert separators! */
      separator = 1;
      if(!config->globoff) {
        /* Unless explicitly shut off, we expand '{...}' and '[...]'
           expressions and return total number of URLs in pattern set */
        res = glob_url(&urls, dourl, &urlnum,
                       config->showerror?
                       (config->errors?config->errors:stderr):NULL);
        if(res != CURLE_OK) {
          break;
        }
      }

      /* if multiple files extracted to stdout, insert separators! */
      separator= ((!outfiles || curl_strequal(outfiles, "-")) && urlnum > 1);

      /* Here's looping around each globbed URL */
      for(i = 0;
          (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
          i++) {
@@ -2813,9 +2870,10 @@ operate(struct Configurable *config, int argc, char *argv[])
            outs.stream = NULL; /* open when needed */
          }
        }
      if(config->infile) {
        infdfopen=FALSE;
        if(uploadfile && !curl_strequal(uploadfile, "-")) {
          /*
         * We have specified a file to upload
           * We have specified a file to upload and it isn't "-".
           */
          struct stat fileinfo;

@@ -2833,15 +2891,15 @@ operate(struct Configurable *config, int argc, char *argv[])

            /* We only want the part of the local path that is on the right
               side of the rightmost slash and backslash. */
          char *filep = strrchr(config->infile, '/');
          char *file2 = strrchr(filep?filep:config->infile, '\\');
            char *filep = strrchr(uploadfile, '/');
            char *file2 = strrchr(filep?filep:uploadfile, '\\');

            if(file2)
              filep = file2+1;
            else if(filep)
              filep++;
            else
            filep = config->infile;
              filep = uploadfile;

            /* URL encode the file name */
            filep = curl_escape(filep, 0 /* use strlen */);
@@ -2876,24 +2934,26 @@ operate(struct Configurable *config, int argc, char *argv[])
/*VMS??   for every record add 1 for linefeed and subtract 2 for the record header */
/*VMS??   for VARIABLE header files only the bare record data needs to be considered with one appended if implied CC */

        infd=(FILE *) fopen(config->infile, "rb");
        if (!infd || stat(config->infile, &fileinfo)) {
          helpf("Can't open '%s'!\n", config->infile);
          infd=(FILE *) fopen(uploadfile, "rb");
          if (!infd || stat(uploadfile, &fileinfo)) {
            helpf("Can't open '%s'!\n", uploadfile);
            return CURLE_READ_ERROR;
          }
        infilesize=fileinfo.st_size;
          infdfopen=TRUE;
          uploadfilesize=fileinfo.st_size;
      
        }
      if((config->conf&CONF_UPLOAD) &&
         config->resume_from_current) {
        config->resume_from = -1; /* -1 will then force get-it-yourself */
        else if(uploadfile && curl_strequal(uploadfile, "-")) {
          infd = stdin;
        }
      if(outs.stream && isatty(fileno(outs.stream)) &&
         !(config->conf&(CONF_UPLOAD|CONF_HTTPPOST)))
        /* we send the output to a tty and it isn't an upload operation,
           therefore we switch off the progress meter */
        config->conf |= CONF_NOPROGRESS;

        if(uploadfile && config->resume_from_current)
          config->resume_from = -1; /* -1 will then force get-it-yourself */

        if(outs.stream && isatty(fileno(outs.stream)))
          /* we send the output to a tty, therefore we switch off the progress
             meter */
          config->conf |= CONF_NOPROGRESS;

        if (urlnum > 1 && !(config->conf&CONF_MUTE)) {
          fprintf(stderr, "\n[%d/%d]: %s --> %s\n",
@@ -2973,7 +3033,7 @@ operate(struct Configurable *config, int argc, char *argv[])
        }

        /* size of uploaded file: */
      curl_easy_setopt(curl, CURLOPT_INFILESIZE, infilesize);
        curl_easy_setopt(curl, CURLOPT_INFILESIZE, uploadfilesize);
        curl_easy_setopt(curl, CURLOPT_URL, url);     /* what to fetch */
        curl_easy_setopt(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
        curl_easy_setopt(curl, CURLOPT_HEADER, config->conf&CONF_HEADER);
@@ -2981,7 +3041,7 @@ operate(struct Configurable *config, int argc, char *argv[])
        curl_easy_setopt(curl, CURLOPT_NOBODY, config->conf&CONF_NOBODY);
        curl_easy_setopt(curl, CURLOPT_FAILONERROR,
                         config->conf&CONF_FAILONERROR);
      curl_easy_setopt(curl, CURLOPT_UPLOAD, config->conf&CONF_UPLOAD);
        curl_easy_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
        curl_easy_setopt(curl, CURLOPT_FTPLISTONLY,
                         config->conf&CONF_FTPLISTONLY);
        curl_easy_setopt(curl, CURLOPT_FTPAPPEND, config->conf&CONF_FTPAPPEND);
@@ -3201,8 +3261,6 @@ operate(struct Configurable *config, int argc, char *argv[])
        }
#endif

      if (config->infile)
        fclose(infd);
        if(headerfilep)
          fclose(headerfilep);
      
@@ -3214,19 +3272,34 @@ operate(struct Configurable *config, int argc, char *argv[])

        if(outfile)
          free(outfile);
    }
    if(outfiles)
      free(outfiles);

        if(infdfopen)
          fclose(infd);

      } /* loop to the next URL */

      if(urls)
        /* cleanup memory used for URL globbing patterns */
        glob_cleanup(urls);
     
      if(uploadfile)
        free(uploadfile);
 
    } /* loop to the next globbed upload file */

    if(inglob)
      glob_cleanup(inglob);

    if(outfiles)
      free(outfiles);

    /* empty this urlnode struct */
    if(urlnode->url)
      free(urlnode->url);
    if(urlnode->outfile)
      free(urlnode->outfile);
    if(urlnode->infile)
      free(urlnode->infile);
    
    /* move on to the next URL */
    nextnode=urlnode->next;