]> sjero.net Git - wget/blobdiff - src/retr.c
[svn] Declare the pointers to literal strings as `const'.
[wget] / src / retr.c
index eedabd8d6e0348248c9a9499dc1d0abdcbd3cb7c..1aae6e23702c77f0103e8d6a294f9078fe60f796 100644 (file)
@@ -63,12 +63,16 @@ so, delete this exception statement from your version.  */
 extern int errno;
 #endif
 
-/* See the comment in gethttp() why this is needed. */
-int global_download_count;
-
 /* Total size of downloaded files.  Used to enforce quota.  */
 LARGE_INT total_downloaded_bytes;
 
+/* If non-NULL, the stream to which output should be written.  This
+   stream is initialized when `-O' is used.  */
+FILE *output_stream;
+
+/* Whether output_document is a regular file we can manipulate,
+   i.e. not `-' or a device file. */
+int output_stream_regular;
 \f
 static struct {
   long chunk_bytes;
@@ -133,32 +137,71 @@ limit_bandwidth (long bytes, struct wget_timer *timer)
 # define MIN(i, j) ((i) <= (j) ? (i) : (j))
 #endif
 
-/* Reads the contents of file descriptor FD, until it is closed, or a
-   read error occurs.  The data is read in 8K chunks, and stored to
-   stream fp, which should have been open for writing.
+/* Write data in BUF to OUT.  However, if *SKIP is non-zero, skip that
+   amount of data and decrease SKIP.  Increment *TOTAL by the amount
+   of data written.  */
+
+static int
+write_data (FILE *out, const char *buf, int bufsize, long *skip,
+           long *written)
+{
+  if (!out)
+    return 1;
+  if (*skip > bufsize)
+    {
+      *skip -= bufsize;
+      return 1;
+    }
+  if (*skip)
+    {
+      buf += *skip;
+      bufsize -= *skip;
+      *skip = 0;
+      if (bufsize == 0)
+       return 1;
+    }
+
+  fwrite (buf, 1, bufsize, out);
+  *written += bufsize;
 
-   The EXPECTED argument is passed to show_progress() unchanged, but
-   otherwise ignored.
+  /* Immediately flush the downloaded data.  This should not hinder
+     performance: fast downloads will arrive in large 16K chunks
+     (which stdio would write out immediately anyway), and slow
+     downloads wouldn't be limited by disk speed.  */
+  fflush (out);
+  return !ferror (out);
+}
 
-   If opt.verbose is set, the progress is also shown.  RESTVAL
-   (RESTart VALue) is the position from which the download starts,
-   needed for progress display.
+/* Read the contents of file descriptor FD until it the connection
+   terminates or a read error occurs.  The data is read in portions of
+   up to 16K and written to OUT as it arrives.  If opt.verbose is set,
+   the progress is shown.
 
-   The function exits and returns codes of 0, -1 and -2 if the
-   connection was closed, there was a read error, or if it could not
-   write to the output stream, respectively.  */
+   TOREAD is the amount of data expected to arrive, normally only used
+   by the progress gauge.
+
+   STARTPOS is the position from which the download starts, used by
+   the progress gauge.  If QTYREAD is non-NULL, the value it points to
+   is incremented by the amount of data read from the network.  If
+   QTYWRITTEN is non-NULL, the value it points to is incremented by
+   the amount of data written to disk.  The time it took to download
+   the data (in milliseconds) is stored to ELAPSED.
+
+   The function exits and returns the amount of data read.  In case of
+   error while reading data, -1 is returned.  In case of error while
+   writing data, -2 is returned.  */
 
 int
-fd_read_body (int fd, FILE *out, long *len, long restval, long expected,
-             int use_expected, double *elapsed)
+fd_read_body (int fd, FILE *out, long toread, long startpos,
+             long *qtyread, long *qtywritten, double *elapsed, int flags)
 {
-  int res = 0;
+  int ret = 0;
 
   static char dlbuf[16384];
   int dlbufsize = sizeof (dlbuf);
 
-  struct wget_timer *timer = wtimer_allocate ();
-  double last_successful_read_tm;
+  struct wget_timer *timer = NULL;
+  double last_successful_read_tm = 0;
 
   /* The progress gauge, set according to the user preferences. */
   void *progress = NULL;
@@ -169,18 +212,36 @@ fd_read_body (int fd, FILE *out, long *len, long restval, long expected,
      data arrives slowly. */
   int progress_interactive = 0;
 
-  *len = restval;
+  int exact = flags & rb_read_exactly;
+  long skip = 0;
+
+  /* How much data we've read/written.  */
+  long sum_read = 0;
+  long sum_written = 0;
+
+  if (flags & rb_skip_startpos)
+    skip = startpos;
 
   if (opt.verbose)
     {
-      progress = progress_create (restval, expected);
+      /* If we're skipping STARTPOS bytes, pass 0 as the INITIAL
+        argument to progress_create because the indicator doesn't
+        (yet) know about "skipping" data.  */
+      progress = progress_create (skip ? 0 : startpos, startpos + toread);
       progress_interactive = progress_interactive_p (progress);
     }
 
   if (opt.limit_rate)
     limit_bandwidth_reset ();
-  wtimer_reset (timer);
-  last_successful_read_tm = 0;
+
+  /* A timer is needed for tracking progress, for throttling, and for
+     tracking elapsed time.  If either of these are requested, start
+     the timer.  */
+  if (progress || opt.limit_rate || elapsed)
+    {
+      timer = wtimer_new ();
+      last_successful_read_tm = 0;
+    }
 
   /* Use a smaller buffer for low requested bandwidths.  For example,
      with --limit-rate=2k, it doesn't make sense to slurp in 16K of
@@ -189,86 +250,90 @@ fd_read_body (int fd, FILE *out, long *len, long restval, long expected,
   if (opt.limit_rate && opt.limit_rate < dlbufsize)
     dlbufsize = opt.limit_rate;
 
-  /* Read from FD while there is available data.
-
-     Normally, if expected is 0, it means that it is not known how
-     much data is expected.  However, if use_expected is specified,
-     then expected being zero means exactly that.  */
-  while (!use_expected || (*len < expected))
+  /* Read from FD while there is data to read.  Normally toread==0
+     means that it is unknown how much data is to arrive.  However, if
+     EXACT is set, then toread==0 means what it says: that no data
+     should be read.  */
+  while (!exact || (sum_read < toread))
     {
-      int amount_to_read = (use_expected
-                           ? MIN (expected - *len, dlbufsize) : dlbufsize);
+      int rdsize = exact ? MIN (toread - sum_read, dlbufsize) : dlbufsize;
       double tmout = opt.read_timeout;
       if (progress_interactive)
        {
-         double waittm;
          /* For interactive progress gauges, always specify a ~1s
             timeout, so that the gauge can be updated regularly even
             when the data arrives very slowly or stalls.  */
          tmout = 0.95;
-         waittm = (wtimer_read (timer) - last_successful_read_tm) / 1000;
-         if (waittm + tmout > opt.read_timeout)
+         if (opt.read_timeout)
            {
-             /* Don't allow waiting time to exceed read timeout. */
-             tmout = opt.read_timeout - waittm;
-             if (tmout < 0)
+             double waittm;
+             waittm = (wtimer_read (timer) - last_successful_read_tm) / 1000;
+             if (waittm + tmout > opt.read_timeout)
                {
-                 /* We've already exceeded the timeout. */
-                 res = -1, errno = ETIMEDOUT;
-                 break;
+                 /* Don't let total idle time exceed read timeout. */
+                 tmout = opt.read_timeout - waittm;
+                 if (tmout < 0)
+                   {
+                     /* We've already exceeded the timeout. */
+                     ret = -1, errno = ETIMEDOUT;
+                     break;
+                   }
                }
            }
        }
-      res = fd_read (fd, dlbuf, amount_to_read, tmout);
+      ret = fd_read (fd, dlbuf, rdsize, tmout);
 
-      if (res == 0 || (res < 0 && errno != ETIMEDOUT))
-       break;
-      else if (res < 0)
-       res = 0;                /* timeout */
+      if (ret == 0 || (ret < 0 && errno != ETIMEDOUT))
+       break;                  /* read error */
+      else if (ret < 0)
+       ret = 0;                /* read timeout */
 
-      wtimer_update (timer);
-      if (res > 0)
+      if (progress || opt.limit_rate)
+       {
+         wtimer_update (timer);
+         if (ret > 0)
+           last_successful_read_tm = wtimer_read (timer);
+       }
+
+      if (ret > 0)
        {
-         if (out)
+         sum_read += ret;
+         if (!write_data (out, dlbuf, ret, &skip, &sum_written))
            {
-             fwrite (dlbuf, 1, res, out);
-             /* Always flush the contents of the network packet.
-                This should not hinder performance: fast downloads
-                will be received in 16K chunks (which stdio would
-                write out anyway), and slow downloads won't be
-                limited by disk performance.  */
-             fflush (out);
-             if (ferror (out))
-               {
-                 res = -2;
-                 goto out;
-               }
+             ret = -2;
+             goto out;
            }
-         last_successful_read_tm = wtimer_read (timer);
        }
 
       if (opt.limit_rate)
-       limit_bandwidth (res, timer);
+       limit_bandwidth (ret, timer);
 
-      *len += res;
       if (progress)
-       progress_update (progress, res, wtimer_read (timer));
+       progress_update (progress, ret, wtimer_read (timer));
 #ifdef WINDOWS
-      if (use_expected && expected > 0)
-       ws_percenttitle (100.0 * (double)(*len) / (double)expected);
+      if (toread > 0)
+       ws_percenttitle (100.0 *
+                        (startpos + sum_read) / (startpos + toread));
 #endif
     }
-  if (res < -1)
-    res = -1;
+  if (ret < -1)
+    ret = -1;
 
  out:
   if (progress)
     progress_finish (progress, wtimer_read (timer));
+
   if (elapsed)
     *elapsed = wtimer_read (timer);
-  wtimer_delete (timer);
+  if (timer)
+    wtimer_delete (timer);
 
-  return res;
+  if (qtyread)
+    *qtyread += sum_read;
+  if (qtywritten)
+    *qtywritten += sum_written;
+
+  return ret;
 }
 \f
 /* Read a hunk of data from FD, up until a terminator.  The terminator
@@ -420,7 +485,7 @@ char *
 retr_rate (long bytes, double msecs, int pad)
 {
   static char res[20];
-  static char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s" };
+  static const char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s" };
   int units = 0;
 
   double dlrate = calc_rate (bytes, msecs, &units);
@@ -702,7 +767,6 @@ retrieve_url (const char *origurl, char **file, char **newloc,
       xfree (url);
     }
 
-  ++global_download_count;
   RESTORE_POST_DATA;
 
   return result;