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_CNTRL ,
61+ FNM_CC_DIGIT ,
62+ FNM_CC_GRAPH ,
63+ FNM_CC_LOWER ,
64+ FNM_CC_PRINT ,
65+ FNM_CC_PUNCT ,
66+ FNM_CC_SPACE ,
67+ FNM_CC_UPPER ,
68+ FNM_CC_XDIGIT ,
69+ FNM_CC_INVALID ,
70+ };
71+
72+ static bool fnm_cc_is_valid (const char * pattern , size_t psize , enum fnm_char_class * cc )
73+ {
74+ if (psize < 4 || * pattern != ':' )
75+ return false;
76+
77+ pattern ++ ; /* skip ':' */
78+ psize -- ;
79+
80+ /* Each class name ends with ":]" */
81+ switch (pattern [0 ]) {
82+ case 'a' :
83+ if (MATCH_CLASS6 (pattern ,'a' ,'l' ,'n' ,'u' ,'m' ,':' ,']' )) {
84+ * cc = FNM_CC_ALNUM ;
85+ return true;
86+ }
87+ if (MATCH_CLASS6 (pattern ,'a' ,'l' ,'p' ,'h' ,'a' ,':' ,']' )) {
88+ * cc = FNM_CC_ALPHA ;
89+ return true;
90+ }
91+ break ;
92+
93+ case 'c' :
94+ if (MATCH_CLASS6 (pattern ,'c' ,'n' ,'t' ,'r' ,'l' ,':' ,']' )) {
95+ * cc = FNM_CC_CNTRL ;
96+ return true;
97+ }
98+ break ;
99+
100+ case 'd' :
101+ if (MATCH_CLASS6 (pattern ,'d' ,'i' ,'g' ,'i' ,'t' ,':' ,']' )) {
102+ * cc = FNM_CC_DIGIT ;
103+ return true;
104+ }
105+ break ;
106+
107+ case 'g' :
108+ if (MATCH_CLASS6 (pattern ,'g' ,'r' ,'a' ,'p' ,'h' ,':' ,']' )) {
109+ * cc = FNM_CC_GRAPH ;
110+ return true;
111+ }
112+ break ;
113+
114+ case 'l' :
115+ if (MATCH_CLASS6 (pattern ,'l' ,'o' ,'w' ,'e' ,'r' ,':' ,']' )) {
116+ * cc = FNM_CC_LOWER ;
117+ return true;
118+ }
119+ break ;
120+
121+ case 'p' :
122+ if (MATCH_CLASS6 (pattern ,'p' ,'r' ,'i' ,'n' ,'t' ,':' ,']' )) {
123+ * cc = FNM_CC_PRINT ;
124+ return true;
125+ }
126+ if (MATCH_CLASS6 (pattern ,'p' ,'u' ,'n' ,'c' ,'t' ,':' ,']' )) {
127+ * cc = FNM_CC_PUNCT ;
128+ return true;
129+ }
130+ break ;
131+
132+ case 's' :
133+ if (MATCH_CLASS6 (pattern ,'s' ,'p' ,'a' ,'c' ,'e' ,':' ,']' )) {
134+ * cc = FNM_CC_SPACE ;
135+ return true;
136+ }
137+ break ;
138+
139+ case 'u' :
140+ if (MATCH_CLASS6 (pattern ,'u' ,'p' ,'p' ,'e' ,'r' ,':' ,']' )) {
141+ * cc = FNM_CC_UPPER ;
142+ return true;
143+ }
144+ break ;
145+
146+ case 'x' :
147+ if (MATCH_CLASS7 (pattern ,'x' ,'d' ,'i' ,'g' ,'i' ,'t' ,':' ,']' )) {
148+ * cc = FNM_CC_XDIGIT ;
149+ return true;
150+ }
151+ break ;
152+
153+ default :
154+ break ;
155+ }
156+
157+ return false;
158+ }
159+
160+ static inline int fnm_cc_match (int c , enum fnm_char_class cc )
161+ {
162+ switch (cc ) {
163+ case FNM_CC_ALNUM : return isalnum (c );
164+ case FNM_CC_ALPHA : return isalpha (c );
165+ case FNM_CC_CNTRL : return iscntrl (c );
166+ case FNM_CC_DIGIT : return isdigit (c );
167+ case FNM_CC_GRAPH : return isgraph (c );
168+ case FNM_CC_LOWER : return islower (c );
169+ case FNM_CC_PRINT : return isprint (c );
170+ case FNM_CC_PUNCT : return ispunct (c );
171+ case FNM_CC_SPACE : return isspace (c );
172+ case FNM_CC_UPPER : return isupper (c );
173+ case FNM_CC_XDIGIT : return isxdigit (c );
174+ default :
175+ break ;
176+ }
177+
178+ return 0 ;
179+ }
180+
181+
51182static inline int foldcase (int ch , int flags )
52183{
53184
@@ -60,6 +191,24 @@ static inline int foldcase(int ch, int flags)
60191
61192#define FOLDCASE (ch , flags ) foldcase((unsigned char)(ch), (flags))
62193
194+ static bool match_posix_class (const char * * pattern , int test )
195+ {
196+ enum fnm_char_class cc ;
197+
198+ const char * p = * pattern ;
199+ size_t remaining = strlen (p );
200+
201+ if (!fnm_cc_is_valid (p , remaining , & cc ))
202+ return false;
203+
204+ /* move pattern pointer past ":]" */
205+ const char * end = strstr (p , ":]" );
206+ if (end )
207+ * pattern = end + 2 ;
208+
209+ return fnm_cc_match (test , cc );
210+ }
211+
63212static const char * rangematch (const char * pattern , int test , int flags )
64213{
65214 bool negate , ok , need ;
@@ -99,6 +248,18 @@ static const char *rangematch(const char *pattern, int test, int flags)
99248 return NULL ;
100249 }
101250
251+ if (c == '[' && * pattern == ':' ) {
252+ if (match_posix_class (& pattern , test )) {
253+ ok = true;
254+ continue ;
255+ } else {
256+ // skip over class if unrecognized
257+ while (* pattern && !(* pattern == ':' && * (pattern + 1 ) == ']' )) pattern ++ ;
258+ if (* pattern ) pattern += 2 ;
259+ continue ;
260+ }
261+ }
262+
102263 if (* pattern == '-' ) {
103264 c2 = FOLDCASE (* (pattern + 1 ), flags );
104265 if (c2 != EOS && c2 != ']' ) {
0 commit comments