[svn] New option --ignore-case for case-insensitive matching.

This commit is contained in:
hniksic 2005-07-06 12:44:00 -07:00
parent 854db53e84
commit 097695b723
10 changed files with 82 additions and 26 deletions

4
NEWS
View File

@ -7,6 +7,10 @@ Please send GNU Wget bug reports to <bug-wget@gnu.org>.
* 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.)

View File

@ -1,3 +1,13 @@
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.

View File

@ -47,6 +47,11 @@
#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 */

View File

@ -1621,7 +1621,7 @@ ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
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"),
@ -1714,12 +1714,14 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
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,

View File

@ -163,6 +163,7 @@ static struct {
{ "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 },

View File

@ -174,6 +174,7 @@ static struct cmdline_option option_data[] =
{ "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 },
@ -446,6 +447,8 @@ Download:\n"),
--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"),

View File

@ -66,6 +66,8 @@ struct options
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;

View File

@ -495,7 +495,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
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;

View File

@ -615,6 +615,28 @@ file_merge (const char *base, const char *file)
return result;
}
/* 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
@ -642,28 +664,34 @@ acceptable (const char *s)
}
/* 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
@ -678,22 +706,23 @@ proclist (char **strlist, const char *s, enum accd flags)
/* 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;
@ -748,21 +777,24 @@ in_acclist (const char *const *accepts, const char *s, bool backward)
{
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;
}
}

View File

@ -30,10 +30,6 @@ so, delete this exception statement from your version. */
#ifndef UTILS_H
#define UTILS_H
enum accd {
ALLABS = 1
};
struct hash_table;
struct file_memory {
@ -72,8 +68,9 @@ FILE *unique_create (const char *, bool, char **);
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 *);