summaryrefslogtreecommitdiffstats
path: root/src/evalfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/evalfunc.c')
-rw-r--r--src/evalfunc.c152
1 files changed, 98 insertions, 54 deletions
diff --git a/src/evalfunc.c b/src/evalfunc.c
index eaaa1e696f..ccb8b3e890 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -9200,8 +9200,7 @@ f_printf(typval_T *argvars, typval_T *rettv)
f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
{
buf_T *buf;
- char_u *callback;
- partial_T *partial;
+ callback_T callback;
if (check_secure())
return;
@@ -9209,17 +9208,12 @@ f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
if (buf == NULL)
return;
- callback = get_callback(&argvars[1], &partial);
- if (callback == NULL)
+ callback = get_callback(&argvars[1]);
+ if (callback.cb_name == NULL)
return;
- free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
- if (partial == NULL)
- buf->b_prompt_callback = vim_strsave(callback);
- else
- /* pointer into the partial */
- buf->b_prompt_callback = callback;
- buf->b_prompt_partial = partial;
+ free_callback(&buf->b_prompt_callback);
+ set_callback(&buf->b_prompt_callback, &callback);
}
/*
@@ -9229,8 +9223,7 @@ f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
{
buf_T *buf;
- char_u *callback;
- partial_T *partial;
+ callback_T callback;
if (check_secure())
return;
@@ -9238,17 +9231,12 @@ f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
if (buf == NULL)
return;
- callback = get_callback(&argvars[1], &partial);
- if (callback == NULL)
+ callback = get_callback(&argvars[1]);
+ if (callback.cb_name == NULL)
return;
- free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
- if (partial == NULL)
- buf->b_prompt_interrupt = vim_strsave(callback);
- else
- /* pointer into the partial */
- buf->b_prompt_interrupt = callback;
- buf->b_prompt_int_partial = partial;
+ free_callback(&buf->b_prompt_interrupt);
+ set_callback(&buf->b_prompt_interrupt, &callback);
}
/*
@@ -14631,44 +14619,106 @@ f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
/*
* Get a callback from "arg". It can be a Funcref or a function name.
* When "arg" is zero return an empty string.
- * Return NULL for an invalid argument.
+ * "cb_name" is not allocated.
+ * "cb_name" is set to NULL for an invalid argument.
*/
- char_u *
-get_callback(typval_T *arg, partial_T **pp)
+ callback_T
+get_callback(typval_T *arg)
{
+ callback_T res;
+
+ res.cb_free_name = FALSE;
if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
{
- *pp = arg->vval.v_partial;
- ++(*pp)->pt_refcount;
- return partial_name(*pp);
+ res.cb_partial = arg->vval.v_partial;
+ ++res.cb_partial->pt_refcount;
+ res.cb_name = partial_name(res.cb_partial);
}
- *pp = NULL;
- if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
+ else
{
- func_ref(arg->vval.v_string);
- return arg->vval.v_string;
+ res.cb_partial = NULL;
+ if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
+ {
+ // Note that we don't make a copy of the string.
+ res.cb_name = arg->vval.v_string;
+ func_ref(res.cb_name);
+ }
+ else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
+ {
+ res.cb_name = (char_u *)"";
+ }
+ else
+ {
+ emsg(_("E921: Invalid callback argument"));
+ res.cb_name = NULL;
+ }
}
- if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
- return (char_u *)"";
- emsg(_("E921: Invalid callback argument"));
- return NULL;
+ return res;
}
/*
- * Unref/free "callback" and "partial" returned by get_callback().
+ * Copy a callback into a typval_T.
*/
void
-free_callback(char_u *callback, partial_T *partial)
+put_callback(callback_T *cb, typval_T *tv)
{
- if (partial != NULL)
- partial_unref(partial);
- else if (callback != NULL)
+ if (cb->cb_partial != NULL)
{
- func_unref(callback);
- vim_free(callback);
+ tv->v_type = VAR_PARTIAL;
+ tv->vval.v_partial = cb->cb_partial;
+ ++tv->vval.v_partial->pt_refcount;
+ }
+ else
+ {
+ tv->v_type = VAR_FUNC;
+ tv->vval.v_string = vim_strsave(cb->cb_name);
+ func_ref(cb->cb_name);
}
}
+/*
+ * Make a copy of "src" into "dest", allocating the function name if needed,
+ * without incrementing the refcount.
+ */
+ void
+set_callback(callback_T *dest, callback_T *src)
+{
+ if (src->cb_partial == NULL)
+ {
+ // just a function name, make a copy
+ dest->cb_name = vim_strsave(src->cb_name);
+ dest->cb_free_name = TRUE;
+ }
+ else
+ {
+ // cb_name is a pointer into cb_partial
+ dest->cb_name = src->cb_name;
+ dest->cb_free_name = FALSE;
+ }
+ dest->cb_partial = src->cb_partial;
+}
+
+/*
+ * Unref/free "callback" returned by get_callback() or set_callback().
+ */
+ void
+free_callback(callback_T *callback)
+{
+ if (callback->cb_partial != NULL)
+ {
+ partial_unref(callback->cb_partial);
+ callback->cb_partial = NULL;
+ }
+ else if (callback->cb_name != NULL)
+ func_unref(callback->cb_name);
+ if (callback->cb_free_name)
+ {
+ vim_free(callback->cb_name);
+ callback->cb_free_name = FALSE;
+ }
+ callback->cb_name = NULL;
+}
+
#ifdef FEAT_TIMERS
/*
* "timer_info([timer])" function
@@ -14723,9 +14773,8 @@ f_timer_start(typval_T *argvars, typval_T *rettv)
long msec = (long)tv_get_number(&argvars[0]);
timer_T *timer;
int repeat = 0;
- char_u *callback;
+ callback_T callback;
dict_T *dict;
- partial_T *partial;
rettv->vval.v_number = -1;
if (check_secure())
@@ -14742,21 +14791,16 @@ f_timer_start(typval_T *argvars, typval_T *rettv)
repeat = dict_get_number(dict, (char_u *)"repeat");
}
- callback = get_callback(&argvars[1], &partial);
- if (callback == NULL)
+ callback = get_callback(&argvars[1]);
+ if (callback.cb_name == NULL)
return;
timer = create_timer(msec, repeat);
if (timer == NULL)
- free_callback(callback, partial);
+ free_callback(&callback);
else
{
- if (partial == NULL)
- timer->tr_callback = vim_strsave(callback);
- else
- /* pointer into the partial */
- timer->tr_callback = callback;
- timer->tr_partial = partial;
+ set_callback(&timer->tr_callback, &callback);
rettv->vval.v_number = (varnumber_T)timer->tr_id;
}
}