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

📄 utils.c

📁 Wget很好的处理了http和ftp的下载,很值得学习的经典代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    /* Round TIMEOUTs smaller than 1 to 1, not to zero.  This is       because alarm(0) means "never deliver the alarm", i.e. "wait       forever", which is not what someone who specifies a 0.5s       timeout would expect.  */    secs = 1;  alarm (secs);#endif /* not ITIMER_REAL */}/* Cancel the alarm set with alarm_set. */static voidalarm_cancel (void){#ifdef ITIMER_REAL  struct itimerval disable;  xzero (disable);  setitimer (ITIMER_REAL, &disable, NULL);#else  /* not ITIMER_REAL */  alarm (0);#endif /* not ITIMER_REAL */}/* Call FUN(ARG), but don't allow it to run for more than TIMEOUT   seconds.  Returns true if the function was interrupted with a   timeout, false otherwise.   This works by setting up SIGALRM to be delivered in TIMEOUT seconds   using setitimer() or alarm().  The timeout is enforced by   longjumping out of the SIGALRM handler.  This has several   advantages compared to the traditional approach of relying on   signals causing system calls to exit with EINTR:     * The callback function is *forcibly* interrupted after the       timeout expires, (almost) regardless of what it was doing and       whether it was in a syscall.  For example, a calculation that       takes a long time is interrupted as reliably as an IO       operation.     * It works with both SYSV and BSD signals because it doesn't       depend on the default setting of SA_RESTART.     * It doesn't require special handler setup beyond a simple call       to signal().  (It does use sigsetjmp/siglongjmp, but they're       optional.)   The only downside is that, if FUN allocates internal resources that   are normally freed prior to exit from the functions, they will be   lost in case of timeout.  */boolrun_with_timeout (double timeout, void (*fun) (void *), void *arg){  int saved_errno;  if (timeout == 0)    {      fun (arg);      return false;    }  signal (SIGALRM, abort_run_with_timeout);  if (SETJMP (run_with_timeout_env) != 0)    {      /* Longjumped out of FUN with a timeout. */      signal (SIGALRM, SIG_DFL);      return true;    }  alarm_set (timeout);  fun (arg);  /* Preserve errno in case alarm() or signal() modifies it. */  saved_errno = errno;  alarm_cancel ();  signal (SIGALRM, SIG_DFL);  errno = saved_errno;  return false;}#else  /* not USE_SIGNAL_TIMEOUT */#ifndef WINDOWS/* A stub version of run_with_timeout that just calls FUN(ARG).  Don't   define it under Windows, because Windows has its own version of   run_with_timeout that uses threads.  */boolrun_with_timeout (double timeout, void (*fun) (void *), void *arg){  fun (arg);  return false;}#endif /* not WINDOWS */#endif /* not USE_SIGNAL_TIMEOUT */#ifndef WINDOWS/* Sleep the specified amount of seconds.  On machines without   nanosleep(), this may sleep shorter if interrupted by signals.  */voidxsleep (double seconds){#ifdef HAVE_NANOSLEEP  /* nanosleep is the preferred interface because it offers high     accuracy and, more importantly, because it allows us to reliably     restart receiving a signal such as SIGWINCH.  (There was an     actual Debian bug report about --limit-rate malfunctioning while     the terminal was being resized.)  */  struct timespec sleep, remaining;  sleep.tv_sec = (long) seconds;  sleep.tv_nsec = 1000000000 * (seconds - (long) seconds);  while (nanosleep (&sleep, &remaining) < 0 && errno == EINTR)    /* If nanosleep has been interrupted by a signal, adjust the       sleeping period and return to sleep.  */    sleep = remaining;#elif defined(HAVE_USLEEP)  /* If usleep is available, use it in preference to select.  */  if (seconds >= 1)    {      /* On some systems, usleep cannot handle values larger than         1,000,000.  If the period is larger than that, use sleep         first, then add usleep for subsecond accuracy.  */      sleep (seconds);      seconds -= (long) seconds;    }  usleep (seconds * 1000000);#else /* fall back select */  /* Note that, although Windows supports select, it can't be used to     implement sleeping because Winsock's select doesn't implement     timeout when it is passed NULL pointers for all fd sets.  (But it     does under Cygwin, which implements Unix-compatible select.)  */  struct timeval sleep;  sleep.tv_sec = (long) seconds;  sleep.tv_usec = 1000000 * (seconds - (long) seconds);  select (0, NULL, NULL, NULL, &sleep);  /* If select returns -1 and errno is EINTR, it means we were     interrupted by a signal.  But without knowing how long we've     actually slept, we can't return to sleep.  Using gettimeofday to     track sleeps is slow and unreliable due to clock skew.  */#endif}#endif /* not WINDOWS *//* Encode the octets in DATA of length LENGTH to base64 format,   storing the result to DEST.  The output will be zero-terminated,   and must point to a writable buffer of at least   1+BASE64_LENGTH(length) bytes.  The function returns the length of   the resulting base64 data, not counting the terminating zero.   This implementation does not emit newlines after 76 characters of   base64 data.  */intbase64_encode (const void *data, int length, char *dest){  /* Conversion table.  */  static const char tbl[64] = {    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',    'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',    'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',    'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'  };  /* Access bytes in DATA as unsigned char, otherwise the shifts below     don't work for data with MSB set. */  const unsigned char *s = data;  /* Theoretical ANSI violation when length < 3. */  const unsigned char *end = (const unsigned char *) data + length - 2;  char *p = dest;  /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */  for (; s < end; s += 3)    {      *p++ = tbl[s[0] >> 2];      *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];      *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];      *p++ = tbl[s[2] & 0x3f];    }  /* Pad the result if necessary...  */  switch (length % 3)    {    case 1:      *p++ = tbl[s[0] >> 2];      *p++ = tbl[(s[0] & 3) << 4];      *p++ = '=';      *p++ = '=';      break;    case 2:      *p++ = tbl[s[0] >> 2];      *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];      *p++ = tbl[((s[1] & 0xf) << 2)];      *p++ = '=';      break;    }  /* ...and zero-terminate it.  */  *p = '\0';  return p - dest;}/* Store in C the next non-whitespace character from the string, or \0   when end of string is reached.  */#define NEXT_CHAR(c, p) do {                    \  c = (unsigned char) *p++;                     \} while (ISSPACE (c))#define IS_ASCII(c) (((c) & 0x80) == 0)/* Decode data from BASE64 (a null-terminated string) into memory   pointed to by DEST.  DEST is assumed to be large enough to   accomodate the decoded data, which is guaranteed to be no more than   3/4*strlen(base64).   Since DEST is assumed to contain binary data, it is not   NUL-terminated.  The function returns the length of the data   written to TO.  -1 is returned in case of error caused by malformed   base64 input.   This function originates from Free Recode.  */intbase64_decode (const char *base64, void *dest){  /* Table of base64 values for first 128 characters.  Note that this     assumes ASCII (but so does Wget in other places).  */  static const signed char base64_char_to_value[128] =    {      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /*   0-  9 */      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /*  10- 19 */      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /*  20- 29 */      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /*  30- 39 */      -1,  -1,  -1,  62,  -1,  -1,  -1,  63,  52,  53,  /*  40- 49 */      54,  55,  56,  57,  58,  59,  60,  61,  -1,  -1,  /*  50- 59 */      -1,  -1,  -1,  -1,  -1,  0,   1,   2,   3,   4,   /*  60- 69 */      5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  /*  70- 79 */      15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  /*  80- 89 */      25,  -1,  -1,  -1,  -1,  -1,  -1,  26,  27,  28,  /*  90- 99 */      29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  /* 100-109 */      39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  /* 110-119 */      49,  50,  51,  -1,  -1,  -1,  -1,  -1             /* 120-127 */    };#define BASE64_CHAR_TO_VALUE(c) ((int) base64_char_to_value[c])#define IS_BASE64(c) ((IS_ASCII (c) && BASE64_CHAR_TO_VALUE (c) >= 0) || c == '=')  const char *p = base64;  char *q = dest;  while (1)    {      unsigned char c;      unsigned long value;      /* Process first byte of a quadruplet.  */      NEXT_CHAR (c, p);      if (!c)        break;      if (c == '=' || !IS_BASE64 (c))        return -1;              /* illegal char while decoding base64 */      value = BASE64_CHAR_TO_VALUE (c) << 18;      /* Process second byte of a quadruplet.  */      NEXT_CHAR (c, p);      if (!c)        return -1;              /* premature EOF while decoding base64 */      if (c == '=' || !IS_BASE64 (c))        return -1;              /* illegal char while decoding base64 */      value |= BASE64_CHAR_TO_VALUE (c) << 12;      *q++ = value >> 16;      /* Process third byte of a quadruplet.  */      NEXT_CHAR (c, p);      if (!c)        return -1;              /* premature EOF while decoding base64 */      if (!IS_BASE64 (c))        return -1;              /* illegal char while decoding base64 */      if (c == '=')        {          NEXT_CHAR (c, p);          if (!c)            return -1;          /* premature EOF while decoding base64 */          if (c != '=')            return -1;          /* padding `=' expected but not found */          continue;        }      value |= BASE64_CHAR_TO_VALUE (c) << 6;      *q++ = 0xff & value >> 8;      /* Process fourth byte of a quadruplet.  */      NEXT_CHAR (c, p);      if (!c)        return -1;              /* premature EOF while decoding base64 */      if (c == '=')        continue;      if (!IS_BASE64 (c))        return -1;              /* illegal char while decoding base64 */      value |= BASE64_CHAR_TO_VALUE (c);      *q++ = 0xff & value;    }#undef IS_BASE64#undef BASE64_CHAR_TO_VALUE  return q - (char *) dest;}#undef IS_ASCII#undef NEXT_CHAR/* Simple merge sort for use by stable_sort.  Implementation courtesy   Zeljko Vrba with additional debugging by Nenad Barbutov.  */static voidmergesort_internal (void *base, void *temp, size_t size, size_t from, size_t to,                    int (*cmpfun) (const void *, const void *)){#define ELT(array, pos) ((char *)(array) + (pos) * size)  if (from < to)    {      size_t i, j, k;      size_t mid = (to + from) / 2;      mergesort_internal (base, temp, size, from, mid, cmpfun);      mergesort_internal (base, temp, size, mid + 1, to, cmpfun);      i = from;      j = mid + 1;      for (k = from; (i <= mid) && (j <= to); k++)        if (cmpfun (ELT (base, i), ELT (base, j)) <= 0)          memcpy (ELT (temp, k), ELT (base, i++), size);        else          memcpy (ELT (temp, k), ELT (base, j++), size);      while (i <= mid)        memcpy (ELT (temp, k++), ELT (base, i++), size);      while (j <= to)        memcpy (ELT (temp, k++), ELT (base, j++), size);      for (k = from; k <= to; k++)        memcpy (ELT (base, k), ELT (temp, k), size);    }#undef ELT}/* Stable sort with interface exactly like standard library's qsort.   Uses mergesort internally, allocating temporary storage with   alloca.  */voidstable_sort (void *base, size_t nmemb, size_t size,             int (*cmpfun) (const void *, const void *)){  if (size > 1)    {      void *temp = alloca (nmemb * size * sizeof (void *));      mergesort_internal (base, temp, size, 0, nmemb - 1, cmpfun);    }}/* Print a decimal number.  If it is equal to or larger than ten, the   number is rounded.  Otherwise it is printed with one significant   digit without trailing zeros and with no more than three fractional   digits total.  For example, 0.1 is printed as "0.1", 0.035 is   printed as "0.04", 0.0091 as "0.009", and 0.0003 as simply "0".   This is useful for displaying durations because it provides   order-of-magnitude information without unnecessary clutter --   long-running downloads are shown without the fractional part, and   short ones still retain one significant digit.  */const char *print_decimal (double number){  static char buf[32];  double n = number >= 0 ? number : -number;  if (n >= 9.95)    /* Cut off at 9.95 because the below %.1f would round 9.96 to       "10.0" instead of "10".  OTOH 9.94 will print as "9.9".  */    snprintf (buf, sizeof buf, "%.0f", number);  else if (n >= 0.95)    snprintf (buf, sizeof buf, "%.1f", number);  else if (n >= 0.001)    snprintf (buf, sizeof buf, "%.1g", number);  else if (n >= 0.0005)    /* round [0.0005, 0.001) to 0.001 */    snprintf (buf, sizeof buf, "%.3f", number);  else    /* print numbers close to 0 as 0, not 0.000 */    strcpy (buf, "0");  return buf;}#ifdef TESTINGconst char *test_subdir_p(){  int i;  struct {    char *d1;    char *d2;    bool result;  } test_array[] = {    { "/somedir", "/somedir", true },    { "/somedir", "/somedir/d2", true },    { "/somedir/d1", "/somedir", false },  };    for (i = 0; i < countof(test_array); ++i)     {      bool res = subdir_p (test_array[i].d1, test_array[i].d2);      mu_assert ("test_subdir_p: wrong result",                  res == test_array[i].result);    }  return NULL;}const char *test_dir_matches_p(){  int i;  struct {    char *dirlist[3];    char *dir;    bool result;  } test_array[] = {    { { "/somedir", "/someotherdir", NULL }, "somedir", true },    { { "/somedir", "/someotherdir", NULL }, "anotherdir", false },    { { "/somedir", "/*otherdir", NULL }, "anotherdir", true },    { { "/somedir/d1", "/someotherdir", NULL }, "somedir/d1", true },    { { "*/*d1", "/someotherdir", NULL }, "somedir/d1", true },    { { "/somedir/d1", "/someotherdir", NULL }, "d1", false },

⌨️ 快捷键说明

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