\f
* Changes in Wget 1.11.
+** The new function `--ignore-case' makes Wget ignore case when
+matching files, directories, and wildcards. This affects the -X, -I,
+-A, and -R options, as well as globbing in FTP URLs.
+
** ETA projection is now displayed in "dot" progress output as well as
in the default progress bar. (The dot progress is used by default when
logging Wget's output to file using the `-o' option.)
+2005-07-06 Hrvoje Niksic <hniksic@xemacs.org>
+
+ * utils.c (fnmatch_nocase): New function.
+ (proclist): Use it instead of fnmatch when opt.ignore_case is
+ requested.
+ (in_acclist): Respect opt.ignore_case.
+ (frontcmp): Respect opt.ignore_case.
+
+ * options.h (struct options): New flag opt.ignore_case.
+
2005-07-06 Hrvoje Niksic <hniksic@xemacs.org>
* ptimer.c: Measure time in seconds rather than milliseconds.
#define _SVID_SOURCE
#define _BSD_SOURCE
+/* Under glibc-based systems we want all GNU extensions as well. This
+ declares some unnecessary cruft, but also useful functions such as
+ timegm, FNM_CASEFOLD extension to fnmatch, memrchr, etc. */
+#define _GNU_SOURCE
+
#endif /* NAMESPACE_TWEAKS */
DEBUGP (("Composing new CWD relative to the initial directory.\n"));
DEBUGP ((" odir = '%s'\n f->name = '%s'\n newdir = '%s'\n\n",
odir, f->name, newdir));
- if (!accdir (newdir, ALLABS))
+ if (!accdir (newdir))
{
logprintf (LOG_VERBOSE, _("\
Not descending to `%s' as it is excluded/not-included.\n"),
If we are dealing with a globbing pattern, that is. */
if (*u->file && (action == GLOB_GLOBALL || action == GLOB_GETONE))
{
+ int (*matcher) (const char *, const char *, int)
+ = opt.ignore_case ? fnmatch_nocase : fnmatch;
int matchres = 0;
f = start;
while (f)
{
- matchres = fnmatch (u->file, f->name, 0);
+ matchres = matcher (u->file, f->name, 0);
if (matchres == -1)
{
logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
{ "httpproxy", &opt.http_proxy, cmd_string },
{ "httpsproxy", &opt.https_proxy, cmd_string },
{ "httpuser", &opt.http_user, cmd_string },
+ { "ignorecase", &opt.ignore_case, cmd_boolean },
{ "ignorelength", &opt.ignore_length, cmd_boolean },
{ "ignoretags", &opt.ignore_tags, cmd_vector },
{ "includedirectories", &opt.includes, cmd_directory_vector },
{ "http-passwd", 0, OPT_VALUE, "httppassword", -1 }, /* deprecated */
{ "http-password", 0, OPT_VALUE, "httppassword", -1 },
{ "http-user", 0, OPT_VALUE, "httpuser", -1 },
+ { "ignore-case", 0, OPT_BOOLEAN, "ignorecase", -1 },
{ "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
{ "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
{ "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
--no-dns-cache disable caching DNS lookups.\n"),
N_("\
--restrict-file-names=OS restrict chars in file names to ones OS allows.\n"),
+ N_("\
+ --ignore-case ignore case when matching files/directories.\n"),
#ifdef ENABLE_IPV6
N_("\
-4, --inet4-only connect only to IPv4 addresses.\n"),
char **excludes; /* List of excluded FTP directories. */
char **includes; /* List of FTP directories to
follow. */
+ bool ignore_case; /* Whether to ignore case when
+ matching dirs and files */
char **domains; /* See host.c */
char **exclude_domains;
exclusion and inclusion lists. */
if (opt.includes || opt.excludes)
{
- if (!accdir (u->dir, ALLABS))
+ if (!accdir (u->dir))
{
DEBUGP (("%s (%s) is excluded/not-included.\n", url, u->dir));
goto out;
return result;
}
\f
+/* Like fnmatch, but performs a lower-case comparison. */
+
+int
+fnmatch_nocase (const char *pattern, const char *string, int flags)
+{
+#ifdef FNM_CASEFOLD
+ return fnmatch (pattern, string, flags | FNM_CASEFOLD);
+#else
+ /* Turn PATTERN and STRING to lower case and call fnmatch on them. */
+ char *patcopy = (char *) alloca (strlen (pattern) + 1);
+ char *strcopy = (char *) alloca (strlen (string) + 1);
+ char *p;
+ for (p = patcopy; *pattern; pattern++, p++)
+ *p = TOLOWER (*pattern);
+ *p = '\0';
+ for (p = strcopy; *string; string++, p++)
+ *p = TOLOWER (*string);
+ *p = '\0';
+ return fnmatch (patcopy, strcopy, flags);
+#endif
+}
+
static bool in_acclist (const char *const *, const char *, bool);
/* Determine whether a file is acceptable to be followed, according to
}
/* Compare S1 and S2 frontally; S2 must begin with S1. E.g. if S1 is
- `/something', frontcmp() will return 1 only if S2 begins with
- `/something'. Otherwise, 0 is returned. */
+ `/something', frontcmp() will return true only if S2 begins with
+ `/something'. */
bool
frontcmp (const char *s1, const char *s2)
{
- for (; *s1 && *s2 && (*s1 == *s2); ++s1, ++s2);
+ if (!opt.ignore_case)
+ for (; *s1 && *s2 && (*s1 == *s2); ++s1, ++s2);
+ else
+ for (; *s1 && *s2 && (TOLOWER (*s1) == TOLOWER (*s2)); ++s1, ++s2);
return *s1 == '\0';
}
/* Iterate through STRLIST, and return the first element that matches
S, through wildcards or front comparison (as appropriate). */
static char *
-proclist (char **strlist, const char *s, enum accd flags)
+proclist (char **strlist, const char *s)
{
char **x;
+ int (*matcher) (const char *, const char *, int)
+ = opt.ignore_case ? fnmatch_nocase : fnmatch;
+
for (x = strlist; *x; x++)
{
- /* Remove leading '/' if ALLABS */
- char *p = *x + ((flags & ALLABS) && (**x == '/'));
+ /* Remove leading '/' */
+ char *p = *x + (**x == '/');
if (has_wildcards_p (p))
{
- if (fnmatch (p, s, FNM_PATHNAME) == 0)
+ if (matcher (p, s, FNM_PATHNAME) == 0)
break;
}
else
/* Returns whether DIRECTORY is acceptable for download, wrt the
include/exclude lists.
- If FLAGS is ALLABS, the leading `/' is ignored in paths; relative
- and absolute paths may be freely intermixed. */
+ The leading `/' is ignored in paths; relative and absolute paths
+ may be freely intermixed. */
+
bool
-accdir (const char *directory, enum accd flags)
+accdir (const char *directory)
{
/* Remove starting '/'. */
- if (flags & ALLABS && *directory == '/')
+ if (*directory == '/')
++directory;
if (opt.includes)
{
- if (!proclist (opt.includes, directory, flags))
+ if (!proclist (opt.includes, directory))
return false;
}
if (opt.excludes)
{
- if (proclist (opt.excludes, directory, flags))
+ if (proclist (opt.excludes, directory))
return false;
}
return true;
{
if (has_wildcards_p (*accepts))
{
- /* fnmatch returns 0 if the pattern *does* match the
- string. */
- if (fnmatch (*accepts, s, 0) == 0)
+ int res = opt.ignore_case
+ ? fnmatch_nocase (*accepts, s, 0) : fnmatch (*accepts, s, 0);
+ /* fnmatch returns 0 if the pattern *does* match the string. */
+ if (res == 0)
return true;
}
else
{
if (backward)
{
- if (match_tail (s, *accepts, 0))
+ if (match_tail (s, *accepts, opt.ignore_case))
return true;
}
else
{
- if (!strcmp (s, *accepts))
+ int cmp = opt.ignore_case
+ ? strcasecmp (s, *accepts) : strcmp (s, *accepts);
+ if (cmp == 0)
return true;
}
}
#ifndef UTILS_H
#define UTILS_H
-enum accd {
- ALLABS = 1
-};
-
struct hash_table;
struct file_memory {
FILE *fopen_excl (const char *, bool);
char *file_merge (const char *, const char *);
+int fnmatch_nocase (const char *, const char *, int);
bool acceptable (const char *);
-bool accdir (const char *s, enum accd);
+bool accdir (const char *s);
char *suffix (const char *s);
bool match_tail (const char *, const char *, bool);
bool has_wildcards_p (const char *);