patch 7.4.1539
Problem: Too much code in eval.c.
Solution: Move job and channel code to channel.c.
diff --git a/src/eval.c b/src/eval.c
index e78bbb0..5807707 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -836,14 +836,11 @@
static int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int verbose);
static typval_T *alloc_string_tv(char_u *string);
static void init_tv(typval_T *varp);
-static long get_tv_number(typval_T *varp);
#ifdef FEAT_FLOAT
static float_T get_tv_float(typval_T *varp);
#endif
static linenr_T get_tv_lnum(typval_T *argvars);
static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf);
-static char_u *get_tv_string(typval_T *varp);
-static char_u *get_tv_string_buf(typval_T *varp, char_u *buf);
static dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
static hashtab_T *find_var_ht(char_u *name, char_u **varname);
@@ -7735,129 +7732,6 @@
}
#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
-/*
- * Decrement the reference count on "channel" and maybe free it when it goes
- * down to zero. Don't free it if there is a pending action.
- * Returns TRUE when the channel is no longer referenced.
- */
- int
-channel_unref(channel_T *channel)
-{
- if (channel != NULL && --channel->ch_refcount <= 0)
- return channel_may_free(channel);
- return FALSE;
-}
-
-static job_T *first_job = NULL;
-
- static void
-job_free(job_T *job)
-{
- ch_log(job->jv_channel, "Freeing job");
- if (job->jv_channel != NULL)
- {
- /* The link from the channel to the job doesn't count as a reference,
- * thus don't decrement the refcount of the job. The reference from
- * the job to the channel does count the refrence, decrement it and
- * NULL the reference. We don't set ch_job_killed, unreferencing the
- * job doesn't mean it stops running. */
- job->jv_channel->ch_job = NULL;
- channel_unref(job->jv_channel);
- }
- mch_clear_job(job);
-
- if (job->jv_next != NULL)
- job->jv_next->jv_prev = job->jv_prev;
- if (job->jv_prev == NULL)
- first_job = job->jv_next;
- else
- job->jv_prev->jv_next = job->jv_next;
-
- vim_free(job->jv_stoponexit);
- vim_free(job->jv_exit_cb);
- vim_free(job);
-}
-
- static void
-job_unref(job_T *job)
-{
- if (job != NULL && --job->jv_refcount <= 0)
- {
- /* Do not free the job when it has not ended yet and there is a
- * "stoponexit" flag or an exit callback. */
- if (job->jv_status != JOB_STARTED
- || (job->jv_stoponexit == NULL && job->jv_exit_cb == NULL))
- {
- job_free(job);
- }
- else if (job->jv_channel != NULL)
- {
- /* Do remove the link to the channel, otherwise it hangs
- * around until Vim exits. See job_free() for refcount. */
- job->jv_channel->ch_job = NULL;
- channel_unref(job->jv_channel);
- job->jv_channel = NULL;
- }
- }
-}
-
-/*
- * Allocate a job. Sets the refcount to one and sets options default.
- */
- static job_T *
-job_alloc(void)
-{
- job_T *job;
-
- job = (job_T *)alloc_clear(sizeof(job_T));
- if (job != NULL)
- {
- job->jv_refcount = 1;
- job->jv_stoponexit = vim_strsave((char_u *)"term");
-
- if (first_job != NULL)
- {
- first_job->jv_prev = job;
- job->jv_next = first_job;
- }
- first_job = job;
- }
- return job;
-}
-
- static void
-job_set_options(job_T *job, jobopt_T *opt)
-{
- if (opt->jo_set & JO_STOPONEXIT)
- {
- vim_free(job->jv_stoponexit);
- if (opt->jo_stoponexit == NULL || *opt->jo_stoponexit == NUL)
- job->jv_stoponexit = NULL;
- else
- job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
- }
- if (opt->jo_set & JO_EXIT_CB)
- {
- vim_free(job->jv_exit_cb);
- if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
- job->jv_exit_cb = NULL;
- else
- job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
- }
-}
-
-/*
- * Called when Vim is exiting: kill all jobs that have the "stoponexit" flag.
- */
- void
-job_stop_on_exit()
-{
- job_T *job;
-
- for (job = first_job; job != NULL; job = job->jv_next)
- if (job->jv_status == JOB_STARTED && job->jv_stoponexit != NULL)
- mch_stop_job(job, job->jv_stoponexit);
-}
#endif
static char *
@@ -9650,7 +9524,7 @@
rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
}
- static buf_T *
+ buf_T *
buflist_find_by_name(char_u *name, int curtab_only)
{
int save_magic;
@@ -9941,397 +9815,8 @@
}
#endif
-#if defined(FEAT_JOB_CHANNEL)
-/*
- * 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.
- */
- static char_u *
-get_callback(typval_T *arg)
-{
- if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
- return arg->vval.v_string;
- if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
- return (char_u *)"";
- EMSG(_("E999: Invalid callback argument"));
- return NULL;
-}
-
- static int
-handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo)
-{
- char_u *val = get_tv_string(item);
-
- opt->jo_set |= jo;
- if (STRCMP(val, "nl") == 0)
- *modep = MODE_NL;
- else if (STRCMP(val, "raw") == 0)
- *modep = MODE_RAW;
- else if (STRCMP(val, "js") == 0)
- *modep = MODE_JS;
- else if (STRCMP(val, "json") == 0)
- *modep = MODE_JSON;
- else
- {
- EMSG2(_(e_invarg2), val);
- return FAIL;
- }
- return OK;
-}
-
- static int
-handle_io(typval_T *item, int part, jobopt_T *opt)
-{
- char_u *val = get_tv_string(item);
-
- opt->jo_set |= JO_OUT_IO << (part - PART_OUT);
- if (STRCMP(val, "null") == 0)
- opt->jo_io[part] = JIO_NULL;
- else if (STRCMP(val, "pipe") == 0)
- opt->jo_io[part] = JIO_PIPE;
- else if (STRCMP(val, "file") == 0)
- opt->jo_io[part] = JIO_FILE;
- else if (STRCMP(val, "buffer") == 0)
- opt->jo_io[part] = JIO_BUFFER;
- else if (STRCMP(val, "out") == 0 && part == PART_ERR)
- opt->jo_io[part] = JIO_OUT;
- else
- {
- EMSG2(_(e_invarg2), val);
- return FAIL;
- }
- return OK;
-}
-
- static void
-clear_job_options(jobopt_T *opt)
-{
- vim_memset(opt, 0, sizeof(jobopt_T));
-}
-
-/*
- * Get the PART_ number from the first character of an option name.
- */
- static int
-part_from_char(int c)
-{
- return c == 'i' ? PART_IN : c == 'o' ? PART_OUT: PART_ERR;
-}
-
-/*
- * Get the option entries from the dict in "tv", parse them and put the result
- * in "opt".
- * Only accept options in "supported".
- * If an option value is invalid return FAIL.
- */
- static int
-get_job_options(typval_T *tv, jobopt_T *opt, int supported)
-{
- typval_T *item;
- char_u *val;
- dict_T *dict;
- int todo;
- hashitem_T *hi;
- int part;
-
- opt->jo_set = 0;
- if (tv->v_type == VAR_UNKNOWN)
- return OK;
- if (tv->v_type != VAR_DICT)
- {
- EMSG(_(e_invarg));
- return FAIL;
- }
- dict = tv->vval.v_dict;
- if (dict == NULL)
- return OK;
-
- todo = (int)dict->dv_hashtab.ht_used;
- for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
- if (!HASHITEM_EMPTY(hi))
- {
- item = &HI2DI(hi)->di_tv;
-
- if (STRCMP(hi->hi_key, "mode") == 0)
- {
- if (!(supported & JO_MODE))
- break;
- if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL)
- return FAIL;
- }
- else if (STRCMP(hi->hi_key, "in-mode") == 0)
- {
- if (!(supported & JO_IN_MODE))
- break;
- if (handle_mode(item, opt, &opt->jo_in_mode, JO_IN_MODE)
- == FAIL)
- return FAIL;
- }
- else if (STRCMP(hi->hi_key, "out-mode") == 0)
- {
- if (!(supported & JO_OUT_MODE))
- break;
- if (handle_mode(item, opt, &opt->jo_out_mode, JO_OUT_MODE)
- == FAIL)
- return FAIL;
- }
- else if (STRCMP(hi->hi_key, "err-mode") == 0)
- {
- if (!(supported & JO_ERR_MODE))
- break;
- if (handle_mode(item, opt, &opt->jo_err_mode, JO_ERR_MODE)
- == FAIL)
- return FAIL;
- }
- else if (STRCMP(hi->hi_key, "in-io") == 0
- || STRCMP(hi->hi_key, "out-io") == 0
- || STRCMP(hi->hi_key, "err-io") == 0)
- {
- if (!(supported & JO_OUT_IO))
- break;
- if (handle_io(item, part_from_char(*hi->hi_key), opt) == FAIL)
- return FAIL;
- }
- else if (STRCMP(hi->hi_key, "in-name") == 0
- || STRCMP(hi->hi_key, "out-name") == 0
- || STRCMP(hi->hi_key, "err-name") == 0)
- {
- part = part_from_char(*hi->hi_key);
-
- if (!(supported & JO_OUT_IO))
- break;
- opt->jo_set |= JO_OUT_NAME << (part - PART_OUT);
- opt->jo_io_name[part] =
- get_tv_string_buf_chk(item, opt->jo_io_name_buf[part]);
- }
- else if (STRCMP(hi->hi_key, "in-buf") == 0
- || STRCMP(hi->hi_key, "out-buf") == 0
- || STRCMP(hi->hi_key, "err-buf") == 0)
- {
- part = part_from_char(*hi->hi_key);
-
- if (!(supported & JO_OUT_IO))
- break;
- opt->jo_set |= JO_OUT_BUF << (part - PART_OUT);
- opt->jo_io_buf[part] = get_tv_number(item);
- if (opt->jo_io_buf[part] <= 0)
- {
- EMSG2(_(e_invarg2), get_tv_string(item));
- return FAIL;
- }
- if (buflist_findnr(opt->jo_io_buf[part]) == NULL)
- {
- EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[part]);
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "in-top") == 0
- || STRCMP(hi->hi_key, "in-bot") == 0)
- {
- linenr_T *lp;
-
- if (!(supported & JO_OUT_IO))
- break;
- if (hi->hi_key[3] == 't')
- {
- lp = &opt->jo_in_top;
- opt->jo_set |= JO_IN_TOP;
- }
- else
- {
- lp = &opt->jo_in_bot;
- opt->jo_set |= JO_IN_BOT;
- }
- *lp = get_tv_number(item);
- if (*lp < 0)
- {
- EMSG2(_(e_invarg2), get_tv_string(item));
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "channel") == 0)
- {
- if (!(supported & JO_OUT_IO))
- break;
- opt->jo_set |= JO_CHANNEL;
- if (item->v_type != VAR_CHANNEL)
- {
- EMSG2(_(e_invarg2), "channel");
- return FAIL;
- }
- opt->jo_channel = item->vval.v_channel;
- }
- else if (STRCMP(hi->hi_key, "callback") == 0)
- {
- if (!(supported & JO_CALLBACK))
- break;
- opt->jo_set |= JO_CALLBACK;
- opt->jo_callback = get_callback(item);
- if (opt->jo_callback == NULL)
- {
- EMSG2(_(e_invarg2), "callback");
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "out-cb") == 0)
- {
- if (!(supported & JO_OUT_CALLBACK))
- break;
- opt->jo_set |= JO_OUT_CALLBACK;
- opt->jo_out_cb = get_callback(item);
- if (opt->jo_out_cb == NULL)
- {
- EMSG2(_(e_invarg2), "out-cb");
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "err-cb") == 0)
- {
- if (!(supported & JO_ERR_CALLBACK))
- break;
- opt->jo_set |= JO_ERR_CALLBACK;
- opt->jo_err_cb = get_callback(item);
- if (opt->jo_err_cb == NULL)
- {
- EMSG2(_(e_invarg2), "err-cb");
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "close-cb") == 0)
- {
- if (!(supported & JO_CLOSE_CALLBACK))
- break;
- opt->jo_set |= JO_CLOSE_CALLBACK;
- opt->jo_close_cb = get_callback(item);
- if (opt->jo_close_cb == NULL)
- {
- EMSG2(_(e_invarg2), "close-cb");
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "waittime") == 0)
- {
- if (!(supported & JO_WAITTIME))
- break;
- opt->jo_set |= JO_WAITTIME;
- opt->jo_waittime = get_tv_number(item);
- }
- else if (STRCMP(hi->hi_key, "timeout") == 0)
- {
- if (!(supported & JO_TIMEOUT))
- break;
- opt->jo_set |= JO_TIMEOUT;
- opt->jo_timeout = get_tv_number(item);
- }
- else if (STRCMP(hi->hi_key, "out-timeout") == 0)
- {
- if (!(supported & JO_OUT_TIMEOUT))
- break;
- opt->jo_set |= JO_OUT_TIMEOUT;
- opt->jo_out_timeout = get_tv_number(item);
- }
- else if (STRCMP(hi->hi_key, "err-timeout") == 0)
- {
- if (!(supported & JO_ERR_TIMEOUT))
- break;
- opt->jo_set |= JO_ERR_TIMEOUT;
- opt->jo_err_timeout = get_tv_number(item);
- }
- else if (STRCMP(hi->hi_key, "part") == 0)
- {
- if (!(supported & JO_PART))
- break;
- opt->jo_set |= JO_PART;
- val = get_tv_string(item);
- if (STRCMP(val, "err") == 0)
- opt->jo_part = PART_ERR;
- else
- {
- EMSG2(_(e_invarg2), val);
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "id") == 0)
- {
- if (!(supported & JO_ID))
- break;
- opt->jo_set |= JO_ID;
- opt->jo_id = get_tv_number(item);
- }
- else if (STRCMP(hi->hi_key, "stoponexit") == 0)
- {
- if (!(supported & JO_STOPONEXIT))
- break;
- opt->jo_set |= JO_STOPONEXIT;
- opt->jo_stoponexit = get_tv_string_buf_chk(item,
- opt->jo_soe_buf);
- if (opt->jo_stoponexit == NULL)
- {
- EMSG2(_(e_invarg2), "stoponexit");
- return FAIL;
- }
- }
- else if (STRCMP(hi->hi_key, "exit-cb") == 0)
- {
- if (!(supported & JO_EXIT_CB))
- break;
- opt->jo_set |= JO_EXIT_CB;
- opt->jo_exit_cb = get_tv_string_buf_chk(item, opt->jo_ecb_buf);
- if (opt->jo_exit_cb == NULL)
- {
- EMSG2(_(e_invarg2), "exit-cb");
- return FAIL;
- }
- }
- else
- break;
- --todo;
- }
- if (todo > 0)
- {
- EMSG2(_(e_invarg2), hi->hi_key);
- return FAIL;
- }
-
- return OK;
-}
-#endif
-
#ifdef FEAT_JOB_CHANNEL
/*
- * Get the channel from the argument.
- * Returns NULL if the handle is invalid.
- */
- static channel_T *
-get_channel_arg(typval_T *tv, int check_open)
-{
- channel_T *channel = NULL;
-
- 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
- {
- EMSG2(_(e_invarg2), get_tv_string(tv));
- return NULL;
- }
-
- if (check_open && (channel == NULL || !channel_is_open(channel)))
- {
- EMSG(_("E906: not an open channel"));
- return NULL;
- }
- return channel;
-}
-
-/*
* "ch_close()" function
*/
static void
@@ -10414,21 +9899,11 @@
char_u *fname;
char_u *opt = (char_u *)"";
char_u buf[NUMBUFLEN];
- FILE *file = NULL;
fname = get_tv_string(&argvars[0]);
if (argvars[1].v_type == VAR_STRING)
opt = get_tv_string_buf(&argvars[1], buf);
- if (*fname != NUL)
- {
- file = fopen((char *)fname, *opt == 'w' ? "w" : "a");
- if (file == NULL)
- {
- EMSG2(_(e_notopen), fname);
- return;
- }
- }
- ch_logfile(file);
+ ch_logfile(fname, opt);
}
/*
@@ -10437,117 +9912,8 @@
static void
f_ch_open(typval_T *argvars, typval_T *rettv)
{
- char_u *address;
- char_u *p;
- char *rest;
- int port;
- jobopt_T opt;
- channel_T *channel;
-
- /* default: fail */
rettv->v_type = VAR_CHANNEL;
- rettv->vval.v_channel = NULL;
-
- address = get_tv_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;
- }
-
- /* parse address */
- p = vim_strchr(address, ':');
- if (p == NULL)
- {
- EMSG2(_(e_invarg2), address);
- return;
- }
- *p++ = NUL;
- port = strtol((char *)p, &rest, 10);
- if (*address == NUL || port <= 0 || *rest != NUL)
- {
- p[-1] = ':';
- EMSG2(_(e_invarg2), address);
- return;
- }
-
- /* 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) == FAIL)
- return;
- if (opt.jo_timeout < 0)
- {
- EMSG(_(e_invarg));
- return;
- }
-
- channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
- if (channel != NULL)
- {
- rettv->vval.v_channel = channel;
- opt.jo_set = JO_ALL;
- channel_set_options(channel, &opt);
- }
-}
-
-/*
- * Common for ch_read() and ch_readraw().
- */
- static void
-common_channel_read(typval_T *argvars, typval_T *rettv, int raw)
-{
- channel_T *channel;
- int part;
- jobopt_T opt;
- int mode;
- int timeout;
- int id = -1;
- typval_T *listtv = NULL;
-
- /* return an empty string by default */
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- clear_job_options(&opt);
- if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID)
- == FAIL)
- return;
-
- channel = get_channel_arg(&argvars[0], TRUE);
- if (channel != NULL)
- {
- if (opt.jo_set & JO_PART)
- part = opt.jo_part;
- else
- part = channel_part_read(channel);
- mode = channel_get_mode(channel, part);
- timeout = channel_get_timeout(channel, part);
- if (opt.jo_set & JO_TIMEOUT)
- timeout = opt.jo_timeout;
-
- if (raw || mode == MODE_RAW || mode == MODE_NL)
- rettv->vval.v_string = channel_read_block(channel, part, timeout);
- else
- {
- if (opt.jo_set & JO_ID)
- id = opt.jo_id;
- channel_read_json_block(channel, part, timeout, id, &listtv);
- if (listtv != NULL)
- {
- *rettv = *listtv;
- vim_free(listtv);
- }
- else
- {
- rettv->v_type = VAR_SPECIAL;
- rettv->vval.v_number = VVAL_NONE;
- }
- }
- }
+ rettv->vval.v_channel = channel_open_func(argvars);
}
/*
@@ -10569,116 +9935,6 @@
}
/*
- * common for "sendexpr()" and "sendraw()"
- * Returns the channel if the caller should read the response.
- * Sets "part_read" to the the read fd.
- * Otherwise returns NULL.
- */
- static channel_T *
-send_common(
- typval_T *argvars,
- char_u *text,
- int id,
- int eval,
- jobopt_T *opt,
- char *fun,
- int *part_read)
-{
- channel_T *channel;
- int part_send;
-
- channel = get_channel_arg(&argvars[0], TRUE);
- if (channel == NULL)
- return NULL;
- part_send = channel_part_send(channel);
- *part_read = channel_part_read(channel);
-
- clear_job_options(opt);
- if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT) == FAIL)
- return NULL;
-
- /* 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 (eval)
- {
- EMSG2(_("E917: Cannot use a callback with %s()"), fun);
- return NULL;
- }
- channel_set_req_callback(channel, part_send, opt->jo_callback, id);
- }
-
- if (channel_send(channel, part_send, text, fun) == OK
- && opt->jo_callback == NULL)
- return channel;
- return NULL;
-}
-
-/*
- * common for "ch_evalexpr()" and "ch_sendexpr()"
- */
- static void
-ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
-{
- char_u *text;
- typval_T *listtv;
- channel_T *channel;
- int id;
- ch_mode_T ch_mode;
- int part_send;
- int part_read;
- jobopt_T opt;
- int timeout;
-
- /* return an empty string by default */
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- channel = get_channel_arg(&argvars[0], TRUE);
- if (channel == NULL)
- return;
- part_send = channel_part_send(channel);
-
- ch_mode = channel_get_mode(channel, part_send);
- if (ch_mode == MODE_RAW || ch_mode == MODE_NL)
- {
- EMSG(_("E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"));
- return;
- }
-
- id = channel_get_id();
- text = json_encode_nr_expr(id, &argvars[1],
- ch_mode == MODE_JS ? JSON_JS : 0);
- if (text == NULL)
- return;
-
- channel = send_common(argvars, text, id, eval, &opt,
- eval ? "ch_evalexpr" : "ch_sendexpr", &part_read);
- vim_free(text);
- if (channel != NULL && eval)
- {
- if (opt.jo_set & JO_TIMEOUT)
- timeout = opt.jo_timeout;
- else
- timeout = channel_get_timeout(channel, part_read);
- timeout = channel_get_timeout(channel, part_read);
- if (channel_read_json_block(channel, part_read, timeout, id, &listtv)
- == OK)
- {
- list_T *list = listtv->vval.v_list;
-
- /* Move the item from the list and then change the type to
- * avoid the value being freed. */
- *rettv = list->lv_last->li_tv;
- list->lv_last->li_tv.v_type = VAR_NUMBER;
- free_tv(listtv);
- }
- }
-}
-
-/*
* "ch_evalexpr()" function
*/
static void
@@ -10697,36 +9953,6 @@
}
/*
- * common for "ch_evalraw()" and "ch_sendraw()"
- */
- static void
-ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
-{
- char_u buf[NUMBUFLEN];
- char_u *text;
- channel_T *channel;
- int part_read;
- jobopt_T opt;
- int timeout;
-
- /* return an empty string by default */
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- text = get_tv_string_buf(&argvars[1], buf);
- channel = send_common(argvars, text, 0, eval, &opt,
- eval ? "ch_evalraw" : "ch_sendraw", &part_read);
- if (channel != NULL && eval)
- {
- if (opt.jo_set & JO_TIMEOUT)
- timeout = opt.jo_timeout;
- else
- timeout = channel_get_timeout(channel, part_read);
- rettv->vval.v_string = channel_read_block(channel, part_read, timeout);
- }
-}
-
-/*
* "ch_evalraw()" function
*/
static void
@@ -15138,250 +14364,8 @@
static void
f_job_start(typval_T *argvars, typval_T *rettv)
{
- job_T *job;
- char_u *cmd = NULL;
-#if defined(UNIX)
-# define USE_ARGV
- char **argv = NULL;
- int argc = 0;
-#else
- garray_T ga;
-#endif
- jobopt_T opt;
- int part;
-
rettv->v_type = VAR_JOB;
- job = job_alloc();
- rettv->vval.v_job = job;
- if (job == NULL)
- return;
-
- rettv->vval.v_job->jv_status = JOB_FAILED;
-
- /* Default mode is NL. */
- clear_job_options(&opt);
- opt.jo_mode = MODE_NL;
- if (get_job_options(&argvars[1], &opt,
- JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL
- + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO) == FAIL)
- return;
-
- /* Check that when io is "file" that there is a file name. */
- for (part = PART_OUT; part <= PART_IN; ++part)
- if ((opt.jo_set & (JO_OUT_IO << (part - PART_OUT)))
- && opt.jo_io[part] == JIO_FILE
- && (!(opt.jo_set & (JO_OUT_NAME << (part - PART_OUT)))
- || *opt.jo_io_name[part] == NUL))
- {
- EMSG(_("E920: -io file requires -name to be set"));
- return;
- }
-
- if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
- {
- buf_T *buf = NULL;
-
- /* check that we can find the buffer before starting the job */
- if (opt.jo_set & JO_IN_BUF)
- {
- buf = buflist_findnr(opt.jo_io_buf[PART_IN]);
- if (buf == NULL)
- EMSGN(_(e_nobufnr), (long)opt.jo_io_buf[PART_IN]);
- }
- else if (!(opt.jo_set & JO_IN_NAME))
- {
- EMSG(_("E915: in-io buffer requires in-buf or in-name to be set"));
- }
- else
- buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
- if (buf == NULL)
- return;
- if (buf->b_ml.ml_mfp == NULL)
- {
- char_u numbuf[NUMBUFLEN];
- char_u *s;
-
- if (opt.jo_set & JO_IN_BUF)
- {
- sprintf((char *)numbuf, "%d", opt.jo_io_buf[PART_IN]);
- s = numbuf;
- }
- else
- s = opt.jo_io_name[PART_IN];
- EMSG2(_("E918: buffer must be loaded: %s"), s);
- return;
- }
- job->jv_in_buf = buf;
- }
-
- job_set_options(job, &opt);
-
-#ifndef USE_ARGV
- ga_init2(&ga, (int)sizeof(char*), 20);
-#endif
-
- if (argvars[0].v_type == VAR_STRING)
- {
- /* Command is a string. */
- cmd = argvars[0].vval.v_string;
-#ifdef USE_ARGV
- if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL)
- return;
- argv[argc] = NULL;
-#endif
- }
- else if (argvars[0].v_type != VAR_LIST
- || argvars[0].vval.v_list == NULL
- || argvars[0].vval.v_list->lv_len < 1)
- {
- EMSG(_(e_invarg));
- return;
- }
- else
- {
- list_T *l = argvars[0].vval.v_list;
- listitem_T *li;
- char_u *s;
-
-#ifdef USE_ARGV
- /* Pass argv[] to mch_call_shell(). */
- argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1));
- if (argv == NULL)
- return;
-#endif
- for (li = l->lv_first; li != NULL; li = li->li_next)
- {
- s = get_tv_string_chk(&li->li_tv);
- if (s == NULL)
- goto theend;
-#ifdef USE_ARGV
- argv[argc++] = (char *)s;
-#else
- /* Only escape when needed, double quotes are not always allowed. */
- if (li != l->lv_first && vim_strpbrk(s, (char_u *)" \t\"") != NULL)
- {
- s = vim_strsave_shellescape(s, FALSE, TRUE);
- if (s == NULL)
- goto theend;
- ga_concat(&ga, s);
- vim_free(s);
- }
- else
- ga_concat(&ga, s);
- if (li->li_next != NULL)
- ga_append(&ga, ' ');
-#endif
- }
-#ifdef USE_ARGV
- argv[argc] = NULL;
-#else
- cmd = ga.ga_data;
-#endif
- }
-
-#ifdef USE_ARGV
- if (ch_log_active())
- {
- garray_T ga;
- int i;
-
- ga_init2(&ga, (int)sizeof(char), 200);
- for (i = 0; i < argc; ++i)
- {
- if (i > 0)
- ga_concat(&ga, (char_u *)" ");
- ga_concat(&ga, (char_u *)argv[i]);
- }
- ch_logs(NULL, "Starting job: %s", (char *)ga.ga_data);
- ga_clear(&ga);
- }
- mch_start_job(argv, job, &opt);
-#else
- ch_logs(NULL, "Starting job: %s", (char *)cmd);
- mch_start_job((char *)cmd, job, &opt);
-#endif
-
- /* If the channel is reading from a buffer, write lines now. */
- if (job->jv_channel != NULL)
- channel_write_in(job->jv_channel);
-
-theend:
-#ifdef USE_ARGV
- vim_free(argv);
-#else
- vim_free(ga.ga_data);
-#endif
-}
-
-/*
- * Get the status of "job" and invoke the exit callback when needed.
- * The returned string is not allocated.
- */
- static char *
-job_status(job_T *job)
-{
- char *result;
-
- if (job->jv_status == JOB_ENDED)
- /* No need to check, dead is dead. */
- result = "dead";
- else if (job->jv_status == JOB_FAILED)
- result = "fail";
- else
- {
- result = mch_job_status(job);
- if (job->jv_status == JOB_ENDED)
- ch_log(job->jv_channel, "Job ended");
- if (job->jv_status == JOB_ENDED && job->jv_exit_cb != NULL)
- {
- typval_T argv[3];
- typval_T rettv;
- int dummy;
-
- /* invoke the exit callback; make sure the refcount is > 0 */
- ++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, (int)STRLEN(job->jv_exit_cb),
- &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
- clear_tv(&rettv);
- --job->jv_refcount;
- }
- if (job->jv_status == JOB_ENDED && job->jv_refcount == 0)
- {
- /* The job was already unreferenced, now that it ended it can be
- * freed. Careful: caller must not use "job" after this! */
- job_free(job);
- }
- }
- return result;
-}
-
-/*
- * Called once in a while: check if any jobs with an "exit-cb" have ended.
- */
- void
-job_check_ended(void)
-{
- static time_t last_check = 0;
- time_t now;
- job_T *job;
- job_T *next;
-
- /* Only do this once in 10 seconds. */
- now = time(NULL);
- if (last_check + 10 < now)
- {
- last_check = now;
- for (job = first_job; job != NULL; job = next)
- {
- next = job->jv_next;
- if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL)
- job_status(job); /* may free "job" */
- }
- }
+ rettv->vval.v_job = job_start(argvars);
}
/*
@@ -15405,38 +14389,12 @@
* "job_stop()" function
*/
static void
-f_job_stop(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+f_job_stop(typval_T *argvars, typval_T *rettv)
{
job_T *job = get_job_arg(&argvars[0]);
if (job != NULL)
- {
- char_u *arg;
-
- if (argvars[1].v_type == VAR_UNKNOWN)
- arg = (char_u *)"";
- else
- {
- arg = get_tv_string_chk(&argvars[1]);
- if (arg == NULL)
- {
- EMSG(_(e_invarg));
- return;
- }
- }
- ch_logs(job->jv_channel, "Stopping job with '%s'", (char *)arg);
- if (mch_stop_job(job, arg) == FAIL)
- rettv->vval.v_number = 0;
- else
- {
- rettv->vval.v_number = 1;
- /* Assume that "hup" does not kill the job. */
- if (job->jv_channel != NULL && STRCMP(arg, "hup") != 0)
- job->jv_channel->ch_job_killed = TRUE;
- }
- /* We don't try freeing the job, obviously the caller still has a
- * reference to it. */
- }
+ rettv->vval.v_number = job_stop(job, argvars);
}
#endif
@@ -22475,7 +21433,7 @@
* caller of incompatible types: it sets *denote to TRUE if "denote"
* is not NULL or returns -1 otherwise.
*/
- static long
+ long
get_tv_number(typval_T *varp)
{
int error = FALSE;
@@ -22626,7 +21584,7 @@
* get_tv_string_chk() and get_tv_string_buf_chk() are similar, but return
* NULL on error.
*/
- static char_u *
+ char_u *
get_tv_string(typval_T *varp)
{
static char_u mybuf[NUMBUFLEN];
@@ -22634,7 +21592,7 @@
return get_tv_string_buf(varp, mybuf);
}
- static char_u *
+ char_u *
get_tv_string_buf(typval_T *varp, char_u *buf)
{
char_u *res = get_tv_string_buf_chk(varp, buf);