New option --ignore-case
Hrvoje Niksic <[email protected]> Wed, 06 Jul 2005 21:43:32 +0200
| Newsgroups | gmane.comp.web.wget.patches |
|---|---|
| Message-ID | <[email protected]> |
This seems to be very frequently requested and is not that hard to implement: an option that makes file and directory matching case-insensitive. This affects options -X, -I, -A, -R, and the ftp globbing code. If I've missed something, please let me know. 2005-07-06 Hrvoje Niksic <[email protected]> * 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. Index: src/options.h =================================================================== --- src/options.h (revision 1958) +++ src/options.h (working copy) @@ -66,6 +66,8 @@ 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; Index: src/utils.c =================================================================== --- src/utils.c (revision 1967) +++ src/utils.c (working copy) @@ -615,6 +615,28 @@ 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 @@ } /* 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 @@ /* 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 @@ { 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; } } Index: src/init.c =================================================================== --- src/init.c (revision 1958) +++ src/init.c (working copy) @@ -163,6 +163,7 @@ { "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 }, Index: src/utils.h =================================================================== --- src/utils.h (revision 1958) +++ src/utils.h (working copy) @@ -30,10 +30,6 @@ #ifndef UTILS_H #define UTILS_H -enum accd { - ALLABS = 1 -}; - struct hash_table; struct file_memory { @@ -72,8 +68,9 @@ 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 *); Index: src/ftp.c =================================================================== --- src/ftp.c (revision 1958) +++ src/ftp.c (working copy) @@ -1621,7 +1621,7 @@ 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 @@ 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, Index: src/config-post.h =================================================================== --- src/config-post.h (revision 1963) +++ src/config-post.h (working copy) @@ -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 */ Index: src/recur.c =================================================================== --- src/recur.c (revision 1958) +++ src/recur.c (working copy) @@ -495,7 +495,7 @@ 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; Index: src/main.c =================================================================== --- src/main.c (revision 1990) +++ src/main.c (working copy) @@ -174,6 +174,7 @@ { "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 @@ --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"), Index: NEWS =================================================================== --- NEWS (revision 1991) +++ NEWS (working copy) @@ -7,6 +7,10 @@ * 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.)