diff --git a/src/core/core.c b/src/core/core.c index 85f3a5d5..34649c81 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -34,16 +34,17 @@ #endif #include -#include #include #include #include -#include +#include #include #include -#include #include #include +#include +#include +#include #include #include @@ -262,6 +263,7 @@ void core_init(void) chat_commands_init(); i_refstr_init(); + special_vars_init(); wcwidth_wrapper_init(); settings_add_str("misc", "ignore_signals", ""); @@ -288,6 +290,7 @@ void core_deinit(void) signal_remove("irssi init finished", (SIGNAL_FUNC) sig_irssi_init_finished); wcwidth_wrapper_deinit(); + special_vars_deinit(); i_refstr_deinit(); chat_commands_deinit(); diff --git a/src/core/special-vars.c b/src/core/special-vars.c index ef56e2e1..802fcb36 100644 --- a/src/core/special-vars.c +++ b/src/core/special-vars.c @@ -19,12 +19,13 @@ */ #include "module.h" +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include #define isvarchar(c) \ @@ -40,6 +41,8 @@ #endif static SPECIAL_HISTORY_FUNC history_func = NULL; +static GSList *special_collector; +static GSList *special_cache; static char *get_argument(char **cmd, char **arglist) { @@ -121,8 +124,40 @@ static char *get_long_variable_value(const char *key, SERVER_REC *server, return NULL; } -static char *get_long_variable(char **cmd, SERVER_REC *server, - void *item, int *free_ret, int getname) +static gboolean cache_find(GSList **cache, const char *var, char **ret) +{ + GSList *tmp; + GSList *prev = NULL; + + if (cache == NULL) + return FALSE; + + for (tmp = *cache; tmp;) { + if (g_strcmp0(var, tmp->data) == 0) { + *ret = tmp->next->data; + if (prev != NULL) + prev->next->next = tmp->next->next; + else + *cache = tmp->next->next; + + g_slist_free_1(tmp->next); + g_slist_free_1(tmp); + return TRUE; + } + prev = tmp; + tmp = tmp->next->next; + } + return FALSE; +} + +static gboolean cache_find_char(GSList **cache, char var, char **ret) +{ + char varn[] = { var, '\0' }; + return cache_find(cache, varn, ret); +} + +static char *get_long_variable(char **cmd, SERVER_REC *server, void *item, int *free_ret, + int getname, GSList **collector, GSList **cache) { char *start, *var, *ret; @@ -135,16 +170,23 @@ static char *get_long_variable(char **cmd, SERVER_REC *server, *free_ret = TRUE; return var; } + if (cache_find(cache, var, &ret)) { + g_free(var); + return ret; + } ret = get_long_variable_value(var, server, item, free_ret); + if (collector != NULL) { + *collector = g_slist_prepend(*collector, g_strdup(ret)); + *collector = g_slist_prepend(*collector, i_refstr_intern(var)); + } g_free(var); return ret; } /* return the value of the variable found from `cmd'. if 'getname' is TRUE, return the name of the variable instead it's value */ -static char *get_variable(char **cmd, SERVER_REC *server, void *item, - char **arglist, int *free_ret, int *arg_used, - int getname) +static char *get_variable(char **cmd, SERVER_REC *server, void *item, char **arglist, int *free_ret, + int *arg_used, int getname, GSList **collector, GSList **cache) { EXPANDO_FUNC func; @@ -158,7 +200,7 @@ static char *get_variable(char **cmd, SERVER_REC *server, void *item, if (i_isalpha(**cmd) && isvarchar((*cmd)[1])) { /* long variable name.. */ - return get_long_variable(cmd, server, item, free_ret, getname); + return get_long_variable(cmd, server, item, free_ret, getname, collector, cache); } /* single character variable. */ @@ -167,15 +209,27 @@ static char *get_variable(char **cmd, SERVER_REC *server, void *item, return g_strdup_printf("%c", **cmd); } *free_ret = FALSE; + { + char *ret; + if (cache_find_char(cache, **cmd, &ret)) { + return ret; + } + } func = expando_find_char(**cmd); if (func == NULL) return NULL; else { char str[2]; + char *ret; str[0] = **cmd; str[1] = '\0'; current_expando = str; - return func(server, item, free_ret); + ret = func(server, item, free_ret); + if (**cmd != 'Z' && collector != NULL) { + *collector = g_slist_prepend(*collector, g_strdup(ret)); + *collector = g_slist_prepend(*collector, i_refstr_intern(str)); + } + return ret; } } @@ -199,9 +253,9 @@ static char *get_history(char **cmd, void *item, int *free_ret) return ret; } -static char *get_special_value(char **cmd, SERVER_REC *server, void *item, - char **arglist, int *free_ret, int *arg_used, - int flags) +static char *get_special_value(char **cmd, SERVER_REC *server, void *item, char **arglist, + int *free_ret, int *arg_used, int flags, GSList **collector, + GSList **cache) { char command, *value, *p; int len; @@ -236,8 +290,8 @@ static char *get_special_value(char **cmd, SERVER_REC *server, void *item, } } - value = get_variable(cmd, server, item, arglist, free_ret, - arg_used, flags & PARSE_FLAG_GETNAME); + value = get_variable(cmd, server, item, arglist, free_ret, arg_used, + flags & PARSE_FLAG_GETNAME, collector, cache); if (flags & PARSE_FLAG_GETNAME) return value; @@ -440,8 +494,9 @@ char *parse_special(char **cmd, SERVER_REC *server, void *item, brackets = TRUE; } - value = get_special_value(cmd, server, item, arglist, - free_ret, arg_used, flags); + value = get_special_value(cmd, server, item, arglist, free_ret, arg_used, flags, + special_collector != NULL ? special_collector->data : NULL, + &special_cache); if (**cmd == '\0') g_error("parse_special() : buffer overflow!"); @@ -635,6 +690,22 @@ void special_history_func_set(SPECIAL_HISTORY_FUNC func) history_func = func; } +void special_push_collector(GSList **list) +{ + special_collector = g_slist_prepend(special_collector, list); +} + +void special_pop_collector(void) +{ + special_collector = g_slist_delete_link(special_collector, special_collector); +} + +void special_fill_cache(GSList *list) +{ + g_slist_free(special_cache); + special_cache = g_slist_copy(list); +} + static void update_signals_hash(GHashTable **hash, int *signals) { void *signal_id; @@ -758,3 +829,15 @@ int *special_vars_get_signals(const char *text) { return special_vars_signals_task(text, 0, NULL, TASK_GET_SIGNALS); } + +void special_vars_init(void) +{ + special_cache = NULL; + special_collector = NULL; +} + +void special_vars_deinit(void) +{ + g_slist_free(special_cache); + g_slist_free(special_collector); +} diff --git a/src/core/special-vars.h b/src/core/special-vars.h index f4bd926d..87aba7d6 100644 --- a/src/core/special-vars.h +++ b/src/core/special-vars.h @@ -32,6 +32,11 @@ char *parse_special_string(const char *cmd, SERVER_REC *server, void *item, void eval_special_string(const char *cmd, const char *data, SERVER_REC *server, void *item); +void special_push_collector(GSList **list); +void special_pop_collector(void); + +void special_fill_cache(GSList *list); + void special_history_func_set(SPECIAL_HISTORY_FUNC func); void special_vars_add_signals(const char *text, @@ -41,4 +46,8 @@ void special_vars_remove_signals(const char *text, /* Returns [, EXPANDO_ARG_xxx, , ..., -1] */ int *special_vars_get_signals(const char *text); +void special_vars_init(void); + +void special_vars_deinit(void); + #endif diff --git a/src/fe-text/textbuffer-formats.c b/src/fe-text/textbuffer-formats.c index 599a85c6..e0a5f193 100644 --- a/src/fe-text/textbuffer-formats.c +++ b/src/fe-text/textbuffer-formats.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,18 @@ TEXT_BUFFER_REC *color_buf; +static void collector_free(GSList **collector) +{ + while (*collector) { + GSList *next = (*collector)->next->next; + i_refstr_release((*collector)->data); + g_free((*collector)->next->data); + g_slist_free_1((*collector)->next); + g_slist_free_1((*collector)); + *collector = next; + } +} + void textbuffer_format_rec_free(TEXT_BUFFER_FORMAT_REC *rec) { int n; @@ -35,6 +48,7 @@ void textbuffer_format_rec_free(TEXT_BUFFER_FORMAT_REC *rec) } rec->nargs = 0; g_free(rec->args); + collector_free(&rec->expando_cache); g_slice_free(TEXT_BUFFER_FORMAT_REC, rec); } @@ -112,12 +126,14 @@ static void sig_print_format(THEME_REC *theme, const char *module, TEXT_DEST_REC info->format = format_rec_new(module, formats[formatnum].tag, dest->server_tag, dest->target, dest->nick, formats[formatnum].params, args); + special_push_collector(&info->format->expando_cache); info->format->flags = dest->flags; dest->flags |= PRINT_FLAG_FORMAT; signal_continue(5, theme, module, dest, formatnump, args); + special_pop_collector(); free_lineinfo_tmp(dest->window); } @@ -125,19 +141,36 @@ static void sig_print_noformat(TEXT_DEST_REC *dest, const char *text) { LINE_INFO_REC *info; + special_push_collector(NULL); info = store_lineinfo_tmp(dest); info->format = format_rec_new(NULL, NULL, dest->server_tag, dest->target, dest->nick, 2, (const char *[]){ NULL, text }); + special_push_collector(&info->format->expando_cache); info->format->flags = dest->flags; dest->flags |= PRINT_FLAG_FORMAT; signal_continue(2, dest, text); + special_pop_collector(); free_lineinfo_tmp(dest->window); } +static GSList *reverse_collector(GSList *a1) +{ + GSList *b1, *c1; + c1 = NULL; + while (a1) { + b1 = a1->next->next; + a1->next->next = c1; + + c1 = a1; + a1 = b1; + } + return c1; +} + static void sig_gui_print_text_finished(WINDOW_REC *window) { GUI_WINDOW_REC *gui; @@ -157,6 +190,8 @@ static void sig_gui_print_text_finished(WINDOW_REC *window) if (info->format == NULL) return; + info->format->expando_cache = reverse_collector(info->format->expando_cache); + info->level |= MSGLEVEL_FORMAT; /* the line will be inserted into the view with textbuffer_view_insert_line by @@ -182,7 +217,7 @@ char *textbuffer_line_get_text(TEXT_BUFFER_REC *buffer, LINE_REC *line) if (line == NULL || gui == NULL) return NULL; - if (line->info.level & MSGLEVEL_FORMAT) { + if (line->info.level & MSGLEVEL_FORMAT && line->info.format != NULL) { TEXT_DEST_REC dest; THEME_REC *theme; int formatnum; @@ -200,6 +235,7 @@ char *textbuffer_line_get_text(TEXT_BUFFER_REC *buffer, LINE_REC *line) theme = window_get_theme(dest.window); + special_fill_cache(format_rec->expando_cache); if (format_rec->format != NULL) { char *arglist[MAX_FORMAT_PARAMS] = { 0 }; formatnum = format_find_tag(format_rec->module, format_rec->format); @@ -238,6 +274,7 @@ char *textbuffer_line_get_text(TEXT_BUFFER_REC *buffer, LINE_REC *line) } else { return text; } + special_fill_cache(NULL); } else { return g_strdup(line->info.text); } diff --git a/src/fe-text/textbuffer-formats.h b/src/fe-text/textbuffer-formats.h index 5a156fda..45e4ce1b 100644 --- a/src/fe-text/textbuffer-formats.h +++ b/src/fe-text/textbuffer-formats.h @@ -11,6 +11,7 @@ typedef struct _TEXT_BUFFER_FORMAT_REC { char *nick; char **args; int nargs; + GSList *expando_cache; int flags; } TEXT_BUFFER_FORMAT_REC;