2 * Copyright 1994 Christopher Seiwald. All rights reserved.
4 * This file is part of Jam - see jam.c for Copyright information.
7 * matchglob.c - match a string against a simple pattern
9 * Understands the following patterns:
11 * * any number of characters
12 * ? any single character
13 * [a-z] any single character in the range a-z
14 * [^a-z] any single character not in the range a-z
19 * matchglob() - match a string against a simple pattern
23 * globchars() - build a bitlist to check for character group match
25 * 11/04/02 (seiwald) - const-ing for string literals
28 #include "matchglob.h"
31 #define CHECK_BIT(tab, bit) (tab[(bit)/8]&(1<<((bit)%8)))
32 #define SET_BIT(tab, bit) (tab[(bit)/8] |= (1<<((bit)%8)))
34 /* bytes used for [chars] in compiled expr */
35 #define BITLISTSIZE (32)
38 static inline int casechar (char ch
) {
40 (ch
>= 'a' && ch
<= 'z') ? ch
-32 :
41 (ch
>= 'A' && ch
<= 'Z') ? ch
+32 :
46 static inline int lower (char ch
) {
47 return (ch
>= 'A' && ch
<= 'Z') ? ch
+32 : ch
;
51 static inline int samechars (char c0
, char c1
, int casesens
) {
52 return casesens
? c0
==c1
: lower(c0
)==lower(c1
);
57 * globchars() - build a bitlist to check for character group match
59 static void globchars (const char *s
, const char *e
, unsigned char *b
, int casesens
) {
62 memset(b
, 0, BITLISTSIZE
);
63 if (*s
== '^') ++neg
, ++s
;
66 if (s
+2 < e
&& s
[1] == '-') {
67 for (c
= (unsigned char)s
[0]; c
<= (unsigned char)s
[2]; ++c
) {
69 if (!casesens
) SET_BIT(b
, casechar(c
));
73 c
= (unsigned char)(*s
++);
75 if (!casesens
) SET_BIT(b
, casechar(c
));
78 if (neg
) for (c
= 0; c
< BITLISTSIZE
; ++c
) b
[c
] ^= 0xff;
79 /* don't include \0 in either $[chars] or $[^chars] */
84 int matchglob (const char *pat
, const char *str
) {
85 return matchglobex(pat
, str
, 1);
90 * matchglobex() - match a string against a simple pattern
92 int matchglobex (const char *pat
, const char *str
, int casesens
) {
93 unsigned char bitlist
[BITLISTSIZE
];
98 case '\0': return *str
?-1:0;
99 case '?': if (!*str
++) return 1; break;
101 /* scan for matching ] */
103 /* k8: allow []...] and [^]...] */
104 if (*pat
== '^') ++pat
;
105 if (*pat
== ']') ++pat
;
107 do { if (!*pat
++) return 1; } while (here
== pat
|| *pat
!= ']') ;
109 /* build character class bitlist */
110 globchars(here
, pat
, bitlist
, casesens
);
111 if (!CHECK_BIT(bitlist
, *(unsigned char *)str
)) return 1;
117 /* try to match the rest of the pattern in a recursive call */
118 /* if the match fails we'll back up chars, retrying */
119 while (str
!= here
) {
121 /* a fast path for the last token in a pattern */
122 r
= *pat
?matchglobex(pat
, str
, casesens
):*str
?-1:0;
129 /* force literal match of next char */
130 if (!*pat
|| !samechars(*str
++, *pat
++, casesens
)) return 1;
133 if (!samechars(*str
++, pat
[-1], casesens
)) return 1;