Now offering support for multiple -T on the same command line, just make
authorDaniel Stenberg <daniel@haxx.se>
Tue, 19 Aug 2003 23:42:24 +0000 (23:42 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 19 Aug 2003 23:42:24 +0000 (23:42 +0000)
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.

src/main.c

index a8afbe9..bee66db 100644 (file)
@@ -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_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,162 +2750,180 @@ 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;
+
+      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;
+        }
+      }
 
-    /* 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;
-    }
-    for(i = 0;
-        (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
-        i++) {
-      char *outfile;
-      outfile = outfiles?strdup(outfiles):NULL;
-      if((urlnode->flags&GETOUT_USEREMOTE) ||
-         (outfile && !curl_strequal("-", outfile)) ) {
+      /* if multiple files extracted to stdout, insert separators! */
+      separator= ((!outfiles || curl_strequal(outfiles, "-")) && urlnum > 1);
 
-        /* 
-         * We have specified a file name to store the result in, or we have
-         * decided we want to use the remote file name.
-         */
+      /* Here's looping around each globbed URL */
+      for(i = 0;
+          (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
+          i++) {
+        char *outfile;
+        outfile = outfiles?strdup(outfiles):NULL;
+        
+        if((urlnode->flags&GETOUT_USEREMOTE) ||
+           (outfile && !curl_strequal("-", outfile)) ) {
+          
+          /* 
+           * We have specified a file name to store the result in, or we have
+           * decided we want to use the remote file name.
+           */
       
-        if(!outfile) {
-          /* Find and get the remote file name */
-          char * pc =strstr(url, "://");
-          if(pc)
-            pc+=3;
-          else
-            pc=url;
-          pc = strrchr(pc, '/');
+          if(!outfile) {
+            /* Find and get the remote file name */
+            char * pc =strstr(url, "://");
+            if(pc)
+              pc+=3;
+            else
+              pc=url;
+            pc = strrchr(pc, '/');
 
-          if(pc) {
-            /* duplicate the string beyond the slash */
-            pc++;
-            outfile = *pc ? strdup(pc): NULL;
-          }
-          if(!outfile || !*outfile) {
-            helpf("Remote file name has no length!\n");
-            res = CURLE_WRITE_ERROR;
-            free(url);
-            break;
-          }
+            if(pc) {
+              /* duplicate the string beyond the slash */
+              pc++;
+              outfile = *pc ? strdup(pc): NULL;
+            }
+            if(!outfile || !*outfile) {
+              helpf("Remote file name has no length!\n");
+              res = CURLE_WRITE_ERROR;
+              free(url);
+              break;
+            }
 #if defined(__DJGPP__)
-          {
-            /* This is for DOS, and then we do some major replacing of 
-               bad characters in the file name before using it */
-            char *file1=xmalloc(PATH_MAX);
-            strcpy(file1, msdosify(outfile));
-            strcpy(outfile, rename_if_dos_device_name(file1));
-            xfree(file1);
-          }
+            {
+              /* This is for DOS, and then we do some major replacing of 
+                 bad characters in the file name before using it */
+              char *file1=xmalloc(PATH_MAX);
+              strcpy(file1, msdosify(outfile));
+              strcpy(outfile, rename_if_dos_device_name(file1));
+              xfree(file1);
+            }
 #endif /* __DJGPP__ */
-        }
-        else if(urls) {
-          /* fill '#1' ... '#9' terms from URL pattern */
-          char *storefile = outfile;
-          outfile = glob_match_url(storefile, urls);
-          free(storefile);
-          if(!outfile) {
-            /* bad globbing */
-            fprintf(stderr, "bad output glob!\n");
-            free(url);
-            res = CURLE_FAILED_INIT;
-            break;
           }
-        }
-      
-        /* Create the directory hierarchy, if not pre-existant to a multiple
-           file output call */
-        
-        if(config->create_dirs)
-          if (-1 == create_dir_hierarchy(outfile)) {
-            return CURLE_WRITE_ERROR;
+          else if(urls) {
+            /* fill '#1' ... '#9' terms from URL pattern */
+            char *storefile = outfile;
+            outfile = glob_match_url(storefile, urls);
+            free(storefile);
+            if(!outfile) {
+              /* bad globbing */
+              fprintf(stderr, "bad output glob!\n");
+              free(url);
+              res = CURLE_FAILED_INIT;
+              break;
+            }
           }
+          
+          /* Create the directory hierarchy, if not pre-existant to a multiple
+             file output call */
         
-        if(config->resume_from_current) {
-          /* We're told to continue from where we are now. Get the
-             size of the file as it is now and open it for append instead */
+          if(config->create_dirs)
+            if (-1 == create_dir_hierarchy(outfile)) {
+              return CURLE_WRITE_ERROR;
+            }
           
-          struct stat fileinfo;
+          if(config->resume_from_current) {
+            /* We're told to continue from where we are now. Get the
+               size of the file as it is now and open it for append instead */
+            
+            struct stat fileinfo;
 
-          /*VMS?? -- Danger, the filesize is only valid for stream files */
-          if(0 == stat(outfile, &fileinfo))
-            /* set offset to current file size: */
-            config->resume_from = fileinfo.st_size;
-          else
-            /* let offset be 0 */
-            config->resume_from = 0;
-        }
+            /*VMS?? -- Danger, the filesize is only valid for stream files */
+            if(0 == stat(outfile, &fileinfo))
+              /* set offset to current file size: */
+              config->resume_from = fileinfo.st_size;
+            else
+              /* let offset be 0 */
+              config->resume_from = 0;
+          }
         
-        if(config->resume_from) {
-          /* open file for output: */
-          outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
-          if (!outs.stream) {
-            helpf("Can't open '%s'!\n", outfile);
-            return CURLE_WRITE_ERROR;
+          if(config->resume_from) {
+            /* open file for output: */
+            outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
+            if (!outs.stream) {
+              helpf("Can't open '%s'!\n", outfile);
+              return CURLE_WRITE_ERROR;
+            }
+          }
+          else {
+            outs.filename = outfile;
+            outs.stream = NULL; /* open when needed */
           }
         }
-        else {
-          outs.filename = outfile;
-          outs.stream = NULL; /* open when needed */
-        }
-      }
-      if(config->infile) {
-        /*
-         * We have specified a file to upload
-         */
-        struct stat fileinfo;
-
-        /* If no file name part is given in the URL, we add this file name */
-        char *ptr=strstr(url, "://");
-        if(ptr)
-          ptr+=3;
-        else
-          ptr=url;
-        ptr = strrchr(ptr, '/');
-        if(!ptr || !strlen(++ptr)) {
-          /* The URL has no file name part, add the local file name. In order
-             to be able to do so, we have to create a new URL in another
-             buffer.*/
-
-          /* 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, '\\');
-
-          if(file2)
-            filep = file2+1;
-          else if(filep)
-            filep++;
+        infdfopen=FALSE;
+        if(uploadfile && !curl_strequal(uploadfile, "-")) {
+          /*
+           * We have specified a file to upload and it isn't "-".
+           */
+          struct stat fileinfo;
+
+          /* If no file name part is given in the URL, we add this file name */
+          char *ptr=strstr(url, "://");
+          if(ptr)
+            ptr+=3;
           else
-            filep = config->infile;
+            ptr=url;
+          ptr = strrchr(ptr, '/');
+          if(!ptr || !strlen(++ptr)) {
+            /* The URL has no file name part, add the local file name. In order
+               to be able to do so, we have to create a new URL in another
+               buffer.*/
+
+            /* We only want the part of the local path that is on the right
+               side of the rightmost slash and backslash. */
+            char *filep = strrchr(uploadfile, '/');
+            char *file2 = strrchr(filep?filep:uploadfile, '\\');
+
+            if(file2)
+              filep = file2+1;
+            else if(filep)
+              filep++;
+            else
+              filep = uploadfile;
 
-          /* URL encode the file name */
-          filep = curl_escape(filep, 0 /* use strlen */);
+            /* URL encode the file name */
+            filep = curl_escape(filep, 0 /* use strlen */);
 
-          if(filep) {
+            if(filep) {
 
-            urlbuffer=(char *)malloc(strlen(url) + strlen(filep) + 3);
-            if(!urlbuffer) {
-              helpf("out of memory\n");
-              return CURLE_OUT_OF_MEMORY;
-            }
-            if(ptr)
-              /* there is a trailing slash on the URL */
-              sprintf(urlbuffer, "%s%s", url, filep);
-            else
-              /* thers is no trailing slash on the URL */
-              sprintf(urlbuffer, "%s/%s", url, filep);
+              urlbuffer=(char *)malloc(strlen(url) + strlen(filep) + 3);
+              if(!urlbuffer) {
+                helpf("out of memory\n");
+                return CURLE_OUT_OF_MEMORY;
+              }
+              if(ptr)
+                /* there is a trailing slash on the URL */
+                sprintf(urlbuffer, "%s%s", url, filep);
+              else
+                /* thers is no trailing slash on the URL */
+                sprintf(urlbuffer, "%s/%s", url, filep);
             
-            curl_free(filep);
+              curl_free(filep);
 
-            free(url);
-            url = urlbuffer; /* use our new URL instead! */
+              free(url);
+              url = urlbuffer; /* use our new URL instead! */
+            }
           }
-        }
 /*VMS??-- Reading binary from files can be a problem... */
 /*VMS??   Only FIXED, VAR etc WITHOUT implied CC will work */
 /*VMS??   Others need a \n appended to a line */
@@ -2876,288 +2934,290 @@ 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);
-          return CURLE_READ_ERROR;
-        }
-        infilesize=fileinfo.st_size;
+          infd=(FILE *) fopen(uploadfile, "rb");
+          if (!infd || stat(uploadfile, &fileinfo)) {
+            helpf("Can't open '%s'!\n", uploadfile);
+            return CURLE_READ_ERROR;
+          }
+          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 */
-      }
-      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 (urlnum > 1 && !(config->conf&CONF_MUTE)) {
-        fprintf(stderr, "\n[%d/%d]: %s --> %s\n",
-                i+1, urlnum, url, outfile ? outfile : "<stdout>");
-        if (separator)
-          printf("%s%s\n", CURLseparator, url);
-      }
-      if (httpgetfields) {
-        /* Find out whether the url contains a file name */
-        char *pc =strstr(url, "://");
-        char separator='?';
-        if(pc)
-          pc+=3;
-        else
-          pc=url;
+        }
+        else if(uploadfile && curl_strequal(uploadfile, "-")) {
+          infd = stdin;
+        }
 
-        pc = strrchr(pc, '/'); /* check for a slash */
+        if(uploadfile && config->resume_from_current)
+          config->resume_from = -1; /* -1 will then force get-it-yourself */
 
-        if(pc) {
-          /* there is a slash present in the URL */
+        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(strchr(pc, '?'))
-          /* Ouch, there's already a question mark in the URL string, we
-             then appead the data with an amperand separator instead! */
-            separator='&';
-        }
-        /*
-         * Then append ? followed by the get fields to the url.
-         */
-        urlbuffer=(char *)malloc(strlen(url) + strlen(httpgetfields) + 2);
-        if(!urlbuffer) {
-          helpf("out of memory\n");
-          return CURLE_OUT_OF_MEMORY;
+        if (urlnum > 1 && !(config->conf&CONF_MUTE)) {
+          fprintf(stderr, "\n[%d/%d]: %s --> %s\n",
+                  i+1, urlnum, url, outfile ? outfile : "<stdout>");
+          if (separator)
+            printf("%s%s\n", CURLseparator, url);
         }
-        if (pc)
-          sprintf(urlbuffer, "%s%c%s", url, separator, httpgetfields);
-        else
-          /* Append  / before the ? to create a well-formed url
-             if the url contains a hostname only
-          */
-          sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
+        if (httpgetfields) {
+          /* Find out whether the url contains a file name */
+          char *pc =strstr(url, "://");
+          char separator='?';
+          if(pc)
+            pc+=3;
+          else
+            pc=url;
+
+          pc = strrchr(pc, '/'); /* check for a slash */
+
+          if(pc) {
+            /* there is a slash present in the URL */
+
+            if(strchr(pc, '?'))
+              /* Ouch, there's already a question mark in the URL string, we
+                 then appead the data with an amperand separator instead! */
+              separator='&';
+          }
+          /*
+           * Then append ? followed by the get fields to the url.
+           */
+          urlbuffer=(char *)malloc(strlen(url) + strlen(httpgetfields) + 2);
+          if(!urlbuffer) {
+            helpf("out of memory\n");
+            return CURLE_OUT_OF_MEMORY;
+          }
+          if (pc)
+            sprintf(urlbuffer, "%s%c%s", url, separator, httpgetfields);
+          else
+            /* Append  / before the ? to create a well-formed url
+               if the url contains a hostname only
+            */
+            sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
  
-        free(url); /* free previous URL */
-        url = urlbuffer; /* use our new URL instead! */
-      }
+          free(url); /* free previous URL */
+          url = urlbuffer; /* use our new URL instead! */
+        }
 
-      if(!config->errors)
-        config->errors = stderr;
+        if(!config->errors)
+          config->errors = stderr;
 
 #ifdef O_BINARY
-      if(!outfile && !(config->conf & CONF_GETTEXT)) {
-        /* We get the output to stdout and we have not got the ASCII/text flag,
-           then set stdout to be binary */
-        setmode( fileno(stdout), O_BINARY );
-      }
+        if(!outfile && !(config->conf & CONF_GETTEXT)) {
+          /* We get the output to stdout and we have not got the ASCII/text flag,
+             then set stdout to be binary */
+          setmode( fileno(stdout), O_BINARY );
+        }
 #endif
 
-      curl_easy_setopt(curl, CURLOPT_SSLENGINE, config->engine);
-      curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
-
-      /* where to store */
-      curl_easy_setopt(curl, CURLOPT_WRITEDATA, (FILE *)&outs);
-      /* what call to write */
-      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
-
-      /* for uploads */
-      input.stream = infd;
-      input.config = config;
-      curl_easy_setopt(curl, CURLOPT_READDATA, &input);
-      /* what call to read */
-      curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_fread);
-
-      if(config->recvpersecond) {
-        /* tell libcurl to use a smaller sized buffer as it allows us to
-           make better sleeps! 7.9.9 stuff! */
-        curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
-      }
+        curl_easy_setopt(curl, CURLOPT_SSLENGINE, config->engine);
+        curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
+
+        /* where to store */
+        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (FILE *)&outs);
+        /* what call to write */
+        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
+
+        /* for uploads */
+        input.stream = infd;
+        input.config = config;
+        curl_easy_setopt(curl, CURLOPT_READDATA, &input);
+        /* what call to read */
+        curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_fread);
+
+        if(config->recvpersecond) {
+          /* tell libcurl to use a smaller sized buffer as it allows us to
+             make better sleeps! 7.9.9 stuff! */
+          curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
+        }
 
-      /* size of uploaded file: */
-      curl_easy_setopt(curl, CURLOPT_INFILESIZE, infilesize);
-      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);
-      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, config->conf&CONF_NOPROGRESS);
-      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_FTPLISTONLY,
-                       config->conf&CONF_FTPLISTONLY);
-      curl_easy_setopt(curl, CURLOPT_FTPAPPEND, config->conf&CONF_FTPAPPEND);
-
-      if (config->conf&CONF_NETRC_OPT)
-        curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
-      else if (config->conf&CONF_NETRC)
-        curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
-      else
-        curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
-
-      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
-                       config->conf&CONF_FOLLOWLOCATION);
-      curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
-                       config->conf&CONF_UNRESTRICTED_AUTH);
-      curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, config->conf&CONF_GETTEXT);
-      curl_easy_setopt(curl, CURLOPT_MUTE, config->conf&CONF_MUTE);
-      curl_easy_setopt(curl, CURLOPT_USERPWD, config->userpwd);
-      curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
-      curl_easy_setopt(curl, CURLOPT_RANGE, config->range);
-      curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
-      curl_easy_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
-      curl_easy_setopt(curl, CURLOPT_POSTFIELDS, config->postfields);
-
-      /* new in libcurl 7.2: */
-      curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, config->postfieldsize);
+        /* size of uploaded file: */
+        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);
+        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, config->conf&CONF_NOPROGRESS);
+        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, uploadfile?TRUE:FALSE);
+        curl_easy_setopt(curl, CURLOPT_FTPLISTONLY,
+                         config->conf&CONF_FTPLISTONLY);
+        curl_easy_setopt(curl, CURLOPT_FTPAPPEND, config->conf&CONF_FTPAPPEND);
+
+        if (config->conf&CONF_NETRC_OPT)
+          curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
+        else if (config->conf&CONF_NETRC)
+          curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
+        else
+          curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
+
+        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
+                         config->conf&CONF_FOLLOWLOCATION);
+        curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
+                         config->conf&CONF_UNRESTRICTED_AUTH);
+        curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, config->conf&CONF_GETTEXT);
+        curl_easy_setopt(curl, CURLOPT_MUTE, config->conf&CONF_MUTE);
+        curl_easy_setopt(curl, CURLOPT_USERPWD, config->userpwd);
+        curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
+        curl_easy_setopt(curl, CURLOPT_RANGE, config->range);
+        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
+        curl_easy_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
+        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, config->postfields);
+
+        /* new in libcurl 7.2: */
+        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, config->postfieldsize);
         
-      curl_easy_setopt(curl, CURLOPT_REFERER, config->referer);
-      curl_easy_setopt(curl, CURLOPT_AUTOREFERER,
-                       config->conf&CONF_AUTO_REFERER);
-      curl_easy_setopt(curl, CURLOPT_USERAGENT, config->useragent);
-      curl_easy_setopt(curl, CURLOPT_FTPPORT, config->ftpport);
-      curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit);
-      curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
-      curl_easy_setopt(curl, CURLOPT_RESUME_FROM,
-                       config->use_resume?config->resume_from:0);
-      curl_easy_setopt(curl, CURLOPT_COOKIE, config->cookie);
-      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
-      curl_easy_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
-      curl_easy_setopt(curl, CURLOPT_SSLCERT, config->cert);
-      curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
-      curl_easy_setopt(curl, CURLOPT_SSLKEY, config->key);
-      curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, config->key_type);
-      curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, config->key_passwd);
-
-      /* default to strict verifyhost */
-      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
-      if(config->cacert || config->capath) {
-        if (config->cacert)
-          curl_easy_setopt(curl, CURLOPT_CAINFO, config->cacert);
-
-        if (config->capath)
-          curl_easy_setopt(curl, CURLOPT_CAPATH, config->capath);
-        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
-      }
-      else
-        if(config->insecure_ok) {
-          /* new stuff needed for libcurl 7.10 */
-          curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
-          curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
+        curl_easy_setopt(curl, CURLOPT_REFERER, config->referer);
+        curl_easy_setopt(curl, CURLOPT_AUTOREFERER,
+                         config->conf&CONF_AUTO_REFERER);
+        curl_easy_setopt(curl, CURLOPT_USERAGENT, config->useragent);
+        curl_easy_setopt(curl, CURLOPT_FTPPORT, config->ftpport);
+        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit);
+        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
+        curl_easy_setopt(curl, CURLOPT_RESUME_FROM,
+                         config->use_resume?config->resume_from:0);
+        curl_easy_setopt(curl, CURLOPT_COOKIE, config->cookie);
+        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
+        curl_easy_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
+        curl_easy_setopt(curl, CURLOPT_SSLCERT, config->cert);
+        curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
+        curl_easy_setopt(curl, CURLOPT_SSLKEY, config->key);
+        curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, config->key_type);
+        curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, config->key_passwd);
+
+        /* default to strict verifyhost */
+        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
+        if(config->cacert || config->capath) {
+          if (config->cacert)
+            curl_easy_setopt(curl, CURLOPT_CAINFO, config->cacert);
+
+          if (config->capath)
+            curl_easy_setopt(curl, CURLOPT_CAPATH, config->capath);
+          curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
         }
+        else
+          if(config->insecure_ok) {
+            /* new stuff needed for libcurl 7.10 */
+            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
+            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
+          }
       
-      if((config->conf&CONF_NOBODY) ||
-         config->remote_time) {
-        /* no body or use remote time */
-        curl_easy_setopt(curl, CURLOPT_FILETIME, TRUE);
-      }
+        if((config->conf&CONF_NOBODY) ||
+           config->remote_time) {
+          /* no body or use remote time */
+          curl_easy_setopt(curl, CURLOPT_FILETIME, TRUE);
+        }
       
-      if (config->maxredirs) 
-        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); 
-      else 
-        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, DEFAULT_MAXREDIRS); 
+        if (config->maxredirs) 
+          curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); 
+        else 
+          curl_easy_setopt(curl, CURLOPT_MAXREDIRS, DEFAULT_MAXREDIRS); 
  
-      curl_easy_setopt(curl, CURLOPT_CRLF, config->crlf);
-      curl_easy_setopt(curl, CURLOPT_QUOTE, config->quote);
-      curl_easy_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
-      curl_easy_setopt(curl, CURLOPT_WRITEHEADER,
-                       config->headerfile?&heads:NULL);
-      curl_easy_setopt(curl, CURLOPT_COOKIEFILE, config->cookiefile);
-      /* cookie jar was added in 7.9 */
-      if(config->cookiejar)
-        curl_easy_setopt(curl, CURLOPT_COOKIEJAR, config->cookiejar);
-      /* cookie session added in 7.9.7 */
-      curl_easy_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
-
-      curl_easy_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
-      curl_easy_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
-      curl_easy_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
-      curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
-      curl_easy_setopt(curl, CURLOPT_STDERR, config->errors);
+        curl_easy_setopt(curl, CURLOPT_CRLF, config->crlf);
+        curl_easy_setopt(curl, CURLOPT_QUOTE, config->quote);
+        curl_easy_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
+        curl_easy_setopt(curl, CURLOPT_WRITEHEADER,
+                         config->headerfile?&heads:NULL);
+        curl_easy_setopt(curl, CURLOPT_COOKIEFILE, config->cookiefile);
+        /* cookie jar was added in 7.9 */
+        if(config->cookiejar)
+          curl_easy_setopt(curl, CURLOPT_COOKIEJAR, config->cookiejar);
+        /* cookie session added in 7.9.7 */
+        curl_easy_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
+
+        curl_easy_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
+        curl_easy_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
+        curl_easy_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
+        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
+        curl_easy_setopt(curl, CURLOPT_STDERR, config->errors);
       
-      /* three new ones in libcurl 7.3: */
-      curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
-      curl_easy_setopt(curl, CURLOPT_INTERFACE, config->iface);
-      curl_easy_setopt(curl, CURLOPT_KRB4LEVEL, config->krb4level);
+        /* three new ones in libcurl 7.3: */
+        curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
+        curl_easy_setopt(curl, CURLOPT_INTERFACE, config->iface);
+        curl_easy_setopt(curl, CURLOPT_KRB4LEVEL, config->krb4level);
       
-      if((config->progressmode == CURL_PROGRESS_BAR) &&
-         !(config->conf&(CONF_NOPROGRESS|CONF_MUTE))) {
-        /* we want the alternative style, then we have to implement it
-           ourselves! */
-        progressbarinit(&progressbar, config);
-        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
-        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
-      }
+        if((config->progressmode == CURL_PROGRESS_BAR) &&
+           !(config->conf&(CONF_NOPROGRESS|CONF_MUTE))) {
+          /* we want the alternative style, then we have to implement it
+             ourselves! */
+          progressbarinit(&progressbar, config);
+          curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
+          curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
+        }
         
-      /* new in libcurl 7.6.2: */
-      curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
+        /* new in libcurl 7.6.2: */
+        curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
 
-      /* new in libcurl 7.7: */
-      curl_easy_setopt(curl, CURLOPT_RANDOM_FILE, config->random_file);
-      curl_easy_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
-      curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
+        /* new in libcurl 7.7: */
+        curl_easy_setopt(curl, CURLOPT_RANDOM_FILE, config->random_file);
+        curl_easy_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
+        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
 
-      if(config->cipher_list)
-        curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
+        if(config->cipher_list)
+          curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
 
-      if(config->httpversion)
-        curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
+        if(config->httpversion)
+          curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
 
-      /* new in libcurl 7.9.2: */
-      if(config->disable_epsv)
-        /* disable it */
-        curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
+        /* new in libcurl 7.9.2: */
+        if(config->disable_epsv)
+          /* disable it */
+          curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
 
-      /* new in libcurl 7.10.5 */
-      if(config->disable_eprt)
-        /* disable it */
-        curl_easy_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
+        /* new in libcurl 7.10.5 */
+        if(config->disable_eprt)
+          /* disable it */
+          curl_easy_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
 
-      /* new in libcurl 7.10.6 (default is Basic) */
-      if(config->authtype)
-        curl_easy_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
+        /* new in libcurl 7.10.6 (default is Basic) */
+        if(config->authtype)
+          curl_easy_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
       
-      /* new in curl 7.9.7 */
-      if(config->trace_dump) {
-        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
-        curl_easy_setopt(curl, CURLOPT_DEBUGDATA, config);
-        config->conf |= CONF_VERBOSE; /* force verbose */
-      }
-      curl_easy_setopt(curl, CURLOPT_VERBOSE, config->conf&CONF_VERBOSE);
+        /* new in curl 7.9.7 */
+        if(config->trace_dump) {
+          curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
+          curl_easy_setopt(curl, CURLOPT_DEBUGDATA, config);
+          config->conf |= CONF_VERBOSE; /* force verbose */
+        }
+        curl_easy_setopt(curl, CURLOPT_VERBOSE, config->conf&CONF_VERBOSE);
 
-      /* new in curl 7.10 */
-      curl_easy_setopt(curl, CURLOPT_ENCODING, 
-                       (config->encoding) ? "" : NULL);
+        /* new in curl 7.10 */
+        curl_easy_setopt(curl, CURLOPT_ENCODING, 
+                         (config->encoding) ? "" : NULL);
 
-      /* new in curl 7.10.7 */
-      curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
-                       config->ftp_create_dirs);
-      if(config->proxyntlm)
-        curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
+        /* new in curl 7.10.7 */
+        curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
+                         config->ftp_create_dirs);
+        if(config->proxyntlm)
+          curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
 
-      res = curl_easy_perform(curl);
+        res = curl_easy_perform(curl);
         
-      if((config->progressmode == CURL_PROGRESS_BAR) &&
-         progressbar.calls) {
-        /* if the custom progress bar has been displayed, we output a
-           newline here */
-        fputs("\n", progressbar.out);
-      }
+        if((config->progressmode == CURL_PROGRESS_BAR) &&
+           progressbar.calls) {
+          /* if the custom progress bar has been displayed, we output a
+             newline here */
+          fputs("\n", progressbar.out);
+        }
 
-      if(config->writeout) {
-        ourWriteOut(curl, config->writeout);
-      }
+        if(config->writeout) {
+          ourWriteOut(curl, config->writeout);
+        }
 #ifdef USE_ENVIRONMENT
-      if (config->writeenv)
-        ourWriteEnv(curl);
+        if (config->writeenv)
+          ourWriteEnv(curl);
 #endif
 
 #ifdef VMS
-      if (!config->showerror)  {
-        vms_show = VMSSTS_HIDE;
-      }
+        if (!config->showerror)  {
+          vms_show = VMSSTS_HIDE;
+        }
 #else
-      if((res!=CURLE_OK) && config->showerror) {
-        if(CURLE_SSL_CACERT == res) {
-          fprintf(config->errors, "curl: (%d) %s\n\n", res, errorbuffer);
+        if((res!=CURLE_OK) && config->showerror) {
+          if(CURLE_SSL_CACERT == res) {
+            fprintf(config->errors, "curl: (%d) %s\n\n", res, errorbuffer);
 #define CURL_CA_CERT_ERRORMSG1 \
 "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
 "curl performs SSL certificate verification by default, using a \"bundle\"\n" \
@@ -3173,60 +3233,73 @@ operate(struct Configurable *config, int argc, char *argv[])
 "If you'd like to turn off curl's verification of the certificate, use\n" \
 " the -k (or --insecure) option.\n"
 
-          fprintf(config->errors, "%s%s",
-                  CURL_CA_CERT_ERRORMSG1,
-                  CURL_CA_CERT_ERRORMSG2 );
+            fprintf(config->errors, "%s%s",
+                    CURL_CA_CERT_ERRORMSG1,
+                    CURL_CA_CERT_ERRORMSG2 );
+          }
+          else
+            fprintf(config->errors, "curl: (%d) %s\n", res, errorbuffer);
         }
-        else
-          fprintf(config->errors, "curl: (%d) %s\n", res, errorbuffer);
-      }
 #endif
 
-      if (outfile && !curl_strequal(outfile, "-") && outs.stream)
-        fclose(outs.stream);
+        if (outfile && !curl_strequal(outfile, "-") && outs.stream)
+          fclose(outs.stream);
 
 #ifdef HAVE_UTIME
-      /* Important that we set the time _after_ the file has been 
-         closed, as is done above here */
-      if(config->remote_time && outs.filename) {
-        /* as libcurl if we got a time. Pretty please */
-        long filetime;
-        curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
-        if(filetime >= 0) {
-          struct utimbuf times;
-          times.actime = filetime;
-          times.modtime = filetime;
-          utime(outs.filename, &times); /* set the time we got */
+        /* Important that we set the time _after_ the file has been 
+           closed, as is done above here */
+        if(config->remote_time && outs.filename) {
+          /* as libcurl if we got a time. Pretty please */
+          long filetime;
+          curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
+          if(filetime >= 0) {
+            struct utimbuf times;
+            times.actime = filetime;
+            times.modtime = filetime;
+            utime(outs.filename, &times); /* set the time we got */
+          }
         }
-      }
 #endif
 
-      if (config->infile)
-        fclose(infd);
-      if(headerfilep)
-        fclose(headerfilep);
+        if(headerfilep)
+          fclose(headerfilep);
       
-      if (httpgetfields)
-        free(httpgetfields);
+        if (httpgetfields)
+          free(httpgetfields);
 
-      if(url)
-        free(url);
+        if(url)
+          free(url);
+
+        if(outfile)
+          free(outfile);
+
+        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(outfile)
-        free(outfile);
-    }
     if(outfiles)
       free(outfiles);
 
-    if(urls)
-      /* cleanup memory used for URL globbing patterns */
-      glob_cleanup(urls);
-
     /* 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;