]> sjero.net Git - wget/blobdiff - src/utils.c
[svn] Update the license to include the OpenSSL exception.
[wget] / src / utils.c
index 3f04edafbb8f70b153a6486518c56d0d66d3a586..a5b6d9ae20e55570ebe6557d7d21ece71334ea26 100644 (file)
@@ -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 <config.h>
 
@@ -59,6 +69,27 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 # include <termios.h>
 #endif
 
+/* Needed for run_with_timeout. */
+#undef USE_SIGNAL_TIMEOUT
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#ifdef HAVE_SETJMP_H
+# include <setjmp.h>
+#endif
+/* If sigsetjmp is a macro, configure won't pick it up. */
+#ifdef sigsetjmp
+# define HAVE_SIGSETJMP
+#endif
+#ifdef HAVE_SIGNAL
+# ifdef HAVE_SIGSETJMP
+#  define USE_SIGNAL_TIMEOUT
+# endif
+# ifdef HAVE_SIGBLOCK
+#  define USE_SIGNAL_TIMEOUT
+# endif
+#endif
+
 #include "wget.h"
 #include "utils.h"
 #include "fnmatch.h"
@@ -533,6 +564,22 @@ file_non_directory_p (const char *path)
   return S_ISDIR (buf.st_mode) ? 0 : 1;
 }
 
+/* Return the size of file named by FILENAME, or -1 if it cannot be
+   opened or seeked into. */
+long
+file_size (const char *filename)
+{
+  long size;
+  /* We use fseek rather than stat to determine the file size because
+     that way we can also verify whether the file is readable.
+     Inspired by the POST patch by Arnaud Wylie.  */
+  FILE *fp = fopen (filename, "rb");
+  fseek (fp, 0, SEEK_END);
+  size = ftell (fp);
+  fclose (fp);
+  return size;
+}
+
 /* Return a unique filename, given a prefix and count */
 static char *
 unique_name_1 (const char *fileprefix, int count)
@@ -718,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
@@ -760,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
@@ -792,6 +856,31 @@ suffix (const char *str)
     return NULL;
 }
 
+/* Return non-zero if FNAME ends with a typical HTML suffix.  The
+   following (case-insensitive) suffixes are presumed to be HTML files:
+   
+     html
+     htm
+     ?html (`?' matches one character)
+
+   #### CAVEAT.  This is not necessarily a good indication that FNAME
+   refers to a file that contains HTML!  */
+int
+has_html_suffix_p (const char *fname)
+{
+  char *suf;
+
+  if ((suf = suffix (fname)) == NULL)
+    return 0;
+  if (!strcasecmp (suf, "html"))
+    return 1;
+  if (!strcasecmp (suf, "htm"))
+    return 1;
+  if (suf[0] && !strcasecmp (suf + 1, "html"))
+    return 1;
+  return 0;
+}
+
 /* Read a line from FP and return the pointer to freshly allocated
    storage.  The stoarage space is obtained through malloc() and
    should be freed with free() when it is no longer needed.
@@ -1285,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))
 
@@ -1344,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;
     }
@@ -1732,3 +1836,75 @@ debug_test_md5 (char *buf)
   return res;
 }
 #endif
+\f
+/* Implementation of run_with_timeout, a generic timeout handler 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 RETSIGTYPE
+abort_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 RETSIGTYPE
+abort_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 */
+#endif /* USE_SIGNAL_TIMEOUT */
+
+int
+run_with_timeout (long timeout, void (*fun) (void *), void *arg)
+{
+#ifndef USE_SIGNAL_TIMEOUT
+  fun (arg);
+  return 0;
+#else
+  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 (timeout);
+  fun (arg);
+
+  /* Preserve errno in case alarm() or signal() modifies it. */
+  saved_errno = errno;
+  alarm (0);
+  signal (SIGALRM, SIG_DFL);
+  errno = saved_errno;
+
+  return 0;
+#endif
+}
+