diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-06-24 00:43:35 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-06-24 00:43:35 +0200 |
commit | 0a1f56fcfe31be929e9cd8c3d81a984c960e4180 (patch) | |
tree | 7bc7684aa4eccb489a5a6a1636dd612397c7348f /src | |
parent | 7be3ab25891fec711d8a2d9d242711a9155852b6 (diff) |
patch 8.1.1584: the evalfunc.c file is getting too bigv8.1.1584
Problem: The evalfunc.c file is getting too big.
Solution: Move channel and job related functions to channel.c.
Diffstat (limited to 'src')
-rw-r--r-- | src/channel.c | 1037 | ||||
-rw-r--r-- | src/evalfunc.c | 470 | ||||
-rw-r--r-- | src/proto/channel.pro | 31 | ||||
-rw-r--r-- | src/version.c | 2 |
4 files changed, 763 insertions, 777 deletions
diff --git a/src/channel.c b/src/channel.c index 4e6df94274..7671e19a62 100644 --- a/src/channel.c +++ b/src/channel.c @@ -952,176 +952,35 @@ channel_open( } /* - * Implements ch_open(). + * Copy callback from "src" to "dest", incrementing the refcounts. */ - channel_T * -channel_open_func(typval_T *argvars) -{ - char_u *address; - char_u *p; - char *rest; - int port; - jobopt_T opt; - channel_T *channel = NULL; - - address = tv_get_string(&argvars[0]); - if (argvars[1].v_type != VAR_UNKNOWN - && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL)) - { - emsg(_(e_invarg)); - return NULL; - } - - /* parse address */ - p = vim_strchr(address, ':'); - if (p == NULL) - { - semsg(_(e_invarg2), address); - return NULL; - } - *p++ = NUL; - port = strtol((char *)p, &rest, 10); - if (*address == NUL || port <= 0 || *rest != NUL) - { - p[-1] = ':'; - semsg(_(e_invarg2), address); - return NULL; - } - - /* parse options */ - clear_job_options(&opt); - opt.jo_mode = MODE_JSON; - opt.jo_timeout = 2000; - if (get_job_options(&argvars[1], &opt, - JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL) - goto theend; - if (opt.jo_timeout < 0) - { - emsg(_(e_invarg)); - goto theend; - } - - channel = channel_open((char *)address, port, opt.jo_waittime, NULL); - if (channel != NULL) - { - opt.jo_set = JO_ALL; - channel_set_options(channel, &opt); - } -theend: - free_job_options(&opt); - return channel; -} - static void -ch_close_part(channel_T *channel, ch_part_T part) -{ - sock_T *fd = &channel->ch_part[part].ch_fd; - - if (*fd != INVALID_FD) - { - if (part == PART_SOCK) - sock_close(*fd); - else - { - /* When using a pty the same FD is set on multiple parts, only - * close it when the last reference is closed. */ - if ((part == PART_IN || channel->CH_IN_FD != *fd) - && (part == PART_OUT || channel->CH_OUT_FD != *fd) - && (part == PART_ERR || channel->CH_ERR_FD != *fd)) - { -#ifdef MSWIN - if (channel->ch_named_pipe) - DisconnectNamedPipe((HANDLE)fd); -#endif - fd_close(*fd); - } - } - *fd = INVALID_FD; - - /* channel is closed, may want to end the job if it was the last */ - channel->ch_to_be_closed &= ~(1U << part); - } -} - - void -channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err) +copy_callback(callback_T *dest, callback_T *src) { - if (in != INVALID_FD) - { - ch_close_part(channel, PART_IN); - channel->CH_IN_FD = in; -# if defined(UNIX) - /* Do not end the job when all output channels are closed, wait until - * the job ended. */ - if (mch_isatty(in)) - channel->ch_to_be_closed |= (1U << PART_IN); -# endif - } - if (out != INVALID_FD) + dest->cb_partial = src->cb_partial; + if (dest->cb_partial != NULL) { -# if defined(FEAT_GUI) - channel_gui_unregister_one(channel, PART_OUT); -# endif - ch_close_part(channel, PART_OUT); - channel->CH_OUT_FD = out; - channel->ch_to_be_closed |= (1U << PART_OUT); -# if defined(FEAT_GUI) - channel_gui_register_one(channel, PART_OUT); -# endif + dest->cb_name = src->cb_name; + dest->cb_free_name = FALSE; + ++dest->cb_partial->pt_refcount; } - if (err != INVALID_FD) + else { -# if defined(FEAT_GUI) - channel_gui_unregister_one(channel, PART_ERR); -# endif - ch_close_part(channel, PART_ERR); - channel->CH_ERR_FD = err; - channel->ch_to_be_closed |= (1U << PART_ERR); -# if defined(FEAT_GUI) - channel_gui_register_one(channel, PART_ERR); -# endif + dest->cb_name = vim_strsave(src->cb_name); + dest->cb_free_name = TRUE; + func_ref(src->cb_name); } } -/* - * Sets the job the channel is associated with and associated options. - * This does not keep a refcount, when the job is freed ch_job is cleared. - */ - void -channel_set_job(channel_T *channel, job_T *job, jobopt_T *options) + static void +free_set_callback(callback_T *cbp, callback_T *callback) { - channel->ch_job = job; - - channel_set_options(channel, options); - - if (job->jv_in_buf != NULL) - { - chanpart_T *in_part = &channel->ch_part[PART_IN]; + free_callback(cbp); - set_bufref(&in_part->ch_bufref, job->jv_in_buf); - ch_log(channel, "reading from buffer '%s'", - (char *)in_part->ch_bufref.br_buf->b_ffname); - if (options->jo_set & JO_IN_TOP) - { - if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT)) - { - /* Special mode: send last-but-one line when appending a line - * to the buffer. */ - in_part->ch_bufref.br_buf->b_write_to_channel = TRUE; - in_part->ch_buf_append = TRUE; - in_part->ch_buf_top = - in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1; - } - else - in_part->ch_buf_top = options->jo_in_top; - } - else - in_part->ch_buf_top = 1; - if (options->jo_set & JO_IN_BOT) - in_part->ch_buf_bot = options->jo_in_bot; - else - in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count; - } + if (callback->cb_name != NULL && *callback->cb_name != NUL) + copy_callback(cbp, callback); + else + cbp->cb_name = NULL; } /* @@ -1179,41 +1038,9 @@ find_buffer(char_u *name, int err, int msg) } /* - * Copy callback from "src" to "dest", incrementing the refcounts. - */ - static void -copy_callback(callback_T *dest, callback_T *src) -{ - dest->cb_partial = src->cb_partial; - if (dest->cb_partial != NULL) - { - 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->cb_name = NULL; -} - -/* * Set various properties from an "opt" argument. */ - void + static void channel_set_options(channel_T *channel, jobopt_T *opt) { ch_part_T part; @@ -1346,6 +1173,179 @@ channel_set_options(channel_T *channel, jobopt_T *opt) } /* + * Implements ch_open(). + */ + channel_T * +channel_open_func(typval_T *argvars) +{ + char_u *address; + char_u *p; + char *rest; + int port; + jobopt_T opt; + channel_T *channel = NULL; + + address = tv_get_string(&argvars[0]); + if (argvars[1].v_type != VAR_UNKNOWN + && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL)) + { + emsg(_(e_invarg)); + return NULL; + } + + /* parse address */ + p = vim_strchr(address, ':'); + if (p == NULL) + { + semsg(_(e_invarg2), address); + return NULL; + } + *p++ = NUL; + port = strtol((char *)p, &rest, 10); + if (*address == NUL || port <= 0 || *rest != NUL) + { + p[-1] = ':'; + semsg(_(e_invarg2), address); + return NULL; + } + + /* parse options */ + clear_job_options(&opt); + opt.jo_mode = MODE_JSON; + opt.jo_timeout = 2000; + if (get_job_options(&argvars[1], &opt, + JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL) + goto theend; + if (opt.jo_timeout < 0) + { + emsg(_(e_invarg)); + goto theend; + } + + channel = channel_open((char *)address, port, opt.jo_waittime, NULL); + if (channel != NULL) + { + opt.jo_set = JO_ALL; + channel_set_options(channel, &opt); + } +theend: + free_job_options(&opt); + return channel; +} + + static void +ch_close_part(channel_T *channel, ch_part_T part) +{ + sock_T *fd = &channel->ch_part[part].ch_fd; + + if (*fd != INVALID_FD) + { + if (part == PART_SOCK) + sock_close(*fd); + else + { + /* When using a pty the same FD is set on multiple parts, only + * close it when the last reference is closed. */ + if ((part == PART_IN || channel->CH_IN_FD != *fd) + && (part == PART_OUT || channel->CH_OUT_FD != *fd) + && (part == PART_ERR || channel->CH_ERR_FD != *fd)) + { +#ifdef MSWIN + if (channel->ch_named_pipe) + DisconnectNamedPipe((HANDLE)fd); +#endif + fd_close(*fd); + } + } + *fd = INVALID_FD; + + /* channel is closed, may want to end the job if it was the last */ + channel->ch_to_be_closed &= ~(1U << part); + } +} + + void +channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err) +{ + if (in != INVALID_FD) + { + ch_close_part(channel, PART_IN); + channel->CH_IN_FD = in; +# if defined(UNIX) + /* Do not end the job when all output channels are closed, wait until + * the job ended. */ + if (mch_isatty(in)) + channel->ch_to_be_closed |= (1U << PART_IN); +# endif + } + if (out != INVALID_FD) + { +# if defined(FEAT_GUI) + channel_gui_unregister_one(channel, PART_OUT); +# endif + ch_close_part(channel, PART_OUT); + channel->CH_OUT_FD = out; + channel->ch_to_be_closed |= (1U << PART_OUT); +# if defined(FEAT_GUI) + channel_gui_register_one(channel, PART_OUT); +# endif + } + if (err != INVALID_FD) + { +# if defined(FEAT_GUI) + channel_gui_unregister_one(channel, PART_ERR); +# endif + ch_close_part(channel, PART_ERR); + channel->CH_ERR_FD = err; + channel->ch_to_be_closed |= (1U << PART_ERR); +# if defined(FEAT_GUI) + channel_gui_register_one(channel, PART_ERR); +# endif + } +} + +/* + * Sets the job the channel is associated with and associated options. + * This does not keep a refcount, when the job is freed ch_job is cleared. + */ + void +channel_set_job(channel_T *channel, job_T *job, jobopt_T *options) +{ + channel->ch_job = job; + + channel_set_options(channel, options); + + if (job->jv_in_buf != NULL) + { + chanpart_T *in_part = &channel->ch_part[PART_IN]; + + set_bufref(&in_part->ch_bufref, job->jv_in_buf); + ch_log(channel, "reading from buffer '%s'", + (char *)in_part->ch_bufref.br_buf->b_ffname); + if (options->jo_set & JO_IN_TOP) + { + if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT)) + { + /* Special mode: send last-but-one line when appending a line + * to the buffer. */ + in_part->ch_bufref.br_buf->b_write_to_channel = TRUE; + in_part->ch_buf_append = TRUE; + in_part->ch_buf_top = + in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1; + } + else + in_part->ch_buf_top = options->jo_in_top; + } + else + in_part->ch_buf_top = 1; + if (options->jo_set & JO_IN_BOT) + in_part->ch_buf_bot = options->jo_in_bot; + else + in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count; + } +} + +/* * Set the callback for "channel"/"part" for the response with "id". */ void @@ -3627,6 +3627,46 @@ channel_read_json_block( } /* + * Get the channel from the argument. + * Returns NULL if the handle is invalid. + * When "check_open" is TRUE check that the channel can be used. + * When "reading" is TRUE "check_open" considers typeahead useful. + * "part" is used to check typeahead, when PART_COUNT use the default part. + */ + static channel_T * +get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part) +{ + channel_T *channel = NULL; + int has_readahead = FALSE; + + if (tv->v_type == VAR_JOB) + { + if (tv->vval.v_job != NULL) + channel = tv->vval.v_job->jv_channel; + } + else if (tv->v_type == VAR_CHANNEL) + { + channel = tv->vval.v_channel; + } + else + { + semsg(_(e_invarg2), tv_get_string(tv)); + return NULL; + } + if (channel != NULL && reading) + has_readahead = channel_has_readahead(channel, + part != PART_COUNT ? part : channel_part_read(channel)); + + if (check_open && (channel == NULL || (!channel_is_open(channel) + && !(reading && has_readahead)))) + { + emsg(_("E906: not an open channel")); + return NULL; + } + return channel; +} + +/* * Common for ch_read() and ch_readraw(). */ void @@ -5193,46 +5233,6 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) return OK; } -/* - * Get the channel from the argument. - * Returns NULL if the handle is invalid. - * When "check_open" is TRUE check that the channel can be used. - * When "reading" is TRUE "check_open" considers typeahead useful. - * "part" is used to check typeahead, when PART_COUNT use the default part. - */ - channel_T * -get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part) -{ - channel_T *channel = NULL; - int has_readahead = FALSE; - - if (tv->v_type == VAR_JOB) - { - if (tv->vval.v_job != NULL) - channel = tv->vval.v_job->jv_channel; - } - else if (tv->v_type == VAR_CHANNEL) - { - channel = tv->vval.v_channel; - } - else - { - semsg(_(e_invarg2), tv_get_string(tv)); - return NULL; - } - if (channel != NULL && reading) - has_readahead = channel_has_readahead(channel, - part != PART_COUNT ? part : channel_part_read(channel)); - - if (check_open && (channel == NULL || (!channel_is_open(channel) - && !(reading && has_readahead)))) - { - emsg(_("E906: not an open channel")); - return NULL; - } - return channel; -} - static job_T *first_job = NULL; static void @@ -5976,77 +5976,6 @@ job_status(job_T *job) } /* - * Implementation of job_info(). - */ - void -job_info(job_T *job, dict_T *dict) -{ - dictitem_T *item; - varnumber_T nr; - list_T *l; - int i; - - dict_add_string(dict, "status", (char_u *)job_status(job)); - - item = dictitem_alloc((char_u *)"channel"); - if (item == NULL) - return; - item->di_tv.v_type = VAR_CHANNEL; - item->di_tv.vval.v_channel = job->jv_channel; - if (job->jv_channel != NULL) - ++job->jv_channel->ch_refcount; - if (dict_add(dict, item) == FAIL) - dictitem_free(item); - -#ifdef UNIX - nr = job->jv_pid; -#else - nr = job->jv_proc_info.dwProcessId; -#endif - dict_add_number(dict, "process", nr); - dict_add_string(dict, "tty_in", job->jv_tty_in); - 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.cb_name); - dict_add_string(dict, "stoponexit", job->jv_stoponexit); -#ifdef UNIX - dict_add_string(dict, "termsig", job->jv_termsig); -#endif -#ifdef MSWIN - dict_add_string(dict, "tty_type", job->jv_tty_type); -#endif - - l = list_alloc(); - if (l != NULL) - { - dict_add_list(dict, "cmd", l); - if (job->jv_argv != NULL) - for (i = 0; job->jv_argv[i] != NULL; i++) - list_append_string(l, (char_u *)job->jv_argv[i], -1); - } -} - -/* - * Implementation of job_info() to return info for all jobs. - */ - void -job_info_all(list_T *l) -{ - job_T *job; - typval_T tv; - - for (job = first_job; job != NULL; job = job->jv_next) - { - tv.v_type = VAR_JOB; - tv.vval.v_job = job; - - if (list_append_tv(l, &tv) != OK) - return; - } -} - -/* * Send a signal to "job". Implements job_stop(). * When "type" is not NULL use this for the type. * Otherwise use argvars[1] for the type. @@ -6147,4 +6076,506 @@ invoke_prompt_interrupt(void) return TRUE; } +/* + * "prompt_setcallback({buffer}, {callback})" function + */ + void +f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED) +{ + buf_T *buf; + callback_T callback; + + if (check_secure()) + return; + buf = tv_get_buf(&argvars[0], FALSE); + if (buf == NULL) + return; + + callback = get_callback(&argvars[1]); + if (callback.cb_name == NULL) + return; + + free_callback(&buf->b_prompt_callback); + set_callback(&buf->b_prompt_callback, &callback); +} + +/* + * "prompt_setinterrupt({buffer}, {callback})" function + */ + void +f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED) +{ + buf_T *buf; + callback_T callback; + + if (check_secure()) + return; + buf = tv_get_buf(&argvars[0], FALSE); + if (buf == NULL) + return; + + callback = get_callback(&argvars[1]); + if (callback.cb_name == NULL) + return; + + free_callback(&buf->b_prompt_interrupt); + set_callback(&buf->b_prompt_interrupt, &callback); +} + +/* + * "prompt_setprompt({buffer}, {text})" function + */ + void +f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED) +{ + buf_T *buf; + char_u *text; + + if (check_secure()) + return; + buf = tv_get_buf(&argvars[0], FALSE); + if (buf == NULL) + return; + + text = tv_get_string(&argvars[1]); + vim_free(buf->b_prompt_text); + buf->b_prompt_text = vim_strsave(text); +} + +/* + * "ch_canread()" function + */ + void +f_ch_canread(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + + rettv->vval.v_number = 0; + if (channel != NULL) + rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK) + || channel_has_readahead(channel, PART_OUT) + || channel_has_readahead(channel, PART_ERR); +} + +/* + * "ch_close()" function + */ + void +f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); + + if (channel != NULL) + { + channel_close(channel, FALSE); + channel_clear(channel); + } +} + +/* + * "ch_close()" function + */ + void +f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); + + if (channel != NULL) + channel_close_in(channel); +} + +/* + * "ch_getbufnr()" function + */ + void +f_ch_getbufnr(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + + rettv->vval.v_number = -1; + if (channel != NULL) + { + char_u *what = tv_get_string(&argvars[1]); + int part; + + if (STRCMP(what, "err") == 0) + part = PART_ERR; + else if (STRCMP(what, "out") == 0) + part = PART_OUT; + else if (STRCMP(what, "in") == 0) + part = PART_IN; + else + part = PART_SOCK; + if (channel->ch_part[part].ch_bufref.br_buf != NULL) + rettv->vval.v_number = + channel->ch_part[part].ch_bufref.br_buf->b_fnum; + } +} + +/* + * "ch_getjob()" function + */ + void +f_ch_getjob(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + + if (channel != NULL) + { + rettv->v_type = VAR_JOB; + rettv->vval.v_job = channel->ch_job; + if (channel->ch_job != NULL) + ++channel->ch_job->jv_refcount; + } +} + +/* + * "ch_info()" function + */ + void +f_ch_info(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + + if (channel != NULL && rettv_dict_alloc(rettv) != FAIL) + channel_info(channel, rettv->vval.v_dict); +} + +/* + * "ch_log()" function + */ + void +f_ch_log(typval_T *argvars, typval_T *rettv UNUSED) +{ + char_u *msg = tv_get_string(&argvars[0]); + channel_T *channel = NULL; + + if (argvars[1].v_type != VAR_UNKNOWN) + channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0); + + ch_log(channel, "%s", msg); +} + +/* + * "ch_logfile()" function + */ + void +f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED) +{ + char_u *fname; + char_u *opt = (char_u *)""; + char_u buf[NUMBUFLEN]; + + /* Don't open a file in restricted mode. */ + if (check_restricted() || check_secure()) + return; + fname = tv_get_string(&argvars[0]); + if (argvars[1].v_type == VAR_STRING) + opt = tv_get_string_buf(&argvars[1], buf); + ch_logfile(fname, opt); +} + +/* + * "ch_open()" function + */ + void +f_ch_open(typval_T *argvars, typval_T *rettv) +{ + rettv->v_type = VAR_CHANNEL; + if (check_restricted() || check_secure()) + return; + rettv->vval.v_channel = channel_open_func(argvars); +} + +/* + * "ch_read()" function + */ + void +f_ch_read(typval_T *argvars, typval_T *rettv) +{ + common_channel_read(argvars, rettv, FALSE, FALSE); +} + +/* + * "ch_readblob()" function + */ + void +f_ch_readblob(typval_T *argvars, typval_T *rettv) +{ + common_channel_read(argvars, rettv, TRUE, TRUE); +} + +/* + * "ch_readraw()" function + */ + void +f_ch_readraw(typval_T *argvars, typval_T *rettv) +{ + common_channel_read(argvars, rettv, TRUE, FALSE); +} + +/* + * "ch_evalexpr()" function + */ + void +f_ch_evalexpr(typval_T *argvars, typval_T *rettv) +{ + ch_expr_common(argvars, rettv, TRUE); +} + +/* + * "ch_sendexpr()" function + */ + void +f_ch_sendexpr(typval_T *argvars, typval_T *rettv) +{ + ch_expr_common(argvars, rettv, FALSE); +} + +/* + * "ch_evalraw()" function + */ + void +f_ch_evalraw(typval_T *argvars, typval_T *rettv) +{ + ch_raw_common(argvars, rettv, TRUE); +} + +/* + * "ch_sendraw()" function + */ + void +f_ch_sendraw(typval_T *argvars, typval_T *rettv) +{ + ch_raw_common(argvars, rettv, FALSE); +} + +/* + * "ch_setoptions()" function + */ + void +f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) +{ + channel_T *channel; + jobopt_T opt; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + if (channel == NULL) + return; + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, + JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK) + channel_set_options(channel, &opt); + free_job_options(&opt); +} + +/* + * "ch_status()" function + */ + void +f_ch_status(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel; + jobopt_T opt; + int part = -1; + + /* return an empty string by default */ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); + + if (argvars[1].v_type != VAR_UNKNOWN) + { + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK + && (opt.jo_set & JO_PART)) + part = opt.jo_part; + } + + rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part)); +} + +/* + * Get the job from the argument. + * Returns NULL if the job is invalid. + */ + static job_T * +get_job_arg(typval_T *tv) +{ + job_T *job; + + if (tv->v_type != VAR_JOB) + { + semsg(_(e_invarg2), tv_get_string(tv)); + return NULL; + } + job = tv->vval.v_job; + + if (job == NULL) + emsg(_("E916: not a valid job")); + return job; +} + +/* + * "job_getchannel()" function + */ + void +f_job_getchannel(typval_T *argvars, typval_T *rettv) +{ + job_T *job = get_job_arg(&argvars[0]); + + if (job != NULL) + { + rettv->v_type = VAR_CHANNEL; + rettv->vval.v_channel = job->jv_channel; + if (job->jv_channel != NULL) + ++job->jv_channel->ch_refcount; + } +} + +/* + * Implementation of job_info(). + */ + static void +job_info(job_T *job, dict_T *dict) +{ + dictitem_T *item; + varnumber_T nr; + list_T *l; + int i; + + dict_add_string(dict, "status", (char_u *)job_status(job)); + + item = dictitem_alloc((char_u *)"channel"); + if (item == NULL) + return; + item->di_tv.v_type = VAR_CHANNEL; + item->di_tv.vval.v_channel = job->jv_channel; + if (job->jv_channel != NULL) + ++job->jv_channel->ch_refcount; + if (dict_add(dict, item) == FAIL) + dictitem_free(item); + +#ifdef UNIX + nr = job->jv_pid; +#else + nr = job->jv_proc_info.dwProcessId; +#endif + dict_add_number(dict, "process", nr); + dict_add_string(dict, "tty_in", job->jv_tty_in); + 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.cb_name); + dict_add_string(dict, "stoponexit", job->jv_stoponexit); +#ifdef UNIX + dict_add_string(dict, "termsig", job->jv_termsig); +#endif +#ifdef MSWIN + dict_add_string(dict, "tty_type", job->jv_tty_type); +#endif + + l = list_alloc(); + if (l != NULL) + { + dict_add_list(dict, "cmd", l); + if (job->jv_argv != NULL) + for (i = 0; job->jv_argv[i] != NULL; i++) + list_append_string(l, (char_u *)job->jv_argv[i], -1); + } +} + +/* + * Implementation of job_info() to return info for all jobs. + */ + static void +job_info_all(list_T *l) +{ + job_T *job; + typval_T tv; + + for (job = first_job; job != NULL; job = job->jv_next) + { + tv.v_type = VAR_JOB; + tv.vval.v_job = job; + + if (list_append_tv(l, &tv) != OK) + return; + } +} + +/* + * "job_info()" function + */ + void +f_job_info(typval_T *argvars, typval_T *rettv) +{ + if (argvars[0].v_type != VAR_UNKNOWN) + { + job_T *job = get_job_arg(&argvars[0]); + + if (job != NULL && rettv_dict_alloc(rettv) != FAIL) + job_info(job, rettv->vval.v_dict); + } + else if (rettv_list_alloc(rettv) == OK) + job_info_all(rettv->vval.v_list); +} + +/* + * "job_setoptions()" function + */ + void +f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED) +{ + job_T *job = get_job_arg(&argvars[0]); + jobopt_T opt; + + if (job == NULL) + return; + clear_job_options(&opt); + if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK) + job_set_options(job, &opt); + free_job_options(&opt); +} + +/* + * "job_start()" function + */ + void +f_job_start(typval_T *argvars, typval_T *rettv) +{ + rettv->v_type = VAR_JOB; + if (check_restricted() || check_secure()) + return; + rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE); +} + +/* + * "job_status()" function + */ + void +f_job_status(typval_T *argvars, typval_T *rettv) +{ + job_T *job = get_job_arg(&argvars[0]); + + if (job != NULL) + { + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strsave((char_u *)job_status(job)); + } +} + +/* + * "job_stop()" function + */ + void +f_job_stop(typval_T *argvars, typval_T *rettv) +{ + job_T *job = get_job_arg(&argvars[0]); + + if (job != NULL) + rettv->vval.v_number = job_stop(job, argvars, NULL); +} + #endif /* FEAT_JOB_CHANNEL */ diff --git a/src/evalfunc.c b/src/evalfunc.c index 7930eb9825..faedda31ce 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -86,26 +86,6 @@ static void f_call(typval_T *argvars, typval_T *rettv); #ifdef FEAT_FLOAT static void f_ceil(typval_T *argvars, typval_T *rettv); #endif -#ifdef FEAT_JOB_CHANNEL -static void f_ch_canread(typval_T *argvars, typval_T *rettv); -static void f_ch_close(typval_T *argvars, typval_T *rettv); -static void f_ch_close_in(typval_T *argvars, typval_T *rettv); -static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv); -static void f_ch_evalraw(typval_T *argvars, typval_T *rettv); -static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv); -static void f_ch_getjob(typval_T *argvars, typval_T *rettv); -static void f_ch_info(typval_T *argvars, typval_T *rettv); -static void f_ch_log(typval_T *argvars, typval_T *rettv); -static void f_ch_logfile(typval_T *argvars, typval_T *rettv); -static void f_ch_open(typval_T *argvars, typval_T *rettv); -static void f_ch_read(typval_T *argvars, typval_T *rettv); -static void f_ch_readblob(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_setoptions(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); static void f_chdir(typval_T *argvars, typval_T *rettv); @@ -246,14 +226,6 @@ static void f_isinf(typval_T *argvars, typval_T *rettv); static void f_isnan(typval_T *argvars, typval_T *rettv); #endif static void f_items(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_JOB_CHANNEL -static void f_job_getchannel(typval_T *argvars, typval_T *rettv); -static void f_job_info(typval_T *argvars, typval_T *rettv); -static void f_job_setoptions(typval_T *argvars, typval_T *rettv); -static void f_job_start(typval_T *argvars, typval_T *rettv); -static void f_job_stop(typval_T *argvars, typval_T *rettv); -static void f_job_status(typval_T *argvars, typval_T *rettv); -#endif static void f_join(typval_T *argvars, typval_T *rettv); static void f_js_decode(typval_T *argvars, typval_T *rettv); static void f_js_encode(typval_T *argvars, typval_T *rettv); @@ -309,11 +281,6 @@ static void f_pow(typval_T *argvars, typval_T *rettv); #endif static void f_prevnonblank(typval_T *argvars, typval_T *rettv); static void f_printf(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_JOB_CHANNEL -static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv); -static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv); -static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv); -#endif static void f_pumvisible(typval_T *argvars, typval_T *rettv); #ifdef FEAT_PYTHON3 static void f_py3eval(typval_T *argvars, typval_T *rettv); @@ -2271,262 +2238,6 @@ f_ceil(typval_T *argvars, typval_T *rettv) } #endif -#ifdef FEAT_JOB_CHANNEL -/* - * "ch_canread()" function - */ - static void -f_ch_canread(typval_T *argvars, typval_T *rettv) -{ - channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); - - rettv->vval.v_number = 0; - if (channel != NULL) - rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK) - || channel_has_readahead(channel, PART_OUT) - || channel_has_readahead(channel, PART_ERR); -} - -/* - * "ch_close()" function - */ - static void -f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) -{ - channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); - - if (channel != NULL) - { - channel_close(channel, FALSE); - channel_clear(channel); - } -} - -/* - * "ch_close()" function - */ - static void -f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED) -{ - channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); - - if (channel |