]> sjero.net Git - wget/blobdiff - src/utils.c
[svn] Restructure generation of HTTP requests. Allow headers specified with
[wget] / src / utils.c
index 11c404aef18a71e4727a831a2333bf8049a07a71..c83e4499f5e8c6f432a4a36462208c67e369e74e 100644 (file)
@@ -1,6 +1,5 @@
-/* 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.
 
@@ -47,7 +46,9 @@ so, delete this exception statement from your version.  */
 #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
@@ -60,6 +61,11 @@ so, delete this exception statement from your version.  */
 #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
@@ -102,238 +108,6 @@ so, delete this exception statement from your version.  */
 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 *
@@ -407,23 +181,63 @@ sepstring (const char *s)
   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)
     {
@@ -444,7 +258,7 @@ datetime_str (time_t *tm)
 {
   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)
     {
@@ -1001,7 +815,7 @@ read_file (const char *file)
     fd = open (file, O_RDONLY);
   if (fd < 0)
     return NULL;
-  fm = xmalloc (sizeof (struct file_memory));
+  fm = xnew (struct file_memory);
 
 #ifdef HAVE_MMAP
   {
@@ -1169,7 +983,7 @@ merge_vecs (char **v1, char **v2)
 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);
@@ -1189,7 +1003,7 @@ slist_append (slist *l, const char *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;
@@ -1386,10 +1200,13 @@ numdigit (long number)
   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'
@@ -1557,6 +1374,9 @@ typedef ULARGE_INTEGER 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;
@@ -1570,14 +1390,15 @@ struct wget_timer {
   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;
 }
 
@@ -1635,8 +1456,11 @@ wtimer_sys_set (wget_sys_time *wst)
 }
 
 /* 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)
@@ -1645,6 +1469,7 @@ 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
@@ -1667,17 +1492,22 @@ wtimer_sys_diff (wget_sys_time *wst1, wget_sys_time *wst2)
 #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);
 
@@ -1702,7 +1532,22 @@ wtimer_elapsed (struct wget_timer *wt)
     }
 
   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
@@ -1978,7 +1823,7 @@ alarm_set (double timeout)
 #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)
@@ -2006,7 +1851,7 @@ alarm_cancel (void)
 {
 #ifdef ITIMER_REAL
   struct itimerval disable;
-  memset (&disable, 0, sizeof (disable));
+  xzero (disable);
   setitimer (ITIMER_REAL, &disable, NULL);
 #else  /* not ITIMER_REAL */
   alarm (0);
@@ -2085,3 +1930,55 @@ run_with_timeout (double timeout, void (*fun) (void *), void *arg)
 }
 #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 */