-/* Various functions of utilitarian nature.
- Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
- Free Software Foundation, Inc.
+/* Various utility functions.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Wget.
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
-#include <limits.h>
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
#ifdef HAVE_UTIME_H
# include <utime.h>
#endif
#endif
#include <fcntl.h>
#include <assert.h>
+#ifdef WGET_USE_STDARG
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
/* For TIOCGWINSZ and friends: */
#ifdef HAVE_SYS_IOCTL_H
#ifdef HAVE_SETJMP_H
# include <setjmp.h>
#endif
+
+#ifndef HAVE_SIGSETJMP
/* If sigsetjmp is a macro, configure won't pick it up. */
-#ifdef sigsetjmp
-# define HAVE_SIGSETJMP
+# ifdef sigsetjmp
+# define HAVE_SIGSETJMP
+# endif
#endif
+
#ifdef HAVE_SIGNAL
# ifdef HAVE_SIGSETJMP
# define USE_SIGNAL_TIMEOUT
extern int errno;
#endif
-/* This section implements several wrappers around the basic
- allocation routines. This is done for two reasons: first, so that
- the callers of these functions need not consistently check for
- errors. If there is not enough virtual memory for running Wget,
- something is seriously wrong, and Wget exits with an appropriate
- error message.
-
- The second reason why these are useful is that, if DEBUG_MALLOC is
- defined, they also provide a handy (if crude) malloc debugging
- interface that checks memory leaks. */
-
-/* Croak the fatal memory error and bail out with non-zero exit
- status. */
-static void
-memfatal (const char *what)
-{
- /* Make sure we don't try to store part of the log line, and thus
- call malloc. */
- log_set_save_context (0);
- logprintf (LOG_ALWAYS, _("%s: %s: Not enough memory.\n"), exec_name, what);
- exit (1);
-}
-
-/* These functions end with _real because they need to be
- distinguished from the debugging functions, and from the macros.
- Explanation follows:
-
- If memory debugging is not turned on, wget.h defines these:
-
- #define xmalloc xmalloc_real
- #define xrealloc xrealloc_real
- #define xstrdup xstrdup_real
- #define xfree free
-
- In case of memory debugging, the definitions are a bit more
- complex, because we want to provide more information, *and* we want
- to call the debugging code. (The former is the reason why xmalloc
- and friends need to be macros in the first place.) Then it looks
- like this:
-
- #define xmalloc(a) xmalloc_debug (a, __FILE__, __LINE__)
- #define xfree(a) xfree_debug (a, __FILE__, __LINE__)
- #define xrealloc(a, b) xrealloc_debug (a, b, __FILE__, __LINE__)
- #define xstrdup(a) xstrdup_debug (a, __FILE__, __LINE__)
-
- Each of the *_debug function does its magic and calls the real one. */
-
-#ifdef DEBUG_MALLOC
-# define STATIC_IF_DEBUG static
-#else
-# define STATIC_IF_DEBUG
-#endif
-
-STATIC_IF_DEBUG void *
-xmalloc_real (size_t size)
-{
- void *ptr = malloc (size);
- if (!ptr)
- memfatal ("malloc");
- return ptr;
-}
-
-STATIC_IF_DEBUG void *
-xrealloc_real (void *ptr, size_t newsize)
-{
- void *newptr;
-
- /* Not all Un*xes have the feature of realloc() that calling it with
- a NULL-pointer is the same as malloc(), but it is easy to
- simulate. */
- if (ptr)
- newptr = realloc (ptr, newsize);
- else
- newptr = malloc (newsize);
- if (!newptr)
- memfatal ("realloc");
- return newptr;
-}
-
-STATIC_IF_DEBUG char *
-xstrdup_real (const char *s)
-{
- char *copy;
-
-#ifndef HAVE_STRDUP
- int l = strlen (s);
- copy = malloc (l + 1);
- if (!copy)
- memfatal ("strdup");
- memcpy (copy, s, l + 1);
-#else /* HAVE_STRDUP */
- copy = strdup (s);
- if (!copy)
- memfatal ("strdup");
-#endif /* HAVE_STRDUP */
-
- return copy;
-}
-
-#ifdef DEBUG_MALLOC
-
-/* Crude home-grown routines for debugging some malloc-related
- problems. Featured:
-
- * Counting the number of malloc and free invocations, and reporting
- the "balance", i.e. how many times more malloc was called than it
- was the case with free.
-
- * Making malloc store its entry into a simple array and free remove
- stuff from that array. At the end, print the pointers which have
- not been freed, along with the source file and the line number.
- This also has the side-effect of detecting freeing memory that
- was never allocated.
-
- Note that this kind of memory leak checking strongly depends on
- every malloc() being followed by a free(), even if the program is
- about to finish. Wget is careful to free the data structure it
- allocated in init.c. */
-
-static int malloc_count, free_count;
-
-static struct {
- char *ptr;
- const char *file;
- int line;
-} malloc_debug[100000];
-
-/* Both register_ptr and unregister_ptr take O(n) operations to run,
- which can be a real problem. It would be nice to use a hash table
- for malloc_debug, but the functions in hash.c are not suitable
- because they can call malloc() themselves. Maybe it would work if
- the hash table were preallocated to a huge size, and if we set the
- rehash threshold to 1.0. */
-
-/* Register PTR in malloc_debug. Abort if this is not possible
- (presumably due to the number of current allocations exceeding the
- size of malloc_debug.) */
-
-static void
-register_ptr (void *ptr, const char *file, int line)
-{
- int i;
- for (i = 0; i < countof (malloc_debug); i++)
- if (malloc_debug[i].ptr == NULL)
- {
- malloc_debug[i].ptr = ptr;
- malloc_debug[i].file = file;
- malloc_debug[i].line = line;
- return;
- }
- abort ();
-}
-
-/* Unregister PTR from malloc_debug. Abort if PTR is not present in
- malloc_debug. (This catches calling free() with a bogus pointer.) */
-
-static void
-unregister_ptr (void *ptr)
-{
- int i;
- for (i = 0; i < countof (malloc_debug); i++)
- if (malloc_debug[i].ptr == ptr)
- {
- malloc_debug[i].ptr = NULL;
- return;
- }
- abort ();
-}
-
-/* Print the malloc debug stats that can be gathered from the above
- information. Currently this is the count of mallocs, frees, the
- difference between the two, and the dump of the contents of
- malloc_debug. The last part are the memory leaks. */
-
-void
-print_malloc_debug_stats (void)
-{
- int i;
- printf ("\nMalloc: %d\nFree: %d\nBalance: %d\n\n",
- malloc_count, free_count, malloc_count - free_count);
- for (i = 0; i < countof (malloc_debug); i++)
- if (malloc_debug[i].ptr != NULL)
- printf ("0x%08ld: %s:%d\n", (long)malloc_debug[i].ptr,
- malloc_debug[i].file, malloc_debug[i].line);
-}
-
-void *
-xmalloc_debug (size_t size, const char *source_file, int source_line)
-{
- void *ptr = xmalloc_real (size);
- ++malloc_count;
- register_ptr (ptr, source_file, source_line);
- return ptr;
-}
-
-void
-xfree_debug (void *ptr, const char *source_file, int source_line)
-{
- assert (ptr != NULL);
- ++free_count;
- unregister_ptr (ptr);
- free (ptr);
-}
-
-void *
-xrealloc_debug (void *ptr, size_t newsize, const char *source_file, int source_line)
-{
- void *newptr = xrealloc_real (ptr, newsize);
- if (!ptr)
- {
- ++malloc_count;
- register_ptr (newptr, source_file, source_line);
- }
- else if (newptr != ptr)
- {
- unregister_ptr (ptr);
- register_ptr (newptr, source_file, source_line);
- }
- return newptr;
-}
-
-char *
-xstrdup_debug (const char *s, const char *source_file, int source_line)
-{
- char *copy = xstrdup_real (s);
- ++malloc_count;
- register_ptr (copy, source_file, source_line);
- return copy;
-}
-
-#endif /* DEBUG_MALLOC */
-\f
/* Utility function: like xstrdup(), but also lowercases S. */
char *
return res;
}
\f
+#ifdef WGET_USE_STDARG
+# define VA_START(args, arg1) va_start (args, arg1)
+#else
+# define VA_START(args, ignored) va_start (args)
+#endif
+
+/* Like sprintf, but allocates a string of sufficient size with malloc
+ and returns it. GNU libc has a similar function named asprintf,
+ which requires the pointer to the string to be passed. */
+
+char *
+aprintf (const char *fmt, ...)
+{
+ /* This function is implemented using vsnprintf, which we provide
+ for the systems that don't have it. Therefore, it should be 100%
+ portable. */
+
+ int size = 32;
+ char *str = xmalloc (size);
+
+ while (1)
+ {
+ int n;
+ va_list args;
+
+ /* See log_vprintf_internal for explanation why it's OK to rely
+ on the return value of vsnprintf. */
+
+ VA_START (args, fmt);
+ n = vsnprintf (str, size, fmt, args);
+ va_end (args);
+
+ /* If the printing worked, return the string. */
+ if (n > -1 && n < size)
+ return str;
+
+ /* Else try again with a larger buffer. */
+ if (n > -1) /* C99 */
+ size = n + 1; /* precisely what is needed */
+ else
+ size <<= 1; /* twice the old size */
+ str = xrealloc (str, size);
+ }
+ return NULL; /* unreached */
+}
+\f
/* Return pointer to a static char[] buffer in which zero-terminated
string-representation of TM (in form hh:mm:ss) is printed.
- If TM is non-NULL, the current time-in-seconds will be stored
- there.
-
- (#### This is misleading: one would expect TM would be used instead
- of the current time in that case. This design was probably
- influenced by the design time(2), and should be changed at some
- points. No callers use non-NULL TM anyway.) */
+ If TM is NULL, the current time will be used. */
char *
time_str (time_t *tm)
{
static char output[15];
struct tm *ptm;
- time_t secs = time (tm);
+ time_t secs = tm ? *tm : time (NULL);
if (secs == -1)
{
{
static char output[20]; /* "YYYY-MM-DD hh:mm:ss" + \0 */
struct tm *ptm;
- time_t secs = time (tm);
+ time_t secs = tm ? *tm : time (NULL);
if (secs == -1)
{
fd = open (file, O_RDONLY);
if (fd < 0)
return NULL;
- fm = xmalloc (sizeof (struct file_memory));
+ fm = xnew (struct file_memory);
#ifdef HAVE_MMAP
{
slist *
slist_append (slist *l, const char *s)
{
- slist *newel = (slist *)xmalloc (sizeof (slist));
+ slist *newel = xnew (slist);
slist *beg = l;
newel->string = xstrdup (s);
slist *
slist_prepend (slist *l, const char *s)
{
- slist *newel = (slist *)xmalloc (sizeof (slist));
+ slist *newel = xnew (slist);
newel->string = xstrdup (s);
newel->next = l;
return newel;
return cnt;
}
-/* A half-assed implementation of INT_MAX on machines that don't
- bother to define one. */
+/* Attempt to calculate INT_MAX on machines that don't bother to
+ define it. */
#ifndef INT_MAX
-# define INT_MAX ((int) ~((unsigned)1 << 8 * sizeof (int) - 1))
+# ifndef CHAR_BIT
+# define CHAR_BIT 8
+# endif
+# define INT_MAX ((int) ~((unsigned)1 << CHAR_BIT * sizeof (int) - 1))
#endif
#define ONE_DIGIT(figure) *p++ = n / (figure) + '0'
#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;
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(). */
+/* 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 =
- (struct wget_timer *)xmalloc (sizeof (struct wget_timer));
+ struct wget_timer *wt = xnew (struct wget_timer);
+ xzero (*wt);
return 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. */
+ wtimer_elapsed() will return the number of elapsed milliseconds.
+ It is allowed to reset a previously used timer.
+
+ If a non-zero value is used as START, the timer's values will be
+ offset by START. */
void
wtimer_reset (struct wget_timer *wt)
wtimer_sys_set (&wt->start);
wt->elapsed_last = 0;
wt->elapsed_pre_start = 0;
+ wt->initialized = 1;
}
static double
#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. */
+/* 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.
-double
-wtimer_elapsed (struct wget_timer *wt)
+ 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);
}
wt->elapsed_last = elapsed;
- return 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
#ifdef ITIMER_REAL
/* Use the modern itimer interface. */
struct itimerval itv;
- memset (&itv, 0, sizeof (itv));
+ xzero (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)
{
#ifdef ITIMER_REAL
struct itimerval disable;
- memset (&disable, 0, sizeof (disable));
+ xzero (disable);
setitimer (ITIMER_REAL, &disable, NULL);
#else /* not ITIMER_REAL */
alarm (0);
}
#endif /* not WINDOWS */
#endif /* not USE_SIGNAL_TIMEOUT */
+\f
+#ifndef WINDOWS
+
+/* Sleep the specified amount of seconds. On machines without
+ nanosleep(), this may sleep shorter if interrupted by signals. */
+
+void
+xsleep (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 after having been interrupted by a signal such as
+ SIGWINCH. */
+ struct timespec sleep, remaining;
+ sleep.tv_sec = (long) seconds;
+ sleep.tv_nsec = 1000000000L * (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 > 1000)
+ {
+ /* usleep apparently accepts unsigned long, which means it can't
+ sleep longer than ~70 min (35min if signed). If the period
+ is larger than what usleep can safely handle, use sleep
+ first, then add usleep for subsecond accuracy. */
+ sleep (seconds);
+ seconds -= (long) seconds;
+ }
+ usleep (seconds * 1000000L);
+#else /* not HAVE_USLEEP */
+#ifdef HAVE_SELECT
+ struct timeval sleep;
+ sleep.tv_sec = (long) seconds;
+ sleep.tv_usec = 1000000L * (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 */