]> arthur.barton.de Git - netdata.git/blob - src/simple_pattern.c
dns_query_time plugin: replace "." with "_" in dimensions
[netdata.git] / src / simple_pattern.c
1 #include "common.h"
2
3 struct simple_pattern {
4     const char *match;
5     size_t len;
6
7     SIMPLE_PREFIX_MODE mode;
8     char negative;
9
10     struct simple_pattern *child;
11
12     struct simple_pattern *next;
13 };
14
15 static inline struct simple_pattern *parse_pattern(const char *str, SIMPLE_PREFIX_MODE default_mode) {
16     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 = SIMPLE_PATTERN_SUBSTRING;
42     }
43     else if(len >= 1 && *s == '*') {
44         s++;
45         mode = SIMPLE_PATTERN_SUFFIX;
46     }
47     else if(len >= 1 && s[len - 1] == '*') {
48         s[len - 1] = '\0';
49         mode = SIMPLE_PATTERN_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 = strdupz(s);
58         m->len = strlen(m->match);
59         m->mode = mode;
60     }
61     else {
62         m->mode = SIMPLE_PATTERN_SUBSTRING;
63     }
64
65     m->child = child;
66
67     freez(buf);
68
69     return m;
70 }
71
72 SIMPLE_PATTERN *simple_pattern_create(const char *list, SIMPLE_PREFIX_MODE default_mode) {
73     struct simple_pattern *root = NULL, *last = NULL;
74
75     if(unlikely(!list || !*list)) return root;
76
77     char *buf = strdupz(list);
78     if(buf && *buf) {
79         char *s = buf;
80
81         while(s && *s) {
82             char negative = 0;
83
84             // skip all spaces
85             while(isspace(*s)) s++;
86
87             if(*s == '!') {
88                 negative = 1;
89                 s++;
90             }
91
92             // empty string
93             if(unlikely(!*s)) break;
94
95             // find the next space
96             char *c = s;
97             while(*c && !isspace(*c)) c++;
98
99             // find the next word
100             char *n;
101             if(likely(*c)) n = c + 1;
102             else n = NULL;
103
104             // terminate our string
105             *c = '\0';
106
107             struct simple_pattern *m = parse_pattern(s, default_mode);
108             m->negative = negative;
109
110             if(likely(n)) *c = ' ';
111
112             // link it at the end
113             if(unlikely(!root))
114                 root = last = m;
115             else {
116                 last->next = m;
117                 last = m;
118             }
119
120             // prepare for next loop
121             s = n;
122         }
123     }
124
125     freez(buf);
126     return (SIMPLE_PATTERN *)root;
127 }
128
129 static inline int match_pattern(struct simple_pattern *m, const char *str, size_t len) {
130     char *s;
131
132     if(m->len <= len) {
133         switch(m->mode) {
134             case SIMPLE_PATTERN_SUBSTRING:
135                 if(!m->len) return 1;
136                 if((s = strstr(str, m->match))) {
137                     if(!m->child) return 1;
138                     return match_pattern(m->child, &s[m->len], len - (s - str) - m->len);
139                 }
140                 break;
141
142             case SIMPLE_PATTERN_PREFIX:
143                 if(unlikely(strncmp(str, m->match, m->len) == 0)) {
144                     if(!m->child) return 1;
145                     return match_pattern(m->child, &str[m->len], len - m->len);
146                 }
147                 break;
148
149             case SIMPLE_PATTERN_SUFFIX:
150                 if(unlikely(strcmp(&str[len - m->len], m->match) == 0)) {
151                     if(!m->child) return 1;
152                     return 0;
153                 }
154                 break;
155
156             case SIMPLE_PATTERN_EXACT:
157             default:
158                 if(unlikely(strcmp(str, m->match) == 0)) {
159                     if(!m->child) return 1;
160                     return 0;
161                 }
162                 break;
163         }
164     }
165
166     return 0;
167 }
168
169 int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) {
170     struct simple_pattern *m, *root = (struct simple_pattern *)list;
171
172     if(unlikely(!root || !str || !*str)) return 0;
173
174     size_t len = strlen(str);
175     for(m = root; m ; m = m->next)
176         if(match_pattern(m, str, len)) {
177             if(m->negative) return 0;
178             return 1;
179         }
180
181     return 0;
182 }
183
184 static inline void free_pattern(struct simple_pattern *m) {
185     if(!m) return;
186
187     free_pattern(m->child);
188     free_pattern(m->next);
189     freez((void *)m->match);
190     freez(m);
191 }
192
193 void simple_pattern_free(SIMPLE_PATTERN *list) {
194     if(!list) return;
195
196     free_pattern(((struct simple_pattern *)list));
197 }