]> arthur.barton.de Git - netdata.git/blob - src/simple_pattern.c
simple_pattern now also supports asterisks in the middle; cgroups cleanup;
[netdata.git] / src / simple_pattern.c
1 #include "common.h"
2
3 struct simple_pattern {
4     const char *match;
5     size_t len;
6     NETDATA_SIMPLE_PREFIX_MODE mode;
7
8     struct simple_pattern *child;
9
10     struct simple_pattern *next;
11 };
12
13 static inline struct simple_pattern *parse_pattern(const char *str, NETDATA_SIMPLE_PREFIX_MODE default_mode) {
14     info(">>>> PARSE: '%s'", str);
15
16     NETDATA_SIMPLE_PREFIX_MODE mode;
17     struct simple_pattern *child = NULL;
18
19     char *buf = strdupz(str);
20     char *s = buf, *c = buf;
21
22     // skip asterisks in front
23     while(*c == '*') c++;
24
25     // find the next asterisk
26     while(*c && *c != '*') c++ ;
27
28     // do we have an asterisk in the middle?
29     if(*c == '*' && c[1] != '\0') {
30         // yes, we have
31         child = parse_pattern(c, default_mode);
32         c[1] = '\0';
33     }
34
35     // check what this one matches
36
37     size_t len = strlen(s);
38     if(len >= 2 && *s == '*' && s[len - 1] == '*') {
39         s[len - 1] = '\0';
40         s++;
41         mode = NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING;
42     }
43     else if(len >= 1 && *s == '*') {
44         s++;
45         mode = NETDATA_SIMPLE_PATTERN_MODE_SUFFIX;
46     }
47     else if(len >= 1 && s[len - 1] == '*') {
48         s[len - 1] = '\0';
49         mode = NETDATA_SIMPLE_PATTERN_MODE_PREFIX;
50     }
51     else
52         mode = default_mode;
53
54     // allocate the structure
55     struct simple_pattern *m = callocz(1, sizeof(struct simple_pattern));
56     if(*s) {
57         m->match = strdup(s);
58         m->len = strlen(m->match);
59         m->mode = mode;
60     }
61     else {
62         m->mode = NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING;
63     }
64
65     m->child = child;
66
67     free(buf);
68
69     info("PATTERN '%s' is composed by", str);
70     struct simple_pattern *p;
71     for(p = m; p ; p = p->child)
72         info(">>>> COMPONENT: '%s%s%s' (len %zu type %u)",
73             (p->mode == NETDATA_SIMPLE_PATTERN_MODE_SUFFIX || p->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
74             p->match,
75             (p->mode == NETDATA_SIMPLE_PATTERN_MODE_PREFIX || p->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
76             p->len,
77             p->mode);
78
79     return m;
80 }
81
82 NETDATA_SIMPLE_PATTERN *netdata_simple_pattern_list_create(const char *list, NETDATA_SIMPLE_PREFIX_MODE default_mode) {
83     struct simple_pattern *root = NULL, *last = NULL;
84
85     if(unlikely(!list || !*list)) return root;
86
87     char *buf = strdupz(list);
88     if(buf && *buf) {
89         char *s = buf;
90
91         while(s && *s) {
92             // skip all spaces
93             while(isspace(*s)) s++;
94
95             // empty string
96             if(unlikely(!*s)) break;
97
98             // find the next space
99             char *c = s;
100             while(*c && !isspace(*c)) c++;
101
102             // find the next word
103             char *n;
104             if(likely(*c)) n = c + 1;
105             else n = NULL;
106
107             // terminate our string
108             *c = '\0';
109
110             struct simple_pattern *m = parse_pattern(s, default_mode);
111
112             if(likely(n)) *c = ' ';
113
114             // link it at the end
115             if(unlikely(!root))
116                 root = last = m;
117             else {
118                 last->next = m;
119                 last = m;
120             }
121
122             // prepare for next loop
123             s = n;
124         }
125     }
126
127     free(buf);
128     return (NETDATA_SIMPLE_PATTERN *)root;
129 }
130
131 static inline int match_pattern(struct simple_pattern *m, const char *str, size_t len) {
132     info("CHECK string '%s' (len %zu) with pattern '%s%s%s' (len %zu type %u)", str, len,
133             (m->mode == NETDATA_SIMPLE_PATTERN_MODE_SUFFIX || m->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
134             m->match,
135             (m->mode == NETDATA_SIMPLE_PATTERN_MODE_PREFIX || m->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
136             m->len, m->mode);
137
138     char *s;
139
140     if(m->len <= len) {
141         switch(m->mode) {
142             case NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING:
143                 if(!m->len) return 1;
144                 if((s = strstr(str, m->match))) {
145                     if(!m->child) return 1;
146                     return match_pattern(m->child, &s[m->len], len - (s - str) - m->len);
147                 }
148                 break;
149
150             case NETDATA_SIMPLE_PATTERN_MODE_PREFIX:
151                 if(unlikely(strncmp(str, m->match, m->len) == 0)) {
152                     if(!m->child) return 1;
153                     return match_pattern(m->child, &str[m->len], len - m->len);
154                 }
155                 break;
156
157             case NETDATA_SIMPLE_PATTERN_MODE_SUFFIX:
158                 if(unlikely(strcmp(&str[len - m->len], m->match) == 0)) {
159                     if(!m->child) return 1;
160                     return 0;
161                 }
162                 break;
163
164             case NETDATA_SIMPLE_PATTERN_MODE_EXACT:
165             default:
166                 if(unlikely(strcmp(str, m->match) == 0)) {
167                     if(!m->child) return 1;
168                     return 0;
169                 }
170                 break;
171         }
172     }
173
174     return 0;
175 }
176
177 int netdata_simple_pattern_list_matches(NETDATA_SIMPLE_PATTERN *list, const char *str) {
178     struct simple_pattern *m, *root = (struct simple_pattern *)list;
179
180     if(unlikely(!root)) return 0;
181
182     size_t len = strlen(str);
183     for(m = root; m ; m = m->next)
184         if(match_pattern(m, str, len)) {
185             info("MATCHED string '%s' (len %zu) with pattern '%s%s%s' (len %zu type %u)", str, len,
186                     (m->mode == NETDATA_SIMPLE_PATTERN_MODE_SUFFIX || m->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
187                     m->match,
188                     (m->mode == NETDATA_SIMPLE_PATTERN_MODE_PREFIX || m->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
189                     m->len, m->mode);
190
191             struct simple_pattern *p;
192             for(p = m; p ; p = p->child)
193                 info(">>>> MATCHED COMPONENT: '%s%s%s' (len %zu type %u)",
194                         (p->mode == NETDATA_SIMPLE_PATTERN_MODE_SUFFIX || p->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
195                         p->match,
196                         (p->mode == NETDATA_SIMPLE_PATTERN_MODE_PREFIX || p->mode == NETDATA_SIMPLE_PATTERN_MODE_SUBSTRING)?"*":"",
197                         p->len,
198                         p->mode);
199
200             return 1;
201         }
202
203     return 0;
204 }