implement FNM_CASEFOLD extension to fnmatch function
authorNagy Szabolcs <nsz@port70.net>
Fri, 10 Oct 2014 10:09:03 +0000 (12:09 +0200)
committerRich Felker <dalias@aerifal.cx>
Wed, 17 Dec 2014 19:54:37 +0000 (14:54 -0500)
src/regex/fnmatch.c

index 4df10a3c0675c30acdafcc98b29dc41ce888a32d..7f6b65f32e399c09a67579d3eddbcf7dff1a0105 100644 (file)
@@ -97,7 +97,13 @@ escaped:
        return pat[0];
 }
 
-static int match_bracket(const char *p, int k)
+static int casefold(int k)
+{
+       int c = towupper(k);
+       return c == k ? towlower(k) : c;
+}
+
+static int match_bracket(const char *p, int k, int kfold)
 {
        wchar_t wc;
        int inv = 0;
@@ -119,7 +125,10 @@ static int match_bracket(const char *p, int k)
                        wchar_t wc2;
                        int l = mbtowc(&wc2, p+1, 4);
                        if (l < 0) return 0;
-                       if (wc<=wc2 && (unsigned)k-wc <= wc2-wc) return !inv;
+                       if (wc <= wc2)
+                               if ((unsigned)k-wc <= wc2-wc ||
+                                   (unsigned)kfold-wc <= wc2-wc)
+                                       return !inv;
                        p += l-1;
                        continue;
                }
@@ -132,7 +141,9 @@ static int match_bracket(const char *p, int k)
                                char buf[16];
                                memcpy(buf, p0, p-1-p0);
                                buf[p-1-p0] = 0;
-                               if (iswctype(k, wctype(buf))) return !inv;
+                               if (iswctype(k, wctype(buf)) ||
+                                   iswctype(kfold, wctype(buf)))
+                                       return !inv;
                        }
                        continue;
                }
@@ -143,7 +154,7 @@ static int match_bracket(const char *p, int k)
                        if (l < 0) return 0;
                        p += l-1;
                }
-               if (wc==k) return !inv;
+               if (wc==k || wc==kfold) return !inv;
        }
        return inv;
 }
@@ -153,7 +164,7 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n
        const char *p, *ptail, *endpat;
        const char *s, *stail, *endstr;
        size_t pinc, sinc, tailcnt=0;
-       int c, k;
+       int c, k, kfold;
 
        if (flags & FNM_PERIOD) {
                if (*str == '.' && *pat != '.')
@@ -173,10 +184,11 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n
                                return (c==END) ? 0 : FNM_NOMATCH;
                        str += sinc;
                        n -= sinc;
+                       kfold = flags & FNM_CASEFOLD ? casefold(k) : k;
                        if (c == BRACKET) {
-                               if (!match_bracket(pat, k))
+                               if (!match_bracket(pat, k, kfold))
                                        return FNM_NOMATCH;
-                       } else if (c != QUESTION && k != c) {
+                       } else if (c != QUESTION && k != c && kfold != c) {
                                return FNM_NOMATCH;
                        }
                        pat+=pinc;
@@ -233,10 +245,11 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n
                        break;
                }
                s += sinc;
+               kfold = flags & FNM_CASEFOLD ? casefold(k) : k;
                if (c == BRACKET) {
-                       if (!match_bracket(p-pinc, k))
+                       if (!match_bracket(p-pinc, k, kfold))
                                return FNM_NOMATCH;
-               } else if (c != QUESTION && k != c) {
+               } else if (c != QUESTION && k != c && kfold != c) {
                        return FNM_NOMATCH;
                }
        }
@@ -261,10 +274,11 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n
                        k = str_next(s, endstr-s, &sinc);
                        if (!k)
                                return FNM_NOMATCH;
+                       kfold = flags & FNM_CASEFOLD ? casefold(k) : k;
                        if (c == BRACKET) {
-                               if (!match_bracket(p-pinc, k))
+                               if (!match_bracket(p-pinc, k, kfold))
                                        break;
-                       } else if (c != QUESTION && k != c) {
+                       } else if (c != QUESTION && k != c && kfold != c) {
                                break;
                        }
                        s += sinc;