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