summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-06-01 13:28:35 +0200
committerBram Moolenaar <Bram@vim.org>2019-06-01 13:28:35 +0200
commit3a97bb3f0f8bd118ae23f1c97e55d84ff42eef20 (patch)
treeb7013f43afaaba6ba20b356a7a80fe55add24f1a
parent7dd64a3e57d296fdee3b3ffe6d938f634b59848c (diff)
patch 8.1.1437: code to handle callbacks is duplicatedv8.1.1437
Problem: Code to handle callbacks is duplicated. Solution: Add callback_T and functions to deal with it.
-rw-r--r--src/buffer.c2
-rw-r--r--src/change.c24
-rw-r--r--src/channel.c278
-rw-r--r--src/eval.c21
-rw-r--r--src/evalfunc.c152
-rw-r--r--src/ex_cmds2.c24
-rw-r--r--src/popupwin.c6
-rw-r--r--src/proto/channel.pro2
-rw-r--r--src/proto/evalfunc.pro6
-rw-r--r--src/proto/userfunc.pro1
-rw-r--r--src/structs.h69
-rw-r--r--src/userfunc.c24
-rw-r--r--src/version.c2
13 files changed, 314 insertions, 297 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 3bfb6396ba..66f6fc654c 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -862,7 +862,7 @@ free_buffer(buf_T *buf)
#endif
#ifdef FEAT_JOB_CHANNEL
vim_free(buf->b_prompt_text);
- free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
+ free_callback(&buf->b_prompt_callback);
#endif
buf_hashtab_remove(buf);
diff --git a/src/change.c b/src/change.c
index b1a56ae4c0..07985ee62a 100644
--- a/src/change.c
+++ b/src/change.c
@@ -270,36 +270,34 @@ may_record_change(
void
f_listener_add(typval_T *argvars, typval_T *rettv)
{
- char_u *callback;
- partial_T *partial;
+ callback_T callback;
listener_T *lnr;
buf_T *buf = curbuf;
- callback = get_callback(&argvars[0], &partial);
- if (callback == NULL)
+ callback = get_callback(&argvars[0]);
+ if (callback.cb_name == NULL)
return;
if (argvars[1].v_type != VAR_UNKNOWN)
{
buf = get_buf_arg(&argvars[1]);
if (buf == NULL)
+ {
+ free_callback(&callback);
return;
+ }
}
lnr = ALLOC_CLEAR_ONE(listener_T);
if (lnr == NULL)
{
- free_callback(callback, partial);
+ free_callback(&callback);
return;
}
lnr->lr_next = buf->b_listener;
buf->b_listener = lnr;
- if (partial == NULL)
- lnr->lr_callback = vim_strsave(callback);
- else
- lnr->lr_callback = callback; // pointer into the partial
- lnr->lr_partial = partial;
+ set_callback(&lnr->lr_callback, &callback);
lnr->lr_id = ++next_listener_id;
rettv->vval.v_number = lnr->lr_id;
@@ -344,7 +342,7 @@ f_listener_remove(typval_T *argvars, typval_T *rettv UNUSED)
prev->lr_next = lnr->lr_next;
else
buf->b_listener = lnr->lr_next;
- free_callback(lnr->lr_callback, lnr->lr_partial);
+ free_callback(&lnr->lr_callback);
vim_free(lnr);
}
prev = lnr;
@@ -418,8 +416,8 @@ invoke_listeners(buf_T *buf)
for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
{
- call_func(lnr->lr_callback, -1, &rettv,
- 5, argv, NULL, 0L, 0L, &dummy, TRUE, lnr->lr_partial, NULL);
+ call_callback(&lnr->lr_callback, -1, &rettv,
+ 5, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv);
}
diff --git a/src/channel.c b/src/channel.c
index 558e36d336..5ace0713d1 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -348,7 +348,7 @@ channel_still_useful(channel_T *channel)
return FALSE;
/* If there is a close callback it may still need to be invoked. */
- if (channel->ch_close_cb != NULL)
+ if (channel->ch_close_cb.cb_name != NULL)
return TRUE;
/* If reading from or a buffer it's still useful. */
@@ -366,12 +366,12 @@ channel_still_useful(channel_T *channel)
has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
|| channel->ch_part[PART_ERR].ch_head.rq_next != NULL
|| channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
- return (channel->ch_callback != NULL && (has_sock_msg
+ return (channel->ch_callback.cb_name != NULL && (has_sock_msg
|| has_out_msg || has_err_msg))
- || ((channel->ch_part[PART_OUT].ch_callback != NULL
+ || ((channel->ch_part[PART_OUT].ch_callback.cb_name != NULL
|| channel->ch_part[PART_OUT].ch_bufref.br_buf != NULL)
&& has_out_msg)
- || ((channel->ch_part[PART_ERR].ch_callback != NULL
+ || ((channel->ch_part[PART_ERR].ch_callback.cb_name != NULL
|| channel->ch_part[PART_ERR].ch_bufref.br_buf != NULL)
&& has_err_msg);
}
@@ -1178,29 +1178,36 @@ find_buffer(char_u *name, int err, int msg)
return buf;
}
+/*
+ * Copy callback from "src" to "dest", incrementing the refcounts.
+ */
static void
-set_callback(
- char_u **cbp,
- partial_T **pp,
- char_u *callback,
- partial_T *partial)
+copy_callback(callback_T *dest, callback_T *src)
{
- free_callback(*cbp, *pp);
- if (callback != NULL && *callback != NUL)
+ dest->cb_partial = src->cb_partial;
+ if (dest->cb_partial != NULL)
{
- if (partial != NULL)
- *cbp = partial_name(partial);
- else
- {
- *cbp = vim_strsave(callback);
- func_ref(*cbp);
- }
+ dest->cb_name = src->cb_name;
+ dest->cb_free_name = FALSE;
+ ++dest->cb_partial->pt_refcount;
+ }
+ else
+ {
+ dest->cb_name = vim_strsave(src->cb_name);
+ dest->cb_free_name = TRUE;
+ func_ref(src->cb_name);
}
+}
+
+ static void
+free_set_callback(callback_T *cbp, callback_T *callback)
+{
+ free_callback(cbp);
+
+ if (callback->cb_name != NULL && *callback->cb_name != NUL)
+ copy_callback(cbp, callback);
else
- *cbp = NULL;
- *pp = partial;
- if (partial != NULL)
- ++partial->pt_refcount;
+ cbp->cb_name = NULL;
}
/*
@@ -1233,19 +1240,15 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
channel->ch_part[PART_IN].ch_block_write = 1;
if (opt->jo_set & JO_CALLBACK)
- set_callback(&channel->ch_callback, &channel->ch_partial,
- opt->jo_callback, opt->jo_partial);
+ free_set_callback(&channel->ch_callback, &opt->jo_callback);
if (opt->jo_set & JO_OUT_CALLBACK)
- set_callback(&channel->ch_part[PART_OUT].ch_callback,
- &channel->ch_part[PART_OUT].ch_partial,
- opt->jo_out_cb, opt->jo_out_partial);
+ free_set_callback(&channel->ch_part[PART_OUT].ch_callback,
+ &opt->jo_out_cb);
if (opt->jo_set & JO_ERR_CALLBACK)
- set_callback(&channel->ch_part[PART_ERR].ch_callback,
- &channel->ch_part[PART_ERR].ch_partial,
- opt->jo_err_cb, opt->jo_err_partial);
+ free_set_callback(&channel->ch_part[PART_ERR].ch_callback,
+ &opt->jo_err_cb);
if (opt->jo_set & JO_CLOSE_CALLBACK)
- set_callback(&channel->ch_close_cb, &channel->ch_close_partial,
- opt->jo_close_cb, opt->jo_close_partial);
+ free_set_callback(&channel->ch_close_cb, &opt->jo_close_cb);
channel->ch_drop_never = opt->jo_drop_never;
if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
@@ -1349,8 +1352,7 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
channel_set_req_callback(
channel_T *channel,
ch_part_T part,
- char_u *callback,
- partial_T *partial,
+ callback_T *callback,
int id)
{
cbq_T *head = &channel->ch_part[part].ch_cb_head;
@@ -1358,17 +1360,7 @@ channel_set_req_callback(
if (item != NULL)
{
- item->cq_partial = partial;
- if (partial != NULL)
- {
- ++partial->pt_refcount;
- item->cq_callback = callback;
- }
- else
- {
- item->cq_callback = vim_strsave(callback);
- func_ref(item->cq_callback);
- }
+ copy_callback(&item->cq_callback, callback);
item->cq_seq_nr = id;
item->cq_prev = head->cq_prev;
head->cq_prev = item;
@@ -1638,8 +1630,7 @@ channel_write_new_lines(buf_T *buf)
* This does not redraw but sets channel_need_redraw;
*/
static void
-invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
- typval_T *argv)
+invoke_callback(channel_T *channel, callback_T *callback, typval_T *argv)
{
typval_T rettv;
int dummy;
@@ -1650,8 +1641,8 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
argv[0].v_type = VAR_CHANNEL;
argv[0].vval.v_channel = channel;
- call_func(callback, -1, &rettv, 2, argv, NULL,
- 0L, 0L, &dummy, TRUE, partial, NULL);
+ call_callback(callback, -1, &rettv, 2, argv, NULL,
+ 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv);
channel_need_redraw = TRUE;
}
@@ -2414,12 +2405,12 @@ invoke_one_time_callback(
typval_T *argv)
{
ch_log(channel, "Invoking one-time callback %s",
- (char *)item->cq_callback);
+ (char *)item->cq_callback.cb_name);
/* Remove the item from the list first, if the callback
* invokes ch_close() the list will be cleared. */
remove_cb_node(cbhead, item);
- invoke_callback(channel, item->cq_callback, item->cq_partial, argv);
- free_callback(item->cq_callback, item->cq_partial);
+ invoke_callback(channel, &item->cq_callback, argv);
+ free_callback(&item->cq_callback);
vim_free(item);
}
@@ -2553,8 +2544,7 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
ch_mode_T ch_mode = ch_part->ch_mode;
cbq_T *cbhead = &ch_part->ch_cb_head;
cbq_T *cbitem;
- char_u *callback = NULL;
- partial_T *partial = NULL;
+ callback_T *callback = NULL;
buf_T *buffer = NULL;
char_u *p;
@@ -2567,20 +2557,11 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
if (cbitem->cq_seq_nr == 0)
break;
if (cbitem != NULL)
- {
- callback = cbitem->cq_callback;
- partial = cbitem->cq_partial;
- }
- else if (ch_part->ch_callback != NULL)
- {
- callback = ch_part->ch_callback;
- partial = ch_part->ch_partial;
- }
- else
- {
- callback = channel->ch_callback;
- partial = channel->ch_partial;
- }
+ callback = &cbitem->cq_callback;
+ else if (ch_part->ch_callback.cb_name != NULL)
+ callback = &ch_part->ch_callback;
+ else if (channel->ch_callback.cb_name != NULL)
+ callback = &channel->ch_callback;
buffer = ch_part->ch_bufref.br_buf;
if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref)
@@ -2642,7 +2623,7 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
{
/* If there is a close callback it may use ch_read() to get the
* messages. */
- if (channel->ch_close_cb == NULL && !channel->ch_drop_never)
+ if (channel->ch_close_cb.cb_name == NULL && !channel->ch_drop_never)
drop_messages(channel, part);
return FALSE;
}
@@ -2761,8 +2742,8 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
{
/* invoke the channel callback */
ch_log(channel, "Invoking channel callback %s",
- (char *)callback);
- invoke_callback(channel, callback, partial, argv);
+ (char *)callback->cb_name);
+ invoke_callback(channel, callback, argv);
}
}
}
@@ -2956,18 +2937,18 @@ channel_close(channel_T *channel, int invoke_close_cb)
ch_part_T part;
/* Invoke callbacks and flush buffers before the close callback. */
- if (channel->ch_close_cb != NULL)
+ if (channel->ch_close_cb.cb_name != NULL)
ch_log(channel,
"Invoking callbacks and flushing buffers before closing");
for (part = PART_SOCK; part < PART_IN; ++part)
{
- if (channel->ch_close_cb != NULL
+ if (channel->ch_close_cb.cb_name != NULL
|| channel->ch_part[part].ch_bufref.br_buf != NULL)
{
/* Increment the refcount to avoid the channel being freed
* halfway. */
++channel->ch_refcount;
- if (channel->ch_close_cb == NULL)
+ if (channel->ch_close_cb.cb_name == NULL)
ch_log(channel, "flushing %s buffers before closing",
part_names[part]);
while (may_invoke_callback(channel, part))
@@ -2976,7 +2957,7 @@ channel_close(channel_T *channel, int invoke_close_cb)
}
}
- if (channel->ch_close_cb != NULL)
+ if (channel->ch_close_cb.cb_name != NULL)
{
typval_T argv[1];
typval_T rettv;
@@ -2986,19 +2967,16 @@ channel_close(channel_T *channel, int invoke_close_cb)
* halfway. */
++channel->ch_refcount;
ch_log(channel, "Invoking close callback %s",
- (char *)channel->ch_close_cb);
+ (char *)channel->ch_close_cb.cb_name);
argv[0].v_type = VAR_CHANNEL;
argv[0].vval.v_channel = channel;
- call_func(channel->ch_close_cb, -1,
- &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
- channel->ch_close_partial, NULL);
+ call_callback(&channel->ch_close_cb, -1,
+ &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv);
channel_need_redraw = TRUE;
/* the callback is only called once */
- free_callback(channel->ch_close_cb, channel->ch_close_partial);
- channel->ch_close_cb = NULL;
- channel->ch_close_partial = NULL;
+ free_callback(&channel->ch_close_cb);
if (channel_need_redraw)
{
@@ -3061,7 +3039,7 @@ channel_clear_one(channel_T *channel, ch_part_T part)
cbq_T *node = cb_head->cq_next;
remove_cb_node(cb_head, node);
- free_callback(node->cq_callback, node->cq_partial);
+ free_callback(&node->cq_callback);
vim_free(node);
}
@@ -3071,9 +3049,7 @@ channel_clear_one(channel_T *channel, ch_part_T part)
remove_json_node(json_head, json_head->jq_next);
}
- free_callback(ch_part->ch_callback, ch_part->ch_partial);
- ch_part->ch_callback = NULL;
- ch_part->ch_partial = NULL;
+ free_callback(&ch_part->ch_callback);
while (ch_part->ch_writeque.wq_next != NULL)
remove_from_writeque(&ch_part->ch_writeque,
@@ -3092,12 +3068,8 @@ channel_clear(channel_T *channel)
channel_clear_one(channel, PART_OUT);
channel_clear_one(channel, PART_ERR);
channel_clear_one(channel, PART_IN);
- free_callback(channel->ch_callback, channel->ch_partial);
- channel->ch_callback = NULL;
- channel->ch_partial = NULL;
- free_callback(channel->ch_close_cb, channel->ch_close_partial);
- channel->ch_close_cb = NULL;
- channel->ch_close_partial = NULL;
+ free_callback(&channel->ch_callback);
+ free_callback(&channel->ch_close_cb);
}
#if defined(EXITFREE) || defined(PROTO)
@@ -3991,19 +3963,18 @@ send_common(
/* Set the callback. An empty callback means no callback and not reading
* the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
* allowed. */
- if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
+ if (opt->jo_callback.cb_name != NULL && *opt->jo_callback.cb_name != NUL)
{
if (eval)
{
semsg(_("E917: Cannot use a callback with %s()"), fun);
return NULL;
}
- channel_set_req_callback(channel, *part_read,
- opt->jo_callback, opt->jo_partial, id);
+ channel_set_req_callback(channel, *part_read, &opt->jo_callback, id);
}
if (channel_send(channel, part_send, text, len, fun) == OK
- && opt->jo_callback == NULL)
+ && opt->jo_callback.cb_name == NULL)
return channel;
return NULL;
}
@@ -4559,26 +4530,26 @@ clear_job_options(jobopt_T *opt)
void
free_job_options(jobopt_T *opt)
{
- if (opt->jo_partial != NULL)
- partial_unref(opt->jo_partial);
- else if (opt->jo_callback != NULL)
- func_unref(opt->jo_callback);
- if (opt->jo_out_partial != NULL)
- partial_unref(opt->jo_out_partial);
- else if (opt->jo_out_cb != NULL)
- func_unref(opt->jo_out_cb);
- if (opt->jo_err_partial != NULL)
- partial_unref(opt->jo_err_partial);
- else if (opt->jo_err_cb != NULL)
- func_unref(opt->jo_err_cb);
- if (opt->jo_close_partial != NULL)
- partial_unref(opt->jo_close_partial);
- else if (opt->jo_close_cb != NULL)
- func_unref(opt->jo_close_cb);
- if (opt->jo_exit_partial != NULL)
- partial_unref(opt->jo_exit_partial);
- else if (opt->jo_exit_cb != NULL)
- func_unref(opt->jo_exit_cb);
+ if (opt->jo_callback.cb_partial != NULL)
+ partial_unref(opt->jo_callback.cb_partial);
+ else if (opt->jo_callback.cb_name != NULL)
+ func_unref(opt->jo_callback.cb_name);
+ if (opt->jo_out_cb.cb_partial != NULL)
+ partial_unref(opt->jo_out_cb.cb_partial);
+ else if (opt->jo_out_cb.cb_name != NULL)
+ func_unref(opt->jo_out_cb.cb_name);
+ if (opt->jo_err_cb.cb_partial != NULL)
+ partial_unref(opt->jo_err_cb.cb_partial);
+ else if (opt->jo_err_cb.cb_name != NULL)
+ func_unref(opt->jo_err_cb.cb_name);
+ if (opt->jo_close_cb.cb_partial != NULL)
+ partial_unref(opt->jo_close_cb.cb_partial);
+ else if (opt->jo_close_cb.cb_name != NULL)
+ func_unref(opt->jo_close_cb.cb_name);
+ if (opt->jo_exit_cb.cb_partial != NULL)
+ partial_unref(opt->jo_exit_cb.cb_partial);
+ else if (opt->jo_exit_cb.cb_name != NULL)
+ func_unref(opt->jo_exit_cb.cb_name);
if (opt->jo_env != NULL)
dict_unref(opt->jo_env);
}
@@ -4771,8 +4742,8 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
if (!(supported & JO_CALLBACK))
break;
opt->jo_set |= JO_CALLBACK;
- opt->jo_callback = get_callback(item, &opt->jo_partial);
- if (opt->jo_callback == NULL)
+ opt->jo_callback = get_callback(item);
+ if (opt->jo_callback.cb_name == NULL)
{
semsg(_(e_invargval), "callback");
return FAIL;
@@ -4783,8 +4754,8 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
if (!(supported & JO_OUT_CALLBACK))
break;
opt->jo_set |= JO_OUT_CALLBACK;
- opt->jo_out_cb = get_callback(item, &opt->jo_out_partial);
- if (opt->jo_out_cb == NULL)
+ opt->jo_out_cb = get_callback(item);
+ if (opt->jo_out_cb.cb_name == NULL)
{
semsg(_(e_invargval), "out_cb");
return FAIL;
@@ -4795,8 +4766,8 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
if (!(supported & JO_ERR_CALLBACK))
break;
opt->jo_set |= JO_ERR_CALLBACK;
- opt->jo_err_cb = get_callback(item, &opt->jo_err_partial);
- if (opt->jo_err_cb == NULL)
+ opt->jo_err_cb = get_callback(item);
+ if (opt->jo_err_cb.cb_name == NULL)
{
semsg(_(e_invargval), "err_cb");
return FAIL;
@@ -4807,8 +4778,8 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
if (!(supported & JO_CLOSE_CALLBACK))
break;
opt->jo_set |= JO_CLOSE_CALLBACK;
- opt->jo_close_cb = get_callback(item, &opt->jo_close_partial);
- if (opt->jo_close_cb == NULL)
+ opt->jo_close_cb = get_callback(item);
+ if (opt->jo_close_cb.cb_name == NULL)
{
semsg(_(e_invargval), "close_cb");
return FAIL;
@@ -4833,8 +4804,8 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
if (!(supported & JO_EXIT_CB))
break;
opt->jo_set |= JO_EXIT_CB;
- opt->jo_exit_cb = get_callback(item, &opt->jo_exit_partial);
- if (opt->jo_exit_cb == NULL)
+ opt->jo_exit_cb = get_callback(item);
+ if (opt->jo_exit_cb.cb_name == NULL)
{
semsg(_(e_invargval), "exit_cb");
return FAIL;
@@ -5201,7 +5172,7 @@ job_free_contents(job_T *job)
#ifdef MSWIN
vim_free(job->jv_tty_type);
#endif
- free_callback(job->jv_exit_cb, job->jv_exit_partial);
+ free_callback(&job->jv_exit_cb);
if (job->jv_argv != NULL)
{
for (i = 0; job->jv_argv[i] != NULL; i++)
@@ -5289,7 +5260,7 @@ job_free_all(void)
job_need_end_check(job_T *job)
{
return job->jv_status == JOB_STARTED
- && (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL);
+ && (job->jv_stoponexit != NULL || job->jv_exit_cb.cb_name != NULL);
}
/*
@@ -5465,22 +5436,22 @@ job_cleanup(job_T *job)
if (job->jv_channel != NULL)
ch_close_part(job->jv_channel, PART_IN);
- if (job->jv_exit_cb != NULL)
+ if (job->jv_exit_cb.cb_name != NULL)
{
typval_T argv[3];
typval_T rettv;
int dummy;
/* Invoke the exit callback. Make sure the refcount is > 0. */
- ch_log(job->jv_channel, "Invoking exit callback %s", job->jv_exit_cb);
+ ch_log(job->jv_channel, "Invoking exit callback %s",
+ job->jv_exit_cb.cb_name);
++job->jv_refcount;
argv[0].v_type = VAR_JOB;
argv[0].vval.v_job = job;
argv[1].v_type = VAR_NUMBER;
argv[1].vval.v_number = job->jv_exitval;
- call_func(job->jv_exit_cb, -1,
- &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
- job->jv_exit_partial, NULL);
+ call_callback(&job->jv_exit_cb, -1,
+ &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv);
--job->jv_refcount;
channel_need_redraw = TRUE;
@@ -5622,26 +5593,14 @@ job_set_options(job_T *job, jobopt_T *opt)
}
if (opt->jo_set & JO_EXIT_CB)
{
- free_callback(job->jv_exit_cb, job->jv_exit_partial);
- if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
+ free_callback(&job->jv_exit_cb);
+ if (opt->jo_exit_cb.cb_name == NULL || *opt->jo_exit_cb.cb_name == NUL)
{
- job->jv_exit_cb = NULL;
- job->jv_exit_partial = NULL;
+ job->jv_exit_cb.cb_name = NULL;
+ job->jv_exit_cb.cb_partial = NULL;
}
else
- {
- job->jv_exit_partial = opt->jo_exit_partial;
- if (job->jv_exit_partial != NULL)
- {
- job->jv_exit_cb = opt->jo_exit_cb;
- ++job->jv_exit_partial->pt_refcount;
- }
- else
- {
- job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
- func_ref(job->jv_exit_cb);
- }
- }
+ copy_callback(&job->jv_exit_cb, &opt->jo_exit_cb);
}
}
@@ -5959,7 +5918,7 @@ job_info(job_T *job, dict_T *dict)
dict_add_string(dict, "tty_out", job->jv_tty_out);
dict_add_number(dict, "exitval", job->jv_exitval);
- dict_add_string(dict, "exit_cb", job->jv_exit_cb);
+ dict_add_string(dict, "exit_cb", job->jv_exit_cb.cb_name);
dict_add_string(dict, "stoponexit", job->jv_stoponexit);
#ifdef UNIX
dict_add_string(dict, "termsig", job->jv_termsig);
@@ -6059,7 +6018,8 @@ invoke_prompt_callback(void)
curwin->w_cursor.lnum = lnum + 1;
curwin->w_cursor.col = 0;
- if (curbuf->b_prompt_callback == NULL || *curbuf->b_prompt_callback == NUL)
+ if (curbuf->b_prompt_callback.cb_name == NULL
+ || *curbuf->b_prompt_callback.cb_name == NUL)
return;
text = ml_get(lnum);
prompt = prompt_text();
@@ -6069,9 +6029,8 @@ invoke_prompt_callback(void)
argv[0].vval.v_string = vim_strsave(text);
argv[1].v_type = VAR_UNKNOWN;
- call_func(curbuf->b_prompt_callback, -1,
- &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
- curbuf->b_prompt_partial, NULL);
+ call_callback(&curbuf->b_prompt_callback, -1,
+ &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&argv[0]);
clear_tv(&rettv);
}
@@ -6086,15 +6045,14 @@ invoke_prompt_interrupt(void)
int dummy;
typval_T argv[1];
- if (curbuf->b_prompt_interrupt == NULL
- || *curbuf->b_prompt_interrupt == NUL)
+ if (curbuf->b_prompt_interrupt.cb_name == NULL
+ || *curbuf->b_prompt_interrupt.cb_name == NUL)
return FALSE;
argv[0].v_type = VAR_UNKNOWN;
got_int = FALSE; // don't skip executing commands
- call_func(curbuf->b_prompt_interrupt, -1,
- &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE,
- curbuf->b_prompt_int_partial, NULL);
+ call_callback(&curbuf->b_prompt_interrupt, -1,
+ &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv);
return TRUE;
}
diff --git a/src/eval.c b/src/eval.c
index dc96e050b0..af7a4af8a6 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -5920,10 +5920,10 @@ set_ref_in_item(
dtv.vval.v_channel = job->jv_channel;
set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
}
- if (job->jv_exit_partial != NULL)
+ if (job->jv_exit_cb.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
- dtv.vval.v_partial = job->jv_exit_partial;
+ dtv.vval.v_partial = job->jv_exit_cb.cb_partial;
set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
}
}
@@ -5946,29 +5946,30 @@ set_ref_in_item(
set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack);
for (cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL;
cq = cq->cq_next)
- if (cq->cq_partial != NULL)
+ if (cq->cq_callback.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
- dtv.vval.v_partial = cq->cq_partial;
+ dtv.vval.v_partial = cq->cq_callback.cb_partial;
set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
}
- if (ch->ch_part[part].ch_partial != NULL)
+ if (ch->ch_part[part].ch_callback.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
- dtv.vval.v_partial = ch->ch_part[part].ch_partial;
+ dtv.vval.v_partial =
+ ch->ch_part[part].ch_callback.cb_partial;
set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
}
}
- if (ch->ch_partial != NULL)
+ if (ch->ch_callback.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
- dtv.vval.v_partial = ch->ch_partial;
+ dtv.vval.v_partial = ch->ch_callback.cb_partial;
set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
}
- if (ch->ch_close_partial != NULL)
+ if (ch->ch_close_cb.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
- dtv.vval.v_partial = ch->ch_close_partial;
+ dtv.vval.v_partial = ch->ch_close_cb.cb_partial;
set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
}
}
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;
}
}
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index f6d9f331fa..5a33bb128c 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -282,7 +282,7 @@ remove_timer(timer_T *timer)
static void
free_timer(timer_T *timer)
{
- free_callback(timer->tr_callback, timer->tr_partial);
+ free_callback(&timer->tr_callback);
vim_free(timer);
}
@@ -325,9 +325,8 @@ timer_callback(timer_T *timer)
argv[0].vval.v_number = (varnumber_T)timer->tr_id;
argv[1].v_type = VAR_UNKNOWN;
- call_func(timer->tr_callback, -1,
- &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
- timer->tr_partial, NULL);
+ call_callback(&timer->tr_callback, -1,
+ &am