]> sjero.net Git - wget/blobdiff - src/utils.c
Fix build when libpsl is not available
[wget] / src / utils.c
index 003b364029fc08ccb2b561941bcbc2d28f058c99..8168fb38719d8880d08ef53608a0a31afe86720c 100644 (file)
@@ -1,6 +1,7 @@
 /* Various utility functions.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+   Inc.
 
 This file is part of GNU Wget.
 
@@ -17,50 +18,53 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
-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.  */
+Additional permission under GNU GPL version 3 section 7
 
-#include <config.h>
+If you modify this program, or any covered work, by linking or
+combining it with the OpenSSL project's OpenSSL library (or a
+modified version of that library), containing parts covered by the
+terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+grants you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts of OpenSSL used as well
+as that of the covered work.  */
+
+#include "wget.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <unistd.h>
 #ifdef HAVE_MMAP
 # include <sys/mman.h>
 #endif
 #ifdef HAVE_PROCESS_H
 # include <process.h>  /* getpid() */
 #endif
-#ifdef HAVE_UTIME_H
-# include <utime.h>
-#endif
-#ifdef HAVE_SYS_UTIME_H
-# include <sys/utime.h>
-#endif
 #include <errno.h>
 #include <fcntl.h>
 #include <assert.h>
 #include <stdarg.h>
 #include <locale.h>
 
-/* For TIOCGWINSZ and friends: */
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
+#if HAVE_UTIME
+# include <sys/types.h>
+# ifdef HAVE_UTIME_H
+#  include <utime.h>
+# endif
+
+# ifdef HAVE_SYS_UTIME_H
+#  include <sys/utime.h>
+# endif
 #endif
+
+#include <sys/time.h>
+
+#include <sys/stat.h>
+
+/* For TIOCGWINSZ and friends: */
+#include <sys/ioctl.h>
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
 #endif
@@ -69,6 +73,11 @@ so, delete this exception statement from your version.  */
 #include <signal.h>
 #include <setjmp.h>
 
+#include <regex.h>
+#ifdef HAVE_LIBPCRE
+# include <pcre.h>
+#endif
+
 #ifndef HAVE_SIGSETJMP
 /* If sigsetjmp is a macro, configure won't pick it up. */
 # ifdef sigsetjmp
@@ -80,13 +89,124 @@ so, delete this exception statement from your version.  */
 # define USE_SIGNAL_TIMEOUT
 #endif
 
-#include "wget.h"
 #include "utils.h"
 #include "hash.h"
 
+#ifdef __VMS
+#include "vms.h"
+#endif /* def __VMS */
+
 #ifdef TESTING
 #include "test.h"
-#endif 
+#endif
+
+static void
+memfatal (const char *context, long attempted_size)
+{
+  /* Make sure we don't try to store part of the log line, and thus
+     call malloc.  */
+  log_set_save_context (false);
+
+  /* We have different log outputs in different situations:
+     1) output without bytes information
+     2) output with bytes information  */
+  if (attempted_size == UNKNOWN_ATTEMPTED_SIZE)
+    {
+      logprintf (LOG_ALWAYS,
+                 _("%s: %s: Failed to allocate enough memory; memory exhausted.\n"),
+                 exec_name, context);
+    }
+  else
+    {
+      logprintf (LOG_ALWAYS,
+                 _("%s: %s: Failed to allocate %ld bytes; memory exhausted.\n"),
+                 exec_name, context, attempted_size);
+    }
+
+  exit (1);
+}
+
+/* Character property table for (re-)escaping VMS ODS5 extended file
+   names.  Note that this table ignores Unicode.
+
+   ODS2 valid characters: 0-9 A-Z a-z $ - _ ~
+
+   ODS5 Invalid characters:
+      C0 control codes (0x00 to 0x1F inclusive)
+      Asterisk (*)
+      Question mark (?)
+
+   ODS5 Invalid characters only in VMS V7.2 (which no one runs, right?):
+      Double quotation marks (")
+      Backslash (\)
+      Colon (:)
+      Left angle bracket (<)
+      Right angle bracket (>)
+      Slash (/)
+      Vertical bar (|)
+
+   Characters escaped by "^":
+      SP  !  "  #  %  &  '  (  )  +  ,  .  :  ;  =
+       @  [  \  ]  ^  `  {  |  }  ~
+
+   Either "^_" or "^ " is accepted as a space.  Period (.) is a special
+   case.  Note that un-escaped < and > can also confuse a directory
+   spec.
+
+   Characters put out as ^xx:
+      7F (DEL)
+      80-9F (C1 control characters)
+      A0 (nonbreaking space)
+      FF (Latin small letter y diaeresis)
+
+   Other cases:
+      Unicode: "^Uxxxx", where "xxxx" is four hex digits.
+
+    Property table values:
+      Normal escape:    1
+      Space:            2
+      Dot:              4
+      Hex-hex escape:   8
+      ODS2 normal:     16
+      ODS2 lower case: 32
+      Hex digit:       64
+*/
+
+unsigned char char_prop[ 256] = {
+
+/* NUL SOH STX ETX EOT ENQ ACK BEL   BS  HT  LF  VT  FF  CR  SO  SI */
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+
+/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB  CAN  EM SUB ESC  FS  GS  RS  US */
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+
+/*  SP  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /  */
+    2,  1,  1,  1, 16,  1,  1,  1,   1,  1,  0,  1,  1, 16,  4,  0,
+
+/*  0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?  */
+   80, 80, 80, 80, 80, 80, 80, 80,  80, 80,  1,  1,  1,  1,  1,  1,
+
+/*  @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O  */
+    1, 80, 80, 80, 80, 80, 80, 16,  16, 16, 16, 16, 16, 16, 16, 16,
+
+/*  P   Q   R   S   T   U   V   W    X   Y   Z   [   \   ]   ^   _  */
+   16, 16, 16, 16, 16, 16, 16, 16,  16, 16, 16,  1,  1,  1,  1, 16,
+
+/*  `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o  */
+    1, 96, 96, 96, 96, 96, 96, 32,  32, 32, 32, 32, 32, 32, 32, 32,
+
+/*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~  DEL */
+   32, 32, 32, 32, 32, 32, 32, 32,  32, 32, 32,  1,  1,  1, 17,  8,
+
+    8,  8,  8,  8,  8,  8,  8,  8,   8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8,   8,  8,  8,  8,  8,  8,  8,  8,
+    8,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  8
+};
 
 /* Utility function: like xstrdup(), but also lowercases S.  */
 
@@ -159,6 +279,13 @@ sepstring (const char *s)
    vsnprintf until the correct size is found.  Since Wget also ships a
    fallback implementation of vsnprintf, this should be portable.  */
 
+/* Constant is using for limits memory allocation for text buffer.
+   Applicable in situation when: vasprintf is not available in the system
+   and vsnprintf return -1 when long line is truncated (in old versions of
+   glibc and in other system where C99 doesn`t support) */
+
+#define FMT_MAX_LENGTH 1048576
+
 char *
 aprintf (const char *fmt, ...)
 {
@@ -171,7 +298,8 @@ aprintf (const char *fmt, ...)
   ret = vasprintf (&str, fmt, args);
   va_end (args);
   if (ret < 0 && errno == ENOMEM)
-    abort ();                   /* for consistency with xmalloc/xrealloc */
+    memfatal ("aprintf", UNKNOWN_ATTEMPTED_SIZE);  /* for consistency
+                                                      with xmalloc/xrealloc */
   else if (ret < 0)
     return NULL;
   return str;
@@ -201,8 +329,21 @@ aprintf (const char *fmt, ...)
       /* Else try again with a larger buffer. */
       if (n > -1)               /* C99 */
         size = n + 1;           /* precisely what is needed */
+      else if (size >= FMT_MAX_LENGTH)  /* We have a huge buffer, */
+        {                               /* maybe we have some wrong
+                                           format string? */
+          logprintf (LOG_ALWAYS,
+                     _("%s: aprintf: text buffer is too big (%ld bytes), "
+                       "aborting.\n"),
+                     exec_name, size);  /* printout a log message */
+          abort ();                     /* and abort... */
+        }
       else
-        size <<= 1;             /* twice the old size */
+        {
+          /* else, we continue to grow our
+           * buffer: Twice the old size. */
+          size <<= 1;
+        }
       str = xrealloc (str, size);
     }
 #endif /* not HAVE_VASPRINTF */
@@ -220,7 +361,7 @@ concat_strings (const char *str0, ...)
 
   const char *next_str;
   int total_length = 0;
-  int argcount;
+  size_t argcount;
 
   /* Calculate the length of and allocate the resulting string. */
 
@@ -293,6 +434,16 @@ datetime_str (time_t t)
 /* The Windows versions of the following two functions are defined in
    mswindows.c. On MSDOS this function should never be called. */
 
+#ifdef __VMS
+
+void
+fork_to_background (void)
+{
+  return;
+}
+
+#else /* def __VMS */
+
 #if !defined(WINDOWS) && !defined(MSDOS)
 void
 fork_to_background (void)
@@ -301,7 +452,7 @@ fork_to_background (void)
   /* Whether we arrange our own version of opt.lfilename here.  */
   bool logfile_changed = false;
 
-  if (!opt.lfilename)
+  if (!opt.lfilename && (!opt.quiet || opt.server_response))
     {
       /* We must create the file immediately to avoid either a race
          condition (which arises from using unique_name and failing to
@@ -327,17 +478,23 @@ fork_to_background (void)
       /* parent, no error */
       printf (_("Continuing in background, pid %d.\n"), (int) pid);
       if (logfile_changed)
-        printf (_("Output will be written to `%s'.\n"), opt.lfilename);
+        printf (_("Output will be written to %s.\n"), quote (opt.lfilename));
       exit (0);                 /* #### should we use _exit()? */
     }
 
   /* child: give up the privileges and keep running. */
   setsid ();
-  freopen ("/dev/null", "r", stdin);
-  freopen ("/dev/null", "w", stdout);
-  freopen ("/dev/null", "w", stderr);
+  if (freopen ("/dev/null", "r", stdin) == NULL)
+    DEBUGP (("Failed to redirect stdin to /dev/null.\n"));
+  if (freopen ("/dev/null", "w", stdout) == NULL)
+    DEBUGP (("Failed to redirect stdout to /dev/null.\n"));
+  if (freopen ("/dev/null", "w", stderr) == NULL)
+    DEBUGP (("Failed to redirect stderr to /dev/null.\n"));
 }
 #endif /* !WINDOWS && !MSDOS */
+
+#endif /* def __VMS [else] */
+
 \f
 /* "Touch" FILE, i.e. make its mtime ("modified time") equal the time
    specified with TM.  The atime ("access time") is set to the current
@@ -346,18 +503,40 @@ fork_to_background (void)
 void
 touch (const char *file, time_t tm)
 {
-#ifdef HAVE_STRUCT_UTIMBUF
+#if HAVE_UTIME
+# ifdef HAVE_STRUCT_UTIMBUF
   struct utimbuf times;
-#else
+# else
   struct {
     time_t actime;
     time_t modtime;
   } times;
-#endif
+# endif
   times.modtime = tm;
   times.actime = time (NULL);
   if (utime (file, &times) == -1)
     logprintf (LOG_NOTQUIET, "utime(%s): %s\n", file, strerror (errno));
+#else
+  struct timespec timespecs[2];
+  int fd;
+
+  fd = open (file, O_WRONLY);
+  if (fd < 0)
+    {
+      logprintf (LOG_NOTQUIET, "open(%s): %s\n", file, strerror (errno));
+      return;
+    }
+
+  timespecs[0].tv_sec = time (NULL);
+  timespecs[0].tv_nsec = 0L;
+  timespecs[1].tv_sec = tm;
+  timespecs[1].tv_nsec = 0L;
+
+  if (futimens (fd, timespecs) == -1)
+    logprintf (LOG_NOTQUIET, "futimens(%s): %s\n", file, strerror (errno));
+
+  close (fd);
+#endif
 }
 
 /* Checks if FILE is a symbolic link, and removes it if it is.  Does
@@ -373,8 +552,8 @@ remove_link (const char *file)
       DEBUGP (("Unlinking %s (symlink).\n", file));
       err = unlink (file);
       if (err != 0)
-        logprintf (LOG_VERBOSE, _("Failed to unlink symlink `%s': %s\n"),
-                   file, strerror (errno));
+        logprintf (LOG_VERBOSE, _("Failed to unlink symlink %s: %s\n"),
+                   quote (file), strerror (errno));
     }
   return err;
 }
@@ -436,6 +615,14 @@ file_size (const char *filename)
 #endif
 }
 
+/* 2005-02-19 SMS.
+   If no UNIQ_SEP is defined (as on VMS), have unique_name() return the
+   original name.  With the VMS file systems' versioning, everything
+   should be fine, and appending ".NN" just causes trouble.
+*/
+
+#ifdef UNIQ_SEP
+
 /* stat file names named PREFIX.1, PREFIX.2, etc., until one that
    doesn't exist is found.  Return a freshly allocated copy of the
    unused file name.  */
@@ -449,7 +636,7 @@ unique_name_1 (const char *prefix)
   char *template_tail = template + plen;
 
   memcpy (template, prefix, plen);
-  *template_tail++ = '.';
+  *template_tail++ = UNIQ_SEP;
 
   do
     number_to_string (template_tail, count++);
@@ -464,6 +651,8 @@ unique_name_1 (const char *prefix)
    If not, FILE.1 is tried, then FILE.2, etc.  The first FILE.<number>
    file name that doesn't exist is returned.
 
+   2005-02-19 SMS.  "." is now UNIQ_SEP, and may be different.
+
    The resulting file is not created, only verified that it didn't
    exist at the point in time when the function was called.
    Therefore, where security matters, don't rely that the file created
@@ -487,6 +676,20 @@ unique_name (const char *file, bool allow_passthrough)
   return unique_name_1 (file);
 }
 
+#else /* def UNIQ_SEP */
+
+/* Dummy unique_name() for VMS.  Return the original name as easily as
+   possible.
+*/
+char *
+unique_name (const char *file, bool allow_passthrough)
+{
+  /* Return the FILE itself, without modification, irregardful. */
+  return allow_passthrough ? (char *)file : xstrdup (file);
+}
+
+#endif /* def UNIQ_SEP [else] */
+
 /* Create a file based on NAME, except without overwriting an existing
    file with that name.  Providing O_EXCL is correctly implemented,
    this function does not have the race condition associated with
@@ -503,7 +706,7 @@ unique_create (const char *name, bool binary, char **opened_name)
       xfree (uname);
       uname = unique_name (name, false);
     }
-  if (opened_name && fp != NULL)
+  if (opened_name)
     {
       if (fp)
         *opened_name = uname;
@@ -527,18 +730,66 @@ unique_create (const char *name, bool binary, char **opened_name)
    If opening the file fails for any reason, including the file having
    previously existed, this function returns NULL and sets errno
    appropriately.  */
-   
+
 FILE *
-fopen_excl (const char *fname, bool binary)
+fopen_excl (const char *fname, int binary)
 {
   int fd;
 #ifdef O_EXCL
+
+/* 2005-04-14 SMS.
+   VMS lacks O_BINARY, but makes up for it in weird and wonderful ways.
+   It also has file versions which obviate all the O_EXCL effort.
+   O_TRUNC (something of a misnomer) requests a new version.
+*/
+# ifdef __VMS
+/* Common open() optional arguments:
+   sequential access only, access callback function.
+*/
+#  define OPEN_OPT_ARGS "fop=sqo", "acc", acc_cb, &open_id
+
+  int open_id;
+  int flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+  if (binary > 1)
+    {
+      open_id = 11;
+      fd = open( fname,                 /* File name. */
+       flags,                           /* Flags. */
+       0777,                            /* Mode for default protection. */
+       "ctx=bin,stm",                   /* Binary, stream access. */
+       "rfm=stmlf",                     /* Stream_LF. */
+       OPEN_OPT_ARGS);                  /* Access callback. */
+    }
+  else if (binary)
+    {
+      open_id = 12;
+      fd = open( fname,                 /* File name. */
+       flags,                           /* Flags. */
+       0777,                            /* Mode for default protection. */
+       "ctx=bin,stm",                   /* Binary, stream access. */
+       "rfm=fix",                       /* Fixed-length, */
+       "mrs=512",                       /* 512-byte records. */
+       OPEN_OPT_ARGS);                  /* Access callback. */
+    }
+  else
+    {
+      open_id = 13;
+      fd = open( fname,                 /* File name. */
+       flags,                           /* Flags. */
+       0777,                            /* Mode for default protection. */
+       "rfm=stmlf",                     /* Stream_LF. */
+       OPEN_OPT_ARGS);                  /* Access callback. */
+    }
+# else /* def __VMS */
   int flags = O_WRONLY | O_CREAT | O_EXCL;
 # ifdef O_BINARY
   if (binary)
     flags |= O_BINARY;
 # endif
   fd = open (fname, flags, 0666);
+# endif /* def __VMS [else] */
+
   if (fd < 0)
     return NULL;
   return fdopen (fd, binary ? "wb" : "w");
@@ -652,12 +903,14 @@ static bool in_acclist (const char *const *, const char *, bool);
 bool
 acceptable (const char *s)
 {
-  int l = strlen (s);
+  const char *p;
+
+  if (opt.output_document && strcmp (s, opt.output_document) == 0)
+    return true;
+
+  if ((p = strrchr (s, '/')))
+    s = p + 1;
 
-  while (l && s[l] != '/')
-    --l;
-  if (s[l] == '/')
-    s += (l + 1);
   if (opt.accepts)
     {
       if (opt.rejects)
@@ -668,22 +921,38 @@ acceptable (const char *s)
     }
   else if (opt.rejects)
     return !in_acclist ((const char *const *)opt.rejects, s, true);
+
+  return true;
+}
+
+/* Determine whether an URL is acceptable to be followed, according to
+   regex patterns to accept/reject.  */
+bool
+accept_url (const char *s)
+{
+  if (opt.acceptregex && !opt.regex_match_fun (opt.acceptregex, s))
+    return false;
+  if (opt.rejectregex && opt.regex_match_fun (opt.rejectregex, s))
+    return false;
+
   return true;
 }
 
 /* Check if D2 is a subdirectory of D1.  E.g. if D1 is `/something', subdir_p()
-   will return true if and only if D2 begins with `/something/' or is exactly 
+   will return true if and only if D2 begins with `/something/' or is exactly
    '/something'.  */
 bool
 subdir_p (const char *d1, const char *d2)
 {
+  if (*d1 == '\0')
+    return true;
   if (!opt.ignore_case)
     for (; *d1 && *d2 && (*d1 == *d2); ++d1, ++d2)
       ;
   else
     for (; *d1 && *d2 && (c_tolower (*d1) == c_tolower (*d2)); ++d1, ++d2)
       ;
-  
+
   return *d1 == '\0' && (*d2 == '\0' || *d2 == '/');
 }
 
@@ -691,16 +960,16 @@ subdir_p (const char *d1, const char *d2)
    first element that matches DIR, through wildcards or front comparison (as
    appropriate).  */
 static bool
-dir_matches_p (char **dirlist, const char *dir)
+dir_matches_p (const char **dirlist, const char *dir)
 {
-  char **x;
+  const char **x;
   int (*matcher) (const char *, const char *, int)
     = opt.ignore_case ? fnmatch_nocase : fnmatch;
 
   for (x = dirlist; *x; x++)
     {
       /* Remove leading '/' */
-      char *p = *x + (**x == '/');
+      const char *p = *x + (**x == '/');
       if (has_wildcards_p (p))
         {
           if (matcher (p, dir, FNM_PATHNAME) == 0)
@@ -712,7 +981,7 @@ dir_matches_p (char **dirlist, const char *dir)
             break;
         }
     }
-      
+
   return *x ? true : false;
 }
 
@@ -752,29 +1021,15 @@ accdir (const char *directory)
 bool
 match_tail (const char *string, const char *tail, bool fold_case)
 {
-  int i, j;
+  int pos = strlen (string) - strlen (tail);
 
-  /* We want this to be fast, so we code two loops, one with
-     case-folding, one without. */
+  if (pos < 0)
+    return false;  /* tail is longer than string.  */
 
   if (!fold_case)
-    {
-      for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--)
-        if (string[i] != tail[j])
-          break;
-    }
+    return !strcmp (string + pos, tail);
   else
-    {
-      for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--)
-        if (c_tolower (string[i]) != c_tolower (tail[j]))
-          break;
-    }
-
-  /* If the tail was exhausted, the match was succesful.  */
-  if (j == -1)
-    return true;
-  else
-    return false;
+    return !strcasecmp (string + pos, tail);
 }
 
 /* Checks whether string S matches each element of ACCEPTS.  A list
@@ -823,15 +1078,12 @@ in_acclist (const char *const *accepts, const char *s, bool backward)
 char *
 suffix (const char *str)
 {
-  int i;
+  char *p;
 
-  for (i = strlen (str); i && str[i] != '/' && str[i] != '.'; i--)
-    ;
+  if ((p = strrchr (str, '.')) && !strchr (p + 1, '/'))
+    return p + 1;
 
-  if (str[i++] == '.')
-    return (char *)str + i;
-  else
-    return NULL;
+  return NULL;
 }
 
 /* Return true if S contains globbing wildcards (`*', `?', `[' or
@@ -840,16 +1092,13 @@ suffix (const char *str)
 bool
 has_wildcards_p (const char *s)
 {
-  for (; *s; s++)
-    if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
-      return true;
-  return false;
+  return !!strpbrk (s, "*?[]");
 }
 
 /* Return true 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)
@@ -872,74 +1121,24 @@ has_html_suffix_p (const char *fname)
   return false;
 }
 
-/* Read a line from FP and return the pointer to freshly allocated
-   storage.  The storage space is obtained through malloc() and should
-   be freed with free() when it is no longer needed.
-
-   The length of the line is not limited, except by available memory.
-   The newline character at the end of line is retained.  The line is
-   terminated with a zero character.
-
-   After end-of-file is encountered without anything being read, NULL
-   is returned.  NULL is also returned on error.  To distinguish
-   between these two cases, use the stdio function ferror().  */
-
-char *
-read_whole_line (FILE *fp)
-{
-  int length = 0;
-  int bufsize = 82;
-  char *line = xmalloc (bufsize);
-
-  while (fgets (line + length, bufsize - length, fp))
-    {
-      length += strlen (line + length);
-      if (length == 0)
-        /* Possible for example when reading from a binary file where
-           a line begins with \0.  */
-        continue;
-
-      if (line[length - 1] == '\n')
-        break;
-
-      /* fgets() guarantees to read the whole line, or to use up the
-         space we've given it.  We can double the buffer
-         unconditionally.  */
-      bufsize <<= 1;
-      line = xrealloc (line, bufsize);
-    }
-  if (length == 0 || ferror (fp))
-    {
-      xfree (line);
-      return NULL;
-    }
-  if (length + 1 < bufsize)
-    /* Relieve the memory from our exponential greediness.  We say
-       `length + 1' because the terminating \0 is not included in
-       LENGTH.  We don't need to zero-terminate the string ourselves,
-       though, because fgets() does that.  */
-    line = xrealloc (line, length + 1);
-  return line;
-}
-\f
 /* Read FILE into memory.  A pointer to `struct file_memory' are
    returned; use struct element `content' to access file contents, and
    the element `length' to know the file length.  `content' is *not*
    zero-terminated, and you should *not* read or write beyond the [0,
    length) range of characters.
 
-   After you are done with the file contents, call read_file_free to
+   After you are done with the file contents, call wget_read_file_free to
    release the memory.
 
    Depending on the operating system and the type of file that is
-   being read, read_file() either mmap's the file into memory, or
+   being read, wget_read_file() either mmap's the file into memory, or
    reads the file into the core using read().
 
    If file is named "-", fileno(stdin) is used for reading instead.
    If you want to read from a real file named "-", use "./-" instead.  */
 
 struct file_memory *
-read_file (const char *file)
+wget_read_file (const char *file)
 {
   int fd;
   struct file_memory *fm;
@@ -1049,7 +1248,7 @@ read_file (const char *file)
    memory needed to hold the FM structure itself.  */
 
 void
-read_file_free (struct file_memory *fm)
+wget_read_file_free (struct file_memory *fm)
 {
 #ifdef HAVE_MMAP
   if (fm->mmap_p)
@@ -1219,6 +1418,12 @@ get_grouping_data (const char **sep, const char **grouping)
       struct lconv *lconv = localeconv ();
       cached_sep = lconv->thousands_sep;
       cached_grouping = lconv->grouping;
+#if ! USE_NLS_PROGRESS_BAR
+      /* We can't count column widths, so ensure that the separator
+       * is single-byte only (let check below determine what byte). */
+      if (strlen(cached_sep) > 1)
+        cached_sep = "";
+#endif
       if (!*cached_sep)
         {
           /* Many locales (such as "C" or "hr_HR") don't specify
@@ -1318,7 +1523,7 @@ with_thousand_seps (wgint n)
    some detail.  */
 
 char *
-human_readable (HR_NUMTYPE n)
+human_readable (HR_NUMTYPE n, const int acc, const int decimals)
 {
   /* These suffixes are compatible with those of GNU `ls -lh'. */
   static char powers[] =
@@ -1331,7 +1536,7 @@ human_readable (HR_NUMTYPE n)
       'E',                      /* exabyte,  2^60 bytes */
     };
   static char buf[8];
-  int i;
+  size_t i;
 
   /* If the quantity is smaller than 1K, just print it. */
   if (n < 1024)
@@ -1351,10 +1556,10 @@ human_readable (HR_NUMTYPE n)
       if ((n / 1024) < 1024 || i == countof (powers) - 1)
         {
           double val = n / 1024.0;
-          /* Print values smaller than 10 with one decimal digits, and
-             others without any decimals.  */
+          /* Print values smaller than the accuracy level (acc) with (decimal)
+           * decimal digits, and others without any decimals.  */
           snprintf (buf, sizeof (buf), "%.*f%c",
-                    val < 10 ? 1 : 0, val, powers[i]);
+                    val < acc ? decimals : 0, val, powers[i]);
           return buf;
         }
       n /= 1024;
@@ -1571,6 +1776,17 @@ number_to_static_string (wgint number)
   ringpos = (ringpos + 1) % RING_SIZE;
   return buf;
 }
+
+/* Converts the byte to bits format if --report-bps option is enabled
+ */
+wgint
+convert_to_bits (wgint num)
+{
+  if (opt.report_bps)
+    return num * 8;
+  return num;
+}
+
 \f
 /* Determine the width of the terminal we're running on.  If that's
    not possible, return 0.  */
@@ -1698,9 +1914,10 @@ abort_run_with_timeout (int sig)
   /* 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);
+  sigset_t set;
+  sigemptyset (&set);
+  sigaddset (&set, SIGALRM);
+  sigprocmask (SIG_BLOCK, &set, NULL);
 
   /* Now it's safe to longjump. */
   longjmp (run_with_timeout_env, -1);
@@ -1888,8 +2105,8 @@ xsleep (double seconds)
    This implementation does not emit newlines after 76 characters of
    base64 data.  */
 
-int
-base64_encode (const void *data, int length, char *dest)
+size_t
+base64_encode (const void *data, size_t length, char *dest)
 {
   /* Conversion table.  */
   static const char tbl[64] = {
@@ -1956,7 +2173,7 @@ base64_encode (const void *data, int length, char *dest)
 
    This function originates from Free Recode.  */
 
-int
+ssize_t
 base64_decode (const char *base64, void *dest)
 {
   /* Table of base64 values for first 128 characters.  Note that this
@@ -2043,6 +2260,89 @@ base64_decode (const char *base64, void *dest)
   return q - (char *) dest;
 }
 
+#ifdef HAVE_LIBPCRE
+/* Compiles the PCRE regex. */
+void *
+compile_pcre_regex (const char *str)
+{
+  const char *errbuf;
+  int erroffset;
+  pcre *regex = pcre_compile (str, 0, &errbuf, &erroffset, 0);
+  if (! regex)
+    {
+      fprintf (stderr, _("Invalid regular expression %s, %s\n"),
+               quote (str), errbuf);
+      return false;
+    }
+  return regex;
+}
+#endif
+
+/* Compiles the POSIX regex. */
+void *
+compile_posix_regex (const char *str)
+{
+  regex_t *regex = xmalloc (sizeof (regex_t));
+  int errcode = regcomp ((regex_t *) regex, str, REG_EXTENDED | REG_NOSUB);
+  if (errcode != 0)
+    {
+      size_t errbuf_size = regerror (errcode, (regex_t *) regex, NULL, 0);
+      char *errbuf = xmalloc (errbuf_size);
+      regerror (errcode, (regex_t *) regex, errbuf, errbuf_size);
+      fprintf (stderr, _("Invalid regular expression %s, %s\n"),
+               quote (str), errbuf);
+      xfree (errbuf);
+      return NULL;
+    }
+
+  return regex;
+}
+
+#ifdef HAVE_LIBPCRE
+#define OVECCOUNT 30
+/* Matches a PCRE regex.  */
+bool
+match_pcre_regex (const void *regex, const char *str)
+{
+  size_t l = strlen (str);
+  int ovector[OVECCOUNT];
+
+  int rc = pcre_exec ((pcre *) regex, 0, str, (int) l, 0, 0, ovector, OVECCOUNT);
+  if (rc == PCRE_ERROR_NOMATCH)
+    return false;
+  else if (rc < 0)
+    {
+      logprintf (LOG_VERBOSE, _("Error while matching %s: %d\n"),
+                 quote (str), rc);
+      return false;
+    }
+  else
+    return true;
+}
+#undef OVECCOUNT
+#endif
+
+/* Matches a POSIX regex.  */
+bool
+match_posix_regex (const void *regex, const char *str)
+{
+  int rc = regexec ((regex_t *) regex, str, 0, NULL, 0);
+  if (rc == REG_NOMATCH)
+    return false;
+  else if (rc == 0)
+    return true;
+  else
+    {
+      size_t errbuf_size = regerror (rc, opt.acceptregex, NULL, 0);
+      char *errbuf = xmalloc (errbuf_size);
+      regerror (rc, opt.acceptregex, errbuf, errbuf_size);
+      logprintf (LOG_VERBOSE, _("Error while matching %s: %d\n"),
+                 quote (str), rc);
+      xfree (errbuf);
+      return false;
+    }
+}
+
 #undef IS_ASCII
 #undef NEXT_CHAR
 \f
@@ -2127,27 +2427,81 @@ print_decimal (double number)
   return buf;
 }
 
+/* Get the maximum name length for the given path. */
+/* Return 0 if length is unknown. */
+long
+get_max_length (const char *path, int length, int name)
+{
+  long ret;
+  char *p, *d;
+
+  /* Make a copy of the path that we can modify. */
+  p = path ? strdupdelim (path, path + length) : strdup ("");
+
+  for (;;)
+    {
+      errno = 0;
+      /* For an empty path query the current directory. */
+#if HAVE_PATHCONF
+      ret = pathconf (*p ? p : ".", name);
+      if (!(ret < 0 && errno == ENOENT))
+        break;
+#else
+      ret = PATH_MAX;
+#endif
+
+      /* The path does not exist yet, but may be created. */
+      /* Already at current or root directory, give up. */
+      if (!*p || strcmp (p, "/") == 0)
+        break;
+
+      /* Remove one directory level and try again. */
+      d = strrchr (p, '/');
+      if (d == p)
+        p[1] = '\0';  /* check root directory */
+      else if (d)
+        *d = '\0';  /* remove last directory part */
+      else
+        *p = '\0';  /* check current directory */
+    }
+
+  xfree (p);
+
+  if (ret < 0)
+    {
+      /* pathconf() has a message for us. */
+      if (errno != 0)
+          perror ("pathconf");
+
+      /* If (errno == 0) then there is no max length.
+         Even on error return 0 so the caller can continue. */
+      return 0;
+    }
+
+  return ret;
+}
+
 #ifdef TESTING
 
 const char *
-test_subdir_p()
+test_subdir_p(void)
 {
-  int i;
-  struct {
-    char *d1;
-    char *d2;
+  static const struct {
+    const char *d1;
+    const char *d2;
     bool result;
   } test_array[] = {
     { "/somedir", "/somedir", true },
     { "/somedir", "/somedir/d2", true },
     { "/somedir/d1", "/somedir", false },
   };
-  
-  for (i = 0; i < countof(test_array); ++i) 
+  unsigned i;
+
+  for (i = 0; i < countof(test_array); ++i)
     {
       bool res = subdir_p (test_array[i].d1, test_array[i].d2);
 
-      mu_assert ("test_subdir_p: wrong result", 
+      mu_assert ("test_subdir_p: wrong result",
                  res == test_array[i].result);
     }
 
@@ -2155,26 +2509,36 @@ test_subdir_p()
 }
 
 const char *
-test_dir_matches_p()
+test_dir_matches_p(void)
 {
-  int i;
-  struct {
-    char *dirlist[3];
-    char *dir;
+  static struct {
+    const char *dirlist[3];
+    const char *dir;
     bool result;
   } test_array[] = {
     { { "/somedir", "/someotherdir", NULL }, "somedir", true },
     { { "/somedir", "/someotherdir", NULL }, "anotherdir", false },
     { { "/somedir", "/*otherdir", NULL }, "anotherdir", true },
     { { "/somedir/d1", "/someotherdir", NULL }, "somedir/d1", true },
+    { { "*/*d1", "/someotherdir", NULL }, "somedir/d1", true },
     { { "/somedir/d1", "/someotherdir", NULL }, "d1", false },
+    { { "!COMPLETE", NULL, NULL }, "!COMPLETE", true },
+    { { "*COMPLETE", NULL, NULL }, "!COMPLETE", true },
+    { { "*/!COMPLETE", NULL, NULL }, "foo/!COMPLETE", true },
+    { { "*COMPLETE", NULL, NULL }, "foo/!COMPLETE", false },
+    { { "*/*COMPLETE", NULL, NULL }, "foo/!COMPLETE", true },
+    { { "/dir with spaces", NULL, NULL }, "dir with spaces", true },
+    { { "/dir*with*spaces", NULL, NULL }, "dir with spaces", true },
+    { { "/Tmp/has", NULL, NULL }, "/Tmp/has space", false },
+    { { "/Tmp/has", NULL, NULL }, "/Tmp/has,comma", false },
   };
-  
-  for (i = 0; i < countof(test_array); ++i) 
+  unsigned i;
+
+  for (i = 0; i < countof(test_array); ++i)
     {
       bool res = dir_matches_p (test_array[i].dirlist, test_array[i].dir);
-      
-      mu_assert ("test_dir_matches_p: wrong result", 
+
+      mu_assert ("test_dir_matches_p: wrong result",
                  res == test_array[i].result);
     }