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

📄 progress.c

📁 一个从网络上自动下载文件的自由工具
💻 C
📖 第 1 页 / 共 3 页
字号:
    }  /* 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 (sumb == hist->total_bytes);    /* We can't use assert(sumt==hist->total_time) because some       precision is lost by adding and subtracting floating-point       numbers.  But during a download this precision should not be       detectable, i.e. no larger than 1ns.  */    double diff = sumt - hist->total_time;    if (diff < 0) diff = -diff;    assert (diff < 1e-9);  }#endif}#define APPEND_LITERAL(s) do {                  \  memcpy (p, s, sizeof (s) - 1);                \  p += sizeof (s) - 1;                          \} while (0)/* Use move_to_end (s) to get S to point the end of the string (the   terminating \0).  This is faster than s+=strlen(s), but some people   are confused when they see strchr (s, '\0') in the code.  */#define move_to_end(s) s = strchr (s, '\0');#ifndef MAX# define MAX(a, b) ((a) >= (b) ? (a) : (b))#endifstatic voidcreate_image (struct bar_progress *bp, double dl_total_time, bool done){  char *p = bp->buffer;  wgint size = bp->initial_length + bp->count;  const char *size_grouped = with_thousand_seps (size);  int size_grouped_len = strlen (size_grouped);  struct bar_progress_hist *hist = &bp->hist;  /* The progress bar should look like this:     xx% [=======>             ] nn,nnn 12.34K/s  eta 36m 51s     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     " 12.5K/s"        - download rate             - 8 chars     "  eta 36m 51s"   - ETA                      - 13 chars     "=====>..."       - progress bar             - the rest  */  int dlbytes_size = 1 + MAX (size_grouped_len, 11);  int progress_size = bp->width - (4 + 2 + dlbytes_size + 8 + 13);  if (progress_size < 5)    progress_size = 0;  /* "xx% " */  if (bp->total_length > 0)    {      int percentage = 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_grouped);  move_to_end (p);  /* " 12.52K/s" */  if (hist->total_time > 0 && 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, " %4.*f%s", dlspeed >= 99.95 ? 0 : dlspeed >= 9.995 ? 1 : 2,               dlspeed, short_units[units]);      move_to_end (p);    }  else    APPEND_LITERAL (" --.-K/s");  if (!done)    {      /* "  eta ..m ..s"; 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 > 3)        {          int eta;          /* 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 < ETA_REFRESH_INTERVAL)            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.  */              wgint bytes_remaining = bp->total_length - size;              double eta_ = dl_total_time * bytes_remaining / bp->count;              if (eta_ >= INT_MAX - 1)                goto skip_eta;              eta = (int) (eta_ + 0.5);              bp->last_eta_value = eta;              bp->last_eta_time = dl_total_time;            }          /* Translation note: "ETA" is English-centric, but this must             be short, ideally 3 chars.  Abbreviate if necessary.  */          sprintf (p, _("  eta %s"), eta_to_human_short (eta, false));          move_to_end (p);        }      else if (bp->total_length > 0)        {        skip_eta:          APPEND_LITERAL ("             ");        }    }  else    {      /* When the download is done, print the elapsed time.  */      /* Note to translators: this should not take up more room than         available here.  Abbreviate if necessary.  */      strcpy (p, _("   in "));      move_to_end (p);          /* not p+=6, think translations! */      if (dl_total_time >= 10)        strcpy (p, eta_to_human_short ((int) (dl_total_time + 0.5), false));      else        sprintf (p, "%ss", print_decimal (dl_total_time));      move_to_end (p);    }  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){  bool old = log_set_save_context (false);  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 SIGWINCHvoidprogress_handle_sigwinch (int sig){  received_sigwinch = 1;  signal (SIGWINCH, progress_handle_sigwinch);}#endif/* Provide a short human-readable rendition of the ETA.  This is like   secs_to_human_time in main.c, except the output doesn't include   fractions (which would look silly in by nature imprecise ETA) and   takes less room.  If the time is measured in hours, hours and   minutes (but not seconds) are shown; if measured in days, then days   and hours are shown.  This ensures brevity while still displaying   as much as possible.   If CONDENSED is true, the separator between minutes and seconds   (and hours and minutes, etc.) is not included, shortening the   display by one additional character.  This is used for dot   progress.   The display never occupies more than 7 characters of screen   space.  */static const char *eta_to_human_short (int secs, bool condensed){  static char buf[10];          /* 8 should be enough, but just in case */  static int last = -1;  const char *space = condensed ? "" : " ";  /* Trivial optimization.  create_image can call us every 200 msecs     (see bar_update) for fast downloads, but ETA will only change     once per 900 msecs.  */  if (secs == last)    return buf;  last = secs;  if (secs < 100)    sprintf (buf, "%ds", secs);  else if (secs < 100 * 60)    sprintf (buf, "%dm%s%ds", secs / 60, space, secs % 60);  else if (secs < 48 * 3600)    sprintf (buf, "%dh%s%dm", secs / 3600, space, (secs / 60) % 60);  else if (secs < 100 * 86400)    sprintf (buf, "%dd%s%dh", secs / 86400, space, (secs / 3600) % 60);  else    /* even (2^31-1)/86400 doesn't overflow BUF. */    sprintf (buf, "%dd", secs / 86400);  return buf;}

⌨️ 快捷键说明

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