diff --git a/src/ChangeLog b/src/ChangeLog index a63c3373..8242627c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2005-04-07 Hrvoje Niksic + + * ptimer.c: New file. Move the "wtimer" functions from utils.c to + this file and rename them to ptimer_. + 2005-04-07 Hrvoje Niksic * host.c (NO_ADDRESS): Define NO_ADDRESS only after the system diff --git a/src/Makefile.in b/src/Makefile.in index e0acdc80..048b9a78 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -76,7 +76,7 @@ GETOPT_OBJ = @GETOPT_OBJ@ OBJ = $(ALLOCA) cmpt$o connect$o convert$o cookies$o \ ftp$o ftp-basic$o ftp-ls$o $(OPIE_OBJ) $(GETOPT_OBJ) hash$o \ host$o html-parse$o html-url$o http$o $(NTLM_OBJ) init$o \ - log$o main$o $(MD5_OBJ) netrc$o progress$o recur$o \ + log$o main$o $(MD5_OBJ) netrc$o progress$o ptimer$o recur$o \ res$o retr$o safe-ctype$o snprintf$o $(SSL_OBJ) url$o \ utils$o version$o xmalloc$o diff --git a/src/convert.c b/src/convert.c index ed567124..33981a3e 100644 --- a/src/convert.c +++ b/src/convert.c @@ -49,6 +49,7 @@ so, delete this exception statement from your version. */ #include "recur.h" #include "utils.h" #include "hash.h" +#include "ptimer.h" static struct hash_table *dl_file_url_map; struct hash_table *dl_url_file_map; @@ -81,7 +82,7 @@ convert_all_links (void) double secs; int file_count = 0; - struct wget_timer *timer = wtimer_new (); + struct ptimer *timer = ptimer_new (); int cnt; char **file_array; @@ -170,9 +171,8 @@ convert_all_links (void) free_urlpos (urls); } - wtimer_update (timer); - secs = wtimer_read (timer) / 1000; - wtimer_delete (timer); + secs = ptimer_measure (timer) / 1000; + ptimer_destroy (timer); logprintf (LOG_VERBOSE, _("Converted %d files in %.*f seconds.\n"), file_count, secs < 10 ? 3 : 1, secs); } @@ -834,8 +834,10 @@ register_html (const char *url, const char *file) string_set_add (downloaded_html_set, file); } -/* Cleanup the data structures associated with recursive retrieving - (the variables above). */ +static void downloaded_files_free PARAMS ((void)); + +/* Cleanup the data structures associated with this file. */ + void convert_cleanup (void) { @@ -853,6 +855,7 @@ convert_cleanup (void) } if (downloaded_html_set) string_set_free (downloaded_html_set); + downloaded_files_free (); } /* Book-keeping code for downloaded files that enables extension @@ -943,7 +946,7 @@ df_free_mapper (void *key, void *value, void *ignored) return 0; } -void +static void downloaded_files_free (void) { if (downloaded_files_hash) @@ -953,3 +956,75 @@ downloaded_files_free (void) downloaded_files_hash = NULL; } } + +/* 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; +} diff --git a/src/convert.h b/src/convert.h index 53b0c97a..bbbd7378 100644 --- a/src/convert.h +++ b/src/convert.h @@ -101,4 +101,6 @@ void register_delete_file PARAMS ((const char *)); void convert_all_links PARAMS ((void)); void convert_cleanup PARAMS ((void)); +char *html_quote_string PARAMS ((const char *)); + #endif /* CONVERT_H */ diff --git a/src/ftp-ls.c b/src/ftp-ls.c index 91330250..dd703dfd 100644 --- a/src/ftp-ls.c +++ b/src/ftp-ls.c @@ -47,6 +47,7 @@ so, delete this exception statement from your version. */ #include "utils.h" #include "ftp.h" #include "url.h" +#include "convert.h" /* for html_quote_string prototype */ extern FILE *output_stream; diff --git a/src/init.c b/src/init.c index 142ff81d..3fb9aa23 100644 --- a/src/init.c +++ b/src/init.c @@ -55,6 +55,7 @@ so, delete this exception statement from your version. */ #include "progress.h" #include "recur.h" /* for INFINITE_RECURSION */ #include "convert.h" /* for convert_cleanup */ +#include "res.h" /* for res_cleanup */ #ifndef errno extern int errno; @@ -1300,8 +1301,6 @@ check_user_specified_header (const char *s) } void cleanup_html_url PARAMS ((void)); -void res_cleanup PARAMS ((void)); -void downloaded_files_free PARAMS ((void)); void http_cleanup PARAMS ((void)); @@ -1332,7 +1331,6 @@ cleanup (void) res_cleanup (); http_cleanup (); cleanup_html_url (); - downloaded_files_free (); host_cleanup (); log_cleanup (); diff --git a/src/ptimer.c b/src/ptimer.c new file mode 100644 index 00000000..e6979216 --- /dev/null +++ b/src/ptimer.c @@ -0,0 +1,412 @@ +/* Portable timers. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Wget. + +GNU Wget is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GNU Wget is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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. + +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. */ + +/* This file implements "portable timers" (ptimers), objects that + measure elapsed time using the primitives most appropriate for the + underlying operating system. The entry points are: + + ptimer_new -- creates a timer. + ptimer_reset -- resets the timer's elapsed time to zero. + ptimer_measure -- measure and return the time elapsed since + creation or last reset. + ptimer_read -- reads the last measured elapsed value. + ptimer_destroy -- destroy the timer. + ptimer_granularity -- returns the approximate granularity of the timers. + + Timers operate in milliseconds, but return floating point values + that can be more precise. For example, to measure the time it + takes to run a loop, you can use something like: + + ptimer *tmr = ptimer_new (); + while (...) + ... loop ... + double msecs = ptimer_measure (); + printf ("The loop took %.2f ms\n", msecs); */ + +#include + +#include +#include +#ifdef HAVE_STRING_H +# include +#else /* not HAVE_STRING_H */ +# include +#endif /* not HAVE_STRING_H */ +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include + +#include "wget.h" +#include "ptimer.h" + +#ifndef errno +extern int errno; +#endif + +/* Depending on the OS and availability of gettimeofday(), one and + only one of PTIMER_WINDOWS, PTIMER_GETTIMEOFDAY, or PTIMER_TIME will + be defined. + + Virtually all modern Unix systems will define PTIMER_GETTIMEOFDAY; + Windows will use PTIMER_WINDOWS. PTIMER_TIME is a catch-all method + for non-Windows systems without gettimeofday, such as DOS or really + old Unix-like systems. */ + +#undef PTIMER_POSIX +#undef PTIMER_GETTIMEOFDAY +#undef PTIMER_TIME +#undef PTIMER_WINDOWS + +#ifdef WINDOWS +# define PTIMER_WINDOWS /* use Windows timers */ +#else +# if _POSIX_TIMERS > 0 +# define PTIMER_POSIX /* use POSIX timers (clock_gettime) */ +# else +# ifdef HAVE_GETTIMEOFDAY +# define PTIMER_GETTIMEOFDAY /* use gettimeofday */ +# else +# define PTIMER_TIME +# endif +# endif +#endif + +/* The type ptimer_system_time holds system time. */ + +#ifdef PTIMER_POSIX +typedef struct timespec ptimer_system_time; +#endif + +#ifdef PTIMER_GETTIMEOFDAY +typedef struct timeval ptimer_system_time; +#endif + +#ifdef PTIMER_TIME +typedef time_t ptimer_system_time; +#endif + +#ifdef PTIMER_WINDOWS +typedef union { + DWORD lores; /* In case GetTickCount is used */ + LARGE_INTEGER hires; /* In case high-resolution timer is used */ +} ptimer_system_time; +#endif + +struct ptimer { + /* Whether the start time has been set. */ + int initialized; + + /* The starting point in time which, subtracted from the current + time, yields elapsed time. */ + ptimer_system_time start; + + /* The most recent elapsed time, calculated by ptimer_measure(). + 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; +}; + +#ifdef PTIMER_WINDOWS +/* Whether high-resolution timers are used. Set by ptimer_initialize_once + the first time ptimer_allocate is called. */ +static int windows_hires_timers; + +/* Frequency of high-resolution timers -- number of updates per + millisecond. Calculated the first time ptimer_allocate is called + provided that high-resolution timers are available. */ +static double windows_hires_msfreq; + +/* The first time a timer is created, determine whether to use + high-resolution timers. */ + +static void +ptimer_init (void) +{ + LARGE_INTEGER freq; + freq.QuadPart = 0; + QueryPerformanceFrequency (&freq); + if (freq.QuadPart != 0) + { + windows_hires_timers = 1; + windows_hires_msfreq = (double) freq.QuadPart / 1000.0; + } +} +#define PTIMER_INIT_DEFINED +#endif /* PTIMER_WINDOWS */ + +#ifdef PTIMER_POSIX + +/* clock_id to use for POSIX clocks. This tries to use + CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise. */ +static int posix_clock_id; + +/* Resolution of the clock, in milliseconds. */ +static double posix_resolution; + +/* Check whether the monotonic clock is available, and retrieve POSIX + timer resolution. */ + +static void +ptimer_init (void) +{ + struct timespec res; + +#if _POSIX_MONOTONIC_CLOCK > 0 + if (sysconf (_SC_MONOTONIC_CLOCK) > 0) + posix_clock_id = CLOCK_MONOTONIC; + else +#endif + posix_clock_id = CLOCK_REALTIME; + + if (clock_getres (posix_clock_id, &res) < 0) + { + logprintf (LOG_NOTQUIET, _("Cannot read clock resolution: %s\n"), + strerror (errno)); + /* Assume 1 ms resolution */ + res.tv_sec = 0; + res.tv_nsec = 1000000; + } + + posix_resolution = res.tv_sec * 1000.0 + res.tv_nsec / 1000000.0; + /* Guard against clock_getres reporting 0 resolution; after all, it + can be used for division. */ + if (posix_resolution == 0) + posix_resolution = 1; +} +#define PTIMER_INIT_DEFINED +#endif + +/* Allocate a timer. Calling ptimer_read on the timer will return + zero. It is not legal to call ptimer_measure with a freshly + allocated timer -- use ptimer_reset first. */ + +struct ptimer * +ptimer_allocate (void) +{ + struct ptimer *wt; + +#ifdef PTIMER_INIT_DEFINED + static int init_done; + if (!init_done) + { + init_done = 1; + ptimer_init (); + } +#endif + + wt = xnew0 (struct ptimer); + return wt; +} + +/* Allocate a new timer and reset it. Return the new timer. */ + +struct ptimer * +ptimer_new (void) +{ + struct ptimer *wt = ptimer_allocate (); + ptimer_reset (wt); + return wt; +} + +/* Free the resources associated with the timer. Its further use is + prohibited. */ + +void +ptimer_destroy (struct ptimer *wt) +{ + xfree (wt); +} + +/* Store system time to PST. */ + +static void +ptimer_sys_set (ptimer_system_time *pst) +{ +#ifdef PTIMER_POSIX + clock_gettime (posix_clock_id, pst); +#endif + +#ifdef PTIMER_GETTIMEOFDAY + gettimeofday (pst, NULL); +#endif + +#ifdef PTIMER_TIME + time (pst); +#endif + +#ifdef PTIMER_WINDOWS + if (windows_hires_timers) + { + QueryPerformanceCounter (&pst->hires); + } + else + { + /* Where hires counters are not available, use GetTickCount rather + GetSystemTime, because it is unaffected by clock skew and simpler + to use. Note that overflows don't affect us because we never use + absolute values of the ticker, only the differences. */ + pst->lores = GetTickCount (); + } +#endif +} + +/* Reset timer WT. This establishes the starting point from which + ptimer_read() will return the number of elapsed milliseconds. + It is allowed to reset a previously used timer. */ + +void +ptimer_reset (struct ptimer *wt) +{ + /* Set the start time to the current time. */ + ptimer_sys_set (&wt->start); + wt->elapsed_last = 0; + wt->elapsed_pre_start = 0; + wt->initialized = 1; +} + +static double +ptimer_diff (ptimer_system_time *pst1, ptimer_system_time *pst2) +{ +#ifdef PTIMER_POSIX + return ((pst1->tv_sec - pst2->tv_sec) * 1000.0 + + (pst1->tv_nsec - pst2->tv_nsec) / 1000000.0); +#endif + +#ifdef PTIMER_GETTIMEOFDAY + return ((pst1->tv_sec - pst2->tv_sec) * 1000.0 + + (pst1->tv_usec - pst2->tv_usec) / 1000.0); +#endif + +#ifdef PTIMER_TIME + return 1000 * (*pst1 - *pst2); +#endif + +#ifdef WINDOWS + if (using_hires_timers) + return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_msfreq; + else + return pst1->lores - pst2->lores; +#endif +} + +/* Measure the elapsed time since timer creation/reset and return it + to the caller. The value remains stored for further reads by + ptimer_read. + + This function causes the timer to call gettimeofday (or time(), + etc.) to update its idea of current time. To get the elapsed + interval in milliseconds, use ptimer_read. + + This function handles clock skew, i.e. time that moves backwards is + ignored. */ + +double +ptimer_measure (struct ptimer *wt) +{ + ptimer_system_time now; + double elapsed; + + assert (wt->initialized != 0); + + ptimer_sys_set (&now); + elapsed = wt->elapsed_pre_start + ptimer_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. + + This cannot happen with Windows and CLOCK_MONOTONIC timers, but + the check is not expensive. */ + + 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 elapsed time in milliseconds between the last call to + ptimer_reset and the last call to ptimer_update. */ + +double +ptimer_read (const struct ptimer *wt) +{ + return wt->elapsed_last; +} + +/* 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. */ + +double +ptimer_granularity (void) +{ +#ifdef PTIMER_POSIX + /* POSIX timers give us a way to measure granularity. */ + assert (posix_resolution != 0); + return posix_resolution; +#endif + +#ifdef PTIMER_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. */ + return 0.1; +#endif + +#ifdef PTIMER_TIME + return 1000; +#endif + +#ifdef PTIMER_WINDOWS + if (windows_hires_timers) + return 1.0 / windows_hires_msfreq; + else + return 10; /* according to MSDN */ +#endif +} diff --git a/src/ptimer.h b/src/ptimer.h new file mode 100644 index 00000000..244c1836 --- /dev/null +++ b/src/ptimer.h @@ -0,0 +1,46 @@ +/* Declarations for ptimer.c. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Wget. + +GNU Wget is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GNU Wget is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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. + +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. */ + +#ifndef PTIMER_H +#define PTIMER_H + +struct ptimer; /* forward declaration; all struct + members are private */ + +struct ptimer *ptimer_allocate PARAMS ((void)); +struct ptimer *ptimer_new PARAMS ((void)); +void ptimer_destroy PARAMS ((struct ptimer *)); + +void ptimer_reset PARAMS ((struct ptimer *)); +double ptimer_measure PARAMS ((struct ptimer *)); +double ptimer_read PARAMS ((const struct ptimer *)); + +double ptimer_granularity PARAMS ((void)); + +#endif /* PTIMER_H */ diff --git a/src/retr.c b/src/retr.c index a19262a0..a5198b7e 100644 --- a/src/retr.c +++ b/src/retr.c @@ -54,6 +54,7 @@ so, delete this exception statement from your version. */ #include "connect.h" #include "hash.h" #include "convert.h" +#include "ptimer.h" #ifdef HAVE_SSL # include "gen_sslfunc.h" /* for ssl_iread */ @@ -92,9 +93,9 @@ limit_bandwidth_reset (void) is the timer that started at the beginning of download. */ static void -limit_bandwidth (wgint bytes, struct wget_timer *timer) +limit_bandwidth (wgint bytes, struct ptimer *timer) { - double delta_t = wtimer_read (timer) - limit_data.chunk_start; + double delta_t = ptimer_read (timer) - limit_data.chunk_start; double expected; limit_data.chunk_bytes += bytes; @@ -119,10 +120,9 @@ limit_bandwidth (wgint bytes, struct wget_timer *timer) slp, number_to_static_string (limit_data.chunk_bytes), limit_data.sleep_adjust)); - t0 = wtimer_read (timer); + t0 = ptimer_read (timer); xsleep (slp / 1000); - wtimer_update (timer); - t1 = wtimer_read (timer); + t1 = ptimer_measure (timer); /* Due to scheduling, we probably slept slightly longer (or shorter) than desired. Calculate the difference between the @@ -132,7 +132,7 @@ limit_bandwidth (wgint bytes, struct wget_timer *timer) } limit_data.chunk_bytes = 0; - limit_data.chunk_start = wtimer_read (timer); + limit_data.chunk_start = ptimer_read (timer); } #ifndef MIN @@ -202,7 +202,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos, static char dlbuf[16384]; int dlbufsize = sizeof (dlbuf); - struct wget_timer *timer = NULL; + struct ptimer *timer = NULL; double last_successful_read_tm = 0; /* The progress gauge, set according to the user preferences. */ @@ -241,7 +241,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos, the timer. */ if (progress || opt.limit_rate || elapsed) { - timer = wtimer_new (); + timer = ptimer_new (); last_successful_read_tm = 0; } @@ -269,7 +269,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos, if (opt.read_timeout) { double waittm; - waittm = (wtimer_read (timer) - last_successful_read_tm) / 1000; + waittm = (ptimer_read (timer) - last_successful_read_tm) / 1000; if (waittm + tmout > opt.read_timeout) { /* Don't let total idle time exceed read timeout. */ @@ -292,9 +292,9 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos, if (progress || opt.limit_rate) { - wtimer_update (timer); + ptimer_measure (timer); if (ret > 0) - last_successful_read_tm = wtimer_read (timer); + last_successful_read_tm = ptimer_read (timer); } if (ret > 0) @@ -311,7 +311,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos, limit_bandwidth (ret, timer); if (progress) - progress_update (progress, ret, wtimer_read (timer)); + progress_update (progress, ret, ptimer_read (timer)); #ifdef WINDOWS if (toread > 0 && !opt.quiet) ws_percenttitle (100.0 * @@ -323,12 +323,12 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos, out: if (progress) - progress_finish (progress, wtimer_read (timer)); + progress_finish (progress, ptimer_read (timer)); if (elapsed) - *elapsed = wtimer_read (timer); + *elapsed = ptimer_read (timer); if (timer) - wtimer_delete (timer); + ptimer_destroy (timer); if (qtyread) *qtyread += sum_read; @@ -534,11 +534,12 @@ calc_rate (wgint bytes, double msecs, int *units) if (msecs == 0) /* If elapsed time is exactly zero, it means we're under the - granularity of the timer. This often happens on systems that - use time() for the timer. */ - msecs = wtimer_granularity (); + granularity of the timer. This can easily happen on systems + that use time() for the timer. Since the interval lies between + 0 and the timer's granularity, assume half the granularity. */ + msecs = ptimer_granularity () / 2.0; - dlrate = (double)1000 * bytes / msecs; + dlrate = 1000.0 * bytes / msecs; if (dlrate < 1024.0) *units = 0; else if (dlrate < 1024.0 * 1024.0) diff --git a/src/utils.c b/src/utils.c index 2e45c4d5..dc16d55a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1515,352 +1515,6 @@ number_to_static_string (wgint number) return buf; } -/* Support for timers. */ - -#undef TIMER_WINDOWS -#undef TIMER_GETTIMEOFDAY -#undef TIMER_TIME - -/* Depending on the OS and availability of gettimeofday(), one and - only one of the above constants will be defined. Virtually all - modern Unix systems will define TIMER_GETTIMEOFDAY; Windows will - use TIMER_WINDOWS. TIMER_TIME is a catch-all method for - non-Windows systems without gettimeofday. */ - -#ifdef WINDOWS -# define TIMER_WINDOWS -#else /* not WINDOWS */ -# ifdef HAVE_GETTIMEOFDAY -# define TIMER_GETTIMEOFDAY -# else -# define TIMER_TIME -# endif -#endif /* not WINDOWS */ - -#ifdef TIMER_GETTIMEOFDAY -typedef struct timeval wget_sys_time; -#endif - -#ifdef TIMER_TIME -typedef time_t wget_sys_time; -#endif - -#ifdef TIMER_WINDOWS -typedef union { - DWORD lores; /* In case GetTickCount is used */ - LARGE_INTEGER hires; /* In case high-resolution timer is used */ -} wget_sys_time; -#endif - -struct wget_timer { - /* Whether the start time has been initialized. */ - int initialized; - - /* 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_update(). - 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; -}; - -#ifdef TIMER_WINDOWS - -/* Whether high-resolution timers are used. Set by wtimer_initialize_once - the first time wtimer_allocate is called. */ -static int using_hires_timers; - -/* Frequency of high-resolution timers -- number of updates per - millisecond. Calculated the first time wtimer_allocate is called - provided that high-resolution timers are available. */ -static double hires_millisec_freq; - -/* The first time a timer is created, determine whether to use - high-resolution timers. */ - -static void -wtimer_initialize_once (void) -{ - static int init_done; - if (!init_done) - { - LARGE_INTEGER freq; - init_done = 1; - freq.QuadPart = 0; - QueryPerformanceFrequency (&freq); - if (freq.QuadPart != 0) - { - using_hires_timers = 1; - hires_millisec_freq = (double) freq.QuadPart / 1000.0; - } - } -} -#endif /* TIMER_WINDOWS */ - -/* Allocate a timer. Calling wtimer_read on the timer will return - zero. It is not legal to call wtimer_update with a freshly - allocated timer -- use wtimer_reset first. */ - -struct wget_timer * -wtimer_allocate (void) -{ - struct wget_timer *wt = xnew (struct wget_timer); - xzero (*wt); - -#ifdef TIMER_WINDOWS - wtimer_initialize_once (); -#endif - - 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. */ - -void -wtimer_delete (struct wget_timer *wt) -{ - xfree (wt); -} - -/* Store system time to WST. */ - -static void -wtimer_sys_set (wget_sys_time *wst) -{ -#ifdef TIMER_GETTIMEOFDAY - gettimeofday (wst, NULL); -#endif - -#ifdef TIMER_TIME - time (wst); -#endif - -#ifdef TIMER_WINDOWS - if (using_hires_timers) - { - QueryPerformanceCounter (&wst->hires); - } - else - { - /* Where hires counters are not available, use GetTickCount rather - GetSystemTime, because it is unaffected by clock skew and simpler - to use. Note that overflows don't affect us because we never use - absolute values of the ticker, only the differences. */ - wst->lores = GetTickCount (); - } -#endif -} - -/* Reset timer WT. This establishes the starting point from which - wtimer_read() will return the number of elapsed milliseconds. - It is allowed to reset a previously used timer. */ - -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; - wt->initialized = 1; -} - -static double -wtimer_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 - if (using_hires_timers) - return (wst1->hires.QuadPart - wst2->hires.QuadPart) / hires_millisec_freq; - else - return wst1->lores - wst2->lores; -#endif -} - -/* Update the timer's elapsed interval. This function causes the - timer to call gettimeofday (or time(), etc.) to update its idea of - current time. To get the elapsed interval in milliseconds, use - wtimer_read. - - This function handles clock skew, i.e. time that moves backwards is - ignored. */ - -void -wtimer_update (struct wget_timer *wt) -{ - wget_sys_time now; - double elapsed; - - assert (wt->initialized != 0); - - 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 the elapsed time in milliseconds between the last call to - wtimer_reset and the last call to wtimer_update. - - A typical use of the timer interface would be: - - struct wtimer *timer = wtimer_new (); - ... do something that takes a while ... - wtimer_update (); - double msecs = wtimer_read (); */ - -double -wtimer_read (const struct wget_timer *wt) -{ - return wt->elapsed_last; -} - -/* 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. */ - -double -wtimer_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 - if (using_hires_timers) - return 1.0 / hires_millisec_freq; - else - return 10; /* according to MSDN */ -#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. */ @@ -2284,7 +1938,7 @@ base64_decode (const char *base64, char *to) { NEXT_BASE64_CHAR (c, p); if (!c) - return -1; /* premature EOF while dcoding base64 */ + return -1; /* premature EOF while decoding base64 */ if (c != '=') return -1; /* padding `=' expected but not found */ continue; @@ -2296,7 +1950,7 @@ base64_decode (const char *base64, char *to) /* Process fourth byte of a quadruplet. */ NEXT_BASE64_CHAR (c, p); if (!c) - return -1; /* premature EOF while dcoding base64 */ + return -1; /* premature EOF while decoding base64 */ if (c == '=') continue; diff --git a/src/utils.h b/src/utils.h index 119cd281..afef13c9 100644 --- a/src/utils.h +++ b/src/utils.h @@ -44,8 +44,6 @@ struct file_memory { #define HYPHENP(x) (*(x) == '-' && !*((x) + 1)) -struct wget_timer; - char *time_str PARAMS ((time_t *)); char *datetime_str PARAMS ((time_t *)); @@ -108,16 +106,6 @@ int numdigit PARAMS ((wgint)); char *number_to_string PARAMS ((char *, wgint)); char *number_to_static_string PARAMS ((wgint)); -struct wget_timer *wtimer_allocate PARAMS ((void)); -struct wget_timer *wtimer_new PARAMS ((void)); -void wtimer_delete PARAMS ((struct wget_timer *)); -void wtimer_reset PARAMS ((struct wget_timer *)); -void wtimer_update PARAMS ((struct wget_timer *)); -double wtimer_read PARAMS ((const struct wget_timer *)); -double wtimer_granularity PARAMS ((void)); - -char *html_quote_string PARAMS ((const char *)); - int determine_screen_width PARAMS ((void)); int random_number PARAMS ((int)); double random_float PARAMS ((void));