diff options
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 461 |
1 files changed, 270 insertions, 191 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7ac51d7bd7..a1c5f958d1 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1113,19 +1113,17 @@ typval_T *eval_expr(char_u *arg, char_u **nextcmd) } -/* - * Call some vimL function and return the result in "*rettv". - * Uses argv[argc] for the function arguments. Only Number and String - * arguments are currently supported. - * Returns OK or FAIL. - */ -int -call_vim_function ( +// Call some vimL function and return the result in "*rettv". +// Uses argv[argc] for the function arguments. Only Number and String +// arguments are currently supported. +// +// Return OK or FAIL. +int call_vim_function( char_u *func, int argc, char_u **argv, - int safe, /* use the sandbox */ - int str_arg_only, /* all arguments are strings */ + int safe, // use the sandbox + int str_arg_only, // all arguments are strings typval_T *rettv ) { @@ -1138,18 +1136,19 @@ call_vim_function ( typval_T *argvars = xmalloc((argc + 1) * sizeof(typval_T)); for (int i = 0; i < argc; i++) { - /* Pass a NULL or empty argument as an empty string */ + // Pass a NULL or empty argument as an empty string if (argv[i] == NULL || *argv[i] == NUL) { argvars[i].v_type = VAR_STRING; argvars[i].vval.v_string = (char_u *)""; continue; } - if (str_arg_only) + if (str_arg_only) { len = 0; - else - /* Recognize a number argument, the others must be strings. */ - vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL); + } else { + // Recognize a number argument, the others must be strings. + vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL); + } if (len != 0 && len == (int)STRLEN(argv[i])) { argvars[i].v_type = VAR_NUMBER; argvars[i].vval.v_number = n; @@ -1166,16 +1165,17 @@ call_vim_function ( rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */ ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, - curwin->w_cursor.lnum, curwin->w_cursor.lnum, - &doesrange, TRUE, NULL); + curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &doesrange, true, NULL); if (safe) { --sandbox; restore_funccal(save_funccalp); } xfree(argvars); - if (ret == FAIL) + if (ret == FAIL) { clear_tv(rettv); + } return ret; } @@ -2890,9 +2890,12 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit) else if (do_unlet(lp->ll_name, forceit) == FAIL) ret = FAIL; *name_end = cc; - } else if (tv_check_lock(lp->ll_tv->v_lock, lp->ll_name)) + } else if ((lp->ll_list != NULL + && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name)) + || (lp->ll_dict != NULL + && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name))) { return FAIL; - else if (lp->ll_range) { + } else if (lp->ll_range) { listitem_T *li; listitem_T *ll_li = lp->ll_li; int ll_n1 = lp->ll_n1; @@ -2953,17 +2956,30 @@ int do_unlet(char_u *name, int forceit) hashtab_T *ht; hashitem_T *hi; char_u *varname; + dict_T *d; dictitem_T *di; dict_T *dict; ht = find_var_ht_dict(name, &varname, &dict); if (ht != NULL && *varname != NUL) { + if (ht == &globvarht) { + d = &globvardict; + } else if (current_funccal != NULL + && ht == ¤t_funccal->l_vars.dv_hashtab) { + d = ¤t_funccal->l_vars; + } else { + di = find_var_in_ht(ht, *name, (char_u *)"", false); + d = di->di_tv.vval.v_dict; + } + hi = hash_find(ht, varname); if (!HASHITEM_EMPTY(hi)) { di = HI2DI(hi); if (var_check_fixed(di->di_flags, name) - || var_check_ro(di->di_flags, name)) + || var_check_ro(di->di_flags, name) + || tv_check_lock(d->dv_lock, name)) { return FAIL; + } typval_T oldtv; bool watched = is_watched(dict); @@ -4025,38 +4041,35 @@ eval6 ( return OK; } -/* - * Handle sixth level expression: - * number number constant - * "string" string constant - * 'string' literal string constant - * &option-name option value - * @r register contents - * identifier variable value - * function() function call - * $VAR environment variable - * (expression) nested expression - * [expr, expr] List - * {key: val, key: val} Dictionary - * - * Also handle: - * ! in front logical NOT - * - in front unary minus - * + in front unary plus (ignored) - * trailing [] subscript in String or List - * trailing .name entry in Dictionary - * - * "arg" must point to the first non-white of the expression. - * "arg" is advanced to the next non-white after the recognized expression. - * - * Return OK or FAIL. - */ -static int -eval7 ( +// Handle sixth level expression: +// number number constant +// "string" string constant +// 'string' literal string constant +// &option-name option value +// @r register contents +// identifier variable value +// function() function call +// $VAR environment variable +// (expression) nested expression +// [expr, expr] List +// {key: val, key: val} Dictionary +// +// Also handle: +// ! in front logical NOT +// - in front unary minus +// + in front unary plus (ignored) +// trailing [] subscript in String or List +// trailing .name entry in Dictionary +// +// "arg" must point to the first non-white of the expression. +// "arg" is advanced to the next non-white after the recognized expression. +// +// Return OK or FAIL. +static int eval7( char_u **arg, typval_T *rettv, int evaluate, - int want_string /* after "." operator */ + int want_string // after "." operator ) { long n; @@ -4066,24 +4079,19 @@ eval7 ( int ret = OK; char_u *alias; - /* - * Initialise variable so that clear_tv() can't mistake this for a - * string and free a string that isn't there. - */ + // Initialise variable so that clear_tv() can't mistake this for a + // string and free a string that isn't there. rettv->v_type = VAR_UNKNOWN; - /* - * Skip '!' and '-' characters. They are handled later. - */ + // Skip '!' and '-' characters. They are handled later. start_leader = *arg; - while (**arg == '!' || **arg == '-' || **arg == '+') + while (**arg == '!' || **arg == '-' || **arg == '+') { *arg = skipwhite(*arg + 1); + } end_leader = *arg; switch (**arg) { - /* - * Number constant. - */ + // Number constant. case '0': case '1': case '2': @@ -4096,27 +4104,30 @@ eval7 ( case '9': { char_u *p = skipdigits(*arg + 1); - int get_float = FALSE; + int get_float = false; - /* We accept a float when the format matches - * "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very - * strict to avoid backwards compatibility problems. - * Don't look for a float after the "." operator, so that - * ":let vers = 1.2.3" doesn't fail. */ + // We accept a float when the format matches + // "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very + // strict to avoid backwards compatibility problems. + // Don't look for a float after the "." operator, so that + // ":let vers = 1.2.3" doesn't fail. if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) { - get_float = TRUE; + get_float = true; p = skipdigits(p + 2); if (*p == 'e' || *p == 'E') { ++p; - if (*p == '-' || *p == '+') + if (*p == '-' || *p == '+') { ++p; - if (!ascii_isdigit(*p)) - get_float = FALSE; - else + } + if (!ascii_isdigit(*p)) { + get_float = false; + } else { p = skipdigits(p + 1); + } + } + if (ASCII_ISALPHA(*p) || *p == '.') { + get_float = false; } - if (ASCII_ISALPHA(*p) || *p == '.') - get_float = FALSE; } if (get_float) { float_T f; @@ -4127,7 +4138,7 @@ eval7 ( rettv->vval.v_float = f; } } else { - vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL); + vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL); *arg += len; if (evaluate) { rettv->v_type = VAR_NUMBER; @@ -4137,62 +4148,47 @@ eval7 ( break; } - /* - * String constant: "string". - */ + // String constant: "string". case '"': ret = get_string_tv(arg, rettv, evaluate); break; - /* - * Literal string constant: 'str''ing'. - */ + // Literal string constant: 'str''ing'. case '\'': ret = get_lit_string_tv(arg, rettv, evaluate); break; - /* - * List: [expr, expr] - */ + // List: [expr, expr] case '[': ret = get_list_tv(arg, rettv, evaluate); break; - /* - * Dictionary: {key: val, key: val} - */ + // Dictionary: {key: val, key: val} case '{': ret = get_dict_tv(arg, rettv, evaluate); break; - /* - * Option value: &name - */ + // Option value: &name case '&': ret = get_option_tv(arg, rettv, evaluate); break; - /* - * Environment variable: $VAR. - */ + // Environment variable: $VAR. case '$': ret = get_env_tv(arg, rettv, evaluate); break; - /* - * Register contents: @r. - */ + // Register contents: @r. case '@': ++*arg; if (evaluate) { rettv->v_type = VAR_STRING; rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc); } - if (**arg != NUL) + if (**arg != NUL) { ++*arg; + } break; - /* - * nested expression: (expression). - */ + // nested expression: (expression). case '(': *arg = skipwhite(*arg + 1); - ret = eval1(arg, rettv, evaluate); /* recursive! */ - if (**arg == ')') + ret = eval1(arg, rettv, evaluate); // recursive! + if (**arg == ')') { ++*arg; - else if (ret == OK) { + } else if (ret == OK) { EMSG(_("E110: Missing ')'")); clear_tv(rettv); ret = FAIL; @@ -4204,71 +4200,72 @@ eval7 ( } if (ret == NOTDONE) { - /* - * Must be a variable or function name. - * Can also be a curly-braces kind of name: {expr}. - */ + // Must be a variable or function name. + // Can also be a curly-braces kind of name: {expr}. s = *arg; - len = get_name_len(arg, &alias, evaluate, TRUE); - if (alias != NULL) + len = get_name_len(arg, &alias, evaluate, true); + if (alias != NULL) { s = alias; + } - if (len <= 0) + if (len <= 0) { ret = FAIL; - else { - if (**arg == '(') { /* recursive! */ - /* If "s" is the name of a variable of type VAR_FUNC - * use its contents. */ + } else { + if (**arg == '(') { // recursive! + // If "s" is the name of a variable of type VAR_FUNC + // use its contents. s = deref_func_name(s, &len, !evaluate); - /* Invoke the function. */ + // Invoke the function. ret = get_func_tv(s, len, rettv, arg, curwin->w_cursor.lnum, curwin->w_cursor.lnum, &len, evaluate, NULL); - /* If evaluate is FALSE rettv->v_type was not set in - * get_func_tv, but it's needed in handle_subscript() to parse - * what follows. So set it here. */ + // If evaluate is false rettv->v_type was not set in + // get_func_tv, but it's needed in handle_subscript() to parse + // what follows. So set it here. if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') { rettv->vval.v_string = empty_string; rettv->v_type = VAR_FUNC; } - /* Stop the expression evaluation when immediately - * aborting on error, or when an interrupt occurred or - * an exception was thrown but not caught. */ + // Stop the expression evaluation when immediately + // aborting on error, or when an interrupt occurred or + // an exception was thrown but not caught. if (aborting()) { - if (ret == OK) + if (ret == OK) { clear_tv(rettv); + } ret = FAIL; } - } else if (evaluate) - ret = get_var_tv(s, len, rettv, TRUE, FALSE); - else + } else if (evaluate) { + ret = get_var_tv(s, len, rettv, true, false); + } else { ret = OK; + } } xfree(alias); } *arg = skipwhite(*arg); - /* Handle following '[', '(' and '.' for expr[expr], expr.name, - * expr(expr). */ - if (ret == OK) - ret = handle_subscript(arg, rettv, evaluate, TRUE); + // Handle following '[', '(' and '.' for expr[expr], expr.name, + // expr(expr). + if (ret == OK) { + ret = handle_subscript(arg, rettv, evaluate, true); + } - /* - * Apply logical NOT and unary '-', from right to left, ignore '+'. - */ + // Apply logical NOT and unary '-', from right to left, ignore '+'. if (ret == OK && evaluate && end_leader > start_leader) { - int error = FALSE; + int error = false; int val = 0; float_T f = 0.0; - if (rettv->v_type == VAR_FLOAT) + if (rettv->v_type == VAR_FLOAT) { f = rettv->vval.v_float; - else + } else { val = get_tv_number_chk(rettv, &error); + } if (error) { clear_tv(rettv); ret = FAIL; @@ -4276,15 +4273,17 @@ eval7 ( while (end_leader > start_leader) { --end_leader; if (*end_leader == '!') { - if (rettv->v_type == VAR_FLOAT) + if (rettv->v_type == VAR_FLOAT) { f = !f; - else + } else { val = !val; + } } else if (*end_leader == '-') { - if (rettv->v_type == VAR_FLOAT) + if (rettv->v_type == VAR_FLOAT) { f = -f; - else + } else { val = -val; + } } } if (rettv->v_type == VAR_FLOAT) { @@ -4655,10 +4654,13 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) int n, nr; int c = toupper(*p); - if (c == 'X') + if (c == 'X') { n = 2; - else + } else if (*p == 'u') { n = 4; + } else { + n = 8; + } nr = 0; while (--n >= 0 && ascii_isxdigit(p[1])) { ++p; @@ -6069,7 +6071,7 @@ dictitem_T *dictitem_alloc(char_u *key) FUNC_ATTR_NONNULL_RET #ifndef __clang_analyzer__ STRCPY(di->di_key, key); #endif - di->di_flags = 0; + di->di_flags = DI_FLAGS_ALLOC; return di; } @@ -6081,7 +6083,7 @@ static dictitem_T *dictitem_copy(dictitem_T *org) FUNC_ATTR_NONNULL_RET dictitem_T *di = xmalloc(sizeof(dictitem_T) + STRLEN(org->di_key)); STRCPY(di->di_key, org->di_key); - di->di_flags = 0; + di->di_flags = DI_FLAGS_ALLOC; copy_tv(&org->di_tv, &di->di_tv); return di; @@ -6109,7 +6111,9 @@ static void dictitem_remove(dict_T *dict, dictitem_T *item) void dictitem_free(dictitem_T *item) { clear_tv(&item->di_tv); - xfree(item); + if (item->di_flags & DI_FLAGS_ALLOC) { + xfree(item); + } } /// Make a copy of dictionary @@ -7205,9 +7209,9 @@ static struct fst { { "getwinposx", 0, 0, f_getwinposx }, { "getwinposy", 0, 0, f_getwinposy }, { "getwinvar", 2, 3, f_getwinvar }, - { "glob", 1, 3, f_glob }, + { "glob", 1, 4, f_glob }, { "glob2regpat", 1, 1, f_glob2regpat }, - { "globpath", 2, 4, f_globpath }, + { "globpath", 2, 5, f_globpath }, { "has", 1, 1, f_has }, { "has_key", 2, 2, f_has_key }, { "haslocaldir", 0, 0, f_haslocaldir }, @@ -7236,6 +7240,7 @@ static struct fst { { "islocked", 1, 1, f_islocked }, { "items", 1, 1, f_items }, { "jobclose", 1, 2, f_jobclose }, + { "jobpid", 1, 1, f_jobpid }, { "jobresize", 3, 3, f_jobresize }, { "jobsend", 2, 2, f_jobsend }, { "jobstart", 1, 2, f_jobstart }, @@ -9225,6 +9230,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action) hashitem_T *hi2; int todo; bool watched = is_watched(d1); + char *arg_errmsg = N_("extend() argument"); todo = (int)d2->dv_hashtab.ht_used; for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) { @@ -9258,6 +9264,11 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action) } else if (*action == 'f' && HI2DI(hi2) != di1) { typval_T oldtv; + if (tv_check_lock(di1->di_tv.v_lock, (char_u *)_(arg_errmsg)) + || var_check_ro(di1->di_flags, (char_u *)_(arg_errmsg))) { + break; + } + if (watched) { copy_tv(&di1->di_tv, &oldtv); } @@ -9473,12 +9484,14 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL - || tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg))) + || (!map && tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg)))) { return; + } } else if (argvars[0].v_type == VAR_DICT) { if ((d = argvars[0].vval.v_dict) == NULL - || tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg))) + || (!map && tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg)))) { return; + } } else { EMSG2(_(e_listdictarg), ermsg); return; @@ -9507,17 +9520,26 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) for (hi = ht->ht_array; todo > 0; ++hi) { if (!HASHITEM_EMPTY(hi)) { --todo; + di = HI2DI(hi); - if (tv_check_lock(di->di_tv.v_lock, - (char_u *)_(arg_errmsg))) + if (map + && (tv_check_lock(di->di_tv.v_lock, (char_u *)_(arg_errmsg)) + || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg)))) { break; + } + vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); int r = filter_map_one(&di->di_tv, expr, map, &rem); clear_tv(&vimvars[VV_KEY].vv_tv); if (r == FAIL || did_emsg) break; - if (!map && rem) + if (!map && rem) { + if (var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg)) + || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) { + break; + } dictitem_remove(d, di); + } } } hash_unlock(ht); @@ -9525,8 +9547,9 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) vimvars[VV_KEY].vv_type = VAR_NUMBER; for (li = l->lv_first; li != NULL; li = nli) { - if (tv_check_lock(li->li_tv.v_lock, (char_u *)_(arg_errmsg))) + if (map && tv_check_lock(li->li_tv.v_lock, (char_u *)_(arg_errmsg))) { break; + } nli = li->li_next; vimvars[VV_KEY].vv_nr = idx; if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL @@ -10717,10 +10740,15 @@ static void f_glob(typval_T *argvars, typval_T *rettv) if (argvars[1].v_type != VAR_UNKNOWN) { if (get_tv_number_chk(&argvars[1], &error)) options |= WILD_KEEP_ALL; - if (argvars[2].v_type != VAR_UNKNOWN - && get_tv_number_chk(&argvars[2], &error)) { - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; + if (argvars[2].v_type != VAR_UNKNOWN) { + if (get_tv_number_chk(&argvars[2], &error)) { + rettv->v_type = VAR_LIST; + rettv->vval.v_list = NULL; + } + if (argvars[3].v_type != VAR_UNKNOWN + && get_tv_number_chk(&argvars[3], &error)) { + options |= WILD_ALLLINKS; + } } } if (!error) { @@ -10759,10 +10787,15 @@ static void f_globpath(typval_T *argvars, typval_T *rettv) flags |= WILD_KEEP_ALL; } - if (argvars[3].v_type != VAR_UNKNOWN - && get_tv_number_chk(&argvars[3], &error)) { - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; + if (argvars[3].v_type != VAR_UNKNOWN) { + if (get_tv_number_chk(&argvars[3], &error)) { + rettv->v_type = VAR_LIST; + rettv->vval.v_list = NULL; + } + if (argvars[4].v_type != VAR_UNKNOWN + && get_tv_number_chk(&argvars[4], &error)) { + flags |= WILD_ALLLINKS; + } } } @@ -10789,15 +10822,15 @@ static void f_globpath(typval_T *argvars, typval_T *rettv) } } -/* - * "glob2regpat()" function - */ +// "glob2regpat()" function static void f_glob2regpat(typval_T *argvars, typval_T *rettv) { - char_u *pat = get_tv_string_chk(&argvars[0]); + char_u *pat = get_tv_string_chk(&argvars[0]); // NULL on type error - rettv->v_type = VAR_STRING; - rettv->vval.v_string = file_pat_to_reg_pat(pat, NULL, NULL, FALSE); + rettv->v_type = VAR_STRING; + rettv->vval.v_string = (pat == NULL) + ? NULL + : file_pat_to_reg_pat(pat, NULL, NULL, false); } /* @@ -11611,6 +11644,31 @@ static void f_jobclose(typval_T *argvars, typval_T *rettv) } } +// "jobpid(id)" function +static void f_jobpid(typval_T *argvars, typval_T *rettv) +{ + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = 0; + + if (check_restricted() || check_secure()) { + return; + } + + if (argvars[0].v_type != VAR_NUMBER) { + EMSG(_(e_invarg)); + return; + } + + TerminalJobData *data = find_job(argvars[0].vval.v_number); + if (!data) { + EMSG(_(e_invjob)); + return; + } + + Process *proc = (Process *)&data->proc; + rettv->vval.v_number = proc->pid; +} + // "jobsend()" function static void f_jobsend(typval_T *argvars, typval_T *rettv) { @@ -11771,8 +11829,9 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv) } bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0; + bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0; TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit, - job_opts, pty); + job_opts, pty, detach); Process *proc = (Process *)&data->proc; if (pty) { @@ -13855,9 +13914,10 @@ static void f_remove(typval_T *argvars, typval_T *rettv) key = get_tv_string_chk(&argvars[1]); if (key != NULL) { di = dict_find(d, key, -1); - if (di == NULL) + if (di == NULL) { EMSG2(_(e_dictkey), key); - else { + } else if (!var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg)) + && !var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) { *rettv = di->di_tv; init_tv(&di->di_tv); dictitem_remove(d, di); @@ -15971,9 +16031,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv) rettv->v_type = VAR_FLOAT; } -/* - * "str2nr()" function - */ +// "str2nr()" function static void f_str2nr(typval_T *argvars, typval_T *rettv) { int base = 10; @@ -15982,16 +16040,21 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv) if (argvars[1].v_type != VAR_UNKNOWN) { base = get_tv_number(&argvars[1]); - if (base != 8 && base != 10 && base != 16) { + if (base != 2 && base != 8 && base != 10 && base != 16) { EMSG(_(e_invarg)); return; } } p = skipwhite(get_tv_string(&argvars[0])); - if (*p == '+') + if (*p == '+') { p = skipwhite(p + 1); - vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL); + } + vim_str2nr(p, NULL, NULL, + base == 2 ? 2 : 0, + base == 8 ? 2 : 0, + base == 16 ? 2 : 0, + &n, NULL); rettv->vval.v_number = n; } @@ -16776,7 +16839,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv) } TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit, - job_opts, true); + job_opts, true, false); data->proc.pty.width = curwin->w_width; data->proc.pty.height = curwin->w_height; data->proc.pty.term_name = xstrdup("xterm-256color"); @@ -18271,9 +18334,10 @@ long get_tv_number_chk(typval_T *varp, int *denote) EMSG(_("E703: Using a Funcref as a Number")); break; case VAR_STRING: - if (varp->vval.v_string != NULL) + if (varp->vval.v_string != NULL) { vim_str2nr(varp->vval.v_string, NULL, NULL, - TRUE, TRUE, &n, NULL); + true, true, true, &n, NULL); + } return n; case VAR_LIST: EMSG(_("E745: Using a List as a Number")); @@ -18285,10 +18349,12 @@ long get_tv_number_chk(typval_T *varp, int *denote) EMSG2(_(e_intern2), "get_tv_number()"); break; } - if (denote == NULL) /* useful for values that must be unsigned */ + if (denote == NULL) { + // useful for values that must be unsigned n = -1; - else - *denote = TRUE; + } else { + *denote = true; + } return n; } @@ -18619,14 +18685,16 @@ static void vars_clear_ext(hashtab_T *ht, int free_val) if (!HASHITEM_EMPTY(hi)) { --todo; - /* Free the variable. Don't remove it from the hashtab, - * ht_array might change then. hash_clear() takes care of it - * later. */ + // Free the variable. Don't remove it from the hashtab, + // ht_array might change then. hash_clear() takes care of it + // later. v = HI2DI(hi); - if (free_val) + if (free_val) { clear_tv(&v->di_tv); - if ((v->di_flags & DI_FLAGS_FIX) == 0) + } + if (v->di_flags & DI_FLAGS_ALLOC) { xfree(v); + } } } hash_clear(ht); @@ -18800,7 +18868,7 @@ set_var ( xfree(v); return; } - v->di_flags = 0; + v->di_flags = DI_FLAGS_ALLOC; } if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) { @@ -20691,7 +20759,7 @@ call_user_func ( v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; } else { v = xmalloc(sizeof(dictitem_T) + STRLEN(name)); - v->di_flags = DI_FLAGS_RO; + v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC; } STRCPY(v->di_key, name); hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v)); @@ -21782,8 +21850,13 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags) return ret; } -static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout, - ufunc_T *on_stderr, ufunc_T *on_exit, dict_T *self, bool pty) +static inline TerminalJobData *common_job_init(char **argv, + ufunc_T *on_stdout, + ufunc_T *on_stderr, + ufunc_T *on_exit, + dict_T *self, + bool pty, + bool detach) { TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData)); data->stopped = false; @@ -21806,6 +21879,7 @@ static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout, } proc->cb = on_process_exit; proc->events = data->events; + proc->detach = detach; return data; } @@ -21833,8 +21907,13 @@ static inline bool common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout, static inline bool common_job_start(TerminalJobData *data, typval_T *rettv) { - data->refcount++; Process *proc = (Process *)&data->proc; + if (proc->type == kProcessTypePty && proc->detach) { + EMSG2(_(e_invarg2), "terminal/pty job cannot be detached"); + return false; + } + + data->refcount++; char *cmd = xstrdup(proc->argv[0]); if (!process_spawn(proc)) { EMSG2(_(e_jobspawn), cmd); |