diff options
author | Lennart Weller <lhw@ring0.de> | 2017-01-24 15:21:09 +0000 |
---|---|---|
committer | Lennart Weller <lhw@ring0.de> | 2017-01-24 15:21:09 +0000 |
commit | 3ed3b02ed96ddab1c084811f3579b3a2aec83e04 (patch) | |
tree | 7a61ab288ae47800c4f11be5677d6ad8288dcd98 /src/simple_pattern.c | |
parent | New upstream version 1.4.0+dfsg (diff) | |
download | netdata-3ed3b02ed96ddab1c084811f3579b3a2aec83e04.tar.xz netdata-3ed3b02ed96ddab1c084811f3579b3a2aec83e04.zip |
New upstream version 1.5.0+dfsgupstream/1.5.0+dfsg
Diffstat (limited to 'src/simple_pattern.c')
-rw-r--r-- | src/simple_pattern.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/simple_pattern.c b/src/simple_pattern.c new file mode 100644 index 000000000..7e4424297 --- /dev/null +++ b/src/simple_pattern.c @@ -0,0 +1,197 @@ +#include "common.h" + +struct simple_pattern { + const char *match; + size_t len; + + SIMPLE_PREFIX_MODE mode; + char negative; + + struct simple_pattern *child; + + struct simple_pattern *next; +}; + +static inline struct simple_pattern *parse_pattern(const char *str, SIMPLE_PREFIX_MODE default_mode) { + SIMPLE_PREFIX_MODE mode; + struct simple_pattern *child = NULL; + + char *buf = strdupz(str); + char *s = buf, *c = buf; + + // skip asterisks in front + while(*c == '*') c++; + + // find the next asterisk + while(*c && *c != '*') c++; + + // do we have an asterisk in the middle? + if(*c == '*' && c[1] != '\0') { + // yes, we have + child = parse_pattern(c, default_mode); + c[1] = '\0'; + } + + // check what this one matches + + size_t len = strlen(s); + if(len >= 2 && *s == '*' && s[len - 1] == '*') { + s[len - 1] = '\0'; + s++; + mode = SIMPLE_PATTERN_SUBSTRING; + } + else if(len >= 1 && *s == '*') { + s++; + mode = SIMPLE_PATTERN_SUFFIX; + } + else if(len >= 1 && s[len - 1] == '*') { + s[len - 1] = '\0'; + mode = SIMPLE_PATTERN_PREFIX; + } + else + mode = default_mode; + + // allocate the structure + struct simple_pattern *m = callocz(1, sizeof(struct simple_pattern)); + if(*s) { + m->match = strdupz(s); + m->len = strlen(m->match); + m->mode = mode; + } + else { + m->mode = SIMPLE_PATTERN_SUBSTRING; + } + + m->child = child; + + freez(buf); + + return m; +} + +SIMPLE_PATTERN *simple_pattern_create(const char *list, SIMPLE_PREFIX_MODE default_mode) { + struct simple_pattern *root = NULL, *last = NULL; + + if(unlikely(!list || !*list)) return root; + + char *buf = strdupz(list); + if(buf && *buf) { + char *s = buf; + + while(s && *s) { + char negative = 0; + + // skip all spaces + while(isspace(*s)) s++; + + if(*s == '!') { + negative = 1; + s++; + } + + // empty string + if(unlikely(!*s)) break; + + // find the next space + char *c = s; + while(*c && !isspace(*c)) c++; + + // find the next word + char *n; + if(likely(*c)) n = c + 1; + else n = NULL; + + // terminate our string + *c = '\0'; + + struct simple_pattern *m = parse_pattern(s, default_mode); + m->negative = negative; + + if(likely(n)) *c = ' '; + + // link it at the end + if(unlikely(!root)) + root = last = m; + else { + last->next = m; + last = m; + } + + // prepare for next loop + s = n; + } + } + + freez(buf); + return (SIMPLE_PATTERN *)root; +} + +static inline int match_pattern(struct simple_pattern *m, const char *str, size_t len) { + char *s; + + if(m->len <= len) { + switch(m->mode) { + case SIMPLE_PATTERN_SUBSTRING: + if(!m->len) return 1; + if((s = strstr(str, m->match))) { + if(!m->child) return 1; + return match_pattern(m->child, &s[m->len], len - (s - str) - m->len); + } + break; + + case SIMPLE_PATTERN_PREFIX: + if(unlikely(strncmp(str, m->match, m->len) == 0)) { + if(!m->child) return 1; + return match_pattern(m->child, &str[m->len], len - m->len); + } + break; + + case SIMPLE_PATTERN_SUFFIX: + if(unlikely(strcmp(&str[len - m->len], m->match) == 0)) { + if(!m->child) return 1; + return 0; + } + break; + + case SIMPLE_PATTERN_EXACT: + default: + if(unlikely(strcmp(str, m->match) == 0)) { + if(!m->child) return 1; + return 0; + } + break; + } + } + + return 0; +} + +int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) { + struct simple_pattern *m, *root = (struct simple_pattern *)list; + + if(unlikely(!root)) return 0; + + size_t len = strlen(str); + for(m = root; m ; m = m->next) + if(match_pattern(m, str, len)) { + if(m->negative) return 0; + return 1; + } + + return 0; +} + +static inline void free_pattern(struct simple_pattern *m) { + if(!m) return; + + if(m->next) free_pattern(m->next); + if(m->child) free_pattern(m->child); + freez((void *)m->match); + freez(m); +} + +void simple_pattern_free(SIMPLE_PATTERN *list) { + if(!list) return; + + free_pattern(((struct simple_pattern *)list)->next); +} |