Mercurial > vim
diff src/eval.c @ 8041:c6443e78cf2d v7.4.1315
commit https://github.com/vim/vim/commit/7707344ddec9069b495b2a5ed41f2104466fc88b
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Feb 13 23:23:53 2016 +0100
patch 7.4.1315
Problem: Using a channel handle does not allow for freeing it when unused.
Solution: Add the Channel variable type.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 13 Feb 2016 23:30:05 +0100 |
parents | ece323e2b57f |
children | 167e22951df4 |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -509,6 +509,7 @@ static void f_ch_open(typval_T *argvars, 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 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 lo 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: @@ -6224,6 +6229,10 @@ tv_equal( #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 *rett #ifdef FEAT_CHANNEL /* - * Get the channel index from the handle argument. - * Returns -1 if the handle is invalid or the channel is closed. - */ - static int + * Get the channel from the argument. + * Returns NULL if the handle is invalid. + */ + static channel_T * get_channel_arg(typval_T *tv) { - int ch_idx; - - if (tv->v_type != VAR_NUMBER) + channel_T *channel; + + if (tv->v_type != VAR_CHANNEL) { EMSG2(_(e_invarg2), get_tv_string(tv)); - return -1; - } - ch_idx = tv->vval.v_number; - - if (!channel_can_write_to(ch_idx)) - { - EMSGN(_("E906: not an open channel"), ch_idx); - return -1; - } - return ch_idx; + return NULL; + } + channel = tv->vval.v_channel; + + if (channel == NULL || !channel_is_open(channel)) + { + EMSG(_("E906: not an open channel")); + return NULL; + } + 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]); - - if (ch_idx >= 0) - channel_close(ch_idx); + channel_T *channel = get_channel_arg(&argvars[0]); + + if (channel != NULL) + channel_close(channel); } /* @@ -9873,10 +9897,11 @@ f_ch_open(typval_T *argvars, typval_T *r 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 *r return; } - ch_idx = channel_open((char *)address, port, waittime, NULL); - if (ch_idx >= 0) - { - channel_set_json_mode(ch_idx, ch_mode); - channel_set_timeout(ch_idx, timeout); + channel = channel_open((char *)address, port, waittime, NULL); + if (channel != NULL) + { + channel_set_json_mode(channel, ch_mode); + channel_set_timeout(channel, timeout); if (callback != NULL && *callback != NUL) - channel_set_callback(ch_idx, callback); - } - rettv->vval.v_number = ch_idx; + channel_set_callback(channel, callback); + } + rettv->vval.v_channel = channel; } /* @@ -9953,53 +9978,65 @@ f_ch_open(typval_T *argvars, typval_T *r 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) - { - EMSG(_(e_invarg)); - return; - } - rettv->vval.v_string = channel_read_block(ch_idx); + 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) + { + EMSG2(_(e_invarg2), get_tv_string(&argvars[0])); + rettv->vval.v_string = NULL; + } + 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. - */ - static int + * Returns the channel if the caller should read the response. + * Otherwise returns NULL. + */ + 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); - - if (channel_send(ch_idx, text, fun) == OK && callback == NULL) - return ch_idx; - return -1; + channel_set_req_callback(channel, callback, id); + + if (channel_send(channel, text, fun) == OK && callback == NULL) + return channel; + return NULL; } /* @@ -10010,7 +10047,7 @@ f_ch_sendexpr(typval_T *argvars, typval_ { 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_ rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - ch_idx = get_channel_arg(&argvars[0]); - if (ch_idx < 0) - { - EMSG(_(e_invarg)); - return; - } - - ch_mode = channel_get_mode(ch_idx); + channel = get_channel_arg(&argvars[0]); + if (channel == NULL) + return; + + 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_ 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_read_json_block(ch_idx, id, &listtv) == OK) + if (channel != NULL) + { + 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_ * 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 { 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 *ret 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, typv { 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 *rett 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; @@ -21412,6 +21457,11 @@ free_tv(typval_T *varp) 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: case VAR_UNKNOWN: @@ -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; } @@ -21531,6 +21586,11 @@ get_tv_number_chk(typval_T *varp, int *d 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)"); break; @@ -21572,6 +21632,11 @@ get_tv_float(typval_T *varp) 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)"); break; @@ -21707,6 +21772,18 @@ get_tv_string_buf_chk(typval_T *varp, ch } #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: EMSG(_("E908: using an invalid value as a String")); break; @@ -22337,6 +22414,12 @@ copy_tv(typval_T *from, typval_T *to) ++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: if (from->vval.v_string == NULL) @@ -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);