00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <u/fnmatch.h>
00041
00042 #include <assert.h>
00043 #include <ctype.h>
00044 #include <string.h>
00045
00046 #define EOS '\0'
00047
00048 static const char *rangematch(const char *, int, int);
00049
00050 static inline int
00051 foldcase(int ch, int flags)
00052 {
00053
00054 if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
00055 return (tolower(ch));
00056 return (ch);
00057 }
00058
00059 #define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags))
00060
00061 int
00062 fnmatch(pattern, string, flags)
00063 const char *pattern, *string;
00064 int flags;
00065 {
00066 const char *stringstart;
00067 char c, test;
00068
00069 for (stringstart = string;;)
00070 switch (c = FOLDCASE(*pattern++, flags)) {
00071 case EOS:
00072 if ((flags & FNM_LEADING_DIR) && *string == '/')
00073 return (0);
00074 return (*string == EOS ? 0 : FNM_NOMATCH);
00075 case '?':
00076 if (*string == EOS)
00077 return (FNM_NOMATCH);
00078 if (*string == '/' && (flags & FNM_PATHNAME))
00079 return (FNM_NOMATCH);
00080 if (*string == '.' && (flags & FNM_PERIOD) &&
00081 (string == stringstart ||
00082 ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
00083 return (FNM_NOMATCH);
00084 ++string;
00085 break;
00086 case '*':
00087 c = FOLDCASE(*pattern, flags);
00088
00089 while (c == '*')
00090 c = FOLDCASE(*++pattern, flags);
00091
00092 if (*string == '.' && (flags & FNM_PERIOD) &&
00093 (string == stringstart ||
00094 ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
00095 return (FNM_NOMATCH);
00096
00097
00098 if (c == EOS) {
00099 if (flags & FNM_PATHNAME)
00100 return ((flags & FNM_LEADING_DIR) ||
00101 strchr(string, '/') == NULL ?
00102 0 : FNM_NOMATCH);
00103 else
00104 return (0);
00105 } else if (c == '/' && flags & FNM_PATHNAME) {
00106 if ((string = strchr(string, '/')) == NULL)
00107 return (FNM_NOMATCH);
00108 break;
00109 }
00110
00111
00112 while ((test = FOLDCASE(*string, flags)) != EOS) {
00113 if (!fnmatch(pattern, string,
00114 flags & ~FNM_PERIOD))
00115 return (0);
00116 if (test == '/' && flags & FNM_PATHNAME)
00117 break;
00118 ++string;
00119 }
00120 return (FNM_NOMATCH);
00121 case '[':
00122 if (*string == EOS)
00123 return (FNM_NOMATCH);
00124 if (*string == '/' && flags & FNM_PATHNAME)
00125 return (FNM_NOMATCH);
00126 if ((pattern =
00127 rangematch(pattern, FOLDCASE(*string, flags),
00128 flags)) == NULL)
00129 return (FNM_NOMATCH);
00130 ++string;
00131 break;
00132 case '\\':
00133 if (!(flags & FNM_NOESCAPE)) {
00134 if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
00135 c = '\\';
00136 --pattern;
00137 }
00138 }
00139
00140 default:
00141 if (c != FOLDCASE(*string++, flags))
00142 return (FNM_NOMATCH);
00143 break;
00144 }
00145
00146 }
00147
00148 static const char *
00149 rangematch(pattern, test, flags)
00150 const char *pattern;
00151 int test, flags;
00152 {
00153 int negate, ok;
00154 char c, c2;
00155
00156
00157
00158
00159
00160
00161
00162
00163 if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
00164 ++pattern;
00165
00166 for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
00167 if (c == '\\' && !(flags & FNM_NOESCAPE))
00168 c = FOLDCASE(*pattern++, flags);
00169 if (c == EOS)
00170 return (NULL);
00171 if (*pattern == '-'
00172 && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
00173 c2 != ']') {
00174 pattern += 2;
00175 if (c2 == '\\' && !(flags & FNM_NOESCAPE))
00176 c2 = FOLDCASE(*pattern++, flags);
00177 if (c2 == EOS)
00178 return (NULL);
00179 if (c <= test && test <= c2)
00180 ok = 1;
00181 } else if (c == test)
00182 ok = 1;
00183 }
00184 return (ok == negate ? NULL : pattern);
00185 }