aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2011-01-20 09:15:30 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-28 06:19:38 -0500
commit68baa431ec2f14ba7510d4e79bceb6ceaf0d3b74 (patch)
tree01c1901907ffa1a462d8a06b126736337f11758e
parentd380eaaea70d775c0520dcb5702ea5d2a56b7be9 (diff)
perf tools: Add strfilter for general purpose string filter
Add strfilter for general purpose string filter. Every filter rules are descrived by glob matching pattern and '!' prefix which means Logical NOT. A strfilter consists of those filter rules connected with '&' and '|'. A set of rules can be folded by using '(' and ')'. It also accepts spaces around rules and those operators. Format: <rule> ::= <glob-exp> | "!" <rule> | <rule> <op> <rule> | "(" <rule> ")" <op> ::= "&" | "|" e.g.: "(add* | del*) & *timer" filter rules pass strings which start with add or del and end with timer. This will be used by perf probe --filter. Changes in V2: - Fix to check result of strdup() and strfilter__alloc(). - Encapsulate and simplify interfaces as like regex(3). Cc: 2nddept-manager@sdl.hitachi.co.jp Cc: Franck Bui-Huu <fbuihuu@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <20110120141530.25915.12673.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/util/strfilter.c200
-rw-r--r--tools/perf/util/strfilter.h48
3 files changed, 250 insertions, 0 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 638e8e146bb9..eedcf9541572 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -417,6 +417,7 @@ LIB_H += util/help.h
417LIB_H += util/session.h 417LIB_H += util/session.h
418LIB_H += util/strbuf.h 418LIB_H += util/strbuf.h
419LIB_H += util/strlist.h 419LIB_H += util/strlist.h
420LIB_H += util/strfilter.h
420LIB_H += util/svghelper.h 421LIB_H += util/svghelper.h
421LIB_H += util/run-command.h 422LIB_H += util/run-command.h
422LIB_H += util/sigchain.h 423LIB_H += util/sigchain.h
@@ -458,6 +459,7 @@ LIB_OBJS += $(OUTPUT)util/quote.o
458LIB_OBJS += $(OUTPUT)util/strbuf.o 459LIB_OBJS += $(OUTPUT)util/strbuf.o
459LIB_OBJS += $(OUTPUT)util/string.o 460LIB_OBJS += $(OUTPUT)util/string.o
460LIB_OBJS += $(OUTPUT)util/strlist.o 461LIB_OBJS += $(OUTPUT)util/strlist.o
462LIB_OBJS += $(OUTPUT)util/strfilter.o
461LIB_OBJS += $(OUTPUT)util/usage.o 463LIB_OBJS += $(OUTPUT)util/usage.o
462LIB_OBJS += $(OUTPUT)util/wrapper.o 464LIB_OBJS += $(OUTPUT)util/wrapper.o
463LIB_OBJS += $(OUTPUT)util/sigchain.o 465LIB_OBJS += $(OUTPUT)util/sigchain.o
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
new file mode 100644
index 000000000000..4064b7d708b8
--- /dev/null
+++ b/tools/perf/util/strfilter.c
@@ -0,0 +1,200 @@
1#include <ctype.h>
2#include "util.h"
3#include "string.h"
4#include "strfilter.h"
5
6/* Operators */
7static const char *OP_and = "&"; /* Logical AND */
8static const char *OP_or = "|"; /* Logical OR */
9static const char *OP_not = "!"; /* Logical NOT */
10
11#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
12#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')')
13
14static void strfilter_node__delete(struct strfilter_node *self)
15{
16 if (self) {
17 if (self->p && !is_operator(*self->p))
18 free((char *)self->p);
19 strfilter_node__delete(self->l);
20 strfilter_node__delete(self->r);
21 free(self);
22 }
23}
24
25void strfilter__delete(struct strfilter *self)
26{
27 if (self) {
28 strfilter_node__delete(self->root);
29 free(self);
30 }
31}
32
33static const char *get_token(const char *s, const char **e)
34{
35 const char *p;
36
37 while (isspace(*s)) /* Skip spaces */
38 s++;
39
40 if (*s == '\0') {
41 p = s;
42 goto end;
43 }
44
45 p = s + 1;
46 if (!is_separator(*s)) {
47 /* End search */
48retry:
49 while (*p && !is_separator(*p) && !isspace(*p))
50 p++;
51 /* Escape and special case: '!' is also used in glob pattern */
52 if (*(p - 1) == '\\' || (*p == '!' && *(p - 1) == '[')) {
53 p++;
54 goto retry;
55 }
56 }
57end:
58 *e = p;
59 return s;
60}
61
62static struct strfilter_node *strfilter_node__alloc(const char *op,
63 struct strfilter_node *l,
64 struct strfilter_node *r)
65{
66 struct strfilter_node *ret = zalloc(sizeof(struct strfilter_node));
67
68 if (ret) {
69 ret->p = op;
70 ret->l = l;
71 ret->r = r;
72 }
73
74 return ret;
75}
76
77static struct strfilter_node *strfilter_node__new(const char *s,
78 const char **ep)
79{
80 struct strfilter_node root, *cur, *last_op;
81 const char *e;
82
83 if (!s)
84 return NULL;
85
86 memset(&root, 0, sizeof(root));
87 last_op = cur = &root;
88
89 s = get_token(s, &e);
90 while (*s != '\0' && *s != ')') {
91 switch (*s) {
92 case '&': /* Exchg last OP->r with AND */
93 if (!cur->r || !last_op->r)
94 goto error;
95 cur = strfilter_node__alloc(OP_and, last_op->r, NULL);
96 if (!cur)
97 goto nomem;
98 last_op->r = cur;
99 last_op = cur;
100 break;
101 case '|': /* Exchg the root with OR */
102 if (!cur->r || !root.r)
103 goto error;
104 cur = strfilter_node__alloc(OP_or, root.r, NULL);
105 if (!cur)
106 goto nomem;
107 root.r = cur;
108 last_op = cur;
109 break;
110 case '!': /* Add NOT as a leaf node */
111 if (cur->r)
112 goto error;
113 cur->r = strfilter_node__alloc(OP_not, NULL, NULL);
114 if (!cur->r)
115 goto nomem;
116 cur = cur->r;
117 break;
118 case '(': /* Recursively parses inside the parenthesis */
119 if (cur->r)
120 goto error;
121 cur->r = strfilter_node__new(s + 1, &s);
122 if (!s)
123 goto nomem;
124 if (!cur->r || *s != ')')
125 goto error;
126 e = s + 1;
127 break;
128 default:
129 if (cur->r)
130 goto error;
131 cur->r = strfilter_node__alloc(NULL, NULL, NULL);
132 if (!cur->r)
133 goto nomem;
134 cur->r->p = strndup(s, e - s);
135 if (!cur->r->p)
136 goto nomem;
137 }
138 s = get_token(e, &e);
139 }
140 if (!cur->r)
141 goto error;
142 *ep = s;
143 return root.r;
144nomem:
145 s = NULL;
146error:
147 *ep = s;
148 strfilter_node__delete(root.r);
149 return NULL;
150}
151
152/*
153 * Parse filter rule and return new strfilter.
154 * Return NULL if fail, and *ep == NULL if memory allocation failed.
155 */
156struct strfilter *strfilter__new(const char *rules, const char **err)
157{
158 struct strfilter *ret = zalloc(sizeof(struct strfilter));
159 const char *ep = NULL;
160
161 if (ret)
162 ret->root = strfilter_node__new(rules, &ep);
163
164 if (!ret || !ret->root || *ep != '\0') {
165 if (err)
166 *err = ep;
167 strfilter__delete(ret);
168 ret = NULL;
169 }
170
171 return ret;
172}
173
174static bool strfilter_node__compare(struct strfilter_node *self,
175 const char *str)
176{
177 if (!self || !self->p)
178 return false;
179
180 switch (*self->p) {
181 case '|': /* OR */
182 return strfilter_node__compare(self->l, str) ||
183 strfilter_node__compare(self->r, str);
184 case '&': /* AND */
185 return strfilter_node__compare(self->l, str) &&
186 strfilter_node__compare(self->r, str);
187 case '!': /* NOT */
188 return !strfilter_node__compare(self->r, str);
189 default:
190 return strglobmatch(str, self->p);
191 }
192}
193
194/* Return true if STR matches the filter rules */
195bool strfilter__compare(struct strfilter *self, const char *str)
196{
197 if (!self)
198 return false;
199 return strfilter_node__compare(self->root, str);
200}
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
new file mode 100644
index 000000000000..00f58a7506de
--- /dev/null
+++ b/tools/perf/util/strfilter.h
@@ -0,0 +1,48 @@
1#ifndef __PERF_STRFILTER_H
2#define __PERF_STRFILTER_H
3/* General purpose glob matching filter */
4
5#include <linux/list.h>
6#include <stdbool.h>
7
8/* A node of string filter */
9struct strfilter_node {
10 struct strfilter_node *l; /* Tree left branche (for &,|) */
11 struct strfilter_node *r; /* Tree right branche (for !,&,|) */
12 const char *p; /* Operator or rule */
13};
14
15/* String filter */
16struct strfilter {
17 struct strfilter_node *root;
18};
19
20/**
21 * strfilter__new - Create a new string filter
22 * @rules: Filter rule, which is a combination of glob expressions.
23 * @err: Pointer which points an error detected on @rules
24 *
25 * Parse @rules and return new strfilter. Return NULL if an error detected.
26 * In that case, *@err will indicate where it is detected, and *@err is NULL
27 * if a memory allocation is failed.
28 */
29struct strfilter *strfilter__new(const char *rules, const char **err);
30
31/**
32 * strfilter__compare - compare given string and a string filter
33 * @self: String filter
34 * @str: target string
35 *
36 * Compare @str and @self. Return true if the str match the rule
37 */
38bool strfilter__compare(struct strfilter *self, const char *str);
39
40/**
41 * strfilter__delete - delete a string filter
42 * @self: String filter to delete
43 *
44 * Delete @self.
45 */
46void strfilter__delete(struct strfilter *self);
47
48#endif