summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/chat-commands.c2
-rw-r--r--src/core/expandos.c90
-rw-r--r--src/core/expandos.h4
-rw-r--r--src/core/signals.c21
-rw-r--r--src/core/signals.h1
-rw-r--r--src/core/special-vars.c96
-rw-r--r--src/core/special-vars.h13
7 files changed, 191 insertions, 36 deletions
diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c
index f2cae1ab..969be382 100644
--- a/src/core/chat-commands.c
+++ b/src/core/chat-commands.c
@@ -81,7 +81,7 @@ static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
free_ret = FALSE;
if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0) {
target = parse_special(&target, server, item,
- NULL, &free_ret, NULL);
+ NULL, &free_ret, NULL, 0);
} else if (strcmp(target, "*") == 0 && item != NULL)
target = item->name;
diff --git a/src/core/expandos.c b/src/core/expandos.c
index 1dbd95ac..37f770a3 100644
--- a/src/core/expandos.c
+++ b/src/core/expandos.c
@@ -44,6 +44,8 @@ typedef struct {
int signal_args[MAX_EXPANDO_SIGNALS];
} EXPANDO_REC;
+static int timer_tag;
+
static EXPANDO_REC *char_expandos[127];
static GHashTable *expandos;
static time_t client_start_time;
@@ -86,6 +88,14 @@ void expando_create(const char *key, EXPANDO_FUNC func, ...)
va_end(va);
}
+static EXPANDO_REC *expando_find(const char *key)
+{
+ if (key[1] != '\0')
+ return g_hash_table_lookup(expandos, key);
+ else
+ return char_expandos[(int) *key];
+}
+
/* Add new signal to expando */
void expando_add_signal(const char *key, const char *signal, ExpandoArg arg)
{
@@ -94,15 +104,15 @@ void expando_add_signal(const char *key, const char *signal, ExpandoArg arg)
g_return_if_fail(key != NULL);
g_return_if_fail(signal != NULL);
- if (key[1] != '\0')
- rec = g_hash_table_lookup(expandos, key);
- else {
- /* single character expando */
- rec = char_expandos[(int) *key];
- }
+ rec = expando_find(key);
g_return_if_fail(rec != NULL);
- if (rec->signals < MAX_EXPANDO_SIGNALS) {
+ if (arg == EXPANDO_NEVER) {
+ /* expando changes never */
+ rec->signals = -1;
+ } else if (rec->signals < MAX_EXPANDO_SIGNALS) {
+ g_return_if_fail(rec->signals != -1);
+
rec->signal_ids[rec->signals] = signal_get_uniq_id(signal);
rec->signal_args[rec->signals] = arg;
rec->signals++;
@@ -135,6 +145,64 @@ void expando_destroy(const char *key, EXPANDO_FUNC func)
}
}
+void expando_bind(const char *key, int funccount, SIGNAL_FUNC *funcs)
+{
+ SIGNAL_FUNC func;
+ EXPANDO_REC *rec;
+ int n, arg;
+
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(funccount >= 1);
+ g_return_if_fail(funcs != NULL);
+ g_return_if_fail(funcs[0] != NULL);
+
+ rec = expando_find(key);
+ g_return_if_fail(rec != NULL);
+
+ if (rec->signals == 0) {
+ /* it's unknown when this expando changes..
+ check it once in a second */
+ signal_add("expando timer", funcs[EXPANDO_ARG_NONE]);
+ }
+
+ for (n = 0; n < rec->signals; n++) {
+ arg = rec->signal_args[n];
+ func = arg < funccount ? funcs[arg] : NULL;
+ if (func == NULL) func = funcs[EXPANDO_ARG_NONE];
+
+ signal_add_to_id(MODULE_NAME, 1, rec->signal_ids[n], func);
+ }
+}
+
+void expando_unbind(const char *key, int funccount, SIGNAL_FUNC *funcs)
+{
+ SIGNAL_FUNC func;
+ EXPANDO_REC *rec;
+ int n, arg;
+
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(funccount >= 1);
+ g_return_if_fail(funcs != NULL);
+ g_return_if_fail(funcs[0] != NULL);
+
+ rec = expando_find(key);
+ g_return_if_fail(rec != NULL);
+
+ if (rec->signals == 0) {
+ /* it's unknown when this expando changes..
+ check it once in a second */
+ signal_remove("expando timer", funcs[EXPANDO_ARG_NONE]);
+ }
+
+ for (n = 0; n < rec->signals; n++) {
+ arg = rec->signal_args[n];
+ func = arg < funccount ? funcs[arg] : NULL;
+ if (func == NULL) func = funcs[EXPANDO_ARG_NONE];
+
+ signal_remove_id(rec->signal_ids[n], func);
+ }
+}
+
EXPANDO_FUNC expando_find_char(char chr)
{
g_return_val_if_fail(chr < sizeof(char_expandos) /
@@ -360,6 +428,12 @@ static void cmd_msg(const char *data, SERVER_REC *server)
cmd_params_free(free_arg);
}
+static int sig_timer(void)
+{
+ signal_emit("expando timer", 0);
+ return 1;
+}
+
void expandos_init(void)
{
#ifdef HAVE_SYS_UTSNAME_H
@@ -455,6 +529,7 @@ void expandos_init(void)
"window changed", EXPANDO_ARG_NONE,
"window server changed", EXPANDO_ARG_WINDOW, NULL);
+ timer_tag = g_timeout_add(1000, (GSourceFunc) sig_timer, NULL);
signal_add("command msg", (SIGNAL_FUNC) cmd_msg);
signal_add("message public", (SIGNAL_FUNC) sig_message_public);
signal_add("message private", (SIGNAL_FUNC) sig_message_private);
@@ -479,6 +554,7 @@ void expandos_deinit(void)
g_free_not_null(last_privmsg_from); g_free_not_null(last_public_from);
g_free_not_null(sysname); g_free_not_null(sysrelease);
+ g_source_remove(timer_tag);
signal_remove("message public", (SIGNAL_FUNC) sig_message_public);
signal_remove("message private", (SIGNAL_FUNC) sig_message_private);
signal_remove("command msg", (SIGNAL_FUNC) cmd_msg);
diff --git a/src/core/expandos.h b/src/core/expandos.h
index 2ce00ecc..a937fcd1 100644
--- a/src/core/expandos.h
+++ b/src/core/expandos.h
@@ -1,6 +1,7 @@
#ifndef __EXPANDOS_H
#define __EXPANDOS_H
+#include "signals.h"
#include "servers.h"
/* first argument of signal must match to active .. */
@@ -25,6 +26,9 @@ void expando_add_signal(const char *key, const char *signal, ExpandoArg arg);
/* Destroy expando */
void expando_destroy(const char *key, EXPANDO_FUNC func);
+void expando_bind(const char *key, int funccount, SIGNAL_FUNC *funcs);
+void expando_unbind(const char *key, int funccount, SIGNAL_FUNC *funcs);
+
/* internal: */
EXPANDO_FUNC expando_find_char(char chr);
EXPANDO_FUNC expando_find_long(const char *key);
diff --git a/src/core/signals.c b/src/core/signals.c
index 710d0687..3c1e4281 100644
--- a/src/core/signals.c
+++ b/src/core/signals.c
@@ -146,25 +146,24 @@ static int signal_remove_from_lists(SIGNAL_REC *rec, int signal_id,
return 0;
}
-/* unbind signal */
-void signal_remove(const char *signal, SIGNAL_FUNC func)
+void signal_remove_id(int signal_id, SIGNAL_FUNC func)
{
SIGNAL_REC *rec;
- int signal_id, found;
- g_return_if_fail(signal != NULL);
+ g_return_if_fail(signal_id >= 0);
g_return_if_fail(func != NULL);
- signal_id = signal_get_uniq_id(signal);
-
rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id));
- found = rec == NULL ? 0 :
+ if (rec != NULL)
signal_remove_from_lists(rec, signal_id, func);
+}
- if (!found) {
- g_warning("signal_remove() : signal \"%s\" isn't "
- "grabbed for %p", signal, func);
- }
+/* unbind signal */
+void signal_remove(const char *signal, SIGNAL_FUNC func)
+{
+ g_return_if_fail(signal != NULL);
+
+ signal_remove_id(signal_get_uniq_id(signal), func);
}
/* Remove all NULL functions from signal list */
diff --git a/src/core/signals.h b/src/core/signals.h
index 24e0ecbf..f1fabf6c 100644
--- a/src/core/signals.h
+++ b/src/core/signals.h
@@ -23,6 +23,7 @@ void signal_add_to_id(const char *module, int pos,
/* unbind signal */
void signal_remove(const char *signal, SIGNAL_FUNC func);
+void signal_remove_id(int signal_id, SIGNAL_FUNC func);
/* emit signal */
int signal_emit(const char *signal, int params, ...);
diff --git a/src/core/special-vars.c b/src/core/special-vars.c
index f3f7cf14..7d4deb78 100644
--- a/src/core/special-vars.c
+++ b/src/core/special-vars.c
@@ -125,7 +125,7 @@ static char *get_long_variable_value(const char *key, SERVER_REC *server,
}
static char *get_long_variable(char **cmd, SERVER_REC *server,
- void *item, int *free_ret)
+ void *item, int *free_ret, int getname)
{
char *start, *var, *ret;
@@ -134,30 +134,41 @@ static char *get_long_variable(char **cmd, SERVER_REC *server,
while (isvarchar((*cmd)[1])) (*cmd)++;
var = g_strndup(start, (int) (*cmd-start)+1);
+ if (getname) {
+ *free_ret = TRUE;
+ return var;
+ }
ret = get_long_variable_value(var, server, item, free_ret);
g_free(var);
return ret;
}
-/* return the value of the variable found from `cmd' */
+/* 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)
+ char **arglist, int *free_ret, int *arg_used,
+ int getname)
{
EXPANDO_FUNC func;
if (isdigit(**cmd) || **cmd == '*' || **cmd == '-' || **cmd == '~') {
- /* argument */
+ /* argument */
*free_ret = TRUE;
if (arg_used != NULL) *arg_used = TRUE;
- return get_argument(cmd, arglist);
+ return getname ? g_strdup_printf("%c", **cmd) :
+ get_argument(cmd, arglist);
}
if (isalpha(**cmd) && isvarchar((*cmd)[1])) {
/* long variable name.. */
- return get_long_variable(cmd, server, item, free_ret);
+ return get_long_variable(cmd, server, item, free_ret, getname);
}
/* single character variable. */
+ if (getname) {
+ *free_ret = TRUE;
+ return g_strdup_printf("%c", **cmd);
+ }
*free_ret = FALSE;
func = expando_find_char(**cmd);
return func == NULL ? NULL : func(server, item, free_ret);
@@ -184,13 +195,17 @@ static char *get_history(char **cmd, void *item, int *free_ret)
}
static char *get_special_value(char **cmd, SERVER_REC *server, void *item,
- char **arglist, int *free_ret, int *arg_used)
+ char **arglist, int *free_ret, int *arg_used,
+ int flags)
{
char command, *value, *p;
int len;
if (**cmd == '!') {
/* find text from command history */
+ if (flags & PARSE_FLAG_GETNAME)
+ return "!";
+
return get_history(cmd, item, free_ret);
}
@@ -203,12 +218,19 @@ static char *get_special_value(char **cmd, SERVER_REC *server, void *item,
/* default to $* */
char *temp_cmd = "*";
+ if (flags & PARSE_FLAG_GETNAME)
+ return "*";
+
*free_ret = TRUE;
return get_argument(&temp_cmd, arglist);
}
}
- value = get_variable(cmd, server, item, arglist, free_ret, arg_used);
+ value = get_variable(cmd, server, item, arglist, free_ret,
+ arg_used, flags & PARSE_FLAG_GETNAME);
+
+ if (flags & PARSE_FLAG_GETNAME)
+ return value;
if (command == '#') {
/* number of words */
@@ -314,7 +336,7 @@ static char *get_alignment(const char *text, int align, int flags, char pad)
/* Parse and expand text after '$' character. return value has to be
g_free()'d if `free_ret' is TRUE. */
char *parse_special(char **cmd, SERVER_REC *server, void *item,
- char **arglist, int *free_ret, int *arg_used)
+ char **arglist, int *free_ret, int *arg_used, int flags)
{
static char **nested_orig_cmd = NULL; /* FIXME: KLUDGE! */
char command, *value;
@@ -355,7 +377,8 @@ char *parse_special(char **cmd, SERVER_REC *server, void *item,
} else {
(*cmd)++;
nest_value = parse_special(cmd, server, item, arglist,
- &nest_free, arg_used);
+ &nest_free, arg_used,
+ flags);
}
while ((*nested_orig_cmd)[1] != '\0') {
@@ -377,10 +400,13 @@ char *parse_special(char **cmd, SERVER_REC *server, void *item,
}
value = get_special_value(cmd, server, item, arglist,
- free_ret, arg_used);
+ free_ret, arg_used, flags);
if (**cmd == '\0')
g_error("parse_special() : buffer overflow!");
+ if (value != NULL && *value != '\0' && (flags & PARSE_FLAG_ISSET_ANY))
+ *arg_used = TRUE;
+
if (brackets) {
while (**cmd != '}' && (*cmd)[1] != '\0')
(*cmd)++;
@@ -388,7 +414,7 @@ char *parse_special(char **cmd, SERVER_REC *server, void *item,
if (nest_free) g_free(nest_value);
- if (command == '[') {
+ if (command == '[' && (flags & PARSE_FLAG_GETNAME) == 0) {
/* alignment */
char *p;
@@ -406,7 +432,7 @@ char *parse_special(char **cmd, SERVER_REC *server, void *item,
/* parse the whole string. $ and \ chars are replaced */
char *parse_special_string(const char *cmd, SERVER_REC *server, void *item,
- const char *data, int *arg_used)
+ const char *data, int *arg_used, int flags)
{
char code, **arglist, *ret;
GString *str;
@@ -438,7 +464,8 @@ char *parse_special_string(const char *cmd, SERVER_REC *server, void *item,
char *ret;
ret = parse_special((char **) &cmd, server, item,
- arglist, &need_free, arg_used);
+ arglist, &need_free, arg_used,
+ flags);
if (ret != NULL) {
g_string_append(str, ret);
if (need_free) g_free(ret);
@@ -488,7 +515,7 @@ void eval_special_string(const char *cmd, const char *data,
}
ret = parse_special_string(start, server, item,
- data, &arg_used);
+ data, &arg_used, 0);
if (arg_used) arg_used_ever = TRUE;
if (strchr(cmdchars, *ret) == NULL) {
@@ -525,3 +552,42 @@ void special_history_func_set(SPECIAL_HISTORY_FUNC func)
{
history_func = func;
}
+
+static void special_vars_signals_do(const char *text, int funccount,
+ SIGNAL_FUNC *funcs, int bind)
+{
+ char *ret;
+ int need_free;
+
+ while (*text != '\0') {
+ if (*text == '\\' && text[1] != '\0') {
+ text += 2;
+ } else if (*text == '$' && text[1] != '\0') {
+ text++;
+ ret = parse_special((char **) &text, NULL, NULL,
+ NULL, &need_free, NULL,
+ PARSE_FLAG_GETNAME);
+ if (ret != NULL) {
+ if (bind)
+ expando_bind(ret, funccount, funcs);
+ else
+ expando_unbind(ret, funccount, funcs);
+ if (need_free) g_free(ret);
+ }
+
+ }
+ else text++;
+ }
+}
+
+void special_vars_add_signals(const char *text,
+ int funccount, SIGNAL_FUNC *funcs)
+{
+ special_vars_signals_do(text, funccount, funcs, TRUE);
+}
+
+void special_vars_remove_signals(const char *text,
+ int funccount, SIGNAL_FUNC *funcs)
+{
+ special_vars_signals_do(text, funccount, funcs, FALSE);
+}
diff --git a/src/core/special-vars.h b/src/core/special-vars.h
index 1b8b3e20..deb4de40 100644
--- a/src/core/special-vars.h
+++ b/src/core/special-vars.h
@@ -1,19 +1,23 @@
#ifndef __SPECIAL_VARS_H
#define __SPECIAL_VARS_H
+#include "signals.h"
#include "servers.h"
+#define PARSE_FLAG_GETNAME 0x01 /* return argument name instead of it's value */
+#define PARSE_FLAG_ISSET_ANY 0x02 /* arg_used field specifies that at least one of the $variables was non-empty */
+
typedef char* (*SPECIAL_HISTORY_FUNC)
(const char *text, void *item, int *free_ret);
/* Parse and expand text after '$' character. return value has to be
g_free()'d if `free_ret' is TRUE. */
char *parse_special(char **cmd, SERVER_REC *server, void *item,
- char **arglist, int *free_ret, int *arg_used);
+ char **arglist, int *free_ret, int *arg_used, int flags);
/* parse the whole string. $ and \ chars are replaced */
char *parse_special_string(const char *cmd, SERVER_REC *server, void *item,
- const char *data, int *arg_used);
+ const char *data, int *arg_used, int flags);
/* execute the commands in string - commands can be split with ';' */
void eval_special_string(const char *cmd, const char *data,
@@ -21,4 +25,9 @@ void eval_special_string(const char *cmd, const char *data,
void special_history_func_set(SPECIAL_HISTORY_FUNC func);
+void special_vars_add_signals(const char *text,
+ int funccount, SIGNAL_FUNC *funcs);
+void special_vars_remove_signals(const char *text,
+ int funccount, SIGNAL_FUNC *funcs);
+
#endif