⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 progress.c

📁 wget讓你可以在console介面下
💻 C
📖 第 1 页 / 共 2 页
字号:
  int stalled;			/* set when no data arrives for longer				   than STALL_START_TIME, then reset				   when new data arrives. */  /* create_image() uses these to make sure that ETA information     doesn't flicker. */  double last_eta_time;		/* time of the last update to download				   speed and ETA, measured since the				   beginning of download. */  wgint last_eta_value;};static void create_image PARAMS ((struct bar_progress *, double));static void display_image PARAMS ((char *));static void *bar_create (wgint initial, wgint total){  struct bar_progress *bp = xnew0 (struct bar_progress);  /* In theory, our callers should take care of this pathological     case, but it can sometimes happen. */  if (initial > total)    total = initial;  bp->initial_length = initial;  bp->total_length   = total;  /* Initialize screen_width if this hasn't been done or if it might     have changed, as indicated by receiving SIGWINCH.  */  if (!screen_width || received_sigwinch)    {      screen_width = determine_screen_width ();      if (!screen_width)	screen_width = DEFAULT_SCREEN_WIDTH;      else if (screen_width < MINIMUM_SCREEN_WIDTH)	screen_width = MINIMUM_SCREEN_WIDTH;      received_sigwinch = 0;    }  /* - 1 because we don't want to use the last screen column. */  bp->width = screen_width - 1;  /* + 1 for the terminating zero. */  bp->buffer = xmalloc (bp->width + 1);  logputs (LOG_VERBOSE, "\n");  create_image (bp, 0.0);  display_image (bp->buffer);  return bp;}static void update_speed_ring PARAMS ((struct bar_progress *, wgint, double));static voidbar_update (void *progress, wgint howmuch, double dltime){  struct bar_progress *bp = progress;  int force_screen_update = 0;  bp->count += howmuch;  if (bp->total_length > 0      && bp->count + bp->initial_length > bp->total_length)    /* We could be downloading more than total_length, e.g. when the       server sends an incorrect Content-Length header.  In that case,       adjust bp->total_length to the new reality, so that the code in       create_image() that depends on total size being smaller or       equal to the expected size doesn't abort.  */    bp->total_length = bp->initial_length + bp->count;  update_speed_ring (bp, howmuch, dltime);  /* If SIGWINCH (the window size change signal) been received,     determine the new screen size and update the screen.  */  if (received_sigwinch)    {      int old_width = screen_width;      screen_width = determine_screen_width ();      if (!screen_width)	screen_width = DEFAULT_SCREEN_WIDTH;      else if (screen_width < MINIMUM_SCREEN_WIDTH)	screen_width = MINIMUM_SCREEN_WIDTH;      if (screen_width != old_width)	{	  bp->width = screen_width - 1;	  bp->buffer = xrealloc (bp->buffer, bp->width + 1);	  force_screen_update = 1;	}      received_sigwinch = 0;    }  if (dltime - bp->last_screen_update < 200 && !force_screen_update)    /* Don't update more often than five times per second. */    return;  create_image (bp, dltime);  display_image (bp->buffer);  bp->last_screen_update = dltime;}static voidbar_finish (void *progress, double dltime){  struct bar_progress *bp = progress;  if (bp->total_length > 0      && bp->count + bp->initial_length > bp->total_length)    /* See bar_update() for explanation. */    bp->total_length = bp->initial_length + bp->count;  create_image (bp, dltime);  display_image (bp->buffer);  logputs (LOG_VERBOSE, "\n\n");  xfree (bp->buffer);  xfree (bp);}/* This code attempts to maintain the notion of a "current" download   speed, over the course of no less than 3s.  (Shorter intervals   produce very erratic results.)   To do so, it samples the speed in 150ms intervals and stores the   recorded samples in a FIFO history ring.  The ring stores no more   than 20 intervals, hence the history covers the period of at least   three seconds and at most 20 reads into the past.  This method   should produce reasonable results for downloads ranging from very   slow to very fast.   The idea is that for fast downloads, we get the speed over exactly   the last three seconds.  For slow downloads (where a network read   takes more than 150ms to complete), we get the speed over a larger   time period, as large as it takes to complete thirty reads.  This   is good because slow downloads tend to fluctuate more and a   3-second average would be too erratic.  */static voidupdate_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime){  struct bar_progress_hist *hist = &bp->hist;  double recent_age = dltime - bp->recent_start;  /* Update the download count. */  bp->recent_bytes += howmuch;  /* For very small time intervals, we return after having updated the     "recent" download count.  When its age reaches or exceeds minimum     sample time, it will be recorded in the history ring.  */  if (recent_age < DLSPEED_SAMPLE_MIN)    return;  if (howmuch == 0)    {      /* If we're not downloading anything, we might be stalling,	 i.e. not downloading anything for an extended period of time.	 Since 0-reads do not enter the history ring, recent_age	 effectively measures the time since last read.  */      if (recent_age >= STALL_START_TIME)	{	  /* If we're stalling, reset the ring contents because it's	     stale and because it will make bar_update stop printing	     the (bogus) current bandwidth.  */	  bp->stalled = 1;	  xzero (*hist);	  bp->recent_bytes = 0;	}      return;    }  /* We now have a non-zero amount of to store to the speed ring.  */  /* If the stall status was acquired, reset it. */  if (bp->stalled)    {      bp->stalled = 0;      /* "recent_age" includes the the entired stalled period, which	 could be very long.  Don't update the speed ring with that	 value because the current bandwidth would start too small.	 Start with an arbitrary (but more reasonable) time value and	 let it level out.  */      recent_age = 1000;    }  /* Store "recent" bytes and download time to history ring at the     position POS.  */  /* To correctly maintain the totals, first invalidate existing data     (least recent in time) at this position. */  hist->total_time  -= hist->times[hist->pos];  hist->total_bytes -= hist->bytes[hist->pos];  /* Now store the new data and update the totals. */  hist->times[hist->pos] = recent_age;  hist->bytes[hist->pos] = bp->recent_bytes;  hist->total_time  += recent_age;  hist->total_bytes += bp->recent_bytes;  /* Start a new "recent" period. */  bp->recent_start = dltime;  bp->recent_bytes = 0;  /* Advance the current ring position. */  if (++hist->pos == DLSPEED_HISTORY_SIZE)    hist->pos = 0;#if 0  /* Sledgehammer check to verify that the totals are accurate. */  {    int i;    double sumt = 0, sumb = 0;    for (i = 0; i < DLSPEED_HISTORY_SIZE; i++)      {	sumt += hist->times[i];	sumb += hist->bytes[i];      }    assert (sumt == hist->total_time);    assert (sumb == hist->total_bytes);  }#endif}#define APPEND_LITERAL(s) do {			\  memcpy (p, s, sizeof (s) - 1);		\  p += sizeof (s) - 1;				\} while (0)#ifndef MAX# define MAX(a, b) ((a) >= (b) ? (a) : (b))#endifstatic voidcreate_image (struct bar_progress *bp, double dl_total_time){  char *p = bp->buffer;  wgint size = bp->initial_length + bp->count;  char *size_legible = with_thousand_seps (size);  int size_legible_len = strlen (size_legible);  struct bar_progress_hist *hist = &bp->hist;  /* The progress bar should look like this:     xx% [=======>             ] nn,nnn 12.34K/s ETA 00:00     Calculate the geometry.  The idea is to assign as much room as     possible to the progress bar.  The other idea is to never let     things "jitter", i.e. pad elements that vary in size so that     their variance does not affect the placement of other elements.     It would be especially bad for the progress bar to be resized     randomly.     "xx% " or "100%"  - percentage               - 4 chars     "[]"              - progress bar decorations - 2 chars     " nnn,nnn,nnn"    - downloaded bytes         - 12 chars or very rarely more     " 1012.56K/s"     - dl rate                  - 11 chars     " ETA xx:xx:xx"   - ETA                      - 13 chars     "=====>..."       - progress bar             - the rest  */  int dlbytes_size = 1 + MAX (size_legible_len, 11);  int progress_size = bp->width - (4 + 2 + dlbytes_size + 11 + 13);  if (progress_size < 5)    progress_size = 0;  /* "xx% " */  if (bp->total_length > 0)    {      int percentage = (int)(100.0 * size / bp->total_length);      assert (percentage <= 100);      if (percentage < 100)	sprintf (p, "%2d%% ", percentage);      else	strcpy (p, "100%");      p += 4;    }  else    APPEND_LITERAL ("    ");  /* The progress bar: "[====>      ]" or "[++==>      ]". */  if (progress_size && bp->total_length > 0)    {      /* Size of the initial portion. */      int insz = (double)bp->initial_length / bp->total_length * progress_size;      /* Size of the downloaded portion. */      int dlsz = (double)size / bp->total_length * progress_size;      char *begin;      int i;      assert (dlsz <= progress_size);      assert (insz <= dlsz);      *p++ = '[';      begin = p;      /* Print the initial portion of the download with '+' chars, the	 rest with '=' and one '>'.  */      for (i = 0; i < insz; i++)	*p++ = '+';      dlsz -= insz;      if (dlsz > 0)	{	  for (i = 0; i < dlsz - 1; i++)	    *p++ = '=';	  *p++ = '>';	}      while (p - begin < progress_size)	*p++ = ' ';      *p++ = ']';    }  else if (progress_size)    {      /* If we can't draw a real progress bar, then at least show	 *something* to the user.  */      int ind = bp->tick % (progress_size * 2 - 6);      int i, pos;      /* Make the star move in two directions. */      if (ind < progress_size - 2)	pos = ind + 1;      else	pos = progress_size - (ind - progress_size + 5);      *p++ = '[';      for (i = 0; i < progress_size; i++)	{	  if      (i == pos - 1) *p++ = '<';	  else if (i == pos    ) *p++ = '=';	  else if (i == pos + 1) *p++ = '>';	  else	    *p++ = ' ';	}      *p++ = ']';      ++bp->tick;    }  /* " 234,567,890" */  sprintf (p, " %-11s", size_legible);  p += strlen (p);  /* " 1012.45K/s" */  if (hist->total_time && hist->total_bytes)    {      static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };      int units = 0;      /* Calculate the download speed using the history ring and	 recent data that hasn't made it to the ring yet.  */      wgint dlquant = hist->total_bytes + bp->recent_bytes;      double dltime = hist->total_time + (dl_total_time - bp->recent_start);      double dlspeed = calc_rate (dlquant, dltime, &units);      sprintf (p, " %7.2f%s", dlspeed, short_units[units]);      p += strlen (p);    }  else    APPEND_LITERAL ("   --.--K/s");  /* " ETA xx:xx:xx"; wait for three seconds before displaying the ETA.     That's because the ETA value needs a while to become     reliable.  */  if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000)    {      wgint eta;      int eta_hrs, eta_min, eta_sec;      /* Don't change the value of ETA more than approximately once	 per second; doing so would cause flashing without providing	 any value to the user. */      if (bp->total_length != size	  && bp->last_eta_value != 0	  && dl_total_time - bp->last_eta_time < 900)	eta = bp->last_eta_value;      else	{	  /* Calculate ETA using the average download speed to predict	     the future speed.  If you want to use a speed averaged	     over a more recent period, replace dl_total_time with	     hist->total_time and bp->count with hist->total_bytes.	     I found that doing that results in a very jerky and	     ultimately unreliable ETA.  */	  double time_sofar = (double)dl_total_time / 1000;	  wgint bytes_remaining = bp->total_length - size;	  eta = (wgint) (time_sofar * bytes_remaining / bp->count);	  bp->last_eta_value = eta;	  bp->last_eta_time = dl_total_time;	}      eta_hrs = eta / 3600, eta %= 3600;      eta_min = eta / 60,   eta %= 60;      eta_sec = eta;      if (eta_hrs > 99)	goto no_eta;      if (eta_hrs == 0)	{	  /* Hours not printed: pad with three spaces. */	  APPEND_LITERAL ("   ");	  sprintf (p, " ETA %02d:%02d", eta_min, eta_sec);	}      else	{	  if (eta_hrs < 10)	    /* Hours printed with one digit: pad with one space. */	    *p++ = ' ';	  sprintf (p, " ETA %d:%02d:%02d", eta_hrs, eta_min, eta_sec);	}      p += strlen (p);    }  else if (bp->total_length > 0)    {    no_eta:      APPEND_LITERAL ("             ");    }  assert (p - bp->buffer <= bp->width);  while (p < bp->buffer + bp->width)    *p++ = ' ';  *p = '\0';}/* Print the contents of the buffer as a one-line ASCII "image" so   that it can be overwritten next time.  */static voiddisplay_image (char *buf){  int old = log_set_save_context (0);  logputs (LOG_VERBOSE, "\r");  logputs (LOG_VERBOSE, buf);  log_set_save_context (old);}static voidbar_set_params (const char *params){  char *term = getenv ("TERM");  if (params      && 0 == strcmp (params, "force"))    current_impl_locked = 1;  if ((opt.lfilename#ifdef HAVE_ISATTY       /* The progress bar doesn't make sense if the output is not a	  TTY -- when logging to file, it is better to review the	  dots.  */       || !isatty (fileno (stderr))#endif       /* Normally we don't depend on terminal type because the	  progress bar only uses ^M to move the cursor to the	  beginning of line, which works even on dumb terminals.  But	  Jamie Zawinski reports that ^M and ^H tricks don't work in	  Emacs shell buffers, and only make a mess.  */       || (term && 0 == strcmp (term, "emacs"))       )      && !current_impl_locked)    {      /* We're not printing to a TTY, so revert to the fallback	 display.  #### We're recursively calling	 set_progress_implementation here, which is slightly kludgy.	 It would be nicer if we provided that function a return value	 indicating a failure of some sort.  */      set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION);      return;    }}#ifdef SIGWINCHRETSIGTYPEprogress_handle_sigwinch (int sig){  received_sigwinch = 1;  signal (SIGWINCH, progress_handle_sigwinch);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -