mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 7.4.1315
Problem: Using a channel handle does not allow for freeing it when unused. Solution: Add the Channel variable type.
This commit is contained in:
217
src/eval.c
217
src/eval.c
@@ -509,6 +509,7 @@ static void f_ch_open(typval_T *argvars, typval_T *rettv);
|
||||
static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
|
||||
static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
|
||||
static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
|
||||
static void f_ch_status(typval_T *argvars, typval_T *rettv);
|
||||
#endif
|
||||
static void f_changenr(typval_T *argvars, typval_T *rettv);
|
||||
static void f_char2nr(typval_T *argvars, typval_T *rettv);
|
||||
@@ -3084,6 +3085,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
|
||||
case VAR_FUNC:
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
break;
|
||||
|
||||
case VAR_LIST:
|
||||
@@ -3863,6 +3865,7 @@ item_lock(typval_T *tv, int deep, int lock)
|
||||
case VAR_FLOAT:
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
break;
|
||||
|
||||
case VAR_LIST:
|
||||
@@ -5359,6 +5362,7 @@ eval_index(
|
||||
#endif
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
if (verbose)
|
||||
EMSG(_("E909: Cannot index a special variable"));
|
||||
return FAIL;
|
||||
@@ -5471,6 +5475,7 @@ eval_index(
|
||||
case VAR_FLOAT:
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
break; /* not evaluating, skipping over subscript */
|
||||
|
||||
case VAR_NUMBER:
|
||||
@@ -6223,6 +6228,10 @@ tv_equal(
|
||||
case VAR_JOB:
|
||||
#ifdef FEAT_JOB
|
||||
return tv1->vval.v_job == tv2->vval.v_job;
|
||||
#endif
|
||||
case VAR_CHANNEL:
|
||||
#ifdef FEAT_CHANNEL
|
||||
return tv1->vval.v_channel == tv2->vval.v_channel;
|
||||
#endif
|
||||
case VAR_UNKNOWN:
|
||||
break;
|
||||
@@ -7719,12 +7728,26 @@ failret:
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef FEAT_CHANNEL
|
||||
static void
|
||||
channel_unref(channel_T *channel)
|
||||
{
|
||||
if (channel != NULL && --channel->ch_refcount <= 0)
|
||||
channel_free(channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_JOB
|
||||
static void
|
||||
job_free(job_T *job)
|
||||
{
|
||||
if (job->jv_channel >= 0)
|
||||
channel_close(job->jv_channel);
|
||||
if (job->jv_channel != NULL)
|
||||
{
|
||||
/* The channel doesn't count as a references for the job, we need to
|
||||
* NULL the reference when the job is freed. */
|
||||
job->jv_channel->ch_job = NULL;
|
||||
channel_unref(job->jv_channel);
|
||||
}
|
||||
mch_clear_job(job);
|
||||
vim_free(job);
|
||||
}
|
||||
@@ -7746,9 +7769,7 @@ job_alloc(void)
|
||||
|
||||
job = (job_T *)alloc_clear(sizeof(job_T));
|
||||
if (job != NULL)
|
||||
{
|
||||
job->jv_refcount = 1;
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
@@ -7850,6 +7871,7 @@ echo_string(
|
||||
case VAR_NUMBER:
|
||||
case VAR_UNKNOWN:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
*tofree = NULL;
|
||||
r = get_tv_string_buf(tv, numbuf);
|
||||
break;
|
||||
@@ -7906,6 +7928,7 @@ tv2string(
|
||||
case VAR_DICT:
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
case VAR_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
@@ -8093,6 +8116,7 @@ static struct fst
|
||||
{"ch_readraw", 1, 2, f_ch_readraw},
|
||||
{"ch_sendexpr", 2, 3, f_ch_sendexpr},
|
||||
{"ch_sendraw", 2, 3, f_ch_sendraw},
|
||||
{"ch_status", 1, 1, f_ch_status},
|
||||
#endif
|
||||
{"changenr", 0, 0, f_changenr},
|
||||
{"char2nr", 1, 2, f_char2nr},
|
||||
@@ -9781,27 +9805,27 @@ f_ceil(typval_T *argvars, typval_T *rettv)
|
||||
|
||||
#ifdef FEAT_CHANNEL
|
||||
/*
|
||||
* Get the channel index from the handle argument.
|
||||
* Returns -1 if the handle is invalid or the channel is closed.
|
||||
* Get the channel from the argument.
|
||||
* Returns NULL if the handle is invalid.
|
||||
*/
|
||||
static int
|
||||
static channel_T *
|
||||
get_channel_arg(typval_T *tv)
|
||||
{
|
||||
int ch_idx;
|
||||
channel_T *channel;
|
||||
|
||||
if (tv->v_type != VAR_NUMBER)
|
||||
if (tv->v_type != VAR_CHANNEL)
|
||||
{
|
||||
EMSG2(_(e_invarg2), get_tv_string(tv));
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ch_idx = tv->vval.v_number;
|
||||
channel = tv->vval.v_channel;
|
||||
|
||||
if (!channel_can_write_to(ch_idx))
|
||||
if (channel == NULL || !channel_is_open(channel))
|
||||
{
|
||||
EMSGN(_("E906: not an open channel"), ch_idx);
|
||||
return -1;
|
||||
EMSG(_("E906: not an open channel"));
|
||||
return NULL;
|
||||
}
|
||||
return ch_idx;
|
||||
return channel;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9810,10 +9834,10 @@ get_channel_arg(typval_T *tv)
|
||||
static void
|
||||
f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
{
|
||||
int ch_idx = get_channel_arg(&argvars[0]);
|
||||
channel_T *channel = get_channel_arg(&argvars[0]);
|
||||
|
||||
if (ch_idx >= 0)
|
||||
channel_close(ch_idx);
|
||||
if (channel != NULL)
|
||||
channel_close(channel);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9873,10 +9897,11 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
||||
int waittime = 0;
|
||||
int timeout = 2000;
|
||||
ch_mode_T ch_mode = MODE_JSON;
|
||||
int ch_idx;
|
||||
channel_T *channel;
|
||||
|
||||
/* default: fail */
|
||||
rettv->vval.v_number = -1;
|
||||
rettv->v_type = VAR_CHANNEL;
|
||||
rettv->vval.v_channel = NULL;
|
||||
|
||||
address = get_tv_string(&argvars[0]);
|
||||
if (argvars[1].v_type != VAR_UNKNOWN
|
||||
@@ -9936,15 +9961,15 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
||||
return;
|
||||
}
|
||||
|
||||
ch_idx = channel_open((char *)address, port, waittime, NULL);
|
||||
if (ch_idx >= 0)
|
||||
channel = channel_open((char *)address, port, waittime, NULL);
|
||||
if (channel != NULL)
|
||||
{
|
||||
channel_set_json_mode(ch_idx, ch_mode);
|
||||
channel_set_timeout(ch_idx, timeout);
|
||||
channel_set_json_mode(channel, ch_mode);
|
||||
channel_set_timeout(channel, timeout);
|
||||
if (callback != NULL && *callback != NUL)
|
||||
channel_set_callback(ch_idx, callback);
|
||||
channel_set_callback(channel, callback);
|
||||
}
|
||||
rettv->vval.v_number = ch_idx;
|
||||
rettv->vval.v_channel = channel;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9953,53 +9978,65 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
||||
static void
|
||||
f_ch_readraw(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
int ch_idx;
|
||||
channel_T *channel;
|
||||
|
||||
/* return an empty string by default */
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
ch_idx = get_channel_arg(&argvars[0]);
|
||||
if (ch_idx < 0)
|
||||
channel = get_channel_arg(&argvars[0]);
|
||||
if (channel != NULL)
|
||||
rettv->vval.v_string = channel_read_block(channel);
|
||||
}
|
||||
|
||||
/*
|
||||
* "ch_status()" function
|
||||
*/
|
||||
static void
|
||||
f_ch_status(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
/* return an empty string by default */
|
||||
rettv->v_type = VAR_STRING;
|
||||
|
||||
if (argvars[0].v_type != VAR_CHANNEL)
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
return;
|
||||
EMSG2(_(e_invarg2), get_tv_string(&argvars[0]));
|
||||
rettv->vval.v_string = NULL;
|
||||
}
|
||||
rettv->vval.v_string = channel_read_block(ch_idx);
|
||||
else
|
||||
rettv->vval.v_string = vim_strsave(
|
||||
(char_u *)channel_status(argvars[0].vval.v_channel));
|
||||
}
|
||||
|
||||
/*
|
||||
* common for "sendexpr()" and "sendraw()"
|
||||
* Returns the channel index if the caller should read the response.
|
||||
* Otherwise returns -1.
|
||||
* Returns the channel if the caller should read the response.
|
||||
* Otherwise returns NULL.
|
||||
*/
|
||||
static int
|
||||
static channel_T *
|
||||
send_common(typval_T *argvars, char_u *text, int id, char *fun)
|
||||
{
|
||||
int ch_idx;
|
||||
channel_T *channel;
|
||||
char_u *callback = NULL;
|
||||
|
||||
ch_idx = get_channel_arg(&argvars[0]);
|
||||
if (ch_idx < 0)
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
return -1;
|
||||
}
|
||||
channel = get_channel_arg(&argvars[0]);
|
||||
if (channel == NULL)
|
||||
return NULL;
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
callback = get_callback(&argvars[2]);
|
||||
if (callback == NULL)
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
/* Set the callback. An empty callback means no callback and not reading
|
||||
* the response. */
|
||||
if (callback != NULL && *callback != NUL)
|
||||
channel_set_req_callback(ch_idx, callback, id);
|
||||
channel_set_req_callback(channel, callback, id);
|
||||
|
||||
if (channel_send(ch_idx, text, fun) == OK && callback == NULL)
|
||||
return ch_idx;
|
||||
return -1;
|
||||
if (channel_send(channel, text, fun) == OK && callback == NULL)
|
||||
return channel;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -10010,7 +10047,7 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *text;
|
||||
typval_T *listtv;
|
||||
int ch_idx;
|
||||
channel_T *channel;
|
||||
int id;
|
||||
ch_mode_T ch_mode;
|
||||
|
||||
@@ -10018,14 +10055,11 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
ch_idx = get_channel_arg(&argvars[0]);
|
||||
if (ch_idx < 0)
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
channel = get_channel_arg(&argvars[0]);
|
||||
if (channel == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
ch_mode = channel_get_mode(ch_idx);
|
||||
ch_mode = channel_get_mode(channel);
|
||||
if (ch_mode == MODE_RAW)
|
||||
{
|
||||
EMSG(_("E912: cannot use ch_sendexpr() with a raw channel"));
|
||||
@@ -10038,11 +10072,11 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
||||
if (text == NULL)
|
||||
return;
|
||||
|
||||
ch_idx = send_common(argvars, text, id, "sendexpr");
|
||||
channel = send_common(argvars, text, id, "sendexpr");
|
||||
vim_free(text);
|
||||
if (ch_idx >= 0)
|
||||
if (channel != NULL)
|
||||
{
|
||||
if (channel_read_json_block(ch_idx, id, &listtv) == OK)
|
||||
if (channel_read_json_block(channel, id, &listtv) == OK)
|
||||
{
|
||||
list_T *list = listtv->vval.v_list;
|
||||
|
||||
@@ -10050,7 +10084,7 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
||||
* avoid the value being freed. */
|
||||
*rettv = list->lv_last->li_tv;
|
||||
list->lv_last->li_tv.v_type = VAR_NUMBER;
|
||||
clear_tv(listtv);
|
||||
free_tv(listtv);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10063,16 +10097,16 @@ f_ch_sendraw(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u *text;
|
||||
int ch_idx;
|
||||
channel_T *channel;
|
||||
|
||||
/* return an empty string by default */
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
text = get_tv_string_buf(&argvars[1], buf);
|
||||
ch_idx = send_common(argvars, text, 0, "sendraw");
|
||||
if (ch_idx >= 0)
|
||||
rettv->vval.v_string = channel_read_block(ch_idx);
|
||||
channel = send_common(argvars, text, 0, "sendraw");
|
||||
if (channel != NULL)
|
||||
rettv->vval.v_string = channel_read_block(channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10708,7 +10742,14 @@ f_empty(typval_T *argvars, typval_T *rettv)
|
||||
|
||||
case VAR_JOB:
|
||||
#ifdef FEAT_JOB
|
||||
n = argvars[0].vval.v_job->jv_status != JOB_STARTED;
|
||||
n = argvars[0].vval.v_job == NULL
|
||||
|| argvars[0].vval.v_job->jv_status != JOB_STARTED;
|
||||
break;
|
||||
#endif
|
||||
case VAR_CHANNEL:
|
||||
#ifdef FEAT_CMDWIN
|
||||
n = argvars[0].vval.v_channel == NULL
|
||||
|| !channel_is_open(argvars[0].vval.v_channel);
|
||||
break;
|
||||
#endif
|
||||
case VAR_UNKNOWN:
|
||||
@@ -14366,8 +14407,10 @@ f_job_getchannel(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
job_T *job = argvars[0].vval.v_job;
|
||||
|
||||
rettv->v_type = VAR_NUMBER;
|
||||
rettv->vval.v_number = job->jv_channel;
|
||||
rettv->v_type = VAR_CHANNEL;
|
||||
rettv->vval.v_channel = job->jv_channel;
|
||||
if (job->jv_channel != NULL)
|
||||
++job->jv_channel->ch_refcount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14659,6 +14702,7 @@ f_len(typval_T *argvars, typval_T *rettv)
|
||||
case VAR_FLOAT:
|
||||
case VAR_FUNC:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
EMSG(_("E701: Invalid type for len()"));
|
||||
break;
|
||||
}
|
||||
@@ -20040,7 +20084,8 @@ f_type(typval_T *argvars, typval_T *rettv)
|
||||
else
|
||||
n = 7;
|
||||
break;
|
||||
case VAR_JOB: n = 8; break;
|
||||
case VAR_JOB: n = 8; break;
|
||||
case VAR_CHANNEL: n = 9; break;
|
||||
case VAR_UNKNOWN:
|
||||
EMSG2(_(e_intern2), "f_type(UNKNOWN)");
|
||||
n = -1;
|
||||
@@ -21411,6 +21456,11 @@ free_tv(typval_T *varp)
|
||||
#ifdef FEAT_JOB
|
||||
job_unref(varp->vval.v_job);
|
||||
break;
|
||||
#endif
|
||||
case VAR_CHANNEL:
|
||||
#ifdef FEAT_CHANNEL
|
||||
channel_unref(varp->vval.v_channel);
|
||||
break;
|
||||
#endif
|
||||
case VAR_NUMBER:
|
||||
case VAR_FLOAT:
|
||||
@@ -21462,6 +21512,11 @@ clear_tv(typval_T *varp)
|
||||
varp->vval.v_job = NULL;
|
||||
#endif
|
||||
break;
|
||||
case VAR_CHANNEL:
|
||||
#ifdef FEAT_CHANNEL
|
||||
channel_unref(varp->vval.v_channel);
|
||||
varp->vval.v_channel = NULL;
|
||||
#endif
|
||||
case VAR_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
@@ -21530,6 +21585,11 @@ get_tv_number_chk(typval_T *varp, int *denote)
|
||||
#ifdef FEAT_JOB
|
||||
EMSG(_("E910: Using a Job as a Number"));
|
||||
break;
|
||||
#endif
|
||||
case VAR_CHANNEL:
|
||||
#ifdef FEAT_CHANNEL
|
||||
EMSG(_("E913: Using a Channel as a Number"));
|
||||
break;
|
||||
#endif
|
||||
case VAR_UNKNOWN:
|
||||
EMSG2(_(e_intern2), "get_tv_number(UNKNOWN)");
|
||||
@@ -21571,6 +21631,11 @@ get_tv_float(typval_T *varp)
|
||||
# ifdef FEAT_JOB
|
||||
EMSG(_("E911: Using a Job as a Float"));
|
||||
break;
|
||||
# endif
|
||||
case VAR_CHANNEL:
|
||||
# ifdef FEAT_CHANNEL
|
||||
EMSG(_("E914: Using a Channel as a Float"));
|
||||
break;
|
||||
# endif
|
||||
case VAR_UNKNOWN:
|
||||
EMSG2(_(e_intern2), "get_tv_float(UNKNOWN)");
|
||||
@@ -21705,6 +21770,18 @@ get_tv_string_buf_chk(typval_T *varp, char_u *buf)
|
||||
# endif
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case VAR_CHANNEL:
|
||||
#ifdef FEAT_CHANNEL
|
||||
{
|
||||
channel_T *channel = varp->vval.v_channel;
|
||||
char *status = channel_status(channel);
|
||||
|
||||
vim_snprintf((char *)buf, NUMBUFLEN,
|
||||
"channel %d %s", channel->ch_id, status);
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case VAR_UNKNOWN:
|
||||
@@ -22336,6 +22413,12 @@ copy_tv(typval_T *from, typval_T *to)
|
||||
to->vval.v_job = from->vval.v_job;
|
||||
++to->vval.v_job->jv_refcount;
|
||||
break;
|
||||
#endif
|
||||
case VAR_CHANNEL:
|
||||
#ifdef FEAT_CHANNEL
|
||||
to->vval.v_channel = from->vval.v_channel;
|
||||
++to->vval.v_channel->ch_refcount;
|
||||
break;
|
||||
#endif
|
||||
case VAR_STRING:
|
||||
case VAR_FUNC:
|
||||
@@ -22404,6 +22487,7 @@ item_copy(
|
||||
case VAR_FUNC:
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
copy_tv(from, to);
|
||||
break;
|
||||
case VAR_LIST:
|
||||
@@ -25076,6 +25160,7 @@ write_viminfo_varlist(FILE *fp)
|
||||
case VAR_UNKNOWN:
|
||||
case VAR_FUNC:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
continue;
|
||||
}
|
||||
fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
|
||||
|
Reference in New Issue
Block a user