summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/expandos.c69
-rw-r--r--src/core/expandos.h5
-rw-r--r--src/core/special-vars.c119
-rw-r--r--src/core/special-vars.h2
4 files changed, 175 insertions, 20 deletions
diff --git a/src/core/expandos.c b/src/core/expandos.c
index 9114a3c9..4659f5ac 100644
--- a/src/core/expandos.c
+++ b/src/core/expandos.c
@@ -54,7 +54,10 @@ static time_t client_start_time;
static char *last_sent_msg, *last_sent_msg_body;
static char *last_privmsg_from, *last_public_from;
static char *sysname, *sysrelease, *sysarch;
+
static const char *timestamp_format;
+static int timestamp_seconds;
+static time_t last_timestamp;
#define CHAR_EXPANDO(chr) \
(char_expandos[(int) (unsigned char) chr])
@@ -209,6 +212,38 @@ void expando_unbind(const char *key, int funccount, SIGNAL_FUNC *funcs)
}
}
+/* Returns [<signal id>, EXPANDO_ARG_xxx, <signal id>, ..., -1] */
+int *expando_get_signals(const char *key)
+{
+ EXPANDO_REC *rec;
+ int *signals;
+ int n;
+
+ g_return_val_if_fail(key != NULL, NULL);
+
+ rec = expando_find(key);
+ if (rec == NULL || rec->signals < 0)
+ return NULL;
+
+ if (rec->signals == 0) {
+ /* it's unknown when this expando changes..
+ check it once in a second */
+ signals = g_new(int, 3);
+ signals[0] = signal_get_uniq_id("expando timer");
+ signals[1] = EXPANDO_ARG_NONE;
+ signals[2] = -1;
+ return signals;
+ }
+
+ signals = g_new(int, rec->signals*2+1);
+ for (n = 0; n < rec->signals; n++) {
+ signals[n*2] = rec->signal_ids[n];
+ signals[n*2+1] = rec->signal_args[n];
+ }
+ signals[rec->signals*2] = -1;
+ return signals;
+}
+
EXPANDO_FUNC expando_find_char(char chr)
{
return CHAR_EXPANDO(chr) == NULL ? NULL :
@@ -437,13 +472,41 @@ static void sig_message_own_private(SERVER_REC *server, const char *msg,
static int sig_timer(void)
{
+ time_t now;
+ struct tm *tm;
+ int last_min;
+
signal_emit("expando timer", 0);
+
+ /* check if $Z has changed */
+ now = time(NULL);
+ if (last_timestamp != now) {
+ if (!timestamp_seconds) {
+ /* assume it changes every minute */
+ tm = localtime(&last_timestamp);
+ last_min = tm->tm_min;
+
+ tm = localtime(&now);
+ if (tm->tm_min == last_min)
+ return 1;
+ }
+
+ signal_emit("time changed", 0);
+ last_timestamp = now;
+ }
+
return 1;
}
static void read_settings(void)
{
- timestamp_format = settings_get_str("timestamp_format");
+ timestamp_format = settings_get_str("timestamp_format");
+ timestamp_seconds =
+ strstr(timestamp_format, "%r") != NULL ||
+ strstr(timestamp_format, "%s") != NULL ||
+ strstr(timestamp_format, "%S") != NULL ||
+ strstr(timestamp_format, "%T") != NULL;
+
}
void expandos_init(void)
@@ -457,6 +520,7 @@ void expandos_init(void)
client_start_time = time(NULL);
last_sent_msg = NULL; last_sent_msg_body = NULL;
last_privmsg_from = NULL; last_public_from = NULL;
+ last_timestamp = 0;
sysname = sysrelease = sysarch = NULL;
#ifdef HAVE_SYS_UTSNAME_H
@@ -523,7 +587,8 @@ void expandos_init(void)
expando_create("Y", expando_realname,
"window changed", EXPANDO_ARG_NONE,
"window server changed", EXPANDO_ARG_WINDOW, NULL);
- expando_create("Z", expando_time, NULL);
+ expando_create("Z", expando_time,
+ "time changed", EXPANDO_ARG_NONE, NULL);
expando_create("$", expando_dollar,
"", EXPANDO_NEVER, NULL);
diff --git a/src/core/expandos.h b/src/core/expandos.h
index 3dcb527e..cf057994 100644
--- a/src/core/expandos.h
+++ b/src/core/expandos.h
@@ -5,7 +5,7 @@
/* first argument of signal must match to active .. */
typedef enum {
- EXPANDO_ARG_NONE,
+ EXPANDO_ARG_NONE = 1,
EXPANDO_ARG_SERVER,
EXPANDO_ARG_WINDOW,
EXPANDO_ARG_WINDOW_ITEM,
@@ -28,6 +28,9 @@ 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);
+/* Returns [<signal id>, EXPANDO_ARG_xxx, <signal id>, ..., -1] */
+int *expando_get_signals(const char *key);
+
/* internal: */
EXPANDO_FUNC expando_find_char(char chr);
EXPANDO_FUNC expando_find_long(const char *key);
diff --git a/src/core/special-vars.c b/src/core/special-vars.c
index 19a0b1b2..442342b6 100644
--- a/src/core/special-vars.c
+++ b/src/core/special-vars.c
@@ -597,41 +597,126 @@ 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)
+static void update_signals_hash(GHashTable **hash, int *signals)
{
- char *ret;
- int need_free;
+ void *signal_id;
+ int arg_type;
+
+ if (*hash == NULL) {
+ *hash = g_hash_table_new((GHashFunc) g_direct_hash,
+ (GCompareFunc) g_direct_equal);
+ }
+
+ while (*signals != -1) {
+ signal_id = GINT_TO_POINTER(*signals);
+ arg_type = GPOINTER_TO_INT(g_hash_table_lookup(*hash, signal_id));
+ if (arg_type != 0 && arg_type != signals[1]) {
+ /* same signal is used for different purposes ..
+ not sure if this should ever happen, but change
+ the argument type to none so it will at least
+ work. */
+ arg_type = EXPANDO_ARG_NONE;
+ }
+
+ if (arg_type == 0) arg_type = signals[1];
+ g_hash_table_insert(*hash, signal_id,
+ GINT_TO_POINTER(arg_type));
+ signals += 2;
+ }
+}
+
+static void get_signal_hash(void *signal_id, void *arg_type, int **pos)
+{
+ (*pos)[0] = GPOINTER_TO_INT(signal_id);
+ (*pos)[1] = GPOINTER_TO_INT(arg_type);
+ (*pos) += 2;
+}
+
+static int *get_signals_list(GHashTable *hash)
+{
+ int *signals, *pos;
+
+ if (hash == NULL) {
+ /* no expandos in text - never needs updating */
+ return NULL;
+ }
+
+ pos = signals = g_new(int, g_hash_table_size(hash)*2 + 1);
+ g_hash_table_foreach(hash, (GHFunc) get_signal_hash, &pos);
+ *pos = -1;
+
+ g_hash_table_destroy(hash);
+ return signals;
+
+}
+
+#define TASK_BIND 1
+#define TASK_UNBIND 2
+#define TASK_GET_SIGNALS 3
+static int *special_vars_signals_task(const char *text, int funccount,
+ SIGNAL_FUNC *funcs, int task)
+{
+ GHashTable *signals;
+ char *expando;
+ int need_free, *expando_signals;
+
+ signals = NULL;
while (*text != '\0') {
if (*text == '\\' && text[1] != '\0') {
+ /* escape */
text += 2;
} else if (*text == '$' && text[1] != '\0') {
+ /* expando */
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);
+ expando = parse_special((char **) &text, NULL, NULL,
+ NULL, &need_free, NULL,
+ PARSE_FLAG_GETNAME);
+ if (expando == NULL)
+ continue;
+
+ switch (task) {
+ case TASK_BIND:
+ expando_bind(expando, funccount, funcs);
+ break;
+ case TASK_UNBIND:
+ expando_unbind(expando, funccount, funcs);
+ break;
+ case TASK_GET_SIGNALS:
+ expando_signals = expando_get_signals(expando);
+ if (expando_signals != NULL) {
+ update_signals_hash(&signals,
+ expando_signals);
+ g_free(expando_signals);
+ }
+ break;
}
-
+ if (need_free) g_free(expando);
+ } else {
+ /* just a char */
+ text++;
}
- else text++;
}
+
+ if (task == TASK_GET_SIGNALS)
+ return get_signals_list(signals);
+
+ return NULL;
}
void special_vars_add_signals(const char *text,
int funccount, SIGNAL_FUNC *funcs)
{
- special_vars_signals_do(text, funccount, funcs, TRUE);
+ special_vars_signals_task(text, funccount, funcs, TASK_BIND);
}
void special_vars_remove_signals(const char *text,
int funccount, SIGNAL_FUNC *funcs)
{
- special_vars_signals_do(text, funccount, funcs, FALSE);
+ special_vars_signals_task(text, funccount, funcs, TASK_UNBIND);
+}
+
+int *special_vars_get_signals(const char *text)
+{
+ return special_vars_signals_task(text, 0, NULL, TASK_GET_SIGNALS);
}
diff --git a/src/core/special-vars.h b/src/core/special-vars.h
index c27a50a8..11262dad 100644
--- a/src/core/special-vars.h
+++ b/src/core/special-vars.h
@@ -31,5 +31,7 @@ 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);
+/* Returns [<signal id>, EXPANDO_ARG_xxx, <signal id>, ..., -1] */
+int *special_vars_get_signals(const char *text);
#endif