X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Futils.c;h=74e4552fd4eeb5c67e58085a3e741a24ea42267f;hb=9228f0bf53d3b42459daeb28372196a007de3014;hp=335144932a1b8b894578a2100dcc86276671de83;hpb=5cb8a6f44dc55734dc1def8abd904ed9108f4d67;p=wget diff --git a/src/utils.c b/src/utils.c index 33514493..74e4552f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -16,7 +16,17 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wget; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +In addition, as a special exception, the Free Software Foundation +gives permission to link the code of its release of Wget with the +OpenSSL project's "OpenSSL" library (or with modified versions of it +that use the same license as the "OpenSSL" library), and distribute +the linked executables. You must obey the GNU General Public License +in all respects for all of the code used other than "OpenSSL". If you +modify this file, you may extend this exception to your version of the +file, but you are not obligated to do so. If you do not wish to do +so, delete this exception statement from your version. */ #include @@ -755,20 +765,37 @@ accdir (const char *directory, enum accd flags) return 1; } -/* Match the end of STRING against PATTERN. For instance: +/* Return non-zero if STRING ends with TAIL. For instance: + + match_tail ("abc", "bc", 0) -> 1 + match_tail ("abc", "ab", 0) -> 0 + match_tail ("abc", "abc", 0) -> 1 + + If FOLD_CASE_P is non-zero, the comparison will be + case-insensitive. */ - match_backwards ("abc", "bc") -> 1 - match_backwards ("abc", "ab") -> 0 - match_backwards ("abc", "abc") -> 1 */ int -match_tail (const char *string, const char *pattern) +match_tail (const char *string, const char *tail, int fold_case_p) { int i, j; - for (i = strlen (string), j = strlen (pattern); i >= 0 && j >= 0; i--, j--) - if (string[i] != pattern[j]) - break; - /* If the pattern was exhausted, the match was succesful. */ + /* We want this to be fast, so we code two loops, one with + case-folding, one without. */ + + if (!fold_case_p) + { + for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--) + if (string[i] != tail[j]) + break; + } + else + { + for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--) + if (TOLOWER (string[i]) != TOLOWER (tail[j])) + break; + } + + /* If the tail was exhausted, the match was succesful. */ if (j == -1) return 1; else @@ -797,7 +824,7 @@ in_acclist (const char *const *accepts, const char *s, int backward) { if (backward) { - if (match_tail (s, *accepts)) + if (match_tail (s, *accepts, 0)) return 1; } else @@ -1347,6 +1374,12 @@ numdigit (long number) return cnt; } +/* A half-assed implementation of INT_MAX on machines that don't + bother to define one. */ +#ifndef INT_MAX +# define INT_MAX ((int) ~((unsigned)1 << 8 * sizeof (int) - 1)) +#endif + #define ONE_DIGIT(figure) *p++ = n / (figure) + '0' #define ONE_DIGIT_ADVANCE(figure) (ONE_DIGIT (figure), n %= (figure)) @@ -1406,6 +1439,15 @@ number_to_string (char *buffer, long number) if (n < 0) { + if (n < -INT_MAX) + { + /* We cannot print a '-' and assign -n to n because -n would + overflow. Let sprintf deal with this border case. */ + sprintf (buffer, "%ld", n); + p += strlen (buffer); + return p; + } + *p++ = '-'; n = -n; } @@ -1490,19 +1532,30 @@ number_to_string (char *buffer, long number) # endif #endif /* not WINDOWS */ -struct wget_timer { #ifdef TIMER_GETTIMEOFDAY - long secs; - long usecs; +typedef struct timeval wget_sys_time; #endif #ifdef TIMER_TIME - time_t secs; +typedef time_t wget_sys_time; #endif #ifdef TIMER_WINDOWS - ULARGE_INTEGER wintime; +typedef ULARGE_INTEGER wget_sys_time; #endif + +struct wget_timer { + /* The starting point in time which, subtracted from the current + time, yields elapsed time. */ + wget_sys_time start; + + /* The most recent elapsed time, calculated by wtimer_elapsed(). + Measured in milliseconds. */ + double elapsed_last; + + /* 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 @@ -1535,76 +1588,121 @@ wtimer_delete (struct wget_timer *wt) xfree (wt); } -/* 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. */ +/* Store system time to WST. */ -void -wtimer_reset (struct wget_timer *wt) +static void +wtimer_sys_set (wget_sys_time *wst) { #ifdef TIMER_GETTIMEOFDAY - struct timeval t; - gettimeofday (&t, NULL); - wt->secs = t.tv_sec; - wt->usecs = t.tv_usec; + gettimeofday (wst, NULL); #endif #ifdef TIMER_TIME - wt->secs = time (NULL); + 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); - wt->wintime.HighPart = ft.dwHighDateTime; - wt->wintime.LowPart = ft.dwLowDateTime; + wst->HighPart = ft.dwHighDateTime; + wst->LowPart = ft.dwLowDateTime; #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. */ +/* 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. */ -long -wtimer_elapsed (struct wget_timer *wt) +void +wtimer_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 double +wtimer_sys_diff (wget_sys_time *wst1, wget_sys_time *wst2) { #ifdef TIMER_GETTIMEOFDAY - struct timeval t; - gettimeofday (&t, NULL); - return (t.tv_sec - wt->secs) * 1000 + (t.tv_usec - wt->usecs) / 1000; + return ((double)(wst1->tv_sec - wst2->tv_sec) * 1000 + + (double)(wst1->tv_usec - wst2->tv_usec) / 1000); #endif #ifdef TIMER_TIME - time_t now = time (NULL); - return 1000 * (now - wt->secs); + return 1000 * (*wst1 - *wst2); #endif #ifdef WINDOWS - FILETIME ft; - SYSTEMTIME st; - ULARGE_INTEGER uli; - GetSystemTime (&st); - SystemTimeToFileTime (&st, &ft); - uli.HighPart = ft.dwHighDateTime; - uli.LowPart = ft.dwLowDateTime; - return (long)((uli.QuadPart - wt->wintime.QuadPart) / 10000); + return (double)(wst1->QuadPart - wst2->QuadPart) / 10000; #endif } -/* Return the assessed granularity of the timer implementation. This - is important for certain code that tries to deal with "zero" time - intervals. */ +/* 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. */ + +double +wtimer_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. */ -long +double wtimer_granularity (void) { #ifdef TIMER_GETTIMEOFDAY - /* Granularity of gettimeofday is hugely architecture-dependent. - However, it appears that on modern machines it is better than - 1ms. */ - return 1; + /* 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 @@ -1613,7 +1711,8 @@ wtimer_granularity (void) #endif #ifdef TIMER_WINDOWS - /* ? */ + /* According to MSDN, GetSystemTime returns a broken-down time + structure the smallest member of which are milliseconds. */ return 1; #endif } @@ -1797,8 +1896,9 @@ debug_test_md5 (char *buf) /* Implementation of run_with_timeout, a generic timeout handler for systems with Unix-like signal handling. */ -#ifdef HAVE_SIGSETJMP -#define SETJMP(env) sigsetjmp (env, 1) +#ifdef USE_SIGNAL_TIMEOUT +# ifdef HAVE_SIGSETJMP +# define SETJMP(env) sigsetjmp (env, 1) static sigjmp_buf run_with_timeout_env; @@ -1808,8 +1908,8 @@ abort_run_with_timeout (int sig) assert (sig == SIGALRM); siglongjmp (run_with_timeout_env, -1); } -#else /* not HAVE_SIGSETJMP */ -#define SETJMP(env) setjmp (env) +# else /* not HAVE_SIGSETJMP */ +# define SETJMP(env) setjmp (env) static jmp_buf run_with_timeout_env; @@ -1827,7 +1927,8 @@ abort_run_with_timeout (int sig) /* Now it's safe to longjump. */ longjmp (run_with_timeout_env, -1); } -#endif /* not HAVE_SIGSETJMP */ +# endif /* not HAVE_SIGSETJMP */ +#endif /* USE_SIGNAL_TIMEOUT */ int run_with_timeout (long timeout, void (*fun) (void *), void *arg)