summaryrefslogtreecommitdiff
path: root/ext/File/Glob/bsd_glob.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/File/Glob/bsd_glob.c')
-rw-r--r--ext/File/Glob/bsd_glob.c93
1 files changed, 81 insertions, 12 deletions
diff --git a/ext/File/Glob/bsd_glob.c b/ext/File/Glob/bsd_glob.c
index f42b689cd7..c422d608bd 100644
--- a/ext/File/Glob/bsd_glob.c
+++ b/ext/File/Glob/bsd_glob.c
@@ -91,6 +91,9 @@ static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
#define BG_RANGE '-'
#define BG_RBRACKET ']'
#define BG_SEP '/'
+#ifdef DOSISH
+#define BG_SEP2 '\\'
+#endif
#define BG_STAR '*'
#define BG_TILDE '~'
#define BG_UNDERSCORE '_'
@@ -132,6 +135,7 @@ typedef U8 Char;
static int compare(const void *, const void *);
+static int ci_compare(const void *, const void *);
static void g_Ctoc(const Char *, char *);
static int g_lstat(Char *, Stat_t *, glob_t *);
static DIR *g_opendir(Char *, glob_t *);
@@ -148,7 +152,7 @@ static int globextend(const Char *, glob_t *);
static const Char * globtilde(const Char *, Char *, glob_t *);
static int globexp1(const Char *, glob_t *);
static int globexp2(const Char *, const Char *, glob_t *, int *);
-static int match(Char *, Char *, Char *);
+static int match(Char *, Char *, Char *, int);
#ifdef GLOB_DEBUG
static void qprintf(const char *, Char *);
#endif /* GLOB_DEBUG */
@@ -186,11 +190,41 @@ bsd_glob(const char *pattern, int flags,
bufnext = patbuf;
bufend = bufnext + MAXPATHLEN;
+#ifdef DOSISH
+ /* Nasty hack to treat patterns like "C:*" correctly. In this
+ * case, the * should match any file in the current directory
+ * on the C: drive. However, the glob code does not treat the
+ * colon specially, so it looks for files beginning "C:" in
+ * the current directory. To fix this, change the pattern to
+ * add an explicit "./" at the start (just after the drive
+ * letter and colon - ie change to "C:./*").
+ */
+ if (isalpha(pattern[0]) && pattern[1] == ':' &&
+ pattern[2] != BG_SEP && pattern[2] != BG_SEP2 &&
+ bufend - bufnext > 4) {
+ *bufnext++ = pattern[0];
+ *bufnext++ = ':';
+ *bufnext++ = '.';
+ *bufnext++ = BG_SEP;
+ patnext += 2;
+ }
+#endif
if (flags & GLOB_QUOTE) {
/* Protect the quoted characters. */
while (bufnext < bufend && (c = *patnext++) != BG_EOS)
if (c == BG_QUOTE) {
+#ifdef DOSISH
+ /* To avoid backslashitis on Win32,
+ * we only treat \ as a quoting character
+ * if it precedes one of the
+ * metacharacters []-{}~\
+ */
+ if ((c = *patnext++) != '[' && c != ']' &&
+ c != '-' && c != '{' && c != '}' &&
+ c != '~' && c != '\\') {
+#else
if ((c = *patnext++) == BG_EOS) {
+#endif
c = BG_QUOTE;
--patnext;
}
@@ -496,12 +530,27 @@ glob0(const Char *pattern, glob_t *pglob)
}
else if (!(pglob->gl_flags & GLOB_NOSORT))
qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
- pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+ pglob->gl_pathc - oldpathc, sizeof(char *),
+ (pglob->gl_flags & GLOB_NOCASE) ? ci_compare : compare);
pglob->gl_flags = oldflags;
return(0);
}
static int
+ci_compare(const void *p, const void *q)
+{
+ const char *pp = *(const char **)p;
+ const char *qq = *(const char **)q;
+ while (*pp && *qq) {
+ if (tolower(*pp) != tolower(*qq))
+ break;
+ ++pp;
+ ++qq;
+ }
+ return (tolower(*pp) - tolower(*qq));
+}
+
+static int
compare(const void *p, const void *q)
{
return(strcmp(*(char **)p, *(char **)q));
@@ -542,7 +591,11 @@ glob2(Char *pathbuf, Char *pathend, Char *pattern, glob_t *pglob)
return(0);
if (((pglob->gl_flags & GLOB_MARK) &&
- pathend[-1] != BG_SEP) && (S_ISDIR(sb.st_mode)
+ pathend[-1] != BG_SEP
+#ifdef DOSISH
+ && pathend[-1] != BG_SEP2
+#endif
+ ) && (S_ISDIR(sb.st_mode)
|| (S_ISLNK(sb.st_mode) &&
(g_stat(pathbuf, &sb, pglob) == 0) &&
S_ISDIR(sb.st_mode)))) {
@@ -559,7 +612,11 @@ glob2(Char *pathbuf, Char *pathend, Char *pattern, glob_t *pglob)
/* Find end of next segment, copy tentatively to pathend. */
q = pathend;
p = pattern;
- while (*p != BG_EOS && *p != BG_SEP) {
+ while (*p != BG_EOS && *p != BG_SEP
+#ifdef DOSISH
+ && *p != BG_SEP2
+#endif
+ ) {
if (ismeta(*p))
anymeta = 1;
*q++ = *p++;
@@ -568,7 +625,11 @@ glob2(Char *pathbuf, Char *pathend, Char *pattern, glob_t *pglob)
if (!anymeta) { /* No expansion, do next segment. */
pathend = q;
pattern = p;
- while (*pattern == BG_SEP)
+ while (*pattern == BG_SEP
+#ifdef DOSISH
+ || *pattern == BG_SEP2
+#endif
+ )
*pathend++ = *pattern++;
} else /* Need expansion, recurse. */
return(glob3(pathbuf, pathend, pattern, p, pglob));
@@ -583,6 +644,7 @@ glob3(Char *pathbuf, Char *pathend, Char *pattern,
register Direntry_t *dp;
DIR *dirp;
int err;
+ int nocase;
char buf[MAXPATHLEN];
/*
@@ -608,6 +670,7 @@ glob3(Char *pathbuf, Char *pathend, Char *pattern,
}
err = 0;
+ nocase = ((pglob->gl_flags & GLOB_NOCASE) != 0);
/* Search directory for matching names. */
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
@@ -624,7 +687,7 @@ glob3(Char *pathbuf, Char *pathend, Char *pattern,
for (sc = (U8 *) dp->d_name, dc = pathend;
(*dc++ = *sc++) != BG_EOS;)
continue;
- if (!match(pathend, pattern, restpattern)) {
+ if (!match(pathend, pattern, restpattern, nocase)) {
*pathend = BG_EOS;
continue;
}
@@ -703,7 +766,7 @@ globextend(const Char *path, glob_t *pglob)
* pattern causes a recursion level.
*/
static int
-match(register Char *name, register Char *pat, register Char *patend)
+match(register Char *name, register Char *pat, register Char *patend, int nocase)
{
int ok, negate_range;
Char c, k;
@@ -715,7 +778,7 @@ match(register Char *name, register Char *pat, register Char *patend)
if (pat == patend)
return(1);
do
- if (match(name, pat, patend))
+ if (match(name, pat, patend, nocase))
return(1);
while (*name++ != BG_EOS);
return(0);
@@ -731,16 +794,22 @@ match(register Char *name, register Char *pat, register Char *patend)
++pat;
while (((c = *pat++) & M_MASK) != M_END)
if ((*pat & M_MASK) == M_RNG) {
- if (c <= k && k <= pat[1])
- ok = 1;
+ if (nocase) {
+ if (tolower(c) <= tolower(k) && tolower(k) <= tolower(pat[1]))
+ ok = 1;
+ } else {
+ if (c <= k && k <= pat[1])
+ ok = 1;
+ }
pat += 2;
- } else if (c == k)
+ } else if (nocase ? (tolower(c) == tolower(k)) : (c == k))
ok = 1;
if (ok == negate_range)
return(0);
break;
default:
- if (*name++ != c)
+ k = *name++;
+ if (nocase ? (tolower(k) != tolower(c)) : (k != c))
return(0);
break;
}