1 // SPDX-License-Identifier: GPL-2.0
7 #include "sane_ctype.h"
10 static const char *OP_and
= "&"; /* Logical AND */
11 static const char *OP_or
= "|"; /* Logical OR */
12 static const char *OP_not
= "!"; /* Logical NOT */
14 #define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
15 #define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')')
17 static void strfilter_node__delete(struct strfilter_node
*node
)
20 if (node
->p
&& !is_operator(*node
->p
))
21 zfree((char **)&node
->p
);
22 strfilter_node__delete(node
->l
);
23 strfilter_node__delete(node
->r
);
28 void strfilter__delete(struct strfilter
*filter
)
31 strfilter_node__delete(filter
->root
);
36 static const char *get_token(const char *s
, const char **e
)
40 while (isspace(*s
)) /* Skip spaces */
49 if (!is_separator(*s
)) {
52 while (*p
&& !is_separator(*p
) && !isspace(*p
))
54 /* Escape and special case: '!' is also used in glob pattern */
55 if (*(p
- 1) == '\\' || (*p
== '!' && *(p
- 1) == '[')) {
65 static struct strfilter_node
*strfilter_node__alloc(const char *op
,
66 struct strfilter_node
*l
,
67 struct strfilter_node
*r
)
69 struct strfilter_node
*node
= zalloc(sizeof(*node
));
80 static struct strfilter_node
*strfilter_node__new(const char *s
,
83 struct strfilter_node root
, *cur
, *last_op
;
89 memset(&root
, 0, sizeof(root
));
90 last_op
= cur
= &root
;
93 while (*s
!= '\0' && *s
!= ')') {
95 case '&': /* Exchg last OP->r with AND */
96 if (!cur
->r
|| !last_op
->r
)
98 cur
= strfilter_node__alloc(OP_and
, last_op
->r
, NULL
);
104 case '|': /* Exchg the root with OR */
105 if (!cur
->r
|| !root
.r
)
107 cur
= strfilter_node__alloc(OP_or
, root
.r
, NULL
);
113 case '!': /* Add NOT as a leaf node */
116 cur
->r
= strfilter_node__alloc(OP_not
, NULL
, NULL
);
121 case '(': /* Recursively parses inside the parenthesis */
124 cur
->r
= strfilter_node__new(s
+ 1, &s
);
127 if (!cur
->r
|| *s
!= ')')
134 cur
->r
= strfilter_node__alloc(NULL
, NULL
, NULL
);
137 cur
->r
->p
= strndup(s
, e
- s
);
141 s
= get_token(e
, &e
);
151 strfilter_node__delete(root
.r
);
156 * Parse filter rule and return new strfilter.
157 * Return NULL if fail, and *ep == NULL if memory allocation failed.
159 struct strfilter
*strfilter__new(const char *rules
, const char **err
)
161 struct strfilter
*filter
= zalloc(sizeof(*filter
));
162 const char *ep
= NULL
;
165 filter
->root
= strfilter_node__new(rules
, &ep
);
167 if (!filter
|| !filter
->root
|| *ep
!= '\0') {
170 strfilter__delete(filter
);
177 static int strfilter__append(struct strfilter
*filter
, bool _or
,
178 const char *rules
, const char **err
)
180 struct strfilter_node
*right
, *root
;
181 const char *ep
= NULL
;
183 if (!filter
|| !rules
)
186 right
= strfilter_node__new(rules
, &ep
);
187 if (!right
|| *ep
!= '\0') {
192 root
= strfilter_node__alloc(_or
? OP_or
: OP_and
, filter
->root
, right
);
202 strfilter_node__delete(right
);
203 return ep
? -EINVAL
: -ENOMEM
;
206 int strfilter__or(struct strfilter
*filter
, const char *rules
, const char **err
)
208 return strfilter__append(filter
, true, rules
, err
);
211 int strfilter__and(struct strfilter
*filter
, const char *rules
,
214 return strfilter__append(filter
, false, rules
, err
);
217 static bool strfilter_node__compare(struct strfilter_node
*node
,
220 if (!node
|| !node
->p
)
225 return strfilter_node__compare(node
->l
, str
) ||
226 strfilter_node__compare(node
->r
, str
);
228 return strfilter_node__compare(node
->l
, str
) &&
229 strfilter_node__compare(node
->r
, str
);
231 return !strfilter_node__compare(node
->r
, str
);
233 return strglobmatch(str
, node
->p
);
237 /* Return true if STR matches the filter rules */
238 bool strfilter__compare(struct strfilter
*filter
, const char *str
)
242 return strfilter_node__compare(filter
->root
, str
);
245 static int strfilter_node__sprint(struct strfilter_node
*node
, char *buf
);
247 /* sprint node in parenthesis if needed */
248 static int strfilter_node__sprint_pt(struct strfilter_node
*node
, char *buf
)
251 int pt
= node
->r
? 2 : 0; /* don't need to check node->l */
255 len
= strfilter_node__sprint(node
, buf
);
263 static int strfilter_node__sprint(struct strfilter_node
*node
, char *buf
)
267 if (!node
|| !node
->p
)
273 len
= strfilter_node__sprint_pt(node
->l
, buf
);
279 *(buf
+ len
++) = *node
->p
;
283 rlen
= strfilter_node__sprint_pt(node
->r
, buf
);
289 len
= strlen(node
->p
);
291 strcpy(buf
, node
->p
);
297 char *strfilter__string(struct strfilter
*filter
)
302 len
= strfilter_node__sprint(filter
->root
, NULL
);
306 ret
= malloc(len
+ 1);
308 strfilter_node__sprint(filter
->root
, ret
);