📄 utils.c
字号:
are currently used, which means that "%s %s %s" will work, but "%s %s %s %s" won't. If you need to print more than three wgints, bump the RING_SIZE (or rethink your message.) */char *number_to_static_string (wgint number){ static char ring[RING_SIZE][24]; static int ringpos; char *buf = ring[ringpos]; number_to_string (buf, number); ringpos = (ringpos + 1) % RING_SIZE; return buf;}/* Determine the width of the terminal we're running on. If that's not possible, return 0. */intdetermine_screen_width (void){ /* If there's a way to get the terminal size using POSIX tcgetattr(), somebody please tell me. */#ifdef TIOCGWINSZ int fd; struct winsize wsz; if (opt.lfilename != NULL) return 0; fd = fileno (stderr); if (ioctl (fd, TIOCGWINSZ, &wsz) < 0) return 0; /* most likely ENOTTY */ return wsz.ws_col;#else /* not TIOCGWINSZ */# ifdef WINDOWS CONSOLE_SCREEN_BUFFER_INFO csbi; if (!GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &csbi)) return 0; return csbi.dwSize.X;# else /* neither WINDOWS nor TIOCGWINSZ */ return 0;#endif /* neither WINDOWS nor TIOCGWINSZ */#endif /* not TIOCGWINSZ */}/* Return a random number between 0 and MAX-1, inclusive. If MAX is greater than the value of RAND_MAX+1 on the system, the returned value will be in the range [0, RAND_MAX]. This may be fixed in a future release. The random number generator is seeded automatically the first time it is called. This uses rand() for portability. It has been suggested that random() offers better randomness, but this is not required for Wget, so I chose to go for simplicity and use rand unconditionally. DO NOT use this for cryptographic purposes. It is only meant to be used in situations where quality of the random numbers returned doesn't really matter. */intrandom_number (int max){ static int seeded; double bounded; int rnd; if (!seeded) { srand (time (NULL)); seeded = 1; } rnd = rand (); /* On systems that don't define RAND_MAX, assume it to be 2**15 - 1, and enforce that assumption by masking other bits. */#ifndef RAND_MAX# define RAND_MAX 32767 rnd &= RAND_MAX;#endif /* This is equivalent to rand() % max, but uses the high-order bits for better randomness on architecture where rand() is implemented using a simple congruential generator. */ bounded = (double)max * rnd / (RAND_MAX + 1.0); return (int)bounded;}/* Return a random uniformly distributed floating point number in the [0, 1) range. The precision of returned numbers is 9 digits. Modify this to use erand48() where available! */doublerandom_float (void){ /* We can't rely on any specific value of RAND_MAX, but I'm pretty sure it's greater than 1000. */ int rnd1 = random_number (1000); int rnd2 = random_number (1000); int rnd3 = random_number (1000); return rnd1 / 1000.0 + rnd2 / 1000000.0 + rnd3 / 1000000000.0;}/* Implementation of run_with_timeout, a generic timeout-forcing routine for systems with Unix-like signal handling. */#ifdef USE_SIGNAL_TIMEOUT# ifdef HAVE_SIGSETJMP# define SETJMP(env) sigsetjmp (env, 1)static sigjmp_buf run_with_timeout_env;static RETSIGTYPEabort_run_with_timeout (int sig){ assert (sig == SIGALRM); siglongjmp (run_with_timeout_env, -1);}# else /* not HAVE_SIGSETJMP */# define SETJMP(env) setjmp (env)static jmp_buf run_with_timeout_env;static RETSIGTYPEabort_run_with_timeout (int sig){ assert (sig == SIGALRM); /* We don't have siglongjmp to preserve the set of blocked signals; if we longjumped out of the handler at this point, SIGALRM would remain blocked. We must unblock it manually. */ int mask = siggetmask (); mask &= ~sigmask (SIGALRM); sigsetmask (mask); /* Now it's safe to longjump. */ longjmp (run_with_timeout_env, -1);}# endif /* not HAVE_SIGSETJMP *//* Arrange for SIGALRM to be delivered in TIMEOUT seconds. This uses setitimer where available, alarm otherwise. TIMEOUT should be non-zero. If the timeout value is so small that it would be rounded to zero, it is rounded to the least legal value instead (1us for setitimer, 1s for alarm). That ensures that SIGALRM will be delivered in all cases. */static voidalarm_set (double timeout){#ifdef ITIMER_REAL /* Use the modern itimer interface. */ struct itimerval itv; xzero (itv); itv.it_value.tv_sec = (long) timeout; itv.it_value.tv_usec = 1000000 * (timeout - (long)timeout); if (itv.it_value.tv_sec == 0 && itv.it_value.tv_usec == 0) /* Ensure that we wait for at least the minimum interval. Specifying zero would mean "wait forever". */ itv.it_value.tv_usec = 1; setitimer (ITIMER_REAL, &itv, NULL);#else /* not ITIMER_REAL */ /* Use the old alarm() interface. */ int secs = (int) timeout; if (secs == 0) /* 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 non-zero if the function was interrupted with a timeout, zero 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. */intrun_with_timeout (double timeout, void (*fun) (void *), void *arg){ int saved_errno; if (timeout == 0) { fun (arg); return 0; } 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 1; } 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 0;}#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. */intrun_with_timeout (double timeout, void (*fun) (void *), void *arg){ fun (arg); return 0;}#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;#else /* not HAVE_NANOSLEEP */#ifdef 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 /* not HAVE_USLEEP */#ifdef HAVE_SELECT /* Note that, although Windows supports select, this sleeping strategy doesn't work there because Winsock's select doesn't implement timeout when it is passed NULL pointers for all fd sets. (But it does work under Cygwin, which implements its own 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. */#else /* not HAVE_SELECT */ sleep (seconds);#endif /* not HAVE_SELECT */#endif /* not HAVE_USLEEP */#endif /* not HAVE_NANOSLEEP */}#endif /* not WINDOWS *//* Encode the string STR of length LENGTH to base64 format and place it to B64STORE. The output will be \0-terminated, and must point to a writable buffer of at least 1+BASE64_LENGTH(length) bytes. It returns the length of the resulting base64 data, not counting the terminating zero. This implementation will not emit newlines after 76 characters of base64 data. */intbase64_encode (const char *str, int length, char *b64store){ /* Conversion table. */ static 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','+','/' }; int i; const unsigned char *s = (const unsigned char *) str; char *p = b64store; /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ for (i = 0; i < length; i += 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]; s += 3; } /* Pad the result if necessary... */ if (i == length + 1) *(p - 1) = '='; else if (i == length + 2) *(p - 1) = *(p - 2) = '='; /* ...and zero-terminate it. */ *p = '\0'; return p - b64store;}#define IS_ASCII(c) (((c) & 0x80) == 0)#define IS_BASE64(c) ((IS_ASCII (c) && base64_char_to_value[c] >= 0) || c == '=')/* Get next character from the string, except that non-base64 characters are ignored, as mandated by rfc2045. */#define NEXT_BASE64_CHAR(c, p) do { \ c = *p++; \} while (c != '\0' && !IS_BASE64 (c))/* Decode data from BASE64 (assumed to be encoded as base64) into memory pointed to by TO. TO should be large enough to accomodate the decoded data, which is guaranteed to be less than strlen(base64). Since TO 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. */intbase64_decode (const char *base64, char *to){ /* Table of base64 values for first 128 characters. Note that this assumes ASCII (but so does Wget in other places). */ static short 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 */ }; const char *p = base64; char *q = to; while (1) { unsigned char c; unsigned long value; /* Process first byte of a quadruplet. */ NEXT_BASE64_CHAR (c, p); if (!c) break; if (c == '=') return -1; /* illegal '=' while decoding base64 */ value = base64_char_to_value[c] << 18; /* Process scond byte of a quadruplet. */ NEXT_BASE64_CHAR (c, p); if (!c) return -1; /* premature EOF while decoding base64 */ if (c == '=') return -1; /* illegal `=' while decoding base64 */ value |= base64_char_to_value[c] << 12; *q++ = value >> 16; /* Process third byte of a quadruplet. */ NEXT_BASE64_CHAR (c, p); if (!c) return -1; /* premature EOF while decoding base64 */ if (c == '=') { NEXT_BASE64_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_BASE64_CHAR (c, p); if (!c) return -1; /* premature EOF while decoding base64 */ if (c == '=') continue; value |= base64_char_to_value[c]; *q++ = 0xff & value; } return q - to;}#undef IS_ASCII#undef IS_BASE64#undef NEXT_BASE64_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) PARAMS ((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) PARAMS ((const void *, const void *))){ if (size > 1) { void *temp = alloca (nmemb * size * sizeof (void *)); mergesort_internal (base, temp, size, 0, nmemb - 1, cmpfun); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -