📄 utils.c
字号:
/* Approximately, the time elapsed between the true start of the measurement and the time represented by START. */ double elapsed_pre_start;};/* Allocate a timer. It is not legal to do anything with a freshly allocated timer, except call wtimer_reset() or wtimer_delete(). */struct wget_timer *wtimer_allocate (void){ struct wget_timer *wt = (struct wget_timer *)xmalloc (sizeof (struct wget_timer)); return wt;}/* Allocate a new timer and reset it. Return the new timer. */struct wget_timer *wtimer_new (void){ struct wget_timer *wt = wtimer_allocate (); wtimer_reset (wt); return wt;}/* Free the resources associated with the timer. Its further use is prohibited. */voidwtimer_delete (struct wget_timer *wt){ xfree (wt);}/* Store system time to WST. */static voidwtimer_sys_set (wget_sys_time *wst){#ifdef TIMER_GETTIMEOFDAY gettimeofday (wst, NULL);#endif#ifdef TIMER_TIME time (wst);#endif#ifdef TIMER_WINDOWS /* We use GetSystemTime to get the elapsed time. MSDN warns that system clock adjustments can skew the output of GetSystemTime when used as a timer and gives preference to GetTickCount and high-resolution timers. But GetTickCount can overflow, and hires timers are typically used for profiling, not for regular time measurement. Since we handle clock skew anyway, we just use GetSystemTime. */ FILETIME ft; SYSTEMTIME st; GetSystemTime (&st); /* As recommended by MSDN, we convert SYSTEMTIME to FILETIME, copy FILETIME to ULARGE_INTEGER, and use regular 64-bit integer arithmetic on that. */ SystemTimeToFileTime (&st, &ft); wst->HighPart = ft.dwHighDateTime; wst->LowPart = ft.dwLowDateTime;#endif}/* Reset timer WT. This establishes the starting point from which wtimer_elapsed() will return the number of elapsed milliseconds. It is allowed to reset a previously used timer. */voidwtimer_reset (struct wget_timer *wt){ /* Set the start time to the current time. */ wtimer_sys_set (&wt->start); wt->elapsed_last = 0; wt->elapsed_pre_start = 0;}static doublewtimer_sys_diff (wget_sys_time *wst1, wget_sys_time *wst2){#ifdef TIMER_GETTIMEOFDAY return ((double)(wst1->tv_sec - wst2->tv_sec) * 1000 + (double)(wst1->tv_usec - wst2->tv_usec) / 1000);#endif#ifdef TIMER_TIME return 1000 * (*wst1 - *wst2);#endif#ifdef WINDOWS /* VC++ 6 doesn't support direct cast of uint64 to double. To work around this, we subtract, then convert to signed, then finally to double. */ return (double)(signed __int64)(wst1->QuadPart - wst2->QuadPart) / 10000;#endif}/* Return the number of milliseconds elapsed since the timer was last reset. It is allowed to call this function more than once to get increasingly higher elapsed values. These timers handle clock skew. */doublewtimer_elapsed (struct wget_timer *wt){ wget_sys_time now; double elapsed; wtimer_sys_set (&now); elapsed = wt->elapsed_pre_start + wtimer_sys_diff (&now, &wt->start); /* Ideally we'd just return the difference between NOW and wt->start. However, the system timer can be set back, and we could return a value smaller than when we were last called, even a negative value. Both of these would confuse the callers, which expect us to return monotonically nondecreasing values. Therefore: if ELAPSED is smaller than its previous known value, we reset wt->start to the current time and effectively start measuring from this point. But since we don't want the elapsed value to start from zero, we set elapsed_pre_start to the last elapsed time and increment all future calculations by that amount. */ if (elapsed < wt->elapsed_last) { wt->start = now; wt->elapsed_pre_start = wt->elapsed_last; elapsed = wt->elapsed_last; } wt->elapsed_last = elapsed; return elapsed;}/* Return the assessed granularity of the timer implementation, in milliseconds. This is used by code that tries to substitute a better value for timers that have returned zero. */doublewtimer_granularity (void){#ifdef TIMER_GETTIMEOFDAY /* Granularity of gettimeofday varies wildly between architectures. However, it appears that on modern machines it tends to be better than 1ms. Assume 100 usecs. (Perhaps the configure process could actually measure this?) */ return 0.1;#endif#ifdef TIMER_TIME return 1000;#endif#ifdef TIMER_WINDOWS /* According to MSDN, GetSystemTime returns a broken-down time structure the smallest member of which are milliseconds. */ return 1;#endif}/* This should probably be at a better place, but it doesn't really fit into html-parse.c. *//* The function returns the pointer to the malloc-ed quoted version of string s. It will recognize and quote numeric and special graphic entities, as per RFC1866: `&' -> `&' `<' -> `<' `>' -> `>' `"' -> `"' SP -> ` ' No other entities are recognized or replaced. */char *html_quote_string (const char *s){ const char *b = s; char *p, *res; int i; /* Pass through the string, and count the new size. */ for (i = 0; *s; s++, i++) { if (*s == '&') i += 4; /* `amp;' */ else if (*s == '<' || *s == '>') i += 3; /* `lt;' and `gt;' */ else if (*s == '\"') i += 5; /* `quot;' */ else if (*s == ' ') i += 4; /* #32; */ } res = (char *)xmalloc (i + 1); s = b; for (p = res; *s; s++) { switch (*s) { case '&': *p++ = '&'; *p++ = 'a'; *p++ = 'm'; *p++ = 'p'; *p++ = ';'; break; case '<': case '>': *p++ = '&'; *p++ = (*s == '<' ? 'l' : 'g'); *p++ = 't'; *p++ = ';'; break; case '\"': *p++ = '&'; *p++ = 'q'; *p++ = 'u'; *p++ = 'o'; *p++ = 't'; *p++ = ';'; break; case ' ': *p++ = '&'; *p++ = '#'; *p++ = '3'; *p++ = '2'; *p++ = ';'; break; default: *p++ = *s; } } *p = '\0'; return res;}/* 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. */#ifndef TIOCGWINSZ return 0;#else /* 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;#endif /* 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;}#if 0/* A debugging function for checking whether an MD5 library works. */#include "gen-md5.h"char *debug_test_md5 (char *buf){ unsigned char raw[16]; static char res[33]; unsigned char *p1; char *p2; int cnt; ALLOCA_MD5_CONTEXT (ctx); gen_md5_init (ctx); gen_md5_update ((unsigned char *)buf, strlen (buf), ctx); gen_md5_finish (ctx, raw); p1 = raw; p2 = res; cnt = 16; while (cnt--) { *p2++ = XNUM_TO_digit (*p1 >> 4); *p2++ = XNUM_TO_digit (*p1 & 0xf); ++p1; } *p2 = '\0'; return res;}#endif/* 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; memset (&itv, 0, sizeof (itv)); itv.it_value.tv_sec = (long) timeout; itv.it_value.tv_usec = 1000000L * (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; memset (&disable, 0, sizeof (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 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -