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; }
char * eval_expression_condition (const char *expr, struct t_hashtable *pointers, struct t_hashtable *extra_vars, int extra_vars_eval, const char *prefix, const char *suffix) { int logic, comp, length, level, rc; const char *pos, *pos_end; char *expr2, *sub_expr, *value, *tmp_value, *tmp_value2; value = NULL; if (!expr) return NULL; if (!expr[0]) return strdup (expr); /* skip spaces at beginning of string */ while (expr[0] == ' ') { expr++; } if (!expr[0]) return strdup (expr); /* skip spaces at end of string */ pos_end = expr + strlen (expr) - 1; while ((pos_end > expr) && (pos_end[0] == ' ')) { pos_end--; } expr2 = string_strndup (expr, pos_end + 1 - expr); if (!expr2) return NULL; /* * search for a logical operator, and if one is found: * - split expression into two sub-expressions * - evaluate first sub-expression * - if needed, evaluate second sub-expression * - return result */ for (logic = 0; logic < EVAL_NUM_LOGICAL_OPS; logic++) { pos = eval_strstr_level (expr2, logical_ops[logic]); if (pos > expr2) { pos_end = pos - 1; while ((pos_end > expr2) && (pos_end[0] == ' ')) { pos_end--; } sub_expr = string_strndup (expr2, pos_end + 1 - expr2); if (!sub_expr) goto end; tmp_value = eval_expression_condition (sub_expr, pointers, extra_vars, extra_vars_eval, prefix, suffix); free (sub_expr); rc = eval_is_true (tmp_value); if (tmp_value) free (tmp_value); /* * if rc == 0 with "&&" or rc == 1 with "||", no need to * evaluate second sub-expression, just return the rc */ if ((!rc && (logic == EVAL_LOGICAL_OP_AND)) || (rc && (logic == EVAL_LOGICAL_OP_OR))) { value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); goto end; } pos += strlen (logical_ops[logic]); while (pos[0] == ' ') { pos++; } tmp_value = eval_expression_condition (pos, pointers, extra_vars, extra_vars_eval, prefix, suffix); rc = eval_is_true (tmp_value); if (tmp_value) free (tmp_value); value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); goto end; } } /* * search for a comparison, and if one is found: * - split expression into two sub-expressions * - evaluate the two sub-expressions * - compare sub-expressions * - return result */ for (comp = 0; comp < EVAL_NUM_COMPARISONS; comp++) { pos = eval_strstr_level (expr2, comparisons[comp]); if (pos > expr2) { pos_end = pos - 1; while ((pos_end > expr2) && (pos_end[0] == ' ')) { pos_end--; } sub_expr = string_strndup (expr2, pos_end + 1 - expr2); if (!sub_expr) goto end; pos += strlen (comparisons[comp]); while (pos[0] == ' ') { pos++; } if ((comp == EVAL_COMPARE_REGEX_MATCHING) || (comp == EVAL_COMPARE_REGEX_NOT_MATCHING)) { /* for regex: just replace vars in both expressions */ tmp_value = eval_replace_vars (sub_expr, pointers, extra_vars, extra_vars_eval, prefix, suffix, NULL); tmp_value2 = eval_replace_vars (pos, pointers, extra_vars, extra_vars_eval, prefix, suffix, NULL); } else { /* other comparison: fully evaluate both expressions */ tmp_value = eval_expression_condition (sub_expr, pointers, extra_vars, extra_vars_eval, prefix, suffix); tmp_value2 = eval_expression_condition (pos, pointers, extra_vars, extra_vars_eval, prefix, suffix); } free (sub_expr); value = eval_compare (tmp_value, comp, tmp_value2); if (tmp_value) free (tmp_value); if (tmp_value2) free (tmp_value2); goto end; } } /* * evaluate sub-expressions between parentheses and replace them with their * value */ while (expr2[0] == '(') { level = 0; pos = expr2 + 1; while (pos[0]) { if (pos[0] == '(') level++; else if (pos[0] == ')') { if (level == 0) break; level--; } pos++; } /* closing parenthesis not found */ if (pos[0] != ')') goto end; sub_expr = string_strndup (expr2 + 1, pos - expr2 - 1); if (!sub_expr) goto end; tmp_value = eval_expression_condition (sub_expr, pointers, extra_vars, extra_vars_eval, prefix, suffix); free (sub_expr); if (!pos[1]) { /* * nothing around parentheses, then return value of * sub-expression as-is */ value = tmp_value; goto end; } length = ((tmp_value) ? strlen (tmp_value) : 0) + 1 + strlen (pos + 1) + 1; tmp_value2 = malloc (length); if (!tmp_value2) { if (tmp_value) free (tmp_value); goto end; } tmp_value2[0] = '\0'; if (tmp_value) strcat (tmp_value2, tmp_value); strcat (tmp_value2, " "); strcat (tmp_value2, pos + 1); free (expr2); expr2 = tmp_value2; if (tmp_value) free (tmp_value); } /* * at this point, there is no more logical operator neither comparison, * so we just replace variables in string and return the result */ value = eval_replace_vars (expr2, pointers, extra_vars, extra_vars_eval, prefix, suffix, NULL); end: if (expr2) free (expr2); return value; }
char * eval_expression (const char *expr, struct t_hashtable *pointers, struct t_hashtable *extra_vars, struct t_hashtable *options) { int condition, rc, pointers_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; struct t_gui_window *window; if (!expr) return NULL; condition = 0; pointers_allocated = 0; prefix = default_prefix; suffix = default_suffix; /* create hashtable pointers if it's NULL */ if (!pointers) { 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 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; } /* evaluate expression */ if (condition) { /* evaluate as condition (return a boolean: "0" or "1") */ value = eval_expression_condition (expr, pointers, extra_vars, prefix, suffix); rc = eval_is_true (value); if (value) free (value); value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); } else { /* only replace variables in expression */ value = eval_replace_vars (expr, pointers, extra_vars, prefix, suffix); } if (pointers_allocated) hashtable_free (pointers); return value; }