4848
4949#define EOS '\0'
5050
51+ #define MATCH_CLASS6 (p ,a ,b ,c ,d ,e ,f ,g ) \
52+ ((p)[0]==(a) && (p)[1]==(b) && (p)[2]==(c) && (p)[3]==(d) && (p)[4]==(e) && (p)[5]==(f) && (p)[6]==(g))
53+
54+ #define MATCH_CLASS7 (p ,a ,b ,c ,d ,e ,f ,g ,h ) \
55+ ((p)[0]==(a) && (p)[1]==(b) && (p)[2]==(c) && (p)[3]==(d) && (p)[4]==(e) && (p)[5]==(f) && (p)[6]==(g) && (p)[7]==(h))
56+
57+ enum fnm_char_class {
58+ FNM_CC_ALNUM ,
59+ FNM_CC_ALPHA ,
60+ FNM_CC_BLANK ,
61+ FNM_CC_CNTRL ,
62+ FNM_CC_DIGIT ,
63+ FNM_CC_GRAPH ,
64+ FNM_CC_LOWER ,
65+ FNM_CC_PRINT ,
66+ FNM_CC_PUNCT ,
67+ FNM_CC_SPACE ,
68+ FNM_CC_UPPER ,
69+ FNM_CC_XDIGIT ,
70+ FNM_CC_INVALID ,
71+ };
72+
73+ static bool fnm_cc_is_valid (const char * pattern , size_t psize , enum fnm_char_class * cc )
74+ {
75+ if (psize < 4 || * pattern != ':' )
76+ return false;
77+
78+ pattern ++ ; /* skip ':' */
79+ psize -- ;
80+
81+ /* Each class name ends with ":]" */
82+ switch (pattern [0 ]) {
83+ case 'a' :
84+ if (MATCH_CLASS6 (pattern ,'a' ,'l' ,'n' ,'u' ,'m' ,':' ,']' )) {
85+ * cc = FNM_CC_ALNUM ;
86+ return true;
87+ }
88+ if (MATCH_CLASS6 (pattern ,'a' ,'l' ,'p' ,'h' ,'a' ,':' ,']' )) {
89+ * cc = FNM_CC_ALPHA ;
90+ return true;
91+ }
92+ break ;
93+
94+ case 'b' :
95+ if (MATCH_CLASS6 (pattern ,'b' ,'l' ,'a' ,'n' ,'k' ,':' ,']' )) {
96+ * cc = FNM_CC_BLANK ;
97+ return true;
98+ }
99+ break ;
100+
101+ case 'c' :
102+ if (MATCH_CLASS6 (pattern ,'c' ,'n' ,'t' ,'r' ,'l' ,':' ,']' )) {
103+ * cc = FNM_CC_CNTRL ;
104+ return true;
105+ }
106+ break ;
107+
108+ case 'd' :
109+ if (MATCH_CLASS6 (pattern ,'d' ,'i' ,'g' ,'i' ,'t' ,':' ,']' )) {
110+ * cc = FNM_CC_DIGIT ;
111+ return true;
112+ }
113+ break ;
114+
115+ case 'g' :
116+ if (MATCH_CLASS6 (pattern ,'g' ,'r' ,'a' ,'p' ,'h' ,':' ,']' )) {
117+ * cc = FNM_CC_GRAPH ;
118+ return true;
119+ }
120+ break ;
121+
122+ case 'l' :
123+ if (MATCH_CLASS6 (pattern ,'l' ,'o' ,'w' ,'e' ,'r' ,':' ,']' )) {
124+ * cc = FNM_CC_LOWER ;
125+ return true;
126+ }
127+ break ;
128+
129+ case 'p' :
130+ if (MATCH_CLASS6 (pattern ,'p' ,'r' ,'i' ,'n' ,'t' ,':' ,']' )) {
131+ * cc = FNM_CC_PRINT ;
132+ return true;
133+ }
134+ if (MATCH_CLASS6 (pattern ,'p' ,'u' ,'n' ,'c' ,'t' ,':' ,']' )) {
135+ * cc = FNM_CC_PUNCT ;
136+ return true;
137+ }
138+ break ;
139+
140+ case 's' :
141+ if (MATCH_CLASS6 (pattern ,'s' ,'p' ,'a' ,'c' ,'e' ,':' ,']' )) {
142+ * cc = FNM_CC_SPACE ;
143+ return true;
144+ }
145+ break ;
146+
147+ case 'u' :
148+ if (MATCH_CLASS6 (pattern ,'u' ,'p' ,'p' ,'e' ,'r' ,':' ,']' )) {
149+ * cc = FNM_CC_UPPER ;
150+ return true;
151+ }
152+ break ;
153+
154+ case 'x' :
155+ if (MATCH_CLASS7 (pattern ,'x' ,'d' ,'i' ,'g' ,'i' ,'t' ,':' ,']' )) {
156+ * cc = FNM_CC_XDIGIT ;
157+ return true;
158+ }
159+ break ;
160+
161+ default :
162+ break ;
163+ }
164+
165+ return false;
166+ }
167+
168+ static inline int fnm_cc_match (int c , enum fnm_char_class cc )
169+ {
170+ switch (cc ) {
171+ case FNM_CC_ALNUM : return isalnum (c );
172+ case FNM_CC_ALPHA : return isalpha (c );
173+ case FNM_CC_BLANK : return isblank (c );
174+ case FNM_CC_CNTRL : return iscntrl (c );
175+ case FNM_CC_DIGIT : return isdigit (c );
176+ case FNM_CC_GRAPH : return isgraph (c );
177+ case FNM_CC_LOWER : return islower (c );
178+ case FNM_CC_PRINT : return isprint (c );
179+ case FNM_CC_PUNCT : return ispunct (c );
180+ case FNM_CC_SPACE : return isspace (c );
181+ case FNM_CC_UPPER : return isupper (c );
182+ case FNM_CC_XDIGIT : return isxdigit (c );
183+ default :
184+ break ;
185+ }
186+
187+ return 0 ;
188+ }
189+
190+
51191static inline int foldcase (int ch , int flags )
52192{
53193
@@ -60,6 +200,24 @@ static inline int foldcase(int ch, int flags)
60200
61201#define FOLDCASE (ch , flags ) foldcase((unsigned char)(ch), (flags))
62202
203+ static bool match_posix_class (const char * * pattern , int test )
204+ {
205+ enum fnm_char_class cc ;
206+
207+ const char * p = * pattern ;
208+ size_t remaining = strlen (p );
209+
210+ if (!fnm_cc_is_valid (p , remaining , & cc ))
211+ return false;
212+
213+ /* move pattern pointer past ":]" */
214+ const char * end = strstr (p , ":]" );
215+ if (end )
216+ * pattern = end + 2 ;
217+
218+ return fnm_cc_match (test , cc );
219+ }
220+
63221static const char * rangematch (const char * pattern , int test , int flags )
64222{
65223 bool negate , ok , need ;
@@ -99,6 +257,18 @@ static const char *rangematch(const char *pattern, int test, int flags)
99257 return NULL ;
100258 }
101259
260+ if (c == '[' && * pattern == ':' ) {
261+ if (match_posix_class (& pattern , test )) {
262+ ok = true;
263+ continue ;
264+ } else {
265+ // skip over class if unrecognized
266+ while (* pattern && !(* pattern == ':' && * (pattern + 1 ) == ']' )) pattern ++ ;
267+ if (* pattern ) pattern += 2 ;
268+ continue ;
269+ }
270+ }
271+
102272 if (* pattern == '-' ) {
103273 c2 = FOLDCASE (* (pattern + 1 ), flags );
104274 if (c2 != EOS && c2 != ']' ) {
0 commit comments