From 097923f7b19a1f40313ecce0e743e42df5c75673 Mon Sep 17 00:00:00 2001
From: hniksic <devnull@localhost>
Date: Tue, 7 Oct 2003 16:53:31 -0700
Subject: [PATCH] [svn] Move fnmatch() to cmpt.c and don't use it under GNU
 libc.

---
 src/ChangeLog   |  12 +++
 src/Makefile.in |  11 ++-
 src/cmpt.c      | 182 ++++++++++++++++++++++++++++++++++++++
 src/fnmatch.c   | 228 ------------------------------------------------
 src/fnmatch.h   |  46 ----------
 src/ftp.c       |  15 +++-
 src/http.c      |   1 -
 src/recur.c     |   1 -
 src/sysdep.h    |  41 +++++++--
 src/utils.c     |  13 ++-
 src/utils.h     |   1 +
 11 files changed, 261 insertions(+), 290 deletions(-)
 delete mode 100644 src/fnmatch.c
 delete mode 100644 src/fnmatch.h

diff --git a/src/ChangeLog b/src/ChangeLog
index 3528831b..91905e6e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,15 @@
+2003-10-08  Hrvoje Niksic  <hniksic@xemacs.org>
+
+	* ftp.c (has_insecure_name_p): Define it here.
+
+	* utils.c (has_wildcards_p): Define it here.
+
+	* sysdep.h: Declare fnmatch-related macros here, if not using
+	system fnmatch().  Update .c files to not declare fnmatch.h
+	directly.
+
+	* cmpt.c (fnmatch): Moved here.  Use it only under non-GNU libc.
+
 2003-10-08  Hrvoje Niksic  <hniksic@xemacs.org>
 
 	* getopt.c: Newer version, imported from Free libit.
diff --git a/src/Makefile.in b/src/Makefile.in
index 4ae47fa6..01e1f93a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -72,7 +72,7 @@ OPIE_OBJ   = @OPIE_OBJ@
 SSL_OBJ    = @SSL_OBJ@
 GETOPT_OBJ = @GETOPT_OBJ@
 
-OBJ = $(ALLOCA) cmpt$o connect$o convert$o cookies$o fnmatch$o    \
+OBJ = $(ALLOCA) cmpt$o connect$o convert$o cookies$o              \
       ftp$o ftp-basic$o ftp-ls$o $(OPIE_OBJ) $(GETOPT_OBJ) hash$o \
       headers$o host$o html-parse$o html-url$o http$o init$o      \
       log$o main$o $(MD5_OBJ) netrc$o progress$o rbuf$o recur$o   \
@@ -157,14 +157,13 @@ cmpt$o: wget.h sysdep.h options.h safe-ctype.h
 connect$o: wget.h sysdep.h options.h safe-ctype.h utils.h connect.h host.h
 convert$o: wget.h convert.h url.h recur.h utils.h hash.h
 cookies$o: wget.h sysdep.h options.h safe-ctype.h cookies.h hash.h url.h utils.h
-fnmatch$o: wget.h sysdep.h options.h safe-ctype.h fnmatch.h
 ftp-basic$o: wget.h sysdep.h options.h safe-ctype.h utils.h rbuf.h connect.h \
 	host.h ftp.h
 ftp-ls$o: wget.h sysdep.h options.h safe-ctype.h utils.h ftp.h rbuf.h host.h \
 	url.h
 ftp-opie$o: wget.h sysdep.h options.h safe-ctype.h gen-md5.h
 ftp$o: wget.h sysdep.h options.h safe-ctype.h utils.h url.h rbuf.h retr.h \
-	ftp.h host.h connect.h fnmatch.h netrc.h
+	ftp.h host.h connect.h netrc.h
 gen-md5$o: wget.h sysdep.h options.h safe-ctype.h gen-md5.h
 gen_sslfunc$o: wget.h sysdep.h options.h safe-ctype.h utils.h connect.h host.h \
 	url.h
@@ -177,7 +176,7 @@ host$o: wget.h sysdep.h options.h safe-ctype.h utils.h host.h url.h hash.h
 html-parse$o: wget.h sysdep.h options.h safe-ctype.h html-parse.h
 html-url$o: wget.h sysdep.h options.h safe-ctype.h html-parse.h url.h utils.h
 http$o: wget.h sysdep.h options.h safe-ctype.h utils.h url.h host.h rbuf.h \
-	retr.h headers.h connect.h host.h fnmatch.h netrc.h gen_sslfunc.h \
+	retr.h headers.h connect.h host.h netrc.h gen_sslfunc.h \
 	cookies.h gen-md5.h
 init$o: wget.h sysdep.h options.h safe-ctype.h utils.h init.h host.h recur.h \
 	netrc.h cookies.h progress.h
@@ -192,12 +191,12 @@ progress$o: wget.h sysdep.h options.h safe-ctype.h progress.h utils.h retr.h \
 rbuf$o: wget.h sysdep.h options.h safe-ctype.h rbuf.h connect.h host.h \
 	gen_sslfunc.h
 recur$o: wget.h sysdep.h options.h safe-ctype.h url.h recur.h utils.h retr.h \
-	rbuf.h ftp.h host.h fnmatch.h hash.h
+	rbuf.h ftp.h host.h hash.h
 res$o: wget.h sysdep.h options.h safe-ctype.h utils.h hash.h url.h retr.h res.h
 retr$o: wget.h sysdep.h options.h safe-ctype.h utils.h retr.h rbuf.h url.h \
 	recur.h ftp.h host.h connect.h hash.h
 snprintf$o: safe-ctype.h
 safe-ctype$o: safe-ctype.h
 url$o: wget.h sysdep.h options.h safe-ctype.h utils.h url.h host.h hash.h
-utils$o: wget.h sysdep.h options.h safe-ctype.h utils.h fnmatch.h hash.h
+utils$o: wget.h sysdep.h options.h safe-ctype.h utils.h hash.h
 version$o:
diff --git a/src/cmpt.c b/src/cmpt.c
index 6edf8402..ea1f44ae 100644
--- a/src/cmpt.c
+++ b/src/cmpt.c
@@ -43,6 +43,11 @@ so, delete this exception statement from your version.  */
 #endif
 #include <limits.h>
 
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
 #include "wget.h"
 
 #ifndef HAVE_STRERROR
@@ -1470,3 +1475,180 @@ memmove (char *dest, const char *source, unsigned length)
 #endif /* not HAVE_MEMMOVE */
 
 #endif /* 0 */
+
+/* fnmatch is a POSIX function, but we include an implementation for
+   the sake of systems that don't have it.  Furthermore, according to
+   anecdotal evidence, historical implementations of fnmatch are buggy
+   and unreliable.  So we use our version, except when compiling under
+   systems where fnmatch is known to work (currently glibc.)  */
+
+#ifndef SYSTEM_FNMATCH
+
+#define	__FNM_FLAGS	(FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD)
+
+/* Match STRING against the filename pattern PATTERN, returning zero
+   if it matches, FNM_NOMATCH if not.  This implementation comes from
+   an earlier version of GNU Bash.  (It doesn't make sense to update
+   it with a newer version because it adds a lot of features Wget
+   doesn't use or care about.)  */
+
+int
+fnmatch (const char *pattern, const char *string, int flags)
+{
+  register const char *p = pattern, *n = string;
+  register char c;
+
+  if ((flags & ~__FNM_FLAGS) != 0)
+    {
+      errno = EINVAL;
+      return (-1);
+    }
+
+  while ((c = *p++) != '\0')
+    {
+      switch (c)
+	{
+	case '?':
+	  if (*n == '\0')
+	    return (FNM_NOMATCH);
+	  else if ((flags & FNM_PATHNAME) && *n == '/')
+	    return (FNM_NOMATCH);
+	  else if ((flags & FNM_PERIOD) && *n == '.' &&
+		   (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+	    return (FNM_NOMATCH);
+	  break;
+
+	case '\\':
+	  if (!(flags & FNM_NOESCAPE))
+	    c = *p++;
+	  if (*n != c)
+	    return (FNM_NOMATCH);
+	  break;
+
+	case '*':
+	  if ((flags & FNM_PERIOD) && *n == '.' &&
+	      (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+	    return (FNM_NOMATCH);
+
+	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+	    if (((flags & FNM_PATHNAME) && *n == '/') ||
+		(c == '?' && *n == '\0'))
+	      return (FNM_NOMATCH);
+
+	  if (c == '\0')
+	    return (0);
+
+	  {
+	    char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+	    for (--p; *n != '\0'; ++n)
+	      if ((c == '[' || *n == c1) &&
+		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+		return (0);
+	    return (FNM_NOMATCH);
+	  }
+
+	case '[':
+	  {
+	    /* Nonzero if the sense of the character class is
+	       inverted.  */
+	    register int not;
+
+	    if (*n == '\0')
+	      return (FNM_NOMATCH);
+
+	    if ((flags & FNM_PERIOD) && *n == '.' &&
+		(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+	      return (FNM_NOMATCH);
+
+	    /* Make sure there is a closing `]'.  If there isn't,
+	       the `[' is just a character to be matched.  */
+	    {
+	      register const char *np;
+
+	      for (np = p; np && *np && *np != ']'; np++);
+
+	      if (np && !*np)
+		{
+		  if (*n != '[')
+		    return (FNM_NOMATCH);
+		  goto next_char;
+		}
+	    }
+
+	    not = (*p == '!' || *p == '^');
+	    if (not)
+	      ++p;
+
+	    c = *p++;
+	    while (1)
+	      {
+		register char cstart = c, cend = c;
+
+		if (!(flags & FNM_NOESCAPE) && c == '\\')
+		  cstart = cend = *p++;
+
+		if (c == '\0')
+		  /* [ (unterminated) loses.  */
+		  return (FNM_NOMATCH);
+
+		c = *p++;
+
+		if ((flags & FNM_PATHNAME) && c == '/')
+		  /* [/] can never match.  */
+		  return (FNM_NOMATCH);
+
+		if (c == '-' && *p != ']')
+		  {
+		    cend = *p++;
+		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
+		      cend = *p++;
+		    if (cend == '\0')
+		      return (FNM_NOMATCH);
+		    c = *p++;
+		  }
+
+		if (*n >= cstart && *n <= cend)
+		  goto matched;
+
+		if (c == ']')
+		  break;
+	      }
+	    if (!not)
+	      return (FNM_NOMATCH);
+
+	  next_char:
+	    break;
+
+	  matched:
+	    /* Skip the rest of the [...] that already matched.  */
+	    while (c != ']')
+	      {
+		if (c == '\0')
+		  /* [... (unterminated) loses.  */
+		  return (FNM_NOMATCH);
+
+		c = *p++;
+		if (!(flags & FNM_NOESCAPE) && c == '\\')
+		  /* 1003.2d11 is unclear if this is right.  %%% */
+		  ++p;
+	      }
+	    if (not)
+	      return (FNM_NOMATCH);
+	  }
+	  break;
+
+	default:
+	  if (c != *n)
+	    return (FNM_NOMATCH);
+	}
+
+      ++n;
+    }
+
+  if (*n == '\0')
+    return (0);
+
+  return (FNM_NOMATCH);
+}
+
+#endif /* not SYSTEM_FNMATCH */
diff --git a/src/fnmatch.c b/src/fnmatch.c
deleted file mode 100644
index 39bf6e01..00000000
--- a/src/fnmatch.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/* Pattern matching (globbing).
-   Copyright (C) 1991, 1996, 1997 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.  */
-
-/* NOTE: Some Un*xes have their own fnmatch() -- yet, they are
-   reportedly unreliable and buggy.  Thus I chose never to use it;
-   this version (from GNU Bash) is used unconditionally.  */
-
-#include <config.h>
-
-#include <errno.h>
-#include "wget.h"
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif /* HAVE_STRING_H */
-#include "fnmatch.h"
-
-/* Match STRING against the filename pattern PATTERN, returning zero
-   if it matches, FNM_NOMATCH if not.  */
-int
-fnmatch (const char *pattern, const char *string, int flags)
-{
-  register const char *p = pattern, *n = string;
-  register char c;
-
-  if ((flags & ~__FNM_FLAGS) != 0)
-    {
-      errno = EINVAL;
-      return (-1);
-    }
-
-  while ((c = *p++) != '\0')
-    {
-      switch (c)
-	{
-	case '?':
-	  if (*n == '\0')
-	    return (FNM_NOMATCH);
-	  else if ((flags & FNM_PATHNAME) && *n == '/')
-	    return (FNM_NOMATCH);
-	  else if ((flags & FNM_PERIOD) && *n == '.' &&
-		   (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
-	    return (FNM_NOMATCH);
-	  break;
-
-	case '\\':
-	  if (!(flags & FNM_NOESCAPE))
-	    c = *p++;
-	  if (*n != c)
-	    return (FNM_NOMATCH);
-	  break;
-
-	case '*':
-	  if ((flags & FNM_PERIOD) && *n == '.' &&
-	      (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
-	    return (FNM_NOMATCH);
-
-	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
-	    if (((flags & FNM_PATHNAME) && *n == '/') ||
-		(c == '?' && *n == '\0'))
-	      return (FNM_NOMATCH);
-
-	  if (c == '\0')
-	    return (0);
-
-	  {
-	    char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
-	    for (--p; *n != '\0'; ++n)
-	      if ((c == '[' || *n == c1) &&
-		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
-		return (0);
-	    return (FNM_NOMATCH);
-	  }
-
-	case '[':
-	  {
-	    /* Nonzero if the sense of the character class is
-	       inverted.  */
-	    register int not;
-
-	    if (*n == '\0')
-	      return (FNM_NOMATCH);
-
-	    if ((flags & FNM_PERIOD) && *n == '.' &&
-		(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
-	      return (FNM_NOMATCH);
-
-	    /* Make sure there is a closing `]'.  If there isn't,
-	       the `[' is just a character to be matched.  */
-	    {
-	      register const char *np;
-
-	      for (np = p; np && *np && *np != ']'; np++);
-
-	      if (np && !*np)
-		{
-		  if (*n != '[')
-		    return (FNM_NOMATCH);
-		  goto next_char;
-		}
-	    }
-
-	    not = (*p == '!' || *p == '^');
-	    if (not)
-	      ++p;
-
-	    c = *p++;
-	    while (1)
-	      {
-		register char cstart = c, cend = c;
-
-		if (!(flags & FNM_NOESCAPE) && c == '\\')
-		  cstart = cend = *p++;
-
-		if (c == '\0')
-		  /* [ (unterminated) loses.  */
-		  return (FNM_NOMATCH);
-
-		c = *p++;
-
-		if ((flags & FNM_PATHNAME) && c == '/')
-		  /* [/] can never match.  */
-		  return (FNM_NOMATCH);
-
-		if (c == '-' && *p != ']')
-		  {
-		    cend = *p++;
-		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
-		      cend = *p++;
-		    if (cend == '\0')
-		      return (FNM_NOMATCH);
-		    c = *p++;
-		  }
-
-		if (*n >= cstart && *n <= cend)
-		  goto matched;
-
-		if (c == ']')
-		  break;
-	      }
-	    if (!not)
-	      return (FNM_NOMATCH);
-
-	  next_char:
-	    break;
-
-	  matched:
-	    /* Skip the rest of the [...] that already matched.  */
-	    while (c != ']')
-	      {
-		if (c == '\0')
-		  /* [... (unterminated) loses.  */
-		  return (FNM_NOMATCH);
-
-		c = *p++;
-		if (!(flags & FNM_NOESCAPE) && c == '\\')
-		  /* 1003.2d11 is unclear if this is right.  %%% */
-		  ++p;
-	      }
-	    if (not)
-	      return (FNM_NOMATCH);
-	  }
-	  break;
-
-	default:
-	  if (c != *n)
-	    return (FNM_NOMATCH);
-	}
-
-      ++n;
-    }
-
-  if (*n == '\0')
-    return (0);
-
-  return (FNM_NOMATCH);
-}
-
-/* Return non-zero if S has a leading '/'  or contains '../' */
-int
-has_insecure_name_p (const char *s)
-{
-  if (*s == '/')
-    return 1;
-
-  if (strstr(s, "../") != 0)
-    return 1;
-
-  return 0;
-}
-
-/* Return non-zero if S contains globbing wildcards (`*', `?', `[' or
-   `]').  */
-int
-has_wildcards_p (const char *s)
-{
-  for (; *s; s++)
-    if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
-      return 1;
-  return 0;
-}
diff --git a/src/fnmatch.h b/src/fnmatch.h
deleted file mode 100644
index a3449aaa..00000000
--- a/src/fnmatch.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Declarations for fnmatch.c.
-   Copyright (C) 1991, 1995, 1996 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 FNMATCH_H
-#define FNMATCH_H
-
-/* Bits set in the FLAGS argument to `fnmatch'.  */
-#define	FNM_PATHNAME	(1 << 0) /* No wildcard can ever match `/'.  */
-#define	FNM_NOESCAPE	(1 << 1) /* Backslashes don't quote special chars.  */
-#define	FNM_PERIOD	(1 << 2) /* Leading `.' is matched only explicitly.  */
-#define	__FNM_FLAGS	(FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD)
-
-/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
-#define	FNM_NOMATCH	1
-
-int fnmatch PARAMS ((const char *, const char *, int));
-int has_insecure_name_p PARAMS ((const char *s));
-int has_wildcards_p PARAMS ((const char *));
-
-#endif /* FNMATCH_H */
diff --git a/src/ftp.c b/src/ftp.c
index d99ddb71..5061d9cf 100644
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -52,7 +52,6 @@ so, delete this exception statement from your version.  */
 #include "ftp.h"
 #include "connect.h"
 #include "host.h"
-#include "fnmatch.h"
 #include "netrc.h"
 #include "convert.h"		/* for downloaded_file */
 
@@ -1593,6 +1592,18 @@ Not descending to `%s' as it is excluded/not-included.\n"), newdir);
     return RETROK;
 }
 
+/* Return non-zero if S has a leading '/'  or contains '../' */
+static int
+has_insecure_name_p (const char *s)
+{
+  if (*s == '/')
+    return 1;
+
+  if (strstr(s, "../") != 0)
+    return 1;
+
+  return 0;
+}
 
 /* A near-top-level function to retrieve the files in a directory.
    The function calls ftp_get_listing, to get a linked list of files.
@@ -1634,7 +1645,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
   f = orig;
   while (f)
     {
-      if (has_insecure_name_p(f->name))
+      if (has_insecure_name_p (f->name))
 	{
 	  logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name);
 	  f = delelement (f, &start);
diff --git a/src/http.c b/src/http.c
index 92043a57..cd48d9b9 100644
--- a/src/http.c
+++ b/src/http.c
@@ -62,7 +62,6 @@ so, delete this exception statement from your version.  */
 #include "retr.h"
 #include "headers.h"
 #include "connect.h"
-#include "fnmatch.h"
 #include "netrc.h"
 #ifdef HAVE_SSL
 # include "gen_sslfunc.h"
diff --git a/src/recur.c b/src/recur.c
index 9a9e8ba1..007354b7 100644
--- a/src/recur.c
+++ b/src/recur.c
@@ -49,7 +49,6 @@ so, delete this exception statement from your version.  */
 #include "utils.h"
 #include "retr.h"
 #include "ftp.h"
-#include "fnmatch.h"
 #include "host.h"
 #include "hash.h"
 #include "res.h"
diff --git a/src/sysdep.h b/src/sysdep.h
index c47a243f..a42cfa8a 100644
--- a/src/sysdep.h
+++ b/src/sysdep.h
@@ -182,8 +182,9 @@ void *memmove ();
 #endif
 
 /* SunOS brain damage -- for some reason, SunOS header files fail to
-   declare the functions below, which causes all kinds of problems
-   (compiling errors) with pointer arithmetic and similar.
+   declare the functions below, which causes all kinds of problems,
+   most notably compilation errors when using pointer arithmetic on
+   their return values.
 
    This used to be only within `#ifdef STDC_HEADERS', but it got
    tripped on other systems (AIX), thus causing havoc.  Fortunately,
@@ -191,16 +192,16 @@ void *memmove ();
    added an extra `#ifdef sun' guard.  */
 #ifndef STDC_HEADERS
 #ifdef sun
-#ifndef __cplusplus
+#ifndef __SVR4			/* exclude Solaris */
 char *strstr ();
 char *strchr ();
 char *strrchr ();
 char *strtok ();
 char *strdup ();
 void *memcpy ();
-#endif /* not __cplusplus */
+#endif /* not __SVR4 */
 #endif /* sun */
-#endif /* STDC_HEADERS */
+#endif /* not STDC_HEADERS */
 
 /* Some systems (Linux libc5, "NCR MP-RAS 3.0", and others) don't
    provide MAP_FAILED, a symbolic constant for the value returned by
@@ -212,4 +213,34 @@ void *memcpy ();
 # define MAP_FAILED ((void *) -1)
 #endif
 
+/* Enable system fnmatch only on systems where we know it works:
+   currently glibc-based systems and Solaris.  One could add more, but
+   fnmatch is not that large, so it might be better to play it
+   safe.  */
+#if defined __GLIBC__ && __GLIBC__ >= 2
+# define SYSTEM_FNMATCH
+#endif
+#ifdef solaris
+# define SYSTEM_FNMATCH
+#endif
+
+#ifdef SYSTEM_FNMATCH
+# include <fnmatch.h>
+#else  /* not SYSTEM_FNMATCH */
+/* Define fnmatch flags.  Undef them first to avoid warnings in case
+   an evil library include chose to include system fnmatch.h.  */
+# undef FNM_PATHNAME
+# undef FNM_NOESCAPE
+# undef FNM_PERIOD
+# undef FNM_NOMATCH
+
+# define FNM_PATHNAME	(1 << 0) /* No wildcard can ever match `/'.  */
+# define FNM_NOESCAPE	(1 << 1) /* Backslashes don't quote special chars.  */
+# define FNM_PERIOD	(1 << 2) /* Leading `.' is matched only explicitly.  */
+# define FNM_NOMATCH	1
+
+/* Declare the function minimally. */
+int fnmatch ();
+#endif
+
 #endif /* SYSDEP_H */
diff --git a/src/utils.c b/src/utils.c
index b563d40a..c78b1708 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -92,7 +92,6 @@ so, delete this exception statement from your version.  */
 
 #include "wget.h"
 #include "utils.h"
-#include "fnmatch.h"
 #include "hash.h"
 
 #ifndef errno
@@ -874,6 +873,18 @@ suffix (const char *str)
     return NULL;
 }
 
+/* Return non-zero if S contains globbing wildcards (`*', `?', `[' or
+   `]').  */
+
+int
+has_wildcards_p (const char *s)
+{
+  for (; *s; s++)
+    if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
+      return 1;
+  return 0;
+}
+
 /* Return non-zero if FNAME ends with a typical HTML suffix.  The
    following (case-insensitive) suffixes are presumed to be HTML files:
    
diff --git a/src/utils.h b/src/utils.h
index 0783602d..01a1d3de 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -80,6 +80,7 @@ int acceptable PARAMS ((const char *));
 int accdir PARAMS ((const char *s, enum accd));
 char *suffix PARAMS ((const char *s));
 int match_tail PARAMS ((const char *, const char *, int));
+int has_wildcards_p PARAMS ((const char *));
 
 int has_html_suffix_p PARAMS ((const char *));