# HG changeset patch # User Bram Moolenaar # Date 1622919603 -7200 # Node ID 8fdf839af1f420d80d6f4a4050f491570d95242d # Parent e89d42919a211a9b527583489db96539a5ecd3e4 patch 8.2.2944: Vim9: no error when using job or channel as a string Commit: https://github.com/vim/vim/commit/1328bde9d406aa1292e92673fa8a026889424e79 Author: Bram Moolenaar Date: Sat Jun 5 20:51:38 2021 +0200 patch 8.2.2944: Vim9: no error when using job or channel as a string Problem: Vim9: no error when using job or channel as a string. Solution: Be more strict about conversion to string. (closes https://github.com/vim/vim/issues/8312) diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -5015,4 +5015,22 @@ f_ch_status(typval_T *argvars, typval_T rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part)); } +/* + * Get a string with information about the channel in "varp" in "buf". + * "buf" must be at least NUMBUFLEN long. + */ + char_u * +channel_to_string_buf(typval_T *varp, char_u *buf) +{ + channel_T *channel = varp->vval.v_channel; + char *status = channel_status(channel, -1); + + if (channel == NULL) + vim_snprintf((char *)buf, NUMBUFLEN, "channel %s", status); + else + vim_snprintf((char *)buf, NUMBUFLEN, + "channel %d %s", channel->ch_id, status); + return buf; +} + #endif // FEAT_JOB_CHANNEL diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -5060,7 +5060,8 @@ echo_string_core( case VAR_JOB: case VAR_CHANNEL: *tofree = NULL; - r = tv_get_string_buf(tv, numbuf); + r = tv->v_type == VAR_JOB ? job_to_string_buf(tv, numbuf) + : channel_to_string_buf(tv, numbuf); if (composite_val) { *tofree = string_quote(r, FALSE); diff --git a/src/job.c b/src/job.c --- a/src/job.c +++ b/src/job.c @@ -1927,4 +1927,34 @@ f_job_stop(typval_T *argvars, typval_T * rettv->vval.v_number = job_stop(job, argvars, NULL); } +/* + * Get a string with information about the job in "varp" in "buf". + * "buf" must be at least NUMBUFLEN long. + */ + char_u * +job_to_string_buf(typval_T *varp, char_u *buf) +{ + job_T *job = varp->vval.v_job; + char *status; + + if (job == NULL) + return (char_u *)"no process"; + status = job->jv_status == JOB_FAILED ? "fail" + : job->jv_status >= JOB_ENDED ? "dead" + : "run"; +# ifdef UNIX + vim_snprintf((char *)buf, NUMBUFLEN, + "process %ld %s", (long)job->jv_pid, status); +# elif defined(MSWIN) + vim_snprintf((char *)buf, NUMBUFLEN, + "process %ld %s", + (long)job->jv_proc_info.dwProcessId, + status); +# else + // fall-back + vim_snprintf((char *)buf, NUMBUFLEN, "process ? %s", status); +# endif + return buf; +} + #endif // FEAT_JOB_CHANNEL diff --git a/src/proto/channel.pro b/src/proto/channel.pro --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -58,4 +58,5 @@ void f_ch_evalraw(typval_T *argvars, typ void f_ch_sendraw(typval_T *argvars, typval_T *rettv); void f_ch_setoptions(typval_T *argvars, typval_T *rettv); void f_ch_status(typval_T *argvars, typval_T *rettv); +char_u *channel_to_string_buf(typval_T *varp, char_u *buf); /* vim: set ft=c : */ diff --git a/src/proto/job.pro b/src/proto/job.pro --- a/src/proto/job.pro +++ b/src/proto/job.pro @@ -34,4 +34,5 @@ void f_job_setoptions(typval_T *argvars, void f_job_start(typval_T *argvars, typval_T *rettv); void f_job_status(typval_T *argvars, typval_T *rettv); void f_job_stop(typval_T *argvars, typval_T *rettv); +char_u *job_to_string_buf(typval_T *varp, char_u *buf); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1104,7 +1104,7 @@ def Test_set_get_bufline() assert_equal([], getbufline(b, 2, 1)) if has('job') - setbufline(b, 2, [function('eval'), {key: 123}, test_null_job()]) + setbufline(b, 2, [function('eval'), {key: 123}, string(test_null_job())]) assert_equal(["function('eval')", "{'key': 123}", "no process"], @@ -1250,6 +1250,16 @@ def Test_submatch() actual->assert_equal(expected) enddef +def Test_substitute() + var res = substitute('A1234', '\d', 'X', '') + assert_equal('AX234', res) + + if has('job') + assert_fails('"text"->substitute(".*", () => job_start(":"), "")', 'E908: using an invalid value as a String: job') + assert_fails('"text"->substitute(".*", () => job_start(":")->job_getchannel(), "")', 'E908: using an invalid value as a String: channel') + endif +enddef + def Test_synID() new setline(1, "text") diff --git a/src/typval.c b/src/typval.c --- a/src/typval.c +++ b/src/typval.c @@ -414,7 +414,7 @@ tv_get_string_strict(typval_T *varp) char_u * tv_get_string_buf(typval_T *varp, char_u *buf) { - char_u *res = tv_get_string_buf_chk(varp, buf); + char_u *res = tv_get_string_buf_chk(varp, buf); return res != NULL ? res : (char_u *)""; } @@ -478,44 +478,22 @@ tv_get_string_buf_chk_strict(typval_T *v break; case VAR_JOB: #ifdef FEAT_JOB_CHANNEL + if (in_vim9script()) { - job_T *job = varp->vval.v_job; - char *status; - - if (job == NULL) - return (char_u *)"no process"; - status = job->jv_status == JOB_FAILED ? "fail" - : job->jv_status >= JOB_ENDED ? "dead" - : "run"; -# ifdef UNIX - vim_snprintf((char *)buf, NUMBUFLEN, - "process %ld %s", (long)job->jv_pid, status); -# elif defined(MSWIN) - vim_snprintf((char *)buf, NUMBUFLEN, - "process %ld %s", - (long)job->jv_proc_info.dwProcessId, - status); -# else - // fall-back - vim_snprintf((char *)buf, NUMBUFLEN, "process ? %s", status); -# endif - return buf; + semsg(_(e_using_invalid_value_as_string_str), "job"); + break; } + return job_to_string_buf(varp, buf); #endif break; case VAR_CHANNEL: #ifdef FEAT_JOB_CHANNEL + if (in_vim9script()) { - channel_T *channel = varp->vval.v_channel; - char *status = channel_status(channel, -1); - - if (channel == NULL) - vim_snprintf((char *)buf, NUMBUFLEN, "channel %s", status); - else - vim_snprintf((char *)buf, NUMBUFLEN, - "channel %d %s", channel->ch_id, status); - return buf; + semsg(_(e_using_invalid_value_as_string_str), "channel"); + break; } + return channel_to_string_buf(varp, buf); #endif break; case VAR_UNKNOWN: diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2944, +/**/ 2943, /**/ 2942, diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -4831,10 +4831,11 @@ list_instructions(char *pfx, isn_T *inst { typval_T tv; char_u *name; + char_u buf[NUMBUFLEN]; tv.v_type = VAR_JOB; tv.vval.v_job = iptr->isn_arg.job; - name = tv_get_string(&tv); + name = job_to_string_buf(&tv, buf); smsg("%s%4d PUSHJOB \"%s\"", pfx, current, name); } #endif