Mercurial > vim
diff src/eval.c @ 323:03b3684919e3 v7.0084
updated for version 7.0084
author | vimboss |
---|---|
date | Mon, 13 Jun 2005 22:28:56 +0000 |
parents | a0451524244d |
children | bfd8935d6200 |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -264,12 +264,11 @@ typedef struct #define VV_RO 2 /* read-only */ #define VV_RO_SBX 4 /* read-only in the sandbox */ -#define VV_NAME(s, t) s, sizeof(s) - 1, {{t}}, {0} +#define VV_NAME(s, t) s, {{t}}, {0} static struct vimvar { char *vv_name; /* name of variable, without v: */ - int vv_len; /* length of name */ dictitem_T vv_di; /* value and name for key */ char vv_filler[16]; /* space for LONGEST name below!!! */ char vv_flags; /* VV_COMPAT, VV_RO, VV_RO_SBX */ @@ -594,9 +593,12 @@ static void free_tv __ARGS((typval_T *va static void clear_tv __ARGS((typval_T *varp)); static void init_tv __ARGS((typval_T *varp)); static long get_tv_number __ARGS((typval_T *varp)); +static long get_tv_number_chk __ARGS((typval_T *varp, int *denote)); static linenr_T get_tv_lnum __ARGS((typval_T *argvars)); static char_u *get_tv_string __ARGS((typval_T *varp)); +static char_u *get_tv_string_chk __ARGS((typval_T *varp)); static char_u *get_tv_string_buf __ARGS((typval_T *varp, char_u *buf)); +static char_u *get_tv_string_buf_chk __ARGS((typval_T *varp, char_u *buf)); static dictitem_T *find_var __ARGS((char_u *name, hashtab_T **htp)); static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, char_u *varname, int writing)); static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname)); @@ -1023,7 +1025,7 @@ eval_to_bool(arg, error, nextcmd, skip) *error = FALSE; if (!skip) { - retval = (get_tv_number(&tv) != 0); + retval = (get_tv_number_chk(&tv, error) != 0); clear_tv(&tv); } } @@ -1137,7 +1139,7 @@ eval_to_number(expr) retval = -1; else { - retval = get_tv_number(&rettv); + retval = get_tv_number_chk(&rettv, NULL); clear_tv(&rettv); } --emsg_off; @@ -1775,8 +1777,8 @@ ex_let_one(arg, tv, copy, endchars, op) { c1 = name[len]; name[len] = NUL; - p = get_tv_string(tv); - if (op != NULL && *op == '.') + p = get_tv_string_chk(tv); + if (p != NULL && op != NULL && *op == '.') { int mustfree = FALSE; char_u *s = vim_getenv(name, &mustfree); @@ -1789,15 +1791,18 @@ ex_let_one(arg, tv, copy, endchars, op) } } if (p != NULL) + { vim_setenv(name, p); - if (STRICMP(name, "HOME") == 0) - init_homedir(); - else if (didset_vim && STRICMP(name, "VIM") == 0) - didset_vim = FALSE; - else if (didset_vimruntime && STRICMP(name, "VIMRUNTIME") == 0) - didset_vimruntime = FALSE; + if (STRICMP(name, "HOME") == 0) + init_homedir(); + else if (didset_vim && STRICMP(name, "VIM") == 0) + didset_vim = FALSE; + else if (didset_vimruntime + && STRICMP(name, "VIMRUNTIME") == 0) + didset_vimruntime = FALSE; + arg_end = arg; + } name[len] = c1; - arg_end = arg; vim_free(tofree); } } @@ -1827,8 +1832,8 @@ ex_let_one(arg, tv, copy, endchars, op) *p = NUL; n = get_tv_number(tv); - s = get_tv_string(tv); - if (op != NULL && *op != '=') + s = get_tv_string_chk(tv); /* != NULL if number or string */ + if (s != NULL && op != NULL && *op != '=') { opt_type = get_option_value(arg, &numval, &stringval, opt_flags); @@ -1852,9 +1857,12 @@ ex_let_one(arg, tv, copy, endchars, op) } } } - set_option_value(arg, n, s, opt_flags); + if (s != NULL) + { + set_option_value(arg, n, s, opt_flags); + arg_end = p; + } *p = c1; - arg_end = p; vim_free(stringval); } } @@ -1875,8 +1883,8 @@ ex_let_one(arg, tv, copy, endchars, op) char_u *tofree = NULL; char_u *s; - p = get_tv_string(tv); - if (op != NULL && *op == '.') + p = get_tv_string_chk(tv); + if (p != NULL && op != NULL && *op == '.') { s = get_reg_contents(*arg == '@' ? '"' : *arg, FALSE, FALSE); if (s != NULL) @@ -1886,8 +1894,10 @@ ex_let_one(arg, tv, copy, endchars, op) } } if (p != NULL) + { write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE); - arg_end = arg + 1; + arg_end = arg + 1; + } vim_free(tofree); } } @@ -2070,6 +2080,12 @@ get_lval(name, rettv, lp, unlet, skip, q empty1 = FALSE; if (eval1(&p, &var1, TRUE) == FAIL) /* recursive! */ return NULL; + if (get_tv_string_chk(&var1) == NULL) + { + /* not a number or string */ + clear_tv(&var1); + return NULL; + } } /* Optionally get the second index [ :expr]. */ @@ -2104,6 +2120,14 @@ get_lval(name, rettv, lp, unlet, skip, q clear_tv(&var1); return NULL; } + if (get_tv_string_chk(&var2) == NULL) + { + /* not a number or string */ + if (!empty1) + clear_tv(&var1); + clear_tv(&var2); + return NULL; + } } lp->ll_range = TRUE; } @@ -2130,7 +2154,7 @@ get_lval(name, rettv, lp, unlet, skip, q if (len == -1) { /* "[key]": get key from "var1" */ - key = get_tv_string(&var1); + key = get_tv_string(&var1); /* is number or string */ if (*key == NUL) { if (!quiet) @@ -2176,7 +2200,7 @@ get_lval(name, rettv, lp, unlet, skip, q lp->ll_n1 = 0; else { - lp->ll_n1 = get_tv_number(&var1); + lp->ll_n1 = get_tv_number(&var1); /* is number or string */ clear_tv(&var1); } lp->ll_dict = NULL; @@ -2199,7 +2223,7 @@ get_lval(name, rettv, lp, unlet, skip, q */ if (lp->ll_range && !lp->ll_empty2) { - lp->ll_n2 = get_tv_number(&var2); + lp->ll_n2 = get_tv_number(&var2); /* is number or string */ clear_tv(&var2); if (lp->ll_n2 < 0) { @@ -3340,9 +3364,13 @@ eval1(arg, rettv, evaluate) result = FALSE; if (evaluate) { - if (get_tv_number(rettv) != 0) + int error = FALSE; + + if (get_tv_number_chk(rettv, &error) != 0) result = TRUE; clear_tv(rettv); + if (error) + return FAIL; } /* @@ -3398,6 +3426,7 @@ eval2(arg, rettv, evaluate) typval_T var2; long result; int first; + int error = FALSE; /* * Get the first variable. @@ -3414,9 +3443,11 @@ eval2(arg, rettv, evaluate) { if (evaluate && first) { - if (get_tv_number(rettv) != 0) + if (get_tv_number_chk(rettv, &error) != 0) result = TRUE; clear_tv(rettv); + if (error) + return FAIL; first = FALSE; } @@ -3432,9 +3463,11 @@ eval2(arg, rettv, evaluate) */ if (evaluate && !result) { - if (get_tv_number(&var2) != 0) + if (get_tv_number_chk(&var2, &error) != 0) result = TRUE; clear_tv(&var2); + if (error) + return FAIL; } if (evaluate) { @@ -3464,6 +3497,7 @@ eval3(arg, rettv, evaluate) typval_T var2; long result; int first; + int error = FALSE; /* * Get the first variable. @@ -3480,9 +3514,11 @@ eval3(arg, rettv, evaluate) { if (evaluate && first) { - if (get_tv_number(rettv) == 0) + if (get_tv_number_chk(rettv, &error) == 0) result = FALSE; clear_tv(rettv); + if (error) + return FAIL; first = FALSE; } @@ -3498,9 +3534,11 @@ eval3(arg, rettv, evaluate) */ if (evaluate && result) { - if (get_tv_number(&var2) == 0) + if (get_tv_number_chk(&var2, &error) == 0) result = FALSE; clear_tv(&var2); + if (error) + return FAIL; } if (evaluate) { @@ -3832,6 +3870,22 @@ eval5(arg, rettv, evaluate) if (op != '+' && op != '-' && op != '.') break; + if (op != '+' || rettv->v_type != VAR_LIST) + { + /* For "list + ...", an illegal use of the first operand as + * a number cannot be determined before evaluating the 2nd + * operand: if this is also a list, all is ok. + * For "something . ...", "something - ..." or "non-list + ...", + * we know that the first operand needs to be a string or number + * without evaluating the 2nd operand. So check before to avoid + * side effects after an error. */ + if (evaluate && get_tv_string_chk(rettv) == NULL) + { + clear_tv(rettv); + return FAIL; + } + } + /* * Get the second variable. */ @@ -3849,8 +3903,14 @@ eval5(arg, rettv, evaluate) */ if (op == '.') { - s1 = get_tv_string_buf(rettv, buf1); - s2 = get_tv_string_buf(&var2, buf2); + s1 = get_tv_string_buf(rettv, buf1); /* already checked */ + s2 = get_tv_string_buf_chk(&var2, buf2); + if (s2 == NULL) /* type error ? */ + { + clear_tv(rettv); + clear_tv(&var2); + return FAIL; + } p = concat_str(s1, s2); clear_tv(rettv); rettv->v_type = VAR_STRING; @@ -3872,8 +3932,24 @@ eval5(arg, rettv, evaluate) } else { - n1 = get_tv_number(rettv); - n2 = get_tv_number(&var2); + int error = FALSE; + + n1 = get_tv_number_chk(rettv, &error); + if (error) + { + /* This can only happen for "list + non-list". + * For "non-list + ..." or "something - ...", we returned + * before evaluating the 2nd operand. */ + clear_tv(rettv); + return FAIL; + } + n2 = get_tv_number_chk(&var2, &error); + if (error) + { + clear_tv(rettv); + clear_tv(&var2); + return FAIL; + } clear_tv(rettv); if (op == '+') n1 = n1 + n2; @@ -3908,6 +3984,7 @@ eval6(arg, rettv, evaluate) typval_T var2; int op; long n1, n2; + int error = FALSE; /* * Get the first variable. @@ -3926,8 +4003,10 @@ eval6(arg, rettv, evaluate) if (evaluate) { - n1 = get_tv_number(rettv); + n1 = get_tv_number_chk(rettv, &error); clear_tv(rettv); + if (error) + return FAIL; } else n1 = 0; @@ -3941,8 +4020,10 @@ eval6(arg, rettv, evaluate) if (evaluate) { - n2 = get_tv_number(&var2); + n2 = get_tv_number_chk(&var2, &error); clear_tv(&var2); + if (error) + return FAIL; /* * Compute the result. @@ -4175,18 +4256,28 @@ eval7(arg, rettv, evaluate) */ if (ret == OK && evaluate && end_leader > start_leader) { - val = get_tv_number(rettv); - while (end_leader > start_leader) - { - --end_leader; - if (*end_leader == '!') - val = !val; - else if (*end_leader == '-') - val = -val; - } - clear_tv(rettv); - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = val; + int error = FALSE; + + val = get_tv_number_chk(rettv, &error); + if (error) + { + clear_tv(rettv); + ret = FAIL; + } + else + { + while (end_leader > start_leader) + { + --end_leader; + if (*end_leader == '!') + val = !val; + else if (*end_leader == '-') + val = -val; + } + clear_tv(rettv); + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = val; + } } return ret; @@ -4243,6 +4334,12 @@ eval_index(arg, rettv, evaluate, verbose empty1 = TRUE; else if (eval1(arg, &var1, evaluate) == FAIL) /* recursive! */ return FAIL; + else if (evaluate && get_tv_string_chk(&var1) == NULL) + { + /* not a number or string */ + clear_tv(&var1); + return FAIL; + } /* * Get the second variable from inside the [:]. @@ -4255,7 +4352,16 @@ eval_index(arg, rettv, evaluate, verbose empty2 = TRUE; else if (eval1(arg, &var2, evaluate) == FAIL) /* recursive! */ { - clear_tv(&var1); + if (!empty1) + clear_tv(&var1); + return FAIL; + } + else if (evaluate && get_tv_string_chk(&var2) == NULL) + { + /* not a number or string */ + if (!empty1) + clear_tv(&var1); + clear_tv(&var2); return FAIL; } } @@ -4928,6 +5034,7 @@ tv_equal(tv1, tv2, ic) int ic; /* ignore case */ { char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; + char_u *s1, *s2; if (tv1->v_type == VAR_LIST || tv2->v_type == VAR_LIST) { @@ -4963,12 +5070,13 @@ tv_equal(tv1, tv2, ic) if (get_tv_number(tv1) != get_tv_number(tv2)) return FALSE; } - else if (!ic && STRCMP(get_tv_string_buf(tv1, buf1), - get_tv_string_buf(tv2, buf2)) != 0) - return FALSE; - else if (ic && STRICMP(get_tv_string_buf(tv1, buf1), - get_tv_string_buf(tv2, buf2)) != 0) - return FALSE; + else + { + s1 = get_tv_string_buf(tv1, buf1); + s2 = get_tv_string_buf(tv2, buf2); + if ((ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2)) != 0) + return FALSE; + } return TRUE; } @@ -5828,10 +5936,12 @@ get_dict_tv(arg, rettv, evaluate) clear_tv(&tvkey); goto failret; } - key = get_tv_string_buf(&tvkey, buf); - if (*key == NUL) - { - EMSG(_(e_emptykey)); + key = get_tv_string_buf_chk(&tvkey, buf); + if (key == NULL || *key == NUL) + { + /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */ + if (key != NULL) + EMSG(_(e_emptykey)); clear_tv(&tvkey); goto failret; } @@ -6731,12 +6841,12 @@ f_append(argvars, rettv) typval_T *rettv; { long lnum; + char_u *line; list_T *l = NULL; listitem_T *li = NULL; typval_T *tv; long added = 0; - rettv->vval.v_number = 1; /* Default: Failed */ lnum = get_tv_lnum(argvars); if (lnum >= 0 && lnum <= curbuf->b_ml.ml_line_count @@ -6749,6 +6859,7 @@ f_append(argvars, rettv) return; li = l->lv_first; } + rettv->vval.v_number = 0; /* Default: Success */ for (;;) { if (l == NULL) @@ -6757,7 +6868,13 @@ f_append(argvars, rettv) break; /* end of list */ else tv = &li->li_tv; /* append item from list */ - ml_append(lnum + added, get_tv_string(tv), (colnr_T)0, FALSE); + line = get_tv_string_chk(tv); + if (line == NULL) /* type error */ + { + rettv->vval.v_number = 1; /* Failed */ + break; + } + ml_append(lnum + added, line, (colnr_T)0, FALSE); ++added; if (l == NULL) break; @@ -6767,8 +6884,9 @@ f_append(argvars, rettv) appended_lines_mark(lnum, added); if (curwin->w_cursor.lnum > lnum) curwin->w_cursor.lnum += added; - rettv->vval.v_number = 0; /* Success */ - } + } + else + rettv->vval.v_number = 1; /* Failed */ } /* @@ -6805,7 +6923,7 @@ f_argv(argvars, rettv) { int idx; - idx = get_tv_number(&argvars[0]); + idx = get_tv_number_chk(&argvars[0], NULL); if (idx >= 0 && idx < ARGCOUNT) rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx])); else @@ -6829,13 +6947,17 @@ f_browse(argvars, rettv) char_u *defname; char_u buf[NUMBUFLEN]; char_u buf2[NUMBUFLEN]; - - save = get_tv_number(&argvars[0]); - title = get_tv_string(&argvars[1]); - initdir = get_tv_string_buf(&argvars[2], buf); - defname = get_tv_string_buf(&argvars[3], buf2); - - rettv->vval.v_string = + int error = FALSE; + + save = get_tv_number_chk(&argvars[0], &error); + title = get_tv_string_chk(&argvars[1]); + initdir = get_tv_string_buf_chk(&argvars[2], buf); + defname = get_tv_string_buf_chk(&argvars[3], buf2); + + if (error || title == NULL || initdir == NULL || defname == NULL) + rettv->vval.v_string = NULL; + else + rettv->vval.v_string = do_browse(save ? BROWSE_SAVE : 0, title, defname, NULL, initdir, NULL, curbuf); #else @@ -6858,10 +6980,13 @@ f_browsedir(argvars, rettv) char_u *initdir; char_u buf[NUMBUFLEN]; - title = get_tv_string(&argvars[0]); - initdir = get_tv_string_buf(&argvars[1], buf); - - rettv->vval.v_string = do_browse(BROWSE_DIR, + title = get_tv_string_chk(&argvars[0]); + initdir = get_tv_string_buf_chk(&argvars[1], buf); + + if (title == NULL || initdir == NULL) + rettv->vval.v_string = NULL; + else + rettv->vval.v_string = do_browse(BROWSE_DIR, title, NULL, NULL, initdir, NULL, curbuf); #else rettv->vval.v_string = NULL; @@ -6994,6 +7119,7 @@ f_bufname(argvars, rettv) { buf_T *buf; + (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ ++emsg_off; buf = get_buf_tv(&argvars[0]); rettv->v_type = VAR_STRING; @@ -7014,6 +7140,7 @@ f_bufnr(argvars, rettv) { buf_T *buf; + (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ ++emsg_off; buf = get_buf_tv(&argvars[0]); if (buf != NULL) @@ -7037,6 +7164,7 @@ f_bufwinnr(argvars, rettv) #endif buf_T *buf; + (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ ++emsg_off; buf = get_buf_tv(&argvars[0]); #ifdef FEAT_WINDOWS @@ -7067,7 +7195,7 @@ f_byte2line(argvars, rettv) #else long boff = 0; - boff = get_tv_number(&argvars[0]) - 1; + boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */ if (boff < 0) rettv->vval.v_number = -1; else @@ -7091,10 +7219,10 @@ f_byteidx(argvars, rettv) char_u *str; long idx; - str = get_tv_string(&argvars[0]); - idx = get_tv_number(&argvars[1]); + str = get_tv_string_chk(&argvars[0]); + idx = get_tv_number_chk(&argvars[1], NULL); rettv->vval.v_number = -1; - if (idx < 0) + if (str == NULL || idx < 0) return; #ifdef FEAT_MBYTE @@ -7140,6 +7268,8 @@ f_call(argvars, rettv) func = argvars[0].vval.v_string; else func = get_tv_string(&argvars[0]); + if (*func == NUL) + return; /* type error or empty name */ if (argvars[2].v_type != VAR_UNKNOWN) { @@ -7185,8 +7315,7 @@ f_char2nr(argvars, rettv) { #ifdef FEAT_MBYTE if (has_mbyte) - rettv->vval.v_number = - (*mb_ptr2char)(get_tv_string(&argvars[0])); + rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0])); else #endif rettv->vval.v_number = get_tv_string(&argvars[0])[0]; @@ -7285,26 +7414,35 @@ f_confirm(argvars, rettv) char_u buf2[NUMBUFLEN]; int def = 1; int type = VIM_GENERIC; - int c; - - message = get_tv_string(&argvars[0]); + char_u *typestr; + int error = FALSE; + + message = get_tv_string_chk(&argvars[0]); + if (message == NULL) + error = TRUE; if (argvars[1].v_type != VAR_UNKNOWN) { - buttons = get_tv_string_buf(&argvars[1], buf); + buttons = get_tv_string_buf_chk(&argvars[1], buf); + if (buttons == NULL) + error = TRUE; if (argvars[2].v_type != VAR_UNKNOWN) { - def = get_tv_number(&argvars[2]); + def = get_tv_number_chk(&argvars[2], &error); if (argvars[3].v_type != VAR_UNKNOWN) { - /* avoid that TOUPPER_ASC calls get_tv_string_buf() twice */ - c = *get_tv_string_buf(&argvars[3], buf2); - switch (TOUPPER_ASC(c)) - { - case 'E': type = VIM_ERROR; break; - case 'Q': type = VIM_QUESTION; break; - case 'I': type = VIM_INFO; break; - case 'W': type = VIM_WARNING; break; - case 'G': type = VIM_GENERIC; break; + typestr = get_tv_string_buf_chk(&argvars[3], buf2); + if (typestr == NULL) + error = TRUE; + else + { + switch (TOUPPER_ASC(*typestr)) + { + case 'E': type = VIM_ERROR; break; + case 'Q': type = VIM_QUESTION; break; + case 'I': type = VIM_INFO; break; + case 'W': type = VIM_WARNING; break; + case 'G': type = VIM_GENERIC; break; + } } } } @@ -7313,7 +7451,10 @@ f_confirm(argvars, rettv) if (buttons == NULL || *buttons == NUL) buttons = (char_u *)_("&Ok"); - rettv->vval.v_number = do_dialog(type, NULL, message, buttons, + if (error) + rettv->vval.v_number = 0; + else + rettv->vval.v_number = do_dialog(type, NULL, message, buttons, def, NULL); #else rettv->vval.v_number = 0; @@ -7353,14 +7494,21 @@ f_count(argvars, rettv) li = l->lv_first; if (argvars[2].v_type != VAR_UNKNOWN) { - ic = get_tv_number(&argvars[2]); + int error = FALSE; + + ic = get_tv_number_chk(&argvars[2], &error); if (argvars[3].v_type != VAR_UNKNOWN) { - idx = get_tv_number(&argvars[3]); - li = list_find(l, idx); - if (li == NULL) - EMSGN(_(e_listidx), idx); - } + idx = get_tv_number_chk(&argvars[3], &error); + if (!error) + { + li = list_find(l, idx); + if (li == NULL) + EMSGN(_(e_listidx), idx); + } + } + if (error) + li = NULL; } for ( ; li != NULL; li = li->li_next) @@ -7376,14 +7524,16 @@ f_count(argvars, rettv) if ((d = argvars[0].vval.v_dict) != NULL) { + int error = FALSE; + if (argvars[2].v_type != VAR_UNKNOWN) { - ic = get_tv_number(&argvars[2]); + ic = get_tv_number_chk(&argvars[2], &error); if (argvars[3].v_type != VAR_UNKNOWN) EMSG(_(e_invarg)); } - todo = d->dv_hashtab.ht_used; + todo = error ? 0 : d->dv_hashtab.ht_used; for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) { if (!HASHITEM_EMPTY(hi)) @@ -7446,9 +7596,11 @@ f_cursor(argvars, rettv) long line, col; line = get_tv_lnum(argvars); + col = get_tv_number_chk(&argvars[1], NULL); + if (line < 0 || col < 0) + return; /* type error; errmsg already given */ if (line > 0) curwin->w_cursor.lnum = line; - col = get_tv_number(&argvars[1]); if (col > 0) curwin->w_cursor.col = col - 1; #ifdef FEAT_VIRTUALEDIT @@ -7478,7 +7630,7 @@ f_deepcopy(argvars, rettv) int noref = 0; if (argvars[1].v_type != VAR_UNKNOWN) - noref = get_tv_number(&argvars[1]); + noref = get_tv_number_chk(&argvars[1], NULL); if (noref < 0 || noref > 1) EMSG(_(e_invarg)); else @@ -7549,6 +7701,8 @@ f_diff_hlID(argvars, rettv) int filler_lines; int col; + if (lnum < 0) /* ignore type error in {lnum} arg */ + lnum = 0; if (lnum != prev_lnum || changedtick != curbuf->b_changedtick || fnum != curbuf->b_fnum) @@ -7578,7 +7732,7 @@ f_diff_hlID(argvars, rettv) if (hlID == HLF_CHD || hlID == HLF_TXD) { - col = get_tv_number(&argvars[1]) - 1; + col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */ if (col >= change_start && col <= change_end) hlID = HLF_TXD; /* changed text */ else @@ -7650,11 +7804,15 @@ f_eval(argvars, rettv) { char_u *s; - s = get_tv_string(&argvars[0]); - s = skipwhite(s); - - if (eval1(&s, rettv, TRUE) == FAIL) + s = get_tv_string_chk(&argvars[0]); + if (s != NULL) + s = skipwhite(s); + + if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) + { + rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; + } else if (*s != NUL) EMSG(_(e_trailing)); } @@ -7772,6 +7930,7 @@ f_expand(argvars, rettv) char_u *errormsg; int flags = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; expand_T xpc; + int error = FALSE; rettv->v_type = VAR_STRING; s = get_tv_string(&argvars[0]); @@ -7785,12 +7944,18 @@ f_expand(argvars, rettv) { /* When the optional second argument is non-zero, don't remove matches * for 'suffixes' and 'wildignore' */ - if (argvars[1].v_type != VAR_UNKNOWN && get_tv_number(&argvars[1])) + if (argvars[1].v_type != VAR_UNKNOWN + && get_tv_number_chk(&argvars[1], &error)) flags |= WILD_KEEP_ALL; - ExpandInit(&xpc); - xpc.xp_context = EXPAND_FILES; - rettv->vval.v_string = ExpandOne(&xpc, s, NULL, flags, WILD_ALL); - ExpandCleanup(&xpc); + if (!error) + { + ExpandInit(&xpc); + xpc.xp_context = EXPAND_FILES; + rettv->vval.v_string = ExpandOne(&xpc, s, NULL, flags, WILD_ALL); + ExpandCleanup(&xpc); + } + else + rettv->vval.v_string = NULL; } } @@ -7809,6 +7974,7 @@ f_extend(argvars, rettv) list_T *l1, *l2; listitem_T *item; long before; + int error = FALSE; l1 = argvars[0].vval.v_list; l2 = argvars[1].vval.v_list; @@ -7817,7 +7983,10 @@ f_extend(argvars, rettv) { if (argvars[2].v_type != VAR_UNKNOWN) { - before = get_tv_number(&argvars[2]); + before = get_tv_number_chk(&argvars[2], &error); + if (error) + return; /* type error; errmsg already given */ + if (before == l1->lv_len) item = NULL; else @@ -7857,7 +8026,9 @@ f_extend(argvars, rettv) { static char *(av[]) = {"keep", "force", "error"}; - action = get_tv_string(&argvars[2]); + action = get_tv_string_chk(&argvars[2]); + if (action == NULL) + return; /* type error; errmsg already given */ for (i = 0; i < 3; ++i) if (STRCMP(action, av[i]) == 0) break; @@ -7963,22 +8134,30 @@ findfilendir(argvars, rettv, dir) if (argvars[1].v_type != VAR_UNKNOWN) { - p = get_tv_string_buf(&argvars[1], pathbuf); - if (*p != NUL) - path = p; - - if (argvars[2].v_type != VAR_UNKNOWN) - count = get_tv_number(&argvars[2]); - } - - do - { - vim_free(fresult); - fresult = find_file_in_path_option(first ? fname : NULL, - first ? (int)STRLEN(fname) : 0, - 0, first, path, dir, NULL); - first = FALSE; - } while (--count > 0 && fresult != NULL); + p = get_tv_string_buf_chk(&argvars[1], pathbuf); + if (p == NULL) + count = -1; /* error */ + else + { + if (*p != NUL) + path = p; + + if (argvars[2].v_type != VAR_UNKNOWN) + count = get_tv_number_chk(&argvars[2], NULL); /* -1: error */ + } + } + + if (*fname != NUL && count >= 0) + { + do + { + vim_free(fresult); + fresult = find_file_in_path_option(first ? fname : NULL, + first ? (int)STRLEN(fname) : 0, + 0, first, path, dir, NULL); + first = FALSE; + } while (--count > 0 && fresult != NULL); + } rettv->vval.v_string = fresult; #else @@ -8073,52 +8252,59 @@ filter_map(argvars, rettv, map) return; } - prepare_vimvar(VV_VAL, &save_val); - expr = skipwhite(get_tv_string_buf(&argvars[1], buf)); - - if (argvars[0].v_type == VAR_DICT) - { - prepare_vimvar(VV_KEY, &save_key); - vimvars[VV_KEY].vv_type = VAR_STRING; - - ht = &d->dv_hashtab; - hash_lock(ht); - todo = ht->ht_used; - 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, msg)) + expr = get_tv_string_buf_chk(&argvars[1], buf); + /* On type errors, the preceding call has already displayed an error + * message. Avoid a misleading error message for an empty string that + * was not passed as argument. */ + if (expr != NULL) + { + prepare_vimvar(VV_VAL, &save_val); + expr = skipwhite(expr); + + if (argvars[0].v_type == VAR_DICT) + { + prepare_vimvar(VV_KEY, &save_key); + vimvars[VV_KEY].vv_type = VAR_STRING; + + ht = &d->dv_hashtab; + hash_lock(ht); + todo = ht->ht_used; + 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, msg)) + break; + vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); + if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL) + break; + if (!map && rem) + dictitem_remove(d, di); + clear_tv(&vimvars[VV_KEY].vv_tv); + } + } + hash_unlock(ht); + + restore_vimvar(VV_KEY, &save_key); + } + else + { + for (li = l->lv_first; li != NULL; li = nli) + { + if (tv_check_lock(li->li_tv.v_lock, msg)) break; - vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); - if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL) + nli = li->li_next; + if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL) break; if (!map && rem) - dictitem_remove(d, di); - clear_tv(&vimvars[VV_KEY].vv_tv); - } - } - hash_unlock(ht); - - restore_vimvar(VV_KEY, &save_key); - } - else - { - for (li = l->lv_first; li != NULL; li = nli) - { - if (tv_check_lock(li->li_tv.v_lock, msg)) - break; - nli = li->li_next; - if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL) - break; - if (!map && rem) - listitem_remove(l, li); - } - } - - restore_vimvar(VV_VAL, &save_val); + listitem_remove(l, li); + } + } + + restore_vimvar(VV_VAL, &save_val); + } copy_tv(&argvars[0], rettv); } @@ -8150,9 +8336,15 @@ filter_map_one(tv, expr, map, remp) } else { + int error = FALSE; + /* filter(): when expr is zero remove the item */ - *remp = (get_tv_number(&rettv) == 0); + *remp = (get_tv_number_chk(&rettv, &error) == 0); clear_tv(&rettv); + /* On type error, nothing has been removed; return FAIL to stop the + * loop. The error message was given by get_tv_number_chk(). */ + if (error) + return FAIL; } clear_tv(&vimvars[VV_VAL].vv_tv); return OK; @@ -8206,11 +8398,15 @@ f_fnamemodify(argvars, rettv) char_u *fbuf = NULL; char_u buf[NUMBUFLEN]; - fname = get_tv_string(&argvars[0]); - mods = get_tv_string_buf(&argvars[1], buf); - len = (int)STRLEN(fname); - - (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len); + fname = get_tv_string_chk(&argvars[0]); + mods = get_tv_string_buf_chk(&argvars[1], buf); + if (fname == NULL || mods == NULL) + fname = NULL; + else + { + len = (int)STRLEN(fname); + (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len); + } rettv->v_type = VAR_STRING; if (fname == NULL) @@ -8381,6 +8577,9 @@ f_foldtextresult(argvars, rettv) rettv->vval.v_string = NULL; #ifdef FEAT_FOLDING lnum = get_tv_lnum(argvars); + /* treat illegal types and illegal string values for {lnum} the same */ + if (lnum < 0) + lnum = 0; fold_count = foldedCount(curwin, lnum, &foldinfo); if (fold_count > 0) { @@ -8455,8 +8654,10 @@ f_get(argvars, rettv) { if ((l = argvars[0].vval.v_list) != NULL) { - li = list_find(l, get_tv_number(&argvars[1])); - if (li != NULL) + int error = FALSE; + + li = list_find(l, get_tv_number_chk(&argvars[1], &error)); + if (!error && li != NULL) tv = &li->li_tv; } } @@ -8496,9 +8697,10 @@ f_getbufvar(argvars, rettv) char_u *varname; dictitem_T *v; + (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ + varname = get_tv_string_chk(&argvars[1]); ++emsg_off; buf = get_buf_tv(&argvars[0]); - varname = get_tv_string(&argvars[1]); rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -8518,6 +8720,11 @@ f_getbufvar(argvars, rettv) } else { + if (*varname == NUL) + /* let getbufvar({nr}, "") return the "b:" dictionary. The + * scope prefix before the NUL byte is required by + * find_var_in_ht(). */ + varname = (char_u *)"b:" + 2; /* look up the variable */ v = find_var_in_ht(&buf->b_vars.dv_hashtab, varname, FALSE); if (v != NULL) @@ -8537,17 +8744,18 @@ f_getchar(argvars, rettv) typval_T *rettv; { varnumber_T n; + int error = FALSE; ++no_mapping; ++allow_keys; if (argvars[0].v_type == VAR_UNKNOWN) /* getchar(): blocking wait. */ n = safe_vgetc(); - else if (get_tv_number(&argvars[0]) == 1) + else if (get_tv_number_chk(&argvars[0], &error) == 1) /* getchar(1): only check if char avail */ n = vpeekc(); - else if (vpeekc() == NUL) - /* getchar(0) and no char avail: return zero */ + else if (error || vpeekc() == NUL) + /* illegal argument or getchar(0) and no char avail: return zero */ n = 0; else /* getchar(0) and char avail: return char */ @@ -8858,8 +9066,9 @@ f_getline(argvars, rettv) listitem_T *li; lnum = get_tv_lnum(argvars); - - if (argvars[1].v_type == VAR_UNKNOWN) + if (lnum < 0) + rettv->vval.v_number = 0; /* failure; error message already given */ + else if (argvars[1].v_type == VAR_UNKNOWN) { if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) p = ml_get(lnum); @@ -8874,7 +9083,8 @@ f_getline(argvars, rettv) end = get_tv_lnum(&argvars[1]); if (end < lnum) { - EMSG(_(e_invrange)); + if (end >= 0) /* else: error message already given */ + EMSG(_(e_invrange)); rettv->vval.v_number = 0; } else @@ -8945,12 +9155,14 @@ f_getreg(argvars, rettv) char_u *strregname; int regname; int arg2 = FALSE; + int error = FALSE; if (argvars[0].v_type != VAR_UNKNOWN) { - strregname = get_tv_string(&argvars[0]); + strregname = get_tv_string_chk(&argvars[0]); + error = strregname == NULL; if (argvars[1].v_type != VAR_UNKNOWN) - arg2 = get_tv_number(&argvars[1]); + arg2 = get_tv_number_chk(&argvars[1], &error); } else strregname = vimvars[VV_REG].vv_str; @@ -8959,7 +9171,8 @@ f_getreg(argvars, rettv) regname = '"'; rettv->v_type = VAR_STRING; - rettv->vval.v_string = get_reg_contents(regname, TRUE, arg2); + rettv->vval.v_string = error ? NULL : + get_reg_contents(regname, TRUE, arg2); } /* @@ -8976,7 +9189,15 @@ f_getregtype(argvars, rettv) long reglen = 0; if (argvars[0].v_type != VAR_UNKNOWN) - strregname = get_tv_string(&argvars[0]); + { + strregname = get_tv_string_chk(&argvars[0]); + if (strregname == NULL) /* type error; errmsg already given */ + { + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + return; + } + } else /* Default to v:register */ strregname = vimvars[VV_REG].vv_str; @@ -9056,9 +9277,9 @@ f_getwinvar(argvars, rettv) char_u *varname; dictitem_T *v; + win = find_win_by_nr(&argvars[0]); + varname = get_tv_string_chk(&argvars[1]); ++emsg_off; - win = find_win_by_nr(&argvars[0]); - varname = get_tv_string(&argvars[1]); rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -9081,6 +9302,11 @@ f_getwinvar(argvars, rettv) } else { + if (*varname == NUL) + /* let getwinvar({nr}, "") return the "w:" dictionary. The + * scope prefix before the NUL byte is required by + * find_var_in_ht(). */ + varname = (char_u *)"w:" + 2; /* look up the variable */ v = find_var_in_ht(&win->w_vars.dv_hashtab, varname, FALSE); if (v != NULL) @@ -9118,10 +9344,13 @@ f_globpath(argvars, rettv) typval_T *rettv; { char_u buf1[NUMBUFLEN]; + char_u *file = get_tv_string_buf_chk(&argvars[1], buf1); rettv->v_type = VAR_STRING; - rettv->vval.v_string = globpath(get_tv_string(&argvars[0]), - get_tv_string_buf(&argvars[1], buf1)); + if (file == NULL) + rettv->vval.v_string = NULL; + else + rettv->vval.v_string = globpath(get_tv_string(&argvars[0]), file); } /* @@ -9697,7 +9926,8 @@ f_histadd(argvars, rettv) if (check_restricted() || check_secure()) return; #ifdef FEAT_CMDHIST - histype = get_histtype(get_tv_string(&argvars[0])); + str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ + histype = str != NULL ? get_histtype(str) : -1; if (histype >= 0) { str = get_tv_string_buf(&argvars[1], buf); @@ -9723,17 +9953,21 @@ f_histdel(argvars, rettv) #ifdef FEAT_CMDHIST int n; char_u buf[NUMBUFLEN]; - - if (argvars[1].v_type == VAR_UNKNOWN) + char_u *str; + + str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ + if (str == NULL) + n = 0; + else if (argvars[1].v_type == VAR_UNKNOWN) /* only one argument: clear entire history */ - n = clr_history(get_histtype(get_tv_string(&argvars[0]))); + n = clr_history(get_histtype(str)); else if (argvars[1].v_type == VAR_NUMBER) /* index given: remove that entry */ - n = del_history_idx(get_histtype(get_tv_string(&argvars[0])), + n = del_history_idx(get_histtype(str), (int)get_tv_number(&argvars[1])); else /* string given: remove all matching entries */ - n = del_history_entry(get_histtype(get_tv_string(&argvars[0])), + n = del_history_entry(get_histtype(str), get_tv_string_buf(&argvars[1], buf)); rettv->vval.v_number = n; #else @@ -9753,13 +9987,21 @@ f_histget(argvars, rettv) #ifdef FEAT_CMDHIST int type; int idx; - - type = get_histtype(get_tv_string(&argvars[0])); - if (argvars[1].v_type == VAR_UNKNOWN) - idx = get_history_idx(type); - else - idx = (int)get_tv_number(&argvars[1]); - rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); + char_u *str; + + str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ + if (str == NULL) + rettv->vval.v_string = NULL; + else + { + type = get_histtype(str); + if (argvars[1].v_type == VAR_UNKNOWN) + idx = get_history_idx(type); + else + idx = (int)get_tv_number_chk(&argvars[1], NULL); + /* -1 on type error */ + rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); + } #else rettv->vval.v_string = NULL; #endif @@ -9778,7 +10020,9 @@ f_histnr(argvars, rettv) int i; #ifdef FEAT_CMDHIST - i = get_histtype(get_tv_string(&argvars[0])); + char_u *history = get_tv_string_chk(&argvars[0]); + + i = history == NULL ? HIST_CMD - 1 : get_histtype(history); if (i >= HIST_CMD && i < HIST_COUNT) i = get_history_idx(i); else @@ -9905,12 +10149,16 @@ f_index(argvars, rettv) item = l->lv_first; if (argvars[2].v_type != VAR_UNKNOWN) { + int error = FALSE; + /* Start at specified item. Use the cached index that list_find() * sets, so that a negative number also works. */ - item = list_find(l, get_tv_number(&argvars[2])); + item = list_find(l, get_tv_number_chk(&argvars[2], &error)); idx = l->lv_idx; if (argvars[3].v_type != VAR_UNKNOWN) - ic = get_tv_number(&argvars[3]); + ic = get_tv_number_chk(&argvars[3], &error); + if (error) + item = NULL; } for ( ; item != NULL; item = item->li_next, ++idx) @@ -9933,11 +10181,12 @@ f_input(argvars, rettv) typval_T *argvars; typval_T *rettv; { - char_u *prompt = get_tv_string(&argvars[0]); + char_u *prompt = get_tv_string_chk(&argvars[0]); char_u *p = NULL; int c; char_u buf[NUMBUFLEN]; int cmd_silent_save = cmd_silent; + char_u *defstr = (char_u *)""; rettv->v_type = VAR_STRING; @@ -9971,17 +10220,22 @@ f_input(argvars, rettv) *p = c; } cmdline_row = msg_row; - } - - if (argvars[1].v_type != VAR_UNKNOWN) - stuffReadbuffSpec(get_tv_string_buf(&argvars[1], buf)); - - rettv->vval.v_string = + + if (argvars[1].v_type != VAR_UNKNOWN) + { + defstr = get_tv_string_buf_chk(&argvars[1], buf); + if (defstr != NULL) + stuffReadbuffSpec(defstr); + } + + if (defstr != NULL) + rettv->vval.v_string = getcmdline_prompt(inputsecret_flag ? NUL : '@', p, echo_attr); - /* since the user typed this, no need to wait for return */ - need_wait_return = FALSE; - msg_didout = FALSE; + /* since the user typed this, no need to wait for return */ + need_wait_return = FALSE; + msg_didout = FALSE; + } cmd_silent = cmd_silent_save; } @@ -9999,21 +10253,25 @@ f_inputdialog(argvars, rettv) { char_u *message; char_u buf[NUMBUFLEN]; - - message = get_tv_string(&argvars[0]); - if (argvars[1].v_type != VAR_UNKNOWN) - { - STRNCPY(IObuff, get_tv_string_buf(&argvars[1], buf), IOSIZE); + char_u *defstr = (char_u *)""; + + message = get_tv_string_chk(&argvars[0]); + if (argvars[1].v_type != VAR_UNKNOWN + && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL) + { + STRNCPY(IObuff, defstr, IOSIZE); IObuff[IOSIZE - 1] = NUL; } else IObuff[0] = NUL; - if (do_dialog(VIM_QUESTION, NULL, message, (char_u *)_("&OK\n&Cancel"), - 1, IObuff) == 1) + if (message != NULL && defstr != NULL + && do_dialog(VIM_QUESTION, NULL, message, + (char_u *)_("&OK\n&Cancel"), 1, IObuff) == 1) rettv->vval.v_string = vim_strsave(IObuff); else { - if (argvars[1].v_type != VAR_UNKNOWN + if (message != NULL && defstr != NULL + && argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) rettv->vval.v_string = vim_strsave( get_tv_string_buf(&argvars[2], buf)); @@ -10099,6 +10357,7 @@ f_insert(argvars, rettv) long before = 0; listitem_T *item; list_T *l; + int error = FALSE; rettv->vval.v_number = 0; if (argvars[0].v_type != VAR_LIST) @@ -10107,7 +10366,9 @@ f_insert(argvars, rettv) && !tv_check_lock(l->lv_lock, (char_u *)"insert()")) { if (argvars[2].v_type != VAR_UNKNOWN) - before = get_tv_number(&argvars[2]); + before = get_tv_number_chk(&argvars[2], &error); + if (error) + return; /* type error; errmsg already given */ if (before == l->lv_len) item = NULL; @@ -10339,14 +10600,19 @@ f_join(argvars, rettv) if (argvars[1].v_type == VAR_UNKNOWN) sep = (char_u *)" "; else - sep = get_tv_string(&argvars[1]); - - ga_init2(&ga, (int)sizeof(char), 80); - list_join(&ga, argvars[0].vval.v_list, sep, TRUE); - ga_append(&ga, NUL); + sep = get_tv_string_chk(&argvars[1]); rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char_u *)ga.ga_data; + + if (sep != NULL) + { + ga_init2(&ga, (int)sizeof(char), 80); + list_join(&ga, argvars[0].vval.v_list, sep, TRUE); + ga_append(&ga, NUL); + rettv->vval.v_string = (char_u *)ga.ga_data; + } + else + rettv->vval.v_string = NULL; } /* @@ -10577,9 +10843,12 @@ get_maparg(argvars, rettv, exact) return; if (argvars[1].v_type != VAR_UNKNOWN) - which = get_tv_string_buf(&argvars[1], buf); + which = get_tv_string_buf_chk(&argvars[1], buf); else which = (char_u *)""; + if (which == NULL) + return; + mode = get_map_mode(&which, 0); keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE); @@ -10683,11 +10952,17 @@ find_some_match(argvars, rettv, type) else expr = str = get_tv_string(&argvars[0]); - pat = get_tv_string_buf(&argvars[1], patbuf); + pat = get_tv_string_buf_chk(&argvars[1], patbuf); + if (pat == NULL) + goto theend; if (argvars[2].v_type != VAR_UNKNOWN) { - start = get_tv_number(&argvars[2]); + int error = FALSE; + + start = get_tv_number_chk(&argvars[2], &error); + if (error) + goto theend; if (l != NULL) { li = list_find(l, start); @@ -10705,7 +10980,9 @@ find_some_match(argvars, rettv, type) } if (argvars[3].v_type != VAR_UNKNOWN) - nth = get_tv_number(&argvars[3]); + nth = get_tv_number_chk(&argvars[3], &error); + if (error) + goto theend; } regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); @@ -10856,6 +11133,7 @@ max_min(argvars, rettv, domax) { long n = 0; long i; + int error = FALSE; if (argvars[0].v_type == VAR_LIST) { @@ -10868,13 +11146,13 @@ max_min(argvars, rettv, domax) li = l->lv_first; if (li != NULL) { - n = get_tv_number(&li->li_tv); + n = get_tv_number_chk(&li->li_tv, &error); while (1) { li = li->li_next; if (li == NULL) break; - i = get_tv_number(&li->li_tv); + i = get_tv_number_chk(&li->li_tv, &error); if (domax ? i > n : i < n) n = i; } @@ -10897,7 +11175,7 @@ max_min(argvars, rettv, domax) if (!HASHITEM_EMPTY(hi)) { --todo; - i = get_tv_number(&HI2DI(hi)->di_tv); + i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error); if (first) { n = i; @@ -10911,7 +11189,7 @@ max_min(argvars, rettv, domax) } else EMSG(_(e_listdictarg)); - rettv->vval.v_number = n; + rettv->vval.v_number = error ? 0 : n; } /* @@ -10990,11 +11268,11 @@ f_mkdir(argvars, rettv) if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[2].v_type != VAR_UNKNOWN) - prot = get_tv_number(&argvars[2]); - if (STRCMP(get_tv_string(&argvars[1]), "p") == 0) + prot = get_tv_number_chk(&argvars[2], NULL); + if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) mkdir_recurse(dir, prot); } - rettv->vval.v_number = vim_mkdir_emsg(dir, prot); + rettv->vval.v_number = prot != -1 ? vim_mkdir_emsg(dir, prot) : 0; } #endif @@ -11050,7 +11328,7 @@ f_nextnonblank(argvars, rettv) for (lnum = get_tv_lnum(argvars); ; ++lnum) { - if (lnum > curbuf->b_ml.ml_line_count) + if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) { lnum = 0; break; @@ -11117,8 +11395,9 @@ f_range(argvars, rettv) long i; list_T *l; listitem_T *li; - - start = get_tv_number(&argvars[0]); + int error = FALSE; + + start = get_tv_number_chk(&argvars[0], &error); if (argvars[1].v_type == VAR_UNKNOWN) { end = start - 1; @@ -11126,12 +11405,14 @@ f_range(argvars, rettv) } else { - end = get_tv_number(&argvars[1]); + end = get_tv_number_chk(&argvars[1], &error); if (argvars[2].v_type != VAR_UNKNOWN) - stride = get_tv_number(&argvars[2]); + stride = get_tv_number_chk(&argvars[2], &error); } rettv->vval.v_number = 0; + if (error) + return; /* type error; errmsg already given */ if (stride == 0) EMSG(_("E726: Stride is zero")); else if (stride > 0 ? end < start : end > start) @@ -11375,7 +11656,9 @@ remote_common(argvars, rettv, expr) return; # endif - server_name = get_tv_string(&argvars[0]); + server_name = get_tv_string_chk(&argvars[0]); + if (server_name == NULL) + return; /* type error; errmsg already given */ keys = get_tv_string_buf(&argvars[1], buf); # ifdef WIN32 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0) @@ -11397,11 +11680,14 @@ remote_common(argvars, rettv, expr) { dictitem_T v; char_u str[30]; + char_u *idvar; sprintf((char *)str, "0x%x", (unsigned int)w); v.di_tv.v_type = VAR_STRING; v.di_tv.vval.v_string = vim_strsave(str); - set_var(get_tv_string(&argvars[2]), &v.di_tv, FALSE); + idvar = get_tv_string_chk(&argvars[2]); + if (idvar != NULL) + set_var(idvar, &v.di_tv, FALSE); vim_free(v.di_tv.vval.v_string); } } @@ -11436,7 +11722,12 @@ f_remote_foreground(argvars, rettv) #ifdef FEAT_CLIENTSERVER # ifdef WIN32 /* On Win32 it's done in this application. */ - serverForeground(get_tv_string(&argvars[0])); + { + char_u *server_name = get_tv_string_chk(&argvars[0]); + + if (server_name != NULL) + serverForeground(server_name); + } # else /* Send a foreground() expression to the server. */ argvars[1].v_type = VAR_STRING; @@ -11460,14 +11751,21 @@ f_remote_peek(argvars, rettv) # ifdef WIN32 int n = 0; # endif + char_u *serverid; if (check_restricted() || check_secure()) { rettv->vval.v_number = -1; return; } + serverid = get_tv_string_chk(&argvars[0]); + if (serverid == NULL) + { + rettv->vval.v_number = -1; + return; /* type error; errmsg already given */ + } # ifdef WIN32 - sscanf(get_tv_string(&argvars[0]), "%x", &n); + sscanf(serverid, "%x", &n); if (n == 0) rettv->vval.v_number = -1; else @@ -11481,14 +11779,18 @@ f_remote_peek(argvars, rettv) return; rettv->vval.v_number = serverPeekReply(X_DISPLAY, - serverStrToWin(get_tv_string(&argvars[0])), &s); + serverStrToWin(serverid), &s); # endif if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) { + char_u *retvar; + v.di_tv.v_type = VAR_STRING; v.di_tv.vval.v_string = vim_strsave(s); - set_var(get_tv_string(&argvars[1]), &v.di_tv, FALSE); + retvar = get_tv_string_chk(&argvars[1]); + if (retvar != NULL) + set_var(retvar, &v.di_tv, FALSE); vim_free(v.di_tv.vval.v_string); } #else @@ -11505,19 +11807,21 @@ f_remote_read(argvars, rettv) char_u *r = NULL; #ifdef FEAT_CLIENTSERVER - if (!check_restricted() && !check_secure()) + char_u *serverid = get_tv_string_chk(&argvars[0]); + + if (serverid != NULL && !check_restricted() && !check_secure()) { # ifdef WIN32 /* The server's HWND is encoded in the 'id' parameter */ int n = 0; - sscanf(get_tv_string(&argvars[0]), "%x", &n); + sscanf(serverid, "%x", &n); if (n != 0) r = serverGetReply((HWND)n, FALSE, TRUE, TRUE); if (r == NULL) # else if (check_connection() == FAIL || serverReadReply(X_DISPLAY, - serverStrToWin(get_tv_string(&argvars[0])), &r, FALSE) < 0) + serverStrToWin(serverid), &r, FALSE) < 0) # endif EMSG(_("E277: Unable to read a server reply")); } @@ -11567,15 +11871,18 @@ f_remove(argvars, rettv) else if ((d = argvars[0].vval.v_dict) != NULL && !tv_check_lock(d->dv_lock, (char_u *)"remove()")) { - key = get_tv_string(&argvars[1]); - di = dict_find(d, key, -1); - if (di == NULL) - EMSG2(_(e_dictkey), key); - else - { - *rettv = di->di_tv; - init_tv(&di->di_tv); - dictitem_remove(d, di); + key = get_tv_string_chk(&argvars[1]); + if (key != NULL) + { + di = dict_find(d, key, -1); + if (di == NULL) + EMSG2(_(e_dictkey), key); + else + { + *rettv = di->di_tv; + init_tv(&di->di_tv); + dictitem_remove(d, di); + } } } } @@ -11584,9 +11891,12 @@ f_remove(argvars, rettv) else if ((l = argvars[0].vval.v_list) != NULL && !tv_check_lock(l->lv_lock, (char_u *)"remove()")) { - idx = get_tv_number(&argvars[1]); - item = list_find(l, idx); - if (item == NULL) + int error = FALSE; + + idx = get_tv_number_chk(&argvars[1], &error); + if (error) + ; /* type error: do nothing, errmsg already given */ + else if ((item = list_find(l, idx)) == NULL) EMSGN(_(e_listidx), idx); else { @@ -11600,9 +11910,10 @@ f_remove(argvars, rettv) else { /* Remove range of items, return list with values. */ - end = get_tv_number(&argvars[2]); - item2 = list_find(l, end); - if (item2 == NULL) + end = get_tv_number_chk(&argvars[2], &error); + if (error) + ; /* type error: do nothing */ + else if ((item2 = list_find(l, end)) == NULL) EMSGN(_(e_listidx), end); else { @@ -11964,7 +12275,9 @@ get_search_arg(varp, flagsp) if (varp->v_type != VAR_UNKNOWN) { - flags = get_tv_string_buf(varp, nbuf); + flags = get_tv_string_buf_chk(varp, nbuf); + if (flags == NULL) + return 0; /* type error; errmsg already given */ while (*flags != NUL) { switch (*flags) @@ -12051,7 +12364,7 @@ f_searchpair(argvars, rettv) { char_u *spat, *mpat, *epat; char_u *skip; - char_u *pat, *pat2, *pat3; + char_u *pat, *pat2 = NULL, *pat3 = NULL; pos_T pos; pos_T firstpos; pos_T foundpos; @@ -12076,9 +12389,11 @@ f_searchpair(argvars, rettv) p_cpo = (char_u *)""; /* Get the three pattern arguments: start, middle, end. */ - spat = get_tv_string(&argvars[0]); - mpat = get_tv_string_buf(&argvars[1], nbuf1); - epat = get_tv_string_buf(&argvars[2], nbuf2); + spat = get_tv_string_chk(&argvars[0]); + mpat = get_tv_string_buf_chk(&argvars[1], nbuf1); + epat = get_tv_string_buf_chk(&argvars[2], nbuf2); + if (spat == NULL || mpat == NULL || epat == NULL) + goto theend; /* type error */ /* Make two search patterns: start/end (pat2, for in nested pairs) and * start/middle/end (pat3, for the top pair). */ @@ -12103,7 +12418,9 @@ f_searchpair(argvars, rettv) || argvars[4].v_type == VAR_UNKNOWN) skip = (char_u *)""; else - skip = get_tv_string_buf(&argvars[4], nbuf3); + skip = get_tv_string_buf_chk(&argvars[4], nbuf3); + if (skip == NULL) + goto theend; /* type error */ save_cursor = curwin->w_cursor; pos = curwin->w_cursor; @@ -12198,10 +12515,12 @@ f_server2client(argvars, rettv) { #ifdef FEAT_CLIENTSERVER char_u buf[NUMBUFLEN]; - char_u *server = get_tv_string(&argvars[0]); - char_u *reply = get_tv_string_buf(&argvars[1], buf); + char_u *server = get_tv_string_chk(&argvars[0]); + char_u *reply = get_tv_string_buf_chk(&argvars[1], buf); rettv->vval.v_number = -1; + if (server == NULL || reply == NULL) + return; if (check_restricted() || check_secure()) return; # ifdef FEAT_X11 @@ -12260,11 +12579,14 @@ f_setbufvar(argvars, rettv) typval_T *varp; char_u nbuf[NUMBUFLEN]; + rettv->vval.v_number = 0; + if (check_restricted() || check_secure()) return; + (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ + varname = get_tv_string_chk(&argvars[1]); ++emsg_off; buf = get_buf_tv(&argvars[0]); - varname = get_tv_string(&argvars[1]); varp = &argvars[2]; if (buf != NULL && varname != NULL && varp != NULL) @@ -12279,9 +12601,17 @@ f_setbufvar(argvars, rettv) if (*varname == '&') { + long numval; + char_u *strval; + int error = FALSE; + ++varname; - set_option_value(varname, get_tv_number(varp), - get_tv_string_buf(varp, nbuf), OPT_LOCAL); + --emsg_off; + numval = get_tv_number_chk(varp, &error); + strval = get_tv_string_buf_chk(varp, nbuf); + ++emsg_off; + if (!error && strval != NULL) + set_option_value(varname, numval, strval, OPT_LOCAL); } else { @@ -12313,8 +12643,10 @@ f_setcmdpos(argvars, rettv) typval_T *argvars; typval_T *rettv; { - rettv->vval.v_number = set_cmdline_pos( - (int)get_tv_number(&argvars[0]) - 1); + int pos = (int)get_tv_number(&argvars[0]) - 1; + + if (pos >= 0) + rettv->vval.v_number = set_cmdline_pos(pos); } /* @@ -12339,7 +12671,7 @@ f_setline(argvars, rettv) li = l->lv_first; } else - line = get_tv_string(&argvars[1]); + line = get_tv_string_chk(&argvars[1]); rettv->vval.v_number = 0; /* OK */ for (;;) @@ -12349,12 +12681,12 @@ f_setline(argvars, rettv) /* list argument, get next string */ if (li == NULL) break; - line = get_tv_string(&li->li_tv); + line = get_tv_string_chk(&li->li_tv); li = li->li_next; } rettv->vval.v_number = 1; /* FAIL */ - if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) + if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) break; if (lnum <= curbuf->b_ml.ml_line_count) { @@ -12406,7 +12738,9 @@ f_setqflist(argvars, rettv) if (argvars[1].v_type == VAR_STRING) { - act = get_tv_string(&argvars[1]); + act = get_tv_string_chk(&argvars[1]); + if (act == NULL) + return; /* type error; errmsg already given */ if (*act == 'a' || *act == 'r') action = *act; } @@ -12428,6 +12762,7 @@ f_setreg(argvars, rettv) int regname; char_u *strregname; char_u *stropt; + char_u *strval; int append; char_u yank_type; long block_len; @@ -12436,10 +12771,12 @@ f_setreg(argvars, rettv) yank_type = MAUTO; append = FALSE; - strregname = get_tv_string(argvars); + strregname = get_tv_string_chk(argvars); rettv->vval.v_number = 1; /* FAIL is default */ - regname = (strregname == NULL ? '"' : *strregname); + if (strregname == NULL) + return; /* type error; errmsg already given */ + regname = *strregname; if (regname == 0 || regname == '@') regname = '"'; else if (regname == '=') @@ -12447,7 +12784,10 @@ f_setreg(argvars, rettv) if (argvars[2].v_type != VAR_UNKNOWN) { - for (stropt = get_tv_string(&argvars[2]); *stropt != NUL; ++stropt) + stropt = get_tv_string_chk(&argvars[2]); + if (stropt == NULL) + return; /* type error */ + for (; *stropt != NUL; ++stropt) switch (*stropt) { case 'a': case 'A': /* append */ @@ -12473,7 +12813,9 @@ f_setreg(argvars, rettv) } } - write_reg_contents_ex(regname, get_tv_string(&argvars[1]), -1, + strval = get_tv_string_chk(&argvars[1]); + if (strval != NULL) + write_reg_contents_ex(regname, strval, -1, append, yank_type, block_len); rettv->vval.v_number = 0; } @@ -12496,11 +12838,13 @@ f_setwinvar(argvars, rettv) typval_T *varp; char_u nbuf[NUMBUFLEN]; + rettv->vval.v_number = 0; + if (check_restricted() || check_secure()) return; + win = find_win_by_nr(&argvars[0]); + varname = get_tv_string_chk(&argvars[1]); ++emsg_off; - win = find_win_by_nr(&argvars[0]); - varname = get_tv_string(&argvars[1]); varp = &argvars[2]; if (win != NULL && varname != NULL && varp != NULL) @@ -12514,9 +12858,17 @@ f_setwinvar(argvars, rettv) if (*varname == '&') { + long numval; + char_u *strval; + int error = FALSE; + ++varname; - set_option_value(varname, get_tv_number(varp), - get_tv_string_buf(varp, nbuf), OPT_LOCAL); + --emsg_off; + numval = get_tv_number_chk(varp, &error); + strval = get_tv_string_buf_chk(varp, nbuf); + ++emsg_off; + if (!error && strval != NULL) + set_option_value(varname, numval, strval, OPT_LOCAL); } else { @@ -12572,6 +12924,7 @@ static int static int item_compare_ic; static char_u *item_compare_func; +static int item_compare_func_err; #define ITEM_COMPARE_FAIL 999 /* @@ -12615,6 +12968,10 @@ item_compare2(s1, s2) typval_T argv[2]; int dummy; + /* shortcut after failure in previous call; compare all items equal */ + if (item_compare_func_err) + return 0; + /* copy the values. This is needed to be able to set v_lock to VAR_FIXED * in the copy without changing the original list items. */ copy_tv(&(*(listitem_T **)s1)->li_tv, &argv[0]); @@ -12629,7 +12986,10 @@ item_compare2(s1, s2) if (res == FAIL) res = ITEM_COMPARE_FAIL; else - res = get_tv_number(&rettv); + /* return value has wrong type */ + res = get_tv_number_chk(&rettv, &item_compare_func_err); + if (item_compare_func_err) + res = ITEM_COMPARE_FAIL; clear_tv(&rettv); return res; } @@ -12669,10 +13029,14 @@ f_sort(argvars, rettv) if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[1].v_type == VAR_FUNC) - item_compare_func = argvars[0].vval.v_string; - else - { - i = get_tv_number(&argvars[1]); + item_compare_func = argvars[1].vval.v_string; + else + { + int error = FALSE; + + i = get_tv_number_chk(&argvars[1], &error); + if (error) + return; /* type error; errmsg already given */ if (i == 1) item_compare_ic = TRUE; else @@ -12688,6 +13052,7 @@ f_sort(argvars, rettv) for (li = l->lv_first; li != NULL; li = li->li_next) ptrs[i++] = li; + item_compare_func_err = FALSE; /* test the compare function */ if (item_compare_func != NULL && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) @@ -12699,11 +13064,14 @@ f_sort(argvars, rettv) qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *), item_compare_func == NULL ? item_compare : item_compare2); - /* Clear the List and append the items in the sorted order. */ - l->lv_first = l->lv_last = NULL; - l->lv_len = 0; - for (i = 0; i < len; ++i) - list_append(l, ptrs[i]); + if (!item_compare_func_err) + { + /* Clear the List and append the items in the sorted order. */ + l->lv_first = l->lv_last = NULL; + l->lv_len = 0; + for (i = 0; i < len; ++i) + list_append(l, ptrs[i]); + } } vim_free(ptrs); @@ -12726,6 +13094,7 @@ f_split(argvars, rettv) list_T *l; colnr_T col = 0; int keepempty = FALSE; + int typeerr = FALSE; /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ save_cpo = p_cpo; @@ -12734,9 +13103,11 @@ f_split(argvars, rettv) str = get_tv_string(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) { - pat = get_tv_string_buf(&argvars[1], patbuf); + pat = get_tv_string_buf_chk(&argvars[1], patbuf); + if (pat == NULL) + typeerr = TRUE; if (argvars[2].v_type != VAR_UNKNOWN) - keepempty = get_tv_number(&argvars[2]); + keepempty = get_tv_number_chk(&argvars[2], &typeerr); } if (pat == NULL || *pat == NUL) pat = (char_u *)"[\\x01- ]\\+"; @@ -12747,6 +13118,8 @@ f_split(argvars, rettv) rettv->v_type = VAR_LIST; rettv->vval.v_list = l; ++l->lv_refcount; + if (typeerr) + return; regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) @@ -12873,14 +13246,18 @@ f_stridx(argvars, rettv) char_u *pos; int start_idx; - needle = get_tv_string(&argvars[1]); - save_haystack = haystack = get_tv_string_buf(&argvars[0], buf); + needle = get_tv_string_chk(&argvars[1]); + save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf); rettv->vval.v_number = -1; + if (needle == NULL || haystack == NULL) + return; /* type error; errmsg already given */ if (argvars[2].v_type != VAR_UNKNOWN) { - start_idx = get_tv_number(&argvars[2]); - if (start_idx >= (int)STRLEN(haystack)) + int error = FALSE; + + start_idx = get_tv_number_chk(&argvars[2], &error); + if (error || start_idx >= (int)STRLEN(haystack)) return; if (start_idx >= 0) haystack += start_idx; @@ -12932,12 +13309,15 @@ f_strpart(argvars, rettv) int n; int len; int slen; + int error = FALSE; p = get_tv_string(&argvars[0]); slen = (int)STRLEN(p); - n = get_tv_number(&argvars[1]); - if (argvars[2].v_type != VAR_UNKNOWN) + n = get_tv_number_chk(&argvars[1], &error); + if (error) + len = 0; + else if (argvars[2].v_type != VAR_UNKNOWN) len = get_tv_number(&argvars[2]); else len = slen - n; /* default len: all bytes that are available. */ @@ -12977,19 +13357,19 @@ f_strridx(argvars, rettv) char_u *lastmatch = NULL; int haystack_len, end_idx; - needle = get_tv_string(&argvars[1]); - haystack = get_tv_string_buf(&argvars[0], buf); + needle = get_tv_string_chk(&argvars[1]); + haystack = get_tv_string_buf_chk(&argvars[0], buf); haystack_len = STRLEN(haystack); + + rettv->vval.v_number = -1; + if (needle == NULL || haystack == NULL) + return; /* type error; errmsg already given */ if (argvars[2].v_type != VAR_UNKNOWN) { /* Third argument: upper limit for index */ - end_idx = get_tv_number(&argvars[2]); + end_idx = get_tv_number_chk(&argvars[2], NULL); if (end_idx < 0) - { - /* can never find a match */ - rettv->vval.v_number = -1; - return; - } + return; /* can never find a match */ } else end_idx = haystack_len; @@ -13037,7 +13417,8 @@ f_submatch(argvars, rettv) typval_T *rettv; { rettv->v_type = VAR_STRING; - rettv->vval.v_string = reg_submatch((int)get_tv_number(&argvars[0])); + rettv->vval.v_string = + reg_submatch((int)get_tv_number_chk(&argvars[0], NULL)); } /* @@ -13052,12 +13433,16 @@ f_substitute(argvars, rettv) char_u subbuf[NUMBUFLEN]; char_u flagsbuf[NUMBUFLEN]; + char_u *str = get_tv_string_chk(&argvars[0]); + char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf); + char_u *sub = get_tv_string_buf_chk(&argvars[2], subbuf); + char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf); + rettv->v_type = VAR_STRING; - rettv->vval.v_string = do_string_sub( - get_tv_string(&argvars[0]), - get_tv_string_buf(&argvars[1], patbuf), - get_tv_string_buf(&argvars[2], subbuf), - get_tv_string_buf(&argvars[3], flagsbuf)); + if (str == NULL || pat == NULL || sub == NULL || flg == NULL) + rettv->vval.v_string = NULL; + else + rettv->vval.v_string = do_string_sub(str, pat, sub, flg); } /* @@ -13074,12 +13459,13 @@ f_synID(argvars, rettv) long lnum; long col; int trans; - - lnum = get_tv_lnum(argvars); - col = get_tv_number(&argvars[1]) - 1; - trans = get_tv_number(&argvars[2]); - - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count + int transerr; + + lnum = get_tv_lnum(argvars); /* -1 on type error */ + col = get_tv_number(&argvars[1]) - 1; /* -1 on type error */ + trans = get_tv_number_chk(&argvars[2], &transerr); + + if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0 && col < (long)STRLEN(ml_get(lnum))) id = syn_get_id(lnum, (colnr_T)col, trans, NULL); #endif @@ -13236,7 +13622,9 @@ f_system(argvars, rettv) EMSG2(_(e_notopen), infile); goto done; } - p = get_tv_string_buf(&argvars[1], buf); + p = get_tv_string_buf_chk(&argvars[1], buf); + if (p == NULL) + goto done; /* type error; errmsg already given */ if (fwrite(p, STRLEN(p), 1, fd) != 1) err = TRUE; if (fclose(fd) != 0) @@ -13305,6 +13693,8 @@ f_taglist(argvars, rettv) tag_pattern = get_tv_string(&argvars[0]); rettv->vval.v_number = FALSE; + if (*tag_pattern == NUL) + return; l = list_alloc(); if (l != NULL) @@ -13407,39 +13797,8 @@ f_toupper(argvars, rettv) typval_T *argvars; typval_T *rettv; { - char_u *p; - - p = vim_strsave(get_tv_string(&argvars[0])); rettv->v_type = VAR_STRING; - rettv->vval.v_string = p; - - if (p != NULL) - while (*p != NUL) - { -#ifdef FEAT_MBYTE - int l; - - if (enc_utf8) - { - int c, uc; - - c = utf_ptr2char(p); - uc = utf_toupper(c); - l = utf_ptr2len_check(p); - /* TODO: reallocate string when byte count changes. */ - if (utf_char2len(uc) == l) - utf_char2bytes(uc, p); - p += l; - } - else if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1) - p += l; /* skip multi-byte character */ - else -#endif - { - *p = TOUPPER_LOC(*p); /* note that toupper() can be a macro */ - p++; - } - } + rettv->vval.v_string = strup_save(get_tv_string(&argvars[0])); } /* @@ -13468,12 +13827,14 @@ f_tr(argvars, rettv) garray_T ga; instr = get_tv_string(&argvars[0]); - fromstr = get_tv_string_buf(&argvars[1], buf); - tostr = get_tv_string_buf(&argvars[2], buf2); + fromstr = get_tv_string_buf_chk(&argvars[1], buf); + tostr = get_tv_string_buf_chk(&argvars[2], buf2); /* Default return value: empty string. */ rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; + if (fromstr == NULL || tostr == NULL) + return; /* type error; errmsg already given */ ga_init2(&ga, (int)sizeof(char), 80); #ifdef FEAT_MBYTE @@ -13718,8 +14079,10 @@ f_winnr(argvars, rettv) if (argvars[0].v_type != VAR_UNKNOWN) { - arg = get_tv_string(&argvars[0]); - if (STRCMP(arg, "$") == 0) + arg = get_tv_string_chk(&argvars[0]); + if (arg == NULL) + nr = 0; /* type error; errmsg already given */ + else if (STRCMP(arg, "$") == 0) twin = lastwin; else if (STRCMP(arg, "#") == 0) { @@ -13806,9 +14169,11 @@ find_win_by_nr(vp) #endif int nr; - nr = get_tv_number(vp); + nr = get_tv_number_chk(vp, NULL); #ifdef FEAT_WINDOWS + if (nr < 0) + return NULL; if (nr == 0) return curwin; @@ -13906,7 +14271,9 @@ var2fpos(varp, lnum) static pos_T pos; pos_T *pp; - name = get_tv_string(varp); + name = get_tv_string_chk(varp); + if (name == NULL) + return NULL; if (name[0] == '.') /* cursor */ return &curwin->w_cursor; if (name[0] == '\'') /* mark */ @@ -14621,18 +14988,31 @@ init_tv(varp) /* * Get the number value of a variable. * If it is a String variable, uses vim_str2nr(). + * For incompatible types, return 0. + * get_tv_number_chk() is similar to get_tv_number(), but informs the + * caller of incompatible types: it sets *denote to TRUE if "denote" + * is not NULL or returns -1 otherwise. */ static long get_tv_number(varp) typval_T *varp; { + int error = FALSE; + + return get_tv_number_chk(varp, &error); /* return 0L on error */ +} + + static long +get_tv_number_chk(varp, denote) + typval_T *varp; + int *denote; +{ long n = 0L; switch (varp->v_type) { case VAR_NUMBER: - n = (long)(varp->vval.v_number); - break; + return (long)(varp->vval.v_number); case VAR_FUNC: EMSG(_("E703: Using a Funcref as a number")); break; @@ -14640,7 +15020,7 @@ get_tv_number(varp) if (varp->vval.v_string != NULL) vim_str2nr(varp->vval.v_string, NULL, NULL, TRUE, TRUE, &n, NULL); - break; + return n; case VAR_LIST: EMSG(_("E745: Using a List as a number")); break; @@ -14651,11 +15031,16 @@ get_tv_number(varp) EMSG2(_(e_intern2), "get_tv_number()"); break; } + if (denote == NULL) /* useful for values that must be unsigned */ + n = -1; + else + *denote = TRUE; return n; } /* * Get the lnum from the first argument. Also accepts ".", "$", etc. + * Returns -1 on error. */ static linenr_T get_tv_lnum(argvars) @@ -14664,7 +15049,7 @@ get_tv_lnum(argvars) typval_T rettv; linenr_T lnum; - lnum = get_tv_number(&argvars[0]); + lnum = get_tv_number_chk(&argvars[0], NULL); if (lnum == 0) /* no valid number, try using line() */ { rettv.v_type = VAR_NUMBER; @@ -14682,6 +15067,8 @@ get_tv_lnum(argvars) * get_tv_string_buf() uses a given buffer. * If the String variable has never been set, return an empty string. * Never returns NULL; + * get_tv_string_chk() and get_tv_string_buf_chk() are similar, but return + * NULL on error. */ static char_u * get_tv_string(varp) @@ -14697,6 +15084,25 @@ get_tv_string_buf(varp, buf) typval_T *varp; char_u *buf; { + char_u *res = get_tv_string_buf_chk(varp, buf); + + return res != NULL ? res : (char_u *)""; +} + + static char_u * +get_tv_string_chk(varp) + typval_T *varp; +{ + static char_u mybuf[NUMBUFLEN]; + + return get_tv_string_buf_chk(varp, mybuf); +} + + static char_u * +get_tv_string_buf_chk(varp, buf) + typval_T *varp; + char_u *buf; +{ switch (varp->v_type) { case VAR_NUMBER: @@ -14714,12 +15120,12 @@ get_tv_string_buf(varp, buf) case VAR_STRING: if (varp->vval.v_string != NULL) return varp->vval.v_string; - break; + return (char_u *)""; default: EMSG2(_(e_intern2), "get_tv_string_buf()"); break; } - return (char_u *)""; + return NULL; } /*