diff options
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 497 |
1 files changed, 290 insertions, 207 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4ab31985b5..1dab9df9cb 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -21,8 +21,6 @@ #include <math.h> #include <limits.h> -#include "nvim/lib/klist.h" - #include "nvim/assert.h" #include "nvim/vim.h" #include "nvim/ascii.h" @@ -89,6 +87,7 @@ #include "nvim/os/rstream_defs.h" #include "nvim/os/time.h" #include "nvim/msgpack_rpc/channel.h" +#include "nvim/msgpack_rpc/server.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/os/dl.h" @@ -469,10 +468,7 @@ typedef struct { list_T *received; int status; } JobEvent; -#define JobEventFreer(x) -KMEMPOOL_INIT(JobEventPool, JobEvent, JobEventFreer) -static kmempool_t(JobEventPool) *job_event_pool = NULL; -static bool defer_job_callbacks = true; +static int disable_job_defer = 0; /* * Initialize the global and v: variables. @@ -508,8 +504,6 @@ void eval_init(void) set_vim_var_nr(VV_SEARCHFORWARD, 1L); set_vim_var_nr(VV_HLSEARCH, 1L); set_reg_var(0); /* default for v:register is not 0 but '"' */ - - job_event_pool = kmp_init(JobEventPool); } #if defined(EXITFREE) @@ -520,7 +514,7 @@ void eval_clear(void) for (int i = 0; i < VV_LEN; ++i) { p = &vimvars[i]; if (p->vv_di.di_tv.v_type == VAR_STRING) { - free(p->vv_str); + xfree(p->vv_str); p->vv_str = NULL; } else if (p->vv_di.di_tv.v_type == VAR_LIST) { list_unref(p->vv_list); @@ -546,7 +540,7 @@ void eval_clear(void) for (int i = 1; i <= ga_scripts.ga_len; ++i) vars_clear(&SCRIPT_VARS(i)); for (int i = 1; i <= ga_scripts.ga_len; ++i) - free(SCRIPT_SV(i)); + xfree(SCRIPT_SV(i)); ga_clear(&ga_scripts); /* unreferenced lists and dicts */ @@ -742,13 +736,13 @@ void var_redir_stop(void) } /* free the collected output */ - free(redir_ga.ga_data); + xfree(redir_ga.ga_data); redir_ga.ga_data = NULL; - free(redir_lval); + xfree(redir_lval); redir_lval = NULL; } - free(redir_varname); + xfree(redir_varname); redir_varname = NULL; } @@ -1066,7 +1060,7 @@ typval_T *eval_expr(char_u *arg, char_u **nextcmd) typval_T *tv = xmalloc(sizeof(typval_T)); if (eval0(arg, tv, nextcmd, TRUE) == FAIL) { - free(tv); + xfree(tv); return NULL; } @@ -1133,7 +1127,7 @@ call_vim_function ( --sandbox; restore_funccal(save_funccalp); } - free(argvars); + xfree(argvars); if (ret == FAIL) clear_tv(rettv); @@ -1698,14 +1692,14 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first) s == NULL ? (char_u *)"" : s, first); *arg = c; - free(tf); + xfree(tf); } clear_tv(&tv); } } } - free(tofree); + xfree(tofree); } arg = skipwhite(arg); @@ -1763,7 +1757,7 @@ ex_let_one ( if (s != NULL) { p = tofree = concat_str(s, p); if (mustfree) - free(s); + xfree(s); } } if (p != NULL) { @@ -1778,7 +1772,7 @@ ex_let_one ( arg_end = arg; } name[len] = c1; - free(tofree); + xfree(tofree); } } } @@ -1819,7 +1813,7 @@ ex_let_one ( n = numval - n; } else if (opt_type == 0 && stringval != NULL) { /* string */ s = concat_str(stringval, s); - free(stringval); + xfree(stringval); stringval = s; } } @@ -1829,7 +1823,7 @@ ex_let_one ( arg_end = p; } *p = c1; - free(stringval); + xfree(stringval); } } /* @@ -1851,14 +1845,14 @@ ex_let_one ( s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc); if (s != NULL) { p = ptofree = concat_str(s, p); - free(s); + xfree(s); } } if (p != NULL) { write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE); arg_end = arg + 1; } - free(ptofree); + xfree(ptofree); } } /* @@ -2218,8 +2212,8 @@ get_lval ( */ static void clear_lval(lval_T *lp) { - free(lp->ll_exp_name); - free(lp->ll_newkey); + xfree(lp->ll_exp_name); + xfree(lp->ll_newkey); } /* @@ -2312,7 +2306,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch /* Need to add an item to the Dictionary. */ di = dictitem_alloc(lp->ll_newkey); if (dict_add(lp->ll_tv->vval.v_dict, di) == FAIL) { - free(di); + xfree(di); return; } lp->ll_tv = &di->di_tv; @@ -2547,7 +2541,7 @@ void free_for_info(void *fi_void) list_rem_watch(fi->fi_list, &fi->fi_lw); list_unref(fi->fi_list); } - free(fi); + xfree(fi); } @@ -2661,7 +2655,7 @@ void ex_call(exarg_T *eap) if (fudi.fd_newkey != NULL) { /* Still need to give an error message for missing key. */ EMSG2(_(e_dictkey), fudi.fd_newkey); - free(fudi.fd_newkey); + xfree(fudi.fd_newkey); } if (tofree == NULL) return; @@ -2741,7 +2735,7 @@ void ex_call(exarg_T *eap) end: dict_unref(fudi.fd_dict); - free(tofree); + xfree(tofree); } /* @@ -3062,7 +3056,7 @@ static char_u *cat_prefix_varname(int prefix, char_u *name) size_t len = STRLEN(name) + 3; if (len > varnamebuflen) { - free(varnamebuf); + xfree(varnamebuf); len += 10; /* some additional space */ varnamebuf = xmalloc(len); varnamebuflen = len; @@ -3149,7 +3143,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) if (vidx < VV_LEN) return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name); - free(varnamebuf); + xfree(varnamebuf); varnamebuf = NULL; varnamebuflen = 0; return NULL; @@ -4157,7 +4151,7 @@ eval7 ( else ret = OK; } - free(alias); + xfree(alias); } *arg = skipwhite(*arg); @@ -4791,9 +4785,9 @@ list_free ( if (recurse || (item->li_tv.v_type != VAR_LIST && item->li_tv.v_type != VAR_DICT)) clear_tv(&item->li_tv); - free(item); + xfree(item); } - free(l); + xfree(l); } /* @@ -4810,7 +4804,7 @@ listitem_T *listitem_alloc(void) FUNC_ATTR_NONNULL_RET void listitem_free(listitem_T *item) { clear_tv(&item->li_tv); - free(item); + xfree(item); } /* @@ -5282,7 +5276,7 @@ static list_T *list_copy(list_T *orig, int deep, int copyID) ni = listitem_alloc(); if (deep) { if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL) { - free(ni); + xfree(ni); break; } } else @@ -5337,7 +5331,7 @@ static char_u *list2string(typval_T *tv, int copyID) ga_init(&ga, (int)sizeof(char), 80); ga_append(&ga, '['); if (list_join(&ga, tv->vval.v_list, (char_u *)", ", FALSE, copyID) == FAIL) { - free(ga.ga_data); + xfree(ga.ga_data); return NULL; } ga_append(&ga, ']'); @@ -5430,7 +5424,7 @@ static int list_join(garray_T *gap, list_T *l, char_u *sep, int echo_style, int ga_init(&join_ga, (int)sizeof(join_T), l->lv_len); retval = list_join_inner(gap, l, sep, echo_style, copyID, &join_ga); -# define FREE_JOIN_TOFREE(join) free((join)->tofree) +# define FREE_JOIN_TOFREE(join) xfree((join)->tofree) GA_DEEP_CLEAR(&join_ga, join_T, FREE_JOIN_TOFREE); return retval; @@ -5736,12 +5730,12 @@ dict_free ( if (recurse || (di->di_tv.v_type != VAR_LIST && di->di_tv.v_type != VAR_DICT)) clear_tv(&di->di_tv); - free(di); + xfree(di); --todo; } } hash_clear(&d->dv_hashtab); - free(d); + xfree(d); } /* @@ -5794,7 +5788,7 @@ static void dictitem_remove(dict_T *dict, dictitem_T *item) void dictitem_free(dictitem_T *item) { clear_tv(&item->di_tv); - free(item); + xfree(item); } /* @@ -5827,7 +5821,7 @@ static dict_T *dict_copy(dict_T *orig, int deep, int copyID) if (deep) { if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep, copyID) == FAIL) { - free(di); + xfree(di); break; } } else @@ -5936,33 +5930,39 @@ dictitem_T *dict_find(dict_T *d, char_u *key, int len) } hi = hash_find(&d->dv_hashtab, akey); - free(tofree); + xfree(tofree); if (HASHITEM_EMPTY(hi)) return NULL; return HI2DI(hi); } -// Get a function from a dictionary -static ufunc_T *get_dict_callback(dict_T *d, char *key) +/// Get a function from a dictionary +/// @param[out] result The address where a pointer to the wanted callback +/// will be left. +/// @return true/false on success/failure. +static bool get_dict_callback(dict_T *d, char *key, ufunc_T **result) { dictitem_T *di = dict_find(d, (uint8_t *)key, -1); if (di == NULL) { - return NULL; + *result = NULL; + return true; } if (di->di_tv.v_type != VAR_FUNC && di->di_tv.v_type != VAR_STRING) { EMSG(_("Argument is not a function or function name")); - return NULL; + *result = NULL; + return false; } uint8_t *name = di->di_tv.vval.v_string; uint8_t *n = name; - ufunc_T *rv; + ufunc_T *rv = NULL; if (*n > '9' || *n < '0') { - n = trans_function_name(&n, false, TFN_INT|TFN_QUIET, NULL); - rv = find_func(n); - free(n); + if ((n = trans_function_name(&n, false, TFN_INT|TFN_QUIET, NULL))) { + rv = find_func(n); + xfree(n); + } } else { // dict function, name is already translated rv = find_func(n); @@ -5970,11 +5970,13 @@ static ufunc_T *get_dict_callback(dict_T *d, char *key) if (!rv) { EMSG2(_("Function %s doesn't exist"), name); - return NULL; + *result = NULL; + return false; } rv->uf_refcount++; - return rv; + *result = rv; + return true; } /* @@ -6044,20 +6046,20 @@ static char_u *dict2string(typval_T *tv, int copyID) tofree = string_quote(hi->hi_key, FALSE); if (tofree != NULL) { ga_concat(&ga, tofree); - free(tofree); + xfree(tofree); } ga_concat(&ga, (char_u *)": "); s = tv2string(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID); if (s != NULL) ga_concat(&ga, s); - free(tofree); + xfree(tofree); if (s == NULL || did_echo_string_emsg) { break; } line_breakcheck(); } if (todo > 0) { - free(ga.ga_data); + xfree(ga.ga_data); return NULL; } @@ -6373,13 +6375,13 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate) } } else { if (mustfree) { - free(string); + xfree(string); } // Next try expanding things like $VIM and ${HOME}. string = expand_env_save(name - 1); if (string != NULL && *string == '$') { - free(string); + xfree(string); string = NULL; } } @@ -6604,6 +6606,9 @@ static struct fst { {"searchpair", 3, 7, f_searchpair}, {"searchpairpos", 3, 7, f_searchpairpos}, {"searchpos", 1, 4, f_searchpos}, + {"serverlist", 0, 0, f_serverlist}, + {"serverstart", 0, 1, f_serverstart}, + {"serverstop", 1, 1, f_serverstop}, {"setbufvar", 3, 3, f_setbufvar}, {"setcmdpos", 1, 1, f_setcmdpos}, {"setline", 2, 2, f_setline}, @@ -7029,8 +7034,8 @@ call_func ( } if (fname != name && fname != fname_buf) - free(fname); - free(name); + xfree(fname); + xfree(name); return ret; } @@ -7049,7 +7054,7 @@ static void emsg_funcname(char *ermsg, char_u *name) p = name; EMSG2(_(ermsg), p); if (p != name) - free(p); + xfree(p); } /* @@ -8199,7 +8204,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv) p = expand_env_save(p); if (p != NULL && *p != '$') n = TRUE; - free(p); + xfree(p); } } else if (*p == '&' || *p == '+') { /* option */ n = (get_option_tv(&p, NULL, TRUE) == OK); @@ -8235,7 +8240,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv) if (*p != NUL) n = FALSE; - free(tofree); + xfree(tofree); } rettv->vval.v_number = n; @@ -8528,7 +8533,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) if (*fname != NUL && !error) { do { if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) - free(fresult); + xfree(fresult); fresult = find_file_in_path_option(first ? fname : NULL, first ? (int)STRLEN(fname) : 0, 0, first, path, @@ -8791,7 +8796,7 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv) rettv->vval.v_string = NULL; else rettv->vval.v_string = vim_strnsave(fname, len); - free(fbuf); + xfree(fbuf); } @@ -9274,7 +9279,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv) slash_adjust(rettv->vval.v_string); #endif } - free(cwd); + xfree(cwd); } /* @@ -10251,8 +10256,8 @@ static void f_iconv(typval_T *argvars, typval_T *rettv) rettv->vval.v_string = string_convert(&vimconv, str, NULL); convert_setup(&vimconv, NULL, NULL); - free(from); - free(to); + xfree(from); + xfree(to); } /* @@ -10390,7 +10395,7 @@ static void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog) rettv->vval.v_string = vim_strsave(get_tv_string_buf( &argvars[2], buf)); - free(xp_arg); + xfree(xp_arg); /* since the user typed this, no need to wait for return */ need_wait_return = FALSE; @@ -10741,7 +10746,7 @@ static void f_jobsend(typval_T *argvars, typval_T *rettv) return; } - WBuffer *buf = wstream_new_buffer(input, input_len, 1, free); + WBuffer *buf = wstream_new_buffer(input, input_len, 1, xfree); rettv->vval.v_number = job_write(job, buf); } @@ -10810,9 +10815,12 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv) return; } - if (!os_can_exe(args->lv_first->li_tv.vval.v_string, NULL)) { + assert(args->lv_first); + + const char_u *exe = get_tv_string(&args->lv_first->li_tv); + if (!os_can_exe(exe, NULL)) { // String is not executable - EMSG2(e_jobexe, args->lv_first->li_tv.vval.v_string); + EMSG2(e_jobexe, exe); return; } @@ -10820,8 +10828,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv) ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL; if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; - common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit); - if (did_emsg) { + if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { return; } } @@ -10830,7 +10837,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv) int i = 0; char **argv = xcalloc(argc + 1, sizeof(char *)); for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) { - argv[i++] = xstrdup((char *)arg->li_tv.vval.v_string); + argv[i++] = xstrdup((char *) get_tv_string(&arg->li_tv)); } JobOptions opts = common_job_options(argv, on_stdout, on_stderr, on_exit, @@ -10912,9 +10919,16 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv) list_T *args = argvars[0].vval.v_list; list_T *rv = list_alloc(); - // must temporarily disable job event deferring so the callbacks are - // processed while waiting. - defer_job_callbacks = false; + ui_busy_start(); + // disable breakchecks, which could result in job callbacks being executed + // at unexpected places + disable_breakcheck++; + // disable job event deferring so the callbacks are processed while waiting. + if (!disable_job_defer++) { + // process any pending job events in the deferred queue, but only do this if + // deferred is not disabled(at the top-level `jobwait()` call) + event_process(); + } // For each item in the input list append an integer to the output list. -3 // is used to represent an invalid job id, -2 is for a interrupted job and // -1 for jobs that were skipped or timed out. @@ -10987,8 +11001,9 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv) // job exits data->status_ptr = NULL; } - // restore defer flag - defer_job_callbacks = true; + disable_job_defer--; + disable_breakcheck--; + ui_busy_stop(); rv->lv_refcount++; rettv->v_type = VAR_LIST; @@ -11228,7 +11243,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); - free(keys_buf); + xfree(keys_buf); if (!get_dict) { /* Return a string. */ @@ -11253,8 +11268,8 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL); dict_add_nr_str(dict, "mode", 0L, mapmode); - free(lhs); - free(mapmode); + xfree(lhs); + xfree(mapmode); } } } @@ -11401,7 +11416,7 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type) match = FALSE; break; } - free(tofree); + xfree(tofree); str = echo_string(&li->li_tv, &tofree, strbuf, 0); if (str == NULL) break; @@ -11465,7 +11480,7 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type) } theend: - free(tofree); + xfree(tofree); p_cpo = save_cpo; } @@ -11699,7 +11714,7 @@ static int mkdir_recurse(char_u *dir, int prot) r = OK; else if (mkdir_recurse(updir, prot) == OK) r = vim_mkdir_emsg(updir, prot); - free(updir); + xfree(updir); return r; } @@ -12128,7 +12143,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv) --cnt; } - free(prev); + xfree(prev); fclose(fd); } @@ -12278,7 +12293,7 @@ static void f_remove(typval_T *argvars, typval_T *rettv) // Remove one item, return its value. vim_list_remove(l, item, item); *rettv = item->li_tv; - free(item); + xfree(item); } else { /* Remove range of items, return list with values. */ end = get_tv_number_chk(&argvars[2], &error); @@ -12421,8 +12436,8 @@ static void f_resolve(typval_T *argvars, typval_T *rettv) buf[len] = NUL; if (limit-- == 0) { - free(p); - free(remain); + xfree(p); + xfree(remain); EMSG(_("E655: Too many symbolic links (cycle?)")); rettv->vval.v_string = NULL; goto fail; @@ -12440,7 +12455,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv) cpy = remain; remain = remain ? concat_str(q - 1, remain) : (char_u *) xstrdup((char *)q - 1); - free(cpy); + xfree(cpy); q[-1] = NUL; } @@ -12455,10 +12470,10 @@ static void f_resolve(typval_T *argvars, typval_T *rettv) cpy = xmalloc(STRLEN(p) + STRLEN(buf) + 1); STRCPY(cpy, p); STRCPY(path_tail(cpy), buf); - free(p); + xfree(p); p = cpy; } else { - free(p); + xfree(p); p = vim_strsave(buf); } } @@ -12471,14 +12486,14 @@ static void f_resolve(typval_T *argvars, typval_T *rettv) len = q - remain - (*q != NUL); cpy = vim_strnsave(p, STRLEN(p) + len); STRNCAT(cpy, remain, len); - free(p); + xfree(p); p = cpy; /* Shorten "remain". */ if (*q != NUL) STRMOVE(remain, q - 1); else { - free(remain); + xfree(remain); remain = NULL; } } @@ -12496,7 +12511,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv) || vim_ispathsep(p[2])))))) { /* Prepend "./". */ cpy = concat_str((char_u *)"./", p); - free(p); + xfree(p); p = cpy; } else if (!is_relative_to_current) { /* Strip leading "./". */ @@ -12527,7 +12542,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv) #ifdef HAVE_READLINK fail: - free(buf); + xfree(buf); #endif rettv->v_type = VAR_STRING; } @@ -12742,7 +12757,7 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv) } if (!channel_send_event((uint64_t)argvars[0].vval.v_number, - (char *)argvars[1].vval.v_string, + (char *)get_tv_string(&argvars[1]), args)) { EMSG2(_(e_invarg2), "Channel doesn't exist"); return; @@ -12809,7 +12824,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv) Error err = ERROR_INIT; Object result = channel_send_call((uint64_t)argvars[0].vval.v_number, - (char *)argvars[1].vval.v_string, + (char *)get_tv_string(&argvars[1]), args, &err); @@ -12873,13 +12888,17 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv) char **argv = xmalloc(sizeof(char_u *) * argvl); // Copy program name + if (argvars[0].vval.v_string == NULL || argvars[0].vval.v_string[0] == NUL) { + EMSG(_(e_api_spawn_failed)); + return; + } argv[0] = xstrdup((char *)argvars[0].vval.v_string); int i = 1; // Copy arguments to the vector if (argsl > 0) { for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) { - argv[i++] = xstrdup((char *)arg->li_tv.vval.v_string); + argv[i++] = xstrdup((char *) get_tv_string(&arg->li_tv)); } } @@ -13241,8 +13260,8 @@ do_searchpair ( if ((flags & SP_NOMOVE) || retval == 0) curwin->w_cursor = save_cursor; - free(pat2); - free(pat3); + xfree(pat2); + xfree(pat3); if (p_cpo == empty_option) p_cpo = save_cpo; else @@ -13277,6 +13296,69 @@ static void f_searchpos(typval_T *argvars, typval_T *rettv) list_append_number(rettv->vval.v_list, (varnumber_T)n); } +/// "serverlist()" function +static void f_serverlist(typval_T *argvars, typval_T *rettv) +{ + size_t n; + char **addrs = server_address_list(&n); + + // Copy addrs into a linked list. + list_T *l = rettv_list_alloc(rettv); + for (size_t i = 0; i < n; i++) { + listitem_T *li = listitem_alloc(); + li->li_tv.v_type = VAR_STRING; + li->li_tv.v_lock = 0; + li->li_tv.vval.v_string = (char_u *) addrs[i]; + list_append(l, li); + } + xfree(addrs); +} + +/// "serverstart()" function +static void f_serverstart(typval_T *argvars, typval_T *rettv) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; // Will hold the address of the new server. + + if (check_restricted() || check_secure()) { + return; + } + + // If the user supplied an address, use it, otherwise use a temp. + if (argvars[0].v_type != VAR_UNKNOWN) { + if (argvars[0].v_type != VAR_STRING) { + EMSG(_(e_invarg)); + return; + } else { + rettv->vval.v_string = vim_strsave(get_tv_string(argvars)); + } + } else { + rettv->vval.v_string = vim_tempname(); + } + + int result = server_start((char *) rettv->vval.v_string); + if (result != 0) { + EMSG2("Failed to start server: %s", uv_strerror(result)); + } +} + +/// "serverstop()" function +static void f_serverstop(typval_T *argvars, typval_T *rettv) +{ + if (check_restricted() || check_secure()) { + return; + } + + if (argvars[0].v_type == VAR_UNKNOWN || argvars[0].v_type != VAR_STRING) { + EMSG(_(e_invarg)); + return; + } + + if (argvars[0].vval.v_string) { + server_stop((char *) argvars[0].vval.v_string); + } +} + /* * "setbufvar()" function */ @@ -13314,7 +13396,7 @@ static void f_setbufvar(typval_T *argvars, typval_T *rettv) STRCPY(bufvarname, "b:"); STRCPY(bufvarname + 2, varname); set_var(bufvarname, varp, TRUE); - free(bufvarname); + xfree(bufvarname); } /* reset notion of buffer */ @@ -13617,8 +13699,8 @@ static void f_setreg(typval_T *argvars, typval_T *rettv) free_lstval: while (curallocval > allocval) - free(*--curallocval); - free(lstval); + xfree(*--curallocval); + xfree(lstval); } else { char_u *strval = get_tv_string_chk(&argvars[1]); if (strval == NULL) { @@ -13658,7 +13740,7 @@ static void f_settabvar(typval_T *argvars, typval_T *rettv) STRCPY(tabvarname, "t:"); STRCPY(tabvarname + 2, varname); set_var(tabvarname, varp, TRUE); - free(tabvarname); + xfree(tabvarname); /* Restore current tabpage */ if (valid_tabpage(save_curtab)) @@ -13724,7 +13806,7 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off) STRCPY(winvarname, "w:"); STRCPY(winvarname + 2, varname); set_var(winvarname, varp, TRUE); - free(winvarname); + xfree(winvarname); } restore_win(save_curwin, save_curtab, TRUE); } @@ -13873,8 +13955,8 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) res = si1->idx > si2->idx ? 1 : -1; } - free(tofree1); - free(tofree2); + xfree(tofree1); + xfree(tofree2); return res; } @@ -14080,7 +14162,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) } } - free(ptrs); + xfree(ptrs); } } @@ -14350,7 +14432,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv) result_buf[0] = NUL; if (conv.vc_type != CONV_NONE) - free(p); + xfree(p); convert_setup(&conv, enc, p_enc); if (conv.vc_type != CONV_NONE) rettv->vval.v_string = string_convert(&conv, result_buf, NULL); @@ -14359,7 +14441,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv) /* Release conversion descriptors */ convert_setup(&conv, NULL, NULL); - free(enc); + xfree(enc); } } @@ -14847,7 +14929,7 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, char *res = NULL; int status = os_system(cmd, input, input_len, &res, &nread); - free(input); + xfree(input); set_vim_var_nr(VV_SHELL_ERROR, (long) status); @@ -14855,6 +14937,8 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, if (retlist) { // return an empty list when there's no output rettv_list_alloc(rettv); + } else { + rettv->vval.v_string = (char_u *) xstrdup(""); } return; } @@ -14868,7 +14952,7 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, rettv->vval.v_list->lv_refcount++; rettv->v_type = VAR_LIST; - free(res); + xfree(res); } else { // res may contain several NULs before the final terminating one. // Replace them with SOH (1) like in get_cmd_output() to avoid truncation. @@ -15026,7 +15110,7 @@ static void f_tagfiles(typval_T *argvars, typval_T *rettv) } tagname_free(&tn); - free(fname); + xfree(fname); } /* @@ -15077,8 +15161,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv) dict_T *job_opts = NULL; if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; - common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit); - if (did_emsg) { + if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { return; } } @@ -15356,7 +15439,7 @@ static void f_undofile(typval_T *argvars, typval_T *rettv) if (ffname != NULL) rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE); - free(ffname); + xfree(ffname); } } } @@ -16099,7 +16182,7 @@ static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u * STRCAT(retval, temp_result); STRCAT(retval, expr_end + 1); } - free(temp_result); + xfree(temp_result); *in_end = c1; /* put char back for error messages */ *expr_start = '{'; @@ -16111,7 +16194,7 @@ static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u * /* Further expansion! */ temp_result = make_expanded_name(retval, expr_start, expr_end, temp_result); - free(retval); + xfree(retval); retval = temp_result; } } @@ -16212,7 +16295,7 @@ set_vim_var_string ( * Will always be invoked when "v:progname" is set. */ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100; - free(vimvars[idx].vv_str); + xfree(vimvars[idx].vv_str); if (val == NULL) vimvars[idx].vv_str = NULL; else if (len == -1) @@ -16291,7 +16374,7 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) oldval = vimvars[VV_CMDARG].vv_str; if (eap == NULL) { - free(oldval); + xfree(oldval); vimvars[VV_CMDARG].vv_str = oldarg; return NULL; } @@ -16474,7 +16557,7 @@ void free_tv(typval_T *varp) func_unref(varp->vval.v_string); /*FALLTHROUGH*/ case VAR_STRING: - free(varp->vval.v_string); + xfree(varp->vval.v_string); break; case VAR_LIST: list_unref(varp->vval.v_list); @@ -16490,7 +16573,7 @@ void free_tv(typval_T *varp) EMSG2(_(e_intern2), "free_tv()"); break; } - free(varp); + xfree(varp); } } @@ -16504,12 +16587,12 @@ void clear_tv(typval_T *varp) case VAR_FUNC: func_unref(varp->vval.v_string); if (varp->vval.v_string != empty_string) { - free(varp->vval.v_string); + xfree(varp->vval.v_string); } varp->vval.v_string = NULL; break; case VAR_STRING: - free(varp->vval.v_string); + xfree(varp->vval.v_string); varp->vval.v_string = NULL; break; case VAR_LIST: @@ -16913,7 +16996,7 @@ static void vars_clear_ext(hashtab_T *ht, int free_val) if (free_val) clear_tv(&v->di_tv); if ((v->di_flags & DI_FLAGS_FIX) == 0) - free(v); + xfree(v); } } hash_clear(ht); @@ -16930,7 +17013,7 @@ static void delete_var(hashtab_T *ht, hashitem_T *hi) hash_remove(ht, hi); clear_tv(&di->di_tv); - free(di); + xfree(di); } /* @@ -16946,7 +17029,7 @@ static void list_one_var(dictitem_T *v, char_u *prefix, int *first) s = echo_string(&v->di_tv, &tofree, numbuf, current_copyID); list_one_var_a(prefix, v->di_key, v->di_tv.v_type, s == NULL ? (char_u *)"" : s, first); - free(tofree); + xfree(tofree); } static void @@ -17041,7 +17124,7 @@ set_var ( */ if (ht == &vimvarht) { if (v->di_tv.v_type == VAR_STRING) { - free(v->di_tv.vval.v_string); + xfree(v->di_tv.vval.v_string); if (copy || tv->v_type != VAR_STRING) v->di_tv.vval.v_string = vim_strsave(get_tv_string(tv)); else { @@ -17078,7 +17161,7 @@ set_var ( v = xmalloc(sizeof(dictitem_T) + STRLEN(varname)); STRCPY(v->di_key, varname); if (hash_add(ht, DI2HIKEY(v)) == FAIL) { - free(v); + xfree(v); return; } v->di_flags = 0; @@ -17369,7 +17452,7 @@ void ex_echo(exarg_T *eap) (void)msg_outtrans_len_attr(p, 1, echo_attr); } } - free(tofree); + xfree(tofree); } clear_tv(&rettv); arg = skipwhite(arg); @@ -17615,7 +17698,7 @@ void ex_function(exarg_T *eap) if (!aborting()) { if (!eap->skip && fudi.fd_newkey != NULL) EMSG2(_(e_dictkey), fudi.fd_newkey); - free(fudi.fd_newkey); + xfree(fudi.fd_newkey); return; } else eap->skip = TRUE; @@ -17731,7 +17814,7 @@ void ex_function(exarg_T *eap) for (int i = 0; i < newargs.ga_len; ++i) if (STRCMP(((char_u **)(newargs.ga_data))[i], arg) == 0) { EMSG2(_("E853: Duplicate argument name: %s"), arg); - free(arg); + xfree(arg); goto erret; } @@ -17837,7 +17920,7 @@ void ex_function(exarg_T *eap) /* between ":append" and "." and between ":python <<EOF" and "EOF" * don't check for ":endfunc". */ if (STRCMP(theline, skip_until) == 0) { - free(skip_until); + xfree(skip_until); skip_until = NULL; } } else { @@ -17848,7 +17931,7 @@ void ex_function(exarg_T *eap) /* Check for "endfunction". */ if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0) { if (line_arg == NULL) - free(theline); + xfree(theline); break; } @@ -17868,7 +17951,7 @@ void ex_function(exarg_T *eap) p = skipwhite(p + 1); } p += eval_fname_script(p); - free(trans_function_name(&p, TRUE, 0, NULL)); + xfree(trans_function_name(&p, TRUE, 0, NULL)); if (*skipwhite(p) == '(') { nesting++; indent += 2; @@ -17884,7 +17967,7 @@ void ex_function(exarg_T *eap) (p[2] == 's')))))) skip_until = vim_strsave((char_u *)"."); - /* Check for ":python <<EOF", ":tcl <<EOF", etc. */ + // Check for ":python <<EOF", ":lua <<EOF", etc. arg = skipwhite(skiptowhite(p)); if (arg[0] == '<' && arg[1] =='<' && ((p[0] == 'p' && p[1] == 'y' @@ -17917,7 +18000,7 @@ void ex_function(exarg_T *eap) * is an extra alloc/free. */ p = vim_strsave(theline); if (line_arg == NULL) - free(theline); + xfree(theline); theline = p; ((char_u **)(newlines.ga_data))[newlines.ga_len++] = theline; @@ -17962,7 +18045,7 @@ void ex_function(exarg_T *eap) /* redefine existing function */ ga_clear_strings(&(fp->uf_args)); ga_clear_strings(&(fp->uf_lines)); - free(name); + xfree(name); name = NULL; } } else { @@ -17984,7 +18067,7 @@ void ex_function(exarg_T *eap) /* Give the function a sequential number. Can only be used with a * Funcref! */ - free(name); + xfree(name); sprintf(numbuf, "%d", ++func_nr); name = vim_strsave((char_u *)numbuf); } @@ -18004,7 +18087,7 @@ void ex_function(exarg_T *eap) if (slen > plen && fnamecmp(p, sourcing_name + slen - plen) == 0) j = OK; - free(scriptname); + xfree(scriptname); } if (j == FAIL) { EMSG2(_( @@ -18021,8 +18104,8 @@ void ex_function(exarg_T *eap) /* add new dict entry */ fudi.fd_di = dictitem_alloc(fudi.fd_newkey); if (dict_add(fudi.fd_dict, fudi.fd_di) == FAIL) { - free(fudi.fd_di); - free(fp); + xfree(fudi.fd_di); + xfree(fp); goto erret; } } else @@ -18059,9 +18142,9 @@ erret: ga_clear_strings(&newargs); ga_clear_strings(&newlines); ret_free: - free(skip_until); - free(fudi.fd_newkey); - free(name); + xfree(skip_until); + xfree(fudi.fd_newkey); + xfree(name); did_emsg |= saved_did_emsg; need_wait_return |= saved_wait_return; } @@ -18373,7 +18456,7 @@ static int function_exists(char_u *name) * "funcname(...", not "funcname!...". */ if (p != NULL && (*nm == NUL || *nm == '(')) n = translated_function_exists(p); - free(p); + xfree(p); return n; } @@ -18480,7 +18563,7 @@ void func_dump_profile(FILE *fd) prof_sort_list(fd, sorttab, st_len, "SELF", TRUE); } - free(sorttab); + xfree(sorttab); } static void @@ -18596,7 +18679,7 @@ script_autoload ( ret = TRUE; } - free(tofree); + xfree(tofree); return ret; } @@ -18686,14 +18769,14 @@ void ex_delfunction(exarg_T *eap) p = eap->arg; name = trans_function_name(&p, eap->skip, 0, &fudi); - free(fudi.fd_newkey); + xfree(fudi.fd_newkey); if (name == NULL) { if (fudi.fd_dict != NULL && !eap->skip) EMSG(_(e_funcref)); return; } if (!ends_excmd(*skipwhite(p))) { - free(name); + xfree(name); EMSG(_(e_trailing)); return; } @@ -18703,7 +18786,7 @@ void ex_delfunction(exarg_T *eap) if (!eap->skip) fp = find_func(name); - free(name); + xfree(name); if (!eap->skip) { if (fp == NULL) { @@ -18739,9 +18822,9 @@ static void func_free(ufunc_T *fp) /* clear this function */ ga_clear_strings(&(fp->uf_args)); ga_clear_strings(&(fp->uf_lines)); - free(fp->uf_tml_count); - free(fp->uf_tml_total); - free(fp->uf_tml_self); + xfree(fp->uf_tml_count); + xfree(fp->uf_tml_total); + xfree(fp->uf_tml_self); /* remove the function from the function hashtable */ hi = hash_find(&func_hashtab, UF2HIKEY(fp)); @@ -18750,7 +18833,7 @@ static void func_free(ufunc_T *fp) else hash_remove(&func_hashtab, hi); - free(fp); + xfree(fp); } /* @@ -18987,7 +19070,7 @@ call_user_func ( s = buf; } msg_puts(s); - free(tofree); + xfree(tofree); } } } @@ -19074,7 +19157,7 @@ call_user_func ( s = buf; } smsg((char_u *)_("%s returning %s"), sourcing_name, s); - free(tofree); + xfree(tofree); } } msg_puts((char_u *)"\n"); /* don't overwrite this either */ @@ -19083,7 +19166,7 @@ call_user_func ( --no_wait_return; } - free(sourcing_name); + xfree(sourcing_name); sourcing_name = save_sourcing_name; sourcing_lnum = save_sourcing_lnum; current_SID = save_current_SID; @@ -19180,7 +19263,7 @@ free_funccal ( for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) clear_tv(&li->li_tv); - free(fc); + xfree(fc); } /* @@ -19311,7 +19394,7 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) clear_tv(current_funccal->rettv); *current_funccal->rettv = *(typval_T *)rettv; if (!is_cmd) - free(rettv); + xfree(rettv); } } @@ -19345,7 +19428,7 @@ char_u *get_return_cmd(void *rettv) STRNCPY(IObuff + 8, s, IOSIZE - 8); if (STRLEN(s) + 8 >= IOSIZE) STRCPY(IObuff + IOSIZE - 4, "..."); - free(tofree); + xfree(tofree); return vim_strsave(IObuff); } @@ -19533,16 +19616,16 @@ int read_viminfo_varlist(vir_T *virp, int writing) * string. */ tv.v_type = VAR_STRING; else { - free(tv.vval.v_string); + xfree(tv.vval.v_string); tv = *etv; - free(etv); + xfree(etv); } } set_var(virp->vir_line + 1, &tv, FALSE); if (tv.v_type == VAR_STRING) - free(tv.vval.v_string); + xfree(tv.vval.v_string); else if (tv.v_type == VAR_DICT || tv.v_type == VAR_LIST) clear_tv(&tv); } @@ -19588,7 +19671,7 @@ void write_viminfo_varlist(FILE *fp) p = echo_string(&this_var->di_tv, &tofree, numbuf, 0); if (p != NULL) viminfo_writestring(fp, p); - free(tofree); + xfree(tofree); } } } @@ -19626,10 +19709,10 @@ int store_session_globals(FILE *fd) (this_var->di_tv.v_type == VAR_STRING) ? '"' : ' ') < 0) || put_eol(fd) == FAIL) { - free(p); + xfree(p); return FAIL; } - free(p); + xfree(p); } else if (this_var->di_tv.v_type == VAR_FLOAT && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) { float_T f = this_var->di_tv.vval.v_float; @@ -19660,7 +19743,7 @@ void last_set_msg(scid_T scriptID) verbose_enter(); MSG_PUTS(_("\n\tLast set from ")); MSG_PUTS(p); - free(p); + xfree(p); verbose_leave(); } } @@ -19740,7 +19823,7 @@ repeat: #endif ) { *fnamep = expand_env_save(*fnamep); - free(*bufp); /* free any allocated file name */ + xfree(*bufp); /* free any allocated file name */ *bufp = *fnamep; if (*fnamep == NULL) return -1; @@ -19760,7 +19843,7 @@ repeat: /* FullName_save() is slow, don't use it when not needed. */ if (*p != NUL || !vim_isAbsName(*fnamep)) { *fnamep = FullName_save(*fnamep, *p != NUL); - free(*bufp); /* free any allocated file name */ + xfree(*bufp); /* free any allocated file name */ *bufp = *fnamep; if (*fnamep == NULL) return -1; @@ -19770,7 +19853,7 @@ repeat: if (os_isdir(*fnamep)) { /* Make room for one or two extra characters. */ *fnamep = vim_strnsave(*fnamep, (int)STRLEN(*fnamep) + 2); - free(*bufp); /* free any allocated file name */ + xfree(*bufp); /* free any allocated file name */ *bufp = *fnamep; if (*fnamep == NULL) return -1; @@ -19806,7 +19889,7 @@ repeat: if (s != NULL) { *fnamep = s; if (pbuf != NULL) { - free(*bufp); /* free any allocated file name */ + xfree(*bufp); /* free any allocated file name */ *bufp = pbuf; pbuf = NULL; } @@ -19817,11 +19900,11 @@ repeat: if (*dirname == '~') { s = vim_strsave(dirname); *fnamep = s; - free(*bufp); + xfree(*bufp); *bufp = s; } } - free(pbuf); + xfree(pbuf); } } @@ -19839,7 +19922,7 @@ repeat: *fnamelen = (int)(tail - *fnamep); if (*fnamelen == 0) { /* Result is empty. Turn it into "." to make ":cd %:h" work. */ - free(*bufp); + xfree(*bufp); *bufp = *fnamep = tail = vim_strsave((char_u *)"."); *fnamelen = 1; } else { @@ -19924,13 +20007,13 @@ repeat: s = do_string_sub(str, pat, sub, flags); *fnamep = s; *fnamelen = (int)STRLEN(s); - free(*bufp); + xfree(*bufp); *bufp = s; didit = TRUE; - free(sub); - free(str); + xfree(sub); + xfree(str); } - free(pat); + xfree(pat); } /* after using ":s", repeat all the modifiers */ if (didit) @@ -19940,7 +20023,7 @@ repeat: if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S') { p = vim_strsave_shellescape(*fnamep, false, false); - free(*bufp); + xfree(*bufp); *bufp = *fnamep = p; *fnamelen = (int)STRLEN(p); *usedlen += 2; @@ -20051,27 +20134,27 @@ static inline JobOptions common_job_options(char **argv, ufunc_T *on_stdout, return opts; } -static inline void common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout, - ufunc_T **on_stderr, ufunc_T **on_exit) +/// Return true/false on success/failure. +static inline bool common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout, + ufunc_T **on_stderr, ufunc_T **on_exit) { - *on_stdout = get_dict_callback(vopts, "on_stdout"); - *on_stderr = get_dict_callback(vopts, "on_stderr"); - *on_exit = get_dict_callback(vopts, "on_exit"); - if (did_emsg) { - if (*on_stdout) { - user_func_unref(*on_stdout); - } - if (*on_stderr) { - user_func_unref(*on_stderr); - } - if (*on_exit) { - user_func_unref(*on_exit); - } - return; + if (get_dict_callback(vopts, "on_stdout", on_stdout) + && get_dict_callback(vopts, "on_stderr", on_stderr) + && get_dict_callback(vopts, "on_exit", on_exit)) { + vopts->internal_refcount++; + vopts->dv_refcount++; + return true; } - - vopts->internal_refcount++; - vopts->dv_refcount++; + if (*on_stdout) { + user_func_unref(*on_stdout); + } + if (*on_stderr) { + user_func_unref(*on_stderr); + } + if (*on_exit) { + user_func_unref(*on_exit); + } + return false; } static inline Job *common_job_start(JobOptions opts, typval_T *rettv) @@ -20083,7 +20166,7 @@ static inline Job *common_job_start(JobOptions opts, typval_T *rettv) if (rettv->vval.v_number <= 0) { if (rettv->vval.v_number == 0) { EMSG(_(e_jobtblfull)); - free(opts.term_name); + xfree(opts.term_name); free_term_job_data(data); } else { EMSG(_(e_jobexe)); @@ -20109,7 +20192,7 @@ static inline void free_term_job_data(TerminalJobData *data) { data->self->internal_refcount--; dict_unref(data->self); } - free(data); + xfree(data); } static inline bool is_user_job(Job *job) @@ -20126,7 +20209,7 @@ static inline bool is_user_job(Job *job) static inline void push_job_event(Job *job, ufunc_T *callback, const char *type, char *data, size_t count, int status) { - JobEvent *event_data = kmp_alloc(JobEventPool, job_event_pool); + JobEvent *event_data = xmalloc(sizeof(JobEvent)); event_data->received = NULL; if (data) { event_data->received = list_alloc(); @@ -20161,7 +20244,7 @@ static inline void push_job_event(Job *job, ufunc_T *callback, event_push((Event) { .handler = on_job_event, .data = event_data - }, defer_job_callbacks); + }, !disable_job_defer); } static void on_job_stdout(RStream *rstream, void *job, bool eof) @@ -20220,7 +20303,7 @@ static void on_job_exit(Job *job, int status, void *d) static void term_write(char *buf, size_t size, void *data) { Job *job = ((TerminalJobData *)data)->job; - WBuffer *wbuf = wstream_new_buffer(xmemdup(buf, size), size, 1, free); + WBuffer *wbuf = wstream_new_buffer(xmemdup(buf, size), size, 1, xfree); job_write(job, wbuf); } @@ -20290,11 +20373,11 @@ static void on_job_event(Event event) clear_tv(&rettv); end: - kmp_free(JobEventPool, job_event_pool, ev); if (!ev->received) { // exit event, safe to free job data now term_job_data_decref(ev->data); } + xfree(ev); } static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv) |