TEST(String, Regex) { int flags, rc; const char *ptr; regex_t regex; string_regex_flags (NULL, 0, NULL); string_regex_flags ("", 0, NULL); string_regex_flags (NULL, 0, &flags); LONGS_EQUAL(0, flags); string_regex_flags ("", 0, &flags); LONGS_EQUAL(0, flags); string_regex_flags (NULL, REG_EXTENDED, &flags); LONGS_EQUAL(REG_EXTENDED, flags); string_regex_flags ("", REG_EXTENDED, &flags); LONGS_EQUAL(REG_EXTENDED, flags); ptr = string_regex_flags ("test", REG_EXTENDED, &flags); LONGS_EQUAL(REG_EXTENDED, flags); STRCMP_EQUAL("test", ptr); string_regex_flags ("(?e)test", 0, &flags); LONGS_EQUAL(REG_EXTENDED, flags); STRCMP_EQUAL("test", ptr); string_regex_flags ("(?ei)test", 0, &flags); LONGS_EQUAL(REG_EXTENDED | REG_ICASE, flags); STRCMP_EQUAL("test", ptr); string_regex_flags ("(?eins)test", 0, &flags); LONGS_EQUAL(REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB, flags); STRCMP_EQUAL("test", ptr); string_regex_flags ("(?ins)test", REG_EXTENDED, &flags); LONGS_EQUAL(REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB, flags); STRCMP_EQUAL("test", ptr); string_regex_flags ("(?ins-e)test", REG_EXTENDED, &flags); LONGS_EQUAL(REG_ICASE | REG_NEWLINE | REG_NOSUB, flags); STRCMP_EQUAL("test", ptr); /* compile regular expression */ LONGS_EQUAL(-1, string_regcomp (®ex, NULL, 0)); LONGS_EQUAL(0, string_regcomp (®ex, "", 0)); regfree (®ex); LONGS_EQUAL(0, string_regcomp (®ex, "test", 0)); regfree (®ex); LONGS_EQUAL(0, string_regcomp (®ex, "test", REG_EXTENDED)); regfree (®ex); LONGS_EQUAL(0, string_regcomp (®ex, "(?ins)test", REG_EXTENDED)); regfree (®ex); }
char * eval_compare (const char *expr1, int comparison, const char *expr2) { int rc, string_compare, length1, length2; regex_t regex; long value1, value2; char *error; rc = 0; string_compare = 0; if (!expr1 || !expr2) goto end; if ((comparison == EVAL_COMPARE_REGEX_MATCHING) || (comparison == EVAL_COMPARE_REGEX_NOT_MATCHING)) { if (string_regcomp (®ex, expr2, REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) { goto end; } rc = (regexec (®ex, expr1, 0, NULL, 0) == 0) ? 1 : 0; regfree (®ex); if (comparison == EVAL_COMPARE_REGEX_NOT_MATCHING) rc ^= 1; goto end; } length1 = strlen (expr1); length2 = strlen (expr2); /* * string comparison is forced if expr1 and expr2 have double quotes at * beginning/end */ if (((length1 == 0) || ((expr1[0] == '"') && expr1[length1 - 1] == '"')) && ((length2 == 0) || ((expr2[0] == '"') && expr2[length2 - 1] == '"'))) { string_compare = 1; } if (!string_compare) { value1 = strtol (expr1, &error, 10); if (!error || error[0]) string_compare = 1; else { value2 = strtol (expr2, &error, 10); if (!error || error[0]) string_compare = 1; } } if (string_compare) rc = strcmp (expr1, expr2); else rc = (value1 < value2) ? -1 : ((value1 > value2) ? 1 : 0); switch (comparison) { case EVAL_COMPARE_EQUAL: rc = (rc == 0); break; case EVAL_COMPARE_NOT_EQUAL: rc = (rc != 0); break; case EVAL_COMPARE_LESS_EQUAL: rc = (rc <= 0); break; case EVAL_COMPARE_LESS: rc = (rc < 0); break; case EVAL_COMPARE_GREATER_EQUAL: rc = (rc >= 0); break; case EVAL_COMPARE_GREATER: rc = (rc > 0); break; case EVAL_NUM_COMPARISONS: break; } end: return strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); }
char * eval_expression (const char *expr, struct t_hashtable *pointers, struct t_hashtable *extra_vars, struct t_hashtable *options) { int condition, extra_vars_eval, rc, pointers_allocated, regex_allocated; char *value; const char *prefix, *suffix; const char *default_prefix = EVAL_DEFAULT_PREFIX; const char *default_suffix = EVAL_DEFAULT_SUFFIX; const char *ptr_value, *regex_replace; struct t_gui_window *window; regex_t *regex; if (!expr) return NULL; condition = 0; extra_vars_eval = 0; pointers_allocated = 0; regex_allocated = 0; prefix = default_prefix; suffix = default_suffix; regex = NULL; regex_replace = NULL; if (pointers) { regex = (regex_t *)hashtable_get (pointers, "regex"); } else { /* create hashtable pointers if it's NULL */ pointers = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, NULL, NULL); if (!pointers) return NULL; pointers_allocated = 1; } /* * set window/buffer with pointer to current window/buffer * (if not already defined in the hashtable) */ if (gui_current_window) { if (!hashtable_has_key (pointers, "window")) hashtable_set (pointers, "window", gui_current_window); if (!hashtable_has_key (pointers, "buffer")) { window = (struct t_gui_window *)hashtable_get (pointers, "window"); if (window) hashtable_set (pointers, "buffer", window->buffer); } } /* read options */ if (options) { /* check the type of evaluation */ ptr_value = hashtable_get (options, "type"); if (ptr_value && (strcmp (ptr_value, "condition") == 0)) condition = 1; /* check if extra vars must be evaluated */ ptr_value = hashtable_get (options, "extra"); if (ptr_value && (strcmp (ptr_value, "eval") == 0)) extra_vars_eval = 1; /* check for custom prefix */ ptr_value = hashtable_get (options, "prefix"); if (ptr_value && ptr_value[0]) prefix = ptr_value; /* check for custom suffix */ ptr_value = hashtable_get (options, "suffix"); if (ptr_value && ptr_value[0]) suffix = ptr_value; /* check for regex */ ptr_value = hashtable_get (options, "regex"); if (ptr_value) { regex = malloc (sizeof (*regex)); if (string_regcomp (regex, ptr_value, REG_EXTENDED | REG_ICASE) == 0) { regex_allocated = 1; } else { free (regex); regex = NULL; } } /* check for regex replacement (evaluated later) */ ptr_value = hashtable_get (options, "regex_replace"); if (ptr_value) { regex_replace = ptr_value; } } /* evaluate expression */ if (condition) { /* evaluate as condition (return a boolean: "0" or "1") */ value = eval_expression_condition (expr, pointers, extra_vars, extra_vars_eval, prefix, suffix); rc = eval_is_true (value); if (value) free (value); value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); } else { if (regex && regex_replace) { /* replace with regex */ value = eval_replace_regex (expr, regex, regex_replace, pointers, extra_vars, extra_vars_eval, prefix, suffix); } else { /* only replace variables in expression */ value = eval_replace_vars (expr, pointers, extra_vars, extra_vars_eval, prefix, suffix, NULL); } } if (pointers_allocated) hashtable_free (pointers); if (regex && regex_allocated) { regfree (regex); free (regex); } return value; }
struct t_gui_filter * gui_filter_new (int enabled, const char *name, const char *buffer_name, const char *tags, const char *regex) { struct t_gui_filter *new_filter; regex_t *regex1, *regex2; char *pos_tab, *regex_prefix; const char *ptr_start_regex, *pos_regex_message; if (!name || !buffer_name || !tags || !regex) return NULL; if (gui_filter_search_by_name (name)) return NULL; ptr_start_regex = regex; if ((ptr_start_regex[0] == '!') || ((ptr_start_regex[0] == '\\') && (ptr_start_regex[1] == '!'))) { ptr_start_regex++; } regex1 = NULL; regex2 = NULL; if (strcmp (ptr_start_regex, "*") != 0) { pos_tab = strstr (ptr_start_regex, "\\t"); if (pos_tab) { regex_prefix = string_strndup (ptr_start_regex, pos_tab - ptr_start_regex); pos_regex_message = pos_tab + 2; } else { regex_prefix = NULL; pos_regex_message = ptr_start_regex; } if (regex_prefix) { regex1 = malloc (sizeof (*regex1)); if (regex1) { if (string_regcomp (regex1, regex_prefix, REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) { free (regex_prefix); free (regex1); return NULL; } } } regex2 = malloc (sizeof (*regex2)); if (regex2) { if (string_regcomp (regex2, pos_regex_message, REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) { if (regex_prefix) free (regex_prefix); if (regex1) free (regex1); free (regex2); return NULL; } } if (regex_prefix) free (regex_prefix); } /* create new filter */ new_filter = malloc (sizeof (*new_filter)); if (new_filter) { /* init filter */ new_filter->enabled = enabled; new_filter->name = strdup (name); new_filter->buffer_name = strdup ((buffer_name) ? buffer_name : "*"); new_filter->buffers = string_split (new_filter->buffer_name, ",", 0, 0, &new_filter->num_buffers); if (tags) { new_filter->tags = (tags) ? strdup (tags) : NULL; new_filter->tags_array = string_split (tags, ",", 0, 0, &new_filter->tags_count); } else { new_filter->tags = NULL; new_filter->tags_count = 0; new_filter->tags_array = NULL; } new_filter->regex = strdup (regex); new_filter->regex_prefix = regex1; new_filter->regex_message = regex2; /* add filter to filters list */ new_filter->prev_filter = last_gui_filter; if (gui_filters) last_gui_filter->next_filter = new_filter; else gui_filters = new_filter; last_gui_filter = new_filter; new_filter->next_filter = NULL; hook_signal_send ("filter_added", WEECHAT_HOOK_SIGNAL_POINTER, new_filter); } return new_filter; }
struct t_gui_filter * gui_filter_new (int enabled, const char *name, const char *buffer_name, const char *tags, const char *regex) { struct t_gui_filter *new_filter; regex_t *regex1, *regex2; char *pos_tab, *regex_prefix, **tags_array, buf[512], str_error[512]; const char *ptr_start_regex, *pos_regex_message; int i, rc; if (!name || !buffer_name || !tags || !regex) { gui_filter_new_error (name, _("not enough arguments")); return NULL; } if (gui_filter_search_by_name (name)) { gui_filter_new_error (name, _("a filter with same name already exists")); return NULL; } ptr_start_regex = regex; if ((ptr_start_regex[0] == '!') || ((ptr_start_regex[0] == '\\') && (ptr_start_regex[1] == '!'))) { ptr_start_regex++; } regex1 = NULL; regex2 = NULL; if (strcmp (ptr_start_regex, "*") != 0) { pos_tab = strstr (ptr_start_regex, "\\t"); if (pos_tab) { regex_prefix = string_strndup (ptr_start_regex, pos_tab - ptr_start_regex); pos_regex_message = pos_tab + 2; } else { regex_prefix = NULL; pos_regex_message = ptr_start_regex; } if (regex_prefix && regex_prefix[0]) { regex1 = malloc (sizeof (*regex1)); if (regex1) { rc = string_regcomp (regex1, regex_prefix, REG_EXTENDED | REG_ICASE | REG_NOSUB); if (rc != 0) { regerror (rc, regex1, buf, sizeof (buf)); snprintf (str_error, sizeof (str_error), /* TRANSLATORS: %s is the error returned by regerror */ _("invalid regular expression (%s)"), buf); gui_filter_new_error (name, str_error); free (regex_prefix); free (regex1); return NULL; } } } if (pos_regex_message && pos_regex_message[0]) { regex2 = malloc (sizeof (*regex2)); if (regex2) { rc = string_regcomp (regex2, pos_regex_message, REG_EXTENDED | REG_ICASE | REG_NOSUB); if (rc != 0) { regerror (rc, regex2, buf, sizeof (buf)); snprintf (str_error, sizeof (str_error), /* TRANSLATORS: %s is the error returned by regerror */ _("invalid regular expression (%s)"), buf); gui_filter_new_error (name, str_error); if (regex_prefix) free (regex_prefix); if (regex1) { regfree (regex1); free (regex1); } free (regex2); return NULL; } } } if (regex_prefix) free (regex_prefix); } /* create new filter */ new_filter = malloc (sizeof (*new_filter)); if (new_filter) { /* init filter */ new_filter->enabled = enabled; new_filter->name = strdup (name); new_filter->buffer_name = strdup ((buffer_name) ? buffer_name : "*"); new_filter->buffers = string_split (new_filter->buffer_name, ",", 0, 0, &new_filter->num_buffers); new_filter->tags = (tags) ? strdup (tags) : NULL; new_filter->tags_count = 0; new_filter->tags_array = NULL; if (new_filter->tags) { tags_array = string_split (new_filter->tags, ",", 0, 0, &new_filter->tags_count); if (tags_array) { new_filter->tags_array = malloc (new_filter->tags_count * sizeof (*new_filter->tags_array)); if (new_filter->tags_array) { for (i = 0; i < new_filter->tags_count; i++) { new_filter->tags_array[i] = string_split (tags_array[i], "+", 0, 0, NULL); } } string_free_split (tags_array); } } new_filter->regex = strdup (regex); new_filter->regex_prefix = regex1; new_filter->regex_message = regex2; /* add filter to filters list */ new_filter->prev_filter = last_gui_filter; if (gui_filters) last_gui_filter->next_filter = new_filter; else gui_filters = new_filter; last_gui_filter = new_filter; new_filter->next_filter = NULL; (void) hook_signal_send ("filter_added", WEECHAT_HOOK_SIGNAL_POINTER, new_filter); } else { gui_filter_new_error (name, _("not enough memory")); } return new_filter; }
TEST(Eval, EvalReplaceRegex) { struct t_hashtable *pointers, *extra_vars, *options; char *value; regex_t regex; pointers = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, NULL, NULL); CHECK(pointers); extra_vars = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); CHECK(extra_vars); hashtable_set (extra_vars, "test", "value"); options = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); CHECK(options); /* replace regex by empty string */ hashtable_remove (pointers, "regex"); hashtable_set (options, "regex", ".*"); hashtable_set (options, "regex_replace", ""); WEE_CHECK_EVAL("", "test"); /* replace empty regex */ hashtable_remove (pointers, "regex"); hashtable_set (options, "regex", ""); hashtable_set (options, "regex_replace", "abc"); WEE_CHECK_EVAL("test", "test"); /* replace empty regex by empty string */ hashtable_remove (pointers, "regex"); hashtable_set (options, "regex", ""); hashtable_set (options, "regex_replace", ""); WEE_CHECK_EVAL("test", "test"); /* add brackets around URLs (regex as string) */ hashtable_remove (pointers, "regex"); hashtable_set (options, "regex", "\\w+://\\S+"); hashtable_set (options, "regex_replace", "[ ${re:0} ]"); WEE_CHECK_EVAL("test: [ https://weechat.org ]", "test: https://weechat.org"); /* add brackets around URLs (compiled regex) */ LONGS_EQUAL(0, string_regcomp (®ex, "\\w+://\\S+", REG_EXTENDED | REG_ICASE)); hashtable_set (pointers, "regex", ®ex); hashtable_remove (options, "regex"); hashtable_set (options, "regex_replace", "[ ${re:0} ]"); WEE_CHECK_EVAL("test: [ https://weechat.org ]", "test: https://weechat.org"); regfree (®ex); /* hide passwords (regex as string) */ hashtable_remove (pointers, "regex"); hashtable_set (options, "regex", "(password=)(\\S+)"); hashtable_set (options, "regex_replace", "${re:1}${hide:*,${re:2}}"); WEE_CHECK_EVAL("password=*** password=***", "password=abc password=def"); /* hide passwords (compiled regex) */ LONGS_EQUAL(0, string_regcomp (®ex, "(password=)(\\S+)", REG_EXTENDED | REG_ICASE)); hashtable_set (pointers, "regex", ®ex); hashtable_remove (options, "regex"); hashtable_set (options, "regex_replace", "${re:1}${hide:*,${re:2}}"); WEE_CHECK_EVAL("password=*** password=***", "password=abc password=def"); regfree (®ex); hashtable_free (pointers); hashtable_free (extra_vars); hashtable_free (options); }