#include "special-vars.h"
#include "expandos.h"
#include "settings.h"
+#include "servers.h"
#include "misc.h"
#define ALIGN_RIGHT 0x01
#define ALIGN_PAD 0x04
#define isvarchar(c) \
- (isalnum(c) || (c) == '_')
+ (i_isalnum(c) || (c) == '_')
+
+#define isarg(c) \
+ (i_isdigit(c) || (c) == '*' || (c) == '~' || (c) == '-')
static SPECIAL_HISTORY_FUNC history_func = NULL;
arg = 0;
max = -1;
- argcount = strarray_length(arglist);
+ argcount = arglist == NULL ? 0 : strarray_length(arglist);
if (**cmd == '*') {
/* get all arguments */
/* get last argument */
arg = max = argcount-1;
} else {
- if (isdigit(**cmd)) {
+ if (i_isdigit(**cmd)) {
/* first argument */
arg = max = (**cmd)-'0';
(*cmd)++;
if (**cmd == '-') {
/* get more than one argument */
(*cmd)++;
- if (!isdigit(**cmd))
+ if (!i_isdigit(**cmd))
max = -1; /* get all the rest */
else {
max = (**cmd)-'0';
}
str = g_string_new(NULL);
- while (arg < argcount && (arg <= max || max == -1)) {
+ while (arg >= 0 && arg < argcount && (arg <= max || max == -1)) {
g_string_append(str, arglist[arg]);
g_string_append_c(str, ' ');
arg++;
void *item, int *free_ret)
{
EXPANDO_FUNC func;
- char *ret;
+ const char *ret;
int type;
*free_ret = FALSE;
/* expando? */
func = expando_find_long(key);
- if (func != NULL)
+ if (func != NULL) {
+ current_expando = key;
return func(server, item, free_ret);
+ }
/* internal setting? */
type = settings_get_type(key);
/* environment variable? */
ret = g_getenv(key);
if (ret != NULL)
- return ret;
+ return (char *) ret;
return NULL;
}
{
EXPANDO_FUNC func;
- if (isdigit(**cmd) || **cmd == '*' || **cmd == '-' || **cmd == '~') {
+ if (isarg(**cmd)) {
/* argument */
*free_ret = TRUE;
if (arg_used != NULL) *arg_used = TRUE;
get_argument(cmd, arglist);
}
- if (isalpha(**cmd) && isvarchar((*cmd)[1])) {
+ if (i_isalpha(**cmd) && isvarchar((*cmd)[1])) {
/* long variable name.. */
return get_long_variable(cmd, server, item, free_ret, getname);
}
}
*free_ret = FALSE;
func = expando_find_char(**cmd);
- return func == NULL ? NULL : func(server, item, free_ret);
+ if (func == NULL)
+ return NULL;
+ else {
+ char str[2];
+
+ str[0] = **cmd; str[1] = '\0';
+ current_expando = str;
+ return func(server, item, free_ret);
+ }
}
static char *get_history(char **cmd, void *item, int *free_ret)
if (history_func == NULL)
ret = NULL;
else {
- text = g_strndup(start, (int) (*cmd-start)+1);
+ text = g_strndup(start, (int) (*cmd-start));
ret = history_func(text, item, free_ret);
g_free(text);
}
char command, *value, *p;
int len;
+ if ((flags & PARSE_FLAG_ONLY_ARGS) && !isarg(**cmd)) {
+ *free_ret = TRUE;
+ return g_strdup_printf("$%c", **cmd);
+ }
+
if (**cmd == '!') {
/* find text from command history */
if (flags & PARSE_FLAG_GETNAME)
/* '!' = don't cut, '-' = right padding */
str = *data;
- while (*str != '\0' && *str != ']' && !isdigit(*str)) {
+ while (*str != '\0' && *str != ']' && !i_isdigit(*str)) {
if (*str == '!')
*flags &= ~ALIGN_CUT;
else if (*str == '-')
*flags &= ~ALIGN_PAD;
str++;
}
- if (!isdigit(*str))
+ if (!i_isdigit(*str))
return FALSE; /* expecting number */
/* get the alignment size */
- while (isdigit(*str)) {
+ while (i_isdigit(*str)) {
*align = (*align) * 10 + (*str-'0');
str++;
}
int brackets, nest_free;
*free_ret = FALSE;
+ if (**cmd == '\0')
+ return NULL;
command = **cmd; (*cmd)++;
switch (command) {
}
nest_free = FALSE; nest_value = NULL;
- if (**cmd == '(') {
+ if (**cmd == '(' && (*cmd)[1] != '\0') {
/* subvariable */
int toplevel = nested_orig_cmd == NULL;
flags);
}
+ if (nest_value == NULL || *nest_value == '\0')
+ return NULL;
+
while ((*nested_orig_cmd)[1] != '\0') {
(*nested_orig_cmd)++;
if (**nested_orig_cmd == ')')
brackets = FALSE;
else {
/* special value is inside {...} (foo${test}bar -> fooXXXbar) */
+ if ((*cmd)[1] == '\0')
+ return NULL;
(*cmd)++;
brackets = TRUE;
}
return value;
}
-static void gstring_append_escaped(GString *str, const char *text)
+static void gstring_append_escaped(GString *str, const char *text, int flags)
{
+ char esc[4], *escpos;
+
+ escpos = esc;
+ if (flags & PARSE_FLAG_ESCAPE_VARS)
+ *escpos++ = '%';
+ if (flags & PARSE_FLAG_ESCAPE_THEME) {
+ *escpos++ = '{';
+ *escpos++ = '}';
+ }
+
+ if (escpos == esc) {
+ g_string_append(str, text);
+ return;
+ }
+
+ *escpos = '\0';
while (*text != '\0') {
- if (*text == '%')
- g_string_append_c(str, '%');
+ for (escpos = esc; *escpos != '\0'; escpos++) {
+ if (*text == *escpos) {
+ g_string_append_c(str, '%');
+ break;
+ }
+ }
g_string_append_c(str, *text);
text++;
}
{
char code, **arglist, *ret;
GString *str;
- int need_free;
+ int need_free, chr;
g_return_val_if_fail(cmd != NULL, NULL);
g_return_val_if_fail(data != NULL, NULL);
code = 0;
str = g_string_new(NULL);
while (*cmd != '\0') {
- if (code == '\\'){
- switch (*cmd) {
- case 't':
- g_string_append_c(str, '\t');
- break;
- case 'n':
- g_string_append_c(str, '\n');
- break;
- default:
- g_string_append_c(str, *cmd);
+ if (code == '\\') {
+ if (*cmd == ';')
+ g_string_append_c(str, ';');
+ else {
+ chr = expand_escape(&cmd);
+ g_string_append_c(str, chr != -1 ? chr : *cmd);
}
code = 0;
} else if (code == '$') {
arglist, &need_free, arg_used,
flags);
if (ret != NULL) {
- if ((flags & PARSE_FLAG_ESCAPE_VARS) == 0)
- g_string_append(str, ret);
- else
- gstring_append_escaped(str, ret);
+ gstring_append_escaped(str, ret, flags);
if (need_free) g_free(ret);
}
code = 0;
/* get a list of all the commands to run */
orig = start = str = g_strdup(cmd);
do {
- if (is_split_char(str, start))
+ if (is_split_char(str, start)) {
*str++ = '\0';
- else if (*str != '\0') {
+ while (*str == ' ') str++;
+ } else if (*str != '\0') {
str++;
continue;
}
ret = parse_special_string(start, server, item,
data, &arg_used, 0);
- if (arg_used) arg_used_ever = TRUE;
+ if (*ret != '\0') {
+ if (arg_used) arg_used_ever = TRUE;
- if (strchr(cmdchars, *ret) == NULL) {
- /* no command char - let's put it there.. */
- char *old = ret;
+ if (strchr(cmdchars, *ret) == NULL) {
+ /* no command char - let's put it there.. */
+ char *old = ret;
- ret = g_strdup_printf("%c%s", *cmdchars, old);
- g_free(old);
+ ret = g_strdup_printf("%c%s", *cmdchars, old);
+ g_free(old);
+ }
+ commands = g_slist_append(commands, ret);
}
- commands = g_slist_append(commands, ret);
start = str;
} while (*start != '\0');
ret = g_strconcat(old, " ", data, NULL);
g_free(old);
}
+
+ if (server != NULL)
+ server_ref(server);
signal_emit("send command", 3, ret, server, item);
+ if (server != NULL && !server_unref(server)) {
+ /* the server was destroyed */
+ server = NULL;
+ item = NULL;
+ }
+
+ /* FIXME: window item would need reference counting as well,
+ eg. "/EVAL win close;say hello" wouldn't work now.. */
+
g_free(ret);
commands = g_slist_remove(commands, commands->data);
}
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);
}